Page MenuHomeFreeBSD

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index 686fe4142256..ce5c9c15dae0 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -1,13952 +1,13952 @@
#
# $FreeBSD$
#
# This file lists old files (OLD_FILES), libraries (OLD_LIBS, MOVED_LIBS)
# and directories (OLD_DIRS) which should get removed after an update.
# Recently removed entries should be listed first (with the date as a
# comment). OLD_LIBS and MOVED_LIBS should only list dynamic libraries.
# Static libraries, links to dynamic libraries (lib*.so), and linker scripts
# should be listed in OLD_FILES. OLD_LIBS and MOVED_LIBS are removed by the
# delete-old-libs target, whereas OLD_FILES and OLD_DIRS are removed by the
# delete-old target. This separation allows users to avoid deleting old
# dynamic libraries still required by existing binaries.
#
# MOVED_LIBS should be used instead of OLD_LIBS when a library is moved
# from usr/lib to lib or vice versa. This avoids removing libraries for
# alternate ABIs (such as lib32) which store all libraries in a single
# directory (e.g. usr/lib32).
#
# For files listed in OLD_FILES, OLD_LIBS, and MOVED_LIBS, the check-old*
# and delete-old* targets will also delete associated debug symbols from
# usr/lib/debug.
#
# In case of a complete directory hierarchy the sorting is in depth first
# order.
#
# Files that are installed or removed depending on some build option
# should be listed in /usr/src/tools/build/mk/OptionalObsoleteFiles.inc
# instead of in this file.
#
# Before you commit changes to this file please check if any entries in
# tools/build/mk/OptionalObsoleteFiles.inc can be removed. The following
# command tells which files are listed more than once regardless of some
# architecture specific conditionals, so you can not blindly trust the
# output:
# ( grep '+=' /usr/src/ObsoleteFiles.inc | sort -u ; \
# grep '+=' /usr/src/tools/build/mk/OptionalObsoleteFiles.inc | sort -u) | \
# sort | uniq -d
#
# To find regular duplicates not dependent on optional components, you can
# also use something that will not give you false positives, e.g.:
# for t in `make -V TARGETS universe`; do
# __MAKE_CONF=/dev/null make -f Makefile.inc1 TARGET=$t \
# -V OLD_FILES -V OLD_LIBS -V MOVED_LIBS -V OLD_DIRS check-old | \
# xargs -n1 | sort | uniq -d;
# done
#
# For optional components, you can use the following to see if some entries
# in OptionalObsoleteFiles.inc have been obsoleted by ObsoleteFiles.inc
# for o in tools/build/options/WITH*; do
# __MAKE_CONF=/dev/null make -f Makefile.inc1 -D${o##*/} \
# -V OLD_FILES -V OLD_LIBS -V MOVED_LIBS -V OLD_DIRS check-old | \
# xargs -n1 | sort | uniq -d;
# done
-# 20230410: new clang import which bumps version from 14.0.5 to 15.0.0
+# 20230410: new clang import which bumps version from 14.0.5 to 15.0.3
OLD_FILES+=usr/lib/clang/14.0.5/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/14.0.5/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/14.0.5/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/14.0.5/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/14.0.5/include/fuzzer/FuzzedDataProvider.h
OLD_DIRS+=usr/lib/clang/14.0.5/include/fuzzer
OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/__clang_openmp_device_functions.h
OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/complex
OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/complex.h
OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/complex_cmath.h
OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/math.h
OLD_FILES+=usr/lib/clang/14.0.5/include/openmp_wrappers/new
OLD_DIRS+=usr/lib/clang/14.0.5/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/pmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/smmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/tmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/14.0.5/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/14.0.5/include/profile/InstrProfData.inc
OLD_FILES+=usr/lib/clang/14.0.5/include/profile/MemProfData.inc
OLD_DIRS+=usr/lib/clang/14.0.5/include/profile
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/memprof_interface.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/tsan_interface_atomic.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sanitizer/ubsan_interface.h
OLD_DIRS+=usr/lib/clang/14.0.5/include/sanitizer
OLD_FILES+=usr/lib/clang/14.0.5/include/xray/xray_interface.h
OLD_FILES+=usr/lib/clang/14.0.5/include/xray/xray_log_interface.h
OLD_FILES+=usr/lib/clang/14.0.5/include/xray/xray_records.h
OLD_DIRS+=usr/lib/clang/14.0.5/include/xray
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_math.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_cuda_texture_intrinsics.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_hip_cmath.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_hip_libdevice_declares.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_hip_math.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__clang_hip_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/14.0.5/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/14.0.5/include/adxintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/altivec.h
OLD_FILES+=usr/lib/clang/14.0.5/include/ammintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/amxintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/arm64intr.h
OLD_FILES+=usr/lib/clang/14.0.5/include/arm_acle.h
OLD_FILES+=usr/lib/clang/14.0.5/include/arm_bf16.h
OLD_FILES+=usr/lib/clang/14.0.5/include/arm_cde.h
OLD_FILES+=usr/lib/clang/14.0.5/include/arm_cmse.h
OLD_FILES+=usr/lib/clang/14.0.5/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/14.0.5/include/arm_mve.h
OLD_FILES+=usr/lib/clang/14.0.5/include/arm_neon.h
OLD_FILES+=usr/lib/clang/14.0.5/include/arm_neon_sve_bridge.h
OLD_FILES+=usr/lib/clang/14.0.5/include/arm_sve.h
OLD_FILES+=usr/lib/clang/14.0.5/include/armintr.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512fp16intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlfp16intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avxintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/avxvnniintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/builtins.h
OLD_FILES+=usr/lib/clang/14.0.5/include/cet.h
OLD_FILES+=usr/lib/clang/14.0.5/include/cetintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/cpuid.h
OLD_FILES+=usr/lib/clang/14.0.5/include/crc32intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/emmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/float.h
OLD_FILES+=usr/lib/clang/14.0.5/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/hexagon_circ_brev_intrinsics.h
OLD_FILES+=usr/lib/clang/14.0.5/include/hexagon_protos.h
OLD_FILES+=usr/lib/clang/14.0.5/include/hexagon_types.h
OLD_FILES+=usr/lib/clang/14.0.5/include/hresetintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/htmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/hvx_hexagon_protos.h
OLD_FILES+=usr/lib/clang/14.0.5/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/immintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/inttypes.h
OLD_FILES+=usr/lib/clang/14.0.5/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/iso646.h
OLD_FILES+=usr/lib/clang/14.0.5/include/keylockerintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/limits.h
OLD_FILES+=usr/lib/clang/14.0.5/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/14.0.5/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/14.0.5/include/mmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/module.modulemap
OLD_FILES+=usr/lib/clang/14.0.5/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/msa.h
OLD_FILES+=usr/lib/clang/14.0.5/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/omp-tools.h
OLD_FILES+=usr/lib/clang/14.0.5/include/omp.h
OLD_FILES+=usr/lib/clang/14.0.5/include/ompt.h
OLD_FILES+=usr/lib/clang/14.0.5/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/14.0.5/include/opencl-c.h
OLD_FILES+=usr/lib/clang/14.0.5/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/riscv_vector.h
OLD_FILES+=usr/lib/clang/14.0.5/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/s390intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/serializeintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/shaintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/smmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/stdalign.h
OLD_FILES+=usr/lib/clang/14.0.5/include/stdarg.h
OLD_FILES+=usr/lib/clang/14.0.5/include/stdatomic.h
OLD_FILES+=usr/lib/clang/14.0.5/include/stdbool.h
OLD_FILES+=usr/lib/clang/14.0.5/include/stddef.h
OLD_FILES+=usr/lib/clang/14.0.5/include/stdint.h
OLD_FILES+=usr/lib/clang/14.0.5/include/stdnoreturn.h
OLD_FILES+=usr/lib/clang/14.0.5/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/tgmath.h
OLD_FILES+=usr/lib/clang/14.0.5/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/tsxldtrkintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/uintrintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/unwind.h
OLD_FILES+=usr/lib/clang/14.0.5/include/vadefs.h
OLD_FILES+=usr/lib/clang/14.0.5/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/varargs.h
OLD_FILES+=usr/lib/clang/14.0.5/include/vecintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/wasm_simd128.h
OLD_FILES+=usr/lib/clang/14.0.5/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/x86gprintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/x86intrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/xopintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/14.0.5/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/14.0.5/include
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_static-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.asan_static-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-powerpc64le.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.5/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/14.0.5/lib/freebsd
OLD_DIRS+=usr/lib/clang/14.0.5/lib
OLD_FILES+=usr/lib/clang/14.0.5/share/asan_ignorelist.txt
OLD_FILES+=usr/lib/clang/14.0.5/share/cfi_ignorelist.txt
OLD_FILES+=usr/lib/clang/14.0.5/share/msan_ignorelist.txt
OLD_DIRS+=usr/lib/clang/14.0.5/share
OLD_DIRS+=usr/lib/clang/14.0.5
-# 20230410: new libc++ import which bumps version from 14.0.5 to 15.0.0
+# 20230410: new libc++ import which bumps version from 14.0.5 to 15.0.3
OLD_FILES+=usr/include/c++/v1/__functional_base
OLD_FILES+=usr/include/c++/v1/__libcpp_version
OLD_FILES+=usr/include/c++/v1/__nullptr
OLD_FILES+=usr/include/c++/v1/__string
OLD_FILES+=usr/include/c++/v1/experimental/filesystem
# 20230320: vcount.9 removed
OLD_FILES+=usr/share/man/man9/count_dev.9.gz
OLD_FILES+=usr/share/man/man9/vcount.9.gz
# 20230308: machine-id merged into hostid_save
OLD_FILES+=etc/rc.d/machine-id
# 20230203: loader help files renamed
OLD_FILES+=boot/loader.help
# 20230201: timeout moved from /usr/bin to /bin
OLD_FILES+=usr/tests/usr.bin/timeout/Kyuafile
OLD_FILES+=usr/tests/usr.bin/timeout/timeout_test
# 20221015: update the ithread(9) man page
OLD_FILES+=usr/share/man/man9/ithread.9.gz
OLD_FILES+=usr/share/man/man9/ithread_add_handler.9.gz
OLD_FILES+=usr/share/man/man9/ithread_create.9.gz
OLD_FILES+=usr/share/man/man9/ithread_destroy.9.gz
OLD_FILES+=usr/share/man/man9/ithread_priority.9.gz
OLD_FILES+=usr/share/man/man9/ithread_remove_handler.9.gz
OLD_FILES+=usr/share/man/man9/ithread_schedule.9.gz
# 20220615: new clang import which bumps version from 14.0.4 to 14.0.5
OLD_FILES+=usr/lib/clang/14.0.4/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/14.0.4/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/14.0.4/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/14.0.4/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/14.0.4/include/fuzzer/FuzzedDataProvider.h
OLD_DIRS+=usr/lib/clang/14.0.4/include/fuzzer
OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/__clang_openmp_device_functions.h
OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/complex
OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/complex.h
OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/complex_cmath.h
OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/math.h
OLD_FILES+=usr/lib/clang/14.0.4/include/openmp_wrappers/new
OLD_DIRS+=usr/lib/clang/14.0.4/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/pmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/smmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/tmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/14.0.4/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/14.0.4/include/profile/InstrProfData.inc
OLD_FILES+=usr/lib/clang/14.0.4/include/profile/MemProfData.inc
OLD_DIRS+=usr/lib/clang/14.0.4/include/profile
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/memprof_interface.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/tsan_interface_atomic.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sanitizer/ubsan_interface.h
OLD_DIRS+=usr/lib/clang/14.0.4/include/sanitizer
OLD_FILES+=usr/lib/clang/14.0.4/include/xray/xray_interface.h
OLD_FILES+=usr/lib/clang/14.0.4/include/xray/xray_log_interface.h
OLD_FILES+=usr/lib/clang/14.0.4/include/xray/xray_records.h
OLD_DIRS+=usr/lib/clang/14.0.4/include/xray
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_math.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_cuda_texture_intrinsics.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_hip_cmath.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_hip_libdevice_declares.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_hip_math.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__clang_hip_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/14.0.4/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/14.0.4/include/adxintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/altivec.h
OLD_FILES+=usr/lib/clang/14.0.4/include/ammintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/amxintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/arm64intr.h
OLD_FILES+=usr/lib/clang/14.0.4/include/arm_acle.h
OLD_FILES+=usr/lib/clang/14.0.4/include/arm_bf16.h
OLD_FILES+=usr/lib/clang/14.0.4/include/arm_cde.h
OLD_FILES+=usr/lib/clang/14.0.4/include/arm_cmse.h
OLD_FILES+=usr/lib/clang/14.0.4/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/14.0.4/include/arm_mve.h
OLD_FILES+=usr/lib/clang/14.0.4/include/arm_neon.h
OLD_FILES+=usr/lib/clang/14.0.4/include/arm_neon_sve_bridge.h
OLD_FILES+=usr/lib/clang/14.0.4/include/arm_sve.h
OLD_FILES+=usr/lib/clang/14.0.4/include/armintr.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512fp16intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlfp16intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avxintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/avxvnniintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/builtins.h
OLD_FILES+=usr/lib/clang/14.0.4/include/cet.h
OLD_FILES+=usr/lib/clang/14.0.4/include/cetintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/cpuid.h
OLD_FILES+=usr/lib/clang/14.0.4/include/crc32intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/emmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/float.h
OLD_FILES+=usr/lib/clang/14.0.4/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/hexagon_circ_brev_intrinsics.h
OLD_FILES+=usr/lib/clang/14.0.4/include/hexagon_protos.h
OLD_FILES+=usr/lib/clang/14.0.4/include/hexagon_types.h
OLD_FILES+=usr/lib/clang/14.0.4/include/hresetintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/htmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/hvx_hexagon_protos.h
OLD_FILES+=usr/lib/clang/14.0.4/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/immintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/inttypes.h
OLD_FILES+=usr/lib/clang/14.0.4/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/iso646.h
OLD_FILES+=usr/lib/clang/14.0.4/include/keylockerintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/limits.h
OLD_FILES+=usr/lib/clang/14.0.4/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/14.0.4/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/14.0.4/include/mmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/module.modulemap
OLD_FILES+=usr/lib/clang/14.0.4/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/msa.h
OLD_FILES+=usr/lib/clang/14.0.4/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/omp-tools.h
OLD_FILES+=usr/lib/clang/14.0.4/include/omp.h
OLD_FILES+=usr/lib/clang/14.0.4/include/ompt.h
OLD_FILES+=usr/lib/clang/14.0.4/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/14.0.4/include/opencl-c.h
OLD_FILES+=usr/lib/clang/14.0.4/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/riscv_vector.h
OLD_FILES+=usr/lib/clang/14.0.4/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/s390intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/serializeintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/shaintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/smmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/stdalign.h
OLD_FILES+=usr/lib/clang/14.0.4/include/stdarg.h
OLD_FILES+=usr/lib/clang/14.0.4/include/stdatomic.h
OLD_FILES+=usr/lib/clang/14.0.4/include/stdbool.h
OLD_FILES+=usr/lib/clang/14.0.4/include/stddef.h
OLD_FILES+=usr/lib/clang/14.0.4/include/stdint.h
OLD_FILES+=usr/lib/clang/14.0.4/include/stdnoreturn.h
OLD_FILES+=usr/lib/clang/14.0.4/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/tgmath.h
OLD_FILES+=usr/lib/clang/14.0.4/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/tsxldtrkintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/uintrintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/unwind.h
OLD_FILES+=usr/lib/clang/14.0.4/include/vadefs.h
OLD_FILES+=usr/lib/clang/14.0.4/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/varargs.h
OLD_FILES+=usr/lib/clang/14.0.4/include/vecintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/wasm_simd128.h
OLD_FILES+=usr/lib/clang/14.0.4/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/x86gprintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/x86intrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/xopintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/14.0.4/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/14.0.4/include
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_static-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.asan_static-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-powerpc64le.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.4/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/14.0.4/lib/freebsd
OLD_DIRS+=usr/lib/clang/14.0.4/lib/share
OLD_DIRS+=usr/lib/clang/14.0.4/lib
OLD_FILES+=usr/lib/clang/14.0.4/share/asan_ignorelist.txt
OLD_FILES+=usr/lib/clang/14.0.4/share/cfi_ignorelist.txt
OLD_FILES+=usr/lib/clang/14.0.4/share/msan_ignorelist.txt
OLD_DIRS+=usr/lib/clang/14.0.4/share
OLD_DIRS+=usr/lib/clang/14.0.4
# 20220609: new clang import which bumps version from 14.0.3 to 14.0.4
OLD_FILES+=usr/lib/clang/14.0.3/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/14.0.3/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/14.0.3/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/14.0.3/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/14.0.3/include/fuzzer/FuzzedDataProvider.h
OLD_DIRS+=usr/lib/clang/14.0.3/include/fuzzer
OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/__clang_openmp_device_functions.h
OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/complex
OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/complex.h
OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/complex_cmath.h
OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/math.h
OLD_FILES+=usr/lib/clang/14.0.3/include/openmp_wrappers/new
OLD_DIRS+=usr/lib/clang/14.0.3/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/pmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/smmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/tmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/14.0.3/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/14.0.3/include/profile/InstrProfData.inc
OLD_FILES+=usr/lib/clang/14.0.3/include/profile/MemProfData.inc
OLD_DIRS+=usr/lib/clang/14.0.3/include/profile
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/memprof_interface.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/tsan_interface_atomic.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sanitizer/ubsan_interface.h
OLD_DIRS+=usr/lib/clang/14.0.3/include/sanitizer
OLD_FILES+=usr/lib/clang/14.0.3/include/xray/xray_interface.h
OLD_FILES+=usr/lib/clang/14.0.3/include/xray/xray_log_interface.h
OLD_FILES+=usr/lib/clang/14.0.3/include/xray/xray_records.h
OLD_DIRS+=usr/lib/clang/14.0.3/include/xray
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_math.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_cuda_texture_intrinsics.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_hip_cmath.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_hip_libdevice_declares.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_hip_math.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__clang_hip_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/14.0.3/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/14.0.3/include/adxintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/altivec.h
OLD_FILES+=usr/lib/clang/14.0.3/include/ammintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/amxintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/arm64intr.h
OLD_FILES+=usr/lib/clang/14.0.3/include/arm_acle.h
OLD_FILES+=usr/lib/clang/14.0.3/include/arm_bf16.h
OLD_FILES+=usr/lib/clang/14.0.3/include/arm_cde.h
OLD_FILES+=usr/lib/clang/14.0.3/include/arm_cmse.h
OLD_FILES+=usr/lib/clang/14.0.3/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/14.0.3/include/arm_mve.h
OLD_FILES+=usr/lib/clang/14.0.3/include/arm_neon.h
OLD_FILES+=usr/lib/clang/14.0.3/include/arm_neon_sve_bridge.h
OLD_FILES+=usr/lib/clang/14.0.3/include/arm_sve.h
OLD_FILES+=usr/lib/clang/14.0.3/include/armintr.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512fp16intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlfp16intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avxintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/avxvnniintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/builtins.h
OLD_FILES+=usr/lib/clang/14.0.3/include/cet.h
OLD_FILES+=usr/lib/clang/14.0.3/include/cetintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/cpuid.h
OLD_FILES+=usr/lib/clang/14.0.3/include/crc32intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/emmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/float.h
OLD_FILES+=usr/lib/clang/14.0.3/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/hexagon_circ_brev_intrinsics.h
OLD_FILES+=usr/lib/clang/14.0.3/include/hexagon_protos.h
OLD_FILES+=usr/lib/clang/14.0.3/include/hexagon_types.h
OLD_FILES+=usr/lib/clang/14.0.3/include/hresetintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/htmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/hvx_hexagon_protos.h
OLD_FILES+=usr/lib/clang/14.0.3/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/immintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/inttypes.h
OLD_FILES+=usr/lib/clang/14.0.3/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/iso646.h
OLD_FILES+=usr/lib/clang/14.0.3/include/keylockerintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/limits.h
OLD_FILES+=usr/lib/clang/14.0.3/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/14.0.3/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/14.0.3/include/mmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/module.modulemap
OLD_FILES+=usr/lib/clang/14.0.3/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/msa.h
OLD_FILES+=usr/lib/clang/14.0.3/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/omp-tools.h
OLD_FILES+=usr/lib/clang/14.0.3/include/omp.h
OLD_FILES+=usr/lib/clang/14.0.3/include/ompt.h
OLD_FILES+=usr/lib/clang/14.0.3/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/14.0.3/include/opencl-c.h
OLD_FILES+=usr/lib/clang/14.0.3/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/riscv_vector.h
OLD_FILES+=usr/lib/clang/14.0.3/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/s390intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/serializeintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/shaintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/smmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/stdalign.h
OLD_FILES+=usr/lib/clang/14.0.3/include/stdarg.h
OLD_FILES+=usr/lib/clang/14.0.3/include/stdatomic.h
OLD_FILES+=usr/lib/clang/14.0.3/include/stdbool.h
OLD_FILES+=usr/lib/clang/14.0.3/include/stddef.h
OLD_FILES+=usr/lib/clang/14.0.3/include/stdint.h
OLD_FILES+=usr/lib/clang/14.0.3/include/stdnoreturn.h
OLD_FILES+=usr/lib/clang/14.0.3/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/tgmath.h
OLD_FILES+=usr/lib/clang/14.0.3/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/tsxldtrkintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/uintrintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/unwind.h
OLD_FILES+=usr/lib/clang/14.0.3/include/vadefs.h
OLD_FILES+=usr/lib/clang/14.0.3/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/varargs.h
OLD_FILES+=usr/lib/clang/14.0.3/include/vecintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/wasm_simd128.h
OLD_FILES+=usr/lib/clang/14.0.3/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/x86gprintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/x86intrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/xopintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/14.0.3/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/14.0.3/include
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_static-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.asan_static-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-powerpc64le.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/14.0.3/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/14.0.3/lib/freebsd
OLD_DIRS+=usr/lib/clang/14.0.3/lib/share
OLD_DIRS+=usr/lib/clang/14.0.3/lib
OLD_FILES+=usr/lib/clang/14.0.3/share/asan_ignorelist.txt
OLD_FILES+=usr/lib/clang/14.0.3/share/cfi_ignorelist.txt
OLD_FILES+=usr/lib/clang/14.0.3/share/msan_ignorelist.txt
OLD_DIRS+=usr/lib/clang/14.0.3/share
OLD_DIRS+=usr/lib/clang/14.0.3
# 20220607: libkqueue test updates
OLD_FILES+=usr/tests/sys/kqueue/libkqueue/kqtest
# 20220604: new clang import which bumps version from 13.0.0 to 14.0.3
OLD_FILES+=usr/lib/clang/13.0.0/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/13.0.0/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/13.0.0/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/13.0.0/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/13.0.0/include/fuzzer/FuzzedDataProvider.h
OLD_DIRS+=usr/lib/clang/13.0.0/include/fuzzer
OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/__clang_openmp_device_functions.h
OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/complex
OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/complex.h
OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/complex_cmath.h
OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/math.h
OLD_FILES+=usr/lib/clang/13.0.0/include/openmp_wrappers/new
OLD_DIRS+=usr/lib/clang/13.0.0/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/pmmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/smmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/tmmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/13.0.0/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/13.0.0/include/profile/InstrProfData.inc
OLD_DIRS+=usr/lib/clang/13.0.0/include/profile
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/tsan_interface_atomic.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sanitizer/ubsan_interface.h
OLD_DIRS+=usr/lib/clang/13.0.0/include/sanitizer
OLD_FILES+=usr/lib/clang/13.0.0/include/xray/xray_interface.h
OLD_FILES+=usr/lib/clang/13.0.0/include/xray/xray_log_interface.h
OLD_FILES+=usr/lib/clang/13.0.0/include/xray/xray_records.h
OLD_DIRS+=usr/lib/clang/13.0.0/include/xray
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_math.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_hip_cmath.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_hip_libdevice_declares.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_hip_math.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__clang_hip_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/13.0.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/13.0.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/altivec.h
OLD_FILES+=usr/lib/clang/13.0.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/amxintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/arm64intr.h
OLD_FILES+=usr/lib/clang/13.0.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/13.0.0/include/arm_bf16.h
OLD_FILES+=usr/lib/clang/13.0.0/include/arm_cde.h
OLD_FILES+=usr/lib/clang/13.0.0/include/arm_cmse.h
OLD_FILES+=usr/lib/clang/13.0.0/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/13.0.0/include/arm_mve.h
OLD_FILES+=usr/lib/clang/13.0.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/13.0.0/include/arm_sve.h
OLD_FILES+=usr/lib/clang/13.0.0/include/armintr.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/avxvnniintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/builtins.h
OLD_FILES+=usr/lib/clang/13.0.0/include/cet.h
OLD_FILES+=usr/lib/clang/13.0.0/include/cetintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/13.0.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/float.h
OLD_FILES+=usr/lib/clang/13.0.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/hexagon_circ_brev_intrinsics.h
OLD_FILES+=usr/lib/clang/13.0.0/include/hexagon_protos.h
OLD_FILES+=usr/lib/clang/13.0.0/include/hexagon_types.h
OLD_FILES+=usr/lib/clang/13.0.0/include/hresetintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/htmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/hvx_hexagon_protos.h
OLD_FILES+=usr/lib/clang/13.0.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/intrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/inttypes.h
OLD_FILES+=usr/lib/clang/13.0.0/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/iso646.h
OLD_FILES+=usr/lib/clang/13.0.0/include/keylockerintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/limits.h
OLD_FILES+=usr/lib/clang/13.0.0/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/13.0.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/13.0.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/13.0.0/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/msa.h
OLD_FILES+=usr/lib/clang/13.0.0/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/omp-tools.h
OLD_FILES+=usr/lib/clang/13.0.0/include/omp.h
OLD_FILES+=usr/lib/clang/13.0.0/include/ompt.h
OLD_FILES+=usr/lib/clang/13.0.0/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/13.0.0/include/opencl-c.h
OLD_FILES+=usr/lib/clang/13.0.0/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/riscv_vector.h
OLD_FILES+=usr/lib/clang/13.0.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/s390intrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/serializeintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/stdalign.h
OLD_FILES+=usr/lib/clang/13.0.0/include/stdarg.h
OLD_FILES+=usr/lib/clang/13.0.0/include/stdatomic.h
OLD_FILES+=usr/lib/clang/13.0.0/include/stdbool.h
OLD_FILES+=usr/lib/clang/13.0.0/include/stddef.h
OLD_FILES+=usr/lib/clang/13.0.0/include/stdint.h
OLD_FILES+=usr/lib/clang/13.0.0/include/stdnoreturn.h
OLD_FILES+=usr/lib/clang/13.0.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/tgmath.h
OLD_FILES+=usr/lib/clang/13.0.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/tsxldtrkintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/uintrintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/unwind.h
OLD_FILES+=usr/lib/clang/13.0.0/include/vadefs.h
OLD_FILES+=usr/lib/clang/13.0.0/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/varargs.h
OLD_FILES+=usr/lib/clang/13.0.0/include/vecintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/wasm_simd128.h
OLD_FILES+=usr/lib/clang/13.0.0/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/x86gprintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/13.0.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/13.0.0/include
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-powerpc64le.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/13.0.0/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/13.0.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/13.0.0/lib
OLD_DIRS+=usr/lib/clang/13.0.0
# 20220604: new libc++ import which bumps version from 13.0.0 to 14.0.3
OLD_FILES+=usr/include/c++/v1/__function_like.h
OLD_FILES+=usr/include/c++/v1/__memory/pointer_safety.h
OLD_FILES+=usr/include/c++/v1/__utility/__decay_copy.h
# 20220220: unwind.h moved to /usr/include
OLD_FILES+=usr/include/c++/v1/unwind-arm.h
OLD_FILES+=usr/include/c++/v1/unwind-itanium.h
OLD_FILES+=usr/include/c++/v1/unwind.h
# 20211221 efi_set_variables_supported.3 should be efi_variables_supported.3
OLD_FILES+=usr/share/man/man3/efi_set_variables_supported.3.gz
# 20211113: new clang import which bumps version from 12.0.1 to 13.0.0
OLD_FILES+=usr/lib/clang/12.0.1/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/12.0.1/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/12.0.1/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/12.0.1/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/12.0.1/include/fuzzer/FuzzedDataProvider.h
OLD_DIRS+=usr/lib/clang/12.0.1/include/fuzzer
OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/__clang_openmp_device_functions.h
OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/complex
OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/complex.h
OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/complex_cmath.h
OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/math.h
OLD_FILES+=usr/lib/clang/12.0.1/include/openmp_wrappers/new
OLD_DIRS+=usr/lib/clang/12.0.1/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/pmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/smmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/tmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/12.0.1/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/12.0.1/include/profile/InstrProfData.inc
OLD_DIRS+=usr/lib/clang/12.0.1/include/profile
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/tsan_interface_atomic.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sanitizer/ubsan_interface.h
OLD_DIRS+=usr/lib/clang/12.0.1/include/sanitizer
OLD_FILES+=usr/lib/clang/12.0.1/include/xray/xray_interface.h
OLD_FILES+=usr/lib/clang/12.0.1/include/xray/xray_log_interface.h
OLD_FILES+=usr/lib/clang/12.0.1/include/xray/xray_records.h
OLD_DIRS+=usr/lib/clang/12.0.1/include/xray
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_math.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_hip_cmath.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_hip_libdevice_declares.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_hip_math.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__clang_hip_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/12.0.1/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/12.0.1/include/adxintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/altivec.h
OLD_FILES+=usr/lib/clang/12.0.1/include/ammintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/amxintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/arm64intr.h
OLD_FILES+=usr/lib/clang/12.0.1/include/arm_acle.h
OLD_FILES+=usr/lib/clang/12.0.1/include/arm_bf16.h
OLD_FILES+=usr/lib/clang/12.0.1/include/arm_cde.h
OLD_FILES+=usr/lib/clang/12.0.1/include/arm_cmse.h
OLD_FILES+=usr/lib/clang/12.0.1/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/12.0.1/include/arm_mve.h
OLD_FILES+=usr/lib/clang/12.0.1/include/arm_neon.h
OLD_FILES+=usr/lib/clang/12.0.1/include/arm_sve.h
OLD_FILES+=usr/lib/clang/12.0.1/include/armintr.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avxintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/avxvnniintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/cet.h
OLD_FILES+=usr/lib/clang/12.0.1/include/cetintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/cpuid.h
OLD_FILES+=usr/lib/clang/12.0.1/include/emmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/float.h
OLD_FILES+=usr/lib/clang/12.0.1/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/hresetintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/htmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/immintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/intrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/inttypes.h
OLD_FILES+=usr/lib/clang/12.0.1/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/iso646.h
OLD_FILES+=usr/lib/clang/12.0.1/include/keylockerintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/limits.h
OLD_FILES+=usr/lib/clang/12.0.1/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/12.0.1/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/12.0.1/include/mmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/module.modulemap
OLD_FILES+=usr/lib/clang/12.0.1/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/msa.h
OLD_FILES+=usr/lib/clang/12.0.1/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/omp-tools.h
OLD_FILES+=usr/lib/clang/12.0.1/include/omp.h
OLD_FILES+=usr/lib/clang/12.0.1/include/ompt.h
OLD_FILES+=usr/lib/clang/12.0.1/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/12.0.1/include/opencl-c.h
OLD_FILES+=usr/lib/clang/12.0.1/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/s390intrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/serializeintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/shaintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/smmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/stdalign.h
OLD_FILES+=usr/lib/clang/12.0.1/include/stdarg.h
OLD_FILES+=usr/lib/clang/12.0.1/include/stdatomic.h
OLD_FILES+=usr/lib/clang/12.0.1/include/stdbool.h
OLD_FILES+=usr/lib/clang/12.0.1/include/stddef.h
OLD_FILES+=usr/lib/clang/12.0.1/include/stdint.h
OLD_FILES+=usr/lib/clang/12.0.1/include/stdnoreturn.h
OLD_FILES+=usr/lib/clang/12.0.1/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/tgmath.h
OLD_FILES+=usr/lib/clang/12.0.1/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/tsxldtrkintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/uintrintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/unwind.h
OLD_FILES+=usr/lib/clang/12.0.1/include/vadefs.h
OLD_FILES+=usr/lib/clang/12.0.1/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/varargs.h
OLD_FILES+=usr/lib/clang/12.0.1/include/vecintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/wasm_simd128.h
OLD_FILES+=usr/lib/clang/12.0.1/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/x86gprintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/x86intrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/xopintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/12.0.1/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/12.0.1/include
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-powerpc64le.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.1/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/12.0.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/12.0.1/lib
OLD_DIRS+=usr/lib/clang/12.0.1
# 20211113: new libc++ import which bumps version from 12.0.1 to 13.0.0
OLD_FILES+=usr/include/c++/v1/__functional_03
OLD_FILES+=usr/include/c++/v1/__functional_base_03
OLD_FILES+=usr/include/c++/v1/__memory/base.h
OLD_FILES+=usr/include/c++/v1/__memory/utilities.h
OLD_FILES+=usr/include/c++/v1/__sso_allocator
OLD_FILES+=usr/include/c++/v1/tr1/__availability
OLD_FILES+=usr/include/c++/v1/tr1/__bit_reference
OLD_FILES+=usr/include/c++/v1/tr1/__bits
OLD_FILES+=usr/include/c++/v1/tr1/__bsd_locale_defaults.h
OLD_FILES+=usr/include/c++/v1/tr1/__bsd_locale_fallbacks.h
OLD_FILES+=usr/include/c++/v1/tr1/__config
OLD_FILES+=usr/include/c++/v1/tr1/__debug
OLD_FILES+=usr/include/c++/v1/tr1/__errc
OLD_FILES+=usr/include/c++/v1/tr1/__functional_03
OLD_FILES+=usr/include/c++/v1/tr1/__functional_base
OLD_FILES+=usr/include/c++/v1/tr1/__functional_base_03
OLD_FILES+=usr/include/c++/v1/tr1/__hash_table
OLD_FILES+=usr/include/c++/v1/tr1/__libcpp_version
OLD_FILES+=usr/include/c++/v1/tr1/__locale
OLD_FILES+=usr/include/c++/v1/tr1/__mutex_base
OLD_FILES+=usr/include/c++/v1/tr1/__node_handle
OLD_FILES+=usr/include/c++/v1/tr1/__nullptr
OLD_FILES+=usr/include/c++/v1/tr1/__split_buffer
OLD_FILES+=usr/include/c++/v1/tr1/__sso_allocator
OLD_FILES+=usr/include/c++/v1/tr1/__std_stream
OLD_FILES+=usr/include/c++/v1/tr1/__string
OLD_FILES+=usr/include/c++/v1/tr1/__threading_support
OLD_FILES+=usr/include/c++/v1/tr1/__tree
OLD_FILES+=usr/include/c++/v1/tr1/__tuple
OLD_FILES+=usr/include/c++/v1/tr1/__undef_macros
OLD_FILES+=usr/include/c++/v1/tr1/algorithm
OLD_FILES+=usr/include/c++/v1/tr1/any
OLD_FILES+=usr/include/c++/v1/tr1/array
OLD_FILES+=usr/include/c++/v1/tr1/atomic
OLD_FILES+=usr/include/c++/v1/tr1/barrier
OLD_FILES+=usr/include/c++/v1/tr1/bit
OLD_FILES+=usr/include/c++/v1/tr1/bitset
OLD_FILES+=usr/include/c++/v1/tr1/cassert
OLD_FILES+=usr/include/c++/v1/tr1/ccomplex
OLD_FILES+=usr/include/c++/v1/tr1/cctype
OLD_FILES+=usr/include/c++/v1/tr1/cerrno
OLD_FILES+=usr/include/c++/v1/tr1/cfenv
OLD_FILES+=usr/include/c++/v1/tr1/cfloat
OLD_FILES+=usr/include/c++/v1/tr1/charconv
OLD_FILES+=usr/include/c++/v1/tr1/chrono
OLD_FILES+=usr/include/c++/v1/tr1/cinttypes
OLD_FILES+=usr/include/c++/v1/tr1/ciso646
OLD_FILES+=usr/include/c++/v1/tr1/climits
OLD_FILES+=usr/include/c++/v1/tr1/clocale
OLD_FILES+=usr/include/c++/v1/tr1/cmath
OLD_FILES+=usr/include/c++/v1/tr1/codecvt
OLD_FILES+=usr/include/c++/v1/tr1/compare
OLD_FILES+=usr/include/c++/v1/tr1/complex
OLD_FILES+=usr/include/c++/v1/tr1/complex.h
OLD_FILES+=usr/include/c++/v1/tr1/concepts
OLD_FILES+=usr/include/c++/v1/tr1/condition_variable
OLD_FILES+=usr/include/c++/v1/tr1/csetjmp
OLD_FILES+=usr/include/c++/v1/tr1/csignal
OLD_FILES+=usr/include/c++/v1/tr1/cstdarg
OLD_FILES+=usr/include/c++/v1/tr1/cstdbool
OLD_FILES+=usr/include/c++/v1/tr1/cstddef
OLD_FILES+=usr/include/c++/v1/tr1/cstdint
OLD_FILES+=usr/include/c++/v1/tr1/cstdio
OLD_FILES+=usr/include/c++/v1/tr1/cstdlib
OLD_FILES+=usr/include/c++/v1/tr1/cstring
OLD_FILES+=usr/include/c++/v1/tr1/ctgmath
OLD_FILES+=usr/include/c++/v1/tr1/ctime
OLD_FILES+=usr/include/c++/v1/tr1/ctype.h
OLD_FILES+=usr/include/c++/v1/tr1/cwchar
OLD_FILES+=usr/include/c++/v1/tr1/cwctype
OLD_FILES+=usr/include/c++/v1/tr1/deque
OLD_FILES+=usr/include/c++/v1/tr1/errno.h
OLD_FILES+=usr/include/c++/v1/tr1/exception
OLD_FILES+=usr/include/c++/v1/tr1/execution
OLD_FILES+=usr/include/c++/v1/tr1/fenv.h
OLD_FILES+=usr/include/c++/v1/tr1/filesystem
OLD_FILES+=usr/include/c++/v1/tr1/float.h
OLD_FILES+=usr/include/c++/v1/tr1/forward_list
OLD_FILES+=usr/include/c++/v1/tr1/fstream
OLD_FILES+=usr/include/c++/v1/tr1/functional
OLD_FILES+=usr/include/c++/v1/tr1/future
OLD_FILES+=usr/include/c++/v1/tr1/initializer_list
OLD_FILES+=usr/include/c++/v1/tr1/inttypes.h
OLD_FILES+=usr/include/c++/v1/tr1/iomanip
OLD_FILES+=usr/include/c++/v1/tr1/ios
OLD_FILES+=usr/include/c++/v1/tr1/iosfwd
OLD_FILES+=usr/include/c++/v1/tr1/iostream
OLD_FILES+=usr/include/c++/v1/tr1/istream
OLD_FILES+=usr/include/c++/v1/tr1/iterator
OLD_FILES+=usr/include/c++/v1/tr1/latch
OLD_FILES+=usr/include/c++/v1/tr1/limits
OLD_FILES+=usr/include/c++/v1/tr1/limits.h
OLD_FILES+=usr/include/c++/v1/tr1/list
OLD_FILES+=usr/include/c++/v1/tr1/locale
OLD_FILES+=usr/include/c++/v1/tr1/locale.h
OLD_FILES+=usr/include/c++/v1/tr1/map
OLD_FILES+=usr/include/c++/v1/tr1/math.h
OLD_FILES+=usr/include/c++/v1/tr1/memory
OLD_FILES+=usr/include/c++/v1/tr1/mutex
OLD_FILES+=usr/include/c++/v1/tr1/new
OLD_FILES+=usr/include/c++/v1/tr1/numbers
OLD_FILES+=usr/include/c++/v1/tr1/numeric
OLD_FILES+=usr/include/c++/v1/tr1/optional
OLD_FILES+=usr/include/c++/v1/tr1/ostream
OLD_FILES+=usr/include/c++/v1/tr1/queue
OLD_FILES+=usr/include/c++/v1/tr1/random
OLD_FILES+=usr/include/c++/v1/tr1/ratio
OLD_FILES+=usr/include/c++/v1/tr1/regex
OLD_FILES+=usr/include/c++/v1/tr1/scoped_allocator
OLD_FILES+=usr/include/c++/v1/tr1/semaphore
OLD_FILES+=usr/include/c++/v1/tr1/set
OLD_FILES+=usr/include/c++/v1/tr1/setjmp.h
OLD_FILES+=usr/include/c++/v1/tr1/shared_mutex
OLD_FILES+=usr/include/c++/v1/tr1/span
OLD_FILES+=usr/include/c++/v1/tr1/sstream
OLD_FILES+=usr/include/c++/v1/tr1/stack
OLD_FILES+=usr/include/c++/v1/tr1/stdbool.h
OLD_FILES+=usr/include/c++/v1/tr1/stddef.h
OLD_FILES+=usr/include/c++/v1/tr1/stdexcept
OLD_FILES+=usr/include/c++/v1/tr1/stdint.h
OLD_FILES+=usr/include/c++/v1/tr1/stdio.h
OLD_FILES+=usr/include/c++/v1/tr1/stdlib.h
OLD_FILES+=usr/include/c++/v1/tr1/streambuf
OLD_FILES+=usr/include/c++/v1/tr1/string
OLD_FILES+=usr/include/c++/v1/tr1/string.h
OLD_FILES+=usr/include/c++/v1/tr1/string_view
OLD_FILES+=usr/include/c++/v1/tr1/strstream
OLD_FILES+=usr/include/c++/v1/tr1/system_error
OLD_FILES+=usr/include/c++/v1/tr1/tgmath.h
OLD_FILES+=usr/include/c++/v1/tr1/thread
OLD_FILES+=usr/include/c++/v1/tr1/tuple
OLD_FILES+=usr/include/c++/v1/tr1/type_traits
OLD_FILES+=usr/include/c++/v1/tr1/typeindex
OLD_FILES+=usr/include/c++/v1/tr1/typeinfo
OLD_FILES+=usr/include/c++/v1/tr1/unordered_map
OLD_FILES+=usr/include/c++/v1/tr1/unordered_set
OLD_FILES+=usr/include/c++/v1/tr1/utility
OLD_FILES+=usr/include/c++/v1/tr1/valarray
OLD_FILES+=usr/include/c++/v1/tr1/variant
OLD_FILES+=usr/include/c++/v1/tr1/vector
OLD_FILES+=usr/include/c++/v1/tr1/version
OLD_FILES+=usr/include/c++/v1/tr1/wchar.h
OLD_FILES+=usr/include/c++/v1/tr1/wctype.h
OLD_DIRS+=usr/include/c++/v1/tr1
# 20211004: Removed sparc64 tests for lastcomm/sa
OLD_FILES+=usr/tests/usr.bin/lastcomm/v1-sparc64-acct.in
OLD_FILES+=usr/tests/usr.bin/lastcomm/v1-sparc64.out
OLD_FILES+=usr/tests/usr.bin/lastcomm/v2-sparc64-acct.in
OLD_FILES+=usr/tests/usr.bin/lastcomm/v2-sparc64.out
OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-sav.in
OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-sav.out
OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-u.out
OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-usr.in
OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-usr.out
OLD_FILES+=usr/tests/usr.sbin/sa/v2-sparc64-sav.in
OLD_FILES+=usr/tests/usr.sbin/sa/v2-sparc64-u.out
OLD_FILES+=usr/tests/usr.sbin/sa/v2-sparc64-usr.in
# 20210906: stop installing {llvm,clang,lldb}-tblgen
OLD_FILES+=usr/bin/llvm-tblgen
OLD_FILES+=usr/bin/clang-tblgen
OLD_FILES+=usr/bin/lldb-tblgen
OLD_FILES+=usr/share/man/man1/llvm-tblgen.1.gz
# 20211115: vm_page busy functions removed
OLD_FILES+=share/man/man9/vm_page_sbusy.9.gz
OLD_FILES+=share/man/man9/vm_page_xbusy.9.gz
OLD_FILES+=share/man/man9/vm_page_sleep_if_busy.9.gz
# 20210923: rename boot(9) to kern_reboot(9)
OLD_FILES+=usr/share/man/man9/boot.9.gz
# 20210810: remove Pentium-related man pages and references
OLD_FILES+=usr/share/man/man3/pmc.p4.3.gz
OLD_FILES+=usr/share/man/man3/pmc.p5.3.gz
OLD_FILES+=usr/share/man/man3/pmc.p6.3.gz
# 20210619: new clang import which bumps version from 12.0.0 to 12.0.1
OLD_FILES+=usr/lib/clang/12.0.0/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/12.0.0/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/12.0.0/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/12.0.0/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/12.0.0/include/fuzzer/FuzzedDataProvider.h
OLD_DIRS+=usr/lib/clang/12.0.0/include/fuzzer
OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/__clang_openmp_device_functions.h
OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/complex
OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/complex.h
OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/complex_cmath.h
OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/math.h
OLD_FILES+=usr/lib/clang/12.0.0/include/openmp_wrappers/new
OLD_DIRS+=usr/lib/clang/12.0.0/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/pmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/smmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/tmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/12.0.0/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/12.0.0/include/profile/InstrProfData.inc
OLD_DIRS+=usr/lib/clang/12.0.0/include/profile
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/tsan_interface_atomic.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sanitizer/ubsan_interface.h
OLD_DIRS+=usr/lib/clang/12.0.0/include/sanitizer
OLD_FILES+=usr/lib/clang/12.0.0/include/xray/xray_interface.h
OLD_FILES+=usr/lib/clang/12.0.0/include/xray/xray_log_interface.h
OLD_FILES+=usr/lib/clang/12.0.0/include/xray/xray_records.h
OLD_DIRS+=usr/lib/clang/12.0.0/include/xray
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_math.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_hip_cmath.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_hip_libdevice_declares.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_hip_math.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__clang_hip_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/12.0.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/12.0.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/altivec.h
OLD_FILES+=usr/lib/clang/12.0.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/amxintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/arm64intr.h
OLD_FILES+=usr/lib/clang/12.0.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/12.0.0/include/arm_bf16.h
OLD_FILES+=usr/lib/clang/12.0.0/include/arm_cde.h
OLD_FILES+=usr/lib/clang/12.0.0/include/arm_cmse.h
OLD_FILES+=usr/lib/clang/12.0.0/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/12.0.0/include/arm_mve.h
OLD_FILES+=usr/lib/clang/12.0.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/12.0.0/include/arm_sve.h
OLD_FILES+=usr/lib/clang/12.0.0/include/armintr.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/avxvnniintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/cet.h
OLD_FILES+=usr/lib/clang/12.0.0/include/cetintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/12.0.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/float.h
OLD_FILES+=usr/lib/clang/12.0.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/hresetintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/htmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/intrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/inttypes.h
OLD_FILES+=usr/lib/clang/12.0.0/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/iso646.h
OLD_FILES+=usr/lib/clang/12.0.0/include/keylockerintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/limits.h
OLD_FILES+=usr/lib/clang/12.0.0/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/12.0.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/12.0.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/12.0.0/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/msa.h
OLD_FILES+=usr/lib/clang/12.0.0/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/omp-tools.h
OLD_FILES+=usr/lib/clang/12.0.0/include/omp.h
OLD_FILES+=usr/lib/clang/12.0.0/include/ompt.h
OLD_FILES+=usr/lib/clang/12.0.0/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/12.0.0/include/opencl-c.h
OLD_FILES+=usr/lib/clang/12.0.0/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/s390intrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/serializeintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/stdalign.h
OLD_FILES+=usr/lib/clang/12.0.0/include/stdarg.h
OLD_FILES+=usr/lib/clang/12.0.0/include/stdatomic.h
OLD_FILES+=usr/lib/clang/12.0.0/include/stdbool.h
OLD_FILES+=usr/lib/clang/12.0.0/include/stddef.h
OLD_FILES+=usr/lib/clang/12.0.0/include/stdint.h
OLD_FILES+=usr/lib/clang/12.0.0/include/stdnoreturn.h
OLD_FILES+=usr/lib/clang/12.0.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/tgmath.h
OLD_FILES+=usr/lib/clang/12.0.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/tsxldtrkintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/uintrintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/unwind.h
OLD_FILES+=usr/lib/clang/12.0.0/include/vadefs.h
OLD_FILES+=usr/lib/clang/12.0.0/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/varargs.h
OLD_FILES+=usr/lib/clang/12.0.0/include/vecintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/wasm_simd128.h
OLD_FILES+=usr/lib/clang/12.0.0/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/x86gprintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/12.0.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/12.0.0/include
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-powerpc64le.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/12.0.0/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/12.0.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/12.0.0/lib
OLD_DIRS+=usr/lib/clang/12.0.0
# 20210613: new clang import which bumps version from 11.0.1 to 12.0.0
OLD_FILES+=usr/lib/clang/11.0.1/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/11.0.1/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/11.0.1/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/11.0.1/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/11.0.1/include/fuzzer/FuzzedDataProvider.h
OLD_DIRS+=usr/lib/clang/11.0.1/include/fuzzer
OLD_FILES+=usr/lib/clang/11.0.1/include/openmp_wrappers/__clang_openmp_device_functions.h
OLD_FILES+=usr/lib/clang/11.0.1/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/11.0.1/include/openmp_wrappers/complex
OLD_FILES+=usr/lib/clang/11.0.1/include/openmp_wrappers/complex.h
OLD_FILES+=usr/lib/clang/11.0.1/include/openmp_wrappers/math.h
OLD_FILES+=usr/lib/clang/11.0.1/include/openmp_wrappers/new
OLD_DIRS+=usr/lib/clang/11.0.1/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/pmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/smmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/tmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/11.0.1/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/11.0.1/include/profile/InstrProfData.inc
OLD_DIRS+=usr/lib/clang/11.0.1/include/profile
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/tsan_interface_atomic.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sanitizer/ubsan_interface.h
OLD_DIRS+=usr/lib/clang/11.0.1/include/sanitizer
OLD_FILES+=usr/lib/clang/11.0.1/include/xray/xray_interface.h
OLD_FILES+=usr/lib/clang/11.0.1/include/xray/xray_log_interface.h
OLD_FILES+=usr/lib/clang/11.0.1/include/xray/xray_records.h
OLD_DIRS+=usr/lib/clang/11.0.1/include/xray
OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_math.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_hip_libdevice_declares.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_hip_math.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__clang_hip_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/11.0.1/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/11.0.1/include/adxintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/altivec.h
OLD_FILES+=usr/lib/clang/11.0.1/include/ammintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/amxintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/arm64intr.h
OLD_FILES+=usr/lib/clang/11.0.1/include/arm_acle.h
OLD_FILES+=usr/lib/clang/11.0.1/include/arm_bf16.h
OLD_FILES+=usr/lib/clang/11.0.1/include/arm_cde.h
OLD_FILES+=usr/lib/clang/11.0.1/include/arm_cmse.h
OLD_FILES+=usr/lib/clang/11.0.1/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/11.0.1/include/arm_mve.h
OLD_FILES+=usr/lib/clang/11.0.1/include/arm_neon.h
OLD_FILES+=usr/lib/clang/11.0.1/include/arm_sve.h
OLD_FILES+=usr/lib/clang/11.0.1/include/armintr.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/avxintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/cet.h
OLD_FILES+=usr/lib/clang/11.0.1/include/cetintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/cpuid.h
OLD_FILES+=usr/lib/clang/11.0.1/include/emmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/float.h
OLD_FILES+=usr/lib/clang/11.0.1/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/htmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/immintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/intrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/inttypes.h
OLD_FILES+=usr/lib/clang/11.0.1/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/iso646.h
OLD_FILES+=usr/lib/clang/11.0.1/include/limits.h
OLD_FILES+=usr/lib/clang/11.0.1/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/11.0.1/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/11.0.1/include/mmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/module.modulemap
OLD_FILES+=usr/lib/clang/11.0.1/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/msa.h
OLD_FILES+=usr/lib/clang/11.0.1/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/omp-tools.h
OLD_FILES+=usr/lib/clang/11.0.1/include/omp.h
OLD_FILES+=usr/lib/clang/11.0.1/include/ompt.h
OLD_FILES+=usr/lib/clang/11.0.1/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/11.0.1/include/opencl-c.h
OLD_FILES+=usr/lib/clang/11.0.1/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/s390intrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/serializeintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/shaintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/smmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/stdalign.h
OLD_FILES+=usr/lib/clang/11.0.1/include/stdarg.h
OLD_FILES+=usr/lib/clang/11.0.1/include/stdatomic.h
OLD_FILES+=usr/lib/clang/11.0.1/include/stdbool.h
OLD_FILES+=usr/lib/clang/11.0.1/include/stddef.h
OLD_FILES+=usr/lib/clang/11.0.1/include/stdint.h
OLD_FILES+=usr/lib/clang/11.0.1/include/stdnoreturn.h
OLD_FILES+=usr/lib/clang/11.0.1/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/tgmath.h
OLD_FILES+=usr/lib/clang/11.0.1/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/tsxldtrkintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/unwind.h
OLD_FILES+=usr/lib/clang/11.0.1/include/vadefs.h
OLD_FILES+=usr/lib/clang/11.0.1/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/varargs.h
OLD_FILES+=usr/lib/clang/11.0.1/include/vecintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/wasm_simd128.h
OLD_FILES+=usr/lib/clang/11.0.1/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/x86intrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/xopintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/11.0.1/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/11.0.1/include
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-powerpc64le.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.1/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/11.0.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/11.0.1/lib
OLD_DIRS+=usr/lib/clang/11.0.1
# 20210613: Rename OpenZFS manual pages
OLD_FILES+=usr/share/man/man5/spl-module-parameters.5.gz
OLD_FILES+=usr/share/man/man5/zfs-events.5.gz
OLD_FILES+=usr/share/man/man5/zfs-module-parameters.5.gz
OLD_FILES+=usr/share/man/man8/zfsconcepts.8.gz
OLD_FILES+=usr/share/man/man8/zfsprops.8.gz
OLD_FILES+=usr/share/man/man5/zpool-features.5.gz
OLD_FILES+=usr/share/man/man8/zpoolconcepts.8.gz
OLD_FILES+=usr/share/man/man8/zpoolprops.8.gz
# 20210413: Remove pfctlinput2
OLD_FILES+=usr/share/man/man9/pfctlinput2.9.gz
# 20210329: Remove kernel-only crypto headers from /usr/include
OLD_FILES+=usr/include/crypto/_cryptodev.h
OLD_FILES+=usr/include/crypto/cbc_mac.h
OLD_FILES+=usr/include/crypto/deflate.h
OLD_FILES+=usr/include/crypto/gfmult.h
OLD_FILES+=usr/include/crypto/gmac.h
OLD_FILES+=usr/include/crypto/rijndael.h
OLD_FILES+=usr/include/crypto/rmd160.h
OLD_FILES+=usr/include/crypto/xform.h
OLD_FILES+=usr/include/crypto/xform_auth.h
OLD_FILES+=usr/include/crypto/xform_comp.h
OLD_FILES+=usr/include/crypto/xform_enc.h
OLD_FILES+=usr/include/crypto/xform_poly1305.h
# 20210204: bump shared libraries which link against ncurses
OLD_LIBS+=lib/libedit.so.7
OLD_LIBS+=usr/lib/libdialog.so.8
OLD_LIBS+=usr/lib/libdpv.so.1
OLD_LIBS+=usr/lib/libform.so.5
OLD_LIBS+=usr/lib/libformw.so.5
OLD_LIBS+=usr/lib/libmenu.so.5
OLD_LIBS+=usr/lib/libmenuw.so.5
OLD_LIBS+=usr/lib/libpanel.so.5
OLD_LIBS+=usr/lib/libpanelw.so.5
# 20210116: if_wl_wavelan.h removed
.if ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/include/machine/if_wl_wavelan.h
.endif
# 20210108: retire cmx, ng_bt3c, wi drivers
OLD_FILES+=usr/include/dev/wi/if_wireg.h
OLD_FILES+=usr/include/dev/wi/if_wavelan_ieee.h
OLD_FILES+=usr/include/dev/wi/if_wivar.h
OLD_FILES+=usr/sbin/bt3cfw
OLD_FILES+=usr/share/man/man4/cmw.4.gz
OLD_FILES+=usr/share/man/man4/if_wi.4.gz
OLD_FILES+=usr/share/man/man4/ng_bt3c.4.gz
OLD_FILES+=usr/share/man/man4/wi.4.gz
OLD_FILES+=usr/share/man/man8/bt3cfw.8.gz
# 20210107: retire a.out support
OLD_DIRS+=usr/lib/aout
OLD_DIRS+=usr/lib/compat/aout
# 20210107: remove cmx(4)
OLD_FILES+=usr/share/man/man4/cmx.4.gz
# 20210105: remove non widechar version of ncurses
OLD_LIBS+=lib/libncurses.so.9
# 20210103: new clang import which bumps version from 11.0.0 to 11.0.1
OLD_FILES+=usr/lib/clang/11.0.0/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/11.0.0/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/11.0.0/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/11.0.0/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/11.0.0/include/fuzzer/FuzzedDataProvider.h
OLD_DIRS+=usr/lib/clang/11.0.0/include/fuzzer
OLD_FILES+=usr/lib/clang/11.0.0/include/openmp_wrappers/__clang_openmp_device_functions.h
OLD_FILES+=usr/lib/clang/11.0.0/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/11.0.0/include/openmp_wrappers/complex
OLD_FILES+=usr/lib/clang/11.0.0/include/openmp_wrappers/complex.h
OLD_FILES+=usr/lib/clang/11.0.0/include/openmp_wrappers/math.h
OLD_FILES+=usr/lib/clang/11.0.0/include/openmp_wrappers/new
OLD_DIRS+=usr/lib/clang/11.0.0/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/pmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/smmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/tmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/11.0.0/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/11.0.0/include/profile/InstrProfData.inc
OLD_DIRS+=usr/lib/clang/11.0.0/include/profile
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/tsan_interface_atomic.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sanitizer/ubsan_interface.h
OLD_DIRS+=usr/lib/clang/11.0.0/include/sanitizer
OLD_FILES+=usr/lib/clang/11.0.0/include/xray/xray_interface.h
OLD_FILES+=usr/lib/clang/11.0.0/include/xray/xray_log_interface.h
OLD_FILES+=usr/lib/clang/11.0.0/include/xray/xray_records.h
OLD_DIRS+=usr/lib/clang/11.0.0/include/xray
OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_math.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_hip_libdevice_declares.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_hip_math.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__clang_hip_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/11.0.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/11.0.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/altivec.h
OLD_FILES+=usr/lib/clang/11.0.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/amxintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/arm64intr.h
OLD_FILES+=usr/lib/clang/11.0.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/11.0.0/include/arm_bf16.h
OLD_FILES+=usr/lib/clang/11.0.0/include/arm_cde.h
OLD_FILES+=usr/lib/clang/11.0.0/include/arm_cmse.h
OLD_FILES+=usr/lib/clang/11.0.0/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/11.0.0/include/arm_mve.h
OLD_FILES+=usr/lib/clang/11.0.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/11.0.0/include/arm_sve.h
OLD_FILES+=usr/lib/clang/11.0.0/include/armintr.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/cet.h
OLD_FILES+=usr/lib/clang/11.0.0/include/cetintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/11.0.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/htmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/11.0.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/11.0.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/11.0.0/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/msa.h
OLD_FILES+=usr/lib/clang/11.0.0/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/11.0.0/include/opencl-c.h
OLD_FILES+=usr/lib/clang/11.0.0/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/s390intrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/serializeintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/tsxldtrkintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/vadefs.h
OLD_FILES+=usr/lib/clang/11.0.0/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/vecintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/wasm_simd128.h
OLD_FILES+=usr/lib/clang/11.0.0/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/11.0.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/11.0.0/include
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-powerpc64le.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/11.0.0/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/11.0.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/11.0.0/lib
OLD_DIRS+=usr/lib/clang/11.0.0
# 20201225: PMC for Xscale removed
OLD_FILES+=usr/share/man/man3/pmc.xscale.3.gz
# 20201225: libregex removed
OLD_FILES+=usr/include/gnu/posix/regex.h
OLD_DIRS+=usr/include/gnu/posix
OLD_FILES+=usr/include/gnu/regex.h
OLD_DIRS+=usr/include/gnu
OLD_FILES+=usr/include/gnuregex.h
OLD_FILES+=usr/lib/libgnuregex.a
OLD_FILES+=usr/lib/libgnuregex.so
OLD_LIBS+=usr/lib/libgnuregex.so.5
OLD_FILES+=usr/lib/libgnuregex_p.a
# 20201225: gnugrep removed
OLD_FILES+=usr/bin/bsdgrep
OLD_FILES+=usr/bin/gnugrep
OLD_FILES+=usr/share/man/man1/bsdgrep.1.gz
OLD_FILES+=usr/share/man/man1/gnugrep.1.gz
# 20201224: mk48txx(4) removed
OLD_FILES+=usr/share/man/man4/mk48txx.4.gz
# 20201215: in-tree gdb removed
OLD_FILES+=usr/libexec/gdb
OLD_FILES+=usr/libexec/kgdb
# 20201211: hme(4) removed
OLD_FILES+=usr/share/man/man4/hme.4.gz
OLD_FILES+=usr/share/man/man4/if_hme.4.gz
# 20201124: ping6(8) was merged into ping(8)
OLD_FILES+=usr/share/man/man8/ping6.8.gz
OLD_FILES+=usr/tests/sbin/ping6/Kyuafile
OLD_FILES+=usr/tests/sbin/ping6/ping6_c1_s8_t1.out
OLD_FILES+=usr/tests/sbin/ping6/ping6_test
OLD_DIRS+=usr/tests/sbin/ping6
# 20201025: Remove cal data files
OLD_FILES+=usr/share/calendar/calendar.all
OLD_FILES+=usr/share/calendar/calendar.australia
OLD_FILES+=usr/share/calendar/calendar.birthday
OLD_FILES+=usr/share/calendar/calendar.brazilian
OLD_FILES+=usr/share/calendar/calendar.christian
OLD_FILES+=usr/share/calendar/calendar.computer
OLD_FILES+=usr/share/calendar/calendar.croatian
OLD_FILES+=usr/share/calendar/calendar.dutch
OLD_FILES+=usr/share/calendar/calendar.french
OLD_FILES+=usr/share/calendar/calendar.german
OLD_FILES+=usr/share/calendar/calendar.history
OLD_FILES+=usr/share/calendar/calendar.holiday
OLD_FILES+=usr/share/calendar/calendar.hungarian
OLD_FILES+=usr/share/calendar/calendar.judaic
OLD_FILES+=usr/share/calendar/calendar.lotr
OLD_FILES+=usr/share/calendar/calendar.music
OLD_FILES+=usr/share/calendar/calendar.newzealand
OLD_FILES+=usr/share/calendar/calendar.russian
OLD_FILES+=usr/share/calendar/calendar.southafrica
OLD_FILES+=usr/share/calendar/calendar.ukrainian
OLD_FILES+=usr/share/calendar/calendar.usholiday
OLD_FILES+=usr/share/calendar/calendar.world
OLD_FILES+=usr/share/calendar/de_AT.ISO_8859-15/calendar.feiertag
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.all
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.feiertag
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.geschichte
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.kirche
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.literatur
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.musik
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.wissenschaft
OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.all
OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.fetes
OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.french
OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.jferies
OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.proverbes
OLD_FILES+=usr/share/calendar/hr_HR.ISO8859-2/calendar.all
OLD_FILES+=usr/share/calendar/hr_HR.ISO8859-2/calendar.praznici
OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.all
OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.nevnapok
OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.unnepek
OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.all
OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.commemorative
OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.holidays
OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.mcommemorative
OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.all
OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.commemorative
OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.holidays
OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.mcommemorative
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.all
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.common
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.holiday
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.military
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.orthodox
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.pagan
OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.all
OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.common
OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.holiday
OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.military
OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.orthodox
OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.pagan
OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.all
OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.holiday
OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.misc
OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.orthodox
# 20201004: logo files renamed to type-agnostic gfx-*.lua
OLD_FILES+=boot/lua/logo-beastie.lua
OLD_FILES+=boot/lua/logo-beastiebw.lua
OLD_FILES+=boot/lua/logo-fbsdbw.lua
OLD_FILES+=boot/lua/logo-orb.lua
OLD_FILES+=boot/lua/logo-orbbw.lua
# 20200825: merged OpenZFS support
OLD_LIBS+=lib/libzfs.so.3
OLD_FILES+=usr/share/man/man1/zstreamdump.1.gz
#OLD_FILES+=usr/share/man/man7/zpool-features.7.gz
# 20200923: memfd_test moved to /usr/tests/sys/posixshm
OLD_FILES+=usr/tests/sys/kern/memfd_test
# 20200910: remove vm_map_create(9) to sync with the code
OLD_FILES+=usr/share/man/man9/vm_map_create.9.gz
# 20200820: Removal of the ufm driver
OLD_FILES+=usr/share/man/man4/ufm.4.gz
# 20200816: new clang import which bumps version from 10.0.1 to 11.0.0
OLD_FILES+=usr/lib/clang/10.0.1/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/10.0.1/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/10.0.1/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/10.0.1/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/10.0.1/include/fuzzer/FuzzedDataProvider.h
OLD_DIRS+=usr/lib/clang/10.0.1/include/fuzzer
OLD_FILES+=usr/lib/clang/10.0.1/include/openmp_wrappers/__clang_openmp_math.h
OLD_FILES+=usr/lib/clang/10.0.1/include/openmp_wrappers/__clang_openmp_math_declares.h
OLD_FILES+=usr/lib/clang/10.0.1/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/10.0.1/include/openmp_wrappers/math.h
OLD_DIRS+=usr/lib/clang/10.0.1/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/pmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/smmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/tmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/10.0.1/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/10.0.1/include/profile/InstrProfData.inc
OLD_DIRS+=usr/lib/clang/10.0.1/include/profile
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/tsan_interface_atomic.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/ubsan_interface.h
OLD_DIRS+=usr/lib/clang/10.0.1/include/sanitizer
OLD_FILES+=usr/lib/clang/10.0.1/include/xray/xray_interface.h
OLD_FILES+=usr/lib/clang/10.0.1/include/xray/xray_log_interface.h
OLD_FILES+=usr/lib/clang/10.0.1/include/xray/xray_records.h
OLD_DIRS+=usr/lib/clang/10.0.1/include/xray
OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/10.0.1/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/10.0.1/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/10.0.1/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/10.0.1/include/adxintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/altivec.h
OLD_FILES+=usr/lib/clang/10.0.1/include/ammintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/arm64intr.h
OLD_FILES+=usr/lib/clang/10.0.1/include/arm_acle.h
OLD_FILES+=usr/lib/clang/10.0.1/include/arm_cmse.h
OLD_FILES+=usr/lib/clang/10.0.1/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/10.0.1/include/arm_mve.h
OLD_FILES+=usr/lib/clang/10.0.1/include/arm_neon.h
OLD_FILES+=usr/lib/clang/10.0.1/include/armintr.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/avxintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/cetintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/cpuid.h
OLD_FILES+=usr/lib/clang/10.0.1/include/emmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/htmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/immintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/10.0.1/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/10.0.1/include/mmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/module.modulemap
OLD_FILES+=usr/lib/clang/10.0.1/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/msa.h
OLD_FILES+=usr/lib/clang/10.0.1/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/10.0.1/include/opencl-c.h
OLD_FILES+=usr/lib/clang/10.0.1/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/s390intrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/shaintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/smmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/vadefs.h
OLD_FILES+=usr/lib/clang/10.0.1/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/vecintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/x86intrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/xopintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/10.0.1/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/10.0.1/include
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/10.0.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/10.0.1/lib
OLD_DIRS+=usr/lib/clang/10.0.1
# 20200803: remove free_domain(9) and uma_zfree_domain(9)
OLD_FILES+=usr/share/man/man9/free_domain.9.gz
OLD_FILES+=usr/share/man/man9/uma_zfree_domain.9.gz
# 20200729: remove long expired serial drivers
OLD_FILES+=usr/share/man/man4/cy.4.gz
OLD_FILES+=usr/share/man/man4/rc.4.gz
OLD_FILES+=usr/share/man/man4/rp.4.gz
# 20200715: rework of devstat(9) man page
OLD_FILES+=usr/share/man/man9/devstat_add_entry.9.gz
# 20200714: update byacc to 20200330
OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_calc1.y
OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_demo.y
OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_destroy1.y
OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_destroy2.y
OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_destroy3.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit1.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit2.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit3.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit4.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit5.y
OLD_FILES+=usr/tests/usr.bin/yacc/inherit0.y
OLD_FILES+=usr/tests/usr.bin/yacc/inherit1.y
OLD_FILES+=usr/tests/usr.bin/yacc/inherit2.y
# 20200706: update of sglist(9), r360574
OLD_FILES+=usr/share/man/man9/sglist_append_ext_pgs.9.gz
OLD_FILES+=usr/share/man/man9/sglist_append_mb_ext_pgs.9.gz
OLD_FILES+=usr/share/man/man9/sglist_count_ext_pgs.9.gz
OLD_FILES+=usr/share/man/man9/sglist_count_mb_ext_pgs.9.gz
# 20200617: update opencsd to 0.14.2
OLD_FILES+=usr/include/opencsd/etmv4/trc_pkt_elem_etmv4d.h
# 20200606: retire binutils build infrastructure
.if !defined(WITH_PORT_BASE_BINUTILS)
OLD_FILES+=usr/bin/as
OLD_FILES+=usr/bin/ld.bfd
OLD_FILES+=usr/share/man/man1/as.1.gz
OLD_FILES+=usr/share/man/man1/ld.bfd.1.gz
OLD_FILES+=usr/share/man/man7/as.7.gz
OLD_FILES+=usr/share/man/man7/ld.7.gz
OLD_FILES+=usr/share/man/man7/ldint.7.gz
OLD_FILES+=usr/share/man/man7/binutils.7.gz
.endif
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/armelf_fbsd.xw
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/armelfb_fbsd.xw
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.x
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xbn
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xc
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xd
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xdc
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xdw
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xn
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xr
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xs
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xsc
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xsw
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xu
OLD_FILES+=usr/libdata/ldscripts/elf32_sparc.xw
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/elf32btsmip_fbsd.xw
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/elf32btsmipn32_fbsd.xw
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmip_fbsd.xw
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/elf32ltsmipn32_fbsd.xw
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/elf32ppc_fbsd.xw
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.x
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xbn
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xc
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xd
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xdc
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xdw
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xn
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xr
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xs
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xsc
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xsw
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xu
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc.xw
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/elf64_sparc_fbsd.xw
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/elf64btsmip_fbsd.xw
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/elf64ltsmip_fbsd.xw
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/elf64ppc_fbsd.xw
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/elf_i386_fbsd.xw
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.x
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xbn
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xc
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xd
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xdc
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xdw
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xn
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xr
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xs
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xsc
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xsw
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xu
OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xw
# 20200601: OpenSSL 32-bit compat engines moved to /usr/lib32/engines
OLD_LIBS+=usr/lib32/capi.so
OLD_LIBS+=usr/lib32/padlock.so
# 20200528: libevent renamed libevent1
OLD_FILES+=usr/include/private/event/event.h
OLD_FILES+=usr/lib/libprivateevent.a
OLD_FILES+=usr/lib/libprivateevent.so
OLD_LIBS+=usr/lib/libprivateevent.so.1
OLD_FILES+=usr/lib/libprivateevent_p.a
OLD_DIRS+=usr/include/private/event
# 20200523: new clang import which bumps version from 10.0.0 to 10.0.1
OLD_FILES+=usr/lib/clang/10.0.0/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/10.0.0/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/10.0.0/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/10.0.0/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/10.0.0/include/fuzzer/FuzzedDataProvider.h
OLD_DIRS+=usr/lib/clang/10.0.0/include/fuzzer
OLD_FILES+=usr/lib/clang/10.0.0/include/openmp_wrappers/__clang_openmp_math.h
OLD_FILES+=usr/lib/clang/10.0.0/include/openmp_wrappers/__clang_openmp_math_declares.h
OLD_FILES+=usr/lib/clang/10.0.0/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/10.0.0/include/openmp_wrappers/math.h
OLD_DIRS+=usr/lib/clang/10.0.0/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/pmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/smmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/tmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/10.0.0/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/10.0.0/include/profile/InstrProfData.inc
OLD_DIRS+=usr/lib/clang/10.0.0/include/profile
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/tsan_interface_atomic.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sanitizer/ubsan_interface.h
OLD_DIRS+=usr/lib/clang/10.0.0/include/sanitizer
OLD_FILES+=usr/lib/clang/10.0.0/include/xray/xray_interface.h
OLD_FILES+=usr/lib/clang/10.0.0/include/xray/xray_log_interface.h
OLD_FILES+=usr/lib/clang/10.0.0/include/xray/xray_records.h
OLD_DIRS+=usr/lib/clang/10.0.0/include/xray
OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/10.0.0/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/10.0.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/10.0.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/10.0.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/10.0.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/altivec.h
OLD_FILES+=usr/lib/clang/10.0.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/arm64intr.h
OLD_FILES+=usr/lib/clang/10.0.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/10.0.0/include/arm_cmse.h
OLD_FILES+=usr/lib/clang/10.0.0/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/10.0.0/include/arm_mve.h
OLD_FILES+=usr/lib/clang/10.0.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/10.0.0/include/armintr.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/cetintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/10.0.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/htmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/10.0.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/10.0.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/10.0.0/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/msa.h
OLD_FILES+=usr/lib/clang/10.0.0/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/10.0.0/include/opencl-c.h
OLD_FILES+=usr/lib/clang/10.0.0/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/s390intrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/vadefs.h
OLD_FILES+=usr/lib/clang/10.0.0/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/vecintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/10.0.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/10.0.0/include
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/10.0.0/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/10.0.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/10.0.0/lib
OLD_DIRS+=usr/lib/clang/10.0.0
# 20200520: xform_userland.h removed
OLD_FILES+=usr/include/crypto/xform_userland.h
# 20200515: libalias cuseeme protocol support retired
OLD_LIBS+=lib/libalias_cuseeme.so
OLD_FILES+=usr/lib/libalias_cuseeme.a
OLD_FILES+=usr/lib/libalias_cuseeme_p.a
# 20200511: Remove deprecated crypto algorithms
OLD_FILES+=usr/include/crypto/cast.h
OLD_FILES+=usr/include/crypto/castsb.h
OLD_FILES+=usr/include/crypto/skipjack.h
# 20200511: Remove ubsec(4)
OLD_FILES+=usr/share/man/man4/ubsec.4.gz
# 20200428: route_var.h moved to net/route
OLD_FILES+=usr/include/net/route_var.h
# 20200418: Make libauditd private
OLD_FILES+=usr/lib/libauditd.a
OLD_FILES+=usr/lib/libauditd.so
OLD_LIBS+=usr/lib/libauditd.so.5
OLD_FILES+=usr/lib/libauditd_p.a
# 20200418: Remove bogus man links
OLD_FILES+=usr/share/man/man3/getauusernam_R.3.gz
OLD_FILES+=usr/share/man/man3/getauclassnam_3.3.gz
# 20200414: NFS file handle affinity code for the NFS server re-organized
OLD_FILES+=usr/include/nfs/nfs_fha.h
# 20200401: Remove procfs-based process debugging
OLD_FILES+=usr/include/sys/pioctl.h
# 20200330: GDB_LIBEXEC option retired (always true)
OLD_FILES+=usr/bin/gdb
OLD_FILES+=usr/bin/gdbserver
OLD_FILES+=usr/bin/kgdb
OLD_FILES+=usr/share/man/man1/gdb.1.gz
OLD_FILES+=usr/share/man/man1/gdbserver.1.gz
OLD_FILES+=usr/share/man/man1/kgdb.1.gz
# 20200327: OCF refactoring
OLD_FILES+=usr/include/crypto/cryptosoft.h
OLD_FILES+=usr/share/man/man9/crypto_find_driver.9.gz
OLD_FILES+=usr/share/man/man9/crypto_register.9.gz
OLD_FILES+=usr/share/man/man9/crypto_unregister.9.gz
# 20200326: compat libs for libl are no longer built
OLD_FILES+=usr/lib32/libfl.a
OLD_FILES+=usr/lib32/libl.a
OLD_FILES+=usr/lib32/libln.a
# 20200323: INTERNALLIB don't install headers anymore
OLD_FILES+=usr/include/libelftc.h
OLD_FILES+=usr/include/libifconfig.h
OLD_FILES+=usr/include/libpmcstat.h
# 20200320: cx and ctau drivers retired
OLD_FILES+=usr/share/man/man4/ctau.4.gz
OLD_FILES+=usr/share/man/man4/cx.4.gz
# 20200318: host.conf was deprecated a long time ago
OLD_FILES+=etc/host.conf
OLD_FILES+=etc/rc.d/nsswitch
# 20200310: new clang import which bumps version from 9.0.1 to 10.0.0
OLD_FILES+=usr/lib/clang/9.0.1/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/9.0.1/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/9.0.1/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/9.0.1/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/9.0.1/include/openmp_wrappers/__clang_openmp_math.h
OLD_FILES+=usr/lib/clang/9.0.1/include/openmp_wrappers/__clang_openmp_math_declares.h
OLD_FILES+=usr/lib/clang/9.0.1/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/9.0.1/include/openmp_wrappers/math.h
OLD_DIRS+=usr/lib/clang/9.0.1/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/9.0.1/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/9.0.1/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/9.0.1/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/9.0.1/include/sanitizer
OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/9.0.1/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/9.0.1/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/9.0.1/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/9.0.1/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/9.0.1/include/adxintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/altivec.h
OLD_FILES+=usr/lib/clang/9.0.1/include/ammintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/arm64intr.h
OLD_FILES+=usr/lib/clang/9.0.1/include/arm_acle.h
OLD_FILES+=usr/lib/clang/9.0.1/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/9.0.1/include/arm_neon.h
OLD_FILES+=usr/lib/clang/9.0.1/include/armintr.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/avxintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/cetintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/cpuid.h
OLD_FILES+=usr/lib/clang/9.0.1/include/emmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/htmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/immintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/9.0.1/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/9.0.1/include/mmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/module.modulemap
OLD_FILES+=usr/lib/clang/9.0.1/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/msa.h
OLD_FILES+=usr/lib/clang/9.0.1/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/9.0.1/include/opencl-c.h
OLD_FILES+=usr/lib/clang/9.0.1/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/s390intrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/shaintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/smmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/vadefs.h
OLD_FILES+=usr/lib/clang/9.0.1/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/vecintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/x86intrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/xopintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/9.0.1/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/9.0.1/include
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.1/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/9.0.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/9.0.1/lib
OLD_DIRS+=usr/lib/clang/9.0.1
# 20200309: amd(8) retired
OLD_FILES+=etc/amd.map
OLD_FILES+=etc/newsyslog.conf.d/amd.conf
OLD_FILES+=etc/rc.d/amd
OLD_FILES+=usr/bin/pawd
OLD_FILES+=usr/sbin/amd
OLD_FILES+=usr/sbin/amq
OLD_FILES+=usr/sbin/fixmount
OLD_FILES+=usr/sbin/fsinfo
OLD_FILES+=usr/sbin/hlfsd
OLD_FILES+=usr/sbin/mk-amd-map
OLD_FILES+=usr/sbin/wire-test
OLD_FILES+=usr/share/examples/etc/amd.map
OLD_FILES+=usr/share/man/man1/pawd.1.gz
OLD_FILES+=usr/share/man/man5/amd.conf.5.gz
OLD_FILES+=usr/share/man/man8/amd.8.gz
OLD_FILES+=usr/share/man/man8/amq.8.gz
OLD_FILES+=usr/share/man/man8/fixmount.8.gz
OLD_FILES+=usr/share/man/man8/fsinfo.8.gz
OLD_FILES+=usr/share/man/man8/hlfsd.8.gz
OLD_FILES+=usr/share/man/man8/mk-amd-map.8.gz
OLD_FILES+=usr/share/man/man8/wire-test.8.gz
# 20200301: bktr removed
OLD_DIRS+=usr/include/dev/bktr
OLD_FILES+=usr/include/dev/bktr/ioctl_bktr.h
OLD_FILES+=usr/include/dev/bktr/ioctl_bt848.h
OLD_FILES+=usr/include/dev/bktr/ioctl_meteor.h
.if ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/include/machine/ioctl_bktr.h
OLD_FILES+=usr/include/machine/ioctl_meteor.h
.endif
OLD_FILES+=usr/share/man/man4/bktr.4.gz
OLD_FILES+=usr/share/man/man4/brooktree.4.gz
# 20200229: GCC 4.2.1 removed
.if !defined(WITH_PORT_BASE_GCC)
OLD_FILES+=usr/bin/g++
OLD_FILES+=usr/bin/gcc
OLD_FILES+=usr/share/man/man1/g++.1.gz
OLD_FILES+=usr/share/man/man1/gcc.1.gz
.endif
OLD_FILES+=usr/bin/gcpp
OLD_FILES+=usr/bin/gperf
OLD_FILES+=usr/include/c++/4.2/algorithm
OLD_FILES+=usr/include/c++/4.2/backward/algo.h
OLD_FILES+=usr/include/c++/4.2/backward/algobase.h
OLD_FILES+=usr/include/c++/4.2/backward/alloc.h
OLD_FILES+=usr/include/c++/4.2/backward/backward_warning.h
OLD_FILES+=usr/include/c++/4.2/backward/bvector.h
OLD_FILES+=usr/include/c++/4.2/backward/complex.h
OLD_FILES+=usr/include/c++/4.2/backward/defalloc.h
OLD_FILES+=usr/include/c++/4.2/backward/deque.h
OLD_FILES+=usr/include/c++/4.2/backward/fstream.h
OLD_FILES+=usr/include/c++/4.2/backward/function.h
OLD_FILES+=usr/include/c++/4.2/backward/hash_map.h
OLD_FILES+=usr/include/c++/4.2/backward/hash_set.h
OLD_FILES+=usr/include/c++/4.2/backward/hashtable.h
OLD_FILES+=usr/include/c++/4.2/backward/heap.h
OLD_FILES+=usr/include/c++/4.2/backward/iomanip.h
OLD_FILES+=usr/include/c++/4.2/backward/iostream.h
OLD_FILES+=usr/include/c++/4.2/backward/istream.h
OLD_FILES+=usr/include/c++/4.2/backward/iterator.h
OLD_FILES+=usr/include/c++/4.2/backward/list.h
OLD_FILES+=usr/include/c++/4.2/backward/map.h
OLD_FILES+=usr/include/c++/4.2/backward/multimap.h
OLD_FILES+=usr/include/c++/4.2/backward/multiset.h
OLD_FILES+=usr/include/c++/4.2/backward/new.h
OLD_FILES+=usr/include/c++/4.2/backward/ostream.h
OLD_FILES+=usr/include/c++/4.2/backward/pair.h
OLD_FILES+=usr/include/c++/4.2/backward/queue.h
OLD_FILES+=usr/include/c++/4.2/backward/rope.h
OLD_FILES+=usr/include/c++/4.2/backward/set.h
OLD_FILES+=usr/include/c++/4.2/backward/slist.h
OLD_FILES+=usr/include/c++/4.2/backward/stack.h
OLD_FILES+=usr/include/c++/4.2/backward/stream.h
OLD_FILES+=usr/include/c++/4.2/backward/streambuf.h
OLD_FILES+=usr/include/c++/4.2/backward/strstream
OLD_FILES+=usr/include/c++/4.2/backward/tempbuf.h
OLD_FILES+=usr/include/c++/4.2/backward/tree.h
OLD_FILES+=usr/include/c++/4.2/backward/vector.h
OLD_FILES+=usr/include/c++/4.2/bits/allocator.h
OLD_FILES+=usr/include/c++/4.2/bits/atomic_word.h
OLD_FILES+=usr/include/c++/4.2/bits/basic_file.h
OLD_FILES+=usr/include/c++/4.2/bits/basic_ios.h
OLD_FILES+=usr/include/c++/4.2/bits/basic_ios.tcc
OLD_FILES+=usr/include/c++/4.2/bits/basic_string.h
OLD_FILES+=usr/include/c++/4.2/bits/basic_string.tcc
OLD_FILES+=usr/include/c++/4.2/bits/boost_concept_check.h
OLD_FILES+=usr/include/c++/4.2/bits/c++allocator.h
OLD_FILES+=usr/include/c++/4.2/bits/c++config.h
OLD_FILES+=usr/include/c++/4.2/bits/c++io.h
OLD_FILES+=usr/include/c++/4.2/bits/c++locale.h
OLD_FILES+=usr/include/c++/4.2/bits/c++locale_internal.h
OLD_FILES+=usr/include/c++/4.2/bits/char_traits.h
OLD_FILES+=usr/include/c++/4.2/bits/cmath.tcc
OLD_FILES+=usr/include/c++/4.2/bits/codecvt.h
OLD_FILES+=usr/include/c++/4.2/bits/compatibility.h
OLD_FILES+=usr/include/c++/4.2/bits/concept_check.h
OLD_FILES+=usr/include/c++/4.2/bits/cpp_type_traits.h
OLD_FILES+=usr/include/c++/4.2/bits/cpu_defines.h
OLD_FILES+=usr/include/c++/4.2/bits/ctype_base.h
OLD_FILES+=usr/include/c++/4.2/bits/ctype_inline.h
OLD_FILES+=usr/include/c++/4.2/bits/ctype_noninline.h
OLD_FILES+=usr/include/c++/4.2/bits/cxxabi_tweaks.h
OLD_FILES+=usr/include/c++/4.2/bits/deque.tcc
OLD_FILES+=usr/include/c++/4.2/bits/fstream.tcc
OLD_FILES+=usr/include/c++/4.2/bits/functexcept.h
OLD_FILES+=usr/include/c++/4.2/bits/gslice.h
OLD_FILES+=usr/include/c++/4.2/bits/gslice_array.h
OLD_FILES+=usr/include/c++/4.2/bits/gthr-default.h
OLD_FILES+=usr/include/c++/4.2/bits/gthr-posix.h
OLD_FILES+=usr/include/c++/4.2/bits/gthr-single.h
OLD_FILES+=usr/include/c++/4.2/bits/gthr-tpf.h
OLD_FILES+=usr/include/c++/4.2/bits/gthr.h
OLD_FILES+=usr/include/c++/4.2/bits/indirect_array.h
OLD_FILES+=usr/include/c++/4.2/bits/ios_base.h
OLD_FILES+=usr/include/c++/4.2/bits/istream.tcc
OLD_FILES+=usr/include/c++/4.2/bits/list.tcc
OLD_FILES+=usr/include/c++/4.2/bits/locale_classes.h
OLD_FILES+=usr/include/c++/4.2/bits/locale_facets.h
OLD_FILES+=usr/include/c++/4.2/bits/locale_facets.tcc
OLD_FILES+=usr/include/c++/4.2/bits/localefwd.h
OLD_FILES+=usr/include/c++/4.2/bits/mask_array.h
OLD_FILES+=usr/include/c++/4.2/bits/messages_members.h
OLD_FILES+=usr/include/c++/4.2/bits/os_defines.h
OLD_FILES+=usr/include/c++/4.2/bits/ostream.tcc
OLD_FILES+=usr/include/c++/4.2/bits/ostream_insert.h
OLD_FILES+=usr/include/c++/4.2/bits/postypes.h
OLD_FILES+=usr/include/c++/4.2/bits/slice_array.h
OLD_FILES+=usr/include/c++/4.2/bits/sstream.tcc
OLD_FILES+=usr/include/c++/4.2/bits/stl_algo.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_algobase.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_bvector.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_construct.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_deque.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_function.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_heap.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_iterator.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_iterator_base_funcs.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_iterator_base_types.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_list.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_map.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_multimap.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_multiset.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_numeric.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_pair.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_queue.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_raw_storage_iter.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_relops.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_set.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_stack.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_tempbuf.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_tree.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_uninitialized.h
OLD_FILES+=usr/include/c++/4.2/bits/stl_vector.h
OLD_FILES+=usr/include/c++/4.2/bits/stream_iterator.h
OLD_FILES+=usr/include/c++/4.2/bits/streambuf.tcc
OLD_FILES+=usr/include/c++/4.2/bits/streambuf_iterator.h
OLD_FILES+=usr/include/c++/4.2/bits/stringfwd.h
OLD_FILES+=usr/include/c++/4.2/bits/time_members.h
OLD_FILES+=usr/include/c++/4.2/bits/valarray_after.h
OLD_FILES+=usr/include/c++/4.2/bits/valarray_array.h
OLD_FILES+=usr/include/c++/4.2/bits/valarray_array.tcc
OLD_FILES+=usr/include/c++/4.2/bits/valarray_before.h
OLD_FILES+=usr/include/c++/4.2/bits/vector.tcc
OLD_FILES+=usr/include/c++/4.2/bitset
OLD_FILES+=usr/include/c++/4.2/cassert
OLD_FILES+=usr/include/c++/4.2/cctype
OLD_FILES+=usr/include/c++/4.2/cerrno
OLD_FILES+=usr/include/c++/4.2/cfloat
OLD_FILES+=usr/include/c++/4.2/ciso646
OLD_FILES+=usr/include/c++/4.2/climits
OLD_FILES+=usr/include/c++/4.2/clocale
OLD_FILES+=usr/include/c++/4.2/cmath
OLD_FILES+=usr/include/c++/4.2/complex
OLD_FILES+=usr/include/c++/4.2/csetjmp
OLD_FILES+=usr/include/c++/4.2/csignal
OLD_FILES+=usr/include/c++/4.2/cstdarg
OLD_FILES+=usr/include/c++/4.2/cstddef
OLD_FILES+=usr/include/c++/4.2/cstdio
OLD_FILES+=usr/include/c++/4.2/cstdlib
OLD_FILES+=usr/include/c++/4.2/cstring
OLD_FILES+=usr/include/c++/4.2/ctime
OLD_FILES+=usr/include/c++/4.2/cwchar
OLD_FILES+=usr/include/c++/4.2/cwctype
OLD_FILES+=usr/include/c++/4.2/cxxabi.h
OLD_FILES+=usr/include/c++/4.2/debug/bitset
OLD_FILES+=usr/include/c++/4.2/debug/debug.h
OLD_FILES+=usr/include/c++/4.2/debug/deque
OLD_FILES+=usr/include/c++/4.2/debug/formatter.h
OLD_FILES+=usr/include/c++/4.2/debug/functions.h
OLD_FILES+=usr/include/c++/4.2/debug/hash_map
OLD_FILES+=usr/include/c++/4.2/debug/hash_map.h
OLD_FILES+=usr/include/c++/4.2/debug/hash_multimap.h
OLD_FILES+=usr/include/c++/4.2/debug/hash_multiset.h
OLD_FILES+=usr/include/c++/4.2/debug/hash_set
OLD_FILES+=usr/include/c++/4.2/debug/hash_set.h
OLD_FILES+=usr/include/c++/4.2/debug/list
OLD_FILES+=usr/include/c++/4.2/debug/macros.h
OLD_FILES+=usr/include/c++/4.2/debug/map
OLD_FILES+=usr/include/c++/4.2/debug/map.h
OLD_FILES+=usr/include/c++/4.2/debug/multimap.h
OLD_FILES+=usr/include/c++/4.2/debug/multiset.h
OLD_FILES+=usr/include/c++/4.2/debug/safe_base.h
OLD_FILES+=usr/include/c++/4.2/debug/safe_iterator.h
OLD_FILES+=usr/include/c++/4.2/debug/safe_iterator.tcc
OLD_FILES+=usr/include/c++/4.2/debug/safe_sequence.h
OLD_FILES+=usr/include/c++/4.2/debug/set
OLD_FILES+=usr/include/c++/4.2/debug/set.h
OLD_FILES+=usr/include/c++/4.2/debug/string
OLD_FILES+=usr/include/c++/4.2/debug/vector
OLD_FILES+=usr/include/c++/4.2/deque
OLD_FILES+=usr/include/c++/4.2/exception
OLD_FILES+=usr/include/c++/4.2/exception_defines.h
OLD_FILES+=usr/include/c++/4.2/ext/algorithm
OLD_FILES+=usr/include/c++/4.2/ext/array_allocator.h
OLD_FILES+=usr/include/c++/4.2/ext/atomicity.h
OLD_FILES+=usr/include/c++/4.2/ext/bitmap_allocator.h
OLD_FILES+=usr/include/c++/4.2/ext/codecvt_specializations.h
OLD_FILES+=usr/include/c++/4.2/ext/concurrence.h
OLD_FILES+=usr/include/c++/4.2/ext/debug_allocator.h
OLD_FILES+=usr/include/c++/4.2/ext/functional
OLD_FILES+=usr/include/c++/4.2/ext/hash_fun.h
OLD_FILES+=usr/include/c++/4.2/ext/hash_map
OLD_FILES+=usr/include/c++/4.2/ext/hash_set
OLD_FILES+=usr/include/c++/4.2/ext/hashtable.h
OLD_FILES+=usr/include/c++/4.2/ext/iterator
OLD_FILES+=usr/include/c++/4.2/ext/malloc_allocator.h
OLD_FILES+=usr/include/c++/4.2/ext/memory
OLD_FILES+=usr/include/c++/4.2/ext/mt_allocator.h
OLD_FILES+=usr/include/c++/4.2/ext/new_allocator.h
OLD_FILES+=usr/include/c++/4.2/ext/numeric
OLD_FILES+=usr/include/c++/4.2/ext/numeric_traits.h
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/assoc_container.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/basic_tree_policy/basic_tree_policy_base.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/basic_tree_policy/null_node_metadata.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/basic_tree_policy/traits.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/basic_types.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/bin_search_tree_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/cond_dtor_entry_dealtor.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/cond_key_dtor_entry_dealtor.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/find_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/info_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/iterators_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/node_iterators.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/point_iterators.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/policy_access_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/r_erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/rotate_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/split_join_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/traits.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/binary_heap_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/const_iterator.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/const_point_iterator.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/entry_cmp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/entry_pred.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/find_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/info_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/iterators_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/policy_access_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/resize_policy.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/split_join_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/trace_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_/binomial_heap_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/binomial_heap_base_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/find_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/split_join_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/cc_ht_map_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/cmp_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/cond_key_dtor_entry_dealtor.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/constructor_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/constructor_destructor_no_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/constructor_destructor_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/debug_no_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/debug_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/entry_list_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/erase_no_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/erase_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/find_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/find_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/info_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/insert_no_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/insert_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/iterators_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/policy_access_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/resize_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/resize_no_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/resize_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/size_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/standard_policies.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/trace_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cond_dealtor.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/container_base_dispatch.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/eq_fn/eq_by_less.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/eq_fn/hash_eq_fn.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/constructor_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/constructor_destructor_no_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/constructor_destructor_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/debug_no_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/debug_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/erase_no_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/erase_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/find_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/find_no_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/find_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/gp_ht_map_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/info_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/insert_no_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/insert_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/iterator_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/policy_access_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/resize_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/resize_no_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/resize_store_hash_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/standard_policies.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/trace_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/direct_mask_range_hashing_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/direct_mod_range_hashing_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/linear_probe_fn_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/mask_based_range_hashing.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/mod_based_range_hashing.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/probe_fn_base.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/quadratic_probe_fn_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/ranged_hash_fn.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/ranged_probe_fn.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/sample_probe_fn.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/sample_range_hashing.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/sample_ranged_hash_fn.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/sample_ranged_probe_fn.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/const_iterator.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/const_point_iterator.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/info_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/iterators_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/left_child_next_sibling_heap_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/node.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/null_metadata.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/policy_access_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/trace_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/constructor_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/entry_metadata_base.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/find_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/info_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/iterators_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/lu_map_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/trace_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy/counter_lu_metadata.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy/counter_lu_policy_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy/mtf_lu_policy_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy/sample_update_policy.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/map_debug_base.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/cond_dtor.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/info_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/iterators_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/node_iterators.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/ov_tree_map_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/policy_access_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/split_join_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/traits.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/find_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/pairing_heap_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/split_join_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/child_iterator.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/cond_dtor_entry_dealtor.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/const_child_iterator.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/find_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/head.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/info_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/insert_join_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/internal_node.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/iterators_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/leaf.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/node_base.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/node_iterators.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/node_metadata_base.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/pat_trie_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/point_iterators.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/policy_access_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/r_erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/rotate_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/split_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/split_join_branch_bag.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/synth_e_access_traits.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/trace_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/traits.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/update_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/priority_queue_base_dispatch.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/find_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/info_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/node.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/rb_tree_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/split_join_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/traits.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/rc.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/rc_binomial_heap_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/split_join_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/trace_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/cc_hash_max_collision_check_resize_trigger_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_exponential_size_policy_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_load_check_resize_trigger_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_load_check_resize_trigger_size_base.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_prime_size_policy_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_standard_resize_policy_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/sample_resize_policy.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/sample_resize_trigger.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/sample_size_policy.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/find_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/info_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/node.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/splay_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/splay_tree_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/split_join_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/traits.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/standard_policies.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/constructors_destructor_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/debug_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/erase_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/find_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/insert_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/split_join_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/thin_heap_.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/trace_fn_imps.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy/node_metadata_selector.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy/null_node_update_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy/order_statistics_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy/sample_tree_node_update.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_trace_base.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/node_metadata_selector.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/null_node_update_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/order_statistics_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/prefix_search_node_update_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/sample_trie_e_access_traits.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/sample_trie_node_update.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/string_trie_e_access_traits_imp.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/trie_policy_base.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/type_utils.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/types_traits.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator/const_iterator.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator/const_point_iterator.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator/iterator.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator/point_iterator.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/exception.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/hash_policy.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/list_update_policy.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/priority_queue.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/tag_and_trait.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/tree_policy.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/trie_policy.hpp
OLD_FILES+=usr/include/c++/4.2/ext/pod_char_traits.h
OLD_FILES+=usr/include/c++/4.2/ext/pool_allocator.h
OLD_FILES+=usr/include/c++/4.2/ext/rb_tree
OLD_FILES+=usr/include/c++/4.2/ext/rc_string_base.h
OLD_FILES+=usr/include/c++/4.2/ext/rope
OLD_FILES+=usr/include/c++/4.2/ext/ropeimpl.h
OLD_FILES+=usr/include/c++/4.2/ext/slist
OLD_FILES+=usr/include/c++/4.2/ext/sso_string_base.h
OLD_FILES+=usr/include/c++/4.2/ext/stdio_filebuf.h
OLD_FILES+=usr/include/c++/4.2/ext/stdio_sync_filebuf.h
OLD_FILES+=usr/include/c++/4.2/ext/throw_allocator.h
OLD_FILES+=usr/include/c++/4.2/ext/type_traits.h
OLD_FILES+=usr/include/c++/4.2/ext/typelist.h
OLD_FILES+=usr/include/c++/4.2/ext/vstring.h
OLD_FILES+=usr/include/c++/4.2/ext/vstring.tcc
OLD_FILES+=usr/include/c++/4.2/ext/vstring_fwd.h
OLD_FILES+=usr/include/c++/4.2/ext/vstring_util.h
OLD_FILES+=usr/include/c++/4.2/fstream
OLD_FILES+=usr/include/c++/4.2/functional
OLD_FILES+=usr/include/c++/4.2/iomanip
OLD_FILES+=usr/include/c++/4.2/ios
OLD_FILES+=usr/include/c++/4.2/iosfwd
OLD_FILES+=usr/include/c++/4.2/iostream
OLD_FILES+=usr/include/c++/4.2/istream
OLD_FILES+=usr/include/c++/4.2/iterator
OLD_FILES+=usr/include/c++/4.2/limits
OLD_FILES+=usr/include/c++/4.2/list
OLD_FILES+=usr/include/c++/4.2/locale
OLD_FILES+=usr/include/c++/4.2/map
OLD_FILES+=usr/include/c++/4.2/memory
OLD_FILES+=usr/include/c++/4.2/new
OLD_FILES+=usr/include/c++/4.2/numeric
OLD_FILES+=usr/include/c++/4.2/ostream
OLD_FILES+=usr/include/c++/4.2/queue
OLD_FILES+=usr/include/c++/4.2/set
OLD_FILES+=usr/include/c++/4.2/sstream
OLD_FILES+=usr/include/c++/4.2/stack
OLD_FILES+=usr/include/c++/4.2/stdexcept
OLD_FILES+=usr/include/c++/4.2/streambuf
OLD_FILES+=usr/include/c++/4.2/string
OLD_FILES+=usr/include/c++/4.2/tr1/array
OLD_FILES+=usr/include/c++/4.2/tr1/bind_iterate.h
OLD_FILES+=usr/include/c++/4.2/tr1/bind_repeat.h
OLD_FILES+=usr/include/c++/4.2/tr1/boost_shared_ptr.h
OLD_FILES+=usr/include/c++/4.2/tr1/cctype
OLD_FILES+=usr/include/c++/4.2/tr1/cfenv
OLD_FILES+=usr/include/c++/4.2/tr1/cfloat
OLD_FILES+=usr/include/c++/4.2/tr1/cinttypes
OLD_FILES+=usr/include/c++/4.2/tr1/climits
OLD_FILES+=usr/include/c++/4.2/tr1/cmath
OLD_FILES+=usr/include/c++/4.2/tr1/common.h
OLD_FILES+=usr/include/c++/4.2/tr1/complex
OLD_FILES+=usr/include/c++/4.2/tr1/cstdarg
OLD_FILES+=usr/include/c++/4.2/tr1/cstdbool
OLD_FILES+=usr/include/c++/4.2/tr1/cstdint
OLD_FILES+=usr/include/c++/4.2/tr1/cstdio
OLD_FILES+=usr/include/c++/4.2/tr1/cstdlib
OLD_FILES+=usr/include/c++/4.2/tr1/ctgmath
OLD_FILES+=usr/include/c++/4.2/tr1/ctime
OLD_FILES+=usr/include/c++/4.2/tr1/ctype.h
OLD_FILES+=usr/include/c++/4.2/tr1/cwchar
OLD_FILES+=usr/include/c++/4.2/tr1/cwctype
OLD_FILES+=usr/include/c++/4.2/tr1/fenv.h
OLD_FILES+=usr/include/c++/4.2/tr1/float.h
OLD_FILES+=usr/include/c++/4.2/tr1/functional
OLD_FILES+=usr/include/c++/4.2/tr1/functional_hash.h
OLD_FILES+=usr/include/c++/4.2/tr1/functional_iterate.h
OLD_FILES+=usr/include/c++/4.2/tr1/hashtable
OLD_FILES+=usr/include/c++/4.2/tr1/hashtable_policy.h
OLD_FILES+=usr/include/c++/4.2/tr1/inttypes.h
OLD_FILES+=usr/include/c++/4.2/tr1/limits.h
OLD_FILES+=usr/include/c++/4.2/tr1/math.h
OLD_FILES+=usr/include/c++/4.2/tr1/memory
OLD_FILES+=usr/include/c++/4.2/tr1/mu_iterate.h
OLD_FILES+=usr/include/c++/4.2/tr1/random
OLD_FILES+=usr/include/c++/4.2/tr1/random.tcc
OLD_FILES+=usr/include/c++/4.2/tr1/ref_fwd.h
OLD_FILES+=usr/include/c++/4.2/tr1/ref_wrap_iterate.h
OLD_FILES+=usr/include/c++/4.2/tr1/repeat.h
OLD_FILES+=usr/include/c++/4.2/tr1/stdarg.h
OLD_FILES+=usr/include/c++/4.2/tr1/stdbool.h
OLD_FILES+=usr/include/c++/4.2/tr1/stdint.h
OLD_FILES+=usr/include/c++/4.2/tr1/stdio.h
OLD_FILES+=usr/include/c++/4.2/tr1/stdlib.h
OLD_FILES+=usr/include/c++/4.2/tr1/tgmath.h
OLD_FILES+=usr/include/c++/4.2/tr1/tuple
OLD_FILES+=usr/include/c++/4.2/tr1/tuple_defs.h
OLD_FILES+=usr/include/c++/4.2/tr1/tuple_iterate.h
OLD_FILES+=usr/include/c++/4.2/tr1/type_traits
OLD_FILES+=usr/include/c++/4.2/tr1/type_traits_fwd.h
OLD_FILES+=usr/include/c++/4.2/tr1/unordered_map
OLD_FILES+=usr/include/c++/4.2/tr1/unordered_set
OLD_FILES+=usr/include/c++/4.2/tr1/utility
OLD_FILES+=usr/include/c++/4.2/tr1/wchar.h
OLD_FILES+=usr/include/c++/4.2/tr1/wctype.h
OLD_FILES+=usr/include/c++/4.2/typeinfo
OLD_FILES+=usr/include/c++/4.2/utility
OLD_FILES+=usr/include/c++/4.2/valarray
OLD_FILES+=usr/include/c++/4.2/vector
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/include/gcc/4.2/__wmmintrin_aes.h
OLD_FILES+=usr/include/gcc/4.2/__wmmintrin_pclmul.h
OLD_FILES+=usr/include/gcc/4.2/ammintrin.h
OLD_FILES+=usr/include/gcc/4.2/emmintrin.h
OLD_FILES+=usr/include/gcc/4.2/mm3dnow.h
OLD_FILES+=usr/include/gcc/4.2/mm_malloc.h
OLD_FILES+=usr/include/gcc/4.2/mmintrin.h
OLD_FILES+=usr/include/gcc/4.2/pmmintrin.h
OLD_FILES+=usr/include/gcc/4.2/tmmintrin.h
OLD_FILES+=usr/include/gcc/4.2/wmmintrin.h
OLD_FILES+=usr/include/gcc/4.2/xmmintrin.h
.elif ${TARGET_ARCH} == "arm"
OLD_FILES+=usr/include/gcc/4.2/mmintrin.h
.elif ${TARGET_ARCH} == "powerpc" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/include/gcc/4.2/altivec.h
OLD_FILES+=usr/include/gcc/4.2/ppc-asm.h
OLD_FILES+=usr/include/gcc/4.2/spe.h
.endif
OLD_FILES+=usr/lib/libgcov.a
OLD_FILES+=usr/lib/libgomp.a
OLD_FILES+=usr/lib/libstdc++.a
OLD_FILES+=usr/lib/libstdc++.so
OLD_LIBS+=usr/lib/libstdc++.so.6
OLD_FILES+=usr/lib/libstdc++_p.a
OLD_FILES+=usr/lib/libsupc++.a
OLD_FILES+=usr/lib/libsupc++.so
OLD_LIBS+=usr/lib/libsupc++.so.1
OLD_FILES+=usr/lib/libsupc++_p.a
OLD_LIBS+=usr/lib/libgomp.so.1
OLD_FILES+=usr/lib/libgomp_p.a
OLD_FILES+=usr/libexec/cc1
OLD_FILES+=usr/libexec/cc1plus
OLD_FILES+=usr/share/man/man1/gcpp.1.gz
OLD_FILES+=usr/share/man/man1/gperf.1.gz
OLD_FILES+=usr/share/man/man7/gperf.7.gz
# 20200220: Upgrade of ncurses, shlib bumped to version 9
OLD_LIBS+=lib/libncurses.so.8
OLD_LIBS+=lib/libncursesw.so.8
# 20200206: Remove elf2aout
OLD_FILES+=usr/bin/elf2aout
OLD_FILES+=usr/share/man/man1/elf2aout.1.gz
# 20200204: simple_httpd removed
OLD_FILES+=usr/sbin/simple_httpd
# 20200127: vpo removed
OLD_FILES+=usr/share/man/man4/imm.4.gz
OLD_FILES+=usr/share/man/man4/vpo.4.gz
# 20200104: gcc libssp removed
OLD_FILES+=usr/include/ssp/ssp.h
OLD_FILES+=usr/include/ssp/stdio.h
OLD_FILES+=usr/include/ssp/string.h
OLD_FILES+=usr/include/ssp/unistd.h
OLD_DIRS+=usr/include/ssp
OLD_FILES+=usr/lib/libssp.a
# 20191229: GEOM_SCHED class and gsched tool removed
OLD_LIBS+=lib/geom/geom_sched.so
OLD_FILES+=sbin/gsched
OLD_FILES+=usr/share/man/man8/gsched.8.gz
# 20191222: new clang import which bumps version from 9.0.0 to 9.0.1
OLD_FILES+=usr/lib/clang/9.0.0/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/9.0.0/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/9.0.0/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/9.0.0/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/9.0.0/include/openmp_wrappers/__clang_openmp_math.h
OLD_FILES+=usr/lib/clang/9.0.0/include/openmp_wrappers/__clang_openmp_math_declares.h
OLD_FILES+=usr/lib/clang/9.0.0/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/9.0.0/include/openmp_wrappers/math.h
OLD_DIRS+=usr/lib/clang/9.0.0/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/9.0.0/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/9.0.0/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/9.0.0/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/9.0.0/include/sanitizer
OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/9.0.0/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/9.0.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/9.0.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/9.0.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/9.0.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/altivec.h
OLD_FILES+=usr/lib/clang/9.0.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/arm64intr.h
OLD_FILES+=usr/lib/clang/9.0.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/9.0.0/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/9.0.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/9.0.0/include/armintr.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/cetintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/9.0.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/htmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/9.0.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/9.0.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/9.0.0/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/msa.h
OLD_FILES+=usr/lib/clang/9.0.0/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/9.0.0/include/opencl-c.h
OLD_FILES+=usr/lib/clang/9.0.0/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/s390intrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/vadefs.h
OLD_FILES+=usr/lib/clang/9.0.0/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/vecintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/9.0.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/9.0.0/include
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/9.0.0/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/9.0.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/9.0.0/lib
OLD_DIRS+=usr/lib/clang/9.0.0
# 20191221: Update libpcap from 1.9.0 to 1.9.1
OLD_FILES+=usr/share/man/man3/pcap_set_immediate_mode.3.gz
OLD_FILES+=usr/share/man/man3/pcap_set_protocol.3.gz
# 20191214: Removal of sranddev(3)
OLD_FILES+=usr/share/man/man3/sranddev.3.gz
# 20191213: Renamed (BIT|CPU)_NAND to (BIT|CPU)_ANDNOT
OLD_FILES+=usr/share/man/man9/BIT_NAND.9.gz
OLD_FILES+=usr/share/man/man9/CPU_NAND.9.gz
# 20191213: remove timeout(9)
OLD_FILES+=usr/share/man/man9/callout_handle_init.9.gz
OLD_FILES+=usr/share/man/man9/timeout.9.gz
OLD_FILES+=usr/share/man/man9/untimeout.9.gz
# 20191128: Removal of trm(4)
OLD_FILES+=usr/share/man/man4/trm.4.gz
# 20191121: Removal of sio(4)
OLD_FILES+=usr/share/man/man4/sio.4.gz
# 20191105: picobsd(8), et al, removed
OLD_FILES+=usr/share/man/man8/picobsd.8.gz
# 20191017: taskqueue_start_threads_pinned became taskqueue_start_threads_cpuset
OLD_FILES+=usr/share/man/man9/taskqueue_start_threads_pinned.9.gz
# 20191009: new clang import which bumps version from 8.0.1 to 9.0.0.
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/esan_interface.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/8.0.1/include/sanitizer
OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/8.0.1/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/8.0.1/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/8.0.1/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/8.0.1/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/8.0.1/include/adxintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/altivec.h
OLD_FILES+=usr/lib/clang/8.0.1/include/ammintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/arm64intr.h
OLD_FILES+=usr/lib/clang/8.0.1/include/arm_acle.h
OLD_FILES+=usr/lib/clang/8.0.1/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/8.0.1/include/arm_neon.h
OLD_FILES+=usr/lib/clang/8.0.1/include/armintr.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/avxintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/cetintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/cpuid.h
OLD_FILES+=usr/lib/clang/8.0.1/include/emmintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/htmintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/immintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/8.0.1/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/8.0.1/include/mmintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/module.modulemap
OLD_FILES+=usr/lib/clang/8.0.1/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/msa.h
OLD_FILES+=usr/lib/clang/8.0.1/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/opencl-c.h
OLD_FILES+=usr/lib/clang/8.0.1/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/s390intrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/shaintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/smmintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/vadefs.h
OLD_FILES+=usr/lib/clang/8.0.1/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/vecintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/x86intrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/xopintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/8.0.1/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/8.0.1/include
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/8.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/8.0.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/8.0.1/lib
OLD_DIRS+=usr/lib/clang/8.0.1
# 20191009: libc++ 9.0.0 removed some experimental files
OLD_FILES+=usr/include/c++/v1/experimental/any
OLD_FILES+=usr/include/c++/v1/experimental/chrono
OLD_FILES+=usr/include/c++/v1/experimental/numeric
OLD_FILES+=usr/include/c++/v1/experimental/optional
OLD_FILES+=usr/include/c++/v1/experimental/ratio
OLD_FILES+=usr/include/c++/v1/experimental/string_view
OLD_FILES+=usr/include/c++/v1/experimental/system_error
OLD_FILES+=usr/include/c++/v1/experimental/tuple
OLD_FILES+=usr/lib/libc++fs.a
# 20191003: Remove useless ZFS tests
OLD_FILES+=usr/tests/sys/cddl/zfs/tests/cli_root/zpool_create/zpool_create_013_neg.ksh
OLD_FILES+=usr/tests/sys/cddl/zfs/tests/cli_root/zpool_create/zpool_create_014_neg.ksh
OLD_FILES+=usr/tests/sys/cddl/zfs/tests/cli_root/zpool_create/zpool_create_016_pos.ksh
# 20190910: mklocale(1) and colldef(1) removed
OLD_FILES+=usr/bin/mklocale
OLD_FILES+=usr/share/man/man1/mklocale.1.gz
OLD_FILES+=usr/bin/colldef
OLD_FILES+=usr/share/man/man1/colldef.1.gz
# 20190909: vm_map_unwire(9) removed
OLD_FILES+=usr/share/man/man9/vm_map_unwire.9.gz
# 20190904: Remove boot1.efifat and gptboot.efifat (which never should have been)
OLD_FILES+=boot/boot1.efifat
OLD_FILES+=boot/gptboot.efifat
# 20190903: pc-sysinstall(8) removed
OLD_FILES+=usr/share/examples/pc-sysinstall/README
OLD_FILES+=usr/share/examples/pc-sysinstall/pc-autoinstall.conf
OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.fbsd-netinstall
OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.geli
OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.gmirror
OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.netinstall
OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.restore
OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.rsync
OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.upgrade
OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.zfs
OLD_FILES+=usr/share/man/man8/pc-sysinstall.8.gz
OLD_FILES+=usr/share/pc-sysinstall/backend-partmanager/create-part.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-partmanager/delete-part.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/detect-emulation.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/detect-laptop.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/detect-nics.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/disk-info.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/disk-list.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/disk-part.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/enable-net.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/get-packages.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-components.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-config.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-mirrors.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-packages.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-rsync-backups.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-tzones.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/query-langs.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/send-logs.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/setup-ssh-keys.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/set-mirror.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/sys-mem.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/test-live.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/test-netup.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/update-part-list.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/xkeyboard-layouts.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/xkeyboard-models.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/xkeyboard-variants.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-bsdlabel.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-cleanup.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-disk.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-extractimage.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-ftp.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-installcomponents.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-installpackages.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-localize.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-mountdisk.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-mountoptical.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-networking.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-newfs.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-parse.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-packages.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-runcommands.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-unmount.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-upgrade.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions-users.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/functions.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/installimage.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/parseconfig.sh
OLD_FILES+=usr/share/pc-sysinstall/backend/startautoinstall.sh
OLD_FILES+=usr/share/pc-sysinstall/conf/avail-langs
OLD_FILES+=usr/share/pc-sysinstall/conf/exclude-from-upgrade
OLD_FILES+=usr/share/pc-sysinstall/conf/license/bsd-en.txt
OLD_FILES+=usr/share/pc-sysinstall/conf/license/intel-en.txt
OLD_FILES+=usr/share/pc-sysinstall/conf/license/nvidia-en.txt
OLD_FILES+=usr/share/pc-sysinstall/conf/pc-sysinstall.conf
OLD_FILES+=usr/share/pc-sysinstall/doc/help-disk-list
OLD_FILES+=usr/share/pc-sysinstall/doc/help-disk-size
OLD_FILES+=usr/share/pc-sysinstall/doc/help-index
OLD_FILES+=usr/share/pc-sysinstall/doc/help-start-autoinstall
OLD_FILES+=usr/sbin/pc-sysinstall
OLD_DIRS+=usr/share/examples/pc-sysinstall
OLD_DIRS+=usr/share/pc-sysinstall/backend
OLD_DIRS+=usr/share/pc-sysinstall/backend-partmanager
OLD_DIRS+=usr/share/pc-sysinstall/backend-query
OLD_DIRS+=usr/share/pc-sysinstall/conf/license
OLD_DIRS+=usr/share/pc-sysinstall/conf
OLD_DIRS+=usr/share/pc-sysinstall/doc
OLD_DIRS+=usr/share/pc-sysinstall
# 20190825: zlib 1.0.4 removed from kernel
OLD_FILES+=usr/include/sys/zlib.h
OLD_FILES+=usr/include/sys/zutil.h
# 20190817: pft_ping.py and sniffer.py moved to /usr/tests/sys/netpfil/common
OLD_FILES+=usr/tests/sys/netpfil/pf/sniffer.py
OLD_FILES+=usr/tests/sys/netpfil/pf/pft_ping.py
# 20190816: dir.h removed from POSIX
OLD_FILES+=usr/include/sys/dir.h
# 20190813: deprecated GEOM classes removed
OLD_FILES+=usr/share/man/man4/geom_fox.4.gz
# 20190729: gzip'ed a.out support removed
OLD_FILES+=usr/include/sys/inflate.h
# 20190722: cap_random(3) removed
OLD_LIBS+=lib/casper/libcap_random.so.1
OLD_FILES+=usr/include/casper/cap_random.h
OLD_LIBS+=usr/lib/casper/libcap_random.so
OLD_FILES+=usr/share/man/man3/libcap_random.3.gz
OLD_FILES+=usr/share/man/man3/cap_random.3.gz
OLD_FILES+=usr/share/man/man3/cap_random_buf.3.gz
# 20190708: vm_page_hold() and _unhold() removed
OLD_FILES+=usr/share/man/man9/vm_page_hold.9.gz
OLD_FILES+=usr/share/man/man9/vm_page_unhold.9.gz
# 20190625: Remove NAND and NANDFS support
OLD_FILES+=usr/share/man/man4/nand.4.gz
OLD_FILES+=usr/share/man/man4/nandsim.4.gz
# 20190618: sys/capability.h removed (sys/capsicum.h is the one to use)
OLD_FILES+=usr/include/sys/capability.h
# 20190615: sys/pwm.h renamed to dev/pwmc.h
OLD_FILES+=usr/include/sys/pwm.h
# 20190612: new clang import which bumps version from 8.0.0 to 8.0.1
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/esan_interface.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/8.0.0/include/sanitizer
OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/8.0.0/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/8.0.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/8.0.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/8.0.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/8.0.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/altivec.h
OLD_FILES+=usr/lib/clang/8.0.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/arm64intr.h
OLD_FILES+=usr/lib/clang/8.0.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/8.0.0/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/8.0.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/8.0.0/include/armintr.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/cetintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/8.0.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/htmintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/8.0.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/8.0.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/8.0.0/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/msa.h
OLD_FILES+=usr/lib/clang/8.0.0/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/opencl-c.h
OLD_FILES+=usr/lib/clang/8.0.0/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/s390intrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/vadefs.h
OLD_FILES+=usr/lib/clang/8.0.0/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/vecintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/8.0.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/8.0.0/include
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/8.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/8.0.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/8.0.0/lib
OLD_DIRS+=usr/lib/clang/8.0.0
# 20190523: Remove obsolete kgzip and support files
OLD_FILES+=usr/sbin/kgzip
OLD_FILES+=usr/lib/kgzldr.o
OLD_FILES+=usr/share/man/man8/kgzip.8.gz
# 20190517: Remove obsolete 10 and 10/100 ethernet drivers
OLD_FILES+=usr/share/man/man4/bm.4.gz
OLD_FILES+=usr/share/man/man4/cs.4.gz
OLD_FILES+=usr/share/man/man4/de.4.gz
OLD_FILES+=usr/share/man/man4/if_de.4.gz
OLD_FILES+=usr/share/man/man4/ed.4.gz
OLD_FILES+=usr/share/man/man4/if_ed.4.gz
OLD_FILES+=usr/share/man/man4/ep.4.gz
OLD_FILES+=usr/share/man/man4/ex.4.gz
OLD_FILES+=usr/share/man/man4/fe.4.gz
OLD_FILES+=usr/share/man/man4/pcn.4.gz
OLD_FILES+=usr/share/man/man4/if_pcn.4.gz
OLD_FILES+=usr/share/man/man4/sf.4.gz
OLD_FILES+=usr/share/man/man4/if_sf.4.gz
OLD_FILES+=usr/share/man/man4/sn.4.gz
OLD_FILES+=usr/share/man/man4/if_sn.4.gz
OLD_FILES+=usr/share/man/man4/tl.4.gz
OLD_FILES+=usr/share/man/man4/if_tl.4.gz
OLD_FILES+=usr/share/man/man4/tx.4.gz
OLD_FILES+=usr/share/man/man4/if_tx.4.gz
OLD_FILES+=usr/share/man/man4/txp.4.gz
OLD_FILES+=usr/share/man/man4/if_txp.4.gz
OLD_FILES+=usr/share/man/man4/vx.4.gz
OLD_FILES+=usr/share/man/man4/wb.4.gz
OLD_FILES+=usr/share/man/man4/if_wb.4.gz
OLD_FILES+=usr/share/man/man4/xe.4.gz
OLD_FILES+=usr/share/man/man4/if_xe.4.gz
# 20190513: libcap_sysctl interface change
OLD_LIBS+=lib/casper/libcap_sysctl.so.1
# 20190509: tests/sys/opencrypto requires the net/py-dpkt package
OLD_FILES+=usr/tests/sys/opencrypto/dpkt.py
OLD_FILES+=usr/tests/sys/opencrypto/dpkt.pyc
# 20190304: new libc++ import which bumps version from 7.0.1 to 8.0.0
OLD_FILES+=usr/include/c++/v1/experimental/dynarray
# 20190304: new clang import which bumps version from 7.0.1 to 8.0.0
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/esan_interface.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/7.0.1/include/sanitizer
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/7.0.1/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/7.0.1/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/7.0.1/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/7.0.1/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/7.0.1/include/adxintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/altivec.h
OLD_FILES+=usr/lib/clang/7.0.1/include/ammintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/arm64intr.h
OLD_FILES+=usr/lib/clang/7.0.1/include/arm_acle.h
OLD_FILES+=usr/lib/clang/7.0.1/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/7.0.1/include/arm_neon.h
OLD_FILES+=usr/lib/clang/7.0.1/include/armintr.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/avxintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/cetintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/cpuid.h
OLD_FILES+=usr/lib/clang/7.0.1/include/emmintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/htmintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/immintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/7.0.1/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/7.0.1/include/mmintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/module.modulemap
OLD_FILES+=usr/lib/clang/7.0.1/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/msa.h
OLD_FILES+=usr/lib/clang/7.0.1/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/opencl-c.h
OLD_FILES+=usr/lib/clang/7.0.1/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/s390intrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/shaintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/smmintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/vadefs.h
OLD_FILES+=usr/lib/clang/7.0.1/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/vecintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/x86intrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/xopintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/7.0.1/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/7.0.1/include
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/7.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/7.0.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/7.0.1/lib
OLD_DIRS+=usr/lib/clang/7.0.1
# 20190227: rename seq.h to seqc.h
OLD_FILES+=usr/include/sys/seq.h
# 20190222: libifconfig made INTERNALLIB
OLD_FILES+=usr/lib/libprivateifconfig.a
OLD_FILES+=usr/lib/libprivateifconfig_p.a
# 20190131: pfil(9) changed
OLD_FILES+=usr/share/man/man9/pfil_hook_get.9.gz
OLD_FILES+=usr/share/man/man9/pfil_rlock.9.gz
OLD_FILES+=usr/share/man/man9/pfil_runlock.9.gz
OLD_FILES+=usr/share/man/man9/pfil_wlock.9.gz
OLD_FILES+=usr/share/man/man9/pfil_wunlock.9.gz
# 20190126: adv(4) / adw(4) removal
OLD_FILES+=usr/share/man/man4/adv.4.gz
OLD_FILES+=usr/share/man/man4/adw.4.gz
# 20190123: nonexistant cred_update_thread(9) removed
OLD_FILES+=usr/share/man/man9/cred_update_thread.9.gz
# 20190114: old pbuf allocator removed
OLD_FILES+=usr/share/man/man9/getpbuf.9.gz
OLD_FILES+=usr/share/man/man9/pbuf.9.gz
OLD_FILES+=usr/share/man/man9/relpbuf.9.gz
OLD_FILES+=usr/share/man/man9/trypbuf.9.gz
# 20181219: ibcs removal
OLD_FILES+=usr/share/examples/ibcs2/hello.uu
OLD_FILES+=usr/share/examples/ibcs2/README
OLD_DIRS+=usr/share/examples/ibcs2
# 20181215: Migration of CTM to ports
OLD_FILES+=usr/sbin/ctm
OLD_FILES+=usr/sbin/ctm_dequeue
OLD_FILES+=usr/sbin/ctm_rmail
OLD_FILES+=usr/sbin/ctm_smail
OLD_FILES+=usr/share/man/man1/ctm.1.gz
OLD_FILES+=usr/share/man/man1/ctm_dequeue.1.gz
OLD_FILES+=usr/share/man/man1/ctm_rmail.1.gz
OLD_FILES+=usr/share/man/man1/ctm_smail.1.gz
OLD_FILES+=usr/share/man/man5/ctm.5.gz
# 20181214: Remove timed files
OLD_FILES+=etc/rc.d/timed
OLD_FILES+=usr/sbin/timed
OLD_FILES+=usr/sbin/timedc
OLD_FILES+=usr/share/man/man8/timed.8.gz
OLD_FILES+=usr/share/man/man8/timedc.8.gz
# 20181211: new clang import which bumps version from 6.0.1 to 7.0.1
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/esan_interface.h
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/6.0.1/include/sanitizer
OLD_FILES+=usr/lib/clang/6.0.1/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/6.0.1/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/6.0.1/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/6.0.1/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/6.0.1/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/6.0.1/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/6.0.1/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/6.0.1/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/6.0.1/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/6.0.1/include/adxintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/altivec.h
OLD_FILES+=usr/lib/clang/6.0.1/include/ammintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/arm64intr.h
OLD_FILES+=usr/lib/clang/6.0.1/include/arm_acle.h
OLD_FILES+=usr/lib/clang/6.0.1/include/arm_neon.h
OLD_FILES+=usr/lib/clang/6.0.1/include/armintr.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/avxintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/cetintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/cpuid.h
OLD_FILES+=usr/lib/clang/6.0.1/include/emmintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/htmintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/immintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/6.0.1/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/6.0.1/include/mmintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/module.modulemap
OLD_FILES+=usr/lib/clang/6.0.1/include/msa.h
OLD_FILES+=usr/lib/clang/6.0.1/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/opencl-c.h
OLD_FILES+=usr/lib/clang/6.0.1/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/s390intrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/shaintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/smmintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/vadefs.h
OLD_FILES+=usr/lib/clang/6.0.1/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/vecintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/x86intrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/xopintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/6.0.1/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/6.0.1/include
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/6.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/6.0.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/6.0.1/lib
OLD_DIRS+=usr/lib/clang/6.0.1
# 20181116: Rename test file
OLD_FILES+=usr/tests/sys/netinet/reuseport_lb
# 20181113: libufs version bumped to 7
OLD_LIBS+=lib/libufs.so.6
# 20181112: Cleanup old libcap_dns
OLD_LIBS+=lib/casper/libcap_dns.so.1
# 20181030: malloc_domain(9) KPI change
OLD_FILES+=usr/share/man/man9/malloc_domain.9.gz
# 20181026: joy(4) removal
OLD_FILES+=usr/share/man/man4/joy.4.gz
# 20181025: OpenSSL libraries version bump to avoid conflict with ports
OLD_LIBS+=lib/libcrypto.so.9
OLD_LIBS+=usr/lib/libssl.so.9
# 20181022: aha(4) removal
OLD_FILES+=usr/share/man/man4/aha.4.gz
# 20181022: dpt(4) removal
OLD_FILES+=usr/share/man/man4/dpt.4.gz
# 20181022: ncr(4) removal
OLD_FILES+=usr/share/man/man4/ncr.4.gz
# 20181022: ncv(4) removal
OLD_FILES+=usr/share/man/man4/ncv.4.gz
# 20181022: nsp(4) removal
OLD_FILES+=usr/share/man/man4/nsp.4.gz
# 20181022: stg(4) removal
OLD_FILES+=usr/share/man/man4/stg.4.gz
# 20181021: mse(4) removal
OLD_FILES+=usr/share/man/man4/mse.4.gz
# 20181015: Stale libcasper(3) files following r329452
OLD_LIBS+=lib/casper/libcap_sysctl.so.0
OLD_LIBS+=lib/casper/libcap_grp.so.0
OLD_LIBS+=lib/casper/libcap_pwd.so.0
OLD_LIBS+=lib/casper/libcap_random.so.0
OLD_LIBS+=lib/casper/libcap_dns.so.0
OLD_LIBS+=lib/casper/libcap_syslog.so.0
# 20181012: rename of ixlv(4) to iavf(4)
OLD_FILES+=usr/share/man/man4/if_ixlv.4.gz
OLD_FILES+=usr/share/man/man4/ixlv.4.gz
# 20181009: OpenSSL 1.1.1
OLD_FILES+=usr/include/openssl/des_old.h
OLD_FILES+=usr/include/openssl/dso.h
OLD_FILES+=usr/include/openssl/krb5_asn.h
OLD_FILES+=usr/include/openssl/kssl.h
OLD_FILES+=usr/include/openssl/pqueue.h
OLD_FILES+=usr/include/openssl/ssl23.h
OLD_FILES+=usr/include/openssl/ui_compat.h
OLD_FILES+=usr/share/openssl/man/man1/dss1.1.gz
OLD_FILES+=usr/share/openssl/man/man1/md2.1.gz
OLD_FILES+=usr/share/openssl/man/man1/md4.1.gz
OLD_FILES+=usr/share/openssl/man/man1/md5.1.gz
OLD_FILES+=usr/share/openssl/man/man1/mdc2.1.gz
OLD_FILES+=usr/share/openssl/man/man1/ripemd160.1.gz
OLD_FILES+=usr/share/openssl/man/man1/sha.1.gz
OLD_FILES+=usr/share/openssl/man/man1/sha1.1.gz
OLD_FILES+=usr/share/openssl/man/man1/sha224.1.gz
OLD_FILES+=usr/share/openssl/man/man1/sha256.1.gz
OLD_FILES+=usr/share/openssl/man/man1/sha384.1.gz
OLD_FILES+=usr/share/openssl/man/man1/sha512.1.gz
OLD_FILES+=usr/share/openssl/man/man1/x509v3_config.1.gz
OLD_FILES+=usr/share/openssl/man/man3/ASN1_STRING_length_set.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BIO_get_conn_int_port.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BIO_get_conn_ip.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BIO_set.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BIO_set_conn_int_port.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BIO_set_conn_ip.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BN_BLINDING_get_thread_id.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BN_BLINDING_set_thread_id.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BN_BLINDING_thread_id.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BN_CTX_init.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BN_MONT_CTX_init.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BN_RECP_CTX_init.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BN_init.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BUF_memdup.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BUF_memdup.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BUF_strdup.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BUF_strlcat.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BUF_strlcpy.3.gz
OLD_FILES+=usr/share/openssl/man/man3/BUF_strndup.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CMS_set1_signer_cert.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_THREADID_cmp.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_THREADID_cpy.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_THREADID_current.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_THREADID_get_callback.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_THREADID_hash.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_THREADID_set_callback.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_destroy_dynlockid.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_get_new_dynlockid.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_lock.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_num_locks.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_set_dynlock_create_callback.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_set_dynlock_destroy_callback.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_set_dynlock_lock_callback.3.gz
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_set_locking_callback.3.gz
OLD_FILES+=usr/share/openssl/man/man3/DES_ede3_cbcm_encrypt.3.gz
OLD_FILES+=usr/share/openssl/man/man3/DES_enc_read.3.gz
OLD_FILES+=usr/share/openssl/man/man3/DES_enc_write.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EC_KEY_get_key_method_data.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EC_KEY_insert_key_method_data.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EC_POINT_set_Jprojective_coordinates.3.gz
OLD_FILES+=usr/share/openssl/man/man3/ERR_load_UI_strings.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_CIPHER_CTX_cleanup.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_CIPHER_CTX_init.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_MAX_MD_SIZE.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_MD_CTX_cleanup.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_MD_CTX_create.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_MD_CTX_destroy.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_MD_CTX_init.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_PKEVP_PKEY_CTX_set_app_data.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_PKEY_CTX_set_rsa_rsa_keygen_bits.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_PKEY_get_default_digest.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_dss.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_dss1.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_sha.3.gz
OLD_FILES+=usr/share/openssl/man/man3/HMAC_CTX_cleanup.3.gz
OLD_FILES+=usr/share/openssl/man/man3/HMAC_CTX_init.3.gz
OLD_FILES+=usr/share/openssl/man/man3/HMAC_cleanup.3.gz
OLD_FILES+=usr/share/openssl/man/man3/OPENSSL_ia32cap_loc.3.gz
OLD_FILES+=usr/share/openssl/man/man3/PEM.3.gz
OLD_FILES+=usr/share/openssl/man/man3/RAND_SSLeay.3.gz
OLD_FILES+=usr/share/openssl/man/man3/RSA_PKCS1_SSLeay.3.gz
OLD_FILES+=usr/share/openssl/man/man3/RSA_null_method.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_CTX_get_ex_new_index.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_CTX_need_tmp_rsa.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_CTX_set_custom_cli_ext.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_CTX_set_default_read_ahead.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_CTX_set_ecdh_auto.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_CTX_set_tmp_rsa.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_CTX_set_tmp_rsa_callback.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_SESSION_get_ex_new_index.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_add_session.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_flush_sessions.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_get_accept_state.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_get_ex_new_index.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_get_msg_callback_arg.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_need_tmp_rsa.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_remove_session.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_set_ecdh_auto.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_set_tmp_rsa.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSL_set_tmp_rsa_callback.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSLeay.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSLeay_add_ssl_algorithms.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSLeay_version.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSLv2_client_method.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSLv2_method.3.gz
OLD_FILES+=usr/share/openssl/man/man3/SSLv2_server_method.3.gz
OLD_FILES+=usr/share/openssl/man/man3/X509_STORE_CTX_set_chain.3.gz
OLD_FILES+=usr/share/openssl/man/man3/X509_STORE_CTX_trusted_stack.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bio.3.gz
OLD_FILES+=usr/share/openssl/man/man3/blowfish.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_add_words.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_check_top.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_cmp_words.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_div_words.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_dump.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_expand.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_expand2.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_fix_top.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_internal.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_mul_add_words.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_mul_comba4.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_mul_comba8.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_mul_high.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_mul_low_normal.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_mul_low_recursive.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_mul_normal.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_mul_part_recursive.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_mul_recursive.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_mul_words.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_print.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_set_high.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_set_low.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_set_max.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_sqr_comba4.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_sqr_comba8.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_sqr_normal.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_sqr_recursive.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_sqr_words.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_sub_words.3.gz
OLD_FILES+=usr/share/openssl/man/man3/bn_wexpand.3.gz
OLD_FILES+=usr/share/openssl/man/man3/buffer.3.gz
OLD_FILES+=usr/share/openssl/man/man3/crypto.3.gz
OLD_FILES+=usr/share/openssl/man/man3/d2i_ECPKParameters_bio.3.gz
OLD_FILES+=usr/share/openssl/man/man3/d2i_ECPKParameters_fp.3.gz
OLD_FILES+=usr/share/openssl/man/man3/d2i_ECPrivate_key.3.gz
OLD_FILES+=usr/share/openssl/man/man3/d2i_Netscape_RSA.3.gz
OLD_FILES+=usr/share/openssl/man/man3/d2i_PKCS8PrivateKey.3.gz
OLD_FILES+=usr/share/openssl/man/man3/d2i_Private_key.3.gz
OLD_FILES+=usr/share/openssl/man/man3/des.3.gz
OLD_FILES+=usr/share/openssl/man/man3/des_read_2passwords.3.gz
OLD_FILES+=usr/share/openssl/man/man3/des_read_password.3.gz
OLD_FILES+=usr/share/openssl/man/man3/des_read_pw.3.gz
OLD_FILES+=usr/share/openssl/man/man3/des_read_pw_string.3.gz
OLD_FILES+=usr/share/openssl/man/man3/dh.3.gz
OLD_FILES+=usr/share/openssl/man/man3/dsa.3.gz
OLD_FILES+=usr/share/openssl/man/man3/ec.3.gz
OLD_FILES+=usr/share/openssl/man/man3/ecdsa.3.gz
OLD_FILES+=usr/share/openssl/man/man3/engine.3.gz
OLD_FILES+=usr/share/openssl/man/man3/err.3.gz
OLD_FILES+=usr/share/openssl/man/man3/evp.3.gz
OLD_FILES+=usr/share/openssl/man/man3/hmac.3.gz
OLD_FILES+=usr/share/openssl/man/man3/i2d_ECPKParameters_bio.3.gz
OLD_FILES+=usr/share/openssl/man/man3/i2d_ECPKParameters_fp.3.gz
OLD_FILES+=usr/share/openssl/man/man3/i2d_Netscape_RSA.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_delete.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_doall.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_doall_arg.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_error.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_free.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_insert.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_new.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_node_stats.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_node_stats_bio.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_node_usage_stats.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_node_usage_stats_bio.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_retrieve.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_stats.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lh_stats_bio.3.gz
OLD_FILES+=usr/share/openssl/man/man3/lhash.3.gz
OLD_FILES+=usr/share/openssl/man/man3/md5.3.gz
OLD_FILES+=usr/share/openssl/man/man3/mdc2.3.gz
OLD_FILES+=usr/share/openssl/man/man3/pem.3.gz
OLD_FILES+=usr/share/openssl/man/man3/rand.3.gz
OLD_FILES+=usr/share/openssl/man/man3/rc4.3.gz
OLD_FILES+=usr/share/openssl/man/man3/ripemd.3.gz
OLD_FILES+=usr/share/openssl/man/man3/rsa.3.gz
OLD_FILES+=usr/share/openssl/man/man3/sha.3.gz
OLD_FILES+=usr/share/openssl/man/man3/ssl.3.gz
OLD_FILES+=usr/share/openssl/man/man3/threads.3.gz
OLD_FILES+=usr/share/openssl/man/man3/ui.3.gz
OLD_FILES+=usr/share/openssl/man/man3/ui_compat.3.gz
OLD_FILES+=usr/share/openssl/man/man3/x509.3.gz
OLD_LIBS+=lib/libcrypto.so.8
OLD_LIBS+=usr/lib/engines/lib4758cca.so
OLD_LIBS+=usr/lib/engines/libaep.so
OLD_LIBS+=usr/lib/engines/libatalla.so
OLD_LIBS+=usr/lib/engines/libcapi.so
OLD_LIBS+=usr/lib/engines/libchil.so
OLD_LIBS+=usr/lib/engines/libcswift.so
OLD_LIBS+=usr/lib/engines/libgost.so
OLD_LIBS+=usr/lib/engines/libnuron.so
OLD_LIBS+=usr/lib/engines/libsureware.so
OLD_LIBS+=usr/lib/engines/libubsec.so
OLD_LIBS+=usr/lib/libssl.so.8
OLD_LIBS+=usr/lib32/lib4758cca.so
OLD_LIBS+=usr/lib32/libaep.so
OLD_LIBS+=usr/lib32/libatalla.so
OLD_LIBS+=usr/lib32/libcapi.so
OLD_LIBS+=usr/lib32/libchil.so
OLD_LIBS+=usr/lib32/libcswift.so
OLD_LIBS+=usr/lib32/libgost.so
OLD_LIBS+=usr/lib32/libnuron.so
OLD_LIBS+=usr/lib32/libsureware.so
OLD_LIBS+=usr/lib32/libubsec.so
# 20180824: libbe(3) SHLIBDIR fixed to reflect correct location
MOVED_LIBS+=usr/lib/libbe.so.1
# 20180819: Remove deprecated arc4random(3) stir/addrandom interfaces
OLD_FILES+=usr/share/man/man3/arc4random_addrandom.3.gz
OLD_FILES+=usr/share/man/man3/arc4random_stir.3.gz
# 20180819: send-pr(1) placeholder removal
OLD_FILES+=usr/bin/send-pr
# 20180801: jedec_ts(4) removed
OLD_FILES+=usr/share/man/man4/jedec_ts.4.gz
# 20180725: Cleanup old libcasper.so.0
OLD_LIBS+=lib/libcasper.so.0
# 20180722: indent(1) option renamed, test files follow
OLD_FILES+=usr/bin/indent/tests/nsac.0
OLD_FILES+=usr/bin/indent/tests/nsac.0.pro
OLD_FILES+=usr/bin/indent/tests/nsac.0.stdout
OLD_FILES+=usr/bin/indent/tests/sac.0
OLD_FILES+=usr/bin/indent/tests/sac.0.pro
OLD_FILES+=usr/bin/indent/tests/sac.0.stdout
# 20180721: move of libmlx5.so.1 and libibverbs.so.1
MOVED_LIBS+=usr/lib/libmlx5.so.1
MOVED_LIBS+=usr/lib/libibverbs.so.1
# 20180720: zfsloader.8 merged into loader.8
OLD_FILES+=usr/share/man/man8/zfsloader.8.gz
# 20180710: old numa cleanup
OLD_FILES+=usr/include/sys/numa.h
OLD_FILES+=usr/share/man/man2/numa_getaffinity.2.gz
OLD_FILES+=usr/share/man/man2/numa_setaffinity.2.gz
OLD_FILES+=usr/share/man/man1/numactl.1.gz
OLD_FILES+=usr/bin/numactl
# 20180630: new clang import which bumps version from 6.0.0 to 6.0.1
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/esan_interface.h
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/6.0.0/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/6.0.0/include/sanitizer
OLD_FILES+=usr/lib/clang/6.0.0/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/6.0.0/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/6.0.0/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/6.0.0/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/6.0.0/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/6.0.0/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/6.0.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/6.0.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/6.0.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/6.0.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/altivec.h
OLD_FILES+=usr/lib/clang/6.0.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/arm64intr.h
OLD_FILES+=usr/lib/clang/6.0.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/6.0.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/6.0.0/include/armintr.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/cetintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/6.0.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/htmintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/6.0.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/6.0.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/6.0.0/include/msa.h
OLD_FILES+=usr/lib/clang/6.0.0/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/opencl-c.h
OLD_FILES+=usr/lib/clang/6.0.0/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/s390intrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/vadefs.h
OLD_FILES+=usr/lib/clang/6.0.0/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/vecintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/6.0.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/6.0.0/include
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/6.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/6.0.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/6.0.0/lib
OLD_DIRS+=usr/lib/clang/6.0.0
# 20180615: asf(8) removed
OLD_FILES+=usr/sbin/asf
OLD_FILES+=usr/share/man/man8/asf.8.gz
# 20180609: obsolete libc++ files missed from the 5.0.0 import
OLD_FILES+=usr/include/c++/v1/__refstring
OLD_FILES+=usr/include/c++/v1/__undef_min_max
OLD_FILES+=usr/include/c++/v1/tr1/__refstring
OLD_FILES+=usr/include/c++/v1/tr1/__undef_min_max
# 20180607: remove nls support from grep
OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/grep.cat
OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/grep.cat
OLD_FILES+=usr/share/nls/ja_JP.SJIS/grep.cat
OLD_FILES+=usr/share/nls/ja_JP.eucJP/grep.cat
OLD_FILES+=usr/share/nls/gl_ES.ISO8859-1/grep.cat
OLD_FILES+=usr/share/nls/zh_CN.UTF-8/grep.cat
OLD_FILES+=usr/share/nls/es_ES.ISO8859-1/grep.cat
OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/grep.cat
OLD_FILES+=usr/share/nls/uk_UA.UTF-8/grep.cat
OLD_FILES+=usr/share/nls/ja_JP.UTF-8/grep.cat
# 20180528: libpcap update removed header file
OLD_FILES+=usr/include/pcap/export-defs.h
# 20180517: retire vxge
OLD_FILES+=usr/share/man/man4/if_vxge.4.gz
OLD_FILES+=usr/share/man/man4/vxge.4.gz
# 20180512: Rename Unbound tools
OLD_FILES+=usr/sbin/unbound
OLD_FILES+=usr/sbin/unbound-anchor
OLD_FILES+=usr/sbin/unbound-checkconf
OLD_FILES+=usr/sbin/unbound-control
OLD_FILES+=usr/share/man/man5/unbound.conf.5.gz
OLD_FILES+=usr/share/man/man8/unbound-anchor.8.gz
OLD_FILES+=usr/share/man/man8/unbound-checkconf.8.gz
OLD_FILES+=usr/share/man/man8/unbound-control.8.gz
OLD_FILES+=usr/share/man/man8/unbound.8.gz
# 20180508: retire nxge
OLD_FILES+=usr/share/man/man4/if_nxge.4.gz
OLD_FILES+=usr/share/man/man4/nxge.4.gz
# 20180505: rhosts
OLD_FILES+=usr/share/skel/dot.rhosts
# 20180502: retire ixgb
OLD_FILES+=usr/share/man/man4/if_ixgb.4.gz
OLD_FILES+=usr/share/man/man4/ixgb.4.gz
# 20180501: retire lmc
OLD_FILES+=usr/include/dev/lmc/if_lmc.h
OLD_DIRS+=usr/include/dev/lmc
OLD_FILES+=usr/sbin/lmcconfig
OLD_FILES+=usr/share/man/man4/lmc.4.gz
OLD_FILES+=usr/share/man/man4/if_lmc.4.gz
OLD_FILES+=usr/share/man/man8/lmcconfig.8.gz
# 20180417: remove fuswintr and suswintr
OLD_FILES+=usr/share/man/man9/fuswintr.9.gz
OLD_FILES+=usr/share/man/man9/suswintr.9.gz
# 20180413: remove Arcnet support
OLD_FILES+=usr/include/net/if_arc.h
OLD_FILES+=usr/share/man/man4/cm.4.gz
# 20180409: remove FDDI support
OLD_FILES+=usr/include/net/fddi.h
OLD_FILES+=usr/share/man/man4/fpa.4.gz
# 20180319: remove /boot/overlays, replaced by /boot/dtb/overlays
OLD_DIRS+=boot/overlays
# 20180311: remove sys/sys/i386/include/pcaudioio.h
.if ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/include/machine/pcaudioio.h
.endif
# 20180310: remove sys/sys/dataacq.h
OLD_FILES+=usr/include/sys/dataacq.h
# 20180306: remove DTrace scripts made obsolete by dwatch(1)
OLD_FILES+=usr/share/dtrace/watch_execve
OLD_FILES+=usr/share/dtrace/watch_kill
OLD_FILES+=usr/share/dtrace/watch_vop_remove
# 20180212: move devmatch
OLD_FILES+=usr/sbin/devmatch
# 20180211: remove usb.conf
OLD_FILES+=etc/devd/usb.conf
# 20180208: remove c_rehash(1)
OLD_FILES+=usr/share/openssl/man/man1/c_rehash.1.gz
# 20180206: remove gdbtui
OLD_FILES+=usr/bin/gdbtui
# 20180201: Obsolete forth files
OLD_FILES+=boot/pcibios.4th
# 20180114: new clang import which bumps version from 5.0.1 to 6.0.0
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/esan_interface.h
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/5.0.1/include/sanitizer
OLD_FILES+=usr/lib/clang/5.0.1/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/5.0.1/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/5.0.1/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/5.0.1/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/5.0.1/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/5.0.1/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/5.0.1/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/5.0.1/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/5.0.1/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/5.0.1/include/adxintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/altivec.h
OLD_FILES+=usr/lib/clang/5.0.1/include/ammintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/arm_acle.h
OLD_FILES+=usr/lib/clang/5.0.1/include/arm_neon.h
OLD_FILES+=usr/lib/clang/5.0.1/include/armintr.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/avxintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/cpuid.h
OLD_FILES+=usr/lib/clang/5.0.1/include/emmintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/htmintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/immintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/5.0.1/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/5.0.1/include/mmintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/module.modulemap
OLD_FILES+=usr/lib/clang/5.0.1/include/msa.h
OLD_FILES+=usr/lib/clang/5.0.1/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/opencl-c.h
OLD_FILES+=usr/lib/clang/5.0.1/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/s390intrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/shaintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/smmintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/vadefs.h
OLD_FILES+=usr/lib/clang/5.0.1/include/vecintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/x86intrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/xopintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/5.0.1/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/5.0.1/include
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/5.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/5.0.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/5.0.1/lib
OLD_DIRS+=usr/lib/clang/5.0.1
# 20180109: Remove vestiges of digi(4) driver
OLD_FILES+=usr/include/sys/digiio.h
OLD_FILES+=usr/sbin/digictl
OLD_FILES+=usr/share/man/man8/digictl.8.gz
# 20180107: Convert remaining geli(8) tests to ATF
OLD_FILES+=tests/sys/geom/class/eli/nokey_test.sh
OLD_FILES+=tests/sys/geom/class/eli/readonly_test.sh
# 20180106: Convert most geli(8) tests to ATF
OLD_FILES+=tests/sys/geom/class/eli/attach_d_test.sh
OLD_FILES+=tests/sys/geom/class/eli/configure_b_B_test.sh
OLD_FILES+=tests/sys/geom/class/eli/detach_l_test.sh
OLD_FILES+=tests/sys/geom/class/eli/init_B_test.sh
OLD_FILES+=tests/sys/geom/class/eli/init_J_test.sh
OLD_FILES+=tests/sys/geom/class/eli/init_a_test.sh
OLD_FILES+=tests/sys/geom/class/eli/init_alias_test.sh
OLD_FILES+=tests/sys/geom/class/eli/init_i_P_test.sh
OLD_FILES+=tests/sys/geom/class/eli/integrity_copy_test.sh
OLD_FILES+=tests/sys/geom/class/eli/integrity_data_test.sh
OLD_FILES+=tests/sys/geom/class/eli/integrity_hmac_test.sh
OLD_FILES+=tests/sys/geom/class/eli/onetime_a_test.sh
OLD_FILES+=tests/sys/geom/class/eli/onetime_d_test.sh
# 20171230: Remove /etc/skel from mtree
OLD_DIRS+=etc/skel
# 20171208: Remove basename_r(3)
OLD_FILES+=usr/share/man/man3/basename_r.3.gz
# 20171204: Move fdformat man page from volume 1 to volume 8
OLD_FILES+=usr/share/man/man1/fdformat.1.gz
# 20171203: libproc version bump
OLD_LIBS+=usr/lib/libproc.so.4
# 20171203: new clang import which bumps version from 5.0.0 to 5.0.1
OLD_FILES+=usr/lib/clang/5.0.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/5.0.0/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/5.0.0/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/5.0.0/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/5.0.0/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/5.0.0/include/sanitizer/esan_interface.h
OLD_FILES+=usr/lib/clang/5.0.0/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/5.0.0/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/5.0.0/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/5.0.0/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/5.0.0/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/5.0.0/include/sanitizer
OLD_FILES+=usr/lib/clang/5.0.0/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/5.0.0/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/5.0.0/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/5.0.0/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/5.0.0/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/5.0.0/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/5.0.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/5.0.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/5.0.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/5.0.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/altivec.h
OLD_FILES+=usr/lib/clang/5.0.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/5.0.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/5.0.0/include/armintr.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/5.0.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/htmintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/5.0.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/5.0.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/5.0.0/include/msa.h
OLD_FILES+=usr/lib/clang/5.0.0/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/opencl-c.h
OLD_FILES+=usr/lib/clang/5.0.0/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/s390intrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/vadefs.h
OLD_FILES+=usr/lib/clang/5.0.0/include/vecintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/5.0.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/5.0.0/include
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/5.0.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/5.0.0/lib
OLD_DIRS+=usr/lib/clang/5.0.0
# 20171118: Remove old etc casper files
OLD_FILES+=etc/casper/system.dns
OLD_FILES+=etc/casper/system.grp
OLD_FILES+=etc/casper/system.pwd
OLD_FILES+=etc/casper/system.random
OLD_FILES+=etc/casper/system.sysctl
OLD_DIRS+=etc/casper
# 20171116: lint(1) removal
OLD_FILES+=usr/bin/lint
OLD_FILES+=usr/libexec/lint1
OLD_FILES+=usr/libexec/lint2
OLD_FILES+=usr/libdata/lint/llib-lposix.ln
OLD_FILES+=usr/libdata/lint/llib-lstdc.ln
OLD_FILES+=usr/share/man/man1/lint.1.gz
OLD_FILES+=usr/share/man/man7/lint.7.gz
OLD_DIRS+=usr/libdata/lint
# 20171114: Removal of all fortune datfiles other than freebsd-tips
OLD_FILES+=usr/share/games/fortune/fortunes
OLD_FILES+=usr/share/games/fortune/fortunes.dat
OLD_FILES+=usr/share/games/fortune/gerrold.limerick
OLD_FILES+=usr/share/games/fortune/gerrold.limerick.dat
OLD_FILES+=usr/share/games/fortune/limerick
OLD_FILES+=usr/share/games/fortune/limerick.dat
OLD_FILES+=usr/share/games/fortune/murphy
OLD_FILES+=usr/share/games/fortune/murphy-o
OLD_FILES+=usr/share/games/fortune/murphy-o.dat
OLD_FILES+=usr/share/games/fortune/murphy.dat
OLD_FILES+=usr/share/games/fortune/startrek
OLD_FILES+=usr/share/games/fortune/startrek.dat
OLD_FILES+=usr/share/games/fortune/zippy
OLD_FILES+=usr/share/games/fortune/zippy.dat
# 20171112: Removal of eqnchar definition
OLD_FILES+=usr/share/misc/eqnchar
# 20171110: Removal of mailaddr man page
OLD_FILES+=usr/share/man/man7/mailaddr.7.gz
# 20171108: Rename of NgSendMsgReply to NgSendReplyMsg
OLD_FILES+=usr/share/man/man3/NgSendMsgReply.3.gz
# 20171108: badsect(8) removal
OLD_FILES+=sbin/badsect
OLD_FILES+=rescue/badsect
OLD_FILES+=usr/share/man/man8/badsect.8.gz
# 20171105: fixing lib/libclang_rt CRTARCH for arm:armv[67]
.if ${MACHINE_ARCH:Marmv[67]*} != "" && \
(!defined(CPUTYPE) || ${CPUTYPE:M*soft*} == "")
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.asan-arm.a
OLD_LIBS+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.safestack-arm.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/5.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
.endif
# 20171104: libcap_random should be in /lib not in /usr/lib
OLD_LIBS+=usr/lib/libcap_random.so.0
# 20171104: Casper can work only as shared library
OLD_FILES+=usr/lib/libcap_dns.a
OLD_FILES+=usr/lib/libcap_dns_p.a
OLD_FILES+=usr/lib/libcap_grp.a
OLD_FILES+=usr/lib/libcap_grp_p.a
OLD_FILES+=usr/lib/libcap_pwd.a
OLD_FILES+=usr/lib/libcap_pwd_p.a
OLD_FILES+=usr/lib/libcap_random.a
OLD_FILES+=usr/lib/libcap_random_p.a
OLD_FILES+=usr/lib/libcap_sysctl.a
OLD_FILES+=usr/lib/libcap_sysctl_p.a
OLD_FILES+=usr/lib/libcasper.a
OLD_FILES+=usr/lib/libcasper_p.a
# 20171031: Removal of adding_user man page
OLD_FILES+=usr/share/man/man7/adding_user.7.gz
# 20171031: Disconnected libpathconv tests
OLD_DIRS+=usr/tests/lib/libpathconv
# 20171017: Removal of mbpool(9)
OLD_FILES+=usr/include/sys/mbpool.h
OLD_FILES+=usr/share/man/man9/mbpool.9.gz
OLD_FILES+=usr/share/man/man9/mbp_destroy.9.gz
OLD_FILES+=usr/share/man/man9/mbp_alloc.9.gz
OLD_FILES+=usr/share/man/man9/mbp_ext_free.9.gz
OLD_FILES+=usr/share/man/man9/mbp_count.9.gz
OLD_FILES+=usr/share/man/man9/mbp_card_free.9.gz
OLD_FILES+=usr/share/man/man9/mbp_get_keep.9.gz
OLD_FILES+=usr/share/man/man9/mbp_free.9.gz
OLD_FILES+=usr/share/man/man9/mbp_get.9.gz
OLD_FILES+=usr/share/man/man9/mbp_create.9.gz
OLD_FILES+=usr/share/man/man9/mbp_sync.9.gz
# 20171010: Remove libstand
OLD_FILES+=usr/lib/libstand.a
OLD_FILES+=usr/lib/libstand_p.a
OLD_FILES+=usr/include/stand.h
OLD_FILES+=usr/share/man/man3/libstand.3.gz
# 20171003: remove RCMDS
OLD_FILES+=bin/rcp
OLD_FILES+=rescue/rcp
OLD_FILES+=usr/bin/rlogin
OLD_FILES+=usr/bin/rsh
OLD_FILES+=usr/libexec/rlogind
OLD_FILES+=usr/libexec/rshd
OLD_FILES+=usr/share/man/man1/rcp.1.gz
OLD_FILES+=usr/share/man/man1/rlogin.1.gz
OLD_FILES+=usr/share/man/man1/rsh.1.gz
OLD_FILES+=usr/share/man/man8/rlogind.8.gz
OLD_FILES+=usr/share/man/man8/rshd.8.gz
# 20170927: crshared
OLD_FILES+=usr/share/man/man9/crshared.9.gz
# 20170927: procctl
OLD_FILES+=usr/share/man/man8/procctl.8.gz
OLD_FILES+=usr/sbin/procctl
# 20170926: remove unneeded man aliases and locales directory
OLD_FILES+=usr/share/man/en.ISO8859-1/man1
OLD_FILES+=usr/share/man/en.ISO8859-1/man2
OLD_FILES+=usr/share/man/en.ISO8859-1/man3
OLD_FILES+=usr/share/man/en.ISO8859-1/man4
OLD_FILES+=usr/share/man/en.ISO8859-1/man5
OLD_FILES+=usr/share/man/en.ISO8859-1/man6
OLD_FILES+=usr/share/man/en.ISO8859-1/man7
OLD_FILES+=usr/share/man/en.ISO8859-1/man8
OLD_FILES+=usr/share/man/en.ISO8859-1/man9
OLD_DIRS+=usr/share/man/en.ISO8859-1
OLD_FILES+=usr/share/man/en.ISO8859-1/mandoc.db
OLD_FILES+=usr/share/man/en.UTF-8/man1
OLD_FILES+=usr/share/man/en.UTF-8/man2
OLD_FILES+=usr/share/man/en.UTF-8/man3
OLD_FILES+=usr/share/man/en.UTF-8/man4
OLD_FILES+=usr/share/man/en.UTF-8/man5
OLD_FILES+=usr/share/man/en.UTF-8/man6
OLD_FILES+=usr/share/man/en.UTF-8/man7
OLD_FILES+=usr/share/man/en.UTF-8/man8
OLD_FILES+=usr/share/man/en.UTF-8/man9
OLD_FILES+=usr/share/man/en.UTF-8/mandoc.db
OLD_DIRS+=usr/share/man/en.UTF-8
OLD_FILES+=usr/share/man/en.ISO8859-15
OLD_FILES+=usr/share/openssl/man/en.ISO8859-1/man1
OLD_FILES+=usr/share/openssl/man/en.ISO8859-1/man3
OLD_FILES+=usr/share/openssl/man/en.ISO8859-1/mandoc.db
OLD_DIRS+=usr/share/openssl/man/en.ISO8859-1
OLD_FILES+=usr/share/openssl/man/en.ISO8859-15
OLD_DIRS+=usr/share/man/ja/man1
OLD_DIRS+=usr/share/man/ja/man2
OLD_DIRS+=usr/share/man/ja/man3
OLD_DIRS+=usr/share/man/ja/man4
OLD_DIRS+=usr/share/man/ja/man5
OLD_DIRS+=usr/share/man/ja/man6
OLD_DIRS+=usr/share/man/ja/man7
OLD_DIRS+=usr/share/man/ja/man8
OLD_DIRS+=usr/share/man/ja/man9
OLD_DIRS+=usr/share/man/ja
# 20170913: remove unneeded catman utility
OLD_FILES+=etc/periodic/weekly/330.catman
OLD_FILES+=usr/bin/catman
OLD_FILES+=usr/libexec/catman.local
OLD_FILES+=usr/share/man/man1/catman.1.gz
OLD_FILES+=usr/share/man/man8/catman.local.8.gz
OLD_DIRS+=usr/share/man/cat1
OLD_DIRS+=usr/share/man/cat2
OLD_DIRS+=usr/share/man/cat3
OLD_DIRS+=usr/share/man/cat4/amd64
OLD_DIRS+=usr/share/man/cat4/arm
OLD_DIRS+=usr/share/man/cat4/i386
OLD_DIRS+=usr/share/man/cat4/powerpc
OLD_DIRS+=usr/share/man/cat4/sparc64
OLD_DIRS+=usr/share/man/cat4
OLD_DIRS+=usr/share/man/cat5
OLD_DIRS+=usr/share/man/cat6
OLD_DIRS+=usr/share/man/cat7
OLD_DIRS+=usr/share/man/cat8/amd64
OLD_DIRS+=usr/share/man/cat8/arm
OLD_DIRS+=usr/share/man/cat8/i386
OLD_DIRS+=usr/share/man/cat8/powerpc
OLD_DIRS+=usr/share/man/cat8/sparc64
OLD_DIRS+=usr/share/man/cat8
OLD_DIRS+=usr/share/man/cat9
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat1
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat2
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat3
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat4/amd64
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat4/arm
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat4/i386
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat4/powerpc
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat4/sparc64
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat4
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat5
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat6
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat7
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat8/amd64
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat8/arm
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat8/i386
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat8/powerpc
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat8/sparc64
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat8
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat9
OLD_DIRS+=usr/share/man/en.UTF-8/cat1
OLD_DIRS+=usr/share/man/en.UTF-8/cat2
OLD_DIRS+=usr/share/man/en.UTF-8/cat3
OLD_DIRS+=usr/share/man/en.UTF-8/cat4/amd64
OLD_DIRS+=usr/share/man/en.UTF-8/cat4/arm
OLD_DIRS+=usr/share/man/en.UTF-8/cat4/i386
OLD_DIRS+=usr/share/man/en.UTF-8/cat4/powerpc
OLD_DIRS+=usr/share/man/en.UTF-8/cat4/sparc64
OLD_DIRS+=usr/share/man/en.UTF-8/cat4
OLD_DIRS+=usr/share/man/en.UTF-8/cat5
OLD_DIRS+=usr/share/man/en.UTF-8/cat6
OLD_DIRS+=usr/share/man/en.UTF-8/cat7
OLD_DIRS+=usr/share/man/en.UTF-8/cat8/amd64
OLD_DIRS+=usr/share/man/en.UTF-8/cat8/arm
OLD_DIRS+=usr/share/man/en.UTF-8/cat8/i386
OLD_DIRS+=usr/share/man/en.UTF-8/cat8/powerpc
OLD_DIRS+=usr/share/man/en.UTF-8/cat8/sparc64
OLD_DIRS+=usr/share/man/en.UTF-8/cat8
OLD_DIRS+=usr/share/man/en.UTF-8/cat9
OLD_DIRS+=usr/share/man/ja/cat1
OLD_DIRS+=usr/share/man/ja/cat2
OLD_DIRS+=usr/share/man/ja/cat3
OLD_DIRS+=usr/share/man/ja/cat4/amd64
OLD_DIRS+=usr/share/man/ja/cat4/arm
OLD_DIRS+=usr/share/man/ja/cat4/i386
OLD_DIRS+=usr/share/man/ja/cat4/powerpc
OLD_DIRS+=usr/share/man/ja/cat4/sparc64
OLD_DIRS+=usr/share/man/ja/cat4
OLD_DIRS+=usr/share/man/ja/cat5
OLD_DIRS+=usr/share/man/ja/cat6
OLD_DIRS+=usr/share/man/ja/cat7
OLD_DIRS+=usr/share/man/ja/cat8/amd64
OLD_DIRS+=usr/share/man/ja/cat8/arm
OLD_DIRS+=usr/share/man/ja/cat8/powerpc
OLD_DIRS+=usr/share/man/ja/cat8/sparc64
OLD_DIRS+=usr/share/man/ja/cat8
OLD_DIRS+=usr/share/man/ja/cat9
OLD_DIRS+=usr/share/openssl/man/cat1
OLD_DIRS+=usr/share/openssl/man/cat3
OLD_DIRS+=usr/share/openssl/man/en.ISO8859-1/cat1
OLD_DIRS+=usr/share/openssl/man/en.ISO8859-1/cat3
# 20170830: rename ntb_hw(4) to ntb_hw_intel(4)
OLD_FILES+=usr/share/man/man4/ntb_hw.4.gz
# 20170802: ksyms(4) ioctl interface was removed
OLD_FILES+=usr/include/sys/ksyms.h
# 20170729: the iicbus/pcf8563 driver is replaced with iicbus/nxprtc
OLD_FILES+=usr/include/dev/iicbus/pcf8563reg.h
# 20170722: new clang import which bumps version from 4.0.0 to 5.0.0
OLD_FILES+=usr/lib/clang/4.0.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/4.0.0/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/4.0.0/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/4.0.0/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/4.0.0/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/4.0.0/include/sanitizer/esan_interface.h
OLD_FILES+=usr/lib/clang/4.0.0/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/4.0.0/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/4.0.0/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/4.0.0/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/4.0.0/include/sanitizer
OLD_FILES+=usr/lib/clang/4.0.0/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/4.0.0/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/4.0.0/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/4.0.0/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/4.0.0/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/4.0.0/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/4.0.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/4.0.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/4.0.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/4.0.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/altivec.h
OLD_FILES+=usr/lib/clang/4.0.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/4.0.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/4.0.0/include/armintr.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/4.0.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/htmintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/4.0.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/4.0.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/4.0.0/include/msa.h
OLD_FILES+=usr/lib/clang/4.0.0/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/opencl-c.h
OLD_FILES+=usr/lib/clang/4.0.0/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/s390intrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/vadefs.h
OLD_FILES+=usr/lib/clang/4.0.0/include/vecintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/4.0.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/4.0.0/include
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/4.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/4.0.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/4.0.0/lib
OLD_DIRS+=usr/lib/clang/4.0.0
OLD_FILES+=usr/bin/llvm-pdbdump
# 20170717: Remove documentation of vaporware
OLD_FILES+=usr/share/man/man2/pdwait4.2.gz
# 20170610: chown-f_test replaced by chown_test
OLD_FILES+=usr/tests/usr.sbin/chown/chown-f_test
# 20170609: drop obsolete manpage link (if_rtwn.ko -> rtwn.ko)
OLD_FILES+=usr/share/man/man4/if_rtwn.4.gz
# 20170531: removal of groff
OLD_FILES+=usr/bin/addftinfo
OLD_FILES+=usr/bin/afmtodit
OLD_FILES+=usr/bin/checknr
OLD_FILES+=usr/bin/colcrt
OLD_FILES+=usr/bin/eqn
OLD_FILES+=usr/bin/grn
OLD_FILES+=usr/bin/grodvi
OLD_FILES+=usr/bin/groff
OLD_FILES+=usr/bin/grog
OLD_FILES+=usr/bin/grolbp
OLD_FILES+=usr/bin/grolj4
OLD_FILES+=usr/bin/grops
OLD_FILES+=usr/bin/grotty
OLD_FILES+=usr/bin/hpftodit
OLD_FILES+=usr/bin/indxbib
OLD_FILES+=usr/bin/lkbib
OLD_FILES+=usr/bin/lookbib
OLD_FILES+=usr/bin/mmroff
OLD_FILES+=usr/bin/neqn
OLD_FILES+=usr/bin/nroff
OLD_FILES+=usr/bin/pfbtops
OLD_FILES+=usr/bin/pic
OLD_FILES+=usr/bin/post-grohtml
OLD_FILES+=usr/bin/pre-grohtml
OLD_FILES+=usr/bin/psroff
OLD_FILES+=usr/bin/refer
OLD_FILES+=usr/bin/tbl
OLD_FILES+=usr/bin/tfmtodit
OLD_FILES+=usr/bin/troff
OLD_FILES+=usr/bin/vgrind
OLD_FILES+=usr/libexec/vfontedpr
OLD_FILES+=usr/share/dict/eign
OLD_FILES+=usr/share/groff_font/devX100-12/CB
OLD_FILES+=usr/share/groff_font/devX100-12/CBI
OLD_FILES+=usr/share/groff_font/devX100-12/CI
OLD_FILES+=usr/share/groff_font/devX100-12/CR
OLD_FILES+=usr/share/groff_font/devX100-12/DESC
OLD_FILES+=usr/share/groff_font/devX100-12/HB
OLD_FILES+=usr/share/groff_font/devX100-12/HBI
OLD_FILES+=usr/share/groff_font/devX100-12/HI
OLD_FILES+=usr/share/groff_font/devX100-12/HR
OLD_FILES+=usr/share/groff_font/devX100-12/NB
OLD_FILES+=usr/share/groff_font/devX100-12/NBI
OLD_FILES+=usr/share/groff_font/devX100-12/NI
OLD_FILES+=usr/share/groff_font/devX100-12/NR
OLD_FILES+=usr/share/groff_font/devX100-12/S
OLD_FILES+=usr/share/groff_font/devX100-12/TB
OLD_FILES+=usr/share/groff_font/devX100-12/TBI
OLD_FILES+=usr/share/groff_font/devX100-12/TI
OLD_FILES+=usr/share/groff_font/devX100-12/TR
OLD_DIRS+=usr/share/groff_font/devX100-12
OLD_FILES+=usr/share/groff_font/devX100/CB
OLD_FILES+=usr/share/groff_font/devX100/CBI
OLD_FILES+=usr/share/groff_font/devX100/CI
OLD_FILES+=usr/share/groff_font/devX100/CR
OLD_FILES+=usr/share/groff_font/devX100/DESC
OLD_FILES+=usr/share/groff_font/devX100/HB
OLD_FILES+=usr/share/groff_font/devX100/HBI
OLD_FILES+=usr/share/groff_font/devX100/HI
OLD_FILES+=usr/share/groff_font/devX100/HR
OLD_FILES+=usr/share/groff_font/devX100/NB
OLD_FILES+=usr/share/groff_font/devX100/NBI
OLD_FILES+=usr/share/groff_font/devX100/NI
OLD_FILES+=usr/share/groff_font/devX100/NR
OLD_FILES+=usr/share/groff_font/devX100/S
OLD_FILES+=usr/share/groff_font/devX100/TB
OLD_FILES+=usr/share/groff_font/devX100/TBI
OLD_FILES+=usr/share/groff_font/devX100/TI
OLD_FILES+=usr/share/groff_font/devX100/TR
OLD_DIRS+=usr/share/groff_font/devX100
OLD_FILES+=usr/share/groff_font/devX75-12/CB
OLD_FILES+=usr/share/groff_font/devX75-12/CBI
OLD_FILES+=usr/share/groff_font/devX75-12/CI
OLD_FILES+=usr/share/groff_font/devX75-12/CR
OLD_FILES+=usr/share/groff_font/devX75-12/DESC
OLD_FILES+=usr/share/groff_font/devX75-12/HB
OLD_FILES+=usr/share/groff_font/devX75-12/HBI
OLD_FILES+=usr/share/groff_font/devX75-12/HI
OLD_FILES+=usr/share/groff_font/devX75-12/HR
OLD_FILES+=usr/share/groff_font/devX75-12/NB
OLD_FILES+=usr/share/groff_font/devX75-12/NBI
OLD_FILES+=usr/share/groff_font/devX75-12/NI
OLD_FILES+=usr/share/groff_font/devX75-12/NR
OLD_FILES+=usr/share/groff_font/devX75-12/S
OLD_FILES+=usr/share/groff_font/devX75-12/TB
OLD_FILES+=usr/share/groff_font/devX75-12/TBI
OLD_FILES+=usr/share/groff_font/devX75-12/TI
OLD_FILES+=usr/share/groff_font/devX75-12/TR
OLD_DIRS+=usr/share/groff_font/devX75-12
OLD_FILES+=usr/share/groff_font/devX75/CB
OLD_FILES+=usr/share/groff_font/devX75/CBI
OLD_FILES+=usr/share/groff_font/devX75/CI
OLD_FILES+=usr/share/groff_font/devX75/CR
OLD_FILES+=usr/share/groff_font/devX75/DESC
OLD_FILES+=usr/share/groff_font/devX75/HB
OLD_FILES+=usr/share/groff_font/devX75/HBI
OLD_FILES+=usr/share/groff_font/devX75/HI
OLD_FILES+=usr/share/groff_font/devX75/HR
OLD_FILES+=usr/share/groff_font/devX75/NB
OLD_FILES+=usr/share/groff_font/devX75/NBI
OLD_FILES+=usr/share/groff_font/devX75/NI
OLD_FILES+=usr/share/groff_font/devX75/NR
OLD_FILES+=usr/share/groff_font/devX75/S
OLD_FILES+=usr/share/groff_font/devX75/TB
OLD_FILES+=usr/share/groff_font/devX75/TBI
OLD_FILES+=usr/share/groff_font/devX75/TI
OLD_FILES+=usr/share/groff_font/devX75/TR
OLD_DIRS+=usr/share/groff_font/devX75
OLD_FILES+=usr/share/groff_font/devascii/B
OLD_FILES+=usr/share/groff_font/devascii/BI
OLD_FILES+=usr/share/groff_font/devascii/CW
OLD_FILES+=usr/share/groff_font/devascii/DESC
OLD_FILES+=usr/share/groff_font/devascii/I
OLD_FILES+=usr/share/groff_font/devascii/L
OLD_FILES+=usr/share/groff_font/devascii/R
OLD_FILES+=usr/share/groff_font/devascii/S
OLD_DIRS+=usr/share/groff_font/devascii
OLD_FILES+=usr/share/groff_font/devcp1047/B
OLD_FILES+=usr/share/groff_font/devcp1047/BI
OLD_FILES+=usr/share/groff_font/devcp1047/CW
OLD_FILES+=usr/share/groff_font/devcp1047/DESC
OLD_FILES+=usr/share/groff_font/devcp1047/I
OLD_FILES+=usr/share/groff_font/devcp1047/L
OLD_FILES+=usr/share/groff_font/devcp1047/R
OLD_FILES+=usr/share/groff_font/devcp1047/S
OLD_DIRS+=usr/share/groff_font/devcp1047
OLD_FILES+=usr/share/groff_font/devdvi/CW
OLD_FILES+=usr/share/groff_font/devdvi/CWEC
OLD_FILES+=usr/share/groff_font/devdvi/CWI
OLD_FILES+=usr/share/groff_font/devdvi/CWIEC
OLD_FILES+=usr/share/groff_font/devdvi/CWITC
OLD_FILES+=usr/share/groff_font/devdvi/CWTC
OLD_FILES+=usr/share/groff_font/devdvi/CompileFonts
OLD_FILES+=usr/share/groff_font/devdvi/DESC
OLD_FILES+=usr/share/groff_font/devdvi/EX
OLD_FILES+=usr/share/groff_font/devdvi/HB
OLD_FILES+=usr/share/groff_font/devdvi/HBEC
OLD_FILES+=usr/share/groff_font/devdvi/HBI
OLD_FILES+=usr/share/groff_font/devdvi/HBIEC
OLD_FILES+=usr/share/groff_font/devdvi/HBITC
OLD_FILES+=usr/share/groff_font/devdvi/HBTC
OLD_FILES+=usr/share/groff_font/devdvi/HI
OLD_FILES+=usr/share/groff_font/devdvi/HIEC
OLD_FILES+=usr/share/groff_font/devdvi/HITC
OLD_FILES+=usr/share/groff_font/devdvi/HR
OLD_FILES+=usr/share/groff_font/devdvi/HREC
OLD_FILES+=usr/share/groff_font/devdvi/HRTC
OLD_FILES+=usr/share/groff_font/devdvi/MI
OLD_FILES+=usr/share/groff_font/devdvi/Makefile
OLD_FILES+=usr/share/groff_font/devdvi/S
OLD_FILES+=usr/share/groff_font/devdvi/SA
OLD_FILES+=usr/share/groff_font/devdvi/SB
OLD_FILES+=usr/share/groff_font/devdvi/SC
OLD_FILES+=usr/share/groff_font/devdvi/TB
OLD_FILES+=usr/share/groff_font/devdvi/TBEC
OLD_FILES+=usr/share/groff_font/devdvi/TBI
OLD_FILES+=usr/share/groff_font/devdvi/TBIEC
OLD_FILES+=usr/share/groff_font/devdvi/TBITC
OLD_FILES+=usr/share/groff_font/devdvi/TBTC
OLD_FILES+=usr/share/groff_font/devdvi/TI
OLD_FILES+=usr/share/groff_font/devdvi/TIEC
OLD_FILES+=usr/share/groff_font/devdvi/TITC
OLD_FILES+=usr/share/groff_font/devdvi/TR
OLD_FILES+=usr/share/groff_font/devdvi/TREC
OLD_FILES+=usr/share/groff_font/devdvi/TRTC
OLD_FILES+=usr/share/groff_font/devdvi/ec.map
OLD_FILES+=usr/share/groff_font/devdvi/msam.map
OLD_FILES+=usr/share/groff_font/devdvi/msbm.map
OLD_FILES+=usr/share/groff_font/devdvi/tc.map
OLD_FILES+=usr/share/groff_font/devdvi/texb.map
OLD_FILES+=usr/share/groff_font/devdvi/texex.map
OLD_FILES+=usr/share/groff_font/devdvi/texi.map
OLD_FILES+=usr/share/groff_font/devdvi/texmi.map
OLD_FILES+=usr/share/groff_font/devdvi/texr.map
OLD_FILES+=usr/share/groff_font/devdvi/texsy.map
OLD_FILES+=usr/share/groff_font/devdvi/textex.map
OLD_FILES+=usr/share/groff_font/devdvi/textt.map
OLD_DIRS+=usr/share/groff_font/devdvi
OLD_FILES+=usr/share/groff_font/devhtml/B
OLD_FILES+=usr/share/groff_font/devhtml/BI
OLD_FILES+=usr/share/groff_font/devhtml/CB
OLD_FILES+=usr/share/groff_font/devhtml/CBI
OLD_FILES+=usr/share/groff_font/devhtml/CI
OLD_FILES+=usr/share/groff_font/devhtml/CR
OLD_FILES+=usr/share/groff_font/devhtml/DESC
OLD_FILES+=usr/share/groff_font/devhtml/I
OLD_FILES+=usr/share/groff_font/devhtml/R
OLD_FILES+=usr/share/groff_font/devhtml/S
OLD_DIRS+=usr/share/groff_font/devhtml
OLD_FILES+=usr/share/groff_font/devkoi8-r/B
OLD_FILES+=usr/share/groff_font/devkoi8-r/BI
OLD_FILES+=usr/share/groff_font/devkoi8-r/CW
OLD_FILES+=usr/share/groff_font/devkoi8-r/DESC
OLD_FILES+=usr/share/groff_font/devkoi8-r/I
OLD_FILES+=usr/share/groff_font/devkoi8-r/L
OLD_FILES+=usr/share/groff_font/devkoi8-r/R
OLD_FILES+=usr/share/groff_font/devkoi8-r/S
OLD_DIRS+=usr/share/groff_font/devkoi8-r
OLD_FILES+=usr/share/groff_font/devlatin1/B
OLD_FILES+=usr/share/groff_font/devlatin1/BI
OLD_FILES+=usr/share/groff_font/devlatin1/CW
OLD_FILES+=usr/share/groff_font/devlatin1/DESC
OLD_FILES+=usr/share/groff_font/devlatin1/I
OLD_FILES+=usr/share/groff_font/devlatin1/L
OLD_FILES+=usr/share/groff_font/devlatin1/R
OLD_FILES+=usr/share/groff_font/devlatin1/S
OLD_DIRS+=usr/share/groff_font/devlatin1
OLD_FILES+=usr/share/groff_font/devlbp/CB
OLD_FILES+=usr/share/groff_font/devlbp/CI
OLD_FILES+=usr/share/groff_font/devlbp/CR
OLD_FILES+=usr/share/groff_font/devlbp/DESC
OLD_FILES+=usr/share/groff_font/devlbp/EB
OLD_FILES+=usr/share/groff_font/devlbp/EI
OLD_FILES+=usr/share/groff_font/devlbp/ER
OLD_FILES+=usr/share/groff_font/devlbp/HB
OLD_FILES+=usr/share/groff_font/devlbp/HBI
OLD_FILES+=usr/share/groff_font/devlbp/HI
OLD_FILES+=usr/share/groff_font/devlbp/HNB
OLD_FILES+=usr/share/groff_font/devlbp/HNBI
OLD_FILES+=usr/share/groff_font/devlbp/HNI
OLD_FILES+=usr/share/groff_font/devlbp/HNR
OLD_FILES+=usr/share/groff_font/devlbp/HR
OLD_FILES+=usr/share/groff_font/devlbp/TB
OLD_FILES+=usr/share/groff_font/devlbp/TBI
OLD_FILES+=usr/share/groff_font/devlbp/TI
OLD_FILES+=usr/share/groff_font/devlbp/TR
OLD_DIRS+=usr/share/groff_font/devlbp
OLD_FILES+=usr/share/groff_font/devlj4/AB
OLD_FILES+=usr/share/groff_font/devlj4/ABI
OLD_FILES+=usr/share/groff_font/devlj4/AI
OLD_FILES+=usr/share/groff_font/devlj4/ALBB
OLD_FILES+=usr/share/groff_font/devlj4/ALBR
OLD_FILES+=usr/share/groff_font/devlj4/AOB
OLD_FILES+=usr/share/groff_font/devlj4/AOI
OLD_FILES+=usr/share/groff_font/devlj4/AOR
OLD_FILES+=usr/share/groff_font/devlj4/AR
OLD_FILES+=usr/share/groff_font/devlj4/CB
OLD_FILES+=usr/share/groff_font/devlj4/CBI
OLD_FILES+=usr/share/groff_font/devlj4/CI
OLD_FILES+=usr/share/groff_font/devlj4/CLARENDON
OLD_FILES+=usr/share/groff_font/devlj4/CORONET
OLD_FILES+=usr/share/groff_font/devlj4/CR
OLD_FILES+=usr/share/groff_font/devlj4/DESC
OLD_FILES+=usr/share/groff_font/devlj4/GB
OLD_FILES+=usr/share/groff_font/devlj4/GBI
OLD_FILES+=usr/share/groff_font/devlj4/GI
OLD_FILES+=usr/share/groff_font/devlj4/GR
OLD_FILES+=usr/share/groff_font/devlj4/LGB
OLD_FILES+=usr/share/groff_font/devlj4/LGI
OLD_FILES+=usr/share/groff_font/devlj4/LGR
OLD_FILES+=usr/share/groff_font/devlj4/MARIGOLD
OLD_FILES+=usr/share/groff_font/devlj4/OB
OLD_FILES+=usr/share/groff_font/devlj4/OBI
OLD_FILES+=usr/share/groff_font/devlj4/OI
OLD_FILES+=usr/share/groff_font/devlj4/OR
OLD_FILES+=usr/share/groff_font/devlj4/S
OLD_FILES+=usr/share/groff_font/devlj4/SYMBOL
OLD_FILES+=usr/share/groff_font/devlj4/TB
OLD_FILES+=usr/share/groff_font/devlj4/TBI
OLD_FILES+=usr/share/groff_font/devlj4/TI
OLD_FILES+=usr/share/groff_font/devlj4/TNRB
OLD_FILES+=usr/share/groff_font/devlj4/TNRBI
OLD_FILES+=usr/share/groff_font/devlj4/TNRI
OLD_FILES+=usr/share/groff_font/devlj4/TNRR
OLD_FILES+=usr/share/groff_font/devlj4/TR
OLD_FILES+=usr/share/groff_font/devlj4/UB
OLD_FILES+=usr/share/groff_font/devlj4/UBI
OLD_FILES+=usr/share/groff_font/devlj4/UCB
OLD_FILES+=usr/share/groff_font/devlj4/UCBI
OLD_FILES+=usr/share/groff_font/devlj4/UCI
OLD_FILES+=usr/share/groff_font/devlj4/UCR
OLD_FILES+=usr/share/groff_font/devlj4/UI
OLD_FILES+=usr/share/groff_font/devlj4/UR
OLD_FILES+=usr/share/groff_font/devlj4/WINGDINGS
OLD_DIRS+=usr/share/groff_font/devlj4
OLD_FILES+=usr/share/groff_font/devps/AB
OLD_FILES+=usr/share/groff_font/devps/ABI
OLD_FILES+=usr/share/groff_font/devps/AI
OLD_FILES+=usr/share/groff_font/devps/AR
OLD_FILES+=usr/share/groff_font/devps/BMB
OLD_FILES+=usr/share/groff_font/devps/BMBI
OLD_FILES+=usr/share/groff_font/devps/BMI
OLD_FILES+=usr/share/groff_font/devps/BMR
OLD_FILES+=usr/share/groff_font/devps/CB
OLD_FILES+=usr/share/groff_font/devps/CBI
OLD_FILES+=usr/share/groff_font/devps/CI
OLD_FILES+=usr/share/groff_font/devps/CR
OLD_FILES+=usr/share/groff_font/devps/DESC
OLD_FILES+=usr/share/groff_font/devps/EURO
OLD_FILES+=usr/share/groff_font/devps/HB
OLD_FILES+=usr/share/groff_font/devps/HBI
OLD_FILES+=usr/share/groff_font/devps/HI
OLD_FILES+=usr/share/groff_font/devps/HNB
OLD_FILES+=usr/share/groff_font/devps/HNBI
OLD_FILES+=usr/share/groff_font/devps/HNI
OLD_FILES+=usr/share/groff_font/devps/HNR
OLD_FILES+=usr/share/groff_font/devps/HR
OLD_FILES+=usr/share/groff_font/devps/Makefile
OLD_FILES+=usr/share/groff_font/devps/NB
OLD_FILES+=usr/share/groff_font/devps/NBI
OLD_FILES+=usr/share/groff_font/devps/NI
OLD_FILES+=usr/share/groff_font/devps/NR
OLD_FILES+=usr/share/groff_font/devps/PB
OLD_FILES+=usr/share/groff_font/devps/PBI
OLD_FILES+=usr/share/groff_font/devps/PI
OLD_FILES+=usr/share/groff_font/devps/PR
OLD_FILES+=usr/share/groff_font/devps/S
OLD_FILES+=usr/share/groff_font/devps/SS
OLD_FILES+=usr/share/groff_font/devps/TB
OLD_FILES+=usr/share/groff_font/devps/TBI
OLD_FILES+=usr/share/groff_font/devps/TI
OLD_FILES+=usr/share/groff_font/devps/TR
OLD_FILES+=usr/share/groff_font/devps/ZCMI
OLD_FILES+=usr/share/groff_font/devps/ZD
OLD_FILES+=usr/share/groff_font/devps/ZDR
OLD_FILES+=usr/share/groff_font/devps/afmname
OLD_FILES+=usr/share/groff_font/devps/dingbats.map
OLD_FILES+=usr/share/groff_font/devps/dingbats.rmap
OLD_FILES+=usr/share/groff_font/devps/download
OLD_FILES+=usr/share/groff_font/devps/freeeuro.pfa
OLD_FILES+=usr/share/groff_font/devps/lgreekmap
OLD_FILES+=usr/share/groff_font/devps/prologue
OLD_FILES+=usr/share/groff_font/devps/symbol.sed
OLD_FILES+=usr/share/groff_font/devps/symbolchars
OLD_FILES+=usr/share/groff_font/devps/symbolsl.afm
OLD_FILES+=usr/share/groff_font/devps/symbolsl.pfa
OLD_FILES+=usr/share/groff_font/devps/text.enc
OLD_FILES+=usr/share/groff_font/devps/textmap
OLD_FILES+=usr/share/groff_font/devps/zapfdr.pfa
OLD_DIRS+=usr/share/groff_font/devps
OLD_FILES+=usr/share/groff_font/devutf8/B
OLD_FILES+=usr/share/groff_font/devutf8/BI
OLD_FILES+=usr/share/groff_font/devutf8/CW
OLD_FILES+=usr/share/groff_font/devutf8/DESC
OLD_FILES+=usr/share/groff_font/devutf8/I
OLD_FILES+=usr/share/groff_font/devutf8/L
OLD_FILES+=usr/share/groff_font/devutf8/R
OLD_FILES+=usr/share/groff_font/devutf8/S
OLD_DIRS+=usr/share/groff_font/devutf8
OLD_DIRS+=usr/share/groff_font
OLD_FILES+=usr/share/man/man1/addftinfo.1.gz
OLD_FILES+=usr/share/man/man1/afmtodit.1.gz
OLD_FILES+=usr/share/man/man1/checknr.1.gz
OLD_FILES+=usr/share/man/man1/colcrt.1.gz
OLD_FILES+=usr/share/man/man1/eqn.1.gz
OLD_FILES+=usr/share/man/man1/grn.1.gz
OLD_FILES+=usr/share/man/man1/grodvi.1.gz
OLD_FILES+=usr/share/man/man1/groff.1.gz
OLD_FILES+=usr/share/man/man1/grog.1.gz
OLD_FILES+=usr/share/man/man1/grolbp.1.gz
OLD_FILES+=usr/share/man/man1/grolj4.1.gz
OLD_FILES+=usr/share/man/man1/grops.1.gz
OLD_FILES+=usr/share/man/man1/grotty.1.gz
OLD_FILES+=usr/share/man/man1/hpftodit.1.gz
OLD_FILES+=usr/share/man/man1/indxbib.1.gz
OLD_FILES+=usr/share/man/man1/lkbib.1.gz
OLD_FILES+=usr/share/man/man1/lookbib.1.gz
OLD_FILES+=usr/share/man/man1/mmroff.1.gz
OLD_FILES+=usr/share/man/man1/neqn.1.gz
OLD_FILES+=usr/share/man/man1/nroff.1.gz
OLD_FILES+=usr/share/man/man1/pfbtops.1.gz
OLD_FILES+=usr/share/man/man1/pic.1.gz
OLD_FILES+=usr/share/man/man1/psroff.1.gz
OLD_FILES+=usr/share/man/man1/refer.1.gz
OLD_FILES+=usr/share/man/man1/tbl.1.gz
OLD_FILES+=usr/share/man/man1/tfmtodit.1.gz
OLD_FILES+=usr/share/man/man1/troff.1.gz
OLD_FILES+=usr/share/man/man1/vgrind.1.gz
OLD_FILES+=usr/share/man/man5/groff_font.5.gz
OLD_FILES+=usr/share/man/man5/groff_out.5.gz
OLD_FILES+=usr/share/man/man5/groff_tmac.5.gz
OLD_FILES+=usr/share/man/man5/lj4_font.5.gz
OLD_FILES+=usr/share/man/man5/tmac.5.gz
OLD_FILES+=usr/share/man/man5/vgrindefs.5.gz
OLD_FILES+=usr/share/man/man7/ditroff.7.gz
OLD_FILES+=usr/share/man/man7/groff.7.gz
OLD_FILES+=usr/share/man/man7/groff_char.7.gz
OLD_FILES+=usr/share/man/man7/groff_diff.7.gz
OLD_FILES+=usr/share/man/man7/groff_man.7.gz
OLD_FILES+=usr/share/man/man7/groff_mdoc.7.gz
OLD_FILES+=usr/share/man/man7/groff_me.7.gz
OLD_FILES+=usr/share/man/man7/groff_mm.7.gz
OLD_FILES+=usr/share/man/man7/groff_mmse.7.gz
OLD_FILES+=usr/share/man/man7/groff_ms.7.gz
OLD_FILES+=usr/share/man/man7/groff_trace.7.gz
OLD_FILES+=usr/share/man/man7/groff_www.7.gz
OLD_FILES+=usr/share/man/man7/mdoc.samples.7.gz
OLD_FILES+=usr/share/man/man7/me.7.gz
OLD_FILES+=usr/share/man/man7/mm.7.gz
OLD_FILES+=usr/share/man/man7/mmse.7.gz
OLD_FILES+=usr/share/man/man7/ms.7.gz
OLD_FILES+=usr/share/man/man7/orig_me.7.gz
OLD_FILES+=usr/share/me/acm.me
OLD_FILES+=usr/share/me/chars.me
OLD_FILES+=usr/share/me/deltext.me
OLD_FILES+=usr/share/me/eqn.me
OLD_FILES+=usr/share/me/float.me
OLD_FILES+=usr/share/me/footnote.me
OLD_FILES+=usr/share/me/index.me
OLD_FILES+=usr/share/me/letterhead.me
OLD_FILES+=usr/share/me/local.me
OLD_FILES+=usr/share/me/null.me
OLD_FILES+=usr/share/me/refer.me
OLD_FILES+=usr/share/me/revisions
OLD_FILES+=usr/share/me/sh.me
OLD_FILES+=usr/share/me/tbl.me
OLD_FILES+=usr/share/me/thesis.me
OLD_DIRS+=usr/share/me
OLD_FILES+=usr/share/misc/vgrindefs
OLD_FILES+=usr/share/misc/vgrindefs.db
OLD_FILES+=usr/share/tmac/X.tmac
OLD_FILES+=usr/share/tmac/Xps.tmac
OLD_FILES+=usr/share/tmac/a4.tmac
OLD_FILES+=usr/share/tmac/an-old.tmac
OLD_FILES+=usr/share/tmac/an.tmac
OLD_FILES+=usr/share/tmac/andoc.tmac
OLD_FILES+=usr/share/tmac/composite.tmac
OLD_FILES+=usr/share/tmac/cp1047.tmac
OLD_FILES+=usr/share/tmac/devtag.tmac
OLD_FILES+=usr/share/tmac/doc.tmac
OLD_FILES+=usr/share/tmac/dvi.tmac
OLD_FILES+=usr/share/tmac/e.tmac
OLD_FILES+=usr/share/tmac/ec.tmac
OLD_FILES+=usr/share/tmac/eqnrc
OLD_FILES+=usr/share/tmac/europs.tmac
OLD_FILES+=usr/share/tmac/html-end.tmac
OLD_FILES+=usr/share/tmac/html.tmac
OLD_FILES+=usr/share/tmac/hyphen.ru
OLD_FILES+=usr/share/tmac/hyphen.us
OLD_FILES+=usr/share/tmac/hyphenex.us
OLD_FILES+=usr/share/tmac/koi8-r.tmac
OLD_FILES+=usr/share/tmac/latin1.tmac
OLD_FILES+=usr/share/tmac/latin2.tmac
OLD_FILES+=usr/share/tmac/latin9.tmac
OLD_FILES+=usr/share/tmac/lbp.tmac
OLD_FILES+=usr/share/tmac/lj4.tmac
OLD_FILES+=usr/share/tmac/m.tmac
OLD_FILES+=usr/share/tmac/man.local
OLD_FILES+=usr/share/tmac/man.tmac
OLD_FILES+=usr/share/tmac/mandoc.tmac
OLD_FILES+=usr/share/tmac/mdoc.local
OLD_FILES+=usr/share/tmac/mdoc.tmac
OLD_FILES+=usr/share/tmac/mdoc/doc-common
OLD_FILES+=usr/share/tmac/mdoc/doc-ditroff
OLD_FILES+=usr/share/tmac/mdoc/doc-nroff
OLD_FILES+=usr/share/tmac/mdoc/doc-syms
OLD_FILES+=usr/share/tmac/mdoc/fr.ISO8859-1
OLD_FILES+=usr/share/tmac/mdoc/ru.KOI8-R
OLD_DIRS+=usr/share/tmac/mdoc
OLD_FILES+=usr/share/tmac/me.tmac
OLD_FILES+=usr/share/tmac/mm/0.MT
OLD_FILES+=usr/share/tmac/mm/4.MT
OLD_FILES+=usr/share/tmac/mm/5.MT
OLD_FILES+=usr/share/tmac/mm/locale
OLD_FILES+=usr/share/tmac/mm/mm.tmac
OLD_FILES+=usr/share/tmac/mm/mmse.tmac
OLD_FILES+=usr/share/tmac/mm/ms.cov
OLD_FILES+=usr/share/tmac/mm/se_locale
OLD_FILES+=usr/share/tmac/mm/se_ms.cov
OLD_DIRS+=usr/share/tmac/mm
OLD_FILES+=usr/share/tmac/ms.tmac
OLD_FILES+=usr/share/tmac/mse.tmac
OLD_FILES+=usr/share/tmac/papersize.tmac
OLD_FILES+=usr/share/tmac/pic.tmac
OLD_FILES+=usr/share/tmac/ps.tmac
OLD_FILES+=usr/share/tmac/psatk.tmac
OLD_FILES+=usr/share/tmac/psold.tmac
OLD_FILES+=usr/share/tmac/pspic.tmac
OLD_FILES+=usr/share/tmac/s.tmac
OLD_FILES+=usr/share/tmac/safer.tmac
OLD_FILES+=usr/share/tmac/tmac.orig_me
OLD_FILES+=usr/share/tmac/tmac.vgrind
OLD_FILES+=usr/share/tmac/trace.tmac
OLD_FILES+=usr/share/tmac/troffrc
OLD_FILES+=usr/share/tmac/troffrc-end
OLD_FILES+=usr/share/tmac/tty-char.tmac
OLD_FILES+=usr/share/tmac/tty.tmac
OLD_FILES+=usr/share/tmac/unicode.tmac
OLD_FILES+=usr/share/tmac/www.tmac
OLD_DIRS+=usr/share/tmac
# 20170607: remove incorrect atf_check(1) manpage link
OLD_FILES+=usr/share/man/man1/atf_check.1.gz
# 20170601: remove stale manpage
OLD_FILES+=usr/share/man/man2/cap_rights_get.2.gz
# 20170601: old libifconfig and libifc
OLD_FILES+=usr/lib/libifc.a
OLD_FILES+=usr/lib/libifc_p.a
OLD_FILES+=usr/lib/libifconfig.a
OLD_FILES+=usr/lib/libifconfig_p.a
# 20170529: mount.conf(8) -> mount.conf(5)
OLD_FILES+=usr/share/man/man8/mount.conf.8.gz
# 20170525: remove misleading template
OLD_FILES+=usr/share/misc/man.template
# 20170525: disconnect the roff docs from the build
OLD_FILES+=usr/share/doc/papers/beyond43.ascii.gz
OLD_FILES+=usr/share/doc/papers/bio.ascii.gz
OLD_FILES+=usr/share/doc/papers/contents.ascii.gz
OLD_FILES+=usr/share/doc/papers/devfs.ascii.gz
OLD_FILES+=usr/share/doc/papers/diskperf.ascii.gz
OLD_FILES+=usr/share/doc/papers/fsinterface.ascii.gz
OLD_FILES+=usr/share/doc/papers/hwpmc.ascii.gz
OLD_FILES+=usr/share/doc/papers/jail.ascii.gz
OLD_FILES+=usr/share/doc/papers/kernmalloc.ascii.gz
OLD_FILES+=usr/share/doc/papers/kerntune.ascii.gz
OLD_FILES+=usr/share/doc/papers/malloc.ascii.gz
OLD_FILES+=usr/share/doc/papers/newvm.ascii.gz
OLD_FILES+=usr/share/doc/papers/releng.ascii.gz
OLD_FILES+=usr/share/doc/papers/sysperf.ascii.gz
OLD_FILES+=usr/share/doc/papers/timecounter.ascii.gz
OLD_DIRS+=usr/share/doc/papers
OLD_FILES+=usr/share/doc/psd/01.cacm/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/01.cacm
OLD_FILES+=usr/share/doc/psd/02.implement/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/02.implement
OLD_FILES+=usr/share/doc/psd/03.iosys/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/03.iosys
OLD_FILES+=usr/share/doc/psd/04.uprog/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/04.uprog
OLD_FILES+=usr/share/doc/psd/05.sysman/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/05.sysman
OLD_FILES+=usr/share/doc/psd/06.Clang/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/06.Clang
OLD_FILES+=usr/share/doc/psd/12.make/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/12.make
OLD_FILES+=usr/share/doc/psd/13.rcs/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/13.rcs
OLD_FILES+=usr/share/doc/psd/13.rcs/rcs_func.ascii.gz
OLD_DIRS+=usr/share/doc/psd/13.rcs
OLD_FILES+=usr/share/doc/psd/15.yacc/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/15.yacc
OLD_FILES+=usr/share/doc/psd/16.lex/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/16.lex
OLD_FILES+=usr/share/doc/psd/17.m4/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/17.m4
OLD_FILES+=usr/share/doc/psd/18.gprof/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/18.gprof
OLD_FILES+=usr/share/doc/psd/20.ipctut/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/20.ipctut
OLD_FILES+=usr/share/doc/psd/21.ipc/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/21.ipc
OLD_FILES+=usr/share/doc/psd/22.rpcgen/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/22.rpcgen
OLD_FILES+=usr/share/doc/psd/23.rpc/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/23.rpc
OLD_FILES+=usr/share/doc/psd/24.xdr/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/24.xdr
OLD_FILES+=usr/share/doc/psd/25.xdrrfc/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/25.xdrrfc
OLD_FILES+=usr/share/doc/psd/26.rpcrfc/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/26.rpcrfc
OLD_FILES+=usr/share/doc/psd/27.nfsrfc/paper.ascii.gz
OLD_DIRS+=usr/share/doc/psd/27.nfsrfc
OLD_FILES+=usr/share/doc/psd/Title.ascii.gz
OLD_FILES+=usr/share/doc/psd/contents.ascii.gz
OLD_DIRS+=usr/share/doc/psd/
OLD_FILES+=usr/share/doc/smm/01.setup/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/01.setup
OLD_FILES+=usr/share/doc/smm/02.config/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/02.config
OLD_FILES+=usr/share/doc/smm/03.fsck/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/03.fsck
OLD_FILES+=usr/share/doc/smm/04.quotas/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/04.quotas
OLD_FILES+=usr/share/doc/smm/05.fastfs/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/05.fastfs
OLD_FILES+=usr/share/doc/smm/06.nfs/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/06.nfs
OLD_FILES+=usr/share/doc/smm/07.lpd/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/07.lpd
OLD_FILES+=usr/share/doc/smm/08.sendmailop/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/08.sendmailop
OLD_FILES+=usr/share/doc/smm/11.timedop/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/11.timedop
OLD_FILES+=usr/share/doc/smm/12.timed/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/12.timed
OLD_FILES+=usr/share/doc/smm/18.net/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/18.net
OLD_FILES+=usr/share/doc/smm/Title.ascii.gz
OLD_FILES+=usr/share/doc/smm/contents.ascii.gz
OLD_DIRS+=usr/share/doc/smm
OLD_FILES+=usr/share/doc/usd/04.csh/paper.ascii.gz
OLD_DIRS+=usr/share/doc/usd/04.csh
OLD_FILES+=usr/share/doc/usd/05.dc/paper.ascii.gz
OLD_DIRS+=usr/share/doc/usd/05.dc
OLD_FILES+=usr/share/doc/usd/06.bc/paper.ascii.gz
OLD_DIRS+=usr/share/doc/usd/06.bc
OLD_FILES+=usr/share/doc/usd/07.mail/paper.ascii.gz
OLD_DIRS+=usr/share/doc/usd/07.mail
OLD_FILES+=usr/share/doc/usd/10.exref/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/10.exref/summary.ascii.gz
OLD_DIRS+=usr/share/doc/usd/10.exref
OLD_FILES+=usr/share/doc/usd/11.edit/paper.ascii.gz
OLD_DIRS+=usr/share/doc/usd/11.edit
OLD_FILES+=usr/share/doc/usd/12.vi/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/12.vi/summary.ascii.gz
OLD_FILES+=usr/share/doc/usd/12.vi/viapwh.ascii.gz
OLD_DIRS+=usr/share/doc/usd/12.vi
OLD_FILES+=usr/share/doc/usd/13.viref/paper.ascii.gz
OLD_DIRS+=usr/share/doc/usd/13.viref
OLD_FILES+=usr/share/doc/usd/18.msdiffs/paper.ascii.gz
OLD_DIRS+=usr/share/doc/usd/18.msdiffs
OLD_FILES+=usr/share/doc/usd/19.memacros/paper.ascii.gz
OLD_DIRS+=usr/share/doc/usd/19.memacros
OLD_FILES+=usr/share/doc/usd/20.meref/paper.ascii.gz
OLD_DIRS+=usr/share/doc/usd/20.meref
OLD_FILES+=usr/share/doc/usd/21.troff/paper.ascii.gz
OLD_DIRS+=usr/share/doc/usd/21.troff
OLD_FILES+=usr/share/doc/usd/22.trofftut/paper.ascii.gz
OLD_DIRS+=usr/share/doc/usd/22.trofftut
OLD_FILES+=usr/share/doc/usd/Title.ascii.gz
OLD_FILES+=usr/share/doc/usd/contents.ascii.gz
OLD_DIRS+=usr/share/doc/usd
# 20170523: 64-bit inode support, library version bumps
OLD_LIBS+=lib/libzfs.so.2
OLD_LIBS+=usr/lib/libarchive.so.6
OLD_LIBS+=usr/lib/libmilter.so.5
# 20170427: NATM configuration support removed
OLD_FILES+=etc/rc.d/atm1
OLD_FILES+=etc/rc.d/atm2
OLD_FILES+=etc/rc.d/atm3
OLD_FILES+=usr/share/man/man8/rc.atm.8.gz
# 20170426: UMA_ZONE_REFCNT removed
OLD_FILES+=usr/share/man/man9/uma_find_refcnt.9.gz
# 20170424: NATM support removed
OLD_FILES+=rescue/atmconfig
OLD_FILES+=sbin/atmconfig
OLD_FILES+=usr/include/bsnmp/snmp_atm.h
OLD_FILES+=usr/include/dev/utopia/idtphy.h
OLD_FILES+=usr/include/dev/utopia/suni.h
OLD_FILES+=usr/include/dev/utopia/utopia.h
OLD_FILES+=usr/include/dev/utopia/utopia_priv.h
OLD_DIRS+=usr/include/dev/utopia
OLD_FILES+=usr/include/net/if_atm.h
OLD_FILES+=usr/include/netgraph/atm/ng_atm.h
OLD_FILES+=usr/include/netinet/if_atm.h
OLD_FILES+=usr/include/netnatm/natm.h
OLD_FILES+=usr/lib/snmp_atm.so
OLD_LIBS+=usr/lib/snmp_atm.so.6
OLD_FILES+=usr/share/doc/atm/atmconfig.help
OLD_FILES+=usr/share/doc/atm/atmconfig_device.help
OLD_DIRS+=usr/share/doc/atm
OLD_FILES+=usr/share/man/man3/snmp_atm.3.gz
OLD_FILES+=usr/share/man/man4/en.4.gz
OLD_FILES+=usr/share/man/man4/fatm.4.gz
OLD_FILES+=usr/share/man/man4/hatm.4.gz
OLD_FILES+=usr/share/man/man4/if_en.4.gz
OLD_FILES+=usr/share/man/man4/if_fatm.4.gz
OLD_FILES+=usr/share/man/man4/if_hatm.4.gz
OLD_FILES+=usr/share/man/man4/if_patm.4.gz
OLD_FILES+=usr/share/man/man4/natm.4.gz
OLD_FILES+=usr/share/man/man4/natmip.4.gz
OLD_FILES+=usr/share/man/man4/ng_atm.4.gz
OLD_FILES+=usr/share/man/man4/patm.4.gz
OLD_FILES+=usr/share/man/man4/utopia.4.gz
OLD_FILES+=usr/share/man/man8/atmconfig.8.gz
OLD_FILES+=usr/share/man/man9/utopia.9.gz
OLD_FILES+=usr/share/snmp/defs/atm_freebsd.def
OLD_FILES+=usr/share/snmp/defs/atm_tree.def
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM-FREEBSD-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM.txt
# 20170420: remove GNU diff
OLD_FILES+=usr/share/man/man7/diff.7.gz
# 20170322: rename <x> to <x>_test to match the FreeBSD test suite name scheme
OLD_FILES+=usr/tests/usr.bin/col/col
OLD_FILES+=usr/tests/usr.bin/diff/diff
OLD_FILES+=usr/tests/usr.bin/ident/ident
OLD_FILES+=usr/tests/usr.bin/mkimg/mkimg
OLD_FILES+=usr/tests/usr.bin/sdiff/sdiff
OLD_FILES+=usr/tests/usr.bin/soelim/soelim
OLD_FILES+=usr/tests/usr.sbin/pw/pw_config
OLD_FILES+=usr/tests/usr.sbin/pw/pw_etcdir
OLD_FILES+=usr/tests/usr.sbin/pw/pw_groupadd
OLD_FILES+=usr/tests/usr.sbin/pw/pw_groupdel
OLD_FILES+=usr/tests/usr.sbin/pw/pw_groupmod
OLD_FILES+=usr/tests/usr.sbin/pw/pw_lock
OLD_FILES+=usr/tests/usr.sbin/pw/pw_useradd
OLD_FILES+=usr/tests/usr.sbin/pw/pw_userdel
OLD_FILES+=usr/tests/usr.sbin/pw/pw_usermod
OLD_FILES+=usr/tests/usr.sbin/pw/pw_usernext
# 20170319: io_test requires zh_TW.Big5 locale
OLD_FILES+=usr/tests/lib/libc/locale/io_test
# 20170319: remove nls for non supported Big5* locales
OLD_DIRS+=usr/share/nls/zh_HK.Big5HKSCS
OLD_DIRS+=usr/share/nls/zh_TW.Big5
# 20170313: move .../sys/geom/eli/... to .../sys/geom/class/eli/...
OLD_FILES+=usr/tests/sys/geom/eli/pbkdf2/pbkdf2
OLD_FILES+=usr/tests/sys/geom/eli/pbkdf2/Kyuafile
OLD_FILES+=usr/tests/sys/geom/eli/Kyuafile
OLD_DIRS+=usr/tests/sys/geom/eli/pbkdf2
OLD_DIRS+=usr/tests/sys/geom/eli
# 20170313: sbin/ipftest and ipresend temporarily disconnected
OLD_FILES+=sbin/ipftest
OLD_FILES+=sbin/ipresend
OLD_FILES+=usr/share/man/man1/ipftest.1.gz
OLD_FILES+=usr/share/man/man1/ipresend.1.gz
# 20170311: Remove WITHOUT_MANDOCDB option
OLD_FILES+=usr/share/man/man1/makewhatis.1.gz
# 20170308: rename some tests
OLD_FILES+=usr/tests/bin/pwait/pwait
OLD_FILES+=usr/tests/usr.bin/timeout/timeout
# 20170307: remove pcap-int.h
OLD_FILES+=usr/include/pcap-int.h
# 20170302: new libc++ import which bumps version from 3.9.1 to 4.0.0
OLD_FILES+=usr/include/c++/v1/__undef___deallocate
OLD_FILES+=usr/include/c++/v1/tr1/__undef___deallocate
# 20170302: new clang import which bumps version from 3.9.1 to 4.0.0
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/esan_interface.h
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/3.9.1/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/3.9.1/include/sanitizer
OLD_FILES+=usr/lib/clang/3.9.1/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/3.9.1/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/3.9.1/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/3.9.1/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/3.9.1/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/3.9.1/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/3.9.1/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/3.9.1/include/adxintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/altivec.h
OLD_FILES+=usr/lib/clang/3.9.1/include/ammintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/arm_acle.h
OLD_FILES+=usr/lib/clang/3.9.1/include/arm_neon.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/avxintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/cpuid.h
OLD_FILES+=usr/lib/clang/3.9.1/include/cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/3.9.1/include/emmintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/htmintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/immintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/3.9.1/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/3.9.1/include/mmintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/module.modulemap
OLD_FILES+=usr/lib/clang/3.9.1/include/msa.h
OLD_FILES+=usr/lib/clang/3.9.1/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/opencl-c.h
OLD_FILES+=usr/lib/clang/3.9.1/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/s390intrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/shaintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/smmintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/vadefs.h
OLD_FILES+=usr/lib/clang/3.9.1/include/vecintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/x86intrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/xopintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/3.9.1/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/3.9.1/include
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.9.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/3.9.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/3.9.1/lib
OLD_DIRS+=usr/lib/clang/3.9.1
# 20170226: SVR4 compatibility removed
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/share/man/man4/streams.4
OLD_FILES+=usr/share/man/man4/svr4.4
.endif
# 20170219: OpenPAM RADULA upgrade removed the libpam tests
OLD_FILES+=usr/tests/lib/libpam/Kyuafile
OLD_FILES+=usr/tests/lib/libpam/t_openpam_ctype
OLD_FILES+=usr/tests/lib/libpam/t_openpam_readlinev
OLD_FILES+=usr/tests/lib/libpam/t_openpam_readword
OLD_DIRS+=usr/test/lib/libpam
# 20170216: remove ahb(4)
OLD_FILES+=usr/share/man/man4/ahb.4.gz
# 20170216: remove fea(4)
OLD_FILES+=usr/share/man/man4/fea.4.gz
# 20170206: remove bdes(1)
OLD_FILES+=usr/bin/bdes
OLD_FILES+=usr/share/man/man1/bdes.1.gz
# 20170206: merged projects/ipsec
OLD_FILES+=usr/include/netinet/ip_ipsec.h
OLD_FILES+=usr/include/netinet6/ip6_ipsec.h
# 20170128: remove pc98 support
OLD_FILES+=usr/include/dev/ic/i8251.h
OLD_FILES+=usr/include/dev/ic/i8255.h
OLD_FILES+=usr/include/dev/ic/rsa.h
OLD_FILES+=usr/include/dev/ic/wd33c93reg.h
OLD_FILES+=usr/include/sys/disk/pc98.h
OLD_FILES+=usr/include/sys/diskpc98.h
OLD_FILES+=usr/share/man/man4/i386/ct.4.gz
OLD_FILES+=usr/share/man/man4/i386/snc.4.gz
OLD_FILES+=usr/share/syscons/keymaps/jp.pc98.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/jp.pc98.kbd
OLD_FILES+=usr/share/vt/keymaps/jp.pc98.iso.kbd
OLD_FILES+=usr/share/vt/keymaps/jp.pc98.kbd
# 20170110: Four files from ggate tests consolidated into one
OLD_FILES+=usr/tests/sys/geom/class/gate/1_test
OLD_FILES+=usr/tests/sys/geom/class/gate/2_test
OLD_FILES+=usr/tests/sys/geom/class/gate/3_test
OLD_FILES+=usr/tests/sys/geom/class/gate/conf.sh
# 20170103: libbsnmptools.so made into an INTERNALLIB
OLD_FILES+=usr/lib/libbsnmptools.a
OLD_FILES+=usr/lib/libbsnmptools_p.a
OLD_LIBS+=usr/lib/libbsnmptools.so.0
OLD_FILES+=usr/lib/libbsnmptools.so
# 20170102: sysdecode_getfsstat_flags() renamed to sysdecode_getfsstat_mode()
OLD_FILES+=usr/share/man/man3/sysdecode_getfsstat_flags.3.gz
# 20161230: libarchive ACL pax test renamed to test_acl_pax_posix1e.tar.uu
OLD_FILES+=usr/tests/lib/libarchive/test_acl_pax.tar.uu
# 20161229: Three files from gnop tests consolidated into one
OLD_FILES+=usr/tests/sys/geom/class/nop/1_test
OLD_FILES+=usr/tests/sys/geom/class/nop/2_test
OLD_FILES+=usr/tests/sys/geom/class/nop/conf.sh
# 20161217: new clang import which bumps version from 3.9.0 to 3.9.1
OLD_FILES+=usr/lib/clang/3.9.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/3.9.0/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/3.9.0/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/3.9.0/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/3.9.0/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/3.9.0/include/sanitizer/esan_interface.h
OLD_FILES+=usr/lib/clang/3.9.0/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/3.9.0/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/3.9.0/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/3.9.0/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/3.9.0/include/sanitizer
OLD_FILES+=usr/lib/clang/3.9.0/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/3.9.0/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/3.9.0/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/3.9.0/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/3.9.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/3.9.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/3.9.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/3.9.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/altivec.h
OLD_FILES+=usr/lib/clang/3.9.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/3.9.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/3.9.0/include/cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/3.9.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/htmintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/3.9.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/3.9.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/3.9.0/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/opencl-c.h
OLD_FILES+=usr/lib/clang/3.9.0/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/s390intrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/vadefs.h
OLD_FILES+=usr/lib/clang/3.9.0/include/vecintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/3.9.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/3.9.0/include
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.9.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/3.9.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/3.9.0/lib
OLD_DIRS+=usr/lib/clang/3.9.0
# 20161205: libproc version bump
OLD_LIBS+=usr/lib/libproc.so.3
# 20161127: Remove vm_page_cache(9)
OLD_FILES+=usr/share/man/man9/vm_page_cache.9.gz
# 20161124: new clang import which bumps version from 3.8.0 to 3.9.0
OLD_FILES+=usr/lib/clang/3.8.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/3.8.0/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/3.8.0/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/3.8.0/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/3.8.0/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/3.8.0/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/3.8.0/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/3.8.0/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/3.8.0/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/3.8.0/include/sanitizer
OLD_FILES+=usr/lib/clang/3.8.0/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/3.8.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/3.8.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/3.8.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/3.8.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/altivec.h
OLD_FILES+=usr/lib/clang/3.8.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/3.8.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/3.8.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/3.8.0/include/cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/3.8.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/htmintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/3.8.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/3.8.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/3.8.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/s390intrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/vadefs.h
OLD_FILES+=usr/lib/clang/3.8.0/include/vecintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/3.8.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/3.8.0/include
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/3.8.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/3.8.0/lib
OLD_DIRS+=usr/lib/clang/3.8.0
# 20161121: Hyper-V manuals only apply to amd64 and i386
.if ${TARGET_ARCH} != "amd64" && ${TARGET_ARCH} != "i386"
OLD_FILES+=usr/share/man/man4/hv_kvp.4.gz
OLD_FILES+=usr/share/man/man4/hv_netvsc.4.gz
OLD_FILES+=usr/share/man/man4/hv_storvsc.4.gz
OLD_FILES+=usr/share/man/man4/hv_utils.4.gz
OLD_FILES+=usr/share/man/man4/hv_vmbus.4.gz
OLD_FILES+=usr/share/man/man4/hv_vss.4.gz
.endif
# 20161118: Remove hv_ata_pci_disengage(4)
OLD_FILES+=usr/share/man/man4/hv_ata_pci_disengage.4.gz
# 20161017: urtwn(4) was merged into rtwn(4)
OLD_FILES+=usr/share/man/man4/if_urtwn.4.gz
OLD_FILES+=usr/share/man/man4/urtwn.4.gz
OLD_FILES+=usr/share/man/man4/urtwnfw.4.gz
# 20161015: Remove GNU rcs
OLD_FILES+=usr/bin/ci
OLD_FILES+=usr/bin/co
OLD_FILES+=usr/bin/merge
OLD_FILES+=usr/bin/rcs
OLD_FILES+=usr/bin/rcsclean
OLD_FILES+=usr/bin/rcsdiff
OLD_FILES+=usr/bin/rcsfreeze
OLD_FILES+=usr/bin/rcsmerge
OLD_FILES+=usr/bin/rlog
OLD_FILES+=usr/share/doc/psd/13.rcs/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/13.rcs/rcs_func.ascii.gz
OLD_DIRS+=usr/share/doc/psd/13.rcs
OLD_FILES+=usr/share/man/man1/ci.1.gz
OLD_FILES+=usr/share/man/man1/co.1.gz
OLD_FILES+=usr/share/man/man1/merge.1.gz
OLD_FILES+=usr/share/man/man1/rcs.1.gz
OLD_FILES+=usr/share/man/man1/rcsclean.1.gz
OLD_FILES+=usr/share/man/man1/rcsdiff.1.gz
OLD_FILES+=usr/share/man/man1/rcsfreeze.1.gz
OLD_FILES+=usr/share/man/man1/rcsintro.1.gz
OLD_FILES+=usr/share/man/man1/rcsmerge.1.gz
OLD_FILES+=usr/share/man/man1/rlog.1.gz
OLD_FILES+=usr/share/man/man5/rcsfile.5.gz
# 20161010: remove link to removed m_getclr(9) macro
OLD_FILES+=usr/share/man/man9/m_getclr.9.gz
# 20161003: MK_ELFCOPY_AS_OBJCOPY option retired
OLD_FILES+=usr/bin/elfcopy
OLD_FILES+=usr/share/man/man1/elfcopy.1.gz
# 20160906: libkqueue tests moved to /usr/tests/sys/kqueue/libkqueue
OLD_FILES+=usr/tests/sys/kqueue/kqtest
OLD_FILES+=usr/tests/sys/kqueue/kqueue_test
# 20160903: idle page zeroing support removed
OLD_FILES+=usr/share/man/man9/pmap_zero_idle.9.gz
# 20160901: Remove digi(4)
OLD_FILES+=usr/share/man/man4/digi.4.gz
# 20160819: Remove ie(4)
OLD_FILES+=usr/share/man/man4/i386/ie.4.gz
# 20160819: Remove spic(4)
OLD_FILES+=usr/share/man/man4/spic.4.gz
# 20160819: Remove wl(4) and wlconfig(8)
OLD_FILES+=usr/share/man/man4/i386/wl.4.gz
OLD_FILES+=usr/sbin/wlconfig
OLD_FILES+=usr/share/man/man8/i386/wlconfig.8.gz
# 20160819: Remove si(4) and sicontrol(8)
OLD_FILES+=usr/share/man/man4/si.4.gz
OLD_FILES+=usr/sbin/sicontrol
OLD_FILES+=usr/share/man/man8/sicontrol.8.gz
# 20160819: Remove scd(4)
OLD_FILES+=usr/share/man/man4/scd.4.gz
# 20160815: Remove mcd(4)
OLD_FILES+=usr/share/man/man4/mcd.4.gz
# 20160805: lockmgr_waiters(9) removed
OLD_FILES+=usr/share/man/man9/lockmgr_waiters.9.gz
# 20160703: POSIXify locales with variants
OLD_FILES+=usr/share/locale/zh_Hant_TW.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_Hant_TW.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_Hant_TW.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_Hant_TW.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_Hant_TW.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_Hant_TW.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/zh_Hant_TW.UTF-8
OLD_FILES+=usr/share/locale/zh_Hant_TW.Big5/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_Hant_TW.Big5/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_Hant_TW.Big5/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_Hant_TW.Big5/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_Hant_TW.Big5/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_Hant_TW.Big5/LC_TIME
OLD_DIRS+=usr/share/locale/zh_Hant_TW.Big5
OLD_FILES+=usr/share/locale/zh_Hant_HK.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_Hant_HK.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_Hant_HK.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_Hant_HK.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_Hant_HK.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_Hant_HK.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/zh_Hant_HK.UTF-8
OLD_FILES+=usr/share/locale/zh_Hans_CN.eucCN/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_Hans_CN.eucCN/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_Hans_CN.eucCN/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_Hans_CN.eucCN/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_Hans_CN.eucCN/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_Hans_CN.eucCN/LC_TIME
OLD_DIRS+=usr/share/locale/zh_Hans_CN.eucCN
OLD_FILES+=usr/share/locale/zh_Hans_CN.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_Hans_CN.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_Hans_CN.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_Hans_CN.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_Hans_CN.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_Hans_CN.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/zh_Hans_CN.UTF-8
OLD_FILES+=usr/share/locale/zh_Hans_CN.GBK/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_Hans_CN.GBK/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_Hans_CN.GBK/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_Hans_CN.GBK/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_Hans_CN.GBK/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_Hans_CN.GBK/LC_TIME
OLD_DIRS+=usr/share/locale/zh_Hans_CN.GBK
OLD_FILES+=usr/share/locale/zh_Hans_CN.GB2312/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_Hans_CN.GB2312/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_Hans_CN.GB2312/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_Hans_CN.GB2312/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_Hans_CN.GB2312/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_Hans_CN.GB2312/LC_TIME
OLD_DIRS+=usr/share/locale/zh_Hans_CN.GB2312
OLD_FILES+=usr/share/locale/zh_Hans_CN.GB18030/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_Hans_CN.GB18030/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_Hans_CN.GB18030/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_Hans_CN.GB18030/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_Hans_CN.GB18030/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_Hans_CN.GB18030/LC_TIME
OLD_DIRS+=usr/share/locale/zh_Hans_CN.GB18030
OLD_FILES+=usr/share/locale/sr_Latn_RS.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/sr_Latn_RS.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/sr_Latn_RS.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/sr_Latn_RS.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/sr_Latn_RS.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/sr_Latn_RS.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/sr_Latn_RS.UTF-8
OLD_FILES+=usr/share/locale/sr_Latn_RS.ISO8859-2/LC_COLLATE
OLD_FILES+=usr/share/locale/sr_Latn_RS.ISO8859-2/LC_CTYPE
OLD_FILES+=usr/share/locale/sr_Latn_RS.ISO8859-2/LC_MESSAGES
OLD_FILES+=usr/share/locale/sr_Latn_RS.ISO8859-2/LC_MONETARY
OLD_FILES+=usr/share/locale/sr_Latn_RS.ISO8859-2/LC_NUMERIC
OLD_FILES+=usr/share/locale/sr_Latn_RS.ISO8859-2/LC_TIME
OLD_DIRS+=usr/share/locale/sr_Latn_RS.ISO8859-2
OLD_FILES+=usr/share/locale/sr_Cyrl_RS.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/sr_Cyrl_RS.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/sr_Cyrl_RS.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/sr_Cyrl_RS.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/sr_Cyrl_RS.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/sr_Cyrl_RS.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/sr_Cyrl_RS.UTF-8
OLD_FILES+=usr/share/locale/sr_Cyrl_RS.ISO8859-5/LC_COLLATE
OLD_FILES+=usr/share/locale/sr_Cyrl_RS.ISO8859-5/LC_CTYPE
OLD_FILES+=usr/share/locale/sr_Cyrl_RS.ISO8859-5/LC_MESSAGES
OLD_FILES+=usr/share/locale/sr_Cyrl_RS.ISO8859-5/LC_MONETARY
OLD_FILES+=usr/share/locale/sr_Cyrl_RS.ISO8859-5/LC_NUMERIC
OLD_FILES+=usr/share/locale/sr_Cyrl_RS.ISO8859-5/LC_TIME
OLD_DIRS+=usr/share/locale/sr_Cyrl_RS.ISO8859-5
OLD_FILES+=usr/share/locale/mn_Cyrl_MN.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/mn_Cyrl_MN.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/mn_Cyrl_MN.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/mn_Cyrl_MN.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/mn_Cyrl_MN.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/mn_Cyrl_MN.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/mn_Cyrl_MN.UTF-8
OLD_FILES+=usr/share/locale/kk_Cyrl_KZ.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/kk_Cyrl_KZ.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/kk_Cyrl_KZ.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/kk_Cyrl_KZ.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/kk_Cyrl_KZ.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/kk_Cyrl_KZ.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/kk_Cyrl_KZ.UTF-8
# 20160608: removed pam_verbose_error
OLD_LIBS+=usr/lib/libpam.so.5
OLD_LIBS+=usr/lib/pam_chroot.so.5
OLD_LIBS+=usr/lib/pam_deny.so.5
OLD_LIBS+=usr/lib/pam_echo.so.5
OLD_LIBS+=usr/lib/pam_exec.so.5
OLD_LIBS+=usr/lib/pam_ftpusers.so.5
OLD_LIBS+=usr/lib/pam_group.so.5
OLD_LIBS+=usr/lib/pam_guest.so.5
OLD_LIBS+=usr/lib/pam_krb5.so.5
OLD_LIBS+=usr/lib/pam_ksu.so.5
OLD_LIBS+=usr/lib/pam_lastlog.so.5
OLD_LIBS+=usr/lib/pam_login_access.so.5
OLD_LIBS+=usr/lib/pam_nologin.so.5
OLD_LIBS+=usr/lib/pam_opie.so.5
OLD_LIBS+=usr/lib/pam_opieaccess.so.5
OLD_LIBS+=usr/lib/pam_passwdqc.so.5
OLD_LIBS+=usr/lib/pam_permit.so.5
OLD_LIBS+=usr/lib/pam_radius.so.5
OLD_LIBS+=usr/lib/pam_rhosts.so.5
OLD_LIBS+=usr/lib/pam_rootok.so.5
OLD_LIBS+=usr/lib/pam_securetty.so.5
OLD_LIBS+=usr/lib/pam_self.so.5
OLD_LIBS+=usr/lib/pam_ssh.so.5
OLD_LIBS+=usr/lib/pam_tacplus.so.5
OLD_LIBS+=usr/lib/pam_unix.so.5
# 20160523: remove extranous ALTQ files
OLD_FILES+=usr/include/altq/altq_codel.h
OLD_FILES+=usr/include/altq/altq_fairq.h
# 20160519: remove DTrace Toolkit from base
OLD_FILES+=usr/sbin/dtruss
OLD_FILES+=usr/share/dtrace/toolkit/execsnoop
OLD_FILES+=usr/share/dtrace/toolkit/hotkernel
OLD_FILES+=usr/share/dtrace/toolkit/hotuser
OLD_FILES+=usr/share/dtrace/toolkit/opensnoop
OLD_FILES+=usr/share/dtrace/toolkit/procsystime
OLD_DIRS+=usr/share/dtrace/toolkit
OLD_FILES+=usr/share/man/man1/dtruss.1.gz
# 20160519: stale MLINK removed
OLD_FILES+=usr/share/man/man9/rman_await_resource.9.gz
# 20160517: ReiserFS removed
OLD_FILES+=usr/share/man/man5/reiserfs.5.gz
# 20160504: tests rework
OLD_FILES+=usr/tests/lib/libc/regex/data/README
# 20160430: kvm_getfiles(3) removed from kvm(3)
OLD_LIBS+=lib/libkvm.so.6
OLD_FILES+=usr/share/man/man3/kvm_getfiles.3.gz
# 20160423: remove mroute6d
OLD_FILES+=etc/rc.d/mroute6d
# 20160419: rename units.lib -> definitions.units
OLD_FILES+=usr/share/misc/units.lib
# 20160419: remove Big5HKSCS locales
OLD_FILES+=usr/share/locale/zh_HK.Big5HKSCS/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_HK.Big5HKSCS/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_HK.Big5HKSCS/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_HK.Big5HKSCS/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_HK.Big5HKSCS/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_HK.Big5HKSCS/LC_TIME
OLD_DIRS+=usr/share/locale/zh_HK.Big5HKSCS
OLD_FILES+=usr/share/locale/zh_Hant_HK.Big5HKSCS/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_Hant_HK.Big5HKSCS/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_Hant_HK.Big5HKSCS/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_Hant_HK.Big5HKSCS/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_Hant_HK.Big5HKSCS/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_Hant_HK.Big5HKSCS/LC_TIME
OLD_DIRS+=usr/share/locale/zh_Hant_HK.Big5HKSCS
# 20160317: rman_res_t size bump to uintmax_t
OLD_LIBS+=usr/lib/libdevinfo.so.5
# 20160305: new clang import which bumps version from 3.7.1 to 3.8.0
OLD_FILES+=usr/bin/macho-dump
OLD_FILES+=usr/bin/tblgen
OLD_FILES+=usr/lib/clang/3.7.1/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/3.7.1/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/3.7.1/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/3.7.1/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/3.7.1/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/3.7.1/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/3.7.1/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/3.7.1/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/3.7.1/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/3.7.1/include/sanitizer
OLD_FILES+=usr/lib/clang/3.7.1/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/3.7.1/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/3.7.1/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/3.7.1/include/adxintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/altivec.h
OLD_FILES+=usr/lib/clang/3.7.1/include/ammintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/arm_acle.h
OLD_FILES+=usr/lib/clang/3.7.1/include/arm_neon.h
OLD_FILES+=usr/lib/clang/3.7.1/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/avxintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/cpuid.h
OLD_FILES+=usr/lib/clang/3.7.1/include/cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/3.7.1/include/emmintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/htmintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/immintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/3.7.1/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/3.7.1/include/mmintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/module.modulemap
OLD_FILES+=usr/lib/clang/3.7.1/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/s390intrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/shaintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/smmintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/vadefs.h
OLD_FILES+=usr/lib/clang/3.7.1/include/vecintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/x86intrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/xopintrin.h
OLD_FILES+=usr/lib/clang/3.7.1/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/3.7.1/include
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.7.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/3.7.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/3.7.1/lib
OLD_DIRS+=usr/lib/clang/3.7.1
OLD_FILES+=usr/share/man/man1/tblgen.1.gz
# 20160301: Remove taskqueue_enqueue_fast
OLD_FILES+=usr/share/man/man9/taskqueue_enqueue_fast.9.gz
# 20160225: Remove casperd and libcapsicum
OLD_FILES+=sbin/casperd
OLD_FILES+=etc/rc.d/casperd
OLD_FILES+=usr/share/man/man8/casperd.8.gz
OLD_FILES+=usr/include/libcapsicum.h
OLD_FILES+=usr/include/libcapsicum_service.h
OLD_FILES+=usr/include/libcapsicum.h
OLD_FILES+=usr/share/man/man3/libcapsicum.3.gz
OLD_FILES+=usr/include/libcapsicum_dns.h
OLD_FILES+=usr/include/libcapsicum_grp.h
OLD_FILES+=usr/include/libcapsicum_impl.h
OLD_FILES+=usr/include/libcapsicum_pwd.h
OLD_FILES+=usr/include/libcapsicum_random.h
OLD_FILES+=usr/include/libcapsicum_sysctl.h
OLD_FILES+=libexec/casper/dns
OLD_FILES+=libexec/casper/grp
OLD_FILES+=libexec/casper/pwd
OLD_FILES+=libexec/casper/random
OLD_FILES+=libexec/casper/sysctl
OLD_FILES+=libexec/casper/.debug/random.debug
OLD_FILES+=libexec/casper/.debug/dns.debug
OLD_FILES+=libexec/casper/.debug/sysctl.debug
OLD_FILES+=libexec/casper/.debug/pwd.debug
OLD_FILES+=libexec/casper/.debug/grp.debug
OLD_DIRS+=libexec/casper/.debug
OLD_DIRS+=libexec/casper
OLD_FILES+=usr/lib/libcapsicum.a
OLD_FILES+=usr/lib/libcapsicum.so
OLD_LIBS+=lib/libcapsicum.so.0
OLD_FILES+=usr/lib/libcapsicum_p.a
# 20160223: functionality from mkulzma(1) merged into mkuzip(1)
OLD_FILES+=usr/bin/mkulzma
OLD_FILES+=usr/share/man/man4/geom_uncompress.4.gz
OLD_FILES+=usr/share/man/man8/mkulzma.8.gz
# 20160211: Remove obsolete unbound-control-setup
OLD_FILES+=usr/sbin/unbound-control-setup
# 20160121: cc.h moved
OLD_FILES+=usr/include/netinet/cc.h
# 20160116: Update mandoc to cvs snapshot 20160116
OLD_FILES+=usr/share/mdocml/example.style.css
OLD_FILES+=usr/share/mdocml/style.css
OLD_DIRS+=usr/share/mdocml
# 20160114: SA-16:06.snmpd
OLD_FILES+=usr/share/examples/etc/snmpd.config
# 20160107: GNU ld installed as ld.bfd and linked as ld
OLD_FILES+=usr/lib/debug/usr/bin/ld.debug
# 20151225: new clang import which bumps version from 3.7.0 to 3.7.1
OLD_FILES+=usr/lib/clang/3.7.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/3.7.0/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/3.7.0/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/3.7.0/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/3.7.0/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/3.7.0/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/3.7.0/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/3.7.0/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/3.7.0/include/sanitizer/tsan_interface_atomic.h
OLD_DIRS+=usr/lib/clang/3.7.0/include/sanitizer
OLD_FILES+=usr/lib/clang/3.7.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/3.7.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/3.7.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/3.7.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/altivec.h
OLD_FILES+=usr/lib/clang/3.7.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/3.7.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/3.7.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/3.7.0/include/cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/3.7.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/htmintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/3.7.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/3.7.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/3.7.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/s390intrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/vadefs.h
OLD_FILES+=usr/lib/clang/3.7.0/include/vecintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/3.7.0/include
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/3.7.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/3.7.0/lib
OLD_DIRS+=usr/lib/clang/3.7.0
# 20151130: libelf moved from /usr/lib to /lib (libkvm dependency in r291406)
MOVED_LIBS+=usr/lib/libelf.so.2
# 20151115: Fox bad upgrade scheme
OLD_FILES+=usr/share/locale/zh_CN.GB18030/zh_Hans_CN.GB18030
OLD_FILES+=usr/share/locale/zh_CN.GB2312/zh_Hans_CN.GB2312
OLD_FILES+=usr/share/locale/zh_CN.GBK/zh_Hans_CN.GBK
OLD_FILES+=usr/share/locale/zh_CN.UTF-8/zh_Hans_CN.UTF-8
OLD_FILES+=usr/share/locale/zh_CN.eucCN/zh_Hans_CN.eucCN
OLD_FILES+=usr/share/locale/zh_TW.Big5/zh_Hant_TW.Big5
OLD_FILES+=usr/share/locale/zh_TW.UTF-8/zh_Hant_TW.UTF-8
# 20151107: String collation improvements
OLD_FILES+=usr/share/locale/UTF-8/LC_CTYPE
OLD_DIRS+=usr/share/locale/UTF-8
OLD_FILES+=usr/share/locale/kk_KZ.PT154/LC_COLLATE
OLD_FILES+=usr/share/locale/kk_KZ.PT154/LC_CTYPE
OLD_FILES+=usr/share/locale/kk_KZ.PT154/LC_MESSAGES
OLD_FILES+=usr/share/locale/kk_KZ.PT154/LC_MONETARY
OLD_FILES+=usr/share/locale/kk_KZ.PT154/LC_NUMERIC
OLD_FILES+=usr/share/locale/kk_KZ.PT154/LC_TIME
OLD_DIRS+=usr/share/locale/kk_KZ.PT154/
OLD_FILES+=usr/share/locale/la_LN.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/la_LN.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/la_LN.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/la_LN.ISO8859-1
OLD_FILES+=usr/share/locale/la_LN.ISO8859-13/LC_COLLATE
OLD_FILES+=usr/share/locale/la_LN.ISO8859-13/LC_CTYPE
OLD_DIRS+=usr/share/locale/la_LN.ISO8859-13
OLD_FILES+=usr/share/locale/la_LN.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/la_LN.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/la_LN.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/la_LN.ISO8859-15
OLD_FILES+=usr/share/locale/la_LN.ISO8859-2/LC_COLLATE
OLD_FILES+=usr/share/locale/la_LN.ISO8859-2/LC_CTYPE
OLD_FILES+=usr/share/locale/la_LN.ISO8859-2/LC_TIME
OLD_DIRS+=usr/share/locale/la_LN.ISO8859-2
OLD_FILES+=usr/share/locale/la_LN.ISO8859-4/LC_COLLATE
OLD_FILES+=usr/share/locale/la_LN.ISO8859-4/LC_CTYPE
OLD_FILES+=usr/share/locale/la_LN.ISO8859-4/LC_TIME
OLD_DIRS+=usr/share/locale/la_LN.ISO8859-4
OLD_FILES+=usr/share/locale/la_LN.US-ASCII/LC_COLLATE
OLD_FILES+=usr/share/locale/la_LN.US-ASCII/LC_CTYPE
OLD_FILES+=usr/share/locale/la_LN.US-ASCII/LC_TIME
OLD_DIRS+=usr/share/locale/la_LN.US-ASCII
OLD_FILES+=usr/share/locale/lt_LT.ISO8859-4/LC_MESSAGES
OLD_FILES+=usr/share/locale/lt_LT.ISO8859-4/LC_TIME
OLD_FILES+=usr/share/locale/lt_LT.ISO8859-4/LC_COLLATE
OLD_FILES+=usr/share/locale/lt_LT.ISO8859-4/LC_MONETARY
OLD_FILES+=usr/share/locale/lt_LT.ISO8859-4/LC_CTYPE
OLD_FILES+=usr/share/locale/lt_LT.ISO8859-4/LC_NUMERIC
OLD_DIRS+=usr/share/locale/lt_LT.ISO8859-4
OLD_FILES+=usr/share/locale/no_NO.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/no_NO.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/no_NO.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/no_NO.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/no_NO.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/no_NO.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/no_NO.ISO8859-1
OLD_FILES+=usr/share/locale/no_NO.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/no_NO.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/no_NO.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/no_NO.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/no_NO.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/no_NO.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/no_NO.ISO8859-15
OLD_FILES+=usr/share/locale/no_NO.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/no_NO.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/no_NO.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/no_NO.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/no_NO.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/no_NO.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/no_NO.UTF-8
OLD_FILES+=usr/share/locale/sr_YU.ISO8859-2/LC_COLLATE
OLD_FILES+=usr/share/locale/sr_YU.ISO8859-2/LC_TIME
OLD_FILES+=usr/share/locale/sr_YU.ISO8859-2/LC_CTYPE
OLD_FILES+=usr/share/locale/sr_YU.ISO8859-2/LC_MESSAGES
OLD_FILES+=usr/share/locale/sr_YU.ISO8859-2/LC_NUMERIC
OLD_FILES+=usr/share/locale/sr_YU.ISO8859-2/LC_MONETARY
OLD_DIRS+=usr/share/locale/sr_YU.ISO8859-2
OLD_FILES+=usr/share/locale/sr_YU.ISO8859-5/LC_COLLATE
OLD_FILES+=usr/share/locale/sr_YU.ISO8859-5/LC_MONETARY
OLD_FILES+=usr/share/locale/sr_YU.ISO8859-5/LC_NUMERIC
OLD_FILES+=usr/share/locale/sr_YU.ISO8859-5/LC_CTYPE
OLD_FILES+=usr/share/locale/sr_YU.ISO8859-5/LC_TIME
OLD_FILES+=usr/share/locale/sr_YU.ISO8859-5/LC_MESSAGES
OLD_DIRS+=usr/share/locale/sr_YU.ISO8859-5
OLD_FILES+=usr/share/locale/sr_YU.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/sr_YU.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/sr_YU.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/sr_YU.UTF-8/LC_TIME
OLD_FILES+=usr/share/locale/sr_YU.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/sr_YU.UTF-8/LC_MESSAGES
OLD_DIRS+=usr/share/locale/sr_YU.UTF-8
# 20151101: added missing _test suffix on multiple tests in lib/libc
OLD_FILES+=usr/tests/lib/libc/c063/faccessat
OLD_FILES+=usr/tests/lib/libc/c063/fchmodat
OLD_FILES+=usr/tests/lib/libc/c063/fchownat
OLD_FILES+=usr/tests/lib/libc/c063/fexecve
OLD_FILES+=usr/tests/lib/libc/c063/fstatat
OLD_FILES+=usr/tests/lib/libc/c063/linkat
OLD_FILES+=usr/tests/lib/libc/c063/mkdirat
OLD_FILES+=usr/tests/lib/libc/c063/mkfifoat
OLD_FILES+=usr/tests/lib/libc/c063/mknodat
OLD_FILES+=usr/tests/lib/libc/c063/openat
OLD_FILES+=usr/tests/lib/libc/c063/readlinkat
OLD_FILES+=usr/tests/lib/libc/c063/renameat
OLD_FILES+=usr/tests/lib/libc/c063/symlinkat
OLD_FILES+=usr/tests/lib/libc/c063/unlinkat
OLD_FILES+=usr/tests/lib/libc/c063/utimensat
OLD_FILES+=usr/tests/lib/libc/string/memchr
OLD_FILES+=usr/tests/lib/libc/string/memcpy
OLD_FILES+=usr/tests/lib/libc/string/memmem
OLD_FILES+=usr/tests/lib/libc/string/memset
OLD_FILES+=usr/tests/lib/libc/string/strcat
OLD_FILES+=usr/tests/lib/libc/string/strchr
OLD_FILES+=usr/tests/lib/libc/string/strcmp
OLD_FILES+=usr/tests/lib/libc/string/strcpy
OLD_FILES+=usr/tests/lib/libc/string/strcspn
OLD_FILES+=usr/tests/lib/libc/string/strerror
OLD_FILES+=usr/tests/lib/libc/string/strlen
OLD_FILES+=usr/tests/lib/libc/string/strpbrk
OLD_FILES+=usr/tests/lib/libc/string/strrchr
OLD_FILES+=usr/tests/lib/libc/string/strspn
OLD_FILES+=usr/tests/lib/libc/string/swab
# 20151101: 430.status-rwho was renamed to 430.status-uptime
OLD_FILES+=etc/periodic/daily/430.status-rwho
# 20151030: OpenSSL 1.0.2d import
OLD_FILES+=usr/share/openssl/man/man3/CMS_set1_signer_certs.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_PKEY_ctrl.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_PKEY_ctrl_str.3.gz
OLD_FILES+=usr/share/openssl/man/man3/d2i_509_CRL_fp.3.gz
OLD_LIBS+=lib/libcrypto.so.7
OLD_LIBS+=usr/lib/libssl.so.7
# 20151029: LinuxKPI moved to sys/compat/linuxkpi
OLD_FILES+=usr/include/dev/usb/usb_compat_linux.h
# 20151015: test symbols moved to /usr/lib/debug
OLD_DIRS+=usr/tests/lib/atf/libatf-c++/.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/atf_c++_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/build_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/check_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/config_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/macros_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/tests_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/utils_test.debug
OLD_DIRS+=usr/tests/lib/atf/libatf-c++/detail/.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/application_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/env_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/exceptions_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/fs_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/process_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/sanity_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/text_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/version_helper.debug
OLD_DIRS+=usr/tests/lib/atf/libatf-c/.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/atf_c_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/build_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/check_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/config_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/error_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/macros_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/tc_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/tp_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/utils_test.debug
OLD_DIRS+=usr/tests/lib/atf/libatf-c/detail/.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/dynstr_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/env_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/fs_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/list_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/map_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/process_helpers.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/process_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/sanity_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/text_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/user_test.debug
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/version_helper.debug
OLD_DIRS+=usr/tests/lib/atf/test-programs/.debug
OLD_FILES+=usr/tests/lib/atf/test-programs/.debug/c_helpers.debug
OLD_FILES+=usr/tests/lib/atf/test-programs/.debug/cpp_helpers.debug
OLD_DIRS+=usr/tests/lib/libc/c063/.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/faccessat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/fchmodat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/fchownat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/fexecve.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/fstatat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/linkat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/mkdirat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/mkfifoat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/mknodat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/openat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/readlinkat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/renameat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/symlinkat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/unlinkat.debug
OLD_FILES+=usr/tests/lib/libc/c063/.debug/utimensat.debug
OLD_DIRS+=usr/tests/lib/libc/db/.debug
OLD_FILES+=usr/tests/lib/libc/db/.debug/h_db.debug
OLD_DIRS+=usr/tests/lib/libc/gen/.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/alarm_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/arc4random_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/assert_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/basedirname_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/dir_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/floatunditf_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/fnmatch_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/fpclassify2_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/fpclassify_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/fpsetmask_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/fpsetround_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/ftok_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/getcwd_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/getgrent_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/glob_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/humanize_number_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/isnan_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/nice_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/pause_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/raise_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/realpath_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/setdomainname_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/sethostname_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/sleep_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/syslog_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/time_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/ttyname_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/.debug/vis_test.debug
OLD_DIRS+=usr/tests/lib/libc/gen/execve/.debug
OLD_FILES+=usr/tests/lib/libc/gen/execve/.debug/execve_test.debug
OLD_DIRS+=usr/tests/lib/libc/gen/posix_spawn/.debug
OLD_FILES+=usr/tests/lib/libc/gen/posix_spawn/.debug/fileactions_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/posix_spawn/.debug/h_fileactions.debug
OLD_FILES+=usr/tests/lib/libc/gen/posix_spawn/.debug/h_spawn.debug
OLD_FILES+=usr/tests/lib/libc/gen/posix_spawn/.debug/h_spawnattr.debug
OLD_FILES+=usr/tests/lib/libc/gen/posix_spawn/.debug/spawn_test.debug
OLD_FILES+=usr/tests/lib/libc/gen/posix_spawn/.debug/spawnattr_test.debug
OLD_DIRS+=usr/tests/lib/libc/hash/.debug
OLD_FILES+=usr/tests/lib/libc/hash/.debug/h_hash.debug
OLD_FILES+=usr/tests/lib/libc/hash/.debug/sha2_test.debug
OLD_DIRS+=usr/tests/lib/libc/inet/.debug
OLD_FILES+=usr/tests/lib/libc/inet/.debug/inet_network_test.debug
OLD_DIRS+=usr/tests/lib/libc/locale/.debug
OLD_FILES+=usr/tests/lib/libc/locale/.debug/io_test.debug
OLD_FILES+=usr/tests/lib/libc/locale/.debug/mbrtowc_test.debug
OLD_FILES+=usr/tests/lib/libc/locale/.debug/mbsnrtowcs_test.debug
OLD_FILES+=usr/tests/lib/libc/locale/.debug/mbstowcs_test.debug
OLD_FILES+=usr/tests/lib/libc/locale/.debug/mbtowc_test.debug
OLD_FILES+=usr/tests/lib/libc/locale/.debug/wcscspn_test.debug
OLD_FILES+=usr/tests/lib/libc/locale/.debug/wcspbrk_test.debug
OLD_FILES+=usr/tests/lib/libc/locale/.debug/wcsspn_test.debug
OLD_FILES+=usr/tests/lib/libc/locale/.debug/wcstod_test.debug
OLD_FILES+=usr/tests/lib/libc/locale/.debug/wctomb_test.debug
OLD_DIRS+=usr/tests/lib/libc/net/.debug
OLD_FILES+=usr/tests/lib/libc/net/.debug/ether_aton_test.debug
OLD_FILES+=usr/tests/lib/libc/net/.debug/getprotoent_test.debug
OLD_FILES+=usr/tests/lib/libc/net/.debug/h_dns_server.debug
OLD_FILES+=usr/tests/lib/libc/net/.debug/h_nsd_recurse.debug
OLD_FILES+=usr/tests/lib/libc/net/.debug/h_protoent.debug
OLD_FILES+=usr/tests/lib/libc/net/.debug/h_servent.debug
OLD_DIRS+=usr/tests/lib/libc/regex/.debug
OLD_FILES+=usr/tests/lib/libc/regex/.debug/exhaust_test.debug
OLD_FILES+=usr/tests/lib/libc/regex/.debug/h_regex.debug
OLD_FILES+=usr/tests/lib/libc/regex/.debug/regex_att_test.debug
OLD_DIRS+=usr/tests/lib/libc/ssp/.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_fgets.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_getcwd.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_gets.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_memcpy.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_memmove.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_memset.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_raw.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_read.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_readlink.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_snprintf.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_sprintf.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_stpcpy.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_stpncpy.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_strcat.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_strcpy.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_strncat.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_strncpy.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_vsnprintf.debug
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_vsprintf.debug
OLD_DIRS+=usr/tests/lib/libc/stdio/.debug
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/clearerr_test.debug
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/fflush_test.debug
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/fmemopen2_test.debug
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/fmemopen_test.debug
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/fopen_test.debug
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/fputc_test.debug
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/mktemp_test.debug
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/popen_test.debug
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/printf_test.debug
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/scanf_test.debug
OLD_DIRS+=usr/tests/lib/libc/stdlib/.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/abs_test.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/atoi_test.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/div_test.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/exit_test.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/getenv_test.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/h_getopt.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/h_getopt_long.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/hsearch_test.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/posix_memalign_test.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/random_test.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/strtod_test.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/strtol_test.debug
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/system_test.debug
OLD_DIRS+=usr/tests/lib/libc/string/.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/memchr.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/memcpy.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/memmem.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/memset.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/strcat.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/strchr.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/strcmp.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/strcpy.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/strcspn.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/strerror.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/strlen.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/strpbrk.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/strrchr.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/strspn.debug
OLD_FILES+=usr/tests/lib/libc/string/.debug/swab.debug
OLD_DIRS+=usr/tests/lib/libc/sys/.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/access_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/chroot_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/clock_gettime_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/connect_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/dup_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/fsync_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getcontext_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getgroups_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getitimer_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getlogin_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getpid_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getrusage_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getsid_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/gettimeofday_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/issetugid_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/kevent_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/kill_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/link_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/listen_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mincore_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mkdir_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mkfifo_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mknod_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mlock_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mmap_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mprotect_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/msgctl_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/msgget_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/msgrcv_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/msgsnd_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/msync_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/nanosleep_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/pipe2_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/pipe_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/poll_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/revoke_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/select_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/setrlimit_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/setuid_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/sigaction_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/sigqueue_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/sigtimedwait_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/socketpair_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/stat_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/timer_create_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/truncate_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/ucontext_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/umask_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/unlink_test.debug
OLD_FILES+=usr/tests/lib/libc/sys/.debug/write_test.debug
OLD_DIRS+=usr/tests/lib/libc/termios/.debug
OLD_FILES+=usr/tests/lib/libc/termios/.debug/tcsetpgrp_test.debug
OLD_DIRS+=usr/tests/lib/libc/tls/.debug
OLD_FILES+=usr/tests/lib/libc/tls/.debug/h_tls_dlopen.so.debug
OLD_FILES+=usr/tests/lib/libc/tls/.debug/libh_tls_dynamic.so.1.debug
OLD_FILES+=usr/tests/lib/libc/tls/.debug/tls_dlopen_test.debug
OLD_FILES+=usr/tests/lib/libc/tls/.debug/tls_dynamic_test.debug
OLD_DIRS+=usr/tests/lib/libc/ttyio/.debug
OLD_FILES+=usr/tests/lib/libc/ttyio/.debug/ttyio_test.debug
OLD_DIRS+=usr/tests/lib/libcrypt/.debug
OLD_FILES+=usr/tests/lib/libcrypt/.debug/crypt_tests.debug
OLD_DIRS+=usr/tests/lib/libmp/.debug
OLD_FILES+=usr/tests/lib/libmp/.debug/legacy_test.debug
OLD_DIRS+=usr/tests/lib/libnv/.debug
OLD_FILES+=usr/tests/lib/libnv/.debug/dnv_tests.debug
OLD_FILES+=usr/tests/lib/libnv/.debug/nv_array_tests.debug
OLD_FILES+=usr/tests/lib/libnv/.debug/nv_tests.debug
OLD_FILES+=usr/tests/lib/libnv/.debug/nvlist_add_test.debug
OLD_FILES+=usr/tests/lib/libnv/.debug/nvlist_exists_test.debug
OLD_FILES+=usr/tests/lib/libnv/.debug/nvlist_free_test.debug
OLD_FILES+=usr/tests/lib/libnv/.debug/nvlist_get_test.debug
OLD_FILES+=usr/tests/lib/libnv/.debug/nvlist_move_test.debug
OLD_FILES+=usr/tests/lib/libnv/.debug/nvlist_send_recv_test.debug
OLD_DIRS+=usr/tests/lib/libpam/.debug
OLD_FILES+=usr/tests/lib/libpam/.debug/t_openpam_ctype.debug
OLD_FILES+=usr/tests/lib/libpam/.debug/t_openpam_readlinev.debug
OLD_FILES+=usr/tests/lib/libpam/.debug/t_openpam_readword.debug
OLD_DIRS+=usr/tests/lib/libproc/.debug
OLD_FILES+=usr/tests/lib/libproc/.debug/proc_test.debug
OLD_FILES+=usr/tests/lib/libproc/.debug/target_prog.debug
OLD_DIRS+=usr/tests/lib/librt/.debug
OLD_FILES+=usr/tests/lib/librt/.debug/sched_test.debug
OLD_FILES+=usr/tests/lib/librt/.debug/sem_test.debug
OLD_DIRS+=usr/tests/lib/libthr/.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/barrier_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/cond_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/condwait_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/detach_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/equal_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/fork_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/fpu_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/h_atexit.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/h_cancel.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/h_exit.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/h_resolv.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/join_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/kill_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/mutex_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/once_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/preempt_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/rwlock_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/sem_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/siglongjmp_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/sigmask_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/sigsuspend_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/sleep_test.debug
OLD_FILES+=usr/tests/lib/libthr/.debug/swapcontext_test.debug
OLD_DIRS+=usr/tests/lib/libthr/dlopen/.debug
OLD_FILES+=usr/tests/lib/libthr/dlopen/.debug/dlopen_test.debug
OLD_FILES+=usr/tests/lib/libthr/dlopen/.debug/h_pthread_dlopen.so.1.debug
OLD_FILES+=usr/tests/lib/libthr/dlopen/.debug/main_pthread_create_test.debug
OLD_DIRS+=usr/tests/lib/libutil/.debug
OLD_FILES+=usr/tests/lib/libutil/.debug/flopen_test.debug
OLD_FILES+=usr/tests/lib/libutil/.debug/grp_test.debug
OLD_FILES+=usr/tests/lib/libutil/.debug/humanize_number_test.debug
OLD_FILES+=usr/tests/lib/libutil/.debug/pidfile_test.debug
OLD_FILES+=usr/tests/lib/libutil/.debug/trimdomain-nodomain_test.debug
OLD_FILES+=usr/tests/lib/libutil/.debug/trimdomain_test.debug
OLD_DIRS+=usr/tests/lib/libxo/.debug
OLD_FILES+=usr/tests/lib/libxo/.debug/libenc_test.so.debug
OLD_FILES+=usr/tests/lib/libxo/.debug/test_01.debug
OLD_FILES+=usr/tests/lib/libxo/.debug/test_02.debug
OLD_FILES+=usr/tests/lib/libxo/.debug/test_03.debug
OLD_FILES+=usr/tests/lib/libxo/.debug/test_04.debug
OLD_FILES+=usr/tests/lib/libxo/.debug/test_05.debug
OLD_FILES+=usr/tests/lib/libxo/.debug/test_06.debug
OLD_FILES+=usr/tests/lib/libxo/.debug/test_07.debug
OLD_FILES+=usr/tests/lib/libxo/.debug/test_08.debug
OLD_FILES+=usr/tests/lib/libxo/.debug/test_09.debug
OLD_FILES+=usr/tests/lib/libxo/.debug/test_10.debug
OLD_FILES+=usr/tests/lib/libxo/.debug/test_11.debug
OLD_DIRS+=usr/tests/lib/msun/.debug
OLD_FILES+=usr/tests/lib/msun/.debug/acos_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/asin_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/atan_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/cbrt_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/ceil_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/cos_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/cosh_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/erf_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/exp_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/fmod_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/infinity_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/ldexp_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/log_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/pow_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/precision_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/round_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/scalbn_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/sin_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/sinh_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/sqrt_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/tan_test.debug
OLD_FILES+=usr/tests/lib/msun/.debug/tanh_test.debug
OLD_DIRS+=usr/tests/libexec/rtld-elf/.debug
OLD_FILES+=usr/tests/libexec/rtld-elf/.debug/ld_library_pathfds.debug
OLD_FILES+=usr/tests/libexec/rtld-elf/.debug/libpythagoras.so.0.debug
OLD_FILES+=usr/tests/libexec/rtld-elf/.debug/target.debug
OLD_DIRS+=usr/tests/sbin/devd/.debug
OLD_FILES+=usr/tests/sbin/devd/.debug/client_test.debug
OLD_DIRS+=usr/tests/sbin/dhclient/.debug
OLD_FILES+=usr/tests/sbin/dhclient/.debug/option-domain-search_test.debug
OLD_DIRS+=usr/tests/share/examples/tests/atf/.debug
OLD_FILES+=usr/tests/share/examples/tests/atf/.debug/printf_test.debug
OLD_DIRS+=usr/tests/share/examples/tests/plain/.debug
OLD_FILES+=usr/tests/share/examples/tests/plain/.debug/printf_test.debug
OLD_DIRS+=usr/tests/sys/aio/.debug
OLD_FILES+=usr/tests/sys/aio/.debug/aio_kqueue_test.debug
OLD_FILES+=usr/tests/sys/aio/.debug/aio_test.debug
OLD_FILES+=usr/tests/sys/aio/.debug/lio_kqueue_test.debug
OLD_DIRS+=usr/tests/sys/fifo/.debug
OLD_FILES+=usr/tests/sys/fifo/.debug/fifo_create.debug
OLD_FILES+=usr/tests/sys/fifo/.debug/fifo_io.debug
OLD_FILES+=usr/tests/sys/fifo/.debug/fifo_misc.debug
OLD_FILES+=usr/tests/sys/fifo/.debug/fifo_open.debug
OLD_DIRS+=usr/tests/sys/file/.debug
OLD_FILES+=usr/tests/sys/file/.debug/closefrom_test.debug
OLD_FILES+=usr/tests/sys/file/.debug/dup_test.debug
OLD_FILES+=usr/tests/sys/file/.debug/fcntlflags_test.debug
OLD_FILES+=usr/tests/sys/file/.debug/flock_helper.debug
OLD_FILES+=usr/tests/sys/file/.debug/ftruncate_test.debug
OLD_FILES+=usr/tests/sys/file/.debug/newfileops_on_fork_test.debug
OLD_DIRS+=usr/tests/sys/kern/.debug
OLD_FILES+=usr/tests/sys/kern/.debug/kern_descrip_test.debug
OLD_FILES+=usr/tests/sys/kern/.debug/ptrace_test.debug
OLD_FILES+=usr/tests/sys/kern/.debug/unix_seqpacket_test.debug
OLD_DIRS+=usr/tests/sys/kern/execve/.debug
OLD_FILES+=usr/tests/sys/kern/execve/.debug/execve_helper.debug
OLD_FILES+=usr/tests/sys/kern/execve/.debug/good_aout.debug
OLD_DIRS+=usr/tests/sys/kqueue/.debug
OLD_FILES+=usr/tests/sys/kqueue/.debug/kqtest.debug
OLD_DIRS+=usr/tests/sys/mqueue/.debug
OLD_FILES+=usr/tests/sys/mqueue/.debug/mqtest1.debug
OLD_FILES+=usr/tests/sys/mqueue/.debug/mqtest2.debug
OLD_FILES+=usr/tests/sys/mqueue/.debug/mqtest3.debug
OLD_FILES+=usr/tests/sys/mqueue/.debug/mqtest4.debug
OLD_FILES+=usr/tests/sys/mqueue/.debug/mqtest5.debug
OLD_DIRS+=usr/tests/sys/netinet/.debug
OLD_FILES+=usr/tests/sys/netinet/.debug/udp_dontroute.debug
OLD_DIRS+=usr/tests/sys/pjdfstest/.debug
OLD_FILES+=usr/tests/sys/pjdfstest/.debug/pjdfstest.debug
OLD_DIRS+=usr/tests/sys/vm/.debug
OLD_FILES+=usr/tests/sys/vm/.debug/mmap_test.debug
# 20151015: Rename files due to file-installed-as-dir bug
OLD_FILES+=usr/share/doc/legal/realtek
OLD_FILES+=usr/share/doc/legal/realtek/LICENSE
OLD_DIRS+=usr/share/doc/legal/realtek
OLD_DIRS+=usr/share/doc/legal/intel_ipw
OLD_FILES+=usr/share/doc/legal/intel_ipw/LICENSE
OLD_FILES+=usr/share/doc/legal/intel_iwn
OLD_FILES+=usr/share/doc/legal/intel_iwn/LICENSE
OLD_DIRS+=usr/share/doc/legal/intel_iwn
OLD_DIRS+=usr/share/doc/legal/intel_iwi
OLD_FILES+=usr/share/doc/legal/intel_iwi/LICENSE
OLD_DIRS+=usr/share/doc/legal/intel_wpi
OLD_FILES+=usr/share/doc/legal/intel_wpi/LICENSE
# 20151006: new libc++ import
OLD_FILES+=usr/include/c++/__tuple_03
OLD_FILES+=usr/include/c++/v1/__tuple_03
OLD_FILES+=usr/include/c++/v1/tr1/__tuple_03
# 20151006: new clang import which bumps version from 3.6.1 to 3.7.0
OLD_FILES+=usr/lib/clang/3.6.1/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/3.6.1/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/3.6.1/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/3.6.1/include/adxintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/altivec.h
OLD_FILES+=usr/lib/clang/3.6.1/include/ammintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/arm_acle.h
OLD_FILES+=usr/lib/clang/3.6.1/include/arm_neon.h
OLD_FILES+=usr/lib/clang/3.6.1/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/avxintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/cpuid.h
OLD_FILES+=usr/lib/clang/3.6.1/include/emmintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/immintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/3.6.1/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/3.6.1/include/mmintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/module.modulemap
OLD_FILES+=usr/lib/clang/3.6.1/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/shaintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/smmintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/x86intrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/3.6.1/include/xopintrin.h
OLD_DIRS+=usr/lib/clang/3.6.1/include
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.san-i386.a
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.san-x86_64.a
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.ubsan-i386.a
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.ubsan-x86_64.a
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.ubsan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.ubsan_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/3.6.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/3.6.1/lib
OLD_DIRS+=usr/lib/clang/3.6.1
# 20150928: unused sgsmsg utility is removed
OLD_FILES+=usr/bin/sgsmsg
# 20150926: remove links to removed/unimplemented mbuf(9) macros
OLD_FILES+=usr/share/man/man9/MEXT_ADD_REF.9.gz
OLD_FILES+=usr/share/man/man9/MEXTFREE.9.gz
OLD_FILES+=usr/share/man/man9/MEXT_IS_REF.9.gz
OLD_FILES+=usr/share/man/man9/MEXT_REM_REF.9.gz
OLD_FILES+=usr/share/man/man9/MFREE.9.gz
# 20150818: *allocm() are gone in jemalloc 4.0.0
OLD_FILES+=usr/share/man/man3/allocm.3.gz
OLD_FILES+=usr/share/man/man3/dallocm.3.gz
OLD_FILES+=usr/share/man/man3/nallocm.3.gz
OLD_FILES+=usr/share/man/man3/rallocm.3.gz
OLD_FILES+=usr/share/man/man3/sallocm.3.gz
# 20150802: Remove netbsd's test on pw(8)
OLD_FILES+=usr/tests/usr.sbin/pw/pw_test
# 20150719: Remove libarchive.pc
OLD_FILES+=usr/libdata/pkgconfig/libarchive.pc
# 20150705: Rename DTrace provider man pages
OLD_FILES+=usr/share/man/man4/dtrace-io.4.gz
OLD_FILES+=usr/share/man/man4/dtrace-ip.4.gz
OLD_FILES+=usr/share/man/man4/dtrace-proc.4.gz
OLD_FILES+=usr/share/man/man4/dtrace-sched.4.gz
OLD_FILES+=usr/share/man/man4/dtrace-tcp.4.gz
OLD_FILES+=usr/share/man/man4/dtrace-udp.4.gz
# 20150704: nvlist private headers no longer installed
OLD_FILES+=usr/include/sys/nv_impl.h
OLD_FILES+=usr/include/sys/nvlist_impl.h
OLD_FILES+=usr/include/sys/nvpair_impl.h
# 20150624
OLD_LIBS+=usr/lib/libugidfw.so.4
# 20150604: Move nvlist man pages to section 9
OLD_FILES+=usr/share/man/man3/libnv.3.gz
OLD_FILES+=usr/share/man/man3/nv.3.gz
OLD_FILES+=usr/share/man/man3/nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_add_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_add_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_add_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_add_null.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_add_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_add_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_add_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_add_stringf.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_add_stringv.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_clone.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_create.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_destroy.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_dump.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_empty.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_error.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_exists.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_exists_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_exists_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_exists_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_exists_null.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_exists_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_exists_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_exists_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_exists_type.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_fdump.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_flags.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_free.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_free_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_free_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_free_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_free_null.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_free_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_free_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_free_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_free_type.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_get_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_get_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_get_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_get_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_get_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_get_parent.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_get_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_move_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_move_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_move_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_move_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_next.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_pack.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_recv.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_send.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_set_error.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_size.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_take_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_take_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_take_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_take_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_take_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_take_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_unpack.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_xfer.3.gz
# 20150702: Remove duplicated nvlist includes
OLD_FILES+=usr/include/dnv.h
OLD_FILES+=usr/include/nv.h
# 20150528: PCI IOV device driver methods moved to a separate kobj interface
OLD_FILES+=usr/share/man/man9/PCI_ADD_VF.9.gz
OLD_FILES+=usr/share/man/man9/PCI_INIT_IOV.9.gz
OLD_FILES+=usr/share/man/man9/PCI_UNINIT_IOV.9.gz
# 20150525: new clang import which bumps version from 3.6.0 to 3.6.1
OLD_FILES+=usr/lib/clang/3.6.0/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/3.6.0/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/3.6.0/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/3.6.0/include/adxintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/altivec.h
OLD_FILES+=usr/lib/clang/3.6.0/include/ammintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/arm_acle.h
OLD_FILES+=usr/lib/clang/3.6.0/include/arm_neon.h
OLD_FILES+=usr/lib/clang/3.6.0/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/avxintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/cpuid.h
OLD_FILES+=usr/lib/clang/3.6.0/include/emmintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/immintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/3.6.0/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/3.6.0/include/mmintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/module.modulemap
OLD_FILES+=usr/lib/clang/3.6.0/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/shaintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/smmintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/x86intrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/3.6.0/include/xopintrin.h
OLD_DIRS+=usr/lib/clang/3.6.0/include
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.san-i386.a
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.san-x86_64.a
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.ubsan-i386.a
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.ubsan-x86_64.a
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.ubsan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.ubsan_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/3.6.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/3.6.0/lib
OLD_DIRS+=usr/lib/clang/3.6.0
# 20150521
OLD_FILES+=usr/bin/demandoc
OLD_FILES+=usr/share/man/man1/demandoc.1.gz
OLD_FILES+=usr/share/man/man3/mandoc.3.gz
OLD_FILES+=usr/share/man/man3/mandoc_headers.3.gz
# 20150520
OLD_FILES+=usr/lib/libheimsqlite.a
OLD_FILES+=usr/lib/libheimsqlite.so
OLD_LIBS+=usr/lib/libheimsqlite.so.11
OLD_FILES+=usr/lib/libheimsqlite_p.a
# 20150506
OLD_FILES+=usr/share/man/man9/NDHASGIANT.9.gz
# 20150504
OLD_FILES+=usr/share/examples/etc/libmap32.conf
OLD_FILES+=usr/include/bsdstat.h
OLD_DIRS+=usr/lib32/private
OLD_LIBS+=usr/lib/private/libatf-c++.so.2
OLD_LIBS+=usr/lib/private/libbsdstat.so.1
OLD_LIBS+=usr/lib/private/libheimipcs.so.11
OLD_LIBS+=usr/lib/private/libsqlite3.so.0
OLD_LIBS+=usr/lib/private/libunbound.so.5
OLD_LIBS+=usr/lib/private/libatf-c.so.1
OLD_LIBS+=usr/lib/private/libheimipcc.so.11
OLD_LIBS+=usr/lib/private/libldns.so.5
OLD_LIBS+=usr/lib/private/libssh.so.5
OLD_LIBS+=usr/lib/private/libucl.so.1
OLD_DIRS+=usr/lib/private
# 20150501
OLD_FILES+=usr/bin/soeliminate
OLD_FILES+=usr/share/man/man1/soeliminate.1.gz
# 20150501: Remove the nvlist_.*[vf] functions manpages
OLD_FILES+=usr/share/man/man3/nvlist_addf_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addf_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addf_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addf_null.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addf_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addf_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addf_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addv_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addv_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addv_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addv_null.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addv_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addv_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_addv_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsf.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsf_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsf_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsf_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsf_null.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsf_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsf_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsf_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsf_type.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsv.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsv_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsv_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsv_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsv_null.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsv_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsv_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsv_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_existsv_type.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freef.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freef_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freef_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freef_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freef_null.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freef_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freef_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freef_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freef_type.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freev.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freev_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freev_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freev_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freev_null.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freev_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freev_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freev_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_freev_type.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_getf_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_getf_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_getf_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_getf_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_getf_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_getf_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_getv_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_getv_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_getv_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_getv_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_getv_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_getv_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_movef_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_movef_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_movef_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_movef_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_movev_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_movev_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_movev_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_movev_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_takef_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_takef_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_takef_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_takef_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_takef_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_takef_string.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_takev_binary.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_takev_bool.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_takev_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_takev_number.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_takev_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/nvlist_takev_string.3.gz
# 20150429: remove never written documentation
OLD_FILES+=usr/share/doc/papers/hwpmc.ascii.gz
# 20150427: test/sys/kern/mmap_test moved to test/sys/vm/mmap_test
OLD_FILES+=usr/tests/sys/kern/mmap_test
# 20150422: zlib.c moved from net to libkern
OLD_FILES+=usr/include/net/zlib.h
OLD_FILES+=usr/include/net/zutil.h
# 20150418
OLD_FILES+=sbin/mount_oldnfs
OLD_FILES+=usr/share/man/man8/mount_oldnfs.8.gz
# 20150416: ALTQ moved to net/altq
OLD_FILES+=usr/include/altq/altq_rmclass_debug.h
OLD_FILES+=usr/include/altq/altq.h
OLD_FILES+=usr/include/altq/altq_cdnr.h
OLD_FILES+=usr/include/altq/altq_hfsc.h
OLD_FILES+=usr/include/altq/altq_priq.h
OLD_FILES+=usr/include/altq/altqconf.h
OLD_FILES+=usr/include/altq/altq_classq.h
OLD_FILES+=usr/include/altq/altq_red.h
OLD_FILES+=usr/include/altq/if_altq.h
OLD_FILES+=usr/include/altq/altq_var.h
OLD_FILES+=usr/include/altq/altq_rmclass.h
OLD_FILES+=usr/include/altq/altq_cbq.h
OLD_FILES+=usr/include/altq/altq_rio.h
OLD_DIRS+=usr/include/altq
# 20150330: ntp 4.2.8p1
OLD_FILES+=usr/share/doc/ntp/driver1.html
OLD_FILES+=usr/share/doc/ntp/driver10.html
OLD_FILES+=usr/share/doc/ntp/driver11.html
OLD_FILES+=usr/share/doc/ntp/driver12.html
OLD_FILES+=usr/share/doc/ntp/driver16.html
OLD_FILES+=usr/share/doc/ntp/driver18.html
OLD_FILES+=usr/share/doc/ntp/driver19.html
OLD_FILES+=usr/share/doc/ntp/driver2.html
OLD_FILES+=usr/share/doc/ntp/driver20.html
OLD_FILES+=usr/share/doc/ntp/driver22.html
OLD_FILES+=usr/share/doc/ntp/driver26.html
OLD_FILES+=usr/share/doc/ntp/driver27.html
OLD_FILES+=usr/share/doc/ntp/driver28.html
OLD_FILES+=usr/share/doc/ntp/driver29.html
OLD_FILES+=usr/share/doc/ntp/driver3.html
OLD_FILES+=usr/share/doc/ntp/driver30.html
OLD_FILES+=usr/share/doc/ntp/driver32.html
OLD_FILES+=usr/share/doc/ntp/driver33.html
OLD_FILES+=usr/share/doc/ntp/driver34.html
OLD_FILES+=usr/share/doc/ntp/driver35.html
OLD_FILES+=usr/share/doc/ntp/driver36.html
OLD_FILES+=usr/share/doc/ntp/driver37.html
OLD_FILES+=usr/share/doc/ntp/driver4.html
OLD_FILES+=usr/share/doc/ntp/driver5.html
OLD_FILES+=usr/share/doc/ntp/driver6.html
OLD_FILES+=usr/share/doc/ntp/driver7.html
OLD_FILES+=usr/share/doc/ntp/driver8.html
OLD_FILES+=usr/share/doc/ntp/driver9.html
OLD_FILES+=usr/share/doc/ntp/ldisc.html
OLD_FILES+=usr/share/doc/ntp/measure.html
OLD_FILES+=usr/share/doc/ntp/mx4200data.html
OLD_FILES+=usr/share/doc/ntp/notes.html
OLD_FILES+=usr/share/doc/ntp/patches.html
OLD_FILES+=usr/share/doc/ntp/porting.html
OLD_FILES+=usr/share/man/man1/sntp.1.gz
# 20150329
.if ${TARGET_ARCH} == "arm"
OLD_FILES+=usr/include/bootconfig.h
.endif
# 20150326
OLD_FILES+=usr/share/man/man1/pmcstudy.1.gz
# 20150315: new clang import which bumps version from 3.5.1 to 3.6.0
OLD_FILES+=usr/include/clang/3.5.1/__wmmintrin_aes.h
OLD_FILES+=usr/include/clang/3.5.1/__wmmintrin_pclmul.h
OLD_FILES+=usr/include/clang/3.5.1/altivec.h
OLD_FILES+=usr/include/clang/3.5.1/ammintrin.h
OLD_FILES+=usr/include/clang/3.5.1/arm_acle.h
OLD_FILES+=usr/include/clang/3.5.1/arm_neon.h
OLD_FILES+=usr/include/clang/3.5.1/avx2intrin.h
OLD_FILES+=usr/include/clang/3.5.1/avxintrin.h
OLD_FILES+=usr/include/clang/3.5.1/bmi2intrin.h
OLD_FILES+=usr/include/clang/3.5.1/bmiintrin.h
OLD_FILES+=usr/include/clang/3.5.1/cpuid.h
OLD_FILES+=usr/include/clang/3.5.1/emmintrin.h
OLD_FILES+=usr/include/clang/3.5.1/f16cintrin.h
OLD_FILES+=usr/include/clang/3.5.1/fma4intrin.h
OLD_FILES+=usr/include/clang/3.5.1/fmaintrin.h
OLD_FILES+=usr/include/clang/3.5.1/ia32intrin.h
OLD_FILES+=usr/include/clang/3.5.1/immintrin.h
OLD_FILES+=usr/include/clang/3.5.1/lzcntintrin.h
OLD_FILES+=usr/include/clang/3.5.1/mm3dnow.h
OLD_FILES+=usr/include/clang/3.5.1/mm_malloc.h
OLD_FILES+=usr/include/clang/3.5.1/mmintrin.h
OLD_FILES+=usr/include/clang/3.5.1/module.modulemap
OLD_FILES+=usr/include/clang/3.5.1/nmmintrin.h
OLD_FILES+=usr/include/clang/3.5.1/pmmintrin.h
OLD_FILES+=usr/include/clang/3.5.1/popcntintrin.h
OLD_FILES+=usr/include/clang/3.5.1/prfchwintrin.h
OLD_FILES+=usr/include/clang/3.5.1/rdseedintrin.h
OLD_FILES+=usr/include/clang/3.5.1/rtmintrin.h
OLD_FILES+=usr/include/clang/3.5.1/shaintrin.h
OLD_FILES+=usr/include/clang/3.5.1/smmintrin.h
OLD_FILES+=usr/include/clang/3.5.1/tbmintrin.h
OLD_FILES+=usr/include/clang/3.5.1/tmmintrin.h
OLD_FILES+=usr/include/clang/3.5.1/wmmintrin.h
OLD_FILES+=usr/include/clang/3.5.1/x86intrin.h
OLD_FILES+=usr/include/clang/3.5.1/xmmintrin.h
OLD_FILES+=usr/include/clang/3.5.1/xopintrin.h
OLD_DIRS+=usr/include/clang/3.5.1
OLD_DIRS+=usr/include/clang
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.san-i386.a
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.san-x86_64.a
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.ubsan-i386.a
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.ubsan-x86_64.a
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.ubsan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.5.1/lib/freebsd/libclang_rt.ubsan_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/3.5.1/lib/freebsd
OLD_DIRS+=usr/lib/clang/3.5.1/lib
OLD_DIRS+=usr/lib/clang/3.5.1
# 20150302: binutils documentation distributed as a manpage
OLD_FILES+=usr/share/doc/binutils/as.txt
OLD_FILES+=usr/share/doc/binutils/ld.txt
OLD_DIRS+=usr/share/doc/binutils
# 20150222: Removed bcd(6) and ppt(6)
OLD_FILES+=usr/bin/bcd
OLD_FILES+=usr/bin/ppt
OLD_FILES+=usr/share/man/man6/bcd.6.gz
OLD_FILES+=usr/share/man/man6/ppt.6.gz
# 20150217: Removed remnants of ar(4) driver
OLD_FILES+=usr/include/dev/ic/hd64570.h
# 20150212: /usr/games moving into /usr/bin
OLD_FILES+=usr/games/bcd
OLD_FILES+=usr/games/caesar
OLD_FILES+=usr/games/factor
OLD_FILES+=usr/games/fortune
OLD_FILES+=usr/games/grdc
OLD_FILES+=usr/games/morse
OLD_FILES+=usr/games/number
OLD_FILES+=usr/games/pom
OLD_FILES+=usr/games/ppt
OLD_FILES+=usr/games/primes
OLD_FILES+=usr/games/random
OLD_FILES+=usr/games/rot13
OLD_FILES+=usr/games/strfile
OLD_FILES+=usr/games/unstr
OLD_DIRS+=usr/games
# 20150209: liblzma header
OLD_FILES+=usr/include/lzma/lzma.h
# 20150124: spl.9 and friends
OLD_FILES+=usr/share/man/man9/spl.9.gz
OLD_FILES+=usr/share/man/man9/spl0.9.gz
OLD_FILES+=usr/share/man/man9/splbio.9.gz
OLD_FILES+=usr/share/man/man9/splclock.9.gz
OLD_FILES+=usr/share/man/man9/splhigh.9.gz
OLD_FILES+=usr/share/man/man9/splimp.9.gz
OLD_FILES+=usr/share/man/man9/splnet.9.gz
OLD_FILES+=usr/share/man/man9/splsoftclock.9.gz
OLD_FILES+=usr/share/man/man9/splsofttty.9.gz
OLD_FILES+=usr/share/man/man9/splstatclock.9.gz
OLD_FILES+=usr/share/man/man9/spltty.9.gz
OLD_FILES+=usr/share/man/man9/splvm.9.gz
OLD_FILES+=usr/share/man/man9/splx.9.gz
# 20150118: toeplitz.c moved from netinet to net
OLD_FILES+=usr/include/netinet/toeplitz.h
# 20150118: new clang import which bumps version from 3.5.0 to 3.5.1
OLD_FILES+=usr/include/clang/3.5.0/__wmmintrin_aes.h
OLD_FILES+=usr/include/clang/3.5.0/__wmmintrin_pclmul.h
OLD_FILES+=usr/include/clang/3.5.0/altivec.h
OLD_FILES+=usr/include/clang/3.5.0/ammintrin.h
OLD_FILES+=usr/include/clang/3.5.0/arm_acle.h
OLD_FILES+=usr/include/clang/3.5.0/arm_neon.h
OLD_FILES+=usr/include/clang/3.5.0/avx2intrin.h
OLD_FILES+=usr/include/clang/3.5.0/avxintrin.h
OLD_FILES+=usr/include/clang/3.5.0/bmi2intrin.h
OLD_FILES+=usr/include/clang/3.5.0/bmiintrin.h
OLD_FILES+=usr/include/clang/3.5.0/cpuid.h
OLD_FILES+=usr/include/clang/3.5.0/emmintrin.h
OLD_FILES+=usr/include/clang/3.5.0/f16cintrin.h
OLD_FILES+=usr/include/clang/3.5.0/fma4intrin.h
OLD_FILES+=usr/include/clang/3.5.0/fmaintrin.h
OLD_FILES+=usr/include/clang/3.5.0/ia32intrin.h
OLD_FILES+=usr/include/clang/3.5.0/immintrin.h
OLD_FILES+=usr/include/clang/3.5.0/lzcntintrin.h
OLD_FILES+=usr/include/clang/3.5.0/mm3dnow.h
OLD_FILES+=usr/include/clang/3.5.0/mm_malloc.h
OLD_FILES+=usr/include/clang/3.5.0/mmintrin.h
OLD_FILES+=usr/include/clang/3.5.0/module.modulemap
OLD_FILES+=usr/include/clang/3.5.0/nmmintrin.h
OLD_FILES+=usr/include/clang/3.5.0/pmmintrin.h
OLD_FILES+=usr/include/clang/3.5.0/popcntintrin.h
OLD_FILES+=usr/include/clang/3.5.0/prfchwintrin.h
OLD_FILES+=usr/include/clang/3.5.0/rdseedintrin.h
OLD_FILES+=usr/include/clang/3.5.0/rtmintrin.h
OLD_FILES+=usr/include/clang/3.5.0/shaintrin.h
OLD_FILES+=usr/include/clang/3.5.0/smmintrin.h
OLD_FILES+=usr/include/clang/3.5.0/tbmintrin.h
OLD_FILES+=usr/include/clang/3.5.0/tmmintrin.h
OLD_FILES+=usr/include/clang/3.5.0/wmmintrin.h
OLD_FILES+=usr/include/clang/3.5.0/x86intrin.h
OLD_FILES+=usr/include/clang/3.5.0/xmmintrin.h
OLD_FILES+=usr/include/clang/3.5.0/xopintrin.h
OLD_DIRS+=usr/include/clang/3.5.0
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.san-i386.a
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.san-x86_64.a
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.ubsan-i386.a
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.ubsan-x86_64.a
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.ubsan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.5.0/lib/freebsd/libclang_rt.ubsan_cxx-x86_64.a
OLD_DIRS+=usr/lib/clang/3.5.0/lib/freebsd
OLD_DIRS+=usr/lib/clang/3.5.0/lib
OLD_DIRS+=usr/lib/clang/3.5.0
# 20150102: removal of asr(4)
OLD_FILES+=usr/share/man/man4/asr.4.gz
# 20150102: removal of texinfo
OLD_FILES+=usr/bin/info
OLD_FILES+=usr/bin/infokey
OLD_FILES+=usr/bin/install-info
OLD_FILES+=usr/bin/makeinfo
OLD_FILES+=usr/bin/texindex
OLD_FILES+=usr/share/info/am-utils.info.gz
OLD_FILES+=usr/share/info/as.info.gz
OLD_FILES+=usr/share/info/binutils.info.gz
OLD_FILES+=usr/share/info/com_err.info.gz
OLD_FILES+=usr/share/info/cpp.info.gz
OLD_FILES+=usr/share/info/cppinternals.info.gz
OLD_FILES+=usr/share/info/diff.info.gz
OLD_FILES+=usr/share/info/dir
OLD_FILES+=usr/share/info/gcc.info.gz
OLD_FILES+=usr/share/info/gccint.info.gz
OLD_FILES+=usr/share/info/gdb.info.gz
OLD_FILES+=usr/share/info/gdbint.info.gz
OLD_FILES+=usr/share/info/gperf.info.gz
OLD_FILES+=usr/share/info/grep.info.gz
OLD_FILES+=usr/share/info/groff.info.gz
OLD_FILES+=usr/share/info/heimdal.info.gz
OLD_FILES+=usr/share/info/history.info.gz
OLD_FILES+=usr/share/info/info-stnd.info.gz
OLD_FILES+=usr/share/info/info.info.gz
OLD_FILES+=usr/share/info/ld.info.gz
OLD_FILES+=usr/share/info/regex.info.gz
OLD_FILES+=usr/share/info/rluserman.info.gz
OLD_FILES+=usr/share/info/stabs.info.gz
OLD_FILES+=usr/share/info/texinfo.info.gz
OLD_FILES+=usr/share/man/man1/info.1.gz
OLD_FILES+=usr/share/man/man1/infokey.1.gz
OLD_FILES+=usr/share/man/man1/install-info.1.gz
OLD_FILES+=usr/share/man/man1/makeinfo.1.gz
OLD_FILES+=usr/share/man/man1/texindex.1.gz
OLD_FILES+=usr/share/man/man5/info.5.gz
OLD_FILES+=usr/share/man/man5/texinfo.5.gz
OLD_DIRS+=usr/share/info
# 20141231: new clang import which bumps version from 3.4.1 to 3.5.0
OLD_FILES+=usr/include/clang/3.4.1/__wmmintrin_aes.h
OLD_FILES+=usr/include/clang/3.4.1/__wmmintrin_pclmul.h
OLD_FILES+=usr/include/clang/3.4.1/altivec.h
OLD_FILES+=usr/include/clang/3.4.1/ammintrin.h
OLD_FILES+=usr/include/clang/3.4.1/arm_neon.h
OLD_FILES+=usr/include/clang/3.4.1/avx2intrin.h
OLD_FILES+=usr/include/clang/3.4.1/avxintrin.h
OLD_FILES+=usr/include/clang/3.4.1/bmi2intrin.h
OLD_FILES+=usr/include/clang/3.4.1/bmiintrin.h
OLD_FILES+=usr/include/clang/3.4.1/cpuid.h
OLD_FILES+=usr/include/clang/3.4.1/emmintrin.h
OLD_FILES+=usr/include/clang/3.4.1/f16cintrin.h
OLD_FILES+=usr/include/clang/3.4.1/fma4intrin.h
OLD_FILES+=usr/include/clang/3.4.1/fmaintrin.h
OLD_FILES+=usr/include/clang/3.4.1/immintrin.h
OLD_FILES+=usr/include/clang/3.4.1/lzcntintrin.h
OLD_FILES+=usr/include/clang/3.4.1/mm3dnow.h
OLD_FILES+=usr/include/clang/3.4.1/mm_malloc.h
OLD_FILES+=usr/include/clang/3.4.1/mmintrin.h
OLD_FILES+=usr/include/clang/3.4.1/module.map
OLD_FILES+=usr/include/clang/3.4.1/nmmintrin.h
OLD_FILES+=usr/include/clang/3.4.1/pmmintrin.h
OLD_FILES+=usr/include/clang/3.4.1/popcntintrin.h
OLD_FILES+=usr/include/clang/3.4.1/prfchwintrin.h
OLD_FILES+=usr/include/clang/3.4.1/rdseedintrin.h
OLD_FILES+=usr/include/clang/3.4.1/rtmintrin.h
OLD_FILES+=usr/include/clang/3.4.1/shaintrin.h
OLD_FILES+=usr/include/clang/3.4.1/smmintrin.h
OLD_FILES+=usr/include/clang/3.4.1/tbmintrin.h
OLD_FILES+=usr/include/clang/3.4.1/tmmintrin.h
OLD_FILES+=usr/include/clang/3.4.1/wmmintrin.h
OLD_FILES+=usr/include/clang/3.4.1/x86intrin.h
OLD_FILES+=usr/include/clang/3.4.1/xmmintrin.h
OLD_FILES+=usr/include/clang/3.4.1/xopintrin.h
OLD_DIRS+=usr/include/clang/3.4.1
# 20141225: Remove gpib/ieee488
OLD_FILES+=usr/include/dev/ieee488/ibfoo_int.h
OLD_FILES+=usr/include/dev/ieee488/tnt4882.h
OLD_FILES+=usr/include/dev/ieee488/ugpib.h
OLD_FILES+=usr/include/dev/ieee488/upd7210.h
OLD_DIRS+=usr/include/dev/ieee488
OLD_FILES+=usr/include/gpib/gpib.h
OLD_DIRS+=usr/include/gpib
OLD_FILES+=usr/lib/libgpib.a
OLD_FILES+=usr/lib/libgpib_p.a
OLD_FILES+=usr/lib/libgpib.so
OLD_LIBS+=usr/lib/libgpib.so.3
OLD_FILES+=usr/share/man/man3/gpib.3.gz
OLD_FILES+=usr/share/man/man3/ibclr.3.gz
OLD_FILES+=usr/share/man/man3/ibdev.3.gz
OLD_FILES+=usr/share/man/man3/ibdma.3.gz
OLD_FILES+=usr/share/man/man3/ibeos.3.gz
OLD_FILES+=usr/share/man/man3/ibeot.3.gz
OLD_FILES+=usr/share/man/man3/ibloc.3.gz
OLD_FILES+=usr/share/man/man3/ibonl.3.gz
OLD_FILES+=usr/share/man/man3/ibpad.3.gz
OLD_FILES+=usr/share/man/man3/ibrd.3.gz
OLD_FILES+=usr/share/man/man3/ibsad.3.gz
OLD_FILES+=usr/share/man/man3/ibsic.3.gz
OLD_FILES+=usr/share/man/man3/ibtmo.3.gz
OLD_FILES+=usr/share/man/man3/ibtrg.3.gz
OLD_FILES+=usr/share/man/man3/ibwrt.3.gz
OLD_FILES+=usr/share/man/man4/gpib.4.gz
OLD_FILES+=usr/share/man/man4/pcii.4.gz
OLD_FILES+=usr/share/man/man4/tnt4882.4.gz
# 20141224: libxo moved to /lib
MOVED_LIBS+=usr/lib/libxo.so.0
# 20141223: remove in6_gif.h, in_gif.h and if_stf.h
OLD_FILES+=usr/include/net/if_stf.h
OLD_FILES+=usr/include/netinet/in_gif.h
OLD_FILES+=usr/include/netinet6/in6_gif.h
# 20141209: pw tests broken into a file per command
OLD_FILES+=usr/tests/usr.sbin/pw/pw_delete
OLD_FILES+=usr/tests/usr.sbin/pw/pw_modify
# 20141202: update to mandoc CVS 20141201
OLD_FILES+=usr.bin/preconv
OLD_FILES+=usr/share/man/man1/preconv.1.gz
# 20141129: mrouted rc.d scripts removed from base
OLD_FILES+=etc/rc.d/mrouted
# 20141126: convert sbin/mdconfig/tests to ATF format tests
OLD_FILES+=usr/tests/sbin/mdconfig/legacy_test
OLD_FILES+=usr/tests/sbin/mdconfig/mdconfig.test
OLD_FILES+=usr/tests/sbin/mdconfig/run.pl
# 20141126: remove xform_ipip decapsulation fallback
OLD_FILES+=usr/include/netipsec/ipip_var.h
# 20141122: mandoc updated to 1.13.1
OLD_FILES+=usr/share/mdocml/external.png
# 20141111: SF_KQUEUE code removed
OLD_FILES+=usr/include/sys/sf_base.h
OLD_FILES+=usr/include/sys/sf_sync.h
# 20141109: faith/faithd removal
OLD_FILES+=etc/rc.d/faith
OLD_FILES+=usr/share/man/man4/faith.4.gz
OLD_FILES+=usr/share/man/man4/if_faith.4.gz
OLD_FILES+=usr/sbin/faithd
OLD_FILES+=usr/share/man/man8/faithd.8.gz
# 20141107: overhaul if_gre(4)
OLD_FILES+=usr/include/netinet/ip_gre.h
# 20141102: postrandom obsoleted by new /dev/random code
OLD_FILES+=etc/rc.d/postrandom
# 20141031: initrandom obsoleted by new /dev/random code
OLD_FILES+=etc/rc.d/initrandom
# 20141030: atf 0.21 import
OLD_FILES+=usr/share/man/man3/atf-c++-api.3.gz
# 20141028: debug files accidentally installed as directory name
OLD_FILES+=usr/lib/debug/usr/lib/i18n
OLD_FILES+=usr/lib/debug/usr/lib/private
OLD_FILES+=usr/lib/debug/usr/lib32/i18n
OLD_FILES+=usr/lib/debug/usr/lib32/private
# 20141015: OpenSSL 1.0.1j import
OLD_FILES+=usr/share/openssl/man/man3/CMS_sign_add1_signer.3.gz
# 20141003: libproc version bump
OLD_LIBS+=usr/lib/libproc.so.2
# 20140922: sleepq_calc_signal_retval.9 and sleepq_catch_signals.9 removed
OLD_FILES+=usr/share/man/man9/sleepq_calc_signal_retval.9.gz
OLD_FILES+=usr/share/man/man9/sleepq_catch_signals.9.gz
# 20140917: hv_kvpd rc.d script removed in favor of devd configuration
OLD_FILES+=etc/rc.d/hv_kvpd
# 20140917: libnv was accidentally being installed to /usr/lib instead of /lib
MOVED_LIBS+=usr/lib/libnv.so.0
# 20140829: rc.d/kerberos removed
OLD_FILES+=etc/rc.d/kerberos
# 20140814: libopie version bump
OLD_LIBS+=usr/lib/libopie.so.7
# 20140811: otp-sha renamed to otp-sha1
OLD_FILES+=usr/bin/otp-sha
OLD_FILES+=usr/share/man/man1/otp-sha.1.gz
# 20140807: Remove private lib files that should not be installed
OLD_FILES+=usr/lib/private/libatf-c.a
OLD_FILES+=usr/lib/private/libatf-c.so
OLD_FILES+=usr/lib/private/libatf-c_p.a
OLD_FILES+=usr/lib/private/libatf-c++.a
OLD_FILES+=usr/lib/private/libatf-c++.so
OLD_FILES+=usr/lib/private/libatf-c++_p.a
OLD_FILES+=usr/lib/private/libbsdstat.a
OLD_FILES+=usr/lib/private/libbsdstat.so
OLD_FILES+=usr/lib/private/libbsdstat_p.a
OLD_FILES+=usr/lib/private/libheimipcc.a
OLD_FILES+=usr/lib/private/libheimipcc.so
OLD_FILES+=usr/lib/private/libheimipcc_p.a
OLD_FILES+=usr/lib/private/libheimipcs.a
OLD_FILES+=usr/lib/private/libheimipcs.so
OLD_FILES+=usr/lib/private/libheimipcs_p.a
OLD_FILES+=usr/lib/private/libldns.a
OLD_FILES+=usr/lib/private/libldns.so
OLD_FILES+=usr/lib/private/libldns_p.a
OLD_FILES+=usr/lib/private/libssh.a
OLD_FILES+=usr/lib/private/libssh.so
OLD_FILES+=usr/lib/private/libssh_p.a
OLD_FILES+=usr/lib/private/libunbound.a
OLD_FILES+=usr/lib/private/libunbound.so
OLD_FILES+=usr/lib/private/libunbound_p.a
OLD_FILES+=usr/lib/private/libucl.a
OLD_FILES+=usr/lib/private/libucl.so
OLD_FILES+=usr/lib/private/libucl_p.a
# 20140803: Remove an obsolete man page
OLD_FILES+=usr/share/man/man9/pmap_change_wiring.9.gz
# 20140731
OLD_FILES+=usr/share/man/man9/SYSCTL_ADD_OID.9.gz
# 20140728: libsbuf restored to old version
OLD_LIBS+=lib/libsbuf.so.7
# 20140728: Remove an obsolete man page
OLD_FILES+=usr/share/man/man9/VOP_GETVOBJECT.9.gz
OLD_FILES+=usr/share/man/man9/VOP_CREATEVOBJECT.9.gz
OLD_FILES+=usr/share/man/man9/VOP_DESTROYVOBJECT.9.gz
# 20140723: renamed to PCBGROUP.9
OLD_FILES+=usr/share/man/man9/PCBGROUPS.9.gz
# 20140722: browse_packages_ftp.sh removed
OLD_FILES+=usr/share/examples/bsdconfig/browse_packages_ftp.sh
# 20140718: Remove obsolete man pages
OLD_FILES+=usr/share/man/man9/zero_copy.9.gz
OLD_FILES+=usr/share/man/man9/zero_copy_sockets.9.gz
# 20140718: Remove an obsolete man page
OLD_FILES+=usr/share/man/man9/pmap_page_protect.9.gz
# 20140717: Remove an obsolete man page
OLD_FILES+=usr/share/man/man9/pmap_clear_reference.9.gz
# 20140716: Remove an incorrectly named man page
OLD_FILES+=usr/share/man/man9/pmap_ts_modified.9.gz
# 20140712: Removal of bsd.dtrace.mk
OLD_FILES+=usr/share/mk/bsd.dtrace.mk
# 20140705: turn libreadline into an internal lib
OLD_LIBS+=lib/libreadline.so.8
OLD_FILES+=usr/lib/libreadline.a
OLD_FILES+=usr/lib/libreadline_p.a
OLD_FILES+=usr/lib/libreadline.so
OLD_FILES+=usr/lib/libhistory.a
OLD_FILES+=usr/lib/libhistory_p.a
OLD_FILES+=usr/lib/libhistory.so
OLD_LIBS+=usr/lib/libhistory.so.8
OLD_FILES+=usr/include/readline/chardefs.h
OLD_FILES+=usr/include/readline/history.h
OLD_FILES+=usr/include/readline/keymaps.h
OLD_FILES+=usr/include/readline/readline.h
OLD_FILES+=usr/include/readline/tilde.h
OLD_FILES+=usr/include/readline/rlconf.h
OLD_FILES+=usr/include/readline/rlstdc.h
OLD_FILES+=usr/include/readline/rltypedefs.h
OLD_FILES+=usr/include/readline/rltypedefs.h
OLD_DIRS+=usr/include/readline
OLD_FILES+=usr/share/info/readline.info.gz
OLD_FILES+=usr/share/man/man3/readline.3.gz
OLD_FILES+=usr/share/man/man3/rlhistory.3.gz
# 20140625: csup removal
OLD_FILES+=usr/bin/csup
OLD_FILES+=usr/bin/cpasswd
OLD_FILES+=usr/share/man/man1/csup.1.gz
OLD_FILES+=usr/share/man/man1/cpasswd.1.gz
OLD_FILES+=usr/share/examples/cvsup/README
OLD_FILES+=usr/share/examples/cvsup/cvs-supfile
OLD_FILES+=usr/share/examples/cvsup/stable-supfile
OLD_FILES+=usr/share/examples/cvsup/standard-supfile
OLD_DIRS+=usr/share/examples/cvsup
# 20140614: send-pr removal
OLD_FILES+=usr/bin/sendbug
OLD_FILES+=usr/share/info/send-pr.info.gz
OLD_FILES+=usr/share/man/man1/send-pr.1.gz
OLD_FILES+=usr/share/man/man1/sendbug.1.gz
OLD_FILES+=etc/gnats/freefall
OLD_DIRS+=etc/gnats
# 20140512: new clang import which bumps version from 3.4 to 3.4.1
OLD_FILES+=usr/include/clang/3.4/__wmmintrin_aes.h
OLD_FILES+=usr/include/clang/3.4/__wmmintrin_pclmul.h
OLD_FILES+=usr/include/clang/3.4/altivec.h
OLD_FILES+=usr/include/clang/3.4/ammintrin.h
OLD_FILES+=usr/include/clang/3.4/avx2intrin.h
OLD_FILES+=usr/include/clang/3.4/avxintrin.h
OLD_FILES+=usr/include/clang/3.4/bmi2intrin.h
OLD_FILES+=usr/include/clang/3.4/bmiintrin.h
OLD_FILES+=usr/include/clang/3.4/cpuid.h
OLD_FILES+=usr/include/clang/3.4/emmintrin.h
OLD_FILES+=usr/include/clang/3.4/f16cintrin.h
OLD_FILES+=usr/include/clang/3.4/fma4intrin.h
OLD_FILES+=usr/include/clang/3.4/fmaintrin.h
OLD_FILES+=usr/include/clang/3.4/immintrin.h
OLD_FILES+=usr/include/clang/3.4/lzcntintrin.h
OLD_FILES+=usr/include/clang/3.4/mm3dnow.h
OLD_FILES+=usr/include/clang/3.4/mm_malloc.h
OLD_FILES+=usr/include/clang/3.4/mmintrin.h
OLD_FILES+=usr/include/clang/3.4/module.map
OLD_FILES+=usr/include/clang/3.4/nmmintrin.h
OLD_FILES+=usr/include/clang/3.4/pmmintrin.h
OLD_FILES+=usr/include/clang/3.4/popcntintrin.h
OLD_FILES+=usr/include/clang/3.4/prfchwintrin.h
OLD_FILES+=usr/include/clang/3.4/rdseedintrin.h
OLD_FILES+=usr/include/clang/3.4/rtmintrin.h
OLD_FILES+=usr/include/clang/3.4/shaintrin.h
OLD_FILES+=usr/include/clang/3.4/smmintrin.h
OLD_FILES+=usr/include/clang/3.4/tbmintrin.h
OLD_FILES+=usr/include/clang/3.4/tmmintrin.h
OLD_FILES+=usr/include/clang/3.4/wmmintrin.h
OLD_FILES+=usr/include/clang/3.4/x86intrin.h
OLD_FILES+=usr/include/clang/3.4/xmmintrin.h
OLD_FILES+=usr/include/clang/3.4/xopintrin.h
OLD_FILES+=usr/include/clang/3.4/arm_neon.h
OLD_FILES+=usr/include/clang/3.4/module.map
OLD_DIRS+=usr/include/clang/3.4
# 20140505: Bogusly installing src.opts.mk
OLD_FILES+=usr/share/mk/src.opts.mk
# 20140505: Reject PR kern/187551
OLD_FILES+=usr/tests/sbin/ifconfig/fibs_test
# 20140502: Removal of lindev(4)
OLD_FILES+=usr/share/man/man4/lindev.4.gz
# 20140425
OLD_FILES+=usr/lib/libssp_p.a
OLD_FILES+=usr/lib/libstand_p.a
# 20140413: Removed NO_MANCOMPRESS from mount_fusefs
OLD_FILES+=usr/share/man/man8/mount_fusefs.8
# 20140314: AppleTalk
OLD_DIRS+=usr/include/netatalk
OLD_FILES+=usr/include/netatalk/aarp.h
OLD_FILES+=usr/include/netatalk/at.h
OLD_FILES+=usr/include/netatalk/at_extern.h
OLD_FILES+=usr/include/netatalk/at_var.h
OLD_FILES+=usr/include/netatalk/ddp.h
OLD_FILES+=usr/include/netatalk/ddp_pcb.h
OLD_FILES+=usr/include/netatalk/ddp_var.h
OLD_FILES+=usr/include/netatalk/endian.h
OLD_FILES+=usr/include/netatalk/phase2.h
# 20140314: Remove IPX/SPX
OLD_LIBS+=lib/libipx.so.5
OLD_FILES+=usr/include/netipx/ipx.h
OLD_FILES+=usr/include/netipx/ipx_if.h
OLD_FILES+=usr/include/netipx/ipx_pcb.h
OLD_FILES+=usr/include/netipx/ipx_var.h
OLD_FILES+=usr/include/netipx/spx.h
OLD_FILES+=usr/include/netipx/spx_debug.h
OLD_FILES+=usr/include/netipx/spx_timer.h
OLD_FILES+=usr/include/netipx/spx_var.h
OLD_DIRS+=usr/include/netipx
OLD_FILES+=usr/lib/libipx.a
OLD_FILES+=usr/lib/libipx.so
OLD_FILES+=usr/lib/libipx_p.a
OLD_FILES+=usr/sbin/IPXrouted
OLD_FILES+=usr/share/man/man3/ipx.3.gz
OLD_FILES+=usr/share/man/man3/ipx_addr.3.gz
OLD_FILES+=usr/share/man/man3/ipx_ntoa.3.gz
OLD_FILES+=usr/share/man/man4/ef.4.gz
OLD_FILES+=usr/share/man/man4/if_ef.4.gz
OLD_FILES+=usr/share/man/man8/IPXrouted.8.gz
# 20140314: bsdconfig usermgmt rewrite
OLD_FILES+=usr/libexec/bsdconfig/070.usermgmt/userinput
# 20140307: bsdconfig groupmgmt rewrite
OLD_FILES+=usr/libexec/bsdconfig/070.usermgmt/groupinput
# 20140223: Remove libyaml
OLD_FILES+=usr/lib/private/libyaml.a
OLD_FILES+=usr/lib/private/libyaml.so
OLD_LIBS+=usr/lib/private/libyaml.so.1
OLD_FILES+=usr/lib/private/libyaml_p.a
# 20140216: new clang import which bumps version from 3.3 to 3.4
OLD_FILES+=usr/bin/llvm-prof
OLD_FILES+=usr/include/clang/3.3/__wmmintrin_aes.h
OLD_FILES+=usr/include/clang/3.3/__wmmintrin_pclmul.h
OLD_FILES+=usr/include/clang/3.3/altivec.h
OLD_FILES+=usr/include/clang/3.3/ammintrin.h
OLD_FILES+=usr/include/clang/3.3/avx2intrin.h
OLD_FILES+=usr/include/clang/3.3/avxintrin.h
OLD_FILES+=usr/include/clang/3.3/bmi2intrin.h
OLD_FILES+=usr/include/clang/3.3/bmiintrin.h
OLD_FILES+=usr/include/clang/3.3/cpuid.h
OLD_FILES+=usr/include/clang/3.3/emmintrin.h
OLD_FILES+=usr/include/clang/3.3/f16cintrin.h
OLD_FILES+=usr/include/clang/3.3/fma4intrin.h
OLD_FILES+=usr/include/clang/3.3/fmaintrin.h
OLD_FILES+=usr/include/clang/3.3/immintrin.h
OLD_FILES+=usr/include/clang/3.3/lzcntintrin.h
OLD_FILES+=usr/include/clang/3.3/mm3dnow.h
OLD_FILES+=usr/include/clang/3.3/mm_malloc.h
OLD_FILES+=usr/include/clang/3.3/mmintrin.h
OLD_FILES+=usr/include/clang/3.3/module.map
OLD_FILES+=usr/include/clang/3.3/nmmintrin.h
OLD_FILES+=usr/include/clang/3.3/pmmintrin.h
OLD_FILES+=usr/include/clang/3.3/popcntintrin.h
OLD_FILES+=usr/include/clang/3.3/prfchwintrin.h
OLD_FILES+=usr/include/clang/3.3/rdseedintrin.h
OLD_FILES+=usr/include/clang/3.3/rtmintrin.h
OLD_FILES+=usr/include/clang/3.3/smmintrin.h
OLD_FILES+=usr/include/clang/3.3/tmmintrin.h
OLD_FILES+=usr/include/clang/3.3/wmmintrin.h
OLD_FILES+=usr/include/clang/3.3/x86intrin.h
OLD_FILES+=usr/include/clang/3.3/xmmintrin.h
OLD_FILES+=usr/include/clang/3.3/xopintrin.h
OLD_FILES+=usr/share/man/man1/llvm-prof.1.gz
OLD_DIRS+=usr/include/clang/3.3
# 20140216: nve(4) removed
OLD_FILES+=usr/share/man/man4/if_nve.4.gz
OLD_FILES+=usr/share/man/man4/nve.4.gz
# 20140205: Open Firmware device moved
OLD_FILES+=usr/include/dev/ofw/ofw_nexus.h
# 20140128: libelf and libdwarf import
OLD_LIBS+=usr/lib/libelf.so.1
OLD_LIBS+=usr/lib/libdwarf.so.3
# 20140123: apicvar header moved to x86
OLD_FILES+=usr/include/machine/apicvar.h
# 20131215: libcam version bumped
OLD_LIBS+=lib/libcam.so.6
# 20131202: libcapsicum and libcasper moved to /lib/
MOVED_LIBS+=usr/lib/libcapsicum.so.0
MOVED_LIBS+=usr/lib/libcasper.so.0
# 20131109: extattr(2) mlinks fixed
OLD_FILES+=usr/share/man/man2/extattr_delete_list.2.gz
OLD_FILES+=usr/share/man/man2/extattr_get_list.2.gz
# 20131107: example files removed
OLD_FILES+=usr/share/examples/libusb20/aux.c
OLD_FILES+=usr/share/examples/libusb20/aux.h
# 20131103: WITH_LIBICONV_COMPAT removal
OLD_FILES+=usr/include/_libiconv_compat.h
OLD_FILES+=usr/lib/libiconv.a
OLD_FILES+=usr/lib/libiconv.so
OLD_LIBS+=usr/lib/libiconv.so.3
OLD_FILES+=usr/lib/libiconv_p.a
# 20131103: removal of utxrm(8), use 'utx rm' instead
OLD_FILES+=usr/sbin/utxrm
OLD_FILES+=usr/share/man/man8/utxrm.8.gz
# 20131031: pkg_install has been removed
OLD_FILES+=etc/periodic/daily/220.backup-pkgdb
OLD_FILES+=etc/periodic/daily/490.status-pkg-changes
OLD_FILES+=etc/periodic/security/460.chkportsum
OLD_FILES+=etc/periodic/weekly/400.status-pkg
OLD_FILES+=usr/sbin/pkg_add
OLD_FILES+=usr/sbin/pkg_create
OLD_FILES+=usr/sbin/pkg_delete
OLD_FILES+=usr/sbin/pkg_info
OLD_FILES+=usr/sbin/pkg_updating
OLD_FILES+=usr/sbin/pkg_version
OLD_FILES+=usr/share/man/man1/pkg_add.1.gz
OLD_FILES+=usr/share/man/man1/pkg_create.1.gz
OLD_FILES+=usr/share/man/man1/pkg_delete.1.gz
OLD_FILES+=usr/share/man/man1/pkg_info.1.gz
OLD_FILES+=usr/share/man/man1/pkg_updating.1.gz
OLD_FILES+=usr/share/man/man1/pkg_version.1.gz
# 20131030: /etc/keys moved to /usr/share/keys
OLD_DIRS+=etc/keys
OLD_DIRS+=etc/keys/pkg
OLD_DIRS+=etc/keys/pkg/revoked
OLD_DIRS+=etc/keys/pkg/trusted
OLD_FILES+=etc/keys/pkg/trusted/pkg.freebsd.org.2013102301
# 20131028: ng_fec(4) removed
OLD_FILES+=usr/include/netgraph/ng_fec.h
OLD_FILES+=usr/share/man/man4/ng_fec.4.gz
# 20131027: header moved
OLD_FILES+=usr/include/net/pf_mtag.h
# 20131023: remove never used iscsi directory
OLD_DIRS+=usr/share/examples/iscsi
# 20131021: isf(4) removed
OLD_FILES+=usr/sbin/isfctl
OLD_FILES+=usr/share/man/man4/isf.4.gz
OLD_FILES+=usr/share/man/man8/isfctl.8.gz
# 20131014: libbsdyml becomes private
OLD_FILES+=usr/lib/libbsdyml.a
OLD_FILES+=usr/lib/libbsdyml.so
OLD_LIBS+=usr/lib/libbsdyml.so.0
OLD_FILES+=usr/lib/libbsdyml_p.a
OLD_FILES+=usr/share/man/man3/libbsdyml.3.gz
OLD_FILES+=usr/include/bsdyml.h
# 20131013: Removal of the ATF tools
OLD_FILES+=etc/atf/FreeBSD.conf
OLD_FILES+=etc/atf/atf-run.hooks
OLD_FILES+=etc/atf/common.conf
OLD_FILES+=usr/bin/atf-config
OLD_FILES+=usr/bin/atf-report
OLD_FILES+=usr/bin/atf-run
OLD_FILES+=usr/bin/atf-version
OLD_FILES+=usr/share/atf/atf-run.hooks
OLD_FILES+=usr/share/examples/atf/atf-run.hooks
OLD_FILES+=usr/share/examples/atf/tests-results.css
OLD_FILES+=usr/share/man/man1/atf-config.1.gz
OLD_FILES+=usr/share/man/man1/atf-report.1.gz
OLD_FILES+=usr/share/man/man1/atf-run.1.gz
OLD_FILES+=usr/share/man/man1/atf-version.1.gz
OLD_FILES+=usr/share/man/man5/atf-formats.5.gz
OLD_FILES+=usr/share/xml/atf/tests-results.dtd
OLD_FILES+=usr/share/xsl/atf/tests-results.xsl
OLD_DIRS+=etc/atf
OLD_DIRS+=usr/share/examples/atf
OLD_DIRS+=usr/share/xml/atf
OLD_DIRS+=usr/share/xml
OLD_DIRS+=usr/share/xsl/atf
OLD_DIRS+=usr/share/xsl
# 20131009: freebsd-version moved from /libexec to /bin
OLD_FILES+=libexec/freebsd-version
# 20131001: ar and ranlib from binutils not used
OLD_FILES+=usr/bin/gnu-ar
OLD_FILES+=usr/bin/gnu-ranlib
OLD_FILES+=usr/share/man/man1/gnu-ar.1.gz
OLD_FILES+=usr/share/man/man1/gnu-ranlib.1.gz
# 20130930: BIND removed from base
OLD_FILES+=etc/mtree/BIND.chroot.dist
OLD_FILES+=etc/namedb
OLD_FILES+=etc/periodic/daily/470.status-named
OLD_FILES+=usr/bin/dig
OLD_FILES+=usr/bin/nslookup
OLD_FILES+=usr/bin/nsupdate
OLD_DIRS+=usr/include/lwres
OLD_FILES+=usr/include/lwres/context.h
OLD_FILES+=usr/include/lwres/int.h
OLD_FILES+=usr/include/lwres/ipv6.h
OLD_FILES+=usr/include/lwres/lang.h
OLD_FILES+=usr/include/lwres/list.h
OLD_FILES+=usr/include/lwres/lwbuffer.h
OLD_FILES+=usr/include/lwres/lwpacket.h
OLD_FILES+=usr/include/lwres/lwres.h
OLD_FILES+=usr/include/lwres/net.h
OLD_FILES+=usr/include/lwres/netdb.h
OLD_FILES+=usr/include/lwres/platform.h
OLD_FILES+=usr/include/lwres/result.h
OLD_FILES+=usr/include/lwres/string.h
OLD_FILES+=usr/include/lwres/version.h
OLD_FILES+=usr/lib/liblwres.a
OLD_FILES+=usr/lib/liblwres.so
OLD_LIBS+=usr/lib/liblwres.so.90
OLD_FILES+=usr/lib/liblwres_p.a
OLD_FILES+=usr/sbin/arpaname
OLD_FILES+=usr/sbin/ddns-confgen
OLD_FILES+=usr/sbin/dnssec-dsfromkey
OLD_FILES+=usr/sbin/dnssec-keyfromlabel
OLD_FILES+=usr/sbin/dnssec-keygen
OLD_FILES+=usr/sbin/dnssec-revoke
OLD_FILES+=usr/sbin/dnssec-settime
OLD_FILES+=usr/sbin/dnssec-signzone
OLD_FILES+=usr/sbin/dnssec-verify
OLD_FILES+=usr/sbin/genrandom
OLD_FILES+=usr/sbin/isc-hmac-fixup
OLD_FILES+=usr/sbin/lwresd
OLD_FILES+=usr/sbin/named
OLD_FILES+=usr/sbin/named-checkconf
OLD_FILES+=usr/sbin/named-checkzone
OLD_FILES+=usr/sbin/named-compilezone
OLD_FILES+=usr/sbin/named-journalprint
OLD_FILES+=usr/sbin/named.reconfig
OLD_FILES+=usr/sbin/named.reload
OLD_FILES+=usr/sbin/nsec3hash
OLD_FILES+=usr/sbin/rndc
OLD_FILES+=usr/sbin/rndc-confgen
OLD_DIRS+=usr/share/doc/bind9
OLD_FILES+=usr/share/doc/bind9/CHANGES
OLD_FILES+=usr/share/doc/bind9/COPYRIGHT
OLD_FILES+=usr/share/doc/bind9/FAQ
OLD_FILES+=usr/share/doc/bind9/HISTORY
OLD_FILES+=usr/share/doc/bind9/README
OLD_DIRS+=usr/share/doc/bind9/arm
OLD_FILES+=usr/share/doc/bind9/arm/Bv9ARM.ch01.html
OLD_FILES+=usr/share/doc/bind9/arm/Bv9ARM.ch02.html
OLD_FILES+=usr/share/doc/bind9/arm/Bv9ARM.ch03.html
OLD_FILES+=usr/share/doc/bind9/arm/Bv9ARM.ch04.html
OLD_FILES+=usr/share/doc/bind9/arm/Bv9ARM.ch05.html
OLD_FILES+=usr/share/doc/bind9/arm/Bv9ARM.ch06.html
OLD_FILES+=usr/share/doc/bind9/arm/Bv9ARM.ch07.html
OLD_FILES+=usr/share/doc/bind9/arm/Bv9ARM.ch08.html
OLD_FILES+=usr/share/doc/bind9/arm/Bv9ARM.ch09.html
OLD_FILES+=usr/share/doc/bind9/arm/Bv9ARM.ch10.html
OLD_FILES+=usr/share/doc/bind9/arm/Bv9ARM.html
OLD_FILES+=usr/share/doc/bind9/arm/Bv9ARM.pdf
OLD_FILES+=usr/share/doc/bind9/arm/man.arpaname.html
OLD_FILES+=usr/share/doc/bind9/arm/man.ddns-confgen.html
OLD_FILES+=usr/share/doc/bind9/arm/man.dig.html
OLD_FILES+=usr/share/doc/bind9/arm/man.dnssec-dsfromkey.html
OLD_FILES+=usr/share/doc/bind9/arm/man.dnssec-keyfromlabel.html
OLD_FILES+=usr/share/doc/bind9/arm/man.dnssec-keygen.html
OLD_FILES+=usr/share/doc/bind9/arm/man.dnssec-revoke.html
OLD_FILES+=usr/share/doc/bind9/arm/man.dnssec-settime.html
OLD_FILES+=usr/share/doc/bind9/arm/man.dnssec-signzone.html
OLD_FILES+=usr/share/doc/bind9/arm/man.dnssec-verify.html
OLD_FILES+=usr/share/doc/bind9/arm/man.genrandom.html
OLD_FILES+=usr/share/doc/bind9/arm/man.host.html
OLD_FILES+=usr/share/doc/bind9/arm/man.isc-hmac-fixup.html
OLD_FILES+=usr/share/doc/bind9/arm/man.named-checkconf.html
OLD_FILES+=usr/share/doc/bind9/arm/man.named-checkzone.html
OLD_FILES+=usr/share/doc/bind9/arm/man.named-journalprint.html
OLD_FILES+=usr/share/doc/bind9/arm/man.named.html
OLD_FILES+=usr/share/doc/bind9/arm/man.nsec3hash.html
OLD_FILES+=usr/share/doc/bind9/arm/man.nsupdate.html
OLD_FILES+=usr/share/doc/bind9/arm/man.rndc-confgen.html
OLD_FILES+=usr/share/doc/bind9/arm/man.rndc.conf.html
OLD_FILES+=usr/share/doc/bind9/arm/man.rndc.html
OLD_DIRS+=usr/share/doc/bind9/misc
OLD_FILES+=usr/share/doc/bind9/misc/dnssec
OLD_FILES+=usr/share/doc/bind9/misc/format-options.pl
OLD_FILES+=usr/share/doc/bind9/misc/ipv6
OLD_FILES+=usr/share/doc/bind9/misc/migration
OLD_FILES+=usr/share/doc/bind9/misc/migration-4to9
OLD_FILES+=usr/share/doc/bind9/misc/options
OLD_FILES+=usr/share/doc/bind9/misc/rfc-compliance
OLD_FILES+=usr/share/doc/bind9/misc/roadmap
OLD_FILES+=usr/share/doc/bind9/misc/sdb
OLD_FILES+=usr/share/doc/bind9/misc/sort-options.pl
OLD_FILES+=usr/share/man/man1/arpaname.1.gz
OLD_FILES+=usr/share/man/man1/dig.1.gz
OLD_FILES+=usr/share/man/man1/nslookup.1.gz
OLD_FILES+=usr/share/man/man1/nsupdate.1.gz
OLD_FILES+=usr/share/man/man3/lwres.3.gz
OLD_FILES+=usr/share/man/man3/lwres_addr_parse.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_add.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_back.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_clear.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_first.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_forward.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_getmem.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_getuint16.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_getuint32.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_getuint8.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_init.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_invalidate.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_putmem.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_putuint16.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_putuint32.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_putuint8.3.gz
OLD_FILES+=usr/share/man/man3/lwres_buffer_subtract.3.gz
OLD_FILES+=usr/share/man/man3/lwres_conf_clear.3.gz
OLD_FILES+=usr/share/man/man3/lwres_conf_get.3.gz
OLD_FILES+=usr/share/man/man3/lwres_conf_init.3.gz
OLD_FILES+=usr/share/man/man3/lwres_conf_parse.3.gz
OLD_FILES+=usr/share/man/man3/lwres_conf_print.3.gz
OLD_FILES+=usr/share/man/man3/lwres_config.3.gz
OLD_FILES+=usr/share/man/man3/lwres_context.3.gz
OLD_FILES+=usr/share/man/man3/lwres_context_allocmem.3.gz
OLD_FILES+=usr/share/man/man3/lwres_context_create.3.gz
OLD_FILES+=usr/share/man/man3/lwres_context_destroy.3.gz
OLD_FILES+=usr/share/man/man3/lwres_context_freemem.3.gz
OLD_FILES+=usr/share/man/man3/lwres_context_initserial.3.gz
OLD_FILES+=usr/share/man/man3/lwres_context_nextserial.3.gz
OLD_FILES+=usr/share/man/man3/lwres_context_sendrecv.3.gz
OLD_FILES+=usr/share/man/man3/lwres_endhostent.3.gz
OLD_FILES+=usr/share/man/man3/lwres_endhostent_r.3.gz
OLD_FILES+=usr/share/man/man3/lwres_freeaddrinfo.3.gz
OLD_FILES+=usr/share/man/man3/lwres_freehostent.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gabn.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gabnrequest_free.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gabnrequest_parse.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gabnrequest_render.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gabnresponse_free.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gabnresponse_parse.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gabnresponse_render.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gai_strerror.3.gz
OLD_FILES+=usr/share/man/man3/lwres_getaddrinfo.3.gz
OLD_FILES+=usr/share/man/man3/lwres_getaddrsbyname.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gethostbyaddr.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gethostbyaddr_r.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gethostbyname.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gethostbyname2.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gethostbyname_r.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gethostent.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gethostent_r.3.gz
OLD_FILES+=usr/share/man/man3/lwres_getipnode.3.gz
OLD_FILES+=usr/share/man/man3/lwres_getipnodebyaddr.3.gz
OLD_FILES+=usr/share/man/man3/lwres_getipnodebyname.3.gz
OLD_FILES+=usr/share/man/man3/lwres_getnamebyaddr.3.gz
OLD_FILES+=usr/share/man/man3/lwres_getnameinfo.3.gz
OLD_FILES+=usr/share/man/man3/lwres_getrrsetbyname.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gnba.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gnbarequest_free.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gnbarequest_parse.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gnbarequest_render.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gnbaresponse_free.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gnbaresponse_parse.3.gz
OLD_FILES+=usr/share/man/man3/lwres_gnbaresponse_render.3.gz
OLD_FILES+=usr/share/man/man3/lwres_herror.3.gz
OLD_FILES+=usr/share/man/man3/lwres_hstrerror.3.gz
OLD_FILES+=usr/share/man/man3/lwres_inetntop.3.gz
OLD_FILES+=usr/share/man/man3/lwres_lwpacket_parseheader.3.gz
OLD_FILES+=usr/share/man/man3/lwres_lwpacket_renderheader.3.gz
OLD_FILES+=usr/share/man/man3/lwres_net_ntop.3.gz
OLD_FILES+=usr/share/man/man3/lwres_noop.3.gz
OLD_FILES+=usr/share/man/man3/lwres_nooprequest_free.3.gz
OLD_FILES+=usr/share/man/man3/lwres_nooprequest_parse.3.gz
OLD_FILES+=usr/share/man/man3/lwres_nooprequest_render.3.gz
OLD_FILES+=usr/share/man/man3/lwres_noopresponse_free.3.gz
OLD_FILES+=usr/share/man/man3/lwres_noopresponse_parse.3.gz
OLD_FILES+=usr/share/man/man3/lwres_noopresponse_render.3.gz
OLD_FILES+=usr/share/man/man3/lwres_packet.3.gz
OLD_FILES+=usr/share/man/man3/lwres_resutil.3.gz
OLD_FILES+=usr/share/man/man3/lwres_sethostent.3.gz
OLD_FILES+=usr/share/man/man3/lwres_sethostent_r.3.gz
OLD_FILES+=usr/share/man/man3/lwres_string_parse.3.gz
OLD_FILES+=usr/share/man/man5/named.conf.5.gz
OLD_FILES+=usr/share/man/man5/rndc.conf.5.gz
OLD_FILES+=usr/share/man/man8/ddns-confgen.8.gz
OLD_FILES+=usr/share/man/man8/dnssec-dsfromkey.8.gz
OLD_FILES+=usr/share/man/man8/dnssec-keyfromlabel.8.gz
OLD_FILES+=usr/share/man/man8/dnssec-keygen.8.gz
OLD_FILES+=usr/share/man/man8/dnssec-revoke.8.gz
OLD_FILES+=usr/share/man/man8/dnssec-settime.8.gz
OLD_FILES+=usr/share/man/man8/dnssec-signzone.8.gz
OLD_FILES+=usr/share/man/man8/dnssec-verify.8.gz
OLD_FILES+=usr/share/man/man8/genrandom.8.gz
OLD_FILES+=usr/share/man/man8/isc-hmac-fixup.8.gz
OLD_FILES+=usr/share/man/man8/lwresd.8.gz
OLD_FILES+=usr/share/man/man8/named-checkconf.8.gz
OLD_FILES+=usr/share/man/man8/named-checkzone.8.gz
OLD_FILES+=usr/share/man/man8/named-compilezone.8.gz
OLD_FILES+=usr/share/man/man8/named-journalprint.8.gz
OLD_FILES+=usr/share/man/man8/named.8.gz
OLD_FILES+=usr/share/man/man8/named.reconfig.8.gz
OLD_FILES+=usr/share/man/man8/named.reload.8.gz
OLD_FILES+=usr/share/man/man8/nsec3hash.8.gz
OLD_FILES+=usr/share/man/man8/rndc-confgen.8.gz
OLD_FILES+=usr/share/man/man8/rndc.8.gz
OLD_DIRS+=var/named/dev
OLD_DIRS+=var/named/etc
OLD_DIRS+=var/named/etc/namedb
OLD_FILES+=var/named/etc/namedb/PROTO.localhost-v6.rev
OLD_FILES+=var/named/etc/namedb/PROTO.localhost.rev
OLD_DIRS+=var/named/etc/namedb/dynamic
OLD_FILES+=var/named/etc/namedb/make-localhost
OLD_DIRS+=var/named/etc/namedb/master
OLD_FILES+=var/named/etc/namedb/master/empty.db
OLD_FILES+=var/named/etc/namedb/master/localhost-forward.db
OLD_FILES+=var/named/etc/namedb/master/localhost-reverse.db
#OLD_FILES+=var/named/etc/namedb/named.conf # intentionally left out
OLD_FILES+=var/named/etc/namedb/named.root
OLD_DIRS+=var/named/etc/namedb/working
OLD_DIRS+=var/named/etc/namedb/slave
OLD_DIRS+=var/named/var
OLD_DIRS+=var/named/var/dump
OLD_DIRS+=var/named/var/log
OLD_DIRS+=var/named/var/run
OLD_DIRS+=var/named/var/run/named
OLD_DIRS+=var/named/var/stats
OLD_DIRS+=var/run/named
# 20130923: example moved
OLD_FILES+=usr/share/examples/bsdconfig/browse_packages.sh
# 20130908: libssh becomes private
OLD_FILES+=usr/lib/libssh.a
OLD_FILES+=usr/lib/libssh.so
OLD_LIBS+=usr/lib/libssh.so.5
OLD_FILES+=usr/lib/libssh_p.a
# 20130903: gnupatch is no more
OLD_FILES+=usr/bin/gnupatch
OLD_FILES+=usr/share/man/man1/gnupatch.1.gz
# 20130829: bsdpatch is patch unconditionally
OLD_FILES+=usr/bin/bsdpatch
OLD_FILES+=usr/share/man/man1/bsdpatch.1.gz
# 20130822: bind 9.9.3-P2 import
OLD_LIBS+=usr/lib/liblwres.so.80
# 20130814: vm_page_busy(9)
OLD_FILES+=usr/share/man/man9/vm_page_flash.9.gz
OLD_FILES+=usr/share/man/man9/vm_page_io.9.gz
OLD_FILES+=usr/share/man/man9/vm_page_io_finish.9.gz
OLD_FILES+=usr/share/man/man9/vm_page_io_start.9.gz
OLD_FILES+=usr/share/man/man9/vm_page_wakeup.9.gz
# 20130710: libkvm version bump
OLD_LIBS+=lib/libkvm.so.5
# 20130623: dialog update from 1.1 to 1.2
OLD_LIBS+=usr/lib/libdialog.so.7
# 20130616: vfs_mount.9 removed
OLD_FILES+=usr/share/man/man9/vfs_mount.9.gz
# 20130614: remove CVS from base
OLD_FILES+=usr/bin/cvs
OLD_FILES+=usr/bin/cvsbug
OLD_FILES+=usr/share/doc/psd/28.cvs/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/28.cvs/paper.ps.gz
OLD_DIRS+=usr/share/doc/psd/28.cvs
OLD_FILES+=usr/share/examples/cvs/contrib/README
OLD_FILES+=usr/share/examples/cvs/contrib/clmerge
OLD_FILES+=usr/share/examples/cvs/contrib/cln_hist
OLD_FILES+=usr/share/examples/cvs/contrib/commit_prep
OLD_FILES+=usr/share/examples/cvs/contrib/cvs2vendor
OLD_FILES+=usr/share/examples/cvs/contrib/cvs_acls
OLD_FILES+=usr/share/examples/cvs/contrib/cvscheck
OLD_FILES+=usr/share/examples/cvs/contrib/cvscheck.man
OLD_FILES+=usr/share/examples/cvs/contrib/cvshelp.man
OLD_FILES+=usr/share/examples/cvs/contrib/descend.man
OLD_FILES+=usr/share/examples/cvs/contrib/easy-import
OLD_FILES+=usr/share/examples/cvs/contrib/intro.doc
OLD_FILES+=usr/share/examples/cvs/contrib/log
OLD_FILES+=usr/share/examples/cvs/contrib/log_accum
OLD_FILES+=usr/share/examples/cvs/contrib/mfpipe
OLD_FILES+=usr/share/examples/cvs/contrib/rcs-to-cvs
OLD_FILES+=usr/share/examples/cvs/contrib/rcs2log
OLD_FILES+=usr/share/examples/cvs/contrib/rcslock
OLD_FILES+=usr/share/examples/cvs/contrib/sccs2rcs
OLD_DIRS+=usr/share/examples/cvs/contrib
OLD_DIRS+=usr/share/examples/cvs
OLD_FILES+=usr/share/info/cvs.info.gz
OLD_FILES+=usr/share/info/cvsclient.info.gz
OLD_FILES+=usr/share/man/man1/cvs.1.gz
OLD_FILES+=usr/share/man/man5/cvs.5.gz
OLD_FILES+=usr/share/man/man8/cvsbug.8.gz
# 20130607: WITH_DEBUG_FILES added
OLD_FILES+=lib/libufs.so.6.symbols
# 20130417: nfs fha moved from nfsserver to nfs
OLD_FILES+=usr/include/nfsserver/nfs_fha.h
# 20130411: new clang import which bumps version from 3.2 to 3.3
OLD_FILES+=usr/include/clang/3.2/__wmmintrin_aes.h
OLD_FILES+=usr/include/clang/3.2/__wmmintrin_pclmul.h
OLD_FILES+=usr/include/clang/3.2/altivec.h
OLD_FILES+=usr/include/clang/3.2/ammintrin.h
OLD_FILES+=usr/include/clang/3.2/avx2intrin.h
OLD_FILES+=usr/include/clang/3.2/avxintrin.h
OLD_FILES+=usr/include/clang/3.2/bmi2intrin.h
OLD_FILES+=usr/include/clang/3.2/bmiintrin.h
OLD_FILES+=usr/include/clang/3.2/cpuid.h
OLD_FILES+=usr/include/clang/3.2/emmintrin.h
OLD_FILES+=usr/include/clang/3.2/f16cintrin.h
OLD_FILES+=usr/include/clang/3.2/fma4intrin.h
OLD_FILES+=usr/include/clang/3.2/fmaintrin.h
OLD_FILES+=usr/include/clang/3.2/immintrin.h
OLD_FILES+=usr/include/clang/3.2/lzcntintrin.h
OLD_FILES+=usr/include/clang/3.2/mm3dnow.h
OLD_FILES+=usr/include/clang/3.2/mm_malloc.h
OLD_FILES+=usr/include/clang/3.2/mmintrin.h
OLD_FILES+=usr/include/clang/3.2/module.map
OLD_FILES+=usr/include/clang/3.2/nmmintrin.h
OLD_FILES+=usr/include/clang/3.2/pmmintrin.h
OLD_FILES+=usr/include/clang/3.2/popcntintrin.h
OLD_FILES+=usr/include/clang/3.2/rtmintrin.h
OLD_FILES+=usr/include/clang/3.2/smmintrin.h
OLD_FILES+=usr/include/clang/3.2/tmmintrin.h
OLD_FILES+=usr/include/clang/3.2/wmmintrin.h
OLD_FILES+=usr/include/clang/3.2/x86intrin.h
OLD_FILES+=usr/include/clang/3.2/xmmintrin.h
OLD_FILES+=usr/include/clang/3.2/xopintrin.h
OLD_DIRS+=usr/include/clang/3.2
# 20130404: legacy ATA stack removed
OLD_FILES+=etc/periodic/daily/405.status-ata-raid
OLD_FILES+=rescue/atacontrol
OLD_FILES+=sbin/atacontrol
OLD_FILES+=usr/share/man/man8/atacontrol.8.gz
OLD_FILES+=usr/share/man/man4/atapicam.4.gz
OLD_FILES+=usr/share/man/man4/ataraid.4.gz
OLD_FILES+=usr/sbin/burncd
OLD_FILES+=usr/share/man/man8/burncd.8.gz
# 20130316: vinum.4 removed
OLD_FILES+=usr/share/man/man4/vinum.4.gz
# 20130312: fortunes-o removed
OLD_FILES+=usr/share/games/fortune/fortunes-o
OLD_FILES+=usr/share/games/fortune/fortunes-o.dat
# 20130311: Ports are no more available via cvsup
OLD_FILES+=usr/share/examples/cvsup/ports-supfile
OLD_FILES+=usr/share/examples/cvsup/refuse
OLD_FILES+=usr/share/examples/cvsup/refuse.README
# 20130309: NWFS and NCP supports removed
OLD_FILES+=usr/bin/ncplist
OLD_FILES+=usr/bin/ncplogin
OLD_FILES+=usr/bin/ncplogout
OLD_FILES+=usr/include/fs/nwfs/nwfs.h
OLD_FILES+=usr/include/fs/nwfs/nwfs_mount.h
OLD_FILES+=usr/include/fs/nwfs/nwfs_node.h
OLD_FILES+=usr/include/fs/nwfs/nwfs_subr.h
OLD_DIRS+=usr/include/fs/nwfs
OLD_FILES+=usr/include/netncp/ncp.h
OLD_FILES+=usr/include/netncp/ncp_cfg.h
OLD_FILES+=usr/include/netncp/ncp_conn.h
OLD_FILES+=usr/include/netncp/ncp_file.h
OLD_FILES+=usr/include/netncp/ncp_lib.h
OLD_FILES+=usr/include/netncp/ncp_ncp.h
OLD_FILES+=usr/include/netncp/ncp_nls.h
OLD_FILES+=usr/include/netncp/ncp_rcfile.h
OLD_FILES+=usr/include/netncp/ncp_rq.h
OLD_FILES+=usr/include/netncp/ncp_sock.h
OLD_FILES+=usr/include/netncp/ncp_subr.h
OLD_FILES+=usr/include/netncp/ncp_user.h
OLD_FILES+=usr/include/netncp/ncpio.h
OLD_FILES+=usr/include/netncp/nwerror.h
OLD_DIRS+=usr/include/netncp
OLD_FILES+=usr/lib/libncp.a
OLD_FILES+=usr/lib/libncp.so
OLD_LIBS+=usr/lib/libncp.so.4
OLD_FILES+=usr/lib/libncp_p.a
OLD_FILES+=usr/sbin/mount_nwfs
OLD_FILES+=usr/share/examples/nwclient/dot.nwfsrc
OLD_FILES+=usr/share/examples/nwclient/nwfs.sh.sample
OLD_DIRS+=usr/share/examples/nwclient
OLD_FILES+=usr/share/man/man1/ncplist.1.gz
OLD_FILES+=usr/share/man/man1/ncplogin.1.gz
OLD_FILES+=usr/share/man/man1/ncplogout.1.gz
OLD_FILES+=usr/share/man/man8/mount_nwfs.8.gz
# 20130302: NTFS support removed
OLD_FILES+=rescue/mount_ntfs
OLD_FILES+=sbin/mount_ntfs
OLD_FILES+=usr/include/fs/ntfs/ntfs.h
OLD_FILES+=usr/include/fs/ntfs/ntfs_compr.h
OLD_FILES+=usr/include/fs/ntfs/ntfs_ihash.h
OLD_FILES+=usr/include/fs/ntfs/ntfs_inode.h
OLD_FILES+=usr/include/fs/ntfs/ntfs_subr.h
OLD_FILES+=usr/include/fs/ntfs/ntfs_vfsops.h
OLD_FILES+=usr/include/fs/ntfs/ntfsmount.h
OLD_DIRS+=usr/include/fs/ntfs
OLD_FILES+=usr/share/man/man8/mount_ntfs.8.gz
# 20130302: PORTALFS support removed
OLD_FILES+=usr/include/fs/portalfs/portal.h
OLD_DIRS+=usr/include/fs/portalfs
OLD_FILES+=usr/sbin/mount_portalfs
OLD_FILES+=usr/share/examples/portal/README
OLD_FILES+=usr/share/examples/portal/portal.conf
OLD_DIRS+=usr/share/examples/portal
OLD_FILES+=usr/share/man/man8/mount_portalfs.8.gz
# 20130302: CODAFS support removed
OLD_FILES+=usr/share/man/man4/coda.4.gz
# 20130302: XFS support removed
OLD_FILES+=usr/share/man/man5/xfs.5.gz
# 20130302: Capsicum overhaul
OLD_FILES+=usr/share/man/man2/cap_getrights.2.gz
OLD_FILES+=usr/share/man/man2/cap_new.2.gz
# 20130213: OpenSSL 1.0.1e import
OLD_FILES+=usr/share/openssl/man/man3/EVP_PKEY_verifyrecover.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_PKEY_verifyrecover_init.3.gz
# 20130116: removed long unused directories for .1aout section manpages
OLD_FILES+=usr/share/man/en.ISO8859-1/man1aout
OLD_FILES+=usr/share/man/en.UTF-8/man1aout
OLD_DIRS+=usr/share/man/man1aout
OLD_DIRS+=usr/share/man/cat1aout
OLD_DIRS+=usr/share/man/en.ISO8859-1/cat1aout
OLD_DIRS+=usr/share/man/en.UTF-8/cat1aout
# 20130103: gnats-supfile removed
OLD_FILES+=usr/share/examples/cvsup/gnats-supfile
# 20121230: libdisk removed
OLD_FILES+=usr/share/man/man3/libdisk.3.gz usr/include/libdisk.h
OLD_FILES+=usr/lib/libdisk.a
# 20121230: remove wrongly created directories for auditdistd
OLD_DIRS+=var/dist
OLD_DIRS+=var/remote
# 20121022: remove harp, hfa and idt man page
OLD_FILES+=usr/share/man/man4/harp.4.gz
OLD_FILES+=usr/share/man/man4/hfa.4.gz
OLD_FILES+=usr/share/man/man4/idt.4.gz
OLD_FILES+=usr/share/man/man4/if_idt.4.gz
# 20121022: VFS_LOCK_GIANT elimination
OLD_FILES+=usr/share/man/man9/VFS_LOCK_GIANT.9.gz
OLD_FILES+=usr/share/man/man9/VFS_UNLOCK_GIANT.9.gz
# 20121004: remove incomplete unwind.h
OLD_FILES+=usr/include/clang/3.2/unwind.h
# 20120910: NetBSD compat shims removed
OLD_FILES+=usr/include/cam/scsi/scsi_low_pisa.h
OLD_FILES+=usr/include/sys/device_port.h
# 20120909: doc and www supfiles removed
OLD_FILES+=usr/share/examples/cvsup/doc-supfile
OLD_FILES+=usr/share/examples/cvsup/www-supfile
# 20120908: pf cleanup
OLD_FILES+=usr/include/net/if_pflow.h
# 20120816: new clang import which bumps version from 3.1 to 3.2
OLD_FILES+=usr/bin/llvm-ld
OLD_FILES+=usr/bin/llvm-stub
OLD_FILES+=usr/include/clang/3.1/altivec.h
OLD_FILES+=usr/include/clang/3.1/avx2intrin.h
OLD_FILES+=usr/include/clang/3.1/avxintrin.h
OLD_FILES+=usr/include/clang/3.1/bmi2intrin.h
OLD_FILES+=usr/include/clang/3.1/bmiintrin.h
OLD_FILES+=usr/include/clang/3.1/cpuid.h
OLD_FILES+=usr/include/clang/3.1/emmintrin.h
OLD_FILES+=usr/include/clang/3.1/fma4intrin.h
OLD_FILES+=usr/include/clang/3.1/immintrin.h
OLD_FILES+=usr/include/clang/3.1/lzcntintrin.h
OLD_FILES+=usr/include/clang/3.1/mm3dnow.h
OLD_FILES+=usr/include/clang/3.1/mm_malloc.h
OLD_FILES+=usr/include/clang/3.1/mmintrin.h
OLD_FILES+=usr/include/clang/3.1/module.map
OLD_FILES+=usr/include/clang/3.1/nmmintrin.h
OLD_FILES+=usr/include/clang/3.1/pmmintrin.h
OLD_FILES+=usr/include/clang/3.1/popcntintrin.h
OLD_FILES+=usr/include/clang/3.1/smmintrin.h
OLD_FILES+=usr/include/clang/3.1/tmmintrin.h
OLD_FILES+=usr/include/clang/3.1/unwind.h
OLD_FILES+=usr/include/clang/3.1/wmmintrin.h
OLD_FILES+=usr/include/clang/3.1/x86intrin.h
OLD_FILES+=usr/include/clang/3.1/xmmintrin.h
OLD_DIRS+=usr/include/clang/3.1
OLD_FILES+=usr/share/man/man1/llvm-ld.1.gz
# 20120712: OpenSSL 1.0.1c import
OLD_LIBS+=lib/libcrypto.so.6
OLD_LIBS+=usr/lib/libssl.so.6
OLD_FILES+=usr/include/openssl/aes_locl.h
OLD_FILES+=usr/include/openssl/bio_lcl.h
OLD_FILES+=usr/include/openssl/e_os.h
OLD_FILES+=usr/include/openssl/fips.h
OLD_FILES+=usr/include/openssl/fips_rand.h
OLD_FILES+=usr/include/openssl/pq_compat.h
OLD_FILES+=usr/include/openssl/tmdiff.h
OLD_FILES+=usr/include/openssl/ui_locl.h
OLD_FILES+=usr/share/openssl/man/man3/CRYPTO_set_id_callback.3.gz
# 20120621: remove old man page
OLD_FILES+=usr/share/man/man8/vnconfig.8.gz
# 20120619: TOE support updated
OLD_FILES+=usr/include/netinet/toedev.h
# 20120613: auth.conf removed
OLD_FILES+=etc/auth.conf
OLD_FILES+=usr/share/examples/etc/auth.conf
OLD_FILES+=usr/share/man/man3/auth.3.gz
OLD_FILES+=usr/share/man/man3/auth_getval.3.gz
OLD_FILES+=usr/share/man/man5/auth.conf.5.gz
# 20120530: kde pam lives now in ports
OLD_FILES+=etc/pam.d/kde
# 20120521: byacc import
OLD_FILES+=usr/bin/yyfix
OLD_FILES+=usr/share/man/man1/yyfix.1.gz
# 20120505: new clang import installed a redundant internal header
OLD_FILES+=usr/include/clang/3.1/stdalign.h
# 20120428: MD2 removed from libmd
OLD_LIBS+=lib/libmd.so.5
OLD_FILES+=usr/include/md2.h
OLD_FILES+=usr/share/man/man3/MD2Data.3.gz
OLD_FILES+=usr/share/man/man3/MD2End.3.gz
OLD_FILES+=usr/share/man/man3/MD2File.3.gz
OLD_FILES+=usr/share/man/man3/MD2FileChunk.3.gz
OLD_FILES+=usr/share/man/man3/MD2Final.3.gz
OLD_FILES+=usr/share/man/man3/MD2Init.3.gz
OLD_FILES+=usr/share/man/man3/MD2Update.3.gz
OLD_FILES+=usr/share/man/man3/md2.3.gz
# 20120425: libusb version bump (r234684)
OLD_LIBS+=usr/lib/libusb.so.2
OLD_FILES+=usr/share/man/man3/libsub_get_active_config_descriptor.3.gz
# 20120415: new clang import which bumps version from 3.0 to 3.1
OLD_FILES+=usr/include/clang/3.0/altivec.h
OLD_FILES+=usr/include/clang/3.0/avxintrin.h
OLD_FILES+=usr/include/clang/3.0/emmintrin.h
OLD_FILES+=usr/include/clang/3.0/immintrin.h
OLD_FILES+=usr/include/clang/3.0/mm3dnow.h
OLD_FILES+=usr/include/clang/3.0/mm_malloc.h
OLD_FILES+=usr/include/clang/3.0/mmintrin.h
OLD_FILES+=usr/include/clang/3.0/nmmintrin.h
OLD_FILES+=usr/include/clang/3.0/pmmintrin.h
OLD_FILES+=usr/include/clang/3.0/smmintrin.h
OLD_FILES+=usr/include/clang/3.0/tmmintrin.h
OLD_FILES+=usr/include/clang/3.0/wmmintrin.h
OLD_FILES+=usr/include/clang/3.0/x86intrin.h
OLD_FILES+=usr/include/clang/3.0/xmmintrin.h
OLD_DIRS+=usr/include/clang/3.0
# 20120412: BIND 9.8.1 release notes removed
OLD_FILES+=usr/share/doc/bind9/RELEASE-NOTES-BIND-9.8.1.pdf
OLD_FILES+=usr/share/doc/bind9/RELEASE-NOTES-BIND-9.8.1.txt
OLD_FILES+=usr/share/doc/bind9/RELEASE-NOTES-BIND-9.8.1.html
OLD_FILES+=usr/share/doc/bind9/release-notes.css
# 20120330: legacy(4) moved to x86
OLD_FILES+=usr/include/machine/legacyvar.h
# 20120324: MPI headers updated
OLD_FILES+=usr/include/dev/mpt/mpilib/mpi_inb.h
# 20120322: hwpmc_mips24k.h removed
OLD_FILES+=usr/include/dev/hwpmc/hwpmc_mips24k.h
# 20120322: Update heimdal to 1.5.1
OLD_FILES+=usr/include/krb5-v4compat.h \
usr/include/krb_err.h \
usr/include/hdb-private.h \
usr/share/man/man3/krb5_addresses.3.gz \
usr/share/man/man3/krb5_cc_cursor.3.gz \
usr/share/man/man3/krb5_cc_ops.3.gz \
usr/share/man/man3/krb5_config.3.gz \
usr/share/man/man3/krb5_config_get_int_default.3.gz \
usr/share/man/man3/krb5_context.3.gz \
usr/share/man/man3/krb5_data.3.gz \
usr/share/man/man3/krb5_err.3.gz \
usr/share/man/man3/krb5_errx.3.gz \
usr/share/man/man3/krb5_keyblock.3.gz \
usr/share/man/man3/krb5_keytab_entry.3.gz \
usr/share/man/man3/krb5_kt_cursor.3.gz \
usr/share/man/man3/krb5_kt_ops.3.gz \
usr/share/man/man3/krb5_set_warn_dest.3.gz \
usr/share/man/man3/krb5_verr.3.gz \
usr/share/man/man3/krb5_verrx.3.gz \
usr/share/man/man3/krb5_vwarnx.3.gz \
usr/share/man/man3/krb5_warn.3.gz \
usr/share/man/man3/krb5_warnx.3.gz
OLD_LIBS+=usr/lib/libasn1.so.10 \
usr/lib/libhdb.so.10 \
usr/lib/libheimntlm.so.10 \
usr/lib/libhx509.so.10 \
usr/lib/libkadm5clnt.so.10 \
usr/lib/libkadm5srv.so.10 \
usr/lib/libkafs5.so.10 \
usr/lib/libkrb5.so.10 \
usr/lib/libroken.so.10
# 20120309: Remove fifofs header files
OLD_FILES+=usr/include/fs/fifofs/fifo.h
OLD_DIRS+=usr/include/fs/fifofs
# 20120304: xlocale cleanup
OLD_FILES+=usr/include/_xlocale_ctype.h
# 20120225: libarchive 3.0.3
OLD_FILES+=usr/share/man/man3/archive_read_data_into_buffer.3.gz \
usr/share/man/man3/archive_read_support_compression_all.3.gz \
usr/share/man/man3/archive_read_support_compression_bzip2.3.gz \
usr/share/man/man3/archive_read_support_compression_compress.3.gz \
usr/share/man/man3/archive_read_support_compression_gzip.3.gz \
usr/share/man/man3/archive_read_support_compression_lzma.3.gz \
usr/share/man/man3/archive_read_support_compression_none.3.gz \
usr/share/man/man3/archive_read_support_compression_program.3.gz \
usr/share/man/man3/archive_read_support_compression_program_signature.3.gz \
usr/share/man/man3/archive_read_support_compression_xz.3.gz \
usr/share/man/man3/archive_write_set_callbacks.3.gz \
usr/share/man/man3/archive_write_set_compression_bzip2.3.gz \
usr/share/man/man3/archive_write_set_compression_compress.3.gz \
usr/share/man/man3/archive_write_set_compression_gzip.3.gz \
usr/share/man/man3/archive_write_set_compression_none.3.gz \
usr/share/man/man3/archive_write_set_compression_program.3.gz
OLD_LIBS+=usr/lib/libarchive.so.5
# 20120113: removal of wtmpcvt(1)
OLD_FILES+=usr/bin/wtmpcvt
OLD_FILES+=usr/share/man/man1/wtmpcvt.1.gz
# 20111214: eventtimers(7) moved to eventtimers(4)
OLD_FILES+=usr/share/man/man7/eventtimers.7.gz
# 20111125: amd(4) removed
OLD_FILES+=usr/share/man/man4/amd.4.gz
# 20111125: libodialog removed
OLD_FILES+=usr/lib/libodialog.a
OLD_FILES+=usr/lib/libodialog.so
OLD_LIBS+=usr/lib/libodialog.so.7
OLD_FILES+=usr/lib/libodialog_p.a
# 20110930: sysinstall removed
OLD_FILES+=usr/sbin/sysinstall
OLD_FILES+=usr/share/man/man8/sysinstall.8.gz
OLD_FILES+=usr/lib/libftpio.a
OLD_FILES+=usr/lib/libftpio.so
OLD_LIBS+=usr/lib/libftpio.so.8
OLD_FILES+=usr/lib/libftpio_p.a
OLD_FILES+=usr/include/ftpio.h
OLD_FILES+=usr/share/man/man3/ftpio.3.gz
# 20110915: rename congestion control manpages
OLD_FILES+=usr/share/man/man9/cc.9.gz
# 20110831: atomic page flags operations
OLD_FILES+=usr/share/man/man9/vm_page_flag.9.gz
OLD_FILES+=usr/share/man/man9/vm_page_flag_clear.9.gz
OLD_FILES+=usr/share/man/man9/vm_page_flag_set.9.gz
# 20110828: library version bump for 9.0
OLD_LIBS+=lib/libcam.so.5
OLD_LIBS+=lib/libpcap.so.7
OLD_LIBS+=lib/libufs.so.5
OLD_LIBS+=usr/lib/libbsnmp.so.5
OLD_LIBS+=usr/lib/libdwarf.so.2
OLD_LIBS+=usr/lib/libopie.so.6
OLD_LIBS+=usr/lib/librtld_db.so.1
OLD_LIBS+=usr/lib/libtacplus.so.4
# 20110817: no more acd.4, ad.4, afd.4 and ast.4
OLD_FILES+=usr/share/man/man4/acd.4.gz
OLD_FILES+=usr/share/man/man4/ad.4.gz
OLD_FILES+=usr/share/man/man4/afd.4.gz
OLD_FILES+=usr/share/man/man4/ast.4.gz
# 20110718: no longer useful in the age of rc.d
OLD_FILES+=usr/sbin/named.reconfig
OLD_FILES+=usr/sbin/named.reload
OLD_FILES+=usr/share/man/man8/named.reconfig.8.gz
OLD_FILES+=usr/share/man/man8/named.reload.8.gz
# 20110716: bind 9.8.0 import
OLD_LIBS+=usr/lib/liblwres.so.50
OLD_FILES+=usr/share/doc/bind9/KNOWN-DEFECTS
OLD_FILES+=usr/share/doc/bind9/NSEC3-NOTES
OLD_FILES+=usr/share/doc/bind9/README.idnkit
OLD_FILES+=usr/share/doc/bind9/README.pkcs11
# 20110709: vm_map_clean.9 -> vm_map_sync.9
OLD_FILES+=usr/share/man/man9/vm_map_clean.9.gz
# 20110709: Catch up with removal of these functions
OLD_FILES+=usr/share/man/man9/vm_page_copy.9.gz
OLD_FILES+=usr/share/man/man9/vm_page_protect.9.gz
OLD_FILES+=usr/share/man/man9/vm_page_zero_fill.9.gz
# 20110707: script no longer needed by /etc/rc.d/nfsd
OLD_FILES+=etc/rc.d/nfsserver
# 20110705: files moved so both NFS clients can share them
OLD_FILES+=usr/include/nfsclient/krpc.h
OLD_FILES+=usr/include/nfsclient/nfsdiskless.h
# 20110705: the switch of default NFS client to the new one
OLD_FILES+=sbin/mount_newnfs
OLD_FILES+=usr/share/man/man8/mount_newnfs.8.gz
OLD_FILES+=usr/include/nfsclient/nfs_kdtrace.h
# 20110628: calendar.msk removed
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.msk
# 20110517: libpkg removed
OLD_FILES+=usr/include/pkg.h
OLD_FILES+=usr/lib/libpkg.a
OLD_FILES+=usr/lib/libpkg.so
OLD_LIBS+=usr/lib/libpkg.so.0
OLD_FILES+=usr/lib/libpkg_p.a
# 20110517: libsbuf version bump
OLD_LIBS+=lib/libsbuf.so.5
# 20110502: new clang import which bumps version from 2.9 to 3.0
OLD_FILES+=usr/include/clang/2.9/emmintrin.h
OLD_FILES+=usr/include/clang/2.9/mm_malloc.h
OLD_FILES+=usr/include/clang/2.9/mmintrin.h
OLD_FILES+=usr/include/clang/2.9/pmmintrin.h
OLD_FILES+=usr/include/clang/2.9/tmmintrin.h
OLD_FILES+=usr/include/clang/2.9/xmmintrin.h
OLD_DIRS+=usr/include/clang/2.9
# 20110417: removal of Objective-C support
OLD_FILES+=usr/include/objc/encoding.h
OLD_FILES+=usr/include/objc/hash.h
OLD_FILES+=usr/include/objc/NXConstStr.h
OLD_FILES+=usr/include/objc/objc-api.h
OLD_FILES+=usr/include/objc/objc-decls.h
OLD_FILES+=usr/include/objc/objc-list.h
OLD_FILES+=usr/include/objc/objc.h
OLD_FILES+=usr/include/objc/Object.h
OLD_FILES+=usr/include/objc/Protocol.h
OLD_FILES+=usr/include/objc/runtime.h
OLD_FILES+=usr/include/objc/sarray.h
OLD_FILES+=usr/include/objc/thr.h
OLD_FILES+=usr/include/objc/typedstream.h
OLD_FILES+=usr/lib/libobjc.a
OLD_FILES+=usr/lib/libobjc.so
OLD_FILES+=usr/lib/libobjc_p.a
OLD_FILES+=usr/libexec/cc1obj
OLD_LIBS+=usr/lib/libobjc.so.4
OLD_DIRS+=usr/include/objc
# 20110331: firmware.img created at build time
OLD_FILES+=usr/share/examples/kld/firmware/fwimage/firmware.img
# 20110224: sticky.8 -> sticky.7
OLD_FILES+=usr/share/man/man8/sticky.8.gz
# 20110220: new clang import which bumps version from 2.8 to 2.9
OLD_FILES+=usr/include/clang/2.8/emmintrin.h
OLD_FILES+=usr/include/clang/2.8/mm_malloc.h
OLD_FILES+=usr/include/clang/2.8/mmintrin.h
OLD_FILES+=usr/include/clang/2.8/pmmintrin.h
OLD_FILES+=usr/include/clang/2.8/tmmintrin.h
OLD_FILES+=usr/include/clang/2.8/xmmintrin.h
OLD_DIRS+=usr/include/clang/2.8
# 20110119: netinet/sctp_cc_functions.h removed
OLD_FILES+=usr/include/netinet/sctp_cc_functions.h
# 20110119: Remove SYSCTL_*X* sysctl additions
OLD_FILES+=usr/share/man/man9/SYSCTL_XINT.9.gz \
usr/share/man/man9/SYSCTL_XLONG.9.gz
# 20110112: Update dialog to new version, rename old libdialog to libodialog,
# removing associated man pages and header files.
OLD_FILES+=usr/share/man/man3/draw_shadow.3.gz \
usr/share/man/man3/draw_box.3.gz usr/share/man/man3/line_edit.3.gz \
usr/share/man/man3/strheight.3.gz usr/share/man/man3/strwidth.3.gz \
usr/share/man/man3/dialog_create_rc.3.gz \
usr/share/man/man3/dialog_yesno.3.gz usr/share/man/man3/dialog_noyes.3.gz \
usr/share/man/man3/dialog_prgbox.3.gz \
usr/share/man/man3/dialog_textbox.3.gz usr/share/man/man3/dialog_menu.3.gz \
usr/share/man/man3/dialog_checklist.3.gz \
usr/share/man/man3/dialog_radiolist.3.gz \
usr/share/man/man3/dialog_inputbox.3.gz \
usr/share/man/man3/dialog_clear_norefresh.3.gz \
usr/share/man/man3/dialog_clear.3.gz usr/share/man/man3/dialog_update.3.gz \
usr/share/man/man3/dialog_fselect.3.gz \
usr/share/man/man3/dialog_notify.3.gz \
usr/share/man/man3/dialog_mesgbox.3.gz \
usr/share/man/man3/dialog_gauge.3.gz usr/share/man/man3/init_dialog.3.gz \
usr/share/man/man3/end_dialog.3.gz usr/share/man/man3/use_helpfile.3.gz \
usr/share/man/man3/use_helpline.3.gz usr/share/man/man3/get_helpline.3.gz \
usr/share/man/man3/restore_helpline.3.gz \
usr/share/man/man3/dialog_msgbox.3.gz \
usr/share/man/man3/dialog_ftree.3.gz usr/share/man/man3/dialog_tree.3.gz \
usr/share/examples/dialog/README usr/share/examples/dialog/checklist \
usr/share/examples/dialog/ftreebox usr/share/examples/dialog/infobox \
usr/share/examples/dialog/inputbox usr/share/examples/dialog/menubox \
usr/share/examples/dialog/msgbox usr/share/examples/dialog/prgbox \
usr/share/examples/dialog/radiolist usr/share/examples/dialog/textbox \
usr/share/examples/dialog/treebox usr/share/examples/dialog/yesno \
usr/share/examples/libdialog/Makefile usr/share/examples/libdialog/check1.c\
usr/share/examples/libdialog/check2.c usr/share/examples/libdialog/check3.c\
usr/share/examples/libdialog/dselect.c \
usr/share/examples/libdialog/fselect.c \
usr/share/examples/libdialog/ftree1.c \
usr/share/examples/libdialog/ftree1.test \
usr/share/examples/libdialog/ftree2.c \
usr/share/examples/libdialog/ftree2.test \
usr/share/examples/libdialog/gauge.c usr/share/examples/libdialog/input1.c \
usr/share/examples/libdialog/input2.c usr/share/examples/libdialog/menu1.c \
usr/share/examples/libdialog/menu2.c usr/share/examples/libdialog/menu3.c \
usr/share/examples/libdialog/msg.c usr/share/examples/libdialog/prgbox.c \
usr/share/examples/libdialog/radio1.c usr/share/examples/libdialog/radio2.c\
usr/share/examples/libdialog/radio3.c usr/share/examples/libdialog/text.c \
usr/share/examples/libdialog/tree.c usr/share/examples/libdialog/yesno.c
OLD_DIRS+=usr/share/examples/libdialog usr/share/examples/dialog
# 20101114: Remove long-obsolete MAKEDEV.8
OLD_FILES+=usr/share/man/man8/MAKEDEV.8.gz
# 20101112: vgonel(9) has gone to private API a while ago
OLD_FILES+=usr/share/man/man9/vgonel.9.gz
# 20101112: removed gasp.info
OLD_FILES+=usr/share/info/gasp.info.gz
# 20101109: machine/mutex.h removed
OLD_FILES+=usr/include/machine/mutex.h
# 20101109: headers moved from machine/ to x86/
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/include/machine/mptable.h
.endif
# 20101101: headers moved from machine/ to x86/
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/include/machine/apicreg.h
OLD_FILES+=usr/include/machine/mca.h
.endif
# 20101020: catch up with vm_page_sleep_if_busy rename
OLD_FILES+=usr/share/man/man9/vm_page_sleep_busy.9.gz
# 20101018: taskqueue(9) updates
OLD_FILES+=usr/share/man/man9/taskqueue_find.9.gz
# 20101011: removed subblock.h from liblzma
OLD_FILES+=usr/include/lzma/subblock.h
# 20101002: removed manpath.config
OLD_FILES+=etc/manpath.config
OLD_FILES+=usr/share/examples/etc/manpath.config
# 20100910: renamed sbuf_overflowed to sbuf_error
OLD_FILES+=usr/share/man/man9/sbuf_overflowed.9.gz
# 20100815: retired last traces of chooseproc(9)
OLD_FILES+=usr/share/man/man9/chooseproc.9.gz
# 20100806: removal of unused libcompat routines
OLD_FILES+=usr/share/man/man3/ascftime.3.gz
OLD_FILES+=usr/share/man/man3/cfree.3.gz
OLD_FILES+=usr/share/man/man3/cftime.3.gz
OLD_FILES+=usr/share/man/man3/getpw.3.gz
# 20100725: acpi_aiboost(4) removal
OLD_FILES+=usr/share/man/man4/acpi_aiboost.4.gz
# 20100724: nfsclient/nfs_lock.h moved to nfs/nfs_lock.h
OLD_FILES+=usr/include/nfsclient/nfs_lock.h
# 20100720: new clang import which bumps version from 2.0 to 2.8
OLD_FILES+=usr/include/clang/2.0/emmintrin.h
OLD_FILES+=usr/include/clang/2.0/mm_malloc.h
OLD_FILES+=usr/include/clang/2.0/mmintrin.h
OLD_FILES+=usr/include/clang/2.0/pmmintrin.h
OLD_FILES+=usr/include/clang/2.0/tmmintrin.h
OLD_FILES+=usr/include/clang/2.0/xmmintrin.h
OLD_DIRS+=usr/include/clang/2.0
# 20100706: removed pc-sysinstall's detect-vmware.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-query/detect-vmware.sh
# 20100701: [powerpc] removed <machine/intr.h>
.if ${TARGET_ARCH} == "powerpc"
OLD_FILES+=usr/include/machine/intr.h
.endif
# 20100514: library version bump for versioned symbols for liblzma
OLD_LIBS+=usr/lib/liblzma.so.0
# 20100511: move GCC-specific headers to /usr/include/gcc
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/include/emmintrin.h
OLD_FILES+=usr/include/mm_malloc.h
OLD_FILES+=usr/include/pmmintrin.h
OLD_FILES+=usr/include/xmmintrin.h
.endif
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386" || ${TARGET_ARCH} == "arm"
OLD_FILES+=usr/include/mmintrin.h
.endif
.if ${TARGET_ARCH} == "powerpc"
OLD_FILES+=usr/include/altivec.h
OLD_FILES+=usr/include/ppc-asm.h
OLD_FILES+=usr/include/spe.h
.endif
# 20100416: [mips] removed <machine/psl.h>
.if ${TARGET_ARCH} == "mips"
OLD_FILES+=usr/include/machine/psl.h
.endif
# 20100415: [mips] removed unused headers
.if ${TARGET_ARCH} == "mips"
OLD_FILES+=usr/include/machine/archtype.h
OLD_FILES+=usr/include/machine/segments.h
OLD_FILES+=usr/include/machine/rm7000.h
OLD_FILES+=usr/include/machine/defs.h
OLD_FILES+=usr/include/machine/queue.h
.endif
# 20100326: gcpio removal
OLD_FILES+=usr/bin/gcpio
OLD_FILES+=usr/share/info/cpio.info.gz
OLD_FILES+=usr/share/man/man1/gcpio.1.gz
# 20100322: libz update
OLD_LIBS+=lib/libz.so.5
# 20100314: removal of regexp.h
OLD_FILES+=usr/include/regexp.h
OLD_FILES+=usr/share/man/man3/regexp.3.gz
OLD_FILES+=usr/share/man/man3/regsub.3.gz
# 20100303: actual removal of utmp.h
OLD_FILES+=usr/include/utmp.h
# 20100208: man pages moved
.if ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/share/man/man4/i386/alpm.4.gz
OLD_FILES+=usr/share/man/man4/i386/amdpm.4.gz
OLD_FILES+=usr/share/man/man4/i386/mcd.4.gz
OLD_FILES+=usr/share/man/man4/i386/padlock.4.gz
OLD_FILES+=usr/share/man/man4/i386/pcf.4.gz
OLD_FILES+=usr/share/man/man4/i386/scd.4.gz
OLD_FILES+=usr/share/man/man4/i386/viapm.4.gz
.endif
# 20100122: move BSDL bc/dc USD documents to /usr/share/doc/usd
OLD_FILES+=usr/share/doc/papers/bc.ascii.gz
OLD_FILES+=usr/share/doc/papers/dc.ascii.gz
# 20100120: replacing GNU bc/dc with BSDL versions
OLD_FILES+=usr/share/examples/bc/ckbook.b
OLD_FILES+=usr/share/examples/bc/pi.b
OLD_FILES+=usr/share/examples/bc/primes.b
OLD_FILES+=usr/share/examples/bc/twins.b
OLD_FILES+=usr/share/info/dc.info.gz
OLD_DIRS+=usr/share/examples/bc
# 20100114: removal of ttyslot(3)
OLD_FILES+=usr/share/man/man3/ttyslot.3.gz
# 20100113: remove utmp.h, replace it by utmpx.h
OLD_FILES+=usr/share/man/man3/login.3.gz
OLD_FILES+=usr/share/man/man3/logout.3.gz
OLD_FILES+=usr/share/man/man3/logwtmp.3.gz
OLD_FILES+=usr/share/man/man3/ulog_endutxent.3.gz
OLD_FILES+=usr/share/man/man3/ulog_getutxent.3.gz
OLD_FILES+=usr/share/man/man3/ulog_getutxline.3.gz
OLD_FILES+=usr/share/man/man3/ulog_getutxuser.3.gz
OLD_FILES+=usr/share/man/man3/ulog_pututxline.3.gz
OLD_FILES+=usr/share/man/man3/ulog_setutxent.3.gz
OLD_FILES+=usr/share/man/man3/ulog_setutxfile.3.gz
OLD_FILES+=usr/share/man/man5/lastlog.5.gz
OLD_FILES+=usr/share/man/man5/utmp.5.gz
OLD_FILES+=usr/share/man/man5/wtmp.5.gz
OLD_LIBS+=lib/libutil.so.8
# 20100105: new userland semaphore implementation
OLD_FILES+=usr/include/sys/semaphore.h
# 20100103: ntptrace(8) removed
OLD_FILES+=usr/sbin/ntptrace
OLD_FILES+=usr/share/man/man8/ntptrace.8.gz
# 20091229: remove no longer relevant examples
OLD_FILES+=usr/share/examples/pppd/auth-down.sample
OLD_FILES+=usr/share/examples/pppd/auth-up.sample
OLD_FILES+=usr/share/examples/pppd/chap-secrets.sample
OLD_FILES+=usr/share/examples/pppd/chat.sh.sample
OLD_FILES+=usr/share/examples/pppd/ip-down.sample
OLD_FILES+=usr/share/examples/pppd/ip-up.sample
OLD_FILES+=usr/share/examples/pppd/options.sample
OLD_FILES+=usr/share/examples/pppd/pap-secrets.sample
OLD_FILES+=usr/share/examples/pppd/ppp.deny.sample
OLD_FILES+=usr/share/examples/pppd/ppp.shells.sample
OLD_DIRS+=usr/share/examples/pppd
OLD_FILES+=usr/share/examples/slattach/unit-command.sh
OLD_DIRS+=usr/share/examples/slattach
OLD_FILES+=usr/share/examples/sliplogin/slip.hosts
OLD_FILES+=usr/share/examples/sliplogin/slip.login
OLD_FILES+=usr/share/examples/sliplogin/slip.logout
OLD_FILES+=usr/share/examples/sliplogin/slip.slparms
OLD_DIRS+=usr/share/examples/sliplogin
OLD_FILES+=usr/share/examples/startslip/sldown.sh
OLD_FILES+=usr/share/examples/startslip/slip.sh
OLD_FILES+=usr/share/examples/startslip/slup.sh
OLD_DIRS+=usr/share/examples/startslip
# 20091202: unify rc.firewall and rc.firewall6
OLD_FILES+=etc/rc.d/ip6fw
OLD_FILES+=etc/rc.firewall6
OLD_FILES+=usr/share/examples/etc/rc.firewall6
# 20091117: removal of rc.early(8) link
OLD_FILES+=usr/share/man/man8/rc.early.8.gz
# 20091027: pselect.3 implemented as syscall
OLD_FILES+=usr/share/man/man3/pselect.3.gz
# 20091005: fusword.9 and susword.9 removed
OLD_FILES+=usr/share/man/man9/fusword.9.gz
OLD_FILES+=usr/share/man/man9/susword.9.gz
# 20090909: vesa and dpms promoted to be i386/amd64 common
OLD_FILES+=usr/include/machine/pc/vesa.h
OLD_FILES+=usr/share/man/man4/i386/dpms.4.gz
# 20090904: remove lukemftpd
OLD_FILES+=usr/libexec/lukemftpd
OLD_FILES+=usr/share/man/man5/ftpd.conf.5.gz
OLD_FILES+=usr/share/man/man5/ftpusers.5.gz
OLD_FILES+=usr/share/man/man8/lukemftpd.8.gz
# 20090902: BSD.{x11,x11-4}.dist are dead and BSD.local.dist lives in ports/
OLD_FILES+=etc/mtree/BSD.local.dist
OLD_FILES+=etc/mtree/BSD.x11.dist
OLD_FILES+=etc/mtree/BSD.x11-4.dist
# 20090812: net80211 documentation overhaul
OLD_FILES+=usr/share/man/man9/ieee80211_add_rates.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_add_xrates.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_alloc_node.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_attach.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_begin_scan.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_cfgget.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_cfgset.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_chan2ieee.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_chan2mode.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_create_ibss.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_crypto_attach.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_crypto_detach.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_decap.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_dump_pkt.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_dup_bss.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_encap.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_end_scan.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_find_node.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_fix_rate.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_free_allnodes.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_ieee2mhz.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_ioctl.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_lookup_node.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_media2rate.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_media_change.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_media_init.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_media_status.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_mhz2ieee.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_next_scan.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_node_attach.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_node_detach.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_node_lateattach.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_print_essid.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_proto_attach.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_proto_detach.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_rate2media.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_recv_mgmt.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_send_mgmt.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_setmode.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_timeout_nodes.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_watchdog.9.gz
OLD_FILES+=usr/share/man/man9/ieee80211_wep_crypt.9.gz
# 20090801: vimage.h removed in favour of vnet.h
OLD_FILES+=usr/include/sys/vimage.h
# 20101208: libbsnmp was moved to usr/lib
MOVED_LIBS+=lib/libbsnmp.so.5
# 20090719: library version bump for 8.0
OLD_LIBS+=lib/libalias.so.6
OLD_LIBS+=lib/libavl.so.1
OLD_LIBS+=lib/libbegemot.so.3
OLD_LIBS+=lib/libbsdxml.so.3
OLD_LIBS+=lib/libbsnmp.so.4
OLD_LIBS+=lib/libcam.so.4
OLD_LIBS+=lib/libcrypt.so.4
OLD_LIBS+=lib/libcrypto.so.5
OLD_LIBS+=lib/libctf.so.1
OLD_LIBS+=lib/libdevstat.so.6
OLD_LIBS+=lib/libdtrace.so.1
OLD_LIBS+=lib/libedit.so.6
OLD_LIBS+=lib/libgeom.so.4
OLD_LIBS+=lib/libipsec.so.3
OLD_LIBS+=lib/libipx.so.4
OLD_LIBS+=lib/libkiconv.so.3
OLD_LIBS+=lib/libkvm.so.4
OLD_LIBS+=lib/libmd.so.4
OLD_LIBS+=lib/libncurses.so.7
OLD_LIBS+=lib/libncursesw.so.7
OLD_LIBS+=lib/libnvpair.so.1
OLD_LIBS+=lib/libpcap.so.6
OLD_LIBS+=lib/libreadline.so.7
OLD_LIBS+=lib/libsbuf.so.4
OLD_LIBS+=lib/libufs.so.4
OLD_LIBS+=lib/libumem.so.1
OLD_LIBS+=lib/libutil.so.7
OLD_LIBS+=lib/libuutil.so.1
OLD_LIBS+=lib/libz.so.4
OLD_LIBS+=lib/libzfs.so.1
OLD_LIBS+=lib/libzpool.so.1
OLD_LIBS+=usr/lib/libarchive.so.4
OLD_LIBS+=usr/lib/libauditd.so.4
OLD_LIBS+=usr/lib/libbluetooth.so.3
OLD_LIBS+=usr/lib/libbsm.so.2
OLD_LIBS+=usr/lib/libbz2.so.3
OLD_LIBS+=usr/lib/libcalendar.so.4
OLD_LIBS+=usr/lib/libcom_err.so.4
OLD_LIBS+=usr/lib/libdevinfo.so.4
OLD_LIBS+=usr/lib/libdialog.so.6
OLD_LIBS+=usr/lib/libdwarf.so.1
OLD_LIBS+=usr/lib/libfetch.so.5
OLD_LIBS+=usr/lib/libform.so.4
OLD_LIBS+=usr/lib/libformw.so.4
OLD_LIBS+=usr/lib/libftpio.so.7
OLD_LIBS+=usr/lib/libgnuregex.so.4
OLD_LIBS+=usr/lib/libgpib.so.2
OLD_LIBS+=usr/lib/libhistory.so.7
OLD_LIBS+=usr/lib/libmagic.so.3
OLD_LIBS+=usr/lib/libmemstat.so.2
OLD_LIBS+=usr/lib/libmenu.so.4
OLD_LIBS+=usr/lib/libmenuw.so.4
OLD_LIBS+=usr/lib/libmilter.so.4
OLD_LIBS+=usr/lib/libncp.so.3
OLD_LIBS+=usr/lib/libnetgraph.so.3
OLD_LIBS+=usr/lib/libngatm.so.3
OLD_LIBS+=usr/lib/libobjc.so.3
OLD_LIBS+=usr/lib/libopie.so.5
OLD_LIBS+=usr/lib/libpam.so.4
OLD_LIBS+=usr/lib/libpanel.so.4
OLD_LIBS+=usr/lib/libpanelw.so.4
OLD_LIBS+=usr/lib/libpmc.so.4
OLD_LIBS+=usr/lib/libproc.so.1
OLD_LIBS+=usr/lib/libradius.so.3
OLD_LIBS+=usr/lib/librpcsvc.so.4
OLD_LIBS+=usr/lib/libsdp.so.3
OLD_LIBS+=usr/lib/libsmb.so.3
OLD_LIBS+=usr/lib/libssh.so.4
OLD_LIBS+=usr/lib/libssl.so.5
OLD_LIBS+=usr/lib/libtacplus.so.3
OLD_LIBS+=usr/lib/libugidfw.so.3
OLD_LIBS+=usr/lib/libusb.so.1
OLD_LIBS+=usr/lib/libusbhid.so.3
OLD_LIBS+=usr/lib/libvgl.so.5
OLD_LIBS+=usr/lib/libwrap.so.5
OLD_LIBS+=usr/lib/libypclnt.so.3
OLD_LIBS+=usr/lib/pam_chroot.so.4
OLD_LIBS+=usr/lib/pam_deny.so.4
OLD_LIBS+=usr/lib/pam_echo.so.4
OLD_LIBS+=usr/lib/pam_exec.so.4
OLD_LIBS+=usr/lib/pam_ftpusers.so.4
OLD_LIBS+=usr/lib/pam_group.so.4
OLD_LIBS+=usr/lib/pam_guest.so.4
OLD_LIBS+=usr/lib/pam_krb5.so.4
OLD_LIBS+=usr/lib/pam_ksu.so.4
OLD_LIBS+=usr/lib/pam_lastlog.so.4
OLD_LIBS+=usr/lib/pam_login_access.so.4
OLD_LIBS+=usr/lib/pam_nologin.so.4
OLD_LIBS+=usr/lib/pam_opie.so.4
OLD_LIBS+=usr/lib/pam_opieaccess.so.4
OLD_LIBS+=usr/lib/pam_passwdqc.so.4
OLD_LIBS+=usr/lib/pam_permit.so.4
OLD_LIBS+=usr/lib/pam_radius.so.4
OLD_LIBS+=usr/lib/pam_rhosts.so.4
OLD_LIBS+=usr/lib/pam_rootok.so.4
OLD_LIBS+=usr/lib/pam_securetty.so.4
OLD_LIBS+=usr/lib/pam_self.so.4
OLD_LIBS+=usr/lib/pam_ssh.so.4
OLD_LIBS+=usr/lib/pam_tacplus.so.4
OLD_LIBS+=usr/lib/pam_unix.so.4
OLD_LIBS+=usr/lib/snmp_atm.so.5
OLD_LIBS+=usr/lib/snmp_bridge.so.5
OLD_LIBS+=usr/lib/snmp_hostres.so.5
OLD_LIBS+=usr/lib/snmp_mibII.so.5
OLD_LIBS+=usr/lib/snmp_netgraph.so.5
OLD_LIBS+=usr/lib/snmp_pf.so.5
# 20090718: the gdm pam.d file is no longer required
OLD_FILES+=etc/pam.d/gdm
# 20090714: net_add_domain(9) renamed to domain_add(9)
OLD_FILES+=usr/share/man/man9/net_add_domain.9.gz
# 20090713: vimage container structs removed
OLD_FILES+=usr/include/netinet/vinet.h
OLD_FILES+=usr/include/netinet6/vinet6.h
OLD_FILES+=usr/include/netipsec/vipsec.h
# 20090712: ieee80211.4 -> net80211.4
OLD_FILES+=usr/share/man/man4/ieee80211.4.gz
# 20090711: typo fixed, kproc_resume,.9 -> kproc_resume.9
OLD_FILES+=usr/share/man/man9/kproc_resume,.9.gz
# 20090709: msgctl.3 msgget.3 msgrcv.3 msgsnd.3 manual pages moved
OLD_FILES+=usr/share/man/man3/msgctl.3.gz
OLD_FILES+=usr/share/man/man3/msgget.3.gz
OLD_FILES+=usr/share/man/man3/msgrcv.3.gz
OLD_FILES+=usr/share/man/man3/msgsnd.3.gz
# 20090630: old kernel RPC implementation removal
OLD_FILES+=usr/include/nfs/rpcv2.h
# 20090624: update usbdi(9)
OLD_FILES+=usr/share/man/man9/usbd_abort_default_pipe.9.gz
OLD_FILES+=usr/share/man/man9/usbd_abort_pipe.9.gz
OLD_FILES+=usr/share/man/man9/usbd_alloc_buffer.9.gz
OLD_FILES+=usr/share/man/man9/usbd_alloc_xfer.9.gz
OLD_FILES+=usr/share/man/man9/usbd_clear_endpoint_stall.9.gz
OLD_FILES+=usr/share/man/man9/usbd_clear_endpoint_stall_async.9.gz
OLD_FILES+=usr/share/man/man9/usbd_clear_endpoint_toggle.9.gz
OLD_FILES+=usr/share/man/man9/usbd_close_pipe.9.gz
OLD_FILES+=usr/share/man/man9/usbd_device2interface_handle.9.gz
OLD_FILES+=usr/share/man/man9/usbd_do_request_async.9.gz
OLD_FILES+=usr/share/man/man9/usbd_do_request_flags_pipe.9.gz
OLD_FILES+=usr/share/man/man9/usbd_endpoint_count.9.gz
OLD_FILES+=usr/share/man/man9/usbd_find_edesc.9.gz
OLD_FILES+=usr/share/man/man9/usbd_find_idesc.9.gz
OLD_FILES+=usr/share/man/man9/usbd_free_buffer.9.gz
OLD_FILES+=usr/share/man/man9/usbd_free_xfer.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_buffer.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_config.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_config_desc.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_config_desc_full.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_config_descriptor.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_device_descriptor.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_endpoint_descriptor.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_interface_altindex.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_interface_descriptor.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_no_alts.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_quirks.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_speed.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_string.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_string_desc.9.gz
OLD_FILES+=usr/share/man/man9/usbd_get_xfer_status.9.gz
OLD_FILES+=usr/share/man/man9/usbd_interface2device_handle.9.gz
OLD_FILES+=usr/share/man/man9/usbd_interface2endpoint_descriptor.9.gz
OLD_FILES+=usr/share/man/man9/usbd_interface_count.9.gz
OLD_FILES+=usr/share/man/man9/usbd_open_pipe.9.gz
OLD_FILES+=usr/share/man/man9/usbd_open_pipe_intr.9.gz
OLD_FILES+=usr/share/man/man9/usbd_pipe2device_handle.9.gz
OLD_FILES+=usr/share/man/man9/usbd_set_config_index.9.gz
OLD_FILES+=usr/share/man/man9/usbd_set_config_no.9.gz
OLD_FILES+=usr/share/man/man9/usbd_set_interface.9.gz
OLD_FILES+=usr/share/man/man9/usbd_setup_default_xfer.9.gz
OLD_FILES+=usr/share/man/man9/usbd_setup_isoc_xfer.9.gz
OLD_FILES+=usr/share/man/man9/usbd_setup_xfer.9.gz
OLD_FILES+=usr/share/man/man9/usbd_sync_transfer.9.gz
OLD_FILES+=usr/share/man/man9/usbd_transfer.9.gz
OLD_FILES+=usr/share/man/man9/usb_find_desc.9.gz
# 20090623: number of headers needed for a usb driver reduced
OLD_FILES+=usr/include/dev/usb/usb_defs.h
OLD_FILES+=usr/include/dev/usb/usb_error.h
OLD_FILES+=usr/include/dev/usb/usb_handle_request.h
OLD_FILES+=usr/include/dev/usb/usb_hid.h
OLD_FILES+=usr/include/dev/usb/usb_lookup.h
OLD_FILES+=usr/include/dev/usb/usb_mfunc.h
OLD_FILES+=usr/include/dev/usb/usb_parse.h
OLD_FILES+=usr/include/dev/usb/usb_revision.h
# 20090609: devclass_add_driver is no longer public
OLD_FILES+=usr/share/man/man9/devclass_add_driver.9.gz
OLD_FILES+=usr/share/man/man9/devclass_delete_driver.9.gz
OLD_FILES+=usr/share/man/man9/devclass_find_driver.9.gz
# 20090605: removal of clists
OLD_FILES+=usr/include/sys/clist.h
# 20090602: removal of window(1)
OLD_FILES+=usr/bin/window
OLD_FILES+=usr/share/man/man1/window.1.gz
# 20090531: bind 9.6.1rc1 import
OLD_LIBS+=usr/lib/liblwres.so.30
# 20090530: removal of early.sh
OLD_FILES+=etc/rc.d/early.sh
# 20090527: renaming of S{LIST,TAILQ}_REMOVE_NEXT() to _REMOVE_AFTER()
OLD_FILES+=usr/share/man/man3/SLIST_REMOVE_NEXT.3.gz
OLD_FILES+=usr/share/man/man3/STAILQ_REMOVE_NEXT.3.gz
# 20090527: removal of legacy USB stack
OLD_FILES+=usr/include/legacy/dev/usb/dsbr100io.h
OLD_FILES+=usr/include/legacy/dev/usb/ehcireg.h
OLD_FILES+=usr/include/legacy/dev/usb/ehcivar.h
OLD_FILES+=usr/include/legacy/dev/usb/hid.h
OLD_FILES+=usr/include/legacy/dev/usb/if_urtwreg.h
OLD_FILES+=usr/include/legacy/dev/usb/if_urtwvar.h
OLD_FILES+=usr/include/legacy/dev/usb/ohcireg.h
OLD_FILES+=usr/include/legacy/dev/usb/ohcivar.h
OLD_FILES+=usr/include/legacy/dev/usb/rio500_usb.h
OLD_FILES+=usr/include/legacy/dev/usb/rt2573_ucode.h
OLD_FILES+=usr/include/legacy/dev/usb/sl811hsreg.h
OLD_FILES+=usr/include/legacy/dev/usb/sl811hsvar.h
OLD_FILES+=usr/include/legacy/dev/usb/ubser.h
OLD_FILES+=usr/include/legacy/dev/usb/ucomvar.h
OLD_FILES+=usr/include/legacy/dev/usb/udbp.h
OLD_FILES+=usr/include/legacy/dev/usb/uftdireg.h
OLD_FILES+=usr/include/legacy/dev/usb/ugraphire_rdesc.h
OLD_FILES+=usr/include/legacy/dev/usb/uhcireg.h
OLD_FILES+=usr/include/legacy/dev/usb/uhcivar.h
OLD_FILES+=usr/include/legacy/dev/usb/usb.h
OLD_FILES+=usr/include/legacy/dev/usb/usb_mem.h
OLD_FILES+=usr/include/legacy/dev/usb/usb_port.h
OLD_FILES+=usr/include/legacy/dev/usb/usb_quirks.h
OLD_FILES+=usr/include/legacy/dev/usb/usbcdc.h
OLD_FILES+=usr/include/legacy/dev/usb/usbdi.h
OLD_FILES+=usr/include/legacy/dev/usb/usbdi_util.h
OLD_FILES+=usr/include/legacy/dev/usb/usbdivar.h
OLD_FILES+=usr/include/legacy/dev/usb/usbhid.h
OLD_FILES+=usr/include/legacy/dev/usb/uxb360gp_rdesc.h
OLD_DIRS+=usr/include/legacy/dev/usb
OLD_DIRS+=usr/include/legacy/dev
OLD_DIRS+=usr/include/legacy
# 20090526: removal of makekey(8)
OLD_FILES+=usr/libexec/makekey
OLD_FILES+=usr/share/man/man8/makekey.8.gz
# 20090522: removal of University of Michigan NFSv4 client
OLD_FILES+=etc/rc.d/idmapd
OLD_FILES+=sbin/idmapd
OLD_FILES+=sbin/mount_nfs4
OLD_FILES+=usr/share/man/man8/idmapd.8.gz
OLD_FILES+=usr/share/man/man8/mount_nfs4.8.gz
# 20090513: removal of legacy versions of USB network interface drivers
OLD_FILES+=usr/include/legacy/dev/usb/if_upgtvar.h
OLD_FILES+=usr/include/legacy/dev/usb/usb_ethersubr.h
# 20090417: removal of legacy versions of USB network interface drivers
OLD_FILES+=usr/include/legacy/dev/usb/if_auereg.h
OLD_FILES+=usr/include/legacy/dev/usb/if_axereg.h
OLD_FILES+=usr/include/legacy/dev/usb/if_cdcereg.h
OLD_FILES+=usr/include/legacy/dev/usb/if_cuereg.h
OLD_FILES+=usr/include/legacy/dev/usb/if_kuereg.h
OLD_FILES+=usr/include/legacy/dev/usb/if_ruereg.h
OLD_FILES+=usr/include/legacy/dev/usb/if_rumreg.h
OLD_FILES+=usr/include/legacy/dev/usb/if_rumvar.h
OLD_FILES+=usr/include/legacy/dev/usb/if_udavreg.h
OLD_FILES+=usr/include/legacy/dev/usb/if_uralreg.h
OLD_FILES+=usr/include/legacy/dev/usb/if_uralvar.h
OLD_FILES+=usr/include/legacy/dev/usb/if_zydfw.h
OLD_FILES+=usr/include/legacy/dev/usb/if_zydreg.h
OLD_FILES+=usr/include/legacy/dev/usb/kue_fw.h
# 20090416: removal of ar(4), ray(4), sr(4), raycontrol(8)
OLD_FILES+=usr/sbin/raycontrol
OLD_FILES+=usr/share/man/man4/i386/ar.4.gz
OLD_FILES+=usr/share/man/man4/i386/ray.4.gz
OLD_FILES+=usr/share/man/man4/i386/sr.4.gz
OLD_FILES+=usr/share/man/man8/raycontrol.8.gz
# 20090410: VOP_LEASE.9 removed
OLD_FILES+=usr/share/man/man9/VOP_LEASE.9.gz
# 20090406: usb_sw_transfer.h removed
OLD_FILES+=usr/include/dev/usb/usb_sw_transfer.h
# 20090405: removal of if_ppp(4) and if_sl(4)
OLD_FILES+=sbin/slattach rescue/slattach
OLD_FILES+=sbin/startslip rescue/startslip
OLD_FILES+=usr/include/net/if_ppp.h
OLD_FILES+=usr/include/net/if_pppvar.h
OLD_FILES+=usr/include/net/if_slvar.h
OLD_FILES+=usr/include/net/ppp_comp.h
OLD_FILES+=usr/include/net/slip.h
OLD_FILES+=usr/sbin/sliplogin
OLD_FILES+=usr/sbin/slstat
OLD_FILES+=usr/sbin/pppd
OLD_FILES+=usr/sbin/pppstats
OLD_FILES+=usr/share/man/man1/startslip.1.gz
OLD_FILES+=usr/share/man/man4/if_ppp.4.gz
OLD_FILES+=usr/share/man/man4/if_sl.4.gz
OLD_FILES+=usr/share/man/man4/ppp.4.gz
OLD_FILES+=usr/share/man/man4/sl.4.gz
OLD_FILES+=usr/share/man/man8/pppd.8.gz
OLD_FILES+=usr/share/man/man8/pppstats.8.gz
OLD_FILES+=usr/share/man/man8/slattach.8.gz
OLD_FILES+=usr/share/man/man8/slip.8.gz
OLD_FILES+=usr/share/man/man8/sliplogin.8.gz
OLD_FILES+=usr/share/man/man8/slstat.8.gz
# 20090321: libpcap upgraded to 1.0.0
OLD_LIBS+=lib/libpcap.so.5
# 20090319: uscanner(4) has been removed
OLD_FILES+=usr/share/man/man4/uscanner.4.gz
# 20090313: k8temp(4) renamed to amdtemp(4)
OLD_FILES+=usr/share/man/man4/k8temp.4.gz
# 20090308: libusb.so.1 renamed
OLD_LIBS+=usr/lib/libusb20.so.1
OLD_FILES+=usr/lib/libusb20.a
OLD_FILES+=usr/lib/libusb20.so
OLD_FILES+=usr/lib/libusb20_p.a
OLD_FILES+=usr/include/libusb20_compat01.h
OLD_FILES+=usr/include/libusb20_compat10.h
# 20090226: libmp(3) functions renamed
OLD_LIBS+=usr/lib/libmp.so.6
# 20090223: changeover of USB stacks
OLD_FILES+=usr/include/dev/usb2/include/ufm2_ioctl.h
OLD_FILES+=usr/include/dev/usb2/include/urio2_ioctl.h
OLD_FILES+=usr/include/dev/usb2/include/usb2_cdc.h
OLD_FILES+=usr/include/dev/usb2/include/usb2_defs.h
OLD_FILES+=usr/include/dev/usb2/include/usb2_devid.h
OLD_FILES+=usr/include/dev/usb2/include/usb2_devtable.h
OLD_FILES+=usr/include/dev/usb2/include/usb2_endian.h
OLD_FILES+=usr/include/dev/usb2/include/usb2_error.h
OLD_FILES+=usr/include/dev/usb2/include/usb2_hid.h
OLD_FILES+=usr/include/dev/usb2/include/usb2_ioctl.h
OLD_FILES+=usr/include/dev/usb2/include/usb2_mfunc.h
OLD_FILES+=usr/include/dev/usb2/include/usb2_revision.h
OLD_FILES+=usr/include/dev/usb2/include/usb2_standard.h
OLD_DIRS+=usr/include/dev/usb2/include
OLD_DIRS+=usr/include/dev/usb2
OLD_FILES+=usr/include/dev/usb/dsbr100io.h
OLD_FILES+=usr/include/dev/usb/ehcireg.h
OLD_FILES+=usr/include/dev/usb/ehcivar.h
OLD_FILES+=usr/include/dev/usb/hid.h
OLD_FILES+=usr/include/dev/usb/if_auereg.h
OLD_FILES+=usr/include/dev/usb/if_axereg.h
OLD_FILES+=usr/include/dev/usb/if_cdcereg.h
OLD_FILES+=usr/include/dev/usb/if_cuereg.h
OLD_FILES+=usr/include/dev/usb/if_kuereg.h
OLD_FILES+=usr/include/dev/usb/if_ruereg.h
OLD_FILES+=usr/include/dev/usb/if_rumreg.h
OLD_FILES+=usr/include/dev/usb/if_rumvar.h
OLD_FILES+=usr/include/dev/usb/if_udavreg.h
OLD_FILES+=usr/include/dev/usb/if_upgtvar.h
OLD_FILES+=usr/include/dev/usb/if_uralreg.h
OLD_FILES+=usr/include/dev/usb/if_uralvar.h
OLD_FILES+=usr/include/dev/usb/if_urtwreg.h
OLD_FILES+=usr/include/dev/usb/if_urtwvar.h
OLD_FILES+=usr/include/dev/usb/if_zydfw.h
OLD_FILES+=usr/include/dev/usb/if_zydreg.h
OLD_FILES+=usr/include/dev/usb/kue_fw.h
OLD_FILES+=usr/include/dev/usb/ohcireg.h
OLD_FILES+=usr/include/dev/usb/ohcivar.h
OLD_FILES+=usr/include/dev/usb/rio500_usb.h
OLD_FILES+=usr/include/dev/usb/rt2573_ucode.h
OLD_FILES+=usr/include/dev/usb/sl811hsreg.h
OLD_FILES+=usr/include/dev/usb/sl811hsvar.h
OLD_FILES+=usr/include/dev/usb/ubser.h
OLD_FILES+=usr/include/dev/usb/ucomvar.h
OLD_FILES+=usr/include/dev/usb/udbp.h
OLD_FILES+=usr/include/dev/usb/uftdireg.h
OLD_FILES+=usr/include/dev/usb/ugraphire_rdesc.h
OLD_FILES+=usr/include/dev/usb/uhcireg.h
OLD_FILES+=usr/include/dev/usb/uhcivar.h
OLD_FILES+=usr/include/dev/usb/usb_ethersubr.h
OLD_FILES+=usr/include/dev/usb/usb_mem.h
OLD_FILES+=usr/include/dev/usb/usb_port.h
OLD_FILES+=usr/include/dev/usb/usb_quirks.h
OLD_FILES+=usr/include/dev/usb/usbcdc.h
OLD_FILES+=usr/include/dev/usb/usbdivar.h
OLD_FILES+=usr/include/dev/usb/uxb360gp_rdesc.h
OLD_FILES+=usr/sbin/usbdevs
OLD_FILES+=usr/share/man/man8/usbdevs.8.gz
# 20090203: removal of pccard header files
OLD_FILES+=usr/include/pccard/cardinfo.h
OLD_FILES+=usr/include/pccard/cis.h
OLD_DIRS+=usr/include/pccard
# 20090203: adding_user.8 moved to adding_user.7
OLD_FILES+=usr/share/man/man8/adding_user.8.gz
# 20090102: file 4.26 import
OLD_FILES+=usr/share/misc/magic.mime
OLD_FILES+=usr/share/misc/magic.mime.mgc
# 20081223: bind 9.4.3 import, nsupdate.8 moved to nsupdate.1
OLD_FILES+=usr/share/man/man8/nsupdate.8.gz
# 20081223: ipprotosw.h removed
OLD_FILES+=usr/include/netinet/ipprotosw.h
# 20081123: vfs_mountedon.9 removed
OLD_FILES+=usr/share/man/man9/vfs_mountedon.9.gz
# 20081023: FREE.9 and MALLOC.9 removed
OLD_FILES+=usr/share/man/man9/FREE.9.gz
OLD_FILES+=usr/share/man/man9/MALLOC.9.gz
# 20080928: removal of inaccurate device_ids(9) manual page
OLD_FILES+=usr/share/man/man9/device_ids.9.gz
OLD_FILES+=usr/share/man/man9/major.9.gz
OLD_FILES+=usr/share/man/man9/minor.9.gz
OLD_FILES+=usr/share/man/man9/umajor.9.gz
OLD_FILES+=usr/share/man/man9/uminor.9.gz
# 20080917: removal of manpage for axed kernel primitive suser(9)
OLD_FILES+=usr/share/man/man9/suser.9.gz
OLD_FILES+=usr/share/man/man9/suser_cred.9.gz
# 20080913: pax removed from rescue
OLD_FILES+=rescue/pax
# 20080823: removal of unneeded pt_chown, to implement grantpt(3)
OLD_FILES+=usr/libexec/pt_chown
# 20080822: ntp 4.2.4p5 import
OLD_FILES+=usr/share/doc/ntp/driver23.html
OLD_FILES+=usr/share/doc/ntp/driver24.html
# 20080821: several man pages moved from man4.i386 to man4
.if ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/share/man/man4/i386/acpi_aiboost.4.gz
OLD_FILES+=usr/share/man/man4/i386/acpi_asus.4.gz
OLD_FILES+=usr/share/man/man4/i386/acpi_fujitsu.4.gz
OLD_FILES+=usr/share/man/man4/i386/acpi_ibm.4.gz
OLD_FILES+=usr/share/man/man4/i386/acpi_panasonic.4.gz
OLD_FILES+=usr/share/man/man4/i386/acpi_sony.4.gz
OLD_FILES+=usr/share/man/man4/i386/acpi_toshiba.4.gz
OLD_FILES+=usr/share/man/man4/i386/ichwd.4.gz
OLD_FILES+=usr/share/man/man4/i386/if_ndis.4.gz
OLD_FILES+=usr/share/man/man4/i386/io.4.gz
OLD_FILES+=usr/share/man/man4/i386/linux.4.gz
OLD_FILES+=usr/share/man/man4/i386/ndis.4.gz
.endif
# 20080820: MPSAFE TTY layer integrated
OLD_FILES+=usr/include/sys/linedisc.h
OLD_FILES+=usr/share/man/man3/posix_openpt.3.gz
# 20080725: sgtty.h removed
OLD_FILES+=usr/include/sgtty.h
# 20080706: bsdlabel(8) removed on powerpc
.if ${TARGET_ARCH} == "powerpc"
OLD_FILES+=sbin/bsdlabel
OLD_FILES+=usr/share/man/man8/bsdlabel.8.gz
.endif
# 20080704: sbsh(4) removed
OLD_FILES+=usr/share/man/man4/if_sbsh.4.gz
OLD_FILES+=usr/share/man/man4/sbsh.4.gz
# 20080704: cnw(4) removed
OLD_FILES+=usr/share/man/man4/if_cnw.4.gz
OLD_FILES+=usr/share/man/man4/cnw.4.gz
# 20080704: oltr(4) removed
.if ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/share/man/man4/i386/if_oltr.4.gz
OLD_FILES+=usr/share/man/man4/i386/oltr.4.gz
.endif
# 20080704: arl(4) removed
.if ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/sbin/arlcontrol
OLD_FILES+=usr/share/man/man4/i386/arl.4.gz
OLD_FILES+=usr/share/man/man8/arlcontrol.8.gz
.endif
# 20080703: sunlabel only for sparc64
.if ${TARGET_ARCH} != "sparc64"
OLD_FILES+=sbin/sunlabel
OLD_FILES+=usr/share/man/man8/sunlabel.8.gz
.endif
# 20080701: wpa_supplicant.conf moved to share/examples/etc/
OLD_FILES+=usr/share/examples/wpa_supplicant/wpa_supplicant.conf
OLD_DIRS+=usr/share/examples/wpa_supplicant
# 20080614: pecoff image activator removed
.if ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/include/machine/pecoff_machdep.h
.endif
# 20080614: sgtty removed
OLD_FILES+=usr/include/sys/ttychars.h
OLD_FILES+=usr/include/sys/ttydev.h
OLD_FILES+=usr/share/man/man3/gtty.3.gz
OLD_FILES+=usr/share/man/man3/stty.3.gz
# 20080609: gpt(8) removed
OLD_FILES+=sbin/gpt
OLD_FILES+=usr/share/man/man8/gpt.8.gz
# 20080525: I4B removed
OLD_FILES+=etc/isdn/answer
OLD_FILES+=etc/isdn/isdntel
OLD_FILES+=etc/isdn/record
OLD_FILES+=etc/isdn/tell
OLD_FILES+=etc/isdn/tell-record
OLD_FILES+=etc/isdn/unknown_incoming
OLD_FILES+=etc/isdn/holidays.D
OLD_FILES+=etc/isdn/isdnd.rates.A
OLD_FILES+=etc/isdn/isdnd.rates.D
OLD_FILES+=etc/isdn/isdnd.rates.F
OLD_FILES+=etc/isdn/isdnd.rates.L
OLD_FILES+=etc/isdn/isdnd.rates.UK.BT
OLD_FILES+=etc/isdn/isdnd.rc.sample
OLD_FILES+=etc/isdn/isdntel.alias.sample
OLD_DIRS+=etc/isdn
OLD_FILES+=etc/rc.d/isdnd
OLD_FILES+=usr/include/i4b/i4b_cause.h
OLD_FILES+=usr/include/i4b/i4b_debug.h
OLD_FILES+=usr/include/i4b/i4b_ioctl.h
OLD_FILES+=usr/include/i4b/i4b_rbch_ioctl.h
OLD_FILES+=usr/include/i4b/i4b_tel_ioctl.h
OLD_FILES+=usr/include/i4b/i4b_trace.h
OLD_DIRS+=usr/include/i4b
OLD_FILES+=usr/sbin/dtmfdecode
OLD_FILES+=usr/sbin/g711conv
OLD_FILES+=usr/sbin/isdnd
OLD_FILES+=usr/sbin/isdndebug
OLD_FILES+=usr/sbin/isdndecode
OLD_FILES+=usr/sbin/isdnmonitor
OLD_FILES+=usr/sbin/isdnphone
OLD_FILES+=usr/sbin/isdntel
OLD_FILES+=usr/sbin/isdntelctl
OLD_FILES+=usr/sbin/isdntrace
OLD_FILES+=usr/share/isdn/0.al
OLD_FILES+=usr/share/isdn/1.al
OLD_FILES+=usr/share/isdn/2.al
OLD_FILES+=usr/share/isdn/3.al
OLD_FILES+=usr/share/isdn/4.al
OLD_FILES+=usr/share/isdn/5.al
OLD_FILES+=usr/share/isdn/6.al
OLD_FILES+=usr/share/isdn/7.al
OLD_FILES+=usr/share/isdn/8.al
OLD_FILES+=usr/share/isdn/9.al
OLD_FILES+=usr/share/isdn/beep.al
OLD_FILES+=usr/share/isdn/msg.al
OLD_DIRS+=usr/share/isdn
OLD_FILES+=usr/share/man/man1/dtmfdecode.1.gz
OLD_FILES+=usr/share/man/man1/g711conv.1.gz
OLD_FILES+=usr/share/man/man4/i4b.4.gz
OLD_FILES+=usr/share/man/man4/i4bcapi.4.gz
OLD_FILES+=usr/share/man/man4/i4bctl.4.gz
OLD_FILES+=usr/share/man/man4/i4bing.4.gz
OLD_FILES+=usr/share/man/man4/i4bipr.4.gz
OLD_FILES+=usr/share/man/man4/i4bisppp.4.gz
OLD_FILES+=usr/share/man/man4/i4bq921.4.gz
OLD_FILES+=usr/share/man/man4/i4bq931.4.gz
OLD_FILES+=usr/share/man/man4/i4brbch.4.gz
OLD_FILES+=usr/share/man/man4/i4btel.4.gz
OLD_FILES+=usr/share/man/man4/i4btrc.4.gz
OLD_FILES+=usr/share/man/man4/iavc.4.gz
OLD_FILES+=usr/share/man/man4/isic.4.gz
OLD_FILES+=usr/share/man/man4/ifpi.4.gz
OLD_FILES+=usr/share/man/man4/ifpi2.4.gz
OLD_FILES+=usr/share/man/man4/ifpnp.4.gz
OLD_FILES+=usr/share/man/man4/ihfc.4.gz
OLD_FILES+=usr/share/man/man4/itjc.4.gz
OLD_FILES+=usr/share/man/man4/iwic.4.gz
OLD_FILES+=usr/share/man/man5/isdnd.rc.5.gz
OLD_FILES+=usr/share/man/man5/isdnd.rates.5.gz
OLD_FILES+=usr/share/man/man5/isdnd.acct.5.gz
OLD_FILES+=usr/share/man/man8/isdnd.8.gz
OLD_FILES+=usr/share/man/man8/isdndebug.8.gz
OLD_FILES+=usr/share/man/man8/isdndecode.8.gz
OLD_FILES+=usr/share/man/man8/isdnmonitor.8.gz
OLD_FILES+=usr/share/man/man8/isdnphone.8.gz
OLD_FILES+=usr/share/man/man8/isdntel.8.gz
OLD_FILES+=usr/share/man/man8/isdntelctl.8.gz
OLD_FILES+=usr/share/man/man8/isdntrace.8.gz
OLD_FILES+=usr/share/examples/isdn/contrib/README
OLD_FILES+=usr/share/examples/isdn/contrib/anleitung.ppp
OLD_FILES+=usr/share/examples/isdn/contrib/answer.c
OLD_FILES+=usr/share/examples/isdn/contrib/answer.sh
OLD_FILES+=usr/share/examples/isdn/contrib/convert.sh
OLD_FILES+=usr/share/examples/isdn/contrib/hplay.c
OLD_FILES+=usr/share/examples/isdn/contrib/i4b-ppp-newbie.txt
OLD_FILES+=usr/share/examples/isdn/contrib/isdnctl
OLD_FILES+=usr/share/examples/isdn/contrib/isdnd_acct
OLD_FILES+=usr/share/examples/isdn/contrib/isdnd_acct.pl
OLD_FILES+=usr/share/examples/isdn/contrib/isdntelmux.c
OLD_FILES+=usr/share/examples/isdn/contrib/mrtg-isp0.sh
OLD_FILES+=usr/share/examples/isdn/i4brunppp/Makefile
OLD_FILES+=usr/share/examples/isdn/i4brunppp/README
OLD_FILES+=usr/share/examples/isdn/i4brunppp/i4brunppp-isdnd.rc
OLD_FILES+=usr/share/examples/isdn/i4brunppp/i4brunppp.8
OLD_FILES+=usr/share/examples/isdn/i4brunppp/i4brunppp.c
OLD_FILES+=usr/share/examples/isdn/v21/Makefile
OLD_FILES+=usr/share/examples/isdn/v21/README
OLD_FILES+=usr/share/examples/isdn/v21/v21modem.c
OLD_FILES+=usr/share/examples/isdn/FAQ
OLD_FILES+=usr/share/examples/isdn/KERNEL
OLD_FILES+=usr/share/examples/isdn/Overview
OLD_FILES+=usr/share/examples/isdn/README
OLD_FILES+=usr/share/examples/isdn/ROADMAP
OLD_FILES+=usr/share/examples/isdn/ReleaseNotes
OLD_FILES+=usr/share/examples/isdn/Resources
OLD_FILES+=usr/share/examples/isdn/SupportedCards
OLD_FILES+=usr/share/examples/isdn/ThankYou
OLD_DIRS+=usr/share/examples/isdn/contrib
OLD_DIRS+=usr/share/examples/isdn/i4brunppp
OLD_DIRS+=usr/share/examples/isdn/v21
OLD_DIRS+=usr/share/examples/isdn
OLD_FILES+=usr/share/examples/ppp/isdnd.rc
OLD_FILES+=usr/share/examples/ppp/ppp.conf.isdn
# 20080525: ng_atmpif removed
OLD_FILES+=usr/include/netgraph/atm/ng_atmpif.h
OLD_FILES+=usr/share/man/man4/ng_atmpif.4.gz
# 20080522: pmap_addr_hint removed
OLD_FILES+=usr/share/man/man9/pmap_addr_hint.9.gz
# 20080517: ipsec_osdep.h removed
OLD_FILES+=usr/include/netipsec/ipsec_osdep.h
# 20080507: heimdal 1.1 import
OLD_LIBS+=usr/lib/libasn1.so.9
OLD_LIBS+=usr/lib/libgssapi.so.9
OLD_LIBS+=usr/lib/libgssapi_krb5.so.9
OLD_LIBS+=usr/lib/libhdb.so.9
OLD_LIBS+=usr/lib/libkadm5clnt.so.9
OLD_LIBS+=usr/lib/libkadm5srv.so.9
OLD_LIBS+=usr/lib/libkafs5.so.9
OLD_LIBS+=usr/lib/libkrb5.so.9
OLD_LIBS+=usr/lib/libroken.so.9
# 20080420: Symbol card support dropped
OLD_FILES+=usr/include/dev/wi/spectrum24t_cf.h
# 20080420: awi removal
OLD_FILES+=usr/share/man/man4/awi.4.gz
OLD_FILES+=usr/share/man/man4/if_awi.4.gz
# 20080331: pkg_sign has been removed
OLD_FILES+=usr/sbin/pkg_check
OLD_FILES+=usr/sbin/pkg_sign
OLD_FILES+=usr/share/man/man1/pkg_check.1.gz
OLD_FILES+=usr/share/man/man1/pkg_sign.1.gz
# 20080314: stack_print(9) mlink fixed
OLD_FILES+=usr/share/man/man9/stack_printf.9.gz
# 20080312: libkse removal
OLD_FILES+=usr/include/sys/kse.h
OLD_FILES+=usr/lib/libkse.so
OLD_LIBS+=usr/lib/libkse.so.3
OLD_FILES+=usr/share/man/man2/kse.2.gz
OLD_FILES+=usr/share/man/man2/kse_create.2.gz
OLD_FILES+=usr/share/man/man2/kse_exit.2.gz
OLD_FILES+=usr/share/man/man2/kse_release.2.gz
OLD_FILES+=usr/share/man/man2/kse_switchin.2.gz
OLD_FILES+=usr/share/man/man2/kse_thr_interrupt.2.gz
OLD_FILES+=usr/share/man/man2/kse_wakeup.2.gz
# 20080225: bsdar/bsdranlib rename to ar/ranlib
OLD_FILES+=usr/bin/bsdar
OLD_FILES+=usr/bin/bsdranlib
OLD_FILES+=usr/share/man/man1/bsdar.1.gz
OLD_FILES+=usr/share/man/man1/bsdranlib.1.gz
# 20080220: geom_lvm rename to geom_linux_lvm
OLD_FILES+=usr/share/man/man4/geom_lvm.4.gz
# 20080126: oldcard.4 removal
OLD_FILES+=usr/share/man/man4/card.4.gz
OLD_FILES+=usr/share/man/man4/oldcard.4.gz
# 20080122: Removed from the tree
OLD_FILES+=usr/share/man/man9/BUF_REFCNT.9.gz
# 20080108: Moved to section 2
OLD_FILES+=usr/share/man/man3/shm_open.3.gz
OLD_FILES+=usr/share/man/man3/shm_unlink.3.gz
# 20071207: Merged with fortunes-o.real
OLD_FILES+=usr/share/games/fortune/fortunes2-o
OLD_FILES+=usr/share/games/fortune/fortunes2-o.dat
# 20071201: Removal of XRPU driver
OLD_FILES+=usr/include/sys/xrpuio.h
# 20071129: Disabled static versions of libkse by default
OLD_FILES+=usr/lib/libkse.a
OLD_FILES+=usr/lib/libkse_p.a
OLD_FILES+=usr/lib/libkse_pic.a
# 20071129: Removed a Solaris compatibility header
OLD_FILES+=usr/include/sys/_elf_solaris.h
# 20071125: Renamed to pmc_get_msr()
OLD_FILES+=usr/share/man/man3/pmc_x86_get_msr.3.gz
# 20071108: Removed very crunch OLDCARD support file
OLD_FILES+=etc/defaults/pccard.conf
# 20071025: rc.d/nfslocking superseded by rc.d/lockd and rc.d/statd
OLD_FILES+=etc/rc.d/nfslocking
# 20070930: rename of cached to nscd
OLD_FILES+=etc/cached.conf
OLD_FILES+=etc/rc.d/cached
OLD_FILES+=usr/sbin/cached
OLD_FILES+=usr/share/man/man5/cached.conf.5.gz
OLD_FILES+=usr/share/man/man8/cached.8.gz
# 20070807: removal of PowerPC specific header file
.if ${TARGET_ARCH} == "powerpc"
OLD_FILES+=usr/include/machine/interruptvar.h
.endif
# 20070801: fast_ipsec.4 gone
OLD_FILES+=usr/share/man/man4/fast_ipsec.4.gz
# 20070715: netatm temporarily disconnected (removed 20080525)
OLD_FILES+=rescue/atm
OLD_FILES+=rescue/fore_dnld
OLD_FILES+=rescue/ilmid
OLD_FILES+=sbin/atm
OLD_FILES+=sbin/fore_dnld
OLD_FILES+=sbin/ilmid
OLD_FILES+=usr/include/libatm.h
OLD_FILES+=usr/include/netatm/atm.h
OLD_FILES+=usr/include/netatm/atm_cm.h
OLD_FILES+=usr/include/netatm/atm_if.h
OLD_FILES+=usr/include/netatm/atm_ioctl.h
OLD_FILES+=usr/include/netatm/atm_pcb.h
OLD_FILES+=usr/include/netatm/atm_sap.h
OLD_FILES+=usr/include/netatm/atm_sigmgr.h
OLD_FILES+=usr/include/netatm/atm_stack.h
OLD_FILES+=usr/include/netatm/atm_sys.h
OLD_FILES+=usr/include/netatm/atm_var.h
OLD_FILES+=usr/include/netatm/atm_vc.h
OLD_FILES+=usr/include/netatm/ipatm/ipatm.h
OLD_FILES+=usr/include/netatm/ipatm/ipatm_serv.h
OLD_FILES+=usr/include/netatm/ipatm/ipatm_var.h
OLD_FILES+=usr/include/netatm/port.h
OLD_FILES+=usr/include/netatm/queue.h
OLD_FILES+=usr/include/netatm/sigpvc/sigpvc_var.h
OLD_FILES+=usr/include/netatm/spans/spans_cls.h
OLD_FILES+=usr/include/netatm/spans/spans_kxdr.h
OLD_FILES+=usr/include/netatm/spans/spans_var.h
OLD_FILES+=usr/include/netatm/uni/sscf_uni.h
OLD_FILES+=usr/include/netatm/uni/sscf_uni_var.h
OLD_FILES+=usr/include/netatm/uni/sscop.h
OLD_FILES+=usr/include/netatm/uni/sscop_misc.h
OLD_FILES+=usr/include/netatm/uni/sscop_pdu.h
OLD_FILES+=usr/include/netatm/uni/sscop_var.h
OLD_FILES+=usr/include/netatm/uni/uni.h
OLD_FILES+=usr/include/netatm/uni/uniip_var.h
OLD_FILES+=usr/include/netatm/uni/unisig.h
OLD_FILES+=usr/include/netatm/uni/unisig_decode.h
OLD_FILES+=usr/include/netatm/uni/unisig_mbuf.h
OLD_FILES+=usr/include/netatm/uni/unisig_msg.h
OLD_FILES+=usr/include/netatm/uni/unisig_print.h
OLD_FILES+=usr/include/netatm/uni/unisig_var.h
OLD_FILES+=usr/lib/libatm.a
OLD_FILES+=usr/lib/libatm_p.a
OLD_FILES+=usr/sbin/atmarpd
OLD_FILES+=usr/sbin/scspd
OLD_FILES+=usr/share/man/en.ISO8859-1/man8/atm.8.gz
OLD_FILES+=usr/share/man/en.ISO8859-1/man8/atmarpd.8.gz
OLD_FILES+=usr/share/man/en.ISO8859-1/man8/fore_dnld.8.gz
OLD_FILES+=usr/share/man/en.ISO8859-1/man8/ilmid.8.gz
OLD_FILES+=usr/share/man/en.ISO8859-1/man8/scspd.8.gz
OLD_FILES+=usr/share/man/man8/atm.8.gz
OLD_FILES+=usr/share/man/man8/atmarpd.8.gz
OLD_FILES+=usr/share/man/man8/fore_dnld.8.gz
OLD_FILES+=usr/share/man/man8/ilmid.8.gz
OLD_FILES+=usr/share/man/man8/scspd.8.gz
OLD_FILES+=usr/share/examples/atm/NOTES
OLD_FILES+=usr/share/examples/atm/README
OLD_FILES+=usr/share/examples/atm/Startup
OLD_FILES+=usr/share/examples/atm/atm-config.sh
OLD_FILES+=usr/share/examples/atm/atm-sockets.txt
OLD_FILES+=usr/share/examples/atm/cpcs-design.txt
OLD_FILES+=usr/share/examples/atm/fore-microcode.txt
OLD_FILES+=usr/share/examples/atm/sscf-design.txt
OLD_FILES+=usr/share/examples/atm/sscop-design.txt
OLD_LIBS+=lib/libatm.so.5
OLD_FILES+=usr/lib/libatm.so
OLD_DIRS+=usr/include/netatm/sigpvc
OLD_DIRS+=usr/include/netatm/spans
OLD_DIRS+=usr/include/netatm/ipatm
OLD_DIRS+=usr/include/netatm/uni
OLD_DIRS+=usr/include/netatm
OLD_DIRS+=usr/share/examples/atm
# 20070705: I4B headers repo-copied to include/i4b/
.if ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/include/machine/i4b_cause.h
OLD_FILES+=usr/include/machine/i4b_debug.h
OLD_FILES+=usr/include/machine/i4b_ioctl.h
OLD_FILES+=usr/include/machine/i4b_rbch_ioctl.h
OLD_FILES+=usr/include/machine/i4b_tel_ioctl.h
OLD_FILES+=usr/include/machine/i4b_trace.h
.endif
# 20070703: pf 4.1 import
OLD_FILES+=usr/libexec/ftp-proxy
# 20070701: KAME IPSec removal
OLD_FILES+=usr/include/netinet6/ah.h
OLD_FILES+=usr/include/netinet6/ah6.h
OLD_FILES+=usr/include/netinet6/ah_aesxcbcmac.h
OLD_FILES+=usr/include/netinet6/esp.h
OLD_FILES+=usr/include/netinet6/esp6.h
OLD_FILES+=usr/include/netinet6/esp_aesctr.h
OLD_FILES+=usr/include/netinet6/esp_camellia.h
OLD_FILES+=usr/include/netinet6/esp_rijndael.h
OLD_FILES+=usr/include/netinet6/ipsec.h
OLD_FILES+=usr/include/netinet6/ipsec6.h
OLD_FILES+=usr/include/netinet6/ipcomp.h
OLD_FILES+=usr/include/netinet6/ipcomp6.h
OLD_FILES+=usr/include/netkey/key.h
OLD_FILES+=usr/include/netkey/key_debug.h
OLD_FILES+=usr/include/netkey/key_var.h
OLD_FILES+=usr/include/netkey/keydb.h
OLD_FILES+=usr/include/netkey/keysock.h
OLD_DIRS+=usr/include/netkey
# 20070701: remove wicontrol
OLD_FILES+=usr/sbin/wicontrol
OLD_FILES+=usr/share/man/man8/wicontrol.8.gz
# 20070625: umapfs removal
OLD_FILES+=rescue/mount_umapfs
OLD_FILES+=sbin/mount_umapfs
OLD_FILES+=usr/include/fs/umapfs/umap.h
OLD_FILES+=usr/share/man/man8/mount_umapfs.8.gz
OLD_DIRS+=usr/include/fs/umapfs
# 20070618: Removal of the PROTO.localhost* files
OLD_FILES+=etc/namedb/PROTO.localhost-v6.rev
OLD_FILES+=etc/namedb/PROTO.localhost.rev
OLD_FILES+=etc/namedb/make-localhost
# 20070618: shared library version bump
OLD_LIBS+=lib/libalias.so.5
OLD_LIBS+=lib/libbsnmp.so.3
OLD_LIBS+=lib/libncurses.so.6
OLD_LIBS+=lib/libncursesw.so.6
OLD_LIBS+=lib/libreadline.so.6
OLD_LIBS+=usr/lib/libdialog.so.5
OLD_LIBS+=usr/lib/libgnuregex.so.3
OLD_LIBS+=usr/lib/libhistory.so.6
OLD_LIBS+=usr/lib/libpam.so.3
OLD_LIBS+=usr/lib/libssh.so.3
OLD_LIBS+=usr/lib/pam_chroot.so.3
OLD_LIBS+=usr/lib/pam_deny.so.3
OLD_LIBS+=usr/lib/pam_echo.so.3
OLD_LIBS+=usr/lib/pam_exec.so.3
OLD_LIBS+=usr/lib/pam_ftpusers.so.3
OLD_LIBS+=usr/lib/pam_group.so.3
OLD_LIBS+=usr/lib/pam_guest.so.3
OLD_LIBS+=usr/lib/pam_krb5.so.3
OLD_LIBS+=usr/lib/pam_ksu.so.3
OLD_LIBS+=usr/lib/pam_lastlog.so.3
OLD_LIBS+=usr/lib/pam_login_access.so.3
OLD_LIBS+=usr/lib/pam_nologin.so.3
OLD_LIBS+=usr/lib/pam_opie.so.3
OLD_LIBS+=usr/lib/pam_opieaccess.so.3
OLD_LIBS+=usr/lib/pam_passwdqc.so.3
OLD_LIBS+=usr/lib/pam_permit.so.3
OLD_LIBS+=usr/lib/pam_radius.so.3
OLD_LIBS+=usr/lib/pam_rhosts.so.3
OLD_LIBS+=usr/lib/pam_rootok.so.3
OLD_LIBS+=usr/lib/pam_securetty.so.3
OLD_LIBS+=usr/lib/pam_self.so.3
OLD_LIBS+=usr/lib/pam_ssh.so.3
OLD_LIBS+=usr/lib/pam_tacplus.so.3
OLD_LIBS+=usr/lib/pam_unix.so.3
OLD_LIBS+=usr/lib/snmp_atm.so.4
OLD_LIBS+=usr/lib/snmp_bridge.so.4
OLD_LIBS+=usr/lib/snmp_hostres.so.4
OLD_LIBS+=usr/lib/snmp_mibII.so.4
OLD_LIBS+=usr/lib/snmp_netgraph.so.4
OLD_LIBS+=usr/lib/snmp_pf.so.4
# 20070613: IPX over IP tunnel removal
OLD_FILES+=usr/include/netipx/ipx_ip.h
# 20070605: sched_core removal
OLD_FILES+=usr/share/man/man4/sched_core.4.gz
# 20070603: BIND 9.4.1 import
OLD_LIBS+=usr/lib/liblwres.so.10
# 20070521: shared library version bump
OLD_LIBS+=lib/libatm.so.4
OLD_LIBS+=lib/libbegemot.so.2
OLD_LIBS+=lib/libbsdxml.so.2
OLD_LIBS+=lib/libcam.so.3
OLD_LIBS+=lib/libcrypt.so.3
OLD_LIBS+=lib/libdevstat.so.5
OLD_LIBS+=lib/libedit.so.5
OLD_LIBS+=lib/libgeom.so.3
OLD_LIBS+=lib/libipsec.so.2
OLD_LIBS+=lib/libipx.so.3
OLD_LIBS+=lib/libkiconv.so.2
OLD_LIBS+=lib/libkse.so.2
OLD_LIBS+=lib/libkvm.so.3
OLD_LIBS+=lib/libm.so.4
OLD_LIBS+=lib/libmd.so.3
OLD_LIBS+=lib/libpcap.so.4
OLD_LIBS+=lib/libpthread.so.2
OLD_LIBS+=lib/libsbuf.so.3
OLD_LIBS+=lib/libthr.so.2
OLD_LIBS+=lib/libufs.so.3
OLD_LIBS+=lib/libutil.so.6
OLD_LIBS+=lib/libz.so.3
OLD_LIBS+=usr/lib/libbluetooth.so.2
OLD_LIBS+=usr/lib/libbsm.so.1
OLD_LIBS+=usr/lib/libbz2.so.2
OLD_LIBS+=usr/lib/libcalendar.so.3
OLD_LIBS+=usr/lib/libcom_err.so.3
OLD_LIBS+=usr/lib/libdevinfo.so.3
OLD_LIBS+=usr/lib/libfetch.so.4
OLD_LIBS+=usr/lib/libform.so.3
OLD_LIBS+=usr/lib/libformw.so.3
OLD_LIBS+=usr/lib/libftpio.so.6
OLD_LIBS+=usr/lib/libgpib.so.1
OLD_LIBS+=usr/lib/libkse.so.2
OLD_LIBS+=usr/lib/libmagic.so.2
OLD_LIBS+=usr/lib/libmemstat.so.1
OLD_LIBS+=usr/lib/libmenu.so.3
OLD_LIBS+=usr/lib/libmenuw.so.3
OLD_LIBS+=usr/lib/libmilter.so.3
OLD_LIBS+=usr/lib/libmp.so.5
OLD_LIBS+=usr/lib/libncp.so.2
OLD_LIBS+=usr/lib/libnetgraph.so.2
OLD_LIBS+=usr/lib/libngatm.so.2
OLD_LIBS+=usr/lib/libopie.so.4
OLD_LIBS+=usr/lib/libpanel.so.3
OLD_LIBS+=usr/lib/libpanelw.so.3
OLD_LIBS+=usr/lib/libpmc.so.3
OLD_LIBS+=usr/lib/libradius.so.2
OLD_LIBS+=usr/lib/librpcsvc.so.3
OLD_LIBS+=usr/lib/libsdp.so.2
OLD_LIBS+=usr/lib/libsmb.so.2
OLD_LIBS+=usr/lib/libstdc++.so.5
OLD_LIBS+=usr/lib/libtacplus.so.2
OLD_LIBS+=usr/lib/libthr.so.2
OLD_LIBS+=usr/lib/libthread_db.so.2
OLD_LIBS+=usr/lib/libugidfw.so.2
OLD_LIBS+=usr/lib/libusbhid.so.2
OLD_LIBS+=usr/lib/libvgl.so.4
OLD_LIBS+=usr/lib/libwrap.so.4
OLD_LIBS+=usr/lib/libypclnt.so.2
OLD_LIBS+=usr/lib/snmp_bridge.so.3
OLD_LIBS+=usr/lib/snmp_hostres.so.3
# 20070519: GCC 4.2
OLD_FILES+=usr/bin/f77
OLD_FILES+=usr/bin/protoize
OLD_FILES+=usr/include/g2c.h
OLD_FILES+=usr/libexec/f771
OLD_FILES+=usr/share/info/g77.info.gz
OLD_FILES+=usr/share/man/man1/f77.1.gz
OLD_FILES+=usr/include/c++/3.4/algorithm
OLD_FILES+=usr/include/c++/3.4/backward/algo.h
OLD_FILES+=usr/include/c++/3.4/backward/algobase.h
OLD_FILES+=usr/include/c++/3.4/backward/alloc.h
OLD_FILES+=usr/include/c++/3.4/backward/backward_warning.h
OLD_FILES+=usr/include/c++/3.4/backward/bvector.h
OLD_FILES+=usr/include/c++/3.4/backward/complex.h
OLD_FILES+=usr/include/c++/3.4/backward/defalloc.h
OLD_FILES+=usr/include/c++/3.4/backward/deque.h
OLD_FILES+=usr/include/c++/3.4/backward/fstream.h
OLD_FILES+=usr/include/c++/3.4/backward/function.h
OLD_FILES+=usr/include/c++/3.4/backward/hash_map.h
OLD_FILES+=usr/include/c++/3.4/backward/hash_set.h
OLD_FILES+=usr/include/c++/3.4/backward/hashtable.h
OLD_FILES+=usr/include/c++/3.4/backward/heap.h
OLD_FILES+=usr/include/c++/3.4/backward/iomanip.h
OLD_FILES+=usr/include/c++/3.4/backward/iostream.h
OLD_FILES+=usr/include/c++/3.4/backward/istream.h
OLD_FILES+=usr/include/c++/3.4/backward/iterator.h
OLD_FILES+=usr/include/c++/3.4/backward/list.h
OLD_FILES+=usr/include/c++/3.4/backward/map.h
OLD_FILES+=usr/include/c++/3.4/backward/multimap.h
OLD_FILES+=usr/include/c++/3.4/backward/multiset.h
OLD_FILES+=usr/include/c++/3.4/backward/new.h
OLD_FILES+=usr/include/c++/3.4/backward/ostream.h
OLD_FILES+=usr/include/c++/3.4/backward/pair.h
OLD_FILES+=usr/include/c++/3.4/backward/queue.h
OLD_FILES+=usr/include/c++/3.4/backward/rope.h
OLD_FILES+=usr/include/c++/3.4/backward/set.h
OLD_FILES+=usr/include/c++/3.4/backward/slist.h
OLD_FILES+=usr/include/c++/3.4/backward/stack.h
OLD_FILES+=usr/include/c++/3.4/backward/stream.h
OLD_FILES+=usr/include/c++/3.4/backward/streambuf.h
OLD_FILES+=usr/include/c++/3.4/backward/strstream
OLD_FILES+=usr/include/c++/3.4/backward/tempbuf.h
OLD_FILES+=usr/include/c++/3.4/backward/tree.h
OLD_FILES+=usr/include/c++/3.4/backward/vector.h
OLD_FILES+=usr/include/c++/3.4/bits/allocator.h
OLD_FILES+=usr/include/c++/3.4/bits/atomic_word.h
OLD_FILES+=usr/include/c++/3.4/bits/atomicity.h
OLD_FILES+=usr/include/c++/3.4/bits/basic_file.h
OLD_FILES+=usr/include/c++/3.4/bits/basic_ios.h
OLD_FILES+=usr/include/c++/3.4/bits/basic_ios.tcc
OLD_FILES+=usr/include/c++/3.4/bits/basic_string.h
OLD_FILES+=usr/include/c++/3.4/bits/basic_string.tcc
OLD_FILES+=usr/include/c++/3.4/bits/boost_concept_check.h
OLD_FILES+=usr/include/c++/3.4/bits/c++allocator.h
OLD_FILES+=usr/include/c++/3.4/bits/c++config.h
OLD_FILES+=usr/include/c++/3.4/bits/c++io.h
OLD_FILES+=usr/include/c++/3.4/bits/c++locale.h
OLD_FILES+=usr/include/c++/3.4/bits/c++locale_internal.h
OLD_FILES+=usr/include/c++/3.4/bits/char_traits.h
OLD_FILES+=usr/include/c++/3.4/bits/cmath.tcc
OLD_FILES+=usr/include/c++/3.4/bits/codecvt.h
OLD_FILES+=usr/include/c++/3.4/bits/codecvt_specializations.h
OLD_FILES+=usr/include/c++/3.4/bits/concept_check.h
OLD_FILES+=usr/include/c++/3.4/bits/concurrence.h
OLD_FILES+=usr/include/c++/3.4/bits/cpp_type_traits.h
OLD_FILES+=usr/include/c++/3.4/bits/ctype_base.h
OLD_FILES+=usr/include/c++/3.4/bits/ctype_inline.h
OLD_FILES+=usr/include/c++/3.4/bits/ctype_noninline.h
OLD_FILES+=usr/include/c++/3.4/bits/deque.tcc
OLD_FILES+=usr/include/c++/3.4/bits/fstream.tcc
OLD_FILES+=usr/include/c++/3.4/bits/functexcept.h
OLD_FILES+=usr/include/c++/3.4/bits/gslice.h
OLD_FILES+=usr/include/c++/3.4/bits/gslice_array.h
OLD_FILES+=usr/include/c++/3.4/bits/gthr-default.h
OLD_FILES+=usr/include/c++/3.4/bits/gthr-posix.h
OLD_FILES+=usr/include/c++/3.4/bits/gthr-single.h
OLD_FILES+=usr/include/c++/3.4/bits/gthr.h
OLD_FILES+=usr/include/c++/3.4/bits/indirect_array.h
OLD_FILES+=usr/include/c++/3.4/bits/ios_base.h
OLD_FILES+=usr/include/c++/3.4/bits/istream.tcc
OLD_FILES+=usr/include/c++/3.4/bits/list.tcc
OLD_FILES+=usr/include/c++/3.4/bits/locale_classes.h
OLD_FILES+=usr/include/c++/3.4/bits/locale_facets.h
OLD_FILES+=usr/include/c++/3.4/bits/locale_facets.tcc
OLD_FILES+=usr/include/c++/3.4/bits/localefwd.h
OLD_FILES+=usr/include/c++/3.4/bits/mask_array.h
OLD_FILES+=usr/include/c++/3.4/bits/messages_members.h
OLD_FILES+=usr/include/c++/3.4/bits/os_defines.h
OLD_FILES+=usr/include/c++/3.4/bits/ostream.tcc
OLD_FILES+=usr/include/c++/3.4/bits/postypes.h
OLD_FILES+=usr/include/c++/3.4/bits/slice_array.h
OLD_FILES+=usr/include/c++/3.4/bits/sstream.tcc
OLD_FILES+=usr/include/c++/3.4/bits/stl_algo.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_algobase.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_bvector.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_construct.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_deque.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_function.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_heap.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_iterator.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_iterator_base_funcs.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_iterator_base_types.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_list.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_map.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_multimap.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_multiset.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_numeric.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_pair.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_queue.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_raw_storage_iter.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_relops.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_set.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_stack.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_tempbuf.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_threads.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_tree.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_uninitialized.h
OLD_FILES+=usr/include/c++/3.4/bits/stl_vector.h
OLD_FILES+=usr/include/c++/3.4/bits/stream_iterator.h
OLD_FILES+=usr/include/c++/3.4/bits/streambuf.tcc
OLD_FILES+=usr/include/c++/3.4/bits/streambuf_iterator.h
OLD_FILES+=usr/include/c++/3.4/bits/stringfwd.h
OLD_FILES+=usr/include/c++/3.4/bits/time_members.h
OLD_FILES+=usr/include/c++/3.4/bits/type_traits.h
OLD_FILES+=usr/include/c++/3.4/bits/valarray_after.h
OLD_FILES+=usr/include/c++/3.4/bits/valarray_array.h
OLD_FILES+=usr/include/c++/3.4/bits/valarray_array.tcc
OLD_FILES+=usr/include/c++/3.4/bits/valarray_before.h
OLD_FILES+=usr/include/c++/3.4/bits/vector.tcc
OLD_FILES+=usr/include/c++/3.4/bitset
OLD_FILES+=usr/include/c++/3.4/cassert
OLD_FILES+=usr/include/c++/3.4/cctype
OLD_FILES+=usr/include/c++/3.4/cerrno
OLD_FILES+=usr/include/c++/3.4/cfloat
OLD_FILES+=usr/include/c++/3.4/ciso646
OLD_FILES+=usr/include/c++/3.4/climits
OLD_FILES+=usr/include/c++/3.4/clocale
OLD_FILES+=usr/include/c++/3.4/cmath
OLD_FILES+=usr/include/c++/3.4/complex
OLD_FILES+=usr/include/c++/3.4/csetjmp
OLD_FILES+=usr/include/c++/3.4/csignal
OLD_FILES+=usr/include/c++/3.4/cstdarg
OLD_FILES+=usr/include/c++/3.4/cstddef
OLD_FILES+=usr/include/c++/3.4/cstdio
OLD_FILES+=usr/include/c++/3.4/cstdlib
OLD_FILES+=usr/include/c++/3.4/cstring
OLD_FILES+=usr/include/c++/3.4/ctime
OLD_FILES+=usr/include/c++/3.4/cwchar
OLD_FILES+=usr/include/c++/3.4/cwctype
OLD_FILES+=usr/include/c++/3.4/cxxabi.h
OLD_FILES+=usr/include/c++/3.4/debug/bitset
OLD_FILES+=usr/include/c++/3.4/debug/debug.h
OLD_FILES+=usr/include/c++/3.4/debug/deque
OLD_FILES+=usr/include/c++/3.4/debug/formatter.h
OLD_FILES+=usr/include/c++/3.4/debug/hash_map
OLD_FILES+=usr/include/c++/3.4/debug/hash_map.h
OLD_FILES+=usr/include/c++/3.4/debug/hash_multimap.h
OLD_FILES+=usr/include/c++/3.4/debug/hash_multiset.h
OLD_FILES+=usr/include/c++/3.4/debug/hash_set
OLD_FILES+=usr/include/c++/3.4/debug/hash_set.h
OLD_FILES+=usr/include/c++/3.4/debug/list
OLD_FILES+=usr/include/c++/3.4/debug/map
OLD_FILES+=usr/include/c++/3.4/debug/map.h
OLD_FILES+=usr/include/c++/3.4/debug/multimap.h
OLD_FILES+=usr/include/c++/3.4/debug/multiset.h
OLD_FILES+=usr/include/c++/3.4/debug/safe_base.h
OLD_FILES+=usr/include/c++/3.4/debug/safe_iterator.h
OLD_FILES+=usr/include/c++/3.4/debug/safe_iterator.tcc
OLD_FILES+=usr/include/c++/3.4/debug/safe_sequence.h
OLD_FILES+=usr/include/c++/3.4/debug/set
OLD_FILES+=usr/include/c++/3.4/debug/set.h
OLD_FILES+=usr/include/c++/3.4/debug/string
OLD_FILES+=usr/include/c++/3.4/debug/vector
OLD_FILES+=usr/include/c++/3.4/deque
OLD_FILES+=usr/include/c++/3.4/exception
OLD_FILES+=usr/include/c++/3.4/exception_defines.h
OLD_FILES+=usr/include/c++/3.4/ext/algorithm
OLD_FILES+=usr/include/c++/3.4/ext/bitmap_allocator.h
OLD_FILES+=usr/include/c++/3.4/ext/debug_allocator.h
OLD_FILES+=usr/include/c++/3.4/ext/enc_filebuf.h
OLD_FILES+=usr/include/c++/3.4/ext/functional
OLD_FILES+=usr/include/c++/3.4/ext/hash_fun.h
OLD_FILES+=usr/include/c++/3.4/ext/hash_map
OLD_FILES+=usr/include/c++/3.4/ext/hash_set
OLD_FILES+=usr/include/c++/3.4/ext/hashtable.h
OLD_FILES+=usr/include/c++/3.4/ext/iterator
OLD_FILES+=usr/include/c++/3.4/ext/malloc_allocator.h
OLD_FILES+=usr/include/c++/3.4/ext/memory
OLD_FILES+=usr/include/c++/3.4/ext/mt_allocator.h
OLD_FILES+=usr/include/c++/3.4/ext/new_allocator.h
OLD_FILES+=usr/include/c++/3.4/ext/numeric
OLD_FILES+=usr/include/c++/3.4/ext/pod_char_traits.h
OLD_FILES+=usr/include/c++/3.4/ext/pool_allocator.h
OLD_FILES+=usr/include/c++/3.4/ext/rb_tree
OLD_FILES+=usr/include/c++/3.4/ext/rope
OLD_FILES+=usr/include/c++/3.4/ext/ropeimpl.h
OLD_FILES+=usr/include/c++/3.4/ext/slist
OLD_FILES+=usr/include/c++/3.4/ext/stdio_filebuf.h
OLD_FILES+=usr/include/c++/3.4/ext/stdio_sync_filebuf.h
OLD_FILES+=usr/include/c++/3.4/fstream
OLD_FILES+=usr/include/c++/3.4/functional
OLD_FILES+=usr/include/c++/3.4/iomanip
OLD_FILES+=usr/include/c++/3.4/ios
OLD_FILES+=usr/include/c++/3.4/iosfwd
OLD_FILES+=usr/include/c++/3.4/iostream
OLD_FILES+=usr/include/c++/3.4/istream
OLD_FILES+=usr/include/c++/3.4/iterator
OLD_FILES+=usr/include/c++/3.4/limits
OLD_FILES+=usr/include/c++/3.4/list
OLD_FILES+=usr/include/c++/3.4/locale
OLD_FILES+=usr/include/c++/3.4/map
OLD_FILES+=usr/include/c++/3.4/memory
OLD_FILES+=usr/include/c++/3.4/new
OLD_FILES+=usr/include/c++/3.4/numeric
OLD_FILES+=usr/include/c++/3.4/ostream
OLD_FILES+=usr/include/c++/3.4/queue
OLD_FILES+=usr/include/c++/3.4/set
OLD_FILES+=usr/include/c++/3.4/sstream
OLD_FILES+=usr/include/c++/3.4/stack
OLD_FILES+=usr/include/c++/3.4/stdexcept
OLD_FILES+=usr/include/c++/3.4/streambuf
OLD_FILES+=usr/include/c++/3.4/string
OLD_FILES+=usr/include/c++/3.4/typeinfo
OLD_FILES+=usr/include/c++/3.4/utility
OLD_FILES+=usr/include/c++/3.4/valarray
OLD_FILES+=usr/include/c++/3.4/vector
OLD_DIRS+=usr/include/c++/3.4/backward
OLD_DIRS+=usr/include/c++/3.4/bits
OLD_DIRS+=usr/include/c++/3.4/debug
OLD_DIRS+=usr/include/c++/3.4/ext
OLD_DIRS+=usr/include/c++/3.4
# 20070510: zpool/zfs moved to /sbin
OLD_FILES+=usr/sbin/zfs
OLD_FILES+=usr/sbin/zpool
# 20070423: rc.bluetooth (examples) removed
OLD_FILES+=usr/share/examples/netgraph/bluetooth/rc.bluetooth
OLD_DIRS+=usr/share/examples/netgraph/bluetooth
# 20070421: worm.4 removed
OLD_FILES+=usr/share/man/man4/worm.4.gz
# 20070417: trunk(4) renamed to lagg(4)
OLD_FILES+=usr/include/net/if_trunk.h
# 20070409: uuidgen moved to /bin/
OLD_FILES+=usr/bin/uuidgen
# 20070328: bzip2 1.0.4
OLD_FILES+=usr/share/info/bzip2.info.gz
# 20070303: libarchive 2.0
OLD_LIBS+=usr/lib/libarchive.so.3
# 20070301: remove addr2ascii and ascii2addr
OLD_FILES+=usr/share/man/man3/addr2ascii.3.gz
OLD_FILES+=usr/share/man/man3/ascii2addr.3.gz
# 20070225: vm_page_unmanage() removed
OLD_FILES+=usr/share/man/man9/vm_page_unmanage.9.gz
# 20070216: VFS_VPTOFH(9) -> VOP_VPTOFH(9)
OLD_FILES+=usr/share/man/man9/VFS_VPTOFH.9.gz
# 20070212: kame.4 removed
OLD_FILES+=usr/share/man/man4/kame.4.gz
# 20070201: remove libmytinfo link
OLD_FILES+=usr/lib/libmytinfo.a
OLD_FILES+=usr/lib/libmytinfo.so
OLD_FILES+=usr/lib/libmytinfo_p.a
OLD_FILES+=usr/lib/libmytinfow.a
OLD_FILES+=usr/lib/libmytinfow.so
OLD_FILES+=usr/lib/libmytinfow_p.a
# 20070128: remove vnconfig
OLD_FILES+=usr/sbin/vnconfig
# 20070127: remove bpf_compat.h
OLD_FILES+=usr/include/net/bpf_compat.h
# 20070125: objformat bites the dust
OLD_FILES+=usr/bin/objformat
OLD_FILES+=usr/share/man/man1/objformat.1.gz
OLD_FILES+=usr/include/objformat.h
OLD_FILES+=usr/share/man/man3/getobjformat.3.gz
# 20061008: rename *.so.4 libalias modules to *.so and move to /lib
# This uses MOVED_LIBS because the new files are libraries even though
# the old files to remove are symlinks
MOVED_LIBS+=usr/lib/libalias_cuseeme.so
MOVED_LIBS+=usr/lib/libalias_dummy.so
MOVED_LIBS+=usr/lib/libalias_ftp.so
MOVED_LIBS+=usr/lib/libalias_irc.so
MOVED_LIBS+=usr/lib/libalias_nbt.so
MOVED_LIBS+=usr/lib/libalias_pptp.so
MOVED_LIBS+=usr/lib/libalias_skinny.so
MOVED_LIBS+=usr/lib/libalias_smedia.so
OLD_LIBS+=lib/libalias_cuseeme.so.4
OLD_LIBS+=lib/libalias_dummy.so.4
OLD_LIBS+=lib/libalias_ftp.so.4
OLD_LIBS+=lib/libalias_irc.so.4
OLD_LIBS+=lib/libalias_nbt.so.4
OLD_LIBS+=lib/libalias_pptp.so.4
OLD_LIBS+=lib/libalias_skinny.so.4
OLD_LIBS+=lib/libalias_smedia.so.4
# 20061126: remove old man page
OLD_FILES+=usr/share/man/man3/archive_read_set_bytes_per_block.3.gz
# 20061125: remove old man page
OLD_FILES+=usr/share/man/man9/devsw.9.gz
# 20061122: remove obsolete mount programs
OLD_FILES+=sbin/mount_devfs
OLD_FILES+=sbin/mount_ext2fs
OLD_FILES+=sbin/mount_fdescfs
OLD_FILES+=sbin/mount_linprocfs
OLD_FILES+=sbin/mount_procfs
OLD_FILES+=sbin/mount_std
OLD_FILES+=rescue/mount_devfs
OLD_FILES+=rescue/mount_ext2fs
OLD_FILES+=rescue/mount_fdescfs
OLD_FILES+=rescue/mount_linprocfs
OLD_FILES+=rescue/mount_procfs
OLD_FILES+=rescue/mount_std
OLD_FILES+=usr/share/man/man8/mount_devfs.8.gz
OLD_FILES+=usr/share/man/man8/mount_ext2fs.8.gz
OLD_FILES+=usr/share/man/man8/mount_fdescfs.8.gz
OLD_FILES+=usr/share/man/man8/mount_linprocfs.8.gz
OLD_FILES+=usr/share/man/man8/mount_procfs.8.gz
OLD_FILES+=usr/share/man/man8/mount_std.8.gz
# 20061116: uhidev.4 removed
OLD_FILES+=usr/share/man/man4/uhidev.4.gz
# 20061106: archive_write_prepare.3 removed
OLD_FILES+=usr/share/man/man3/archive_write_prepare.3.gz
# 20061018: pccardc removed
OLD_FILES+=usr/sbin/pccardc usr/share/man/man8/pccardc.8.gz
# 20060930: demangle.h from contrib/libstdc++/include/ext/
OLD_FILES+=usr/include/c++/3.4/ext/demangle.h
# 20060929: mrouted removed
OLD_FILES+=usr/sbin/map-mbone
OLD_FILES+=usr/sbin/mrinfo
OLD_FILES+=usr/sbin/mrouted
OLD_FILES+=usr/sbin/mtrace
OLD_FILES+=usr/share/man/man8/map-mbone.8.gz
OLD_FILES+=usr/share/man/man8/mrinfo.8.gz
OLD_FILES+=usr/share/man/man8/mrouted.8.gz
OLD_FILES+=usr/share/man/man8/mtrace.8.gz
# 20060924: tcpslice removed
OLD_FILES+=usr/sbin/tcpslice
OLD_FILES+=usr/share/man/man1/tcpslice.1.gz
# 20060829: kvmdb cleanup script removed
OLD_FILES+=etc/periodic/weekly/120.clean-kvmdb
# 20060822: ramdisk{,-own} have been replaced by mdconfig{,2}
OLD_FILES+=etc/rc.d/ramdisk
OLD_FILES+=etc/rc.d/ramdisk-own
# 20060729: OpenSSL 0.9.7e -> 0.9.8b upgrade
OLD_FILES+=usr/include/openssl/eng_int.h
OLD_FILES+=usr/include/openssl/hw_4758_cca_err.h
OLD_FILES+=usr/include/openssl/hw_aep_err.h
OLD_FILES+=usr/include/openssl/hw_atalla_err.h
OLD_FILES+=usr/include/openssl/hw_cswift_err.h
OLD_FILES+=usr/include/openssl/hw_ncipher_err.h
OLD_FILES+=usr/include/openssl/hw_nuron_err.h
OLD_FILES+=usr/include/openssl/hw_sureware_err.h
OLD_FILES+=usr/include/openssl/hw_ubsec_err.h
# 20060713: mount_linsysfs(8) never existed in 7.x
OLD_FILES+=sbin/mount_linsysfs
OLD_FILES+=usr/share/man/man8/mount_linsysfs.8.gz
# 20060704: KAME compat file net_osdep.h removed
OLD_FILES+=usr/include/net/net_osdep.h
# 20060605: man page links removed by OpenBSM 1.0 alpha 6 import
OLD_FILES+=usr/share/man/man3/au_to_socket.3.gz
OLD_FILES+=usr/share/man/man3/au_to_socket_ex_128.3.gz
OLD_FILES+=usr/share/man/man3/au_to_socket_ex_32.3.gz
# 20060517: pcvt removed
OLD_FILES+=usr/share/pcvt/README.FIRST
OLD_FILES+=usr/share/pcvt/Etc/xmodmap-german
OLD_FILES+=usr/share/pcvt/Etc/pcvt.sh
OLD_FILES+=usr/share/pcvt/Etc/pcvt.el
OLD_FILES+=usr/share/pcvt/Etc/Terminfo
OLD_FILES+=usr/share/pcvt/Etc/Termcap
OLD_DIRS+=usr/share/pcvt/Etc
OLD_FILES+=usr/share/pcvt/Doc/NotesAndHints
OLD_FILES+=usr/share/pcvt/Doc/Keyboard.VT
OLD_FILES+=usr/share/pcvt/Doc/Keyboard.HP
OLD_FILES+=usr/share/pcvt/Doc/EscapeSequences
OLD_FILES+=usr/share/pcvt/Doc/Charsets
OLD_FILES+=usr/share/pcvt/Doc/CharGen
OLD_FILES+=usr/share/pcvt/Doc/Bibliography
OLD_FILES+=usr/share/pcvt/Doc/Acknowledgements
OLD_DIRS+=usr/share/pcvt/Doc
OLD_DIRS+=usr/share/pcvt
OLD_FILES+=usr/share/misc/pcvtfonts/vt220l.816
OLD_FILES+=usr/share/misc/pcvtfonts/vt220l.814
OLD_FILES+=usr/share/misc/pcvtfonts/vt220l.810
OLD_FILES+=usr/share/misc/pcvtfonts/vt220l.808
OLD_FILES+=usr/share/misc/pcvtfonts/vt220h.816
OLD_FILES+=usr/share/misc/pcvtfonts/vt220h.814
OLD_FILES+=usr/share/misc/pcvtfonts/vt220h.810
OLD_FILES+=usr/share/misc/pcvtfonts/vt220h.808
OLD_DIRS+=usr/share/misc/pcvtfonts
OLD_FILES+=usr/share/misc/keycap.pcvt
OLD_FILES+=usr/share/man/man8/ispcvt.8.gz
OLD_FILES+=usr/share/man/man5/keycap.5.gz
OLD_FILES+=usr/share/man/man4/pcvt.4.gz
OLD_FILES+=usr/share/man/man3/kgetstr.3.gz
OLD_FILES+=usr/share/man/man3/kgetnum.3.gz
OLD_FILES+=usr/share/man/man3/kgetflag.3.gz
OLD_FILES+=usr/share/man/man3/kgetent.3.gz
OLD_FILES+=usr/share/man/man3/keycap.3.gz
OLD_FILES+=usr/share/man/man1/vt220keys.1.gz
OLD_FILES+=usr/share/man/man1/scon.1.gz
OLD_FILES+=usr/share/man/man1/loadfont.1.gz
OLD_FILES+=usr/share/man/man1/kcon.1.gz
OLD_FILES+=usr/share/man/man1/fontedit.1.gz
OLD_FILES+=usr/share/man/man1/cursor.1.gz
OLD_FILES+=usr/sbin/vt220keys
OLD_FILES+=usr/sbin/scon
OLD_FILES+=usr/sbin/loadfont
OLD_FILES+=usr/sbin/kcon
OLD_FILES+=usr/sbin/ispcvt
OLD_FILES+=usr/sbin/fontedit
OLD_FILES+=usr/sbin/cursor
OLD_FILES+=usr/lib/libkeycap_p.a
OLD_FILES+=usr/lib/libkeycap.a
OLD_FILES+=usr/include/machine/pcvt_ioctl.h
# 20060514: lnc(4) replaced by le(4)
OLD_FILES+=usr/share/man/man4/i386/lnc.4.gz
# 20060512: remove ip6fw
OLD_FILES+=etc/periodic/security/600.ip6fwdenied
OLD_FILES+=etc/periodic/security/650.ip6fwlimit
OLD_FILES+=sbin/ip6fw
OLD_FILES+=usr/include/netinet6/ip6_fw.h
OLD_FILES+=usr/share/man/man8/ip6fw.8.gz
# 20060424: sab(4) removed
OLD_FILES+=usr/share/man/man4/sab.4.gz
# 20060328: remove redundant rc.d script
OLD_FILES+=etc/rc.d/ike
# 20060127: revert libdisk to static-only
OLD_FILES+=usr/lib/libdisk.so
# 20060115: sys/pccard includes cleanup
OLD_FILES+=usr/include/pccard/driver.h
OLD_FILES+=usr/include/pccard/i82365.h
OLD_FILES+=usr/include/pccard/meciareg.h
OLD_FILES+=usr/include/pccard/pccard_nbk.h
OLD_FILES+=usr/include/pccard/pcic_pci.h
OLD_FILES+=usr/include/pccard/pcicvar.h
OLD_FILES+=usr/include/pccard/slot.h
# 20051215: rescue/nextboot.sh renamed to rescue/nextboot
OLD_FILES+=rescue/nextboot.sh
# 20051214: usbd(8) removed
OLD_FILES+=etc/rc.d/usbd
OLD_FILES+=etc/usbd.conf
OLD_FILES+=usr/sbin/usbd
OLD_FILES+=usr/share/man/man8/usbd.8.gz
# 20051029: rc.d/ppp-user renamed to rc.d/ppp for convenience
OLD_FILES+=etc/rc.d/ppp-user
# 20051012: setkey(8) moved to /sbin/
OLD_FILES+=usr/sbin/setkey
# 20050930: pccardd(8) removed
OLD_FILES+=usr/sbin/pccardd
OLD_FILES+=usr/share/man/man5/pccard.conf.5.gz
OLD_FILES+=usr/share/man/man8/pccardd.8.gz
# 20050927: bridge(4) replaced by if_bridge(4)
OLD_FILES+=usr/include/net/bridge.h
# 20050831: not implemented
OLD_FILES+=usr/share/man/man3/getino.3.gz
OLD_FILES+=usr/share/man/man3/putino.3.gz
# 20050825: T/TCP retired several months ago
OLD_FILES+=usr/share/man/man4/ttcp.4.gz
# 20050805 tn3270 retired long ago
OLD_FILES+=usr/share/misc/map3270
# 20050801: too old to be interesting here
OLD_FILES+=usr/share/doc/papers/px.ps.gz
# 20050721: moved to ports
OLD_FILES+=usr/sbin/vttest
OLD_FILES+=usr/share/man/man1/vttest.1.gz
# 20050617: wpa man pages moved to section 8
OLD_FILES+=usr/share/man/man1/hostapd.1.gz
OLD_FILES+=usr/share/man/man1/hostapd_cli.1.gz
OLD_FILES+=usr/share/man/man1/wpa_cli.1.gz
OLD_FILES+=usr/share/man/man1/wpa_supplicant.1.gz
# 20050610: rexecd (insecure by design)
OLD_FILES+=etc/pam.d/rexecd
OLD_FILES+=usr/share/man/man8/rexecd.8.gz
OLD_FILES+=usr/libexec/rexecd
# 20050606: OpenBSD dhclient replaces ISC one
OLD_FILES+=bin/omshell
OLD_FILES+=sbin/omshell
OLD_FILES+=usr/share/man/man1/omshell.1.gz
OLD_FILES+=usr/share/man/man5/dhcp-eval.5.gz
# 200504XX: ipf tools moved from /usr to /
OLD_FILES+=rescue/ipfs
OLD_FILES+=rescue/ipfstat
OLD_FILES+=rescue/ipmon
OLD_FILES+=rescue/ipnat
OLD_FILES+=usr/sbin/ipftest
OLD_FILES+=usr/sbin/ipresend
OLD_FILES+=usr/sbin/ipsend
OLD_FILES+=usr/sbin/iptest
OLD_FILES+=usr/share/man/man1/ipnat.1.gz
OLD_FILES+=usr/share/man/man1/ipsend.1.gz
OLD_FILES+=usr/share/man/man1/iptest.1.gz
OLD_FILES+=usr/share/man/man5/ipsend.5.gz
# 200503XX: bsdtar takes over gtar
OLD_FILES+=usr/bin/gtar
OLD_FILES+=usr/share/man/man1/gtar.1.gz
# 200503XX
OLD_FILES+=usr/share/man/man3/exp10.3.gz
OLD_FILES+=usr/share/man/man3/exp10f.3.gz
OLD_FILES+=usr/share/man/man3/fpsetsticky.3.gz
# 20050324: updated release infrastructure
OLD_FILES+=usr/share/man/man5/drivers.conf.5.gz
# 20050317: removed from BIND 9 distribution
OLD_FILES+=usr/share/doc/bind9/KNOWN_DEFECTS
# 2005XXXX:
OLD_FILES+=sbin/mount_autofs
OLD_FILES+=usr/lib/libautofs.a
OLD_FILES+=usr/lib/libautofs.so
OLD_FILES+=usr/share/man/man8/mount_autofs.8.gz
# 20050203: Merged with fortunes
OLD_FILES+=usr/share/games/fortune/fortunes2
OLD_FILES+=usr/share/games/fortune/fortunes2.dat
# 200501XX:
OLD_FILES+=usr/libexec/getNAME
# 200411XX: gvinum replaces vinum
OLD_FILES+=bin/vinum
OLD_FILES+=rescue/vinum
OLD_FILES+=sbin/vinum
OLD_FILES+=usr/share/man/man8/vinum.8.gz
# 200411XX: libxpg4 removal
OLD_FILES+=usr/lib/libxpg4.a
OLD_FILES+=usr/lib/libxpg4.so
OLD_FILES+=usr/lib/libxpg4_p.a
# 20041109: replaced by em(4)
OLD_FILES+=usr/share/man/man4/gx.4.gz
OLD_FILES+=usr/share/man/man4/if_gx.4.gz
# 20041017: rune interface removed
OLD_FILES+=usr/include/rune.h
OLD_FILES+=usr/share/man/man3/fgetrune.3.gz
OLD_FILES+=usr/share/man/man3/fputrune.3.gz
OLD_FILES+=usr/share/man/man3/fungetrune.3.gz
OLD_FILES+=usr/share/man/man3/mbrrune.3.gz
OLD_FILES+=usr/share/man/man3/mbrune.3.gz
OLD_FILES+=usr/share/man/man3/rune.3.gz
OLD_FILES+=usr/share/man/man3/setinvalidrune.3.gz
OLD_FILES+=usr/share/man/man3/sgetrune.3.gz
OLD_FILES+=usr/share/man/man3/sputrune.3.gz
# 20040925: bind9 import
OLD_FILES+=usr/bin/dnskeygen
OLD_FILES+=usr/bin/dnsquery
OLD_FILES+=usr/lib/libisc.a
OLD_FILES+=usr/lib/libisc.so
OLD_FILES+=usr/lib/libisc_p.a
OLD_FILES+=usr/libexec/named-xfer
OLD_FILES+=usr/sbin/named.restart
OLD_FILES+=usr/sbin/ndc
OLD_FILES+=usr/sbin/nslookup
OLD_FILES+=usr/sbin/nsupdate
OLD_FILES+=usr/share/doc/bind/html/acl.html
OLD_FILES+=usr/share/doc/bind/html/address_list.html
OLD_FILES+=usr/share/doc/bind/html/comments.html
OLD_FILES+=usr/share/doc/bind/html/config.html
OLD_FILES+=usr/share/doc/bind/html/controls.html
OLD_FILES+=usr/share/doc/bind/html/docdef.html
OLD_FILES+=usr/share/doc/bind/html/example.html
OLD_FILES+=usr/share/doc/bind/html/include.html
OLD_FILES+=usr/share/doc/bind/html/index.html
OLD_FILES+=usr/share/doc/bind/html/key.html
OLD_FILES+=usr/share/doc/bind/html/logging.html
OLD_FILES+=usr/share/doc/bind/html/master.html
OLD_FILES+=usr/share/doc/bind/html/options.html
OLD_FILES+=usr/share/doc/bind/html/server.html
OLD_FILES+=usr/share/doc/bind/html/trusted-keys.html
OLD_FILES+=usr/share/doc/bind/html/zone.html
OLD_FILES+=usr/share/doc/bind/misc/DynamicUpdate
OLD_FILES+=usr/share/doc/bind/misc/FAQ.1of2
OLD_FILES+=usr/share/doc/bind/misc/FAQ.2of2
OLD_FILES+=usr/share/doc/bind/misc/rfc2317-notes.txt
OLD_FILES+=usr/share/doc/bind/misc/style.txt
OLD_FILES+=usr/share/man/man1/dnskeygen.1.gz
OLD_FILES+=usr/share/man/man1/dnsquery.1.gz
OLD_FILES+=usr/share/man/man8/named-bootconf.8.gz
OLD_FILES+=usr/share/man/man8/named-xfer.8.gz
OLD_FILES+=usr/share/man/man8/named.restart.8.gz
OLD_FILES+=usr/share/man/man8/ndc.8.gz
OLD_FILES+=usr/share/man/man8/nslookup.8.gz
# 200409XX
OLD_FILES+=usr/share/man/man3/ENSURE.3.gz
OLD_FILES+=usr/share/man/man3/ENSURE_ERR.3.gz
OLD_FILES+=usr/share/man/man3/INSIST.3.gz
OLD_FILES+=usr/share/man/man3/INSIST_ERR.3.gz
OLD_FILES+=usr/share/man/man3/INVARIANT.3.gz
OLD_FILES+=usr/share/man/man3/INVARIANT_ERR.3.gz
OLD_FILES+=usr/share/man/man3/REQUIRE.3.gz
OLD_FILES+=usr/share/man/man3/REQUIRE_ERR.3.gz
OLD_FILES+=usr/share/man/man3/assertion_type_to_text.3.gz
OLD_FILES+=usr/share/man/man3/assertions.3.gz
OLD_FILES+=usr/share/man/man3/bitncmp.3.gz
OLD_FILES+=usr/share/man/man3/evAddTime.3.gz
OLD_FILES+=usr/share/man/man3/evCancelConn.3.gz
OLD_FILES+=usr/share/man/man3/evCancelRW.3.gz
OLD_FILES+=usr/share/man/man3/evClearIdleTimer.3.gz
OLD_FILES+=usr/share/man/man3/evClearTimer.3.gz
OLD_FILES+=usr/share/man/man3/evCmpTime.3.gz
OLD_FILES+=usr/share/man/man3/evConnFunc.3.gz
OLD_FILES+=usr/share/man/man3/evConnect.3.gz
OLD_FILES+=usr/share/man/man3/evConsIovec.3.gz
OLD_FILES+=usr/share/man/man3/evConsTime.3.gz
OLD_FILES+=usr/share/man/man3/evCreate.3.gz
OLD_FILES+=usr/share/man/man3/evDefer.3.gz
OLD_FILES+=usr/share/man/man3/evDeselectFD.3.gz
OLD_FILES+=usr/share/man/man3/evDestroy.3.gz
OLD_FILES+=usr/share/man/man3/evDispatch.3.gz
OLD_FILES+=usr/share/man/man3/evDo.3.gz
OLD_FILES+=usr/share/man/man3/evDrop.3.gz
OLD_FILES+=usr/share/man/man3/evFileFunc.3.gz
OLD_FILES+=usr/share/man/man3/evGetNext.3.gz
OLD_FILES+=usr/share/man/man3/evHold.3.gz
OLD_FILES+=usr/share/man/man3/evInitID.3.gz
OLD_FILES+=usr/share/man/man3/evLastEventTime.3.gz
OLD_FILES+=usr/share/man/man3/evListen.3.gz
OLD_FILES+=usr/share/man/man3/evMainLoop.3.gz
OLD_FILES+=usr/share/man/man3/evNowTime.3.gz
OLD_FILES+=usr/share/man/man3/evPrintf.3.gz
OLD_FILES+=usr/share/man/man3/evRead.3.gz
OLD_FILES+=usr/share/man/man3/evResetTimer.3.gz
OLD_FILES+=usr/share/man/man3/evSelectFD.3.gz
OLD_FILES+=usr/share/man/man3/evSetDebug.3.gz
OLD_FILES+=usr/share/man/man3/evSetIdleTimer.3.gz
OLD_FILES+=usr/share/man/man3/evSetTimer.3.gz
OLD_FILES+=usr/share/man/man3/evStreamFunc.3.gz
OLD_FILES+=usr/share/man/man3/evSubTime.3.gz
OLD_FILES+=usr/share/man/man3/evTestID.3.gz
OLD_FILES+=usr/share/man/man3/evTimeRW.3.gz
OLD_FILES+=usr/share/man/man3/evTimeSpec.3.gz
OLD_FILES+=usr/share/man/man3/evTimeVal.3.gz
OLD_FILES+=usr/share/man/man3/evTimerFunc.3.gz
OLD_FILES+=usr/share/man/man3/evTouchIdleTimer.3.gz
OLD_FILES+=usr/share/man/man3/evTryAccept.3.gz
OLD_FILES+=usr/share/man/man3/evUnhold.3.gz
OLD_FILES+=usr/share/man/man3/evUntimeRW.3.gz
OLD_FILES+=usr/share/man/man3/evUnwait.3.gz
OLD_FILES+=usr/share/man/man3/evWaitFor.3.gz
OLD_FILES+=usr/share/man/man3/evWaitFunc.3.gz
OLD_FILES+=usr/share/man/man3/evWrite.3.gz
OLD_FILES+=usr/share/man/man3/eventlib.3.gz
OLD_FILES+=usr/share/man/man3/heap.3.gz
OLD_FILES+=usr/share/man/man3/heap_decreased.3.gz
OLD_FILES+=usr/share/man/man3/heap_delete.3.gz
OLD_FILES+=usr/share/man/man3/heap_element.3.gz
OLD_FILES+=usr/share/man/man3/heap_for_each.3.gz
OLD_FILES+=usr/share/man/man3/heap_free.3.gz
OLD_FILES+=usr/share/man/man3/heap_increased.3.gz
OLD_FILES+=usr/share/man/man3/heap_insert.3.gz
OLD_FILES+=usr/share/man/man3/heap_new.3.gz
OLD_FILES+=usr/share/man/man3/log_add_channel.3.gz
OLD_FILES+=usr/share/man/man3/log_category_is_active.3.gz
OLD_FILES+=usr/share/man/man3/log_close_stream.3.gz
OLD_FILES+=usr/share/man/man3/log_dec_references.3.gz
OLD_FILES+=usr/share/man/man3/log_free_channel.3.gz
OLD_FILES+=usr/share/man/man3/log_free_context.3.gz
OLD_FILES+=usr/share/man/man3/log_get_filename.3.gz
OLD_FILES+=usr/share/man/man3/log_get_stream.3.gz
OLD_FILES+=usr/share/man/man3/log_inc_references.3.gz
OLD_FILES+=usr/share/man/man3/log_new_context.3.gz
OLD_FILES+=usr/share/man/man3/log_new_file_channel.3.gz
OLD_FILES+=usr/share/man/man3/log_new_null_channel.3.gz
OLD_FILES+=usr/share/man/man3/log_new_syslog_channel.3.gz
OLD_FILES+=usr/share/man/man3/log_open_stream.3.gz
OLD_FILES+=usr/share/man/man3/log_option.3.gz
OLD_FILES+=usr/share/man/man3/log_remove_channel.3.gz
OLD_FILES+=usr/share/man/man3/log_set_file_owner.3.gz
OLD_FILES+=usr/share/man/man3/log_vwrite.3.gz
OLD_FILES+=usr/share/man/man3/log_write.3.gz
OLD_FILES+=usr/share/man/man3/logging.3.gz
OLD_FILES+=usr/share/man/man3/memcluster.3.gz
OLD_FILES+=usr/share/man/man3/memget.3.gz
OLD_FILES+=usr/share/man/man3/memput.3.gz
OLD_FILES+=usr/share/man/man3/memstats.3.gz
OLD_FILES+=usr/share/man/man3/set_assertion_failure_callback.3.
OLD_FILES+=usr/share/man/man3/sigwait.3.gz
OLD_FILES+=usr/share/man/man3/tree_add.3.gz
OLD_FILES+=usr/share/man/man3/tree_delete.3.gz
OLD_FILES+=usr/share/man/man3/tree_init.3.gz
OLD_FILES+=usr/share/man/man3/tree_mung.3.gz
OLD_FILES+=usr/share/man/man3/tree_srch.3.gz
OLD_FILES+=usr/share/man/man3/tree_trav.3.gz
# 2004XXYY: OS internal libs, no ports use them, no need to use OLD_LIBS
OLD_LIBS+=lib/geom/geom_concat.so.1
OLD_LIBS+=lib/geom/geom_label.so.1
OLD_LIBS+=lib/geom/geom_nop.so.1
OLD_LIBS+=lib/geom/geom_stripe.so.1
# 20040728: GCC 3.4.2
OLD_DIRS+=usr/include/c++/3.3
OLD_FILES+=usr/include/c++/3.3/FlexLexer.h
OLD_FILES+=usr/include/c++/3.3/algorithm
OLD_FILES+=usr/include/c++/3.3/backward/algo.h
OLD_FILES+=usr/include/c++/3.3/backward/algobase.h
OLD_FILES+=usr/include/c++/3.3/backward/alloc.h
OLD_FILES+=usr/include/c++/3.3/backward/backward_warning.h
OLD_FILES+=usr/include/c++/3.3/backward/bvector.h
OLD_FILES+=usr/include/c++/3.3/backward/complex.h
OLD_FILES+=usr/include/c++/3.3/backward/defalloc.h
OLD_FILES+=usr/include/c++/3.3/backward/deque.h
OLD_FILES+=usr/include/c++/3.3/backward/fstream.h
OLD_FILES+=usr/include/c++/3.3/backward/function.h
OLD_FILES+=usr/include/c++/3.3/backward/hash_map.h
OLD_FILES+=usr/include/c++/3.3/backward/hash_set.h
OLD_FILES+=usr/include/c++/3.3/backward/hashtable.h
OLD_FILES+=usr/include/c++/3.3/backward/heap.h
OLD_FILES+=usr/include/c++/3.3/backward/iomanip.h
OLD_FILES+=usr/include/c++/3.3/backward/iostream.h
OLD_FILES+=usr/include/c++/3.3/backward/istream.h
OLD_FILES+=usr/include/c++/3.3/backward/iterator.h
OLD_FILES+=usr/include/c++/3.3/backward/list.h
OLD_FILES+=usr/include/c++/3.3/backward/map.h
OLD_FILES+=usr/include/c++/3.3/backward/multimap.h
OLD_FILES+=usr/include/c++/3.3/backward/multiset.h
OLD_FILES+=usr/include/c++/3.3/backward/new.h
OLD_FILES+=usr/include/c++/3.3/backward/ostream.h
OLD_FILES+=usr/include/c++/3.3/backward/pair.h
OLD_FILES+=usr/include/c++/3.3/backward/queue.h
OLD_FILES+=usr/include/c++/3.3/backward/rope.h
OLD_FILES+=usr/include/c++/3.3/backward/set.h
OLD_FILES+=usr/include/c++/3.3/backward/slist.h
OLD_FILES+=usr/include/c++/3.3/backward/stack.h
OLD_FILES+=usr/include/c++/3.3/backward/stream.h
OLD_FILES+=usr/include/c++/3.3/backward/streambuf.h
OLD_FILES+=usr/include/c++/3.3/backward/strstream
OLD_FILES+=usr/include/c++/3.3/backward/strstream.h
OLD_FILES+=usr/include/c++/3.3/backward/tempbuf.h
OLD_FILES+=usr/include/c++/3.3/backward/tree.h
OLD_FILES+=usr/include/c++/3.3/backward/vector.h
OLD_DIRS+=usr/include/c++/3.3/backward
OLD_FILES+=usr/include/c++/3.3/bits/atomicity.h
OLD_FILES+=usr/include/c++/3.3/bits/basic_file.h
OLD_FILES+=usr/include/c++/3.3/bits/basic_ios.h
OLD_FILES+=usr/include/c++/3.3/bits/basic_ios.tcc
OLD_FILES+=usr/include/c++/3.3/bits/basic_string.h
OLD_FILES+=usr/include/c++/3.3/bits/basic_string.tcc
OLD_FILES+=usr/include/c++/3.3/bits/boost_concept_check.h
OLD_FILES+=usr/include/c++/3.3/bits/c++config.h
OLD_FILES+=usr/include/c++/3.3/bits/c++io.h
OLD_FILES+=usr/include/c++/3.3/bits/c++locale.h
OLD_FILES+=usr/include/c++/3.3/bits/c++locale_internal.h
OLD_FILES+=usr/include/c++/3.3/bits/char_traits.h
OLD_FILES+=usr/include/c++/3.3/bits/cmath.tcc
OLD_FILES+=usr/include/c++/3.3/bits/codecvt.h
OLD_FILES+=usr/include/c++/3.3/bits/codecvt_specializations.h
OLD_FILES+=usr/include/c++/3.3/bits/concept_check.h
OLD_FILES+=usr/include/c++/3.3/bits/cpp_type_traits.h
OLD_FILES+=usr/include/c++/3.3/bits/ctype_base.h
OLD_FILES+=usr/include/c++/3.3/bits/ctype_inline.h
OLD_FILES+=usr/include/c++/3.3/bits/ctype_noninline.h
OLD_FILES+=usr/include/c++/3.3/bits/deque.tcc
OLD_FILES+=usr/include/c++/3.3/bits/fpos.h
OLD_FILES+=usr/include/c++/3.3/bits/fstream.tcc
OLD_FILES+=usr/include/c++/3.3/bits/functexcept.h
OLD_FILES+=usr/include/c++/3.3/bits/generic_shadow.h
OLD_FILES+=usr/include/c++/3.3/bits/gslice.h
OLD_FILES+=usr/include/c++/3.3/bits/gslice_array.h
OLD_FILES+=usr/include/c++/3.3/bits/gthr-default.h
OLD_FILES+=usr/include/c++/3.3/bits/gthr-posix.h
OLD_FILES+=usr/include/c++/3.3/bits/gthr-single.h
OLD_FILES+=usr/include/c++/3.3/bits/gthr.h
OLD_FILES+=usr/include/c++/3.3/bits/indirect_array.h
OLD_FILES+=usr/include/c++/3.3/bits/ios_base.h
OLD_FILES+=usr/include/c++/3.3/bits/istream.tcc
OLD_FILES+=usr/include/c++/3.3/bits/list.tcc
OLD_FILES+=usr/include/c++/3.3/bits/locale_classes.h
OLD_FILES+=usr/include/c++/3.3/bits/locale_facets.h
OLD_FILES+=usr/include/c++/3.3/bits/locale_facets.tcc
OLD_FILES+=usr/include/c++/3.3/bits/localefwd.h
OLD_FILES+=usr/include/c++/3.3/bits/mask_array.h
OLD_FILES+=usr/include/c++/3.3/bits/messages_members.h
OLD_FILES+=usr/include/c++/3.3/bits/os_defines.h
OLD_FILES+=usr/include/c++/3.3/bits/ostream.tcc
OLD_FILES+=usr/include/c++/3.3/bits/pthread_allocimpl.h
OLD_FILES+=usr/include/c++/3.3/bits/slice.h
OLD_FILES+=usr/include/c++/3.3/bits/slice_array.h
OLD_FILES+=usr/include/c++/3.3/bits/sstream.tcc
OLD_FILES+=usr/include/c++/3.3/bits/stl_algo.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_algobase.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_alloc.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_bvector.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_construct.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_deque.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_function.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_heap.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_iterator.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_iterator_base_funcs.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_iterator_base_types.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_list.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_map.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_multimap.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_multiset.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_numeric.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_pair.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_pthread_alloc.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_queue.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_raw_storage_iter.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_relops.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_set.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_stack.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_tempbuf.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_threads.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_tree.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_uninitialized.h
OLD_FILES+=usr/include/c++/3.3/bits/stl_vector.h
OLD_FILES+=usr/include/c++/3.3/bits/stream_iterator.h
OLD_FILES+=usr/include/c++/3.3/bits/streambuf.tcc
OLD_FILES+=usr/include/c++/3.3/bits/streambuf_iterator.h
OLD_FILES+=usr/include/c++/3.3/bits/stringfwd.h
OLD_FILES+=usr/include/c++/3.3/bits/time_members.h
OLD_FILES+=usr/include/c++/3.3/bits/type_traits.h
OLD_FILES+=usr/include/c++/3.3/bits/valarray_array.h
OLD_FILES+=usr/include/c++/3.3/bits/valarray_array.tcc
OLD_FILES+=usr/include/c++/3.3/bits/valarray_meta.h
OLD_FILES+=usr/include/c++/3.3/bits/vector.tcc
OLD_DIRS+=usr/include/c++/3.3/bits
OLD_FILES+=usr/include/c++/3.3/bitset
OLD_FILES+=usr/include/c++/3.3/cassert
OLD_FILES+=usr/include/c++/3.3/cctype
OLD_FILES+=usr/include/c++/3.3/cerrno
OLD_FILES+=usr/include/c++/3.3/cfloat
OLD_FILES+=usr/include/c++/3.3/ciso646
OLD_FILES+=usr/include/c++/3.3/climits
OLD_FILES+=usr/include/c++/3.3/clocale
OLD_FILES+=usr/include/c++/3.3/cmath
OLD_FILES+=usr/include/c++/3.3/complex
OLD_FILES+=usr/include/c++/3.3/csetjmp
OLD_FILES+=usr/include/c++/3.3/csignal
OLD_FILES+=usr/include/c++/3.3/cstdarg
OLD_FILES+=usr/include/c++/3.3/cstddef
OLD_FILES+=usr/include/c++/3.3/cstdio
OLD_FILES+=usr/include/c++/3.3/cstdlib
OLD_FILES+=usr/include/c++/3.3/cstring
OLD_FILES+=usr/include/c++/3.3/ctime
OLD_FILES+=usr/include/c++/3.3/cwchar
OLD_FILES+=usr/include/c++/3.3/cwctype
OLD_FILES+=usr/include/c++/3.3/cxxabi.h
OLD_FILES+=usr/include/c++/3.3/deque
OLD_FILES+=usr/include/c++/3.3/exception
OLD_FILES+=usr/include/c++/3.3/exception_defines.h
OLD_FILES+=usr/include/c++/3.3/ext/algorithm
OLD_FILES+=usr/include/c++/3.3/ext/enc_filebuf.h
OLD_FILES+=usr/include/c++/3.3/ext/functional
OLD_FILES+=usr/include/c++/3.3/ext/hash_map
OLD_FILES+=usr/include/c++/3.3/ext/hash_set
OLD_FILES+=usr/include/c++/3.3/ext/iterator
OLD_FILES+=usr/include/c++/3.3/ext/memory
OLD_FILES+=usr/include/c++/3.3/ext/numeric
OLD_FILES+=usr/include/c++/3.3/ext/rb_tree
OLD_FILES+=usr/include/c++/3.3/ext/rope
OLD_FILES+=usr/include/c++/3.3/ext/ropeimpl.h
OLD_FILES+=usr/include/c++/3.3/ext/slist
OLD_FILES+=usr/include/c++/3.3/ext/stdio_filebuf.h
OLD_FILES+=usr/include/c++/3.3/ext/stl_hash_fun.h
OLD_FILES+=usr/include/c++/3.3/ext/stl_hashtable.h
OLD_FILES+=usr/include/c++/3.3/ext/stl_rope.h
OLD_DIRS+=usr/include/c++/3.3/ext
OLD_FILES+=usr/include/c++/3.3/fstream
OLD_FILES+=usr/include/c++/3.3/functional
OLD_FILES+=usr/include/c++/3.3/iomanip
OLD_FILES+=usr/include/c++/3.3/ios
OLD_FILES+=usr/include/c++/3.3/iosfwd
OLD_FILES+=usr/include/c++/3.3/iostream
OLD_FILES+=usr/include/c++/3.3/istream
OLD_FILES+=usr/include/c++/3.3/iterator
OLD_FILES+=usr/include/c++/3.3/limits
OLD_FILES+=usr/include/c++/3.3/list
OLD_FILES+=usr/include/c++/3.3/locale
OLD_FILES+=usr/include/c++/3.3/map
OLD_FILES+=usr/include/c++/3.3/memory
OLD_FILES+=usr/include/c++/3.3/new
OLD_FILES+=usr/include/c++/3.3/numeric
OLD_FILES+=usr/include/c++/3.3/ostream
OLD_FILES+=usr/include/c++/3.3/queue
OLD_FILES+=usr/include/c++/3.3/set
OLD_FILES+=usr/include/c++/3.3/sstream
OLD_FILES+=usr/include/c++/3.3/stack
OLD_FILES+=usr/include/c++/3.3/stdexcept
OLD_FILES+=usr/include/c++/3.3/streambuf
OLD_FILES+=usr/include/c++/3.3/string
OLD_FILES+=usr/include/c++/3.3/typeinfo
OLD_FILES+=usr/include/c++/3.3/utility
OLD_FILES+=usr/include/c++/3.3/valarray
OLD_FILES+=usr/include/c++/3.3/vector
# 20040713: fla(4) removed
OLD_FILES+=usr/share/man/man4/fla.4.gz
# 200407XX
OLD_FILES+=usr/sbin/kernbb
OLD_FILES+=usr/sbin/ntp-genkeys
OLD_FILES+=usr/sbin/ntptimeset
OLD_FILES+=usr/share/man/man8/kernbb.8.gz
OLD_FILES+=usr/share/man/man8/ntp-genkeys.8.gz
# 20040627: usbdevs.h and usbdevs_data.h removal
OLD_FILES+=usr/include/dev/usb/usbdevs.h
OLD_FILES+=usr/include/dev/usb/usbdevs_data.h
# 200406XX
OLD_FILES+=usr/bin/gasp
OLD_FILES+=usr/bin/gdbreplay
OLD_FILES+=usr/share/man/man1/gasp.1.gz
OLD_FILES+=sbin/mountd
OLD_FILES+=sbin/mount_fdesc
OLD_FILES+=sbin/mount_umap
OLD_FILES+=sbin/mount_union
OLD_FILES+=sbin/mount_msdos
OLD_FILES+=sbin/mount_null
OLD_FILES+=sbin/mount_kernfs
# 200405XX: arl
OLD_FILES+=usr/sbin/arlconfig
OLD_FILES+=usr/share/man/man8/arlconfig.8.gz
# 200403XX
OLD_FILES+=bin/raidctl
OLD_FILES+=sbin/raidctl
OLD_FILES+=usr/bin/sasc
OLD_FILES+=usr/sbin/sgsc
OLD_FILES+=usr/sbin/stlload
OLD_FILES+=usr/sbin/stlstats
OLD_FILES+=usr/share/man/man1/sasc.1.gz
OLD_FILES+=usr/share/man/man1/sgsc.1.gz
OLD_FILES+=usr/share/man/man4/i386/stl.4.gz
OLD_FILES+=usr/share/man/man8/raidctl.8.gz
# 20040229: clean_environment() was removed after 3 days
OLD_FILES+=usr/share/man/man3/clean_environment.3.gz
# 20040119: installed as `isdntel' in newer systems
OLD_FILES+=etc/isdn/isdntel.sh
# 200XYYZZ: /lib transition clitches
OLD_FILES+=lib/libalias.so
OLD_FILES+=lib/libatm.so
OLD_FILES+=lib/libbsdxml.so
OLD_FILES+=lib/libc.so
OLD_FILES+=lib/libcam.so
OLD_FILES+=lib/libcrypt.so
OLD_FILES+=lib/libcrypto.so
OLD_FILES+=lib/libdevstat.so
OLD_FILES+=lib/libedit.so
OLD_FILES+=lib/libgeom.so
OLD_FILES+=lib/libipsec.so
OLD_FILES+=lib/libipx.so
OLD_FILES+=lib/libkvm.so
OLD_FILES+=lib/libm.so
OLD_FILES+=lib/libmd.so
OLD_FILES+=lib/libncurses.so
OLD_FILES+=lib/libreadline.so
OLD_FILES+=lib/libsbuf.so
OLD_FILES+=lib/libufs.so
OLD_FILES+=lib/libz.so
# 200312XX
OLD_FILES+=bin/cxconfig
OLD_FILES+=sbin/cxconfig
OLD_FILES+=usr/share/man/man8/cxconfig.8.gz
# 20031016: MULTI_DRIVER_MODULE macro removed
OLD_FILES+=usr/share/man/man9/MULTI_DRIVER_MODULE.9.gz
# 200309XX
OLD_FILES+=usr/bin/symorder
OLD_FILES+=usr/share/man/man1/symorder.1.gz
# 200308XX
OLD_FILES+=usr/sbin/amldb
OLD_FILES+=usr/share/man/man8/amldb.8.gz
# 200307XX
OLD_FILES+=sbin/mount_nwfs
OLD_FILES+=sbin/mount_portalfs
OLD_FILES+=sbin/mount_smbfs
# 200306XX
OLD_FILES+=usr/sbin/dev_mkdb
OLD_FILES+=usr/share/man/man8/dev_mkdb.8.gz
# 200304XX
OLD_FILES+=usr/lib/libcipher.a
OLD_FILES+=usr/lib/libcipher.so
OLD_FILES+=usr/lib/libcipher_p.a
OLD_FILES+=usr/lib/libgmp.a
OLD_FILES+=usr/lib/libgmp.so
OLD_FILES+=usr/lib/libgmp_p.a
OLD_FILES+=usr/lib/libperl.a
OLD_FILES+=usr/lib/libperl.so
OLD_FILES+=usr/lib/libperl_p.a
OLD_FILES+=usr/lib/libposix1e.a
OLD_FILES+=usr/lib/libposix1e.so
OLD_FILES+=usr/lib/libposix1e_p.a
OLD_FILES+=usr/lib/libskey.a
OLD_FILES+=usr/lib/libskey.so
OLD_FILES+=usr/lib/libskey_p.a
OLD_FILES+=usr/libexec/tradcpp0
OLD_FILES+=usr/libexec/cpp0
# 200304XX: removal of xten
OLD_FILES+=usr/libexec/xtend
OLD_FILES+=usr/sbin/xten
OLD_FILES+=usr/share/man/man1/xten.1.gz
OLD_FILES+=usr/share/man/man8/xtend.8.gz
# 200303XX
OLD_FILES+=usr/lib/libacl.so
OLD_FILES+=usr/lib/libdescrypt.so
OLD_FILES+=usr/lib/libf2c.so
OLD_FILES+=usr/lib/libg++.so
OLD_FILES+=usr/lib/libkdb.so
OLD_FILES+=usr/lib/librsaINTL.so
OLD_FILES+=usr/lib/libscrypt.so
OLD_FILES+=usr/lib/libss.so
# 200302XX
OLD_FILES+=usr/lib/libacl.a
OLD_FILES+=usr/lib/libacl_p.a
OLD_FILES+=usr/lib/libkadm.a
OLD_FILES+=usr/lib/libkadm.so
OLD_FILES+=usr/lib/libkadm_p.a
OLD_FILES+=usr/lib/libkafs.a
OLD_FILES+=usr/lib/libkafs.so
OLD_FILES+=usr/lib/libkafs_p.a
OLD_FILES+=usr/lib/libkdb.a
OLD_FILES+=usr/lib/libkdb_p.a
OLD_FILES+=usr/lib/libkrb.a
OLD_FILES+=usr/lib/libkrb.so
OLD_FILES+=usr/lib/libkrb_p.a
OLD_FILES+=usr/share/man/man3/SSL_CIPHER_get_name.3.gz
OLD_FILES+=usr/share/man/man3/SSL_COMP_add_compression_method.3
OLD_FILES+=usr/share/man/man3/SSL_CTX_add_extra_chain_cert.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_add_session.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_ctrl.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_flush_sessions.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_free.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_get_verify_mode.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_load_verify_locations.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_new.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_sess_number.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_sess_set_cache_size.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_sess_set_get_cb.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_sessions.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_cert_store.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_cert_verify_callback.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_cipher_list.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_client_CA_list.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_client_cert_cb.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_default_passwd_cb.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_generate_session_id.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_info_callback.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_max_cert_list.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_mode.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_msg_callback.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_options.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_quiet_shutdown.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_session_cache_mode.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_session_id_context.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_ssl_version.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_timeout.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_tmp_dh_callback.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_tmp_rsa_callback.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_set_verify.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_use_certificate.3.gz
OLD_FILES+=usr/share/man/man3/SSL_SESSION_free.3.gz
OLD_FILES+=usr/share/man/man3/SSL_SESSION_get_ex_new_index.3.gz
OLD_FILES+=usr/share/man/man3/SSL_SESSION_get_time.3.gz
OLD_FILES+=usr/share/man/man3/SSL_accept.3.gz
OLD_FILES+=usr/share/man/man3/SSL_alert_type_string.3.gz
OLD_FILES+=usr/share/man/man3/SSL_clear.3.gz
OLD_FILES+=usr/share/man/man3/SSL_connect.3.gz
OLD_FILES+=usr/share/man/man3/SSL_do_handshake.3.gz
OLD_FILES+=usr/share/man/man3/SSL_free.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_SSL_CTX.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_ciphers.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_client_CA_list.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_current_cipher.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_default_timeout.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_error.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_ex_data_X509_STORE_CTX_idx.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_ex_new_index.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_fd.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_peer_cert_chain.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_peer_certificate.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_rbio.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_session.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_verify_result.3.gz
OLD_FILES+=usr/share/man/man3/SSL_get_version.3.gz
OLD_FILES+=usr/share/man/man3/SSL_library_init.3.gz
OLD_FILES+=usr/share/man/man3/SSL_load_client_CA_file.3.gz
OLD_FILES+=usr/share/man/man3/SSL_new.3.gz
OLD_FILES+=usr/share/man/man3/SSL_pending.3.gz
OLD_FILES+=usr/share/man/man3/SSL_read.3.gz
OLD_FILES+=usr/share/man/man3/SSL_rstate_string.3.gz
OLD_FILES+=usr/share/man/man3/SSL_session_reused.3.gz
OLD_FILES+=usr/share/man/man3/SSL_set_bio.3.gz
OLD_FILES+=usr/share/man/man3/SSL_set_connect_state.3.gz
OLD_FILES+=usr/share/man/man3/SSL_set_fd.3.gz
OLD_FILES+=usr/share/man/man3/SSL_set_session.3.gz
OLD_FILES+=usr/share/man/man3/SSL_set_shutdown.3.gz
OLD_FILES+=usr/share/man/man3/SSL_set_verify_result.3.gz
OLD_FILES+=usr/share/man/man3/SSL_shutdown.3.gz
OLD_FILES+=usr/share/man/man3/SSL_state_string.3.gz
OLD_FILES+=usr/share/man/man3/SSL_want.3.gz
OLD_FILES+=usr/share/man/man3/SSL_write.3.gz
OLD_FILES+=usr/share/man/man3/d2i_SSL_SESSION.3.gz
# 200301XX
OLD_FILES+=usr/share/man/man3/des_3cbc_encrypt.3.gz
OLD_FILES+=usr/share/man/man3/des_3ecb_encrypt.3.gz
OLD_FILES+=usr/share/man/man3/des_cbc_cksum.3.gz
OLD_FILES+=usr/share/man/man3/des_cbc_encrypt.3.gz
OLD_FILES+=usr/share/man/man3/des_cfb_encrypt.3.gz
OLD_FILES+=usr/share/man/man3/des_ecb_encrypt.3.gz
OLD_FILES+=usr/share/man/man3/des_enc_read.3.gz
OLD_FILES+=usr/share/man/man3/des_enc_write.3.gz
OLD_FILES+=usr/share/man/man3/des_is_weak_key.3.gz
OLD_FILES+=usr/share/man/man3/des_key_sched.3.gz
OLD_FILES+=usr/share/man/man3/des_ofb_encrypt.3.gz
OLD_FILES+=usr/share/man/man3/des_pcbc_encrypt.3.gz
OLD_FILES+=usr/share/man/man3/des_quad_cksum.3.gz
OLD_FILES+=usr/share/man/man3/des_random_key.3.gz
OLD_FILES+=usr/share/man/man3/des_read_2password.3.gz
OLD_FILES+=usr/share/man/man3/des_read_password.3.gz
OLD_FILES+=usr/share/man/man3/des_read_pw_string.3.gz
OLD_FILES+=usr/share/man/man3/des_set_key.3.gz
OLD_FILES+=usr/share/man/man3/des_set_odd_parity.3.gz
OLD_FILES+=usr/share/man/man3/des_string_to_2key.3.gz
OLD_FILES+=usr/share/man/man3/des_string_to_key.3.gz
# 200212XX
OLD_FILES+=usr/sbin/kenv
OLD_FILES+=usr/bin/kenv
OLD_FILES+=usr/sbin/elf2aout
# 200210XX
OLD_FILES+=usr/include/libusbhid.h
OLD_FILES+=usr/share/man/man3/All_FreeBSD.3.gz
OLD_FILES+=usr/share/man/man3/CheckRules.3.gz
OLD_FILES+=usr/share/man/man3/ChunkCanBeRoot.3.gz
OLD_FILES+=usr/share/man/man3/Clone_Disk.3.gz
OLD_FILES+=usr/share/man/man3/Collapse_Chunk.3.gz
OLD_FILES+=usr/share/man/man3/Collapse_Disk.3.gz
OLD_FILES+=usr/share/man/man3/Create_Chunk.3.gz
OLD_FILES+=usr/share/man/man3/Create_Chunk_DWIM.3.gz
OLD_FILES+=usr/share/man/man3/Cyl_Aligned.3.gz
OLD_FILES+=usr/share/man/man3/Debug_Disk.3.gz
OLD_FILES+=usr/share/man/man3/Delete_Chunk.3.gz
OLD_FILES+=usr/share/man/man3/Disk_Names.3.gz
OLD_FILES+=usr/share/man/man3/Free_Disk.3.gz
OLD_FILES+=usr/share/man/man3/MakeDev.3.gz
OLD_FILES+=usr/share/man/man3/MakeDevDisk.3.gz
OLD_FILES+=usr/share/man/man3/Next_Cyl_Aligned.3.gz
OLD_FILES+=usr/share/man/man3/Next_Track_Aligned.3.gz
OLD_FILES+=usr/share/man/man3/Open_Disk.3.gz
OLD_FILES+=usr/share/man/man3/Prev_Cyl_Aligned.3.gz
OLD_FILES+=usr/share/man/man3/Prev_Track_Aligned.3.gz
OLD_FILES+=usr/share/man/man3/Set_Bios_Geom.3.gz
OLD_FILES+=usr/share/man/man3/Set_Boot_Blocks.3.gz
OLD_FILES+=usr/share/man/man3/Set_Boot_Mgr.3.gz
OLD_FILES+=usr/share/man/man3/ShowChunkFlags.3.gz
OLD_FILES+=usr/share/man/man3/Track_Aligned.3.gz
OLD_FILES+=usr/share/man/man3/Write_Disk.3.gz
OLD_FILES+=usr/share/man/man3/slice_type_name.3.gz
# 200210XX: most games moved to ports
OLD_FILES+=usr/share/man/man6/adventure.6.gz
OLD_FILES+=usr/share/man/man6/arithmetic.6.gz
OLD_FILES+=usr/share/man/man6/atc.6.gz
OLD_FILES+=usr/share/man/man6/backgammon.6.gz
OLD_FILES+=usr/share/man/man6/battlestar.6.gz
OLD_FILES+=usr/share/man/man6/bs.6.gz
OLD_FILES+=usr/share/man/man6/canfield.6.gz
OLD_FILES+=usr/share/man/man6/cfscores.6.gz
OLD_FILES+=usr/share/man/man6/cribbage.6.gz
OLD_FILES+=usr/share/man/man6/fish.6.gz
OLD_FILES+=usr/share/man/man6/hack.6.gz
OLD_FILES+=usr/share/man/man6/hangman.6.gz
OLD_FILES+=usr/share/man/man6/larn.6.gz
OLD_FILES+=usr/share/man/man6/mille.6.gz
OLD_FILES+=usr/share/man/man6/phantasia.6.gz
OLD_FILES+=usr/share/man/man6/piano.6.gz
OLD_FILES+=usr/share/man/man6/pig.6.gz
OLD_FILES+=usr/share/man/man6/quiz.6.gz
OLD_FILES+=usr/share/man/man6/rain.6.gz
OLD_FILES+=usr/share/man/man6/robots.6.gz
OLD_FILES+=usr/share/man/man6/rogue.6.gz
OLD_FILES+=usr/share/man/man6/sail.6.gz
OLD_FILES+=usr/share/man/man6/snake.6.gz
OLD_FILES+=usr/share/man/man6/snscore.6.gz
OLD_FILES+=usr/share/man/man6/trek.6.gz
OLD_FILES+=usr/share/man/man6/wargames.6.gz
OLD_FILES+=usr/share/man/man6/worm.6.gz
OLD_FILES+=usr/share/man/man6/worms.6.gz
OLD_FILES+=usr/share/man/man6/wump.6.gz
# 200207XX
OLD_FILES+=usr/share/man/man1aout/ar.1aout.gz
OLD_FILES+=usr/share/man/man1aout/as.1aout.gz
OLD_FILES+=usr/share/man/man1aout/ld.1aout.gz
OLD_FILES+=usr/share/man/man1aout/nm.1aout.gz
OLD_FILES+=usr/share/man/man1aout/ranlib.1aout.gz
OLD_FILES+=usr/share/man/man1aout/size.1aout.gz
OLD_FILES+=usr/share/man/man1aout/strings.1aout.gz
OLD_FILES+=usr/share/man/man1aout/strip.1aout.gz
OLD_FILES+=bin/mountd
OLD_FILES+=bin/nfsd
# 20020707 sbin/nfsd -> usr.sbin/nfsd
OLD_FILES+=sbin/nfsd
# 200206XX
OLD_FILES+=usr/lib/libpam_ssh.a
OLD_FILES+=usr/lib/libpam_ssh_p.a
OLD_FILES+=usr/bin/help
OLD_FILES+=usr/bin/sccs
.if ${TARGET_ARCH} != "amd64" && ${TARGET} != "arm" && ${TARGET_ARCH} != "i386" && ${TARGET} != "powerpc"
OLD_FILES+=usr/bin/gdbserver
.endif
OLD_FILES+=usr/bin/ssh-keysign
OLD_FILES+=usr/sbin/gifconfig
OLD_FILES+=usr/sbin/prefix
# 200205XX
OLD_FILES+=usr/bin/doscmd
# 200204XX
OLD_FILES+=usr/bin/a2p
OLD_FILES+=usr/bin/ptx
OLD_FILES+=usr/bin/pod2text
OLD_FILES+=usr/bin/pod2man
OLD_FILES+=usr/bin/pod2latex
OLD_FILES+=usr/bin/pod2html
OLD_FILES+=usr/bin/h2ph
OLD_FILES+=usr/bin/dprofpp
OLD_FILES+=usr/bin/c2ph
OLD_FILES+=usr/bin/h2xs
OLD_FILES+=usr/bin/pl2pm
OLD_FILES+=usr/bin/splain
OLD_FILES+=usr/bin/s2p
OLD_FILES+=usr/bin/find2perl
OLD_FILES+=usr/sbin/pkg_update
OLD_FILES+=usr/sbin/scriptdump
# 20020409 GC kget(1), userconfig is long dead.
OLD_FILES+=sbin/kget
OLD_FILES+=usr/share/man/man8/kget.8.gz
# 200203XX
OLD_FILES+=usr/lib/libss.a
OLD_FILES+=usr/lib/libss_p.a
OLD_FILES+=usr/lib/libtelnet.a
OLD_FILES+=usr/lib/libtelnet_p.a
OLD_FILES+=usr/sbin/diskpart
# 200202XX
OLD_FILES+=usr/bin/gprof4
# 200201XX
OLD_FILES+=usr/sbin/linux
# 2001XXXX
OLD_FILES+=usr/bin/joy
OLD_FILES+=usr/sbin/ibcs2
OLD_FILES+=usr/sbin/svr4
OLD_FILES+=usr/bin/chflags
OLD_FILES+=usr/sbin/uuconv
OLD_FILES+=usr/sbin/uuchk
OLD_FILES+=usr/sbin/portmap
OLD_FILES+=usr/sbin/pmap_set
OLD_FILES+=usr/sbin/pmap_dump
OLD_FILES+=usr/sbin/mcon
OLD_FILES+=usr/sbin/stlstty
OLD_FILES+=usr/sbin/ispppcontrol
OLD_FILES+=usr/sbin/rndcontrol
# 20011001: UUCP migration to ports
OLD_FILES+=usr/bin/uucp
OLD_FILES+=usr/bin/uulog
OLD_FILES+=usr/bin/uuname
OLD_FILES+=usr/bin/uupick
OLD_FILES+=usr/bin/uusched
OLD_FILES+=usr/bin/uustat
OLD_FILES+=usr/bin/uuto
OLD_FILES+=usr/bin/uux
OLD_FILES+=usr/libexec/uucp/uucico
OLD_FILES+=usr/libexec/uucp/uuxqt
OLD_FILES+=usr/libexec/uucpd
OLD_FILES+=usr/share/man/man1/uuconv.1.gz
OLD_FILES+=usr/share/man/man1/uucp.1.gz
OLD_FILES+=usr/share/man/man1/uulog.1.gz
OLD_FILES+=usr/share/man/man1/uuname.1.gz
OLD_FILES+=usr/share/man/man1/uupick.1.gz
OLD_FILES+=usr/share/man/man1/uustat.1.gz
OLD_FILES+=usr/share/man/man1/uuto.1.gz
OLD_FILES+=usr/share/man/man1/uux.1.gz
OLD_FILES+=usr/share/man/man8/uuchk.8.gz
OLD_FILES+=usr/share/man/man8/uucico.8.gz
OLD_FILES+=usr/share/man/man8/uucpd.8.gz
OLD_FILES+=usr/share/man/man8/uusched.8.gz
OLD_FILES+=usr/share/man/man8/uuxqt.8.gz
# 20010523 mount_portal -> mount_portalfs
OLD_FILES+=sbin/mount_portal
OLD_FILES+=usr/share/man/man8/mount_portal.8.gz
# 200104XX
OLD_FILES+=usr/lib/libdescrypt.a
OLD_FILES+=usr/lib/libscrypt.a
OLD_FILES+=usr/lib/libscrypt_p.a
OLD_FILES+=usr/sbin/pim6stat
OLD_FILES+=usr/sbin/pim6sd
OLD_FILES+=usr/sbin/pim6dd
# 20010217
OLD_FILES+=usr/share/doc/bind/misc/dns-setup
# 20001200
OLD_FILES+=usr/lib/libgcc_r_pic.a
# 200009XX
OLD_FILES+=usr/lib/libRSAglue.a
OLD_FILES+=usr/lib/libRSAglue.so
OLD_FILES+=usr/lib/librsaINTL.a
OLD_FILES+=usr/lib/librsaUSA.a
OLD_FILES+=usr/lib/librsaUSA.so
# 200002XX ?
OLD_FILES+=usr/lib/libf2c.a
OLD_FILES+=usr/lib/libf2c_p.a
OLD_FILES+=usr/lib/libg++.a
OLD_FILES+=usr/lib/libg++_p.a
# 20001006
OLD_FILES+=usr/bin/miniperl
# 20000810
OLD_FILES+=usr/bin/sperl
# 200001XX
OLD_FILES+=usr/sbin/apmconf
## unsorted
# do we still support aout builds?
#OLD_FILES+=usr/lib/aout/c++rt0.o
#OLD_FILES+=usr/lib/aout/crt0.o
#OLD_FILES+=usr/lib/aout/gcrt0.o
#OLD_FILES+=usr/lib/aout/scrt0.o
#OLD_FILES+=usr/lib/aout/sgcrt0.o
OLD_FILES+=usr/lib/pam_ftp.so
OLD_FILES+=usr/share/man/man1/CA.pl.1.gz
OLD_FILES+=usr/share/man/man1/asn1parse.1.gz
OLD_FILES+=usr/share/man/man1/ca.1.gz
OLD_FILES+=usr/share/man/man1/ciphers.1.gz
OLD_FILES+=usr/share/man/man1/config.1.gz
OLD_FILES+=usr/share/man/man1/crl.1.gz
OLD_FILES+=usr/share/man/man1/crl2pkcs7.1.gz
OLD_FILES+=usr/share/man/man1/dgst.1.gz
OLD_FILES+=usr/share/man/man1/dhparam.1.gz
OLD_FILES+=usr/share/man/man1/doscmd.1.gz
OLD_FILES+=usr/share/man/man1/dsa.1.gz
OLD_FILES+=usr/share/man/man1/dsaparam.1.gz
OLD_FILES+=usr/share/man/man1/enc.1.gz
OLD_FILES+=usr/share/man/man1/gendsa.1.gz
OLD_FILES+=usr/share/man/man1/genrsa.1.gz
OLD_FILES+=usr/share/man/man1/getNAME.1.gz
OLD_FILES+=usr/share/man/man1/nseq.1.gz
OLD_FILES+=usr/share/man/man1/ocsp.1.gz
OLD_FILES+=usr/share/man/man1/openssl.1.gz
OLD_FILES+=usr/share/man/man1/pkcs12.1.gz
OLD_FILES+=usr/share/man/man1/pkcs7.1.gz
OLD_FILES+=usr/share/man/man1/pkcs8.1.gz
OLD_FILES+=usr/share/man/man1/rand.1.gz
OLD_FILES+=usr/share/man/man1/req.1.gz
OLD_FILES+=usr/share/man/man1/rsa.1.gz
OLD_FILES+=usr/share/man/man1/rsautl.1.gz
OLD_FILES+=usr/share/man/man1/s_client.1.gz
OLD_FILES+=usr/share/man/man1/s_server.1.gz
OLD_FILES+=usr/share/man/man1/sess_id.1.gz
OLD_FILES+=usr/share/man/man1/smime.1.gz
OLD_FILES+=usr/share/man/man1/speed.1.gz
OLD_FILES+=usr/share/man/man1/spkac.1.gz
OLD_FILES+=usr/share/man/man1/verify.1.gz
OLD_FILES+=usr/share/man/man1/version.1.gz
OLD_FILES+=usr/share/man/man1/x509.1.gz
OLD_FILES+=usr/share/man/man3/SSL_COMP_add_compression_method.3.gz
OLD_FILES+=usr/share/man/man3/SSL_CTX_get_ex_new_index.3.gz
OLD_FILES+=usr/share/man/man3/archive_entry_dup.3.gz
OLD_FILES+=usr/share/man/man3/archive_entry_set_tartype.3.gz
OLD_FILES+=usr/share/man/man3/archive_entry_tartype.3.gz
OLD_FILES+=usr/share/man/man3/archive_read_data_into_file.3.gz
OLD_FILES+=usr/share/man/man3/archive_read_open_tar.3.gz
OLD_FILES+=usr/share/man/man3/archive_read_support_format_gnutar.3.gz
OLD_FILES+=usr/share/man/man3/cipher.3.gz
OLD_FILES+=usr/share/man/man3/des_cipher.3.gz
OLD_FILES+=usr/share/man/man3/des_setkey.3.gz
OLD_FILES+=usr/share/man/man3/encrypt.3.gz
OLD_FILES+=usr/share/man/man3/endvfsent.3.gz
OLD_FILES+=usr/share/man/man3/getvfsbytype.3.gz
OLD_FILES+=usr/share/man/man3/getvfsent.3.gz
OLD_FILES+=usr/share/man/man3/isnanf.3.gz
OLD_FILES+=usr/share/man/man3/libautofs.3.gz
OLD_FILES+=usr/share/man/man3/pthread_attr_setsstack.3.gz
OLD_FILES+=usr/share/man/man3/pthread_getcancelstate.3.gz
OLD_FILES+=usr/share/man/man3/set_assertion_failure_callback.3.gz
OLD_FILES+=usr/share/man/man3/setkey.3.gz
OLD_FILES+=usr/share/man/man3/setvfsent.3.gz
OLD_FILES+=usr/share/man/man3/ssl.3.gz
OLD_FILES+=usr/share/man/man3/vfsisloadable.3.gz
OLD_FILES+=usr/share/man/man3/vfsload.3.gz
OLD_FILES+=usr/share/man/man4/als4000.4.gz
OLD_FILES+=usr/share/man/man4/csa.4.gz
OLD_FILES+=usr/share/man/man4/emu10k1.4.gz
OLD_FILES+=usr/share/man/man4/euc.4.gz
OLD_FILES+=usr/share/man/man4/gusc.4.gz
OLD_FILES+=usr/share/man/man4/if_fwp.4.gz
OLD_FILES+=usr/share/man/man4/lomac.4.gz
OLD_FILES+=usr/share/man/man4/maestro3.4.gz
OLD_FILES+=usr/share/man/man4/raid.4.gz
OLD_FILES+=usr/share/man/man4/sbc.4.gz
OLD_FILES+=usr/share/man/man4/sd.4.gz
OLD_FILES+=usr/share/man/man4/snc.4.gz
OLD_FILES+=usr/share/man/man4/st.4.gz
OLD_FILES+=usr/share/man/man4/uaudio.4.gz
OLD_FILES+=usr/share/man/man4/utf2.4.gz
OLD_FILES+=usr/share/man/man4/vinumdebug.4.gz
OLD_FILES+=usr/share/man/man5/disklabel.5.gz
OLD_FILES+=usr/share/man/man5/dm.conf.5.gz
OLD_FILES+=usr/share/man/man5/ranlib.5.gz
OLD_FILES+=usr/share/man/man5/utf2.5.gz
OLD_FILES+=usr/share/man/man7/groff_mwww.7.gz
OLD_FILES+=usr/share/man/man7/mmroff.7.gz
OLD_FILES+=usr/share/man/man7/mwww.7.gz
OLD_FILES+=usr/share/man/man8/apm.8.gz
OLD_FILES+=usr/share/man/man8/apmconf.8.gz
OLD_FILES+=usr/share/man/man8/apmd.8.gz
OLD_FILES+=usr/share/man/man8/dm.8.gz
OLD_FILES+=usr/share/man/man8/pam_ftp.8.gz
OLD_FILES+=usr/share/man/man8/pam_wheel.8.gz
OLD_FILES+=usr/share/man/man8/sconfig.8.gz
OLD_FILES+=usr/share/man/man8/ssl.8.gz
OLD_FILES+=usr/share/man/man8/wlconfig.8.gz
OLD_FILES+=usr/share/man/man9/CURSIG.9.gz
OLD_FILES+=usr/share/man/man9/VFS_INIT.9.gz
OLD_FILES+=usr/share/man/man9/at_exit.9.gz
OLD_FILES+=usr/share/man/man9/at_fork.9.gz
OLD_FILES+=usr/share/man/man9/cdevsw_add.9.gz
OLD_FILES+=usr/share/man/man9/cdevsw_remove.9.gz
OLD_FILES+=usr/share/man/man9/cv_waitq_empty.9.gz
OLD_FILES+=usr/share/man/man9/cv_waitq_remove.9.gz
OLD_FILES+=usr/share/man/man9/endtsleep.9.gz
OLD_FILES+=usr/share/man/man9/jumbo.9.gz
OLD_FILES+=usr/share/man/man9/jumbo_freem.9.gz
OLD_FILES+=usr/share/man/man9/jumbo_pg_alloc.9.gz
OLD_FILES+=usr/share/man/man9/jumbo_pg_free.9.gz
OLD_FILES+=usr/share/man/man9/jumbo_pg_steal.9.gz
OLD_FILES+=usr/share/man/man9/jumbo_phys_to_kva.9.gz
OLD_FILES+=usr/share/man/man9/jumbo_vm_init.9.gz
OLD_FILES+=usr/share/man/man9/mac_biba.9.gz
OLD_FILES+=usr/share/man/man9/mac_bsdextended.9.gz
OLD_FILES+=usr/share/man/man9/mono_time.9.gz
OLD_FILES+=usr/share/man/man9/p1003_1b.9.gz
OLD_FILES+=usr/share/man/man9/pmap_prefault.9.gz
OLD_FILES+=usr/share/man/man9/posix4.9.gz
OLD_FILES+=usr/share/man/man9/resource_query_name.9.gz
OLD_FILES+=usr/share/man/man9/resource_query_string.9.gz
OLD_FILES+=usr/share/man/man9/resource_query_unit.9.gz
OLD_FILES+=usr/share/man/man9/rm_at_exit.9.gz
OLD_FILES+=usr/share/man/man9/rm_at_fork.9.gz
OLD_FILES+=usr/share/man/man9/runtime.9.gz
OLD_FILES+=usr/share/man/man9/sleepinit.9.gz
OLD_FILES+=usr/share/man/man9/unsleep.9.gz
OLD_FILES+=usr/share/games/atc/Game_List
OLD_FILES+=usr/share/games/atc/Killer
OLD_FILES+=usr/share/games/atc/crossover
OLD_FILES+=usr/share/games/atc/default
OLD_FILES+=usr/share/games/atc/easy
OLD_FILES+=usr/share/games/atc/game_2
OLD_FILES+=usr/share/games/larn/larnmaze
OLD_FILES+=usr/share/games/larn/larnopts
OLD_FILES+=usr/share/games/larn/larn.help
OLD_FILES+=usr/share/games/quiz.db/africa
OLD_FILES+=usr/share/games/quiz.db/america
OLD_FILES+=usr/share/games/quiz.db/areas
OLD_FILES+=usr/share/games/quiz.db/arith
OLD_FILES+=usr/share/games/quiz.db/asia
OLD_FILES+=usr/share/games/quiz.db/babies
OLD_FILES+=usr/share/games/quiz.db/bard
OLD_FILES+=usr/share/games/quiz.db/chinese
OLD_FILES+=usr/share/games/quiz.db/collectives
OLD_FILES+=usr/share/games/quiz.db/ed
OLD_FILES+=usr/share/games/quiz.db/elements
OLD_FILES+=usr/share/games/quiz.db/europe
OLD_FILES+=usr/share/games/quiz.db/flowers
OLD_FILES+=usr/share/games/quiz.db/greek
OLD_FILES+=usr/share/games/quiz.db/inca
OLD_FILES+=usr/share/games/quiz.db/index
OLD_FILES+=usr/share/games/quiz.db/latin
OLD_FILES+=usr/share/games/quiz.db/locomotive
OLD_FILES+=usr/share/games/quiz.db/midearth
OLD_FILES+=usr/share/games/quiz.db/morse
OLD_FILES+=usr/share/games/quiz.db/murders
OLD_FILES+=usr/share/games/quiz.db/poetry
OLD_FILES+=usr/share/games/quiz.db/posneg
OLD_FILES+=usr/share/games/quiz.db/pres
OLD_FILES+=usr/share/games/quiz.db/province
OLD_FILES+=usr/share/games/quiz.db/seq-easy
OLD_FILES+=usr/share/games/quiz.db/seq-hard
OLD_FILES+=usr/share/games/quiz.db/sexes
OLD_FILES+=usr/share/games/quiz.db/sov
OLD_FILES+=usr/share/games/quiz.db/spell
OLD_FILES+=usr/share/games/quiz.db/state
OLD_FILES+=usr/share/games/quiz.db/trek
OLD_FILES+=usr/share/games/quiz.db/ucc
OLD_FILES+=usr/share/games/cribbage.instr
OLD_FILES+=usr/share/games/fish.instr
OLD_FILES+=usr/share/games/wump.info
OLD_FILES+=usr/games/hide/adventure
OLD_FILES+=usr/games/hide/arithmetic
OLD_FILES+=usr/games/hide/atc
OLD_FILES+=usr/games/hide/backgammon
OLD_FILES+=usr/games/hide/teachgammon
OLD_FILES+=usr/games/hide/battlestar
OLD_FILES+=usr/games/hide/bs
OLD_FILES+=usr/games/hide/canfield
OLD_FILES+=usr/games/hide/cribbage
OLD_FILES+=usr/games/hide/fish
OLD_FILES+=usr/games/hide/hack
OLD_FILES+=usr/games/hide/hangman
OLD_FILES+=usr/games/hide/larn
OLD_FILES+=usr/games/hide/mille
OLD_FILES+=usr/games/hide/phantasia
OLD_FILES+=usr/games/hide/quiz
OLD_FILES+=usr/games/hide/robots
OLD_FILES+=usr/games/hide/rogue
OLD_FILES+=usr/games/hide/sail
OLD_FILES+=usr/games/hide/snake
OLD_FILES+=usr/games/hide/trek
OLD_FILES+=usr/games/hide/worm
OLD_FILES+=usr/games/hide/wump
OLD_FILES+=usr/games/adventure
OLD_FILES+=usr/games/arithmetic
OLD_FILES+=usr/games/atc
OLD_FILES+=usr/games/backgammon
OLD_FILES+=usr/games/teachgammon
OLD_FILES+=usr/games/battlestar
OLD_FILES+=usr/games/bs
OLD_FILES+=usr/games/canfield
OLD_FILES+=usr/games/cfscores
OLD_FILES+=usr/games/cribbage
OLD_FILES+=usr/games/dm
OLD_FILES+=usr/games/fish
OLD_FILES+=usr/games/hack
OLD_FILES+=usr/games/hangman
OLD_FILES+=usr/games/larn
OLD_FILES+=usr/games/mille
OLD_FILES+=usr/games/phantasia
OLD_FILES+=usr/games/piano
OLD_FILES+=usr/games/pig
OLD_FILES+=usr/games/quiz
OLD_FILES+=usr/games/rain
OLD_FILES+=usr/games/robots
OLD_FILES+=usr/games/rogue
OLD_FILES+=usr/games/sail
OLD_FILES+=usr/games/snake
OLD_FILES+=usr/games/snscore
OLD_FILES+=usr/games/trek
OLD_FILES+=usr/games/wargames
OLD_FILES+=usr/games/worm
OLD_FILES+=usr/games/worms
OLD_FILES+=usr/games/wump
OLD_FILES+=sbin/mount_reiserfs
OLD_FILES+=usr/include/cam/cam_extend.h
OLD_FILES+=usr/include/dev/wi/wi_hostap.h
OLD_FILES+=usr/include/disktab.h
OLD_FILES+=usr/include/g++/FlexLexer.h
OLD_FILES+=usr/include/g++/PlotFile.h
OLD_FILES+=usr/include/g++/SFile.h
OLD_FILES+=usr/include/g++/_G_config.h
OLD_FILES+=usr/include/g++/algo.h
OLD_FILES+=usr/include/g++/algobase.h
OLD_FILES+=usr/include/g++/algorithm
OLD_FILES+=usr/include/g++/alloc.h
OLD_FILES+=usr/include/g++/bitset
OLD_FILES+=usr/include/g++/builtinbuf.h
OLD_FILES+=usr/include/g++/bvector.h
OLD_FILES+=usr/include/g++/cassert
OLD_FILES+=usr/include/g++/cctype
OLD_FILES+=usr/include/g++/cerrno
OLD_FILES+=usr/include/g++/cfloat
OLD_FILES+=usr/include/g++/ciso646
OLD_FILES+=usr/include/g++/climits
OLD_FILES+=usr/include/g++/clocale
OLD_FILES+=usr/include/g++/cmath
OLD_FILES+=usr/include/g++/complex
OLD_FILES+=usr/include/g++/complex.h
OLD_FILES+=usr/include/g++/csetjmp
OLD_FILES+=usr/include/g++/csignal
OLD_FILES+=usr/include/g++/cstdarg
OLD_FILES+=usr/include/g++/cstddef
OLD_FILES+=usr/include/g++/cstdio
OLD_FILES+=usr/include/g++/cstdlib
OLD_FILES+=usr/include/g++/cstring
OLD_FILES+=usr/include/g++/ctime
OLD_FILES+=usr/include/g++/cwchar
OLD_FILES+=usr/include/g++/cwctype
OLD_FILES+=usr/include/g++/defalloc.h
OLD_FILES+=usr/include/g++/deque
OLD_FILES+=usr/include/g++/deque.h
OLD_FILES+=usr/include/g++/editbuf.h
OLD_FILES+=usr/include/g++/exception
OLD_FILES+=usr/include/g++/floatio.h
OLD_FILES+=usr/include/g++/fstream
OLD_FILES+=usr/include/g++/fstream.h
OLD_FILES+=usr/include/g++/function.h
OLD_FILES+=usr/include/g++/functional
OLD_FILES+=usr/include/g++/hash_map
OLD_FILES+=usr/include/g++/hash_map.h
OLD_FILES+=usr/include/g++/hash_set
OLD_FILES+=usr/include/g++/hash_set.h
OLD_FILES+=usr/include/g++/hashtable.h
OLD_FILES+=usr/include/g++/heap.h
OLD_FILES+=usr/include/g++/indstream.h
OLD_FILES+=usr/include/g++/iolibio.h
OLD_FILES+=usr/include/g++/iomanip
OLD_FILES+=usr/include/g++/iomanip.h
OLD_FILES+=usr/include/g++/iosfwd
OLD_FILES+=usr/include/g++/iostdio.h
OLD_FILES+=usr/include/g++/iostream
OLD_FILES+=usr/include/g++/iostream.h
OLD_FILES+=usr/include/g++/iostreamP.h
OLD_FILES+=usr/include/g++/istream.h
OLD_FILES+=usr/include/g++/iterator
OLD_FILES+=usr/include/g++/iterator.h
OLD_FILES+=usr/include/g++/libio.h
OLD_FILES+=usr/include/g++/libioP.h
OLD_FILES+=usr/include/g++/list
OLD_FILES+=usr/include/g++/list.h
OLD_FILES+=usr/include/g++/map
OLD_FILES+=usr/include/g++/map.h
OLD_FILES+=usr/include/g++/memory
OLD_FILES+=usr/include/g++/multimap.h
OLD_FILES+=usr/include/g++/multiset.h
OLD_FILES+=usr/include/g++/new
OLD_FILES+=usr/include/g++/new.h
OLD_FILES+=usr/include/g++/numeric
OLD_FILES+=usr/include/g++/ostream.h
OLD_FILES+=usr/include/g++/pair.h
OLD_FILES+=usr/include/g++/parsestream.h
OLD_FILES+=usr/include/g++/pfstream.h
OLD_FILES+=usr/include/g++/procbuf.h
OLD_FILES+=usr/include/g++/pthread_alloc
OLD_FILES+=usr/include/g++/pthread_alloc.h
OLD_FILES+=usr/include/g++/queue
OLD_FILES+=usr/include/g++/rope
OLD_FILES+=usr/include/g++/rope.h
OLD_FILES+=usr/include/g++/ropeimpl.h
OLD_FILES+=usr/include/g++/set
OLD_FILES+=usr/include/g++/set.h
OLD_FILES+=usr/include/g++/slist
OLD_FILES+=usr/include/g++/slist.h
OLD_FILES+=usr/include/g++/sstream
OLD_FILES+=usr/include/g++/stack
OLD_FILES+=usr/include/g++/stack.h
OLD_FILES+=usr/include/g++/std/bastring.cc
OLD_FILES+=usr/include/g++/std/bastring.h
OLD_FILES+=usr/include/g++/std/complext.cc
OLD_FILES+=usr/include/g++/std/complext.h
OLD_FILES+=usr/include/g++/std/dcomplex.h
OLD_FILES+=usr/include/g++/std/fcomplex.h
OLD_FILES+=usr/include/g++/std/gslice.h
OLD_FILES+=usr/include/g++/std/gslice_array.h
OLD_FILES+=usr/include/g++/std/indirect_array.h
OLD_FILES+=usr/include/g++/std/ldcomplex.h
OLD_FILES+=usr/include/g++/std/mask_array.h
OLD_FILES+=usr/include/g++/std/slice.h
OLD_FILES+=usr/include/g++/std/slice_array.h
OLD_FILES+=usr/include/g++/std/std_valarray.h
OLD_FILES+=usr/include/g++/std/straits.h
OLD_FILES+=usr/include/g++/std/valarray_array.h
OLD_FILES+=usr/include/g++/std/valarray_array.tcc
OLD_FILES+=usr/include/g++/std/valarray_meta.h
OLD_FILES+=usr/include/g++/stdexcept
OLD_FILES+=usr/include/g++/stdiostream.h
OLD_FILES+=usr/include/g++/stl.h
OLD_FILES+=usr/include/g++/stl_algo.h
OLD_FILES+=usr/include/g++/stl_algobase.h
OLD_FILES+=usr/include/g++/stl_alloc.h
OLD_FILES+=usr/include/g++/stl_bvector.h
OLD_FILES+=usr/include/g++/stl_config.h
OLD_FILES+=usr/include/g++/stl_construct.h
OLD_FILES+=usr/include/g++/stl_deque.h
OLD_FILES+=usr/include/g++/stl_function.h
OLD_FILES+=usr/include/g++/stl_hash_fun.h
OLD_FILES+=usr/include/g++/stl_hash_map.h
OLD_FILES+=usr/include/g++/stl_hash_set.h
OLD_FILES+=usr/include/g++/stl_hashtable.h
OLD_FILES+=usr/include/g++/stl_heap.h
OLD_FILES+=usr/include/g++/stl_iterator.h
OLD_FILES+=usr/include/g++/stl_list.h
OLD_FILES+=usr/include/g++/stl_map.h
OLD_FILES+=usr/include/g++/stl_multimap.h
OLD_FILES+=usr/include/g++/stl_multiset.h
OLD_FILES+=usr/include/g++/stl_numeric.h
OLD_FILES+=usr/include/g++/stl_pair.h
OLD_FILES+=usr/include/g++/stl_queue.h
OLD_FILES+=usr/include/g++/stl_raw_storage_iter.h
OLD_FILES+=usr/include/g++/stl_relops.h
OLD_FILES+=usr/include/g++/stl_rope.h
OLD_FILES+=usr/include/g++/stl_set.h
OLD_FILES+=usr/include/g++/stl_slist.h
OLD_FILES+=usr/include/g++/stl_stack.h
OLD_FILES+=usr/include/g++/stl_tempbuf.h
OLD_FILES+=usr/include/g++/stl_tree.h
OLD_FILES+=usr/include/g++/stl_uninitialized.h
OLD_FILES+=usr/include/g++/stl_vector.h
OLD_FILES+=usr/include/g++/stream.h
OLD_FILES+=usr/include/g++/streambuf.h
OLD_FILES+=usr/include/g++/strfile.h
OLD_FILES+=usr/include/g++/string
OLD_FILES+=usr/include/g++/strstream
OLD_FILES+=usr/include/g++/strstream.h
OLD_FILES+=usr/include/g++/tempbuf.h
OLD_FILES+=usr/include/g++/tree.h
OLD_FILES+=usr/include/g++/type_traits.h
OLD_FILES+=usr/include/g++/typeinfo
OLD_FILES+=usr/include/g++/utility
OLD_FILES+=usr/include/g++/valarray
OLD_FILES+=usr/include/g++/vector
OLD_FILES+=usr/include/g++/vector.h
OLD_FILES+=usr/include/gmp.h
OLD_FILES+=usr/include/isc/assertions.h
OLD_FILES+=usr/include/isc/ctl.h
OLD_FILES+=usr/include/isc/dst.h
OLD_FILES+=usr/include/isc/eventlib.h
OLD_FILES+=usr/include/isc/heap.h
OLD_FILES+=usr/include/isc/irpmarshall.h
OLD_FILES+=usr/include/isc/list.h
OLD_FILES+=usr/include/isc/logging.h
OLD_FILES+=usr/include/isc/memcluster.h
OLD_FILES+=usr/include/isc/misc.h
OLD_FILES+=usr/include/isc/tree.h
OLD_FILES+=usr/include/machine/ansi.h
OLD_FILES+=usr/include/machine/apic.h
OLD_FILES+=usr/include/machine/asc_ioctl.h
OLD_FILES+=usr/include/machine/asnames.h
OLD_FILES+=usr/include/machine/bus_at386.h
OLD_FILES+=usr/include/machine/bus_memio.h
OLD_FILES+=usr/include/machine/bus_pc98.h
OLD_FILES+=usr/include/machine/bus_pio.h
OLD_FILES+=usr/include/machine/cdk.h
OLD_FILES+=usr/include/machine/comstats.h
OLD_FILES+=usr/include/machine/console.h
OLD_FILES+=usr/include/machine/critical.h
OLD_FILES+=usr/include/machine/cronyx.h
OLD_FILES+=usr/include/machine/dvcfg.h
OLD_FILES+=usr/include/machine/globaldata.h
OLD_FILES+=usr/include/machine/globals.h
OLD_FILES+=usr/include/machine/gsc.h
OLD_FILES+=usr/include/machine/i4b_isppp.h
OLD_FILES+=usr/include/machine/if_wavelan_ieee.h
OLD_FILES+=usr/include/machine/iic.h
OLD_FILES+=usr/include/machine/ioctl_ctx.h
OLD_FILES+=usr/include/machine/ioctl_fd.h
OLD_FILES+=usr/include/machine/ipl.h
OLD_FILES+=usr/include/machine/lock.h
OLD_FILES+=usr/include/machine/mouse.h
OLD_FILES+=usr/include/machine/mpapic.h
OLD_FILES+=usr/include/machine/mtpr.h
OLD_FILES+=usr/include/machine/pc/msdos.h
OLD_FILES+=usr/include/machine/physio_proc.h
OLD_FILES+=usr/include/machine/smb.h
OLD_FILES+=usr/include/machine/spigot.h
OLD_FILES+=usr/include/machine/types.h
OLD_FILES+=usr/include/machine/uc_device.h
OLD_FILES+=usr/include/machine/ultrasound.h
OLD_FILES+=usr/include/machine/wtio.h
OLD_FILES+=usr/include/msdosfs/bootsect.h
OLD_FILES+=usr/include/msdosfs/bpb.h
OLD_FILES+=usr/include/msdosfs/denode.h
OLD_FILES+=usr/include/msdosfs/direntry.h
OLD_FILES+=usr/include/msdosfs/fat.h
OLD_FILES+=usr/include/msdosfs/msdosfsmount.h
OLD_FILES+=usr/include/net/hostcache.h
OLD_FILES+=usr/include/net/if_faith.h
OLD_FILES+=usr/include/net/if_ieee80211.h
OLD_FILES+=usr/include/net/if_tunvar.h
OLD_FILES+=usr/include/net/intrq.h
OLD_FILES+=usr/include/netatm/kern_include.h
OLD_FILES+=usr/include/netinet/if_fddi.h
OLD_FILES+=usr/include/netinet/in_hostcache.h
OLD_FILES+=usr/include/netinet/ip_flow.h
OLD_FILES+=usr/include/netinet/ip_fw2.h
OLD_FILES+=usr/include/netinet6/in6_prefix.h
OLD_FILES+=usr/include/netns/idp.h
OLD_FILES+=usr/include/netns/idp_var.h
OLD_FILES+=usr/include/netns/ns.h
OLD_FILES+=usr/include/netns/ns_error.h
OLD_FILES+=usr/include/netns/ns_if.h
OLD_FILES+=usr/include/netns/ns_pcb.h
OLD_FILES+=usr/include/netns/sp.h
OLD_FILES+=usr/include/netns/spidp.h
OLD_FILES+=usr/include/netns/spp_debug.h
OLD_FILES+=usr/include/netns/spp_timer.h
OLD_FILES+=usr/include/netns/spp_var.h
OLD_FILES+=usr/include/nfs/nfs.h
OLD_FILES+=usr/include/nfs/nfsm_subs.h
OLD_FILES+=usr/include/nfs/nfsmount.h
OLD_FILES+=usr/include/nfs/nfsnode.h
OLD_FILES+=usr/include/nfs/nfsrtt.h
OLD_FILES+=usr/include/nfs/nfsrvcache.h
OLD_FILES+=usr/include/nfs/nfsv2.h
OLD_FILES+=usr/include/nfs/nqnfs.h
OLD_FILES+=usr/include/ntfs/ntfs.h
OLD_FILES+=usr/include/ntfs/ntfs_compr.h
OLD_FILES+=usr/include/ntfs/ntfs_ihash.h
OLD_FILES+=usr/include/ntfs/ntfs_inode.h
OLD_FILES+=usr/include/ntfs/ntfs_subr.h
OLD_FILES+=usr/include/ntfs/ntfs_vfsops.h
OLD_FILES+=usr/include/ntfs/ntfsmount.h
OLD_FILES+=usr/include/nwfs/nwfs.h
OLD_FILES+=usr/include/nwfs/nwfs_mount.h
OLD_FILES+=usr/include/nwfs/nwfs_node.h
OLD_FILES+=usr/include/nwfs/nwfs_subr.h
OLD_FILES+=usr/include/posix4/_semaphore.h
OLD_FILES+=usr/include/posix4/aio.h
OLD_FILES+=usr/include/posix4/ksem.h
OLD_FILES+=usr/include/posix4/mqueue.h
OLD_FILES+=usr/include/posix4/posix4.h
OLD_FILES+=usr/include/posix4/sched.h
OLD_FILES+=usr/include/posix4/semaphore.h
OLD_DIRS+=usr/include/posix4
OLD_FILES+=usr/include/security/_pam_compat.h
OLD_FILES+=usr/include/security/_pam_macros.h
OLD_FILES+=usr/include/security/_pam_types.h
OLD_FILES+=usr/include/security/pam_malloc.h
OLD_FILES+=usr/include/security/pam_misc.h
OLD_FILES+=usr/include/skey.h
OLD_FILES+=usr/include/strhash.h
OLD_FILES+=usr/include/struct.h
OLD_FILES+=usr/include/sys/_label.h
OLD_FILES+=usr/include/sys/_posix.h
OLD_FILES+=usr/include/sys/bus_private.h
OLD_FILES+=usr/include/sys/ccdvar.h
OLD_FILES+=usr/include/sys/diskslice.h
OLD_FILES+=usr/include/sys/dmap.h
OLD_FILES+=usr/include/sys/inttypes.h
OLD_FILES+=usr/include/sys/jumbo.h
OLD_FILES+=usr/include/sys/mac_policy.h
OLD_FILES+=usr/include/sys/pbioio.h
OLD_FILES+=usr/include/sys/syscall-hide.h
OLD_FILES+=usr/include/sys/tprintf.h
OLD_FILES+=usr/include/sys/vnioctl.h
OLD_FILES+=usr/include/sys/wormio.h
OLD_FILES+=usr/include/telnet.h
OLD_FILES+=usr/include/ufs/mfs/mfs_extern.h
OLD_FILES+=usr/include/ufs/mfs/mfsnode.h
OLD_FILES+=usr/include/values.h
OLD_FILES+=usr/include/vm/vm_zone.h
OLD_FILES+=usr/share/examples/etc/usbd.conf
OLD_FILES+=usr/share/examples/meteor/README
OLD_FILES+=usr/share/examples/meteor/rgb16.c
OLD_FILES+=usr/share/examples/meteor/rgb24.c
OLD_FILES+=usr/share/examples/meteor/test-n.c
OLD_FILES+=usr/share/examples/meteor/yuvpk.c
OLD_FILES+=usr/share/examples/meteor/yuvpl.c
OLD_FILES+=usr/share/examples/worm/README
OLD_FILES+=usr/share/examples/worm/makecdfs.sh
OLD_FILES+=usr/share/groff_font/devlj4/Makefile
OLD_FILES+=usr/share/groff_font/devlj4/text.map
OLD_FILES+=usr/share/groff_font/devlj4/special.map
OLD_FILES+=usr/share/misc/nslookup.help
OLD_FILES+=usr/share/sendmail/cf/feature/nodns.m4
OLD_FILES+=usr/share/syscons/keymaps/lat-amer.kbd
OLD_FILES+=usr/share/vi/catalog/ru_SU.KOI8-R
OLD_FILES+=usr/share/zoneinfo/SystemV/YST9
OLD_FILES+=usr/share/zoneinfo/SystemV/PST8
OLD_FILES+=usr/share/zoneinfo/SystemV/EST5EDT
OLD_FILES+=usr/share/zoneinfo/SystemV/CST6CDT
OLD_FILES+=usr/share/zoneinfo/SystemV/MST7MDT
OLD_FILES+=usr/share/zoneinfo/SystemV/PST8PDT
OLD_FILES+=usr/share/zoneinfo/SystemV/YST9YDT
OLD_FILES+=usr/share/zoneinfo/SystemV/HST10
OLD_FILES+=usr/share/zoneinfo/SystemV/MST7
OLD_FILES+=usr/share/zoneinfo/SystemV/EST5
OLD_FILES+=usr/share/zoneinfo/SystemV/AST4ADT
OLD_FILES+=usr/share/zoneinfo/SystemV/CST6
OLD_FILES+=usr/share/zoneinfo/SystemV/AST4
OLD_DIRS+=usr/share/zoneinfo/SystemV
OLD_FILES+=usr/share/doc/ntp/accopt.htm
OLD_FILES+=usr/share/doc/ntp/assoc.htm
OLD_FILES+=usr/share/doc/ntp/audio.htm
OLD_FILES+=usr/share/doc/ntp/authopt.htm
OLD_FILES+=usr/share/doc/ntp/biblio.htm
OLD_FILES+=usr/share/doc/ntp/build.htm
OLD_FILES+=usr/share/doc/ntp/clockopt.htm
OLD_FILES+=usr/share/doc/ntp/config.htm
OLD_FILES+=usr/share/doc/ntp/confopt.htm
OLD_FILES+=usr/share/doc/ntp/copyright.htm
OLD_FILES+=usr/share/doc/ntp/debug.htm
OLD_FILES+=usr/share/doc/ntp/driver1.htm
OLD_FILES+=usr/share/doc/ntp/driver10.htm
OLD_FILES+=usr/share/doc/ntp/driver11.htm
OLD_FILES+=usr/share/doc/ntp/driver12.htm
OLD_FILES+=usr/share/doc/ntp/driver16.htm
OLD_FILES+=usr/share/doc/ntp/driver18.htm
OLD_FILES+=usr/share/doc/ntp/driver19.htm
OLD_FILES+=usr/share/doc/ntp/driver2.htm
OLD_FILES+=usr/share/doc/ntp/driver20.htm
OLD_FILES+=usr/share/doc/ntp/driver22.htm
OLD_FILES+=usr/share/doc/ntp/driver23.htm
OLD_FILES+=usr/share/doc/ntp/driver24.htm
OLD_FILES+=usr/share/doc/ntp/driver26.htm
OLD_FILES+=usr/share/doc/ntp/driver27.htm
OLD_FILES+=usr/share/doc/ntp/driver28.htm
OLD_FILES+=usr/share/doc/ntp/driver29.htm
OLD_FILES+=usr/share/doc/ntp/driver3.htm
OLD_FILES+=usr/share/doc/ntp/driver30.htm
OLD_FILES+=usr/share/doc/ntp/driver32.htm
OLD_FILES+=usr/share/doc/ntp/driver33.htm
OLD_FILES+=usr/share/doc/ntp/driver34.htm
OLD_FILES+=usr/share/doc/ntp/driver35.htm
OLD_FILES+=usr/share/doc/ntp/driver36.htm
OLD_FILES+=usr/share/doc/ntp/driver37.htm
OLD_FILES+=usr/share/doc/ntp/driver4.htm
OLD_FILES+=usr/share/doc/ntp/driver5.htm
OLD_FILES+=usr/share/doc/ntp/driver6.htm
OLD_FILES+=usr/share/doc/ntp/driver7.htm
OLD_FILES+=usr/share/doc/ntp/driver8.htm
OLD_FILES+=usr/share/doc/ntp/driver9.htm
OLD_FILES+=usr/share/doc/ntp/exec.htm
OLD_FILES+=usr/share/doc/ntp/extern.htm
OLD_FILES+=usr/share/doc/ntp/gadget.htm
OLD_FILES+=usr/share/doc/ntp/hints.htm
OLD_FILES+=usr/share/doc/ntp/howto.htm
OLD_FILES+=usr/share/doc/ntp/htmlprimer.htm
OLD_FILES+=usr/share/doc/ntp/index.htm
OLD_FILES+=usr/share/doc/ntp/kern.htm
OLD_FILES+=usr/share/doc/ntp/kernpps.htm
OLD_FILES+=usr/share/doc/ntp/ldisc.htm
OLD_FILES+=usr/share/doc/ntp/measure.htm
OLD_FILES+=usr/share/doc/ntp/miscopt.htm
OLD_FILES+=usr/share/doc/ntp/monopt.htm
OLD_FILES+=usr/share/doc/ntp/mx4200data.htm
OLD_FILES+=usr/share/doc/ntp/notes.htm
OLD_FILES+=usr/share/doc/ntp/ntpd.htm
OLD_FILES+=usr/share/doc/ntp/ntpdate.htm
OLD_FILES+=usr/share/doc/ntp/ntpdc.htm
OLD_FILES+=usr/share/doc/ntp/ntpq.htm
OLD_FILES+=usr/share/doc/ntp/ntptime.htm
OLD_FILES+=usr/share/doc/ntp/ntptrace.htm
OLD_FILES+=usr/share/doc/ntp/parsedata.htm
OLD_FILES+=usr/share/doc/ntp/parsenew.htm
OLD_FILES+=usr/share/doc/ntp/patches.htm
OLD_FILES+=usr/share/doc/ntp/porting.htm
OLD_FILES+=usr/share/doc/ntp/pps.htm
OLD_FILES+=usr/share/doc/ntp/prefer.htm
OLD_FILES+=usr/share/doc/ntp/qth.htm
OLD_FILES+=usr/share/doc/ntp/quick.htm
OLD_FILES+=usr/share/doc/ntp/rdebug.htm
OLD_FILES+=usr/share/doc/ntp/refclock.htm
OLD_FILES+=usr/share/doc/ntp/release.htm
OLD_FILES+=usr/share/doc/ntp/tickadj.htm
OLD_FILES+=usr/share/doc/papers/nqnfs.ascii.gz
OLD_FILES+=usr/share/doc/papers/px.ascii.gz
OLD_FILES+=usr/share/man/man3/exp10.3.gz
OLD_FILES+=usr/share/man/man3/exp10f.3.gz
OLD_FILES+=usr/share/man/man3/fpsetsticky.3.gz
OLD_FILES+=usr/share/man/man3/gss_krb5_compat_des3_mic.3.gz
OLD_FILES+=usr/share/man/man3/gss_krb5_copy_ccache.3.gz
OLD_FILES+=usr/share/man/man3/mac_is_present_np.3.gz
OLD_FILES+=usr/share/man/man3/mbmb.3.gz
OLD_FILES+=usr/share/man/man3/setrunelocale.3.gz
OLD_FILES+=usr/share/man/man5/usbd.conf.5.gz
.if ${TARGET_ARCH} != "i386" && ${TARGET_ARCH} != "amd64"
OLD_FILES+=usr/share/man/man8/boot_i386.8.gz
.endif
.if ${TARGET_ARCH} != "aarch64" && ${TARGET} != "arm" && \
${TARGET_ARCH} != "powerpc" && ${TARGET_ARCH} != "powerpc64" && \
${TARGET_ARCH} != "sparc64" && ${TARGET} != "mips"
OLD_FILES+=usr/share/man/man8/ofwdump.8.gz
.endif
OLD_FILES+=usr/share/man/man8/mount_reiserfs.8.gz
OLD_FILES+=usr/share/man/man9/VFS_START.9.gz
OLD_FILES+=usr/share/man/man9/cpu_critical_exit.9.gz
OLD_FILES+=usr/share/man/man9/cpu_critical_enter.9.gz
OLD_FILES+=usr/share/info/annotate.info.gz
OLD_FILES+=usr/share/info/tar.info.gz
OLD_FILES+=usr/share/bsnmp/defs/tree.def
OLD_FILES+=usr/share/bsnmp/defs/mibII_tree.def
OLD_FILES+=usr/share/bsnmp/defs/netgraph_tree.def
OLD_FILES+=usr/share/bsnmp/mibs/FOKUS-MIB.txt
OLD_FILES+=usr/share/bsnmp/mibs/BEGEMOT-MIB.txt
OLD_FILES+=usr/share/bsnmp/mibs/BEGEMOT-SNMPD.txt
OLD_FILES+=usr/share/bsnmp/mibs/BEGEMOT-NETGRAPH.txt
OLD_FILES+=usr/libdata/msdosfs/iso22dos
OLD_FILES+=usr/libdata/msdosfs/iso72dos
OLD_FILES+=usr/libdata/msdosfs/koi2dos
OLD_FILES+=usr/libdata/msdosfs/koi8u2dos
# The following files are *not* obsolete, they just don't get touched at
# install, so don't add them:
# - boot/loader.rc
# - usr/share/tmac/man.local
# - usr/share/tmac/mm/locale
# - usr/share/tmac/mm/se_locale
# - var/yp/Makefile
# Early entries split OLD_FILES, OLD_LIBS, and OLD_DIRS into separate sections
# in this file, but this practice was abandoned in the mid-2000s.
#
# 20071120: shared library version bump
OLD_LIBS+=usr/lib/libasn1.so.8
OLD_LIBS+=usr/lib/libgssapi.so.8
OLD_LIBS+=usr/lib/libgssapi_krb5.so.8
OLD_LIBS+=usr/lib/libhdb.so.8
OLD_LIBS+=usr/lib/libkadm5clnt.so.8
OLD_LIBS+=usr/lib/libkadm5srv.so.8
OLD_LIBS+=usr/lib/libkafs5.so.8
OLD_LIBS+=usr/lib/libkrb5.so.8
OLD_LIBS+=usr/lib/libobjc.so.2
# 20070519: GCC 4.2
OLD_FILES+=usr/lib/libg2c.a
OLD_FILES+=usr/lib/libg2c.so
OLD_LIBS+=usr/lib/libg2c.so.2
OLD_FILES+=usr/lib/libg2c_p.a
OLD_FILES+=usr/lib/libgcc_pic.a
# 20060729: OpenSSL 0.9.7e -> 0.9.8b upgrade
OLD_LIBS+=lib/libcrypto.so.4
OLD_LIBS+=usr/lib/libssl.so.4
# 20060521: gethostbyaddr(3) ABI change
OLD_LIBS+=usr/lib/libroken.so.8
OLD_LIBS+=lib/libatm.so.3
OLD_LIBS+=lib/libc.so.6
OLD_LIBS+=lib/libutil.so.5
# 20060413: shared library moved to /usr/lib
MOVED_LIBS+=lib/libgpib.so.1
# 20060413: libpcap.so.4 moved to /lib/
MOVED_LIBS+=usr/lib/libpcap.so.4
# 20060412: libpthread.so.2 moved to /lib/
MOVED_LIBS+=usr/lib/libpthread.so.2
# 20060127: revert libdisk to static-only
OLD_LIBS+=usr/lib/libdisk.so.3
# 20051027: libc_r discontinued (removed 20101113)
OLD_FILES+=usr/lib/libc_r.a
OLD_FILES+=usr/lib/libc_r.so
OLD_LIBS+=usr/lib/libc_r.so.7
OLD_FILES+=usr/lib/libc_r_p.a
# 20050722: bump for 6.0-RELEASE
OLD_LIBS+=lib/libalias.so.4
OLD_LIBS+=lib/libatm.so.2
OLD_LIBS+=lib/libbegemot.so.1
OLD_LIBS+=lib/libbsdxml.so.1
OLD_LIBS+=lib/libbsnmp.so.2
OLD_LIBS+=lib/libc.so.5
OLD_LIBS+=lib/libcam.so.2
OLD_LIBS+=lib/libcrypt.so.2
OLD_LIBS+=lib/libcrypto.so.3
OLD_LIBS+=lib/libdevstat.so.4
OLD_LIBS+=lib/libedit.so.4
OLD_LIBS+=lib/libgeom.so.2
OLD_LIBS+=lib/libgpib.so.0
OLD_LIBS+=lib/libipsec.so.1
OLD_LIBS+=lib/libipx.so.2
OLD_LIBS+=lib/libkiconv.so.1
OLD_LIBS+=lib/libkvm.so.2
OLD_LIBS+=lib/libm.so.3
OLD_LIBS+=lib/libmd.so.2
OLD_LIBS+=lib/libncurses.so.5
OLD_LIBS+=lib/libreadline.so.5
OLD_LIBS+=lib/libsbuf.so.2
OLD_LIBS+=lib/libufs.so.2
OLD_LIBS+=lib/libutil.so.4
OLD_LIBS+=lib/libz.so.2
OLD_LIBS+=usr/lib/libarchive.so.1
OLD_LIBS+=usr/lib/libasn1.so.7
OLD_LIBS+=usr/lib/libbluetooth.so.1
OLD_LIBS+=usr/lib/libbz2.so.1
OLD_LIBS+=usr/lib/libc_r.so.5
OLD_LIBS+=usr/lib/libcalendar.so.2
OLD_LIBS+=usr/lib/libcom_err.so.2
OLD_LIBS+=usr/lib/libdevinfo.so.2
OLD_LIBS+=usr/lib/libdialog.so.4
OLD_LIBS+=usr/lib/libfetch.so.3
OLD_LIBS+=usr/lib/libform.so.2
OLD_LIBS+=usr/lib/libftpio.so.5
OLD_LIBS+=usr/lib/libg2c.so.1
OLD_LIBS+=usr/lib/libgnuregex.so.2
OLD_LIBS+=usr/lib/libgssapi.so.7
OLD_LIBS+=usr/lib/libhdb.so.7
OLD_LIBS+=usr/lib/libhistory.so.5
OLD_LIBS+=usr/lib/libkadm5clnt.so.7
OLD_LIBS+=usr/lib/libkadm5srv.so.7
OLD_LIBS+=usr/lib/libkafs5.so.7
OLD_LIBS+=usr/lib/libkrb5.so.7
OLD_LIBS+=usr/lib/libmagic.so.1
OLD_LIBS+=usr/lib/libmenu.so.2
OLD_LIBS+=usr/lib/libmilter.so.2
OLD_LIBS+=usr/lib/libmp.so.4
OLD_LIBS+=usr/lib/libncp.so.1
OLD_LIBS+=usr/lib/libnetgraph.so.1
OLD_LIBS+=usr/lib/libngatm.so.1
OLD_LIBS+=usr/lib/libobjc.so.1
OLD_LIBS+=usr/lib/libopie.so.3
OLD_LIBS+=usr/lib/libpam.so.2
OLD_LIBS+=usr/lib/libpanel.so.2
OLD_LIBS+=usr/lib/libpcap.so.3
OLD_LIBS+=usr/lib/libpmc.so.2
OLD_LIBS+=usr/lib/libpthread.so.1
OLD_LIBS+=usr/lib/libradius.so.1
OLD_LIBS+=usr/lib/libroken.so.7
OLD_LIBS+=usr/lib/librpcsvc.so.2
OLD_LIBS+=usr/lib/libsdp.so.1
OLD_LIBS+=usr/lib/libsmb.so.1
OLD_LIBS+=usr/lib/libssh.so.2
OLD_LIBS+=usr/lib/libssl.so.3
OLD_LIBS+=usr/lib/libstdc++.so.4
OLD_LIBS+=usr/lib/libtacplus.so.1
OLD_LIBS+=usr/lib/libthr.so.1
OLD_LIBS+=usr/lib/libthread_db.so.1
OLD_LIBS+=usr/lib/libugidfw.so.1
OLD_LIBS+=usr/lib/libusbhid.so.1
OLD_LIBS+=usr/lib/libvgl.so.3
OLD_LIBS+=usr/lib/libwrap.so.3
OLD_LIBS+=usr/lib/libypclnt.so.1
OLD_LIBS+=usr/lib/pam_chroot.so.2
OLD_LIBS+=usr/lib/pam_deny.so.2
OLD_LIBS+=usr/lib/pam_echo.so.2
OLD_LIBS+=usr/lib/pam_exec.so.2
OLD_LIBS+=usr/lib/pam_ftpusers.so.2
OLD_LIBS+=usr/lib/pam_group.so.2
OLD_LIBS+=usr/lib/pam_guest.so.2
OLD_LIBS+=usr/lib/pam_krb5.so.2
OLD_LIBS+=usr/lib/pam_ksu.so.2
OLD_LIBS+=usr/lib/pam_lastlog.so.2
OLD_LIBS+=usr/lib/pam_login_access.so.2
OLD_LIBS+=usr/lib/pam_nologin.so.2
OLD_LIBS+=usr/lib/pam_opie.so.2
OLD_LIBS+=usr/lib/pam_opieaccess.so.2
OLD_LIBS+=usr/lib/pam_passwdqc.so.2
OLD_LIBS+=usr/lib/pam_permit.so.2
OLD_LIBS+=usr/lib/pam_radius.so.2
OLD_LIBS+=usr/lib/pam_rhosts.so.2
OLD_LIBS+=usr/lib/pam_rootok.so.2
OLD_LIBS+=usr/lib/pam_securetty.so.2
OLD_LIBS+=usr/lib/pam_self.so.2
OLD_LIBS+=usr/lib/pam_ssh.so.2
OLD_LIBS+=usr/lib/pam_tacplus.so.2
OLD_LIBS+=usr/lib/pam_unix.so.2
OLD_LIBS+=usr/lib/snmp_atm.so.3
OLD_LIBS+=usr/lib/snmp_mibII.so.3
OLD_LIBS+=usr/lib/snmp_netgraph.so.3
OLD_LIBS+=usr/lib/snmp_pf.so.3
# 200505XX: ?
OLD_LIBS+=usr/lib/snmp_atm.so.2
OLD_LIBS+=usr/lib/snmp_mibII.so.2
OLD_LIBS+=usr/lib/snmp_netgraph.so.2
OLD_LIBS+=usr/lib/snmp_pf.so.2
# 2005XXXX: not ready for primetime yet
OLD_LIBS+=usr/lib/libautofs.so.1
# 200411XX: libxpg4 removal
OLD_LIBS+=usr/lib/libxpg4.so.3
# 200410XX: libm compatibility fix
OLD_LIBS+=lib/libm.so.2
# 20041001: version bump
OLD_LIBS+=lib/libreadline.so.4
OLD_LIBS+=usr/lib/libhistory.so.4
OLD_LIBS+=usr/lib/libopie.so.2
OLD_LIBS+=usr/lib/libpcap.so.2
# 20040925: bind9 import
OLD_LIBS+=usr/lib/libisc.so.1
# 200408XX
OLD_LIBS+=usr/lib/snmp_netgraph.so.1
# 200404XX
OLD_LIBS+=usr/lib/libsnmp.so.1
OLD_LIBS+=usr/lib/snmp_mibII.so.1
# 200309XX
OLD_LIBS+=usr/lib/libasn1.so.6
OLD_LIBS+=usr/lib/libhdb.so.6
OLD_LIBS+=usr/lib/libkadm5clnt.so.6
OLD_LIBS+=usr/lib/libkadm5srv.so.6
OLD_LIBS+=usr/lib/libkrb5.so.6
OLD_LIBS+=usr/lib/libroken.so.6
# 200304XX
OLD_LIBS+=usr/lib/libc.so.4
OLD_LIBS+=usr/lib/libc_r.so.4
OLD_LIBS+=usr/lib/libdevstat.so.2
OLD_LIBS+=usr/lib/libedit.so.3
OLD_LIBS+=usr/lib/libgmp.so.3
OLD_LIBS+=usr/lib/libmp.so.3
OLD_LIBS+=usr/lib/libpam.so.1
OLD_LIBS+=usr/lib/libposix1e.so.2
OLD_LIBS+=usr/lib/libskey.so.2
OLD_LIBS+=usr/lib/libusbhid.so.0
OLD_LIBS+=usr/lib/libvgl.so.2
# 20030218: OpenSSL 0.9.7 import
OLD_FILES+=usr/include/des.h
OLD_FILES+=usr/lib/libdes.a
OLD_FILES+=usr/lib/libdes.so
OLD_LIBS+=usr/lib/libdes.so.3
OLD_FILES+=usr/lib/libdes_p.a
# 200302XX
OLD_LIBS+=usr/lib/libacl.so.3
OLD_LIBS+=usr/lib/libasn1.so.5
OLD_LIBS+=usr/lib/libcrypto.so.2
OLD_LIBS+=usr/lib/libgssapi.so.5
OLD_LIBS+=usr/lib/libhdb.so.5
OLD_LIBS+=usr/lib/libkadm.so.3
OLD_LIBS+=usr/lib/libkadm5clnt.so.5
OLD_LIBS+=usr/lib/libkadm5srv.so.5
OLD_LIBS+=usr/lib/libkafs.so.3
OLD_LIBS+=usr/lib/libkafs5.so.5
OLD_LIBS+=usr/lib/libkdb.so.3
OLD_LIBS+=usr/lib/libkrb.so.3
OLD_LIBS+=usr/lib/libroken.so.5
OLD_LIBS+=usr/lib/libssl.so.2
OLD_LIBS+=usr/lib/pam_kerberosIV.so
# 200208XX
OLD_LIBS+=usr/lib/libgssapi.so.4
# 200203XX
OLD_LIBS+=usr/lib/libss.so.3
OLD_LIBS+=usr/lib/libusb.so.0
# 200112XX
OLD_LIBS+=usr/lib/libfetch.so.2
# 200110XX
OLD_LIBS+=usr/lib/libgssapi.so.3
# 200104XX
OLD_LIBS+=usr/lib/libdescrypt.so.2
OLD_LIBS+=usr/lib/libscrypt.so.2
# 200102XX
OLD_LIBS+=usr/lib/libcrypto.so.1
OLD_LIBS+=usr/lib/libssl.so.1
# 200009XX
OLD_LIBS+=usr/lib/libRSAglue.so.1
OLD_LIBS+=usr/lib/librsaINTL.so.1
OLD_LIBS+=usr/lib/librsaUSA.so.1
# 200006XX
OLD_LIBS+=usr/lib/libalias.so.3
OLD_LIBS+=usr/lib/libfetch.so.1
OLD_LIBS+=usr/lib/libipsec.so.0
# 200005XX
OLD_LIBS+=usr/lib/libxpg4.so.2
# 200002XX
OLD_LIBS+=usr/lib/libc.so.3
OLD_LIBS+=usr/lib/libcurses.so.2
OLD_LIBS+=usr/lib/libdialog.so.3
OLD_LIBS+=usr/lib/libedit.so.2
OLD_LIBS+=usr/lib/libf2c.so.2
OLD_LIBS+=usr/lib/libftpio.so.4
OLD_LIBS+=usr/lib/libg++.so.4
OLD_LIBS+=usr/lib/libhistory.so.3
OLD_LIBS+=usr/lib/libmytinfo.so.2
OLD_LIBS+=usr/lib/libncurses.so.3
OLD_LIBS+=usr/lib/libreadline.so.3
OLD_LIBS+=usr/lib/libss.so.2
OLD_LIBS+=usr/lib/libtermcap.so.2
OLD_LIBS+=usr/lib/libutil.so.2
OLD_LIBS+=usr/lib/libvgl.so.1
OLD_LIBS+=usr/lib/libwrap.so.2
# ???
OLD_LIBS+=usr/lib/libarchive.so.2
OLD_LIBS+=usr/lib/libbsnmp.so.1
OLD_LIBS+=usr/lib/libc_r.so.6
OLD_LIBS+=usr/lib/libcipher.so.2
OLD_LIBS+=usr/lib/libgssapi.so.6
OLD_LIBS+=usr/lib/libkse.so.1
OLD_LIBS+=usr/lib/liblwres.so.3
OLD_LIBS+=usr/lib/pam_ftp.so.2
# 20040925: bind9 import
OLD_DIRS+=usr/share/doc/bind/html
OLD_DIRS+=usr/share/doc/bind/misc
OLD_DIRS+=usr/share/doc/bind/
# ???
OLD_DIRS+=usr/include/g++/std
OLD_DIRS+=usr/include/msdosfs
OLD_DIRS+=usr/include/ntfs
OLD_DIRS+=usr/include/nwfs
OLD_DIRS+=usr/include/ufs/mfs
# 20011001: UUCP migration to ports
OLD_DIRS+=usr/libexec/uucp
.include "tools/build/mk/OptionalObsoleteFiles.inc"
diff --git a/contrib/llvm-project/clang/include/clang/Basic/DiagnosticSemaKinds.td b/contrib/llvm-project/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6ff5b8de57fd..cb460401eb47 100644
--- a/contrib/llvm-project/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/contrib/llvm-project/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1,11653 +1,11653 @@
//==--- DiagnosticSemaKinds.td - libsema diagnostics ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Semantic Analysis
//===----------------------------------------------------------------------===//
let Component = "Sema" in {
let CategoryName = "Semantic Issue" in {
def note_previous_decl : Note<"%0 declared here">;
def note_entity_declared_at : Note<"%0 declared here">;
def note_callee_decl : Note<"%0 declared here">;
def note_defined_here : Note<"%0 defined here">;
// For loop analysis
def warn_variables_not_in_loop_body : Warning<
"variable%select{s| %1|s %1 and %2|s %1, %2, and %3|s %1, %2, %3, and %4}0 "
"used in loop condition not modified in loop body">,
InGroup<ForLoopAnalysis>, DefaultIgnore;
def warn_redundant_loop_iteration : Warning<
"variable %0 is %select{decremented|incremented}1 both in the loop header "
"and in the loop body">,
InGroup<ForLoopAnalysis>, DefaultIgnore;
def note_loop_iteration_here : Note<"%select{decremented|incremented}0 here">;
def warn_duplicate_enum_values : Warning<
"element %0 has been implicitly assigned %1 which another element has "
"been assigned">, InGroup<DiagGroup<"duplicate-enum">>, DefaultIgnore;
def note_duplicate_element : Note<"element %0 also has value %1">;
// Absolute value functions
def warn_unsigned_abs : Warning<
"taking the absolute value of unsigned type %0 has no effect">,
InGroup<AbsoluteValue>;
def note_remove_abs : Note<
"remove the call to '%0' since unsigned values cannot be negative">;
def warn_abs_too_small : Warning<
"absolute value function %0 given an argument of type %1 but has parameter "
"of type %2 which may cause truncation of value">, InGroup<AbsoluteValue>;
def warn_wrong_absolute_value_type : Warning<
"using %select{integer|floating point|complex}1 absolute value function %0 "
"when argument is of %select{integer|floating point|complex}2 type">,
InGroup<AbsoluteValue>;
def note_replace_abs_function : Note<"use function '%0' instead">;
def warn_pointer_abs : Warning<
"taking the absolute value of %select{pointer|function|array}0 type %1 is suspicious">,
InGroup<AbsoluteValue>;
def warn_max_unsigned_zero : Warning<
"taking the max of "
"%select{a value and unsigned zero|unsigned zero and a value}0 "
"is always equal to the other value">,
InGroup<MaxUnsignedZero>;
def note_remove_max_call : Note<
"remove call to max function and unsigned zero argument">;
def warn_infinite_recursive_function : Warning<
"all paths through this function will call itself">,
InGroup<InfiniteRecursion>, DefaultIgnore;
def warn_comma_operator : Warning<"possible misuse of comma operator here">,
InGroup<DiagGroup<"comma">>, DefaultIgnore;
def note_cast_to_void : Note<"cast expression to void to silence warning">;
def note_cast_operand_to_int : Note<"cast one or both operands to int to silence this warning">;
// Constant expressions
def err_expr_not_ice : Error<
"expression is not an %select{integer|integral}0 constant expression">;
def ext_expr_not_ice : Extension<
"expression is not an %select{integer|integral}0 constant expression; "
"folding it to a constant is a GNU extension">, InGroup<GNUFoldingConstant>;
def err_typecheck_converted_constant_expression : Error<
"value of type %0 is not implicitly convertible to %1">;
def err_typecheck_converted_constant_expression_disallowed : Error<
"conversion from %0 to %1 is not allowed in a converted constant expression">;
def err_typecheck_converted_constant_expression_indirect : Error<
"conversion from %0 to %1 in converted constant expression would "
"bind reference to a temporary">;
def err_expr_not_cce : Error<
"%select{case value|enumerator value|non-type template argument|"
"array size|explicit specifier argument|noexcept specifier argument}0 "
"is not a constant expression">;
def ext_cce_narrowing : ExtWarn<
"%select{case value|enumerator value|non-type template argument|"
"array size|explicit specifier argument|noexcept specifier argument}0 "
"%select{cannot be narrowed from type %2 to %3|"
"evaluates to %2, which cannot be narrowed to type %3}1">,
InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
def err_ice_not_integral : Error<
"%select{integer|integral}1 constant expression must have "
"%select{integer|integral or unscoped enumeration}1 type, not %0">;
def err_ice_incomplete_type : Error<
"integral constant expression has incomplete class type %0">;
def err_ice_explicit_conversion : Error<
"integral constant expression requires explicit conversion from %0 to %1">;
def note_ice_conversion_here : Note<
"conversion to %select{integral|enumeration}0 type %1 declared here">;
def err_ice_ambiguous_conversion : Error<
"ambiguous conversion from type %0 to an integral or unscoped "
"enumeration type">;
def err_ice_too_large : Error<
"integer constant expression evaluates to value %0 that cannot be "
"represented in a %1-bit %select{signed|unsigned}2 integer type">;
def err_expr_not_string_literal : Error<"expression is not a string literal">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
"predefined identifier is only valid inside function">,
InGroup<DiagGroup<"predefined-identifier-outside-function">>;
def warn_float_overflow : Warning<
"magnitude of floating-point constant too large for type %0; maximum is %1">,
InGroup<LiteralRange>;
def warn_float_underflow : Warning<
"magnitude of floating-point constant too small for type %0; minimum is %1">,
InGroup<LiteralRange>;
def warn_float_compare_literal : Warning<
"floating-point comparison is always %select{true|false}0; "
"constant cannot be represented exactly in type %1">,
InGroup<LiteralRange>;
def warn_double_const_requires_fp64 : Warning<
"double precision constant requires %select{cl_khr_fp64|cl_khr_fp64 and __opencl_c_fp64}0, "
"casting to single precision">;
def err_half_const_requires_fp16 : Error<
"half precision constant requires cl_khr_fp16">;
// C99 variable-length arrays
def ext_vla : Extension<"variable length arrays are a C99 feature">,
InGroup<VLAExtension>;
def warn_vla_used : Warning<"variable length array used">,
InGroup<VLA>, DefaultIgnore;
def err_vla_in_sfinae : Error<
"variable length array cannot be formed during template argument deduction">;
def err_array_star_in_function_definition : Error<
"variable length array must be bound in function definition">;
def err_vla_decl_in_file_scope : Error<
"variable length array declaration not allowed at file scope">;
def err_vla_decl_has_static_storage : Error<
"variable length array declaration cannot have 'static' storage duration">;
def err_vla_decl_has_extern_linkage : Error<
"variable length array declaration cannot have 'extern' linkage">;
def ext_vla_folded_to_constant : ExtWarn<
"variable length array folded to constant array as an extension">,
InGroup<GNUFoldingConstant>;
def err_vla_unsupported : Error<
"variable length arrays are not supported for the current target">;
def note_vla_unsupported : Note<
"variable length arrays are not supported for the current target">;
// C99 variably modified types
def err_variably_modified_template_arg : Error<
"variably modified type %0 cannot be used as a template argument">;
def err_variably_modified_nontype_template_param : Error<
"non-type template parameter of variably modified type %0">;
def err_variably_modified_new_type : Error<
"'new' cannot allocate object of variably modified type %0">;
// C99 Designated Initializers
def ext_designated_init : Extension<
"designated initializers are a C99 feature">, InGroup<C99Designator>;
def err_array_designator_negative : Error<
"array designator value '%0' is negative">;
def err_array_designator_empty_range : Error<
"array designator range [%0, %1] is empty">;
def err_array_designator_non_array : Error<
"array designator cannot initialize non-array type %0">;
def err_array_designator_too_large : Error<
"array designator index (%0) exceeds array bounds (%1)">;
def err_field_designator_non_aggr : Error<
"field designator cannot initialize a "
"%select{non-struct, non-union|non-class}0 type %1">;
def err_field_designator_unknown : Error<
"field designator %0 does not refer to any field in type %1">;
def err_field_designator_nonfield : Error<
"field designator %0 does not refer to a non-static data member">;
def note_field_designator_found : Note<"field designator refers here">;
def err_designator_for_scalar_or_sizeless_init : Error<
"designator in initializer for %select{scalar|indivisible sizeless}0 "
"type %1">;
def warn_initializer_overrides : Warning<
"initializer %select{partially |}0overrides prior initialization of "
"this subobject">, InGroup<InitializerOverrides>;
def ext_initializer_overrides : ExtWarn<warn_initializer_overrides.Text>,
InGroup<InitializerOverrides>, SFINAEFailure;
def err_initializer_overrides_destructed : Error<
"initializer would partially override prior initialization of object of "
"type %1 with non-trivial destruction">;
def note_previous_initializer : Note<
"previous initialization %select{|with side effects }0is here"
"%select{| (side effects will not occur at run time)}0">;
def err_designator_into_flexible_array_member : Error<
"designator into flexible array member subobject">;
def note_flexible_array_member : Note<
"initialized flexible array member %0 is here">;
def ext_flexible_array_init : Extension<
"flexible array initialization is a GNU extension">, InGroup<GNUFlexibleArrayInitializer>;
// C++20 designated initializers
def ext_cxx_designated_init : Extension<
"designated initializers are a C++20 extension">, InGroup<CXX20Designator>,
SuppressInSystemMacro;
def warn_cxx17_compat_designated_init : Warning<
"designated initializers are incompatible with C++ standards before C++20">,
InGroup<CXXPre20CompatPedantic>, DefaultIgnore;
def ext_designated_init_mixed : ExtWarn<
"mixture of designated and non-designated initializers in the same "
"initializer list is a C99 extension">, InGroup<C99Designator>;
def note_designated_init_mixed : Note<
"first non-designated initializer is here">;
def ext_designated_init_array : ExtWarn<
"array designators are a C99 extension">, InGroup<C99Designator>;
def ext_designated_init_nested : ExtWarn<
"nested designators are a C99 extension">, InGroup<C99Designator>;
def ext_designated_init_reordered : ExtWarn<
"ISO C++ requires field designators to be specified in declaration order; "
"field %1 will be initialized after field %0">, InGroup<ReorderInitList>,
SFINAEFailure;
def note_previous_field_init : Note<
"previous initialization for field %0 is here">;
def ext_designated_init_brace_elision : ExtWarn<
"brace elision for designated initializer is a C99 extension">,
InGroup<C99Designator>, SFINAEFailure;
// Declarations.
def ext_plain_complex : ExtWarn<
"plain '_Complex' requires a type specifier; assuming '_Complex double'">;
def ext_imaginary_constant : Extension<
"imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>;
def ext_integer_complex : Extension<
"complex integer types are a GNU extension">, InGroup<GNUComplexInteger>;
def err_invalid_saturation_spec : Error<"'_Sat' specifier is only valid on "
"'_Fract' or '_Accum', not '%0'">;
def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">;
def err_invalid_width_spec : Error<
"'%select{|short|long|long long}0 %1' is invalid">;
def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">;
def ext_auto_type_specifier : ExtWarn<
"'auto' type specifier is a C++11 extension">, InGroup<CXX11>;
def warn_auto_storage_class : Warning<
"'auto' storage class specifier is redundant and incompatible with C++11">,
InGroup<CXX11Compat>, DefaultIgnore;
def warn_deprecated_register : Warning<
"'register' storage class specifier is deprecated "
"and incompatible with C++17">, InGroup<DeprecatedRegister>;
def ext_register_storage_class : ExtWarn<
"ISO C++17 does not allow 'register' storage class specifier">,
DefaultError, InGroup<Register>;
def err_invalid_decl_spec_combination : Error<
"cannot combine with previous '%0' declaration specifier">;
def err_invalid_vector_decl_spec_combination : Error<
"cannot combine with previous '%0' declaration specifier. "
"'__vector' must be first">;
def err_invalid_pixel_decl_spec_combination : Error<
"'__pixel' must be preceded by '__vector'. "
"'%0' declaration specifier not allowed here">;
def err_invalid_vector_bool_decl_spec : Error<
"cannot use '%0' with '__vector bool'">;
def err_invalid_vector_long_decl_spec : Error<
"cannot use 'long' with '__vector'">;
def err_invalid_vector_float_decl_spec : Error<
"cannot use 'float' with '__vector'">;
def err_invalid_vector_double_decl_spec : Error <
"use of 'double' with '__vector' requires VSX support to be enabled "
"(available on POWER7 or later)">;
def err_invalid_vector_bool_int128_decl_spec : Error <
"use of '__int128' with '__vector bool' requires VSX support enabled (on "
"POWER10 or later)">;
def err_invalid_vector_int128_decl_spec : Error<
"use of '__int128' with '__vector' requires extended Altivec support"
" (available on POWER8 or later)">;
def err_invalid_vector_long_long_decl_spec : Error <
"use of 'long long' with '__vector' requires VSX support (available on "
"POWER7 or later) to be enabled">;
def err_invalid_vector_long_double_decl_spec : Error<
"cannot use 'long double' with '__vector'">;
def warn_vector_long_decl_spec_combination : Warning<
"Use of 'long' with '__vector' is deprecated">, InGroup<Deprecated>;
def err_redeclaration_different_type : Error<
"redeclaration of %0 with a different type%diff{: $ vs $|}1,2">;
def err_bad_variable_name : Error<
"%0 cannot be the name of a variable or data member">;
def err_bad_parameter_name : Error<
"%0 cannot be the name of a parameter">;
def err_bad_parameter_name_template_id : Error<
"parameter name cannot have template arguments">;
def ext_parameter_name_omitted_c2x : ExtWarn<
"omitting the parameter name in a function definition is a C2x extension">,
InGroup<C2x>;
def err_anyx86_interrupt_attribute : Error<
"%select{x86|x86-64}0 'interrupt' attribute only applies to functions that "
"have %select{a 'void' return type|"
"only a pointer parameter optionally followed by an integer parameter|"
"a pointer as the first parameter|a %2 type as the second parameter}1">;
def err_anyx86_interrupt_called : Error<
"interrupt service routine cannot be called directly">;
def warn_anyx86_interrupt_regsave : Warning<
"interrupt service routine should only call a function"
" with attribute 'no_caller_saved_registers'">,
InGroup<DiagGroup<"interrupt-service-routine">>;
def warn_arm_interrupt_calling_convention : Warning<
"call to function without interrupt attribute could clobber interruptee's VFP registers">,
InGroup<Extra>;
def warn_interrupt_attribute_invalid : Warning<
"%select{MIPS|MSP430|RISC-V}0 'interrupt' attribute only applies to "
"functions that have %select{no parameters|a 'void' return type}1">,
InGroup<IgnoredAttributes>;
def warn_riscv_repeated_interrupt_attribute : Warning<
"repeated RISC-V 'interrupt' attribute">, InGroup<IgnoredAttributes>;
def note_riscv_repeated_interrupt_attribute : Note<
"repeated RISC-V 'interrupt' attribute is here">;
def warn_unused_parameter : Warning<"unused parameter %0">,
InGroup<UnusedParameter>, DefaultIgnore;
def warn_unused_but_set_parameter : Warning<"parameter %0 set but not used">,
InGroup<UnusedButSetParameter>, DefaultIgnore;
def warn_unused_variable : Warning<"unused variable %0">,
InGroup<UnusedVariable>, DefaultIgnore;
def warn_unused_but_set_variable : Warning<"variable %0 set but not used">,
InGroup<UnusedButSetVariable>, DefaultIgnore;
def warn_unused_local_typedef : Warning<
"unused %select{typedef|type alias}0 %1">,
InGroup<UnusedLocalTypedef>, DefaultIgnore;
def warn_unused_property_backing_ivar :
Warning<"ivar %0 which backs the property is not "
"referenced in this property's accessor">,
InGroup<UnusedPropertyIvar>, DefaultIgnore;
def warn_unused_const_variable : Warning<"unused variable %0">,
InGroup<UnusedConstVariable>, DefaultIgnore;
def warn_unused_exception_param : Warning<"unused exception parameter %0">,
InGroup<UnusedExceptionParameter>, DefaultIgnore;
def warn_decl_in_param_list : Warning<
"declaration of %0 will not be visible outside of this function">,
InGroup<Visibility>;
def warn_redefinition_in_param_list : Warning<
"redefinition of %0 will not be visible outside of this function">,
InGroup<Visibility>;
def warn_empty_parens_are_function_decl : Warning<
"empty parentheses interpreted as a function declaration">,
InGroup<VexingParse>;
def warn_parens_disambiguated_as_function_declaration : Warning<
"parentheses were disambiguated as a function declaration">,
InGroup<VexingParse>;
def warn_parens_disambiguated_as_variable_declaration : Warning<
"parentheses were disambiguated as redundant parentheses around declaration "
"of variable named %0">, InGroup<VexingParse>;
def warn_redundant_parens_around_declarator : Warning<
"redundant parentheses surrounding declarator">,
InGroup<DiagGroup<"redundant-parens">>, DefaultIgnore;
def note_additional_parens_for_variable_declaration : Note<
"add a pair of parentheses to declare a variable">;
def note_raii_guard_add_name : Note<
"add a variable name to declare a %0 initialized with %1">;
def note_function_style_cast_add_parentheses : Note<
"add enclosing parentheses to perform a function-style cast">;
def note_remove_parens_for_variable_declaration : Note<
"remove parentheses to silence this warning">;
def note_empty_parens_function_call : Note<
"change this ',' to a ';' to call %0">;
def note_empty_parens_default_ctor : Note<
"remove parentheses to declare a variable">;
def note_empty_parens_zero_initialize : Note<
"replace parentheses with an initializer to declare a variable">;
def warn_unused_function : Warning<"unused function %0">,
InGroup<UnusedFunction>, DefaultIgnore;
def warn_unused_template : Warning<"unused %select{function|variable}0 template %1">,
InGroup<UnusedTemplate>, DefaultIgnore;
def warn_unused_member_function : Warning<"unused member function %0">,
InGroup<UnusedMemberFunction>, DefaultIgnore;
def warn_used_but_marked_unused: Warning<"%0 was marked unused but was used">,
InGroup<UsedButMarkedUnused>, DefaultIgnore;
def warn_unneeded_internal_decl : Warning<
"%select{function|variable}0 %1 is not needed and will not be emitted">,
InGroup<UnneededInternalDecl>, DefaultIgnore;
def warn_unneeded_static_internal_decl : Warning<
"'static' function %0 declared in header file "
"should be declared 'static inline'">,
InGroup<UnneededInternalDecl>, DefaultIgnore;
def warn_unneeded_member_function : Warning<
"member function %0 is not needed and will not be emitted">,
InGroup<UnneededMemberFunction>, DefaultIgnore;
def warn_unused_private_field: Warning<"private field %0 is not used">,
InGroup<UnusedPrivateField>, DefaultIgnore;
def warn_unused_lambda_capture: Warning<"lambda capture %0 is not "
"%select{used|required to be captured for this use}1">,
InGroup<UnusedLambdaCapture>, DefaultIgnore;
def warn_reserved_extern_symbol: Warning<
"identifier %0 is reserved because %select{"
"<ERROR>|" // ReservedIdentifierStatus::NotReserved
"it starts with '_' at global scope|"
"it starts with '_' and has C language linkage|"
"it starts with '__'|"
"it starts with '_' followed by a capital letter|"
"it contains '__'}1">,
InGroup<ReservedIdentifier>, DefaultIgnore;
def warn_parameter_size: Warning<
"%0 is a large (%1 bytes) pass-by-value argument; "
"pass it by reference instead ?">, InGroup<LargeByValueCopy>;
def warn_return_value_size: Warning<
"return value of %0 is a large (%1 bytes) pass-by-value object; "
"pass it by reference instead ?">, InGroup<LargeByValueCopy>;
def warn_return_value_udt: Warning<
"%0 has C-linkage specified, but returns user-defined type %1 which is "
"incompatible with C">, InGroup<ReturnTypeCLinkage>;
def warn_return_value_udt_incomplete: Warning<
"%0 has C-linkage specified, but returns incomplete type %1 which could be "
"incompatible with C">, InGroup<ReturnTypeCLinkage>;
def warn_implicit_function_decl : Warning<
"implicit declaration of function %0">,
InGroup<ImplicitFunctionDeclare>, DefaultIgnore;
def ext_implicit_function_decl_c99 : ExtWarn<
"call to undeclared function %0; ISO C99 and later do not support implicit "
- "function declarations">, InGroup<ImplicitFunctionDeclare>, DefaultError;
+ "function declarations">, InGroup<ImplicitFunctionDeclare>;
def note_function_suggestion : Note<"did you mean %0?">;
def err_ellipsis_first_param : Error<
"ISO C requires a named parameter before '...'">;
def err_declarator_need_ident : Error<"declarator requires an identifier">;
def err_language_linkage_spec_unknown : Error<"unknown linkage language">;
def err_language_linkage_spec_not_ascii : Error<
"string literal in language linkage specifier cannot have an "
"encoding-prefix">;
def ext_use_out_of_scope_declaration : ExtWarn<
"use of out-of-scope declaration of %0%select{| whose type is not "
"compatible with that of an implicit declaration}1">,
InGroup<DiagGroup<"out-of-scope-function">>;
def err_inline_non_function : Error<
"'inline' can only appear on functions%select{| and non-local variables}0">;
def err_noreturn_non_function : Error<
"'_Noreturn' can only appear on functions">;
def warn_qual_return_type : Warning<
"'%0' type qualifier%s1 on return type %plural{1:has|:have}1 no effect">,
InGroup<IgnoredQualifiers>, DefaultIgnore;
def warn_deprecated_redundant_constexpr_static_def : Warning<
"out-of-line definition of constexpr static data member is redundant "
"in C++17 and is deprecated">,
InGroup<Deprecated>, DefaultIgnore;
def warn_decl_shadow :
Warning<"declaration shadows a %select{"
"local variable|"
"variable in %2|"
"static data member of %2|"
"field of %2|"
"typedef in %2|"
"type alias in %2|"
"structured binding}1">,
InGroup<Shadow>, DefaultIgnore, SuppressInSystemMacro;
def warn_decl_shadow_uncaptured_local :
Warning<warn_decl_shadow.Text>,
InGroup<ShadowUncapturedLocal>, DefaultIgnore;
def warn_ctor_parm_shadows_field:
Warning<"constructor parameter %0 shadows the field %1 of %2">,
InGroup<ShadowFieldInConstructor>, DefaultIgnore;
def warn_modifying_shadowing_decl :
Warning<"modifying constructor parameter %0 that shadows a "
"field of %1">,
InGroup<ShadowFieldInConstructorModified>, DefaultIgnore;
// C++ decomposition declarations
def err_decomp_decl_context : Error<
"decomposition declaration not permitted in this context">;
def warn_cxx14_compat_decomp_decl : Warning<
"decomposition declarations are incompatible with "
"C++ standards before C++17">, DefaultIgnore, InGroup<CXXPre17Compat>;
def ext_decomp_decl : ExtWarn<
"decomposition declarations are a C++17 extension">, InGroup<CXX17>;
def ext_decomp_decl_cond : ExtWarn<
"ISO C++17 does not permit structured binding declaration in a condition">,
InGroup<DiagGroup<"binding-in-condition">>;
def err_decomp_decl_spec : Error<
"decomposition declaration cannot be declared "
"%plural{1:'%1'|:with '%1' specifiers}0">;
def ext_decomp_decl_spec : ExtWarn<
"decomposition declaration declared "
"%plural{1:'%1'|:with '%1' specifiers}0 is a C++20 extension">,
InGroup<CXX20>;
def warn_cxx17_compat_decomp_decl_spec : Warning<
"decomposition declaration declared "
"%plural{1:'%1'|:with '%1' specifiers}0 "
"is incompatible with C++ standards before C++20">,
InGroup<CXXPre20Compat>, DefaultIgnore;
def err_decomp_decl_type : Error<
"decomposition declaration cannot be declared with type %0; "
"declared type must be 'auto' or reference to 'auto'">;
def err_decomp_decl_parens : Error<
"decomposition declaration cannot be declared with parentheses">;
def err_decomp_decl_template : Error<
"decomposition declaration template not supported">;
def err_decomp_decl_not_alone : Error<
"decomposition declaration must be the only declaration in its group">;
def err_decomp_decl_requires_init : Error<
"decomposition declaration %0 requires an initializer">;
def err_decomp_decl_wrong_number_bindings : Error<
"type %0 decomposes into %3 %plural{1:element|:elements}2, but "
"%select{%plural{0:no|:only %1}1|%1}4 "
"%plural{1:name was|:names were}1 provided">;
def err_decomp_decl_unbindable_type : Error<
"cannot decompose %select{union|non-class, non-array}1 type %2">;
def err_decomp_decl_multiple_bases_with_members : Error<
"cannot decompose class type %1: "
"%select{its base classes %2 and|both it and its base class}0 %3 "
"have non-static data members">;
def err_decomp_decl_ambiguous_base : Error<
"cannot decompose members of ambiguous base class %1 of %0:%2">;
def err_decomp_decl_inaccessible_base : Error<
"cannot decompose members of inaccessible base class %1 of %0">,
AccessControl;
def err_decomp_decl_inaccessible_field : Error<
"cannot decompose %select{private|protected}0 member %1 of %3">,
AccessControl;
def err_decomp_decl_lambda : Error<
"cannot decompose lambda closure type">;
def err_decomp_decl_anon_union_member : Error<
"cannot decompose class type %0 because it has an anonymous "
"%select{struct|union}1 member">;
def err_decomp_decl_std_tuple_element_not_specialized : Error<
"cannot decompose this type; 'std::tuple_element<%0>::type' "
"does not name a type">;
def err_decomp_decl_std_tuple_size_not_constant : Error<
"cannot decompose this type; 'std::tuple_size<%0>::value' "
"is not a valid integral constant expression">;
def note_in_binding_decl_init : Note<
"in implicit initialization of binding declaration %0">;
def err_std_type_trait_not_class_template : Error<
"unsupported standard library implementation: "
"'std::%0' is not a class template">;
// C++ using declarations
def err_using_requires_qualname : Error<
"using declaration requires a qualified name">;
def err_using_typename_non_type : Error<
"'typename' keyword used on a non-type">;
def err_using_dependent_value_is_type : Error<
"dependent using declaration resolved to type without 'typename'">;
def err_using_decl_nested_name_specifier_is_not_class : Error<
"using declaration in class refers into '%0', which is not a class">;
def warn_cxx17_compat_using_decl_non_member_enumerator : Warning<
"member using declaration naming non-class '%0' enumerator is "
"incompatible with C++ standards before C++20">, InGroup<CXXPre20Compat>,
DefaultIgnore;
def err_using_decl_nested_name_specifier_is_current_class : Error<
"using declaration refers to its own class">;
def err_using_decl_nested_name_specifier_is_not_base_class : Error<
"using declaration refers into '%0', which is not a base class of %1">;
def err_using_decl_constructor_not_in_direct_base : Error<
"%0 is not a direct base of %1, cannot inherit constructors">;
def err_using_decl_can_not_refer_to_class_member : Error<
"using declaration cannot refer to class member">;
def warn_cxx17_compat_using_decl_class_member_enumerator : Warning<
"member using declaration naming a non-member enumerator is incompatible "
"with C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
def err_using_enum_is_dependent : Error<
"using-enum cannot name a dependent type">;
def err_ambiguous_inherited_constructor : Error<
"constructor of %0 inherited from multiple base class subobjects">;
def note_ambiguous_inherited_constructor_using : Note<
"inherited from base class %0 here">;
def note_using_decl_class_member_workaround : Note<
"use %select{an alias declaration|a typedef declaration|a reference|"
"a const variable|a constexpr variable}0 instead">;
def err_using_decl_can_not_refer_to_namespace : Error<
"using declaration cannot refer to a namespace">;
def warn_cxx17_compat_using_decl_scoped_enumerator: Warning<
"using declaration naming a scoped enumerator is incompatible with "
"C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
def ext_using_decl_scoped_enumerator : ExtWarn<
"using declaration naming a scoped enumerator is a C++20 extension">,
InGroup<CXX20>;
def err_using_decl_constructor : Error<
"using declaration cannot refer to a constructor">;
def warn_cxx98_compat_using_decl_constructor : Warning<
"inheriting constructors are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_using_decl_destructor : Error<
"using declaration cannot refer to a destructor">;
def err_using_decl_template_id : Error<
"using declaration cannot refer to a template specialization">;
def note_using_decl_target : Note<"target of using declaration">;
def note_using_decl_conflict : Note<"conflicting declaration">;
def err_using_decl_redeclaration : Error<"redeclaration of using declaration">;
def err_using_decl_conflict : Error<
"target of using declaration conflicts with declaration already in scope">;
def err_using_decl_conflict_reverse : Error<
"declaration conflicts with target of using declaration already in scope">;
def note_using_decl : Note<"%select{|previous }0using declaration">;
def err_using_decl_redeclaration_expansion : Error<
"using declaration pack expansion at block scope produces multiple values">;
def err_use_of_empty_using_if_exists : Error<
"reference to unresolved using declaration">;
def note_empty_using_if_exists_here : Note<
"using declaration annotated with 'using_if_exists' here">;
def err_using_if_exists_on_ctor : Error<
"'using_if_exists' attribute cannot be applied to an inheriting constructor">;
def err_using_enum_decl_redeclaration : Error<
"redeclaration of using-enum declaration">;
def note_using_enum_decl : Note<"%select{|previous }0using-enum declaration">;
def warn_access_decl_deprecated : Warning<
"access declarations are deprecated; use using declarations instead">,
InGroup<Deprecated>;
def err_access_decl : Error<
"ISO C++11 does not allow access declarations; "
"use using declarations instead">;
def warn_deprecated_copy : Warning<
"definition of implicit copy %select{constructor|assignment operator}1 "
"for %0 is deprecated because it has a user-declared copy "
"%select{assignment operator|constructor}1">,
InGroup<DeprecatedCopy>, DefaultIgnore;
def warn_deprecated_copy_with_dtor : Warning<
"definition of implicit copy %select{constructor|assignment operator}1 "
"for %0 is deprecated because it has a user-declared destructor">,
InGroup<DeprecatedCopyWithDtor>, DefaultIgnore;
def warn_deprecated_copy_with_user_provided_copy: Warning<
"definition of implicit copy %select{constructor|assignment operator}1 "
"for %0 is deprecated because it has a user-provided copy "
"%select{assignment operator|constructor}1">,
InGroup<DeprecatedCopyWithUserProvidedCopy>, DefaultIgnore;
def warn_deprecated_copy_with_user_provided_dtor : Warning<
"definition of implicit copy %select{constructor|assignment operator}1 "
"for %0 is deprecated because it has a user-provided destructor">,
InGroup<DeprecatedCopyWithUserProvidedDtor>, DefaultIgnore;
def warn_cxx17_compat_exception_spec_in_signature : Warning<
"mangled name of %0 will change in C++17 due to non-throwing exception "
"specification in function signature">, InGroup<CXX17CompatMangling>;
def warn_global_constructor : Warning<
"declaration requires a global constructor">,
InGroup<GlobalConstructors>, DefaultIgnore;
def warn_global_destructor : Warning<
"declaration requires a global destructor">,
InGroup<GlobalConstructors>, DefaultIgnore;
def warn_exit_time_destructor : Warning<
"declaration requires an exit-time destructor">,
InGroup<ExitTimeDestructors>, DefaultIgnore;
def err_invalid_thread : Error<
"'%0' is only allowed on variable declarations">;
def err_thread_non_global : Error<
"'%0' variables must have global storage">;
def err_thread_unsupported : Error<
"thread-local storage is not supported for the current target">;
// FIXME: Combine fallout warnings to just one warning.
def warn_maybe_falloff_nonvoid_function : Warning<
"non-void function does not return a value in all control paths">,
InGroup<ReturnType>;
def warn_falloff_nonvoid_function : Warning<
"non-void function does not return a value">,
InGroup<ReturnType>;
def err_maybe_falloff_nonvoid_block : Error<
"non-void block does not return a value in all control paths">;
def err_falloff_nonvoid_block : Error<
"non-void block does not return a value">;
def warn_maybe_falloff_nonvoid_coroutine : Warning<
"non-void coroutine does not return a value in all control paths">,
InGroup<ReturnType>;
def warn_falloff_nonvoid_coroutine : Warning<
"non-void coroutine does not return a value">,
InGroup<ReturnType>;
def warn_suggest_noreturn_function : Warning<
"%select{function|method}0 %1 could be declared with attribute 'noreturn'">,
InGroup<MissingNoreturn>, DefaultIgnore;
def warn_suggest_noreturn_block : Warning<
"block could be declared with attribute 'noreturn'">,
InGroup<MissingNoreturn>, DefaultIgnore;
// Unreachable code.
def warn_unreachable : Warning<
"code will never be executed">,
InGroup<UnreachableCode>, DefaultIgnore;
def warn_unreachable_break : Warning<
"'break' will never be executed">,
InGroup<UnreachableCodeBreak>, DefaultIgnore;
def warn_unreachable_return : Warning<
"'return' will never be executed">,
InGroup<UnreachableCodeReturn>, DefaultIgnore;
def warn_unreachable_loop_increment : Warning<
"loop will run at most once (loop increment never executed)">,
InGroup<UnreachableCodeLoopIncrement>, DefaultIgnore;
def warn_unreachable_fallthrough_attr : Warning<
"fallthrough annotation in unreachable code">,
InGroup<UnreachableCodeFallthrough>, DefaultIgnore;
def note_unreachable_silence : Note<
"silence by adding parentheses to mark code as explicitly dead">;
def warn_unreachable_association : Warning<
"due to lvalue conversion of the controlling expression, association of type "
"%0 will never be selected because it is %select{of array type|qualified}1">,
InGroup<UnreachableCodeGenericAssoc>;
/// Built-in functions.
def ext_implicit_lib_function_decl : ExtWarn<
"implicitly declaring library function '%0' with type %1">,
InGroup<ImplicitFunctionDeclare>;
def ext_implicit_lib_function_decl_c99 : ExtWarn<
"call to undeclared library function '%0' with type %1; ISO C99 and later "
"do not support implicit function declarations">,
- InGroup<ImplicitFunctionDeclare>, DefaultError;
+ InGroup<ImplicitFunctionDeclare>;
def note_include_header_or_declare : Note<
"include the header <%0> or explicitly provide a declaration for '%1'">;
def note_previous_builtin_declaration : Note<"%0 is a builtin with type %1">;
def warn_implicit_decl_no_jmp_buf
: Warning<"declaration of built-in function '%0' requires the declaration"
" of the 'jmp_buf' type, commonly provided in the header <setjmp.h>.">,
InGroup<DiagGroup<"incomplete-setjmp-declaration">>;
def warn_implicit_decl_requires_sysheader : Warning<
"declaration of built-in function '%1' requires inclusion of the header <%0>">,
InGroup<BuiltinRequiresHeader>;
def warn_redecl_library_builtin : Warning<
"incompatible redeclaration of library function %0">,
InGroup<DiagGroup<"incompatible-library-redeclaration">>;
def err_builtin_definition : Error<"definition of builtin function %0">;
def err_builtin_redeclare : Error<"cannot redeclare builtin function %0">;
def err_arm_invalid_specialreg : Error<"invalid special register for builtin">;
def err_arm_invalid_coproc : Error<"coprocessor %0 must be configured as "
"%select{GCP|CDE}1">;
def err_invalid_cpu_supports : Error<"invalid cpu feature string for builtin">;
def err_invalid_cpu_is : Error<"invalid cpu name for builtin">;
def err_invalid_cpu_specific_dispatch_value : Error<
"invalid option '%0' for %select{cpu_specific|cpu_dispatch}1">;
def warn_builtin_unknown : Warning<"use of unknown builtin %0">,
InGroup<ImplicitFunctionDeclare>, DefaultError;
def warn_cstruct_memaccess : Warning<
"%select{destination for|source of|first operand of|second operand of}0 this "
"%1 call is a pointer to record %2 that is not trivial to "
"%select{primitive-default-initialize|primitive-copy}3">,
InGroup<NonTrivialMemaccess>;
def note_nontrivial_field : Note<
"field is non-trivial to %select{copy|default-initialize}0">;
def err_non_trivial_c_union_in_invalid_context : Error<
"cannot %select{"
"use type %1 for a function/method parameter|"
"use type %1 for function/method return|"
"default-initialize an object of type %1|"
"declare an automatic variable of type %1|"
"copy-initialize an object of type %1|"
"assign to a variable of type %1|"
"construct an automatic compound literal of type %1|"
"capture a variable of type %1|"
"cannot use volatile type %1 where it causes an lvalue-to-rvalue conversion"
"}3 "
"since it %select{contains|is}2 a union that is non-trivial to "
"%select{default-initialize|destruct|copy}0">;
def note_non_trivial_c_union : Note<
"%select{%2 has subobjects that are|%3 has type %2 that is}0 "
"non-trivial to %select{default-initialize|destruct|copy}1">;
def warn_dyn_class_memaccess : Warning<
"%select{destination for|source of|first operand of|second operand of}0 this "
"%1 call is a pointer to %select{|class containing a }2dynamic class %3; "
"vtable pointer will be %select{overwritten|copied|moved|compared}4">,
InGroup<DynamicClassMemaccess>;
def note_bad_memaccess_silence : Note<
"explicitly cast the pointer to silence this warning">;
def warn_sizeof_pointer_expr_memaccess : Warning<
"'%0' call operates on objects of type %1 while the size is based on a "
"different type %2">,
InGroup<SizeofPointerMemaccess>;
def warn_sizeof_pointer_expr_memaccess_note : Note<
"did you mean to %select{dereference the argument to 'sizeof' (and multiply "
"it by the number of elements)|remove the addressof in the argument to "
"'sizeof' (and multiply it by the number of elements)|provide an explicit "
"length}0?">;
def warn_sizeof_pointer_type_memaccess : Warning<
"argument to 'sizeof' in %0 call is the same pointer type %1 as the "
"%select{destination|source}2; expected %3 or an explicit length">,
InGroup<SizeofPointerMemaccess>;
def warn_strlcpycat_wrong_size : Warning<
"size argument in %0 call appears to be size of the source; "
"expected the size of the destination">,
InGroup<DiagGroup<"strlcpy-strlcat-size">>;
def note_strlcpycat_wrong_size : Note<
"change size argument to be the size of the destination">;
def warn_memsize_comparison : Warning<
"size argument in %0 call is a comparison">,
InGroup<DiagGroup<"memsize-comparison">>;
def note_memsize_comparison_paren : Note<
"did you mean to compare the result of %0 instead?">;
def note_memsize_comparison_cast_silence : Note<
"explicitly cast the argument to size_t to silence this warning">;
def warn_suspicious_sizeof_memset : Warning<
"%select{'size' argument to memset is '0'|"
"setting buffer to a 'sizeof' expression}0"
"; did you mean to transpose the last two arguments?">,
InGroup<MemsetTransposedArgs>;
def note_suspicious_sizeof_memset_silence : Note<
"%select{parenthesize the third argument|"
"cast the second argument to 'int'}0 to silence">;
def warn_suspicious_bzero_size : Warning<"'size' argument to bzero is '0'">,
InGroup<SuspiciousBzero>;
def note_suspicious_bzero_size_silence : Note<
"parenthesize the second argument to silence">;
def warn_strncat_large_size : Warning<
"the value of the size argument in 'strncat' is too large, might lead to a "
"buffer overflow">, InGroup<StrncatSize>;
def warn_strncat_src_size : Warning<"size argument in 'strncat' call appears "
"to be size of the source">, InGroup<StrncatSize>;
def warn_strncat_wrong_size : Warning<
"the value of the size argument to 'strncat' is wrong">, InGroup<StrncatSize>;
def note_strncat_wrong_size : Note<
"change the argument to be the free space in the destination buffer minus "
"the terminating null byte">;
def warn_assume_side_effects : Warning<
"the argument to %0 has side effects that will be discarded">,
InGroup<DiagGroup<"assume">>;
def warn_assume_attribute_string_unknown : Warning<
"unknown assumption string '%0'; attribute is potentially ignored">,
InGroup<UnknownAssumption>;
def warn_assume_attribute_string_unknown_suggested : Warning<
"unknown assumption string '%0' may be misspelled; attribute is potentially "
"ignored, did you mean '%1'?">,
InGroup<MisspelledAssumption>;
def warn_builtin_chk_overflow : Warning<
"'%0' will always overflow; destination buffer has size %1,"
" but size argument is %2">,
InGroup<DiagGroup<"builtin-memcpy-chk-size">>;
def warn_fortify_source_overflow
: Warning<warn_builtin_chk_overflow.Text>, InGroup<FortifySource>;
def warn_fortify_source_size_mismatch : Warning<
"'%0' size argument is too large; destination buffer has size %1,"
" but size argument is %2">, InGroup<FortifySource>;
def warn_fortify_strlen_overflow: Warning<
"'%0' will always overflow; destination buffer has size %1,"
" but the source string has length %2 (including NUL byte)">,
InGroup<FortifySource>;
def warn_fortify_source_format_overflow : Warning<
"'%0' will always overflow; destination buffer has size %1,"
" but format string expands to at least %2">,
InGroup<FortifySource>;
def warn_fortify_scanf_overflow : Warning<
"'%0' may overflow; destination buffer in argument %1 has size "
"%2, but the corresponding specifier may require size %3">,
InGroup<FortifySource>;
def err_function_start_invalid_type: Error<
"argument must be a function">;
/// main()
// static main() is not an error in C, just in C++.
def warn_static_main : Warning<"'main' should not be declared static">,
InGroup<Main>;
def err_static_main : Error<"'main' is not allowed to be declared static">;
def err_inline_main : Error<"'main' is not allowed to be declared inline">;
def ext_variadic_main : ExtWarn<
"'main' is not allowed to be declared variadic">, InGroup<Main>;
def ext_noreturn_main : ExtWarn<
"'main' is not allowed to be declared _Noreturn">, InGroup<Main>;
def note_main_remove_noreturn : Note<"remove '_Noreturn'">;
def err_constexpr_main : Error<
"'main' is not allowed to be declared %select{constexpr|consteval}0">;
def err_deleted_main : Error<"'main' is not allowed to be deleted">;
def err_mainlike_template_decl : Error<"%0 cannot be a template">;
def err_main_returns_nonint : Error<"'main' must return 'int'">;
def ext_main_returns_nonint : ExtWarn<"return type of 'main' is not 'int'">,
InGroup<MainReturnType>;
def note_main_change_return_type : Note<"change return type to 'int'">;
def err_main_surplus_args : Error<"too many parameters (%0) for 'main': "
"must be 0, 2, or 3">;
def warn_main_one_arg : Warning<"only one parameter on 'main' declaration">,
InGroup<Main>;
def err_main_arg_wrong : Error<"%select{first|second|third|fourth}0 "
"parameter of 'main' (%select{argument count|argument array|environment|"
"platform-specific data}0) must be of type %1">;
def warn_main_returns_bool_literal : Warning<"bool literal returned from "
"'main'">, InGroup<Main>;
def err_main_global_variable :
Error<"main cannot be declared as global variable">;
def warn_main_redefined : Warning<"variable named 'main' with external linkage "
"has undefined behavior">, InGroup<Main>;
def ext_main_used : Extension<
"ISO C++ does not allow 'main' to be used by a program">, InGroup<Main>;
/// parser diagnostics
def ext_no_declarators : ExtWarn<"declaration does not declare anything">,
InGroup<MissingDeclarations>;
def err_no_declarators : Error<"declaration does not declare anything">;
def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">,
InGroup<MissingDeclarations>;
def err_typedef_not_identifier : Error<"typedef name must be an identifier">;
def ext_non_c_like_anon_struct_in_typedef : ExtWarn<
"anonymous non-C-compatible type given name for linkage purposes "
"by %select{typedef|alias}0 declaration; "
"add a tag name here">, InGroup<DiagGroup<"non-c-typedef-for-linkage">>;
def err_non_c_like_anon_struct_in_typedef : Error<
"anonymous non-C-compatible type given name for linkage purposes "
"by %select{typedef|alias}0 declaration after its linkage was computed; "
"add a tag name here to establish linkage prior to definition">;
def err_typedef_changes_linkage : Error<
"unsupported: anonymous type given name for linkage purposes "
"by %select{typedef|alias}0 declaration after its linkage was computed; "
"add a tag name here to establish linkage prior to definition">;
def note_non_c_like_anon_struct : Note<
"type is not C-compatible due to this "
"%select{base class|default member initializer|lambda expression|"
"friend declaration|member declaration}0">;
def note_typedef_for_linkage_here : Note<
"type is given name %0 for linkage purposes by this "
"%select{typedef|alias}1 declaration">;
def err_statically_allocated_object : Error<
"interface type cannot be statically allocated">;
def err_object_cannot_be_passed_returned_by_value : Error<
"interface type %1 cannot be %select{returned|passed}0 by value"
"; did you forget * in %1?">;
def err_parameters_retval_cannot_have_fp16_type : Error<
"%select{parameters|function return value}0 cannot have __fp16 type; did you forget * ?">;
def err_opencl_half_load_store : Error<
"%select{loading directly from|assigning directly to}0 pointer to type %1 requires "
"cl_khr_fp16. Use vector data %select{load|store}0 builtin functions instead">;
def err_opencl_cast_to_half : Error<"casting to type %0 is not allowed">;
def err_opencl_half_declaration : Error<
"declaring variable of type %0 is not allowed">;
def err_opencl_invalid_param : Error<
"declaring function parameter of type %0 is not allowed%select{; did you forget * ?|}1">;
def err_opencl_invalid_return : Error<
"declaring function return value of type %0 is not allowed %select{; did you forget * ?|}1">;
def warn_enum_value_overflow : Warning<"overflow in enumeration value">;
def warn_pragma_options_align_reset_failed : Warning<
"#pragma options align=reset failed: %0">,
InGroup<IgnoredPragmas>;
def err_pragma_options_align_mac68k_target_unsupported : Error<
"mac68k alignment pragma is not supported on this target">;
def warn_pragma_align_not_xl_compatible : Warning<
"#pragma align(packed) may not be compatible with objects generated with AIX XL C/C++">,
InGroup<AIXCompat>;
def warn_pragma_pack_invalid_alignment : Warning<
"expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">,
InGroup<IgnoredPragmas>;
def err_pragma_pack_invalid_alignment : Error<
warn_pragma_pack_invalid_alignment.Text>;
def warn_pragma_pack_non_default_at_include : Warning<
"non-default #pragma pack value changes the alignment of struct or union "
"members in the included file">, InGroup<PragmaPackSuspiciousInclude>,
DefaultIgnore;
def warn_pragma_pack_modified_after_include : Warning<
"the current #pragma pack alignment value is modified in the included "
"file">, InGroup<PragmaPack>;
def warn_pragma_pack_no_pop_eof : Warning<"unterminated "
"'#pragma pack (push, ...)' at end of file">, InGroup<PragmaPack>;
def note_pragma_pack_here : Note<
"previous '#pragma pack' directive that modifies alignment is here">;
def note_pragma_pack_pop_instead_reset : Note<
"did you intend to use '#pragma pack (pop)' instead of '#pragma pack()'?">;
// Follow the Microsoft implementation.
def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">;
def warn_pragma_pack_pop_identifier_and_alignment : Warning<
"specifying both a name and alignment to 'pop' is undefined">;
def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">,
InGroup<IgnoredPragmas>;
def err_pragma_fc_pp_scope : Error<
"'#pragma float_control push/pop' can only appear at file or namespace scope "
"or within a language linkage specification">;
def err_pragma_fc_noprecise_requires_nofenv : Error<
"'#pragma float_control(precise, off)' is illegal when fenv_access is enabled">;
def err_pragma_fc_except_requires_precise : Error<
"'#pragma float_control(except, on)' is illegal when precise is disabled">;
def err_pragma_fc_noprecise_requires_noexcept : Error<
"'#pragma float_control(precise, off)' is illegal when except is enabled">;
def err_pragma_fenv_requires_precise : Error<
"'#pragma STDC FENV_ACCESS ON' is illegal when precise is disabled">;
def warn_cxx_ms_struct :
Warning<"ms_struct may not produce Microsoft-compatible layouts for classes "
"with base classes or virtual functions">,
DefaultError, InGroup<IncompatibleMSStruct>;
def err_pragma_pack_identifer_not_supported : Error<
"specifying an identifier within `#pragma pack` is not supported on this target">;
def err_section_conflict : Error<"%0 causes a section type conflict with %1">;
def err_no_base_classes : Error<"invalid use of '__super', %0 has no base classes">;
def err_invalid_super_scope : Error<"invalid use of '__super', "
"this keyword can only be used inside class or member function scope">;
def err_super_in_lambda_unsupported : Error<
"use of '__super' inside a lambda is unsupported">;
def err_pragma_expected_file_scope : Error<
"'#pragma %0' can only appear at file scope">;
def err_pragma_alloc_text_c_linkage: Error<
"'#pragma alloc_text' is applicable only to functions with C linkage">;
def err_pragma_alloc_text_not_function: Error<
"'#pragma alloc_text' is applicable only to functions">;
def warn_pragma_unused_undeclared_var : Warning<
"undeclared variable %0 used as an argument for '#pragma unused'">,
InGroup<IgnoredPragmas>;
def warn_atl_uuid_deprecated : Warning<
"specifying 'uuid' as an ATL attribute is deprecated; use __declspec instead">,
InGroup<DeprecatedDeclarations>;
def warn_pragma_unused_expected_var_arg : Warning<
"only variables can be arguments to '#pragma unused'">,
InGroup<IgnoredPragmas>;
def err_pragma_push_visibility_mismatch : Error<
"#pragma visibility push with no matching #pragma visibility pop">;
def note_surrounding_namespace_ends_here : Note<
"surrounding namespace with visibility attribute ends here">;
def err_pragma_pop_visibility_mismatch : Error<
"#pragma visibility pop with no matching #pragma visibility push">;
def note_surrounding_namespace_starts_here : Note<
"surrounding namespace with visibility attribute starts here">;
def err_pragma_loop_invalid_argument_type : Error<
"invalid argument of type %0; expected an integer type">;
def err_pragma_loop_invalid_argument_value : Error<
"%select{invalid value '%0'; must be positive|value '%0' is too large}1">;
def err_pragma_loop_compatibility : Error<
"%select{incompatible|duplicate}0 directives '%1' and '%2'">;
def err_pragma_loop_precedes_nonloop : Error<
"expected a for, while, or do-while loop to follow '%0'">;
def err_pragma_attribute_matcher_subrule_contradicts_rule : Error<
"redundant attribute subject matcher sub-rule '%0'; '%1' already matches "
"those declarations">;
def err_pragma_attribute_matcher_negated_subrule_contradicts_subrule : Error<
"negated attribute subject matcher sub-rule '%0' contradicts sub-rule '%1'">;
def err_pragma_attribute_invalid_matchers : Error<
"attribute %0 can't be applied to %1">;
def err_pragma_attribute_stack_mismatch : Error<
"'#pragma clang attribute %select{%1.|}0pop' with no matching"
" '#pragma clang attribute %select{%1.|}0push'">;
def warn_pragma_attribute_unused : Warning<
"unused attribute %0 in '#pragma clang attribute push' region">,
InGroup<PragmaClangAttribute>;
def note_pragma_attribute_region_ends_here : Note<
"'#pragma clang attribute push' regions ends here">;
def err_pragma_attribute_no_pop_eof : Error<"unterminated "
"'#pragma clang attribute push' at end of file">;
def note_pragma_attribute_applied_decl_here : Note<
"when applied to this declaration">;
def err_pragma_attr_attr_no_push : Error<
"'#pragma clang attribute' attribute with no matching "
"'#pragma clang attribute push'">;
/// Objective-C parser diagnostics
def err_duplicate_class_def : Error<
"duplicate interface definition for class %0">;
def err_undef_superclass : Error<
"cannot find interface declaration for %0, superclass of %1">;
def err_forward_superclass : Error<
"attempting to use the forward class %0 as superclass of %1">;
def err_no_nsconstant_string_class : Error<
"cannot find interface declaration for %0">;
def err_recursive_superclass : Error<
"trying to recursively use %0 as superclass of %1">;
def err_conflicting_aliasing_type : Error<"conflicting types for alias %0">;
def warn_undef_interface : Warning<"cannot find interface declaration for %0">;
def warn_duplicate_protocol_def : Warning<
"duplicate protocol definition of %0 is ignored">,
InGroup<DiagGroup<"duplicate-protocol">>;
def err_protocol_has_circular_dependency : Error<
"protocol has circular dependency">;
def err_undeclared_protocol : Error<"cannot find protocol declaration for %0">;
def warn_undef_protocolref : Warning<"cannot find protocol definition for %0">;
def err_atprotocol_protocol : Error<
"@protocol is using a forward protocol declaration of %0">;
def warn_readonly_property : Warning<
"attribute 'readonly' of property %0 restricts attribute "
"'readwrite' of property inherited from %1">,
InGroup<PropertyAttr>;
def warn_property_attribute : Warning<
"'%1' attribute on property %0 does not match the property inherited from %2">,
InGroup<PropertyAttr>;
def warn_property_types_are_incompatible : Warning<
"property type %0 is incompatible with type %1 inherited from %2">,
InGroup<DiagGroup<"incompatible-property-type">>;
def warn_protocol_property_mismatch : Warning<
"property %select{of type %1|with attribute '%1'|without attribute '%1'|with "
"getter %1|with setter %1}0 was selected for synthesis">,
InGroup<DiagGroup<"protocol-property-synthesis-ambiguity">>;
def err_protocol_property_mismatch: Error<warn_protocol_property_mismatch.Text>;
def err_undef_interface : Error<"cannot find interface declaration for %0">;
def err_category_forward_interface : Error<
"cannot define %select{category|class extension}0 for undefined class %1">;
def err_class_extension_after_impl : Error<
"cannot declare class extension for %0 after class implementation">;
def note_implementation_declared : Note<
"class implementation is declared here">;
def note_while_in_implementation : Note<
"detected while default synthesizing properties in class implementation">;
def note_class_declared : Note<
"class is declared here">;
def note_receiver_class_declared : Note<
"receiver is instance of class declared here">;
def note_receiver_expr_here : Note<
"receiver expression is here">;
def note_receiver_is_id : Note<
"receiver is treated with 'id' type for purpose of method lookup">;
def note_suppressed_class_declare : Note<
"class with specified objc_requires_property_definitions attribute is declared here">;
def err_objc_root_class_subclass : Error<
"objc_root_class attribute may only be specified on a root class declaration">;
def err_restricted_superclass_mismatch : Error<
"cannot subclass a class that was declared with the "
"'objc_subclassing_restricted' attribute">;
def err_class_stub_subclassing_mismatch : Error<
"'objc_class_stub' attribute cannot be specified on a class that does not "
"have the 'objc_subclassing_restricted' attribute">;
def err_implementation_of_class_stub : Error<
"cannot declare implementation of a class declared with the "
"'objc_class_stub' attribute">;
def warn_objc_root_class_missing : Warning<
"class %0 defined without specifying a base class">,
InGroup<ObjCRootClass>;
def err_objc_runtime_visible_category : Error<
"cannot implement a category for class %0 that is only visible via the "
"Objective-C runtime">;
def err_objc_runtime_visible_subclass : Error<
"cannot implement subclass %0 of a superclass %1 that is only visible via the "
"Objective-C runtime">;
def note_objc_needs_superclass : Note<
"add a super class to fix this problem">;
def err_conflicting_super_class : Error<"conflicting super class name %0">;
def err_dup_implementation_class : Error<"reimplementation of class %0">;
def err_dup_implementation_category : Error<
"reimplementation of category %1 for class %0">;
def err_conflicting_ivar_type : Error<
"instance variable %0 has conflicting type%diff{: $ vs $|}1,2">;
def err_duplicate_ivar_declaration : Error<
"instance variable is already declared">;
def warn_on_superclass_use : Warning<
"class implementation may not have super class">;
def err_conflicting_ivar_bitwidth : Error<
"instance variable %0 has conflicting bit-field width">;
def err_conflicting_ivar_name : Error<
"conflicting instance variable names: %0 vs %1">;
def err_inconsistent_ivar_count : Error<
"inconsistent number of instance variables specified">;
def warn_undef_method_impl : Warning<"method definition for %0 not found">,
InGroup<DiagGroup<"incomplete-implementation">>;
def warn_objc_boxing_invalid_utf8_string : Warning<
"string is ill-formed as UTF-8 and will become a null %0 when boxed">,
InGroup<ObjCBoxing>;
def err_objc_non_runtime_protocol_in_protocol_expr : Error<
"cannot use a protocol declared 'objc_non_runtime_protocol' in a @protocol expression">;
def err_objc_direct_on_protocol : Error<
"'objc_direct' attribute cannot be applied to %select{methods|properties}0 "
"declared in an Objective-C protocol">;
def err_objc_direct_duplicate_decl : Error<
"%select{|direct }0%select{method|property}1 declaration conflicts "
"with previous %select{|direct }2declaration of %select{method|property}1 %3">;
def err_objc_direct_impl_decl_mismatch : Error<
"direct method was declared in %select{the primary interface|an extension|a category}0 "
"but is implemented in %select{the primary interface|a category|a different category}1">;
def err_objc_direct_missing_on_decl : Error<
"direct method implementation was previously declared not direct">;
def err_objc_direct_on_override : Error<
"methods that %select{override superclass methods|implement protocol requirements}0 cannot be direct">;
def err_objc_override_direct_method : Error<
"cannot override a method that is declared direct by a superclass">;
def warn_objc_direct_ignored : Warning<
"%0 attribute isn't implemented by this Objective-C runtime">,
InGroup<IgnoredAttributes>;
def warn_objc_direct_property_ignored : Warning<
"direct attribute on property %0 ignored (not implemented by this Objective-C runtime)">,
InGroup<IgnoredAttributes>;
def err_objc_direct_dynamic_property : Error<
"direct property cannot be @dynamic">;
def err_objc_direct_protocol_conformance : Error<
"%select{category %1|class extension}0 cannot conform to protocol %2 because "
"of direct members declared in interface %3">;
def note_direct_member_here : Note<"direct member declared here">;
def warn_conflicting_overriding_ret_types : Warning<
"conflicting return type in "
"declaration of %0%diff{: $ vs $|}1,2">,
InGroup<OverridingMethodMismatch>, DefaultIgnore;
def warn_conflicting_ret_types : Warning<
"conflicting return type in "
"implementation of %0%diff{: $ vs $|}1,2">,
InGroup<MismatchedReturnTypes>;
def warn_conflicting_overriding_ret_type_modifiers : Warning<
"conflicting distributed object modifiers on return type "
"in declaration of %0">,
InGroup<OverridingMethodMismatch>, DefaultIgnore;
def warn_conflicting_ret_type_modifiers : Warning<
"conflicting distributed object modifiers on return type "
"in implementation of %0">,
InGroup<DistributedObjectModifiers>;
def warn_non_covariant_overriding_ret_types : Warning<
"conflicting return type in "
"declaration of %0: %1 vs %2">,
InGroup<OverridingMethodMismatch>, DefaultIgnore;
def warn_non_covariant_ret_types : Warning<
"conflicting return type in "
"implementation of %0: %1 vs %2">,
InGroup<MethodSignatures>, DefaultIgnore;
def warn_conflicting_overriding_param_types : Warning<
"conflicting parameter types in "
"declaration of %0%diff{: $ vs $|}1,2">,
InGroup<OverridingMethodMismatch>, DefaultIgnore;
def warn_conflicting_param_types : Warning<
"conflicting parameter types in "
"implementation of %0%diff{: $ vs $|}1,2">,
InGroup<MismatchedParameterTypes>;
def warn_conflicting_param_modifiers : Warning<
"conflicting distributed object modifiers on parameter type "
"in implementation of %0">,
InGroup<DistributedObjectModifiers>;
def warn_conflicting_overriding_param_modifiers : Warning<
"conflicting distributed object modifiers on parameter type "
"in declaration of %0">,
InGroup<OverridingMethodMismatch>, DefaultIgnore;
def warn_non_contravariant_overriding_param_types : Warning<
"conflicting parameter types in "
"declaration of %0: %1 vs %2">,
InGroup<OverridingMethodMismatch>, DefaultIgnore;
def warn_non_contravariant_param_types : Warning<
"conflicting parameter types in "
"implementation of %0: %1 vs %2">,
InGroup<MethodSignatures>, DefaultIgnore;
def warn_conflicting_overriding_variadic :Warning<
"conflicting variadic declaration of method and its "
"implementation">,
InGroup<OverridingMethodMismatch>, DefaultIgnore;
def warn_conflicting_variadic :Warning<
"conflicting variadic declaration of method and its "
"implementation">;
def warn_category_method_impl_match:Warning<
"category is implementing a method which will also be implemented"
" by its primary class">, InGroup<ObjCProtocolMethodImpl>;
def warn_implements_nscopying : Warning<
"default assign attribute on property %0 which implements "
"NSCopying protocol is not appropriate with -fobjc-gc[-only]">;
def warn_multiple_method_decl : Warning<"multiple methods named %0 found">,
InGroup<ObjCMultipleMethodNames>;
def warn_strict_multiple_method_decl : Warning<
"multiple methods named %0 found">, InGroup<StrictSelector>, DefaultIgnore;
def warn_accessor_property_type_mismatch : Warning<
"type of property %0 does not match type of accessor %1">;
def note_conv_function_declared_at : Note<"type conversion function declared here">;
def note_method_declared_at : Note<"method %0 declared here">;
def note_direct_method_declared_at : Note<"direct method %0 declared here">;
def note_property_attribute : Note<"property %0 is declared "
"%select{deprecated|unavailable|partial}1 here">;
def err_setter_type_void : Error<"type of setter must be void">;
def err_duplicate_method_decl : Error<"duplicate declaration of method %0">;
def warn_duplicate_method_decl :
Warning<"multiple declarations of method %0 found and ignored">,
InGroup<MethodDuplicate>, DefaultIgnore;
def warn_objc_cdirective_format_string :
Warning<"using %0 directive in %select{NSString|CFString}1 "
"which is being passed as a formatting argument to the formatting "
"%select{method|CFfunction}2">,
InGroup<ObjCCStringFormat>, DefaultIgnore;
def err_objc_var_decl_inclass :
Error<"cannot declare variable inside @interface or @protocol">;
def err_missing_method_context : Error<
"missing context for method declaration">;
def err_objc_property_attr_mutually_exclusive : Error<
"property attributes '%0' and '%1' are mutually exclusive">;
def err_objc_property_requires_object : Error<
"property with '%0' attribute must be of object type">;
def warn_objc_property_assign_on_object : Warning<
"'assign' property of object type may become a dangling reference; consider using 'unsafe_unretained'">,
InGroup<ObjCPropertyAssignOnObjectType>, DefaultIgnore;
def warn_objc_property_no_assignment_attribute : Warning<
"no 'assign', 'retain', or 'copy' attribute is specified - "
"'assign' is assumed">,
InGroup<ObjCPropertyNoAttribute>;
def warn_objc_isa_use : Warning<
"direct access to Objective-C's isa is deprecated in favor of "
"object_getClass()">, InGroup<DeprecatedObjCIsaUsage>;
def warn_objc_isa_assign : Warning<
"assignment to Objective-C's isa is deprecated in favor of "
"object_setClass()">, InGroup<DeprecatedObjCIsaUsage>;
def warn_objc_pointer_masking : Warning<
"bitmasking for introspection of Objective-C object pointers is strongly "
"discouraged">,
InGroup<ObjCPointerIntrospect>;
def warn_objc_pointer_masking_performSelector : Warning<warn_objc_pointer_masking.Text>,
InGroup<ObjCPointerIntrospectPerformSelector>;
def warn_objc_property_default_assign_on_object : Warning<
"default property attribute 'assign' not appropriate for object">,
InGroup<ObjCPropertyNoAttribute>;
def warn_property_attr_mismatch : Warning<
"property attribute in class extension does not match the primary class">,
InGroup<PropertyAttr>;
def warn_property_implicitly_mismatched : Warning <
"primary property declaration is implicitly strong while redeclaration "
"in class extension is weak">,
InGroup<DiagGroup<"objc-property-implicit-mismatch">>;
def warn_objc_property_copy_missing_on_block : Warning<
"'copy' attribute must be specified for the block property "
"when -fobjc-gc-only is specified">;
def warn_objc_property_retain_of_block : Warning<
"retain'ed block property does not copy the block "
"- use copy attribute instead">, InGroup<ObjCRetainBlockProperty>;
def warn_objc_readonly_property_has_setter : Warning<
"setter cannot be specified for a readonly property">,
InGroup<ObjCReadonlyPropertyHasSetter>;
def warn_atomic_property_rule : Warning<
"writable atomic property %0 cannot pair a synthesized %select{getter|setter}1 "
"with a user defined %select{getter|setter}2">,
InGroup<DiagGroup<"atomic-property-with-user-defined-accessor">>;
def note_atomic_property_fixup_suggest : Note<"setter and getter must both be "
"synthesized, or both be user defined,or the property must be nonatomic">;
def err_atomic_property_nontrivial_assign_op : Error<
"atomic property of reference type %0 cannot have non-trivial assignment"
" operator">;
def warn_cocoa_naming_owned_rule : Warning<
"property follows Cocoa naming"
" convention for returning 'owned' objects">,
InGroup<DiagGroup<"objc-property-matches-cocoa-ownership-rule">>;
def err_cocoa_naming_owned_rule : Error<
"property follows Cocoa naming"
" convention for returning 'owned' objects">;
def note_cocoa_naming_declare_family : Note<
"explicitly declare getter %objcinstance0 with '%1' to return an 'unowned' "
"object">;
def warn_auto_synthesizing_protocol_property :Warning<
"auto property synthesis will not synthesize property %0"
" declared in protocol %1">,
InGroup<DiagGroup<"objc-protocol-property-synthesis">>;
def note_add_synthesize_directive : Note<
"add a '@synthesize' directive">;
def warn_no_autosynthesis_shared_ivar_property : Warning <
"auto property synthesis will not synthesize property "
"%0 because it cannot share an ivar with another synthesized property">,
InGroup<ObjCNoPropertyAutoSynthesis>;
def warn_no_autosynthesis_property : Warning<
"auto property synthesis will not synthesize property "
"%0 because it is 'readwrite' but it will be synthesized 'readonly' "
"via another property">,
InGroup<ObjCNoPropertyAutoSynthesis>;
def warn_autosynthesis_property_in_superclass : Warning<
"auto property synthesis will not synthesize property "
"%0; it will be implemented by its superclass, use @dynamic to "
"acknowledge intention">,
InGroup<ObjCNoPropertyAutoSynthesis>;
def warn_autosynthesis_property_ivar_match :Warning<
"autosynthesized property %0 will use %select{|synthesized}1 instance variable "
"%2, not existing instance variable %3">,
InGroup<DiagGroup<"objc-autosynthesis-property-ivar-name-match">>;
def warn_missing_explicit_synthesis : Warning <
"auto property synthesis is synthesizing property not explicitly synthesized">,
InGroup<DiagGroup<"objc-missing-property-synthesis">>, DefaultIgnore;
def warn_property_getter_owning_mismatch : Warning<
"property declared as returning non-retained objects"
"; getter returning retained objects">;
def warn_property_redecl_getter_mismatch : Warning<
"getter name mismatch between property redeclaration (%1) and its original "
"declaration (%0)">, InGroup<PropertyAttr>;
def err_property_setter_ambiguous_use : Error<
"synthesized properties %0 and %1 both claim setter %2 -"
" use of this setter will cause unexpected behavior">;
def warn_default_atomic_custom_getter_setter : Warning<
"atomic by default property %0 has a user defined %select{getter|setter}1 "
"(property should be marked 'atomic' if this is intended)">,
InGroup<CustomAtomic>, DefaultIgnore;
def err_use_continuation_class : Error<
"illegal redeclaration of property in class extension %0"
" (attribute must be 'readwrite', while its primary must be 'readonly')">;
def err_type_mismatch_continuation_class : Error<
"type of property %0 in class extension does not match "
"property type in primary class">;
def err_use_continuation_class_redeclaration_readwrite : Error<
"illegal redeclaration of 'readwrite' property in class extension %0"
" (perhaps you intended this to be a 'readwrite' redeclaration of a "
"'readonly' public property?)">;
def err_continuation_class : Error<"class extension has no primary class">;
def err_property_type : Error<"property cannot have array or function type %0">;
def err_missing_property_context : Error<
"missing context for property implementation declaration">;
def err_bad_property_decl : Error<
"property implementation must have its declaration in interface %0 or one of "
"its extensions">;
def err_category_property : Error<
"property declared in category %0 cannot be implemented in "
"class implementation">;
def note_property_declare : Note<
"property declared here">;
def note_protocol_property_declare : Note<
"it could also be property "
"%select{of type %1|without attribute '%1'|with attribute '%1'|with getter "
"%1|with setter %1}0 declared here">;
def note_property_synthesize : Note<
"property synthesized here">;
def err_synthesize_category_decl : Error<
"@synthesize not allowed in a category's implementation">;
def err_synthesize_on_class_property : Error<
"@synthesize not allowed on a class property %0">;
def err_missing_property_interface : Error<
"property implementation in a category with no category declaration">;
def err_bad_category_property_decl : Error<
"property implementation must have its declaration in the category %0">;
def err_bad_property_context : Error<
"property implementation must be in a class or category implementation">;
def err_missing_property_ivar_decl : Error<
"synthesized property %0 must either be named the same as a compatible"
" instance variable or must explicitly name an instance variable">;
def err_arc_perform_selector_retains : Error<
"performSelector names a selector which retains the object">;
def warn_arc_perform_selector_leaks : Warning<
"performSelector may cause a leak because its selector is unknown">,
InGroup<DiagGroup<"arc-performSelector-leaks">>;
def warn_dealloc_in_category : Warning<
"-dealloc is being overridden in a category">,
InGroup<DeallocInCategory>;
def err_gc_weak_property_strong_type : Error<
"weak attribute declared on a __strong type property in GC mode">;
def warn_arc_repeated_use_of_weak : Warning <
"weak %select{variable|property|implicit property|instance variable}0 %1 is "
"accessed multiple times in this %select{function|method|block|lambda}2 "
"but may be unpredictably set to nil; assign to a strong variable to keep "
"the object alive">,
InGroup<ARCRepeatedUseOfWeak>, DefaultIgnore;
def warn_implicitly_retains_self : Warning <
"block implicitly retains 'self'; explicitly mention 'self' to indicate "
"this is intended behavior">,
InGroup<DiagGroup<"implicit-retain-self">>, DefaultIgnore;
def warn_arc_possible_repeated_use_of_weak : Warning <
"weak %select{variable|property|implicit property|instance variable}0 %1 may "
"be accessed multiple times in this %select{function|method|block|lambda}2 "
"and may be unpredictably set to nil; assign to a strong variable to keep "
"the object alive">,
InGroup<ARCRepeatedUseOfWeakMaybe>, DefaultIgnore;
def note_arc_weak_also_accessed_here : Note<
"also accessed here">;
def err_incomplete_synthesized_property : Error<
"cannot synthesize property %0 with incomplete type %1">;
def err_property_ivar_type : Error<
"type of property %0 (%1) does not match type of instance variable %2 (%3)">;
def err_property_accessor_type : Error<
"type of property %0 (%1) does not match type of accessor %2 (%3)">;
def err_ivar_in_superclass_use : Error<
"property %0 attempting to use instance variable %1 declared in super class %2">;
def err_weak_property : Error<
"existing instance variable %1 for __weak property %0 must be __weak">;
def err_strong_property : Error<
"existing instance variable %1 for strong property %0 may not be __weak">;
def err_dynamic_property_ivar_decl : Error<
"dynamic property cannot have instance variable specification">;
def err_duplicate_ivar_use : Error<
"synthesized properties %0 and %1 both claim instance variable %2">;
def err_property_implemented : Error<"property %0 is already implemented">;
def warn_objc_missing_super_call : Warning<
"method possibly missing a [super %0] call">,
InGroup<ObjCMissingSuperCalls>;
def err_dealloc_bad_result_type : Error<
"dealloc return type must be correctly specified as 'void' under ARC, "
"instead of %0">;
def warn_undeclared_selector : Warning<
"undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore;
def warn_undeclared_selector_with_typo : Warning<
"undeclared selector %0; did you mean %1?">,
InGroup<UndeclaredSelector>, DefaultIgnore;
def warn_implicit_atomic_property : Warning<
"property is assumed atomic by default">, InGroup<ImplicitAtomic>, DefaultIgnore;
def note_auto_readonly_iboutlet_fixup_suggest : Note<
"property should be changed to be readwrite">;
def warn_auto_readonly_iboutlet_property : Warning<
"readonly IBOutlet property %0 when auto-synthesized may "
"not work correctly with 'nib' loader">,
InGroup<DiagGroup<"readonly-iboutlet-property">>;
def warn_auto_implicit_atomic_property : Warning<
"property is assumed atomic when auto-synthesizing the property">,
InGroup<ImplicitAtomic>, DefaultIgnore;
def warn_unimplemented_selector: Warning<
"no method with selector %0 is implemented in this translation unit">,
InGroup<Selector>, DefaultIgnore;
def warn_unimplemented_protocol_method : Warning<
"method %0 in protocol %1 not implemented">, InGroup<Protocol>;
def warn_multiple_selectors: Warning<
"several methods with selector %0 of mismatched types are found "
"for the @selector expression">,
InGroup<SelectorTypeMismatch>, DefaultIgnore;
def err_direct_selector_expression : Error<
"@selector expression formed with direct selector %0">;
def warn_potentially_direct_selector_expression : Warning<
"@selector expression formed with potentially direct selector %0">,
InGroup<ObjCPotentiallyDirectSelector>;
def warn_strict_potentially_direct_selector_expression : Warning<
warn_potentially_direct_selector_expression.Text>,
InGroup<ObjCStrictPotentiallyDirectSelector>, DefaultIgnore;
def err_objc_kindof_nonobject : Error<
"'__kindof' specifier cannot be applied to non-object type %0">;
def err_objc_kindof_wrong_position : Error<
"'__kindof' type specifier must precede the declarator">;
def err_objc_method_unsupported_param_ret_type : Error<
"%0 %select{parameter|return}1 type is unsupported; "
"support for vector types for this target is introduced in %2">;
def warn_messaging_unqualified_id : Warning<
"messaging unqualified id">, DefaultIgnore,
InGroup<DiagGroup<"objc-messaging-id">>;
def err_messaging_unqualified_id_with_direct_method : Error<
"messaging unqualified id with a method that is possibly direct">;
def err_messaging_super_with_direct_method : Error<
"messaging super with a direct method">;
def err_messaging_class_with_direct_method : Error<
"messaging a Class with a method that is possibly direct">;
// C++ declarations
def err_static_assert_expression_is_not_constant : Error<
"static assertion expression is not an integral constant expression">;
def err_constexpr_if_condition_expression_is_not_constant : Error<
"constexpr if condition is not a constant expression">;
def err_static_assert_failed : Error<"static assertion failed%select{: %1|}0">;
def err_static_assert_requirement_failed : Error<
"static assertion failed due to requirement '%0'%select{: %2|}1">;
def warn_consteval_if_always_true : Warning<
"consteval if is always true in an %select{unevaluated|immediate}0 context">,
InGroup<DiagGroup<"redundant-consteval-if">>;
def ext_inline_variable : ExtWarn<
"inline variables are a C++17 extension">, InGroup<CXX17>;
def warn_cxx14_compat_inline_variable : Warning<
"inline variables are incompatible with C++ standards before C++17">,
DefaultIgnore, InGroup<CXXPre17Compat>;
def warn_inline_namespace_reopened_noninline : Warning<
"inline namespace reopened as a non-inline namespace">,
InGroup<InlineNamespaceReopenedNoninline>;
def err_inline_namespace_mismatch : Error<
"non-inline namespace cannot be reopened as inline">;
def err_unexpected_friend : Error<
"friends can only be classes or functions">;
def ext_enum_friend : ExtWarn<
"befriending enumeration type %0 is a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_enum_friend : Warning<
"befriending enumeration type %0 is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def ext_nonclass_type_friend : ExtWarn<
"non-class friend type %0 is a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_nonclass_type_friend : Warning<
"non-class friend type %0 is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_friend_is_member : Error<
"friends cannot be members of the declaring class">;
def warn_cxx98_compat_friend_is_member : Warning<
"friend declaration naming a member of the declaring class is incompatible "
"with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def ext_unelaborated_friend_type : ExtWarn<
"unelaborated friend declaration is a C++11 extension; specify "
"'%select{struct|interface|union|class|enum}0' to befriend %1">,
InGroup<CXX11>;
def warn_cxx98_compat_unelaborated_friend_type : Warning<
"befriending %1 without '%select{struct|interface|union|class|enum}0' "
"keyword is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def err_qualified_friend_no_match : Error<
"friend declaration of %0 does not match any declaration in %1">;
def err_introducing_special_friend : Error<
"%plural{[0,2]:must use a qualified name when declaring|3:cannot declare}0"
" a %select{constructor|destructor|conversion operator|deduction guide}0 "
"as a friend">;
def err_tagless_friend_type_template : Error<
"friend type templates must use an elaborated type">;
def err_no_matching_local_friend : Error<
"no matching function found in local scope">;
def err_no_matching_local_friend_suggest : Error<
"no matching function %0 found in local scope; did you mean %3?">;
def err_partial_specialization_friend : Error<
"partial specialization cannot be declared as a friend">;
def err_qualified_friend_def : Error<
"friend function definition cannot be qualified with '%0'">;
def err_friend_def_in_local_class : Error<
"friend function cannot be defined in a local class">;
def err_friend_not_first_in_declaration : Error<
"'friend' must appear first in a non-function declaration">;
def err_using_decl_friend : Error<
"cannot befriend target of using declaration">;
def warn_template_qualified_friend_unsupported : Warning<
"dependent nested name specifier '%0' for friend class declaration is "
"not supported; turning off access control for %1">,
InGroup<UnsupportedFriend>;
def warn_template_qualified_friend_ignored : Warning<
"dependent nested name specifier '%0' for friend template declaration is "
"not supported; ignoring this friend declaration">,
InGroup<UnsupportedFriend>;
def ext_friend_tag_redecl_outside_namespace : ExtWarn<
"unqualified friend declaration referring to type outside of the nearest "
"enclosing namespace is a Microsoft extension; add a nested name specifier">,
InGroup<MicrosoftUnqualifiedFriend>;
def err_pure_friend : Error<"friend declaration cannot have a pure-specifier">;
def err_invalid_base_in_interface : Error<
"interface type cannot inherit from "
"%select{struct|non-public interface|class}0 %1">;
def err_abstract_type_in_decl : Error<
"%select{return|parameter|variable|field|instance variable|"
"synthesized instance variable}0 type %1 is an abstract class">;
def err_allocation_of_abstract_type : Error<
"allocating an object of abstract class type %0">;
def err_throw_abstract_type : Error<
"cannot throw an object of abstract type %0">;
def err_array_of_abstract_type : Error<"array of abstract class type %0">;
def err_capture_of_abstract_type : Error<
"by-copy capture of value of abstract type %0">;
def err_capture_of_incomplete_or_sizeless_type : Error<
"by-copy capture of variable %0 with %select{incomplete|sizeless}1 type %2">;
def err_capture_default_non_local : Error<
"non-local lambda expression cannot have a capture-default">;
def err_multiple_final_overriders : Error<
"virtual function %q0 has more than one final overrider in %1">;
def note_final_overrider : Note<"final overrider of %q0 in %1">;
def err_type_defined_in_type_specifier : Error<
"%0 cannot be defined in a type specifier">;
def err_type_defined_in_result_type : Error<
"%0 cannot be defined in the result type of a function">;
def err_type_defined_in_param_type : Error<
"%0 cannot be defined in a parameter type">;
def err_type_defined_in_alias_template : Error<
"%0 cannot be defined in a type alias template">;
def err_type_defined_in_condition : Error<
"%0 cannot be defined in a condition">;
def err_type_defined_in_enum : Error<
"%0 cannot be defined in an enumeration">;
def note_pure_virtual_function : Note<
"unimplemented pure virtual method %0 in %1">;
def note_pure_qualified_call_kext : Note<
"qualified call to %0::%1 is treated as a virtual call to %1 due to -fapple-kext">;
def err_deleted_decl_not_first : Error<
"deleted definition must be first declaration">;
def err_deleted_override : Error<
"deleted function %0 cannot override a non-deleted function">;
def err_non_deleted_override : Error<
"non-deleted function %0 cannot override a deleted function">;
def err_consteval_override : Error<
"consteval function %0 cannot override a non-consteval function">;
def err_non_consteval_override : Error<
"non-consteval function %0 cannot override a consteval function">;
def warn_weak_vtable : Warning<
"%0 has no out-of-line virtual method definitions; its vtable will be "
"emitted in every translation unit">,
InGroup<DiagGroup<"weak-vtables">>, DefaultIgnore;
def warn_weak_template_vtable : Warning<
"this warning is no longer in use and will be removed in the next release">,
InGroup<DiagGroup<"weak-template-vtables">>, DefaultIgnore;
def ext_using_undefined_std : ExtWarn<
"using directive refers to implicitly-defined namespace 'std'">;
// C++ exception specifications
def err_exception_spec_in_typedef : Error<
"exception specifications are not allowed in %select{typedefs|type aliases}0">;
def err_distant_exception_spec : Error<
"exception specifications are not allowed beyond a single level "
"of indirection">;
def err_incomplete_in_exception_spec : Error<
"%select{|pointer to |reference to }0incomplete type %1 is not allowed "
"in exception specification">;
def err_sizeless_in_exception_spec : Error<
"%select{|reference to }0sizeless type %1 is not allowed "
"in exception specification">;
def ext_incomplete_in_exception_spec : ExtWarn<err_incomplete_in_exception_spec.Text>,
InGroup<MicrosoftExceptionSpec>;
def err_rref_in_exception_spec : Error<
"rvalue reference type %0 is not allowed in exception specification">;
def err_mismatched_exception_spec : Error<
"exception specification in declaration does not match previous declaration">;
def ext_mismatched_exception_spec : ExtWarn<err_mismatched_exception_spec.Text>,
InGroup<MicrosoftExceptionSpec>;
def err_override_exception_spec : Error<
"exception specification of overriding function is more lax than "
"base version">;
def ext_override_exception_spec : ExtWarn<err_override_exception_spec.Text>,
InGroup<MicrosoftExceptionSpec>;
def err_incompatible_exception_specs : Error<
"target exception specification is not superset of source">;
def warn_incompatible_exception_specs : Warning<
err_incompatible_exception_specs.Text>, InGroup<IncompatibleExceptionSpec>;
def err_deep_exception_specs_differ : Error<
"exception specifications of %select{return|argument}0 types differ">;
def warn_deep_exception_specs_differ : Warning<
err_deep_exception_specs_differ.Text>, InGroup<IncompatibleExceptionSpec>;
def err_missing_exception_specification : Error<
"%0 is missing exception specification '%1'">;
def ext_missing_exception_specification : ExtWarn<
err_missing_exception_specification.Text>,
InGroup<DiagGroup<"missing-exception-spec">>;
def err_exception_spec_not_parsed : Error<
"exception specification is not available until end of class definition">;
def err_exception_spec_cycle : Error<
"exception specification of %0 uses itself">;
def err_exception_spec_incomplete_type : Error<
"exception specification needed for member of incomplete class %0">;
def warn_wasm_dynamic_exception_spec_ignored : ExtWarn<
"dynamic exception specifications with types are currently ignored in wasm">,
InGroup<WebAssemblyExceptionSpec>;
// C++ access checking
def err_class_redeclared_with_different_access : Error<
"%0 redeclared with '%1' access">;
def err_access : Error<
"%1 is a %select{private|protected}0 member of %3">, AccessControl;
def ext_ms_using_declaration_inaccessible : ExtWarn<
"using declaration referring to inaccessible member '%0' (which refers "
"to accessible member '%1') is a Microsoft compatibility extension">,
AccessControl, InGroup<MicrosoftUsingDecl>;
def err_access_ctor : Error<
"calling a %select{private|protected}0 constructor of class %2">,
AccessControl;
def ext_rvalue_to_reference_access_ctor : Extension<
"C++98 requires an accessible copy constructor for class %2 when binding "
"a reference to a temporary; was %select{private|protected}0">,
AccessControl, InGroup<BindToTemporaryCopy>;
def err_access_base_ctor : Error<
// The ERRORs represent other special members that aren't constructors, in
// hopes that someone will bother noticing and reporting if they appear
"%select{base class|inherited virtual base class}0 %1 has %select{private|"
"protected}3 %select{default |copy |move |*ERROR* |*ERROR* "
"|*ERROR*|}2constructor">, AccessControl;
def err_access_field_ctor : Error<
// The ERRORs represent other special members that aren't constructors, in
// hopes that someone will bother noticing and reporting if they appear
"field of type %0 has %select{private|protected}2 "
"%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}1constructor">,
AccessControl;
def err_access_friend_function : Error<
"friend function %1 is a %select{private|protected}0 member of %3">,
AccessControl;
def err_access_dtor : Error<
"calling a %select{private|protected}1 destructor of class %0">,
AccessControl;
def err_access_dtor_base :
Error<"base class %0 has %select{private|protected}1 destructor">,
AccessControl;
def err_access_dtor_vbase :
Error<"inherited virtual base class %1 has "
"%select{private|protected}2 destructor">,
AccessControl;
def err_access_dtor_temp :
Error<"temporary of type %0 has %select{private|protected}1 destructor">,
AccessControl;
def err_access_dtor_exception :
Error<"exception object of type %0 has %select{private|protected}1 "
"destructor">, AccessControl;
def err_access_dtor_field :
Error<"field of type %1 has %select{private|protected}2 destructor">,
AccessControl;
def err_access_dtor_var :
Error<"variable of type %1 has %select{private|protected}2 destructor">,
AccessControl;
def err_access_dtor_ivar :
Error<"instance variable of type %0 has %select{private|protected}1 "
"destructor">,
AccessControl;
def note_previous_access_declaration : Note<
"previously declared '%1' here">;
def note_access_natural : Note<
"%select{|implicitly }1declared %select{private|protected}0 here">;
def note_access_constrained_by_path : Note<
"constrained by %select{|implicitly }1%select{private|protected}0"
" inheritance here">;
def note_access_protected_restricted_noobject : Note<
"must name member using the type of the current context %0">;
def note_access_protected_restricted_ctordtor : Note<
"protected %select{constructor|destructor}0 can only be used to "
"%select{construct|destroy}0 a base class subobject">;
def note_access_protected_restricted_object : Note<
"can only access this member on an object of type %0">;
def warn_cxx98_compat_sfinae_access_control : Warning<
"substitution failure due to access control is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore, NoSFINAE;
// C++ name lookup
def err_incomplete_nested_name_spec : Error<
"incomplete type %0 named in nested name specifier">;
def err_incomplete_enum : Error<
"enumeration %0 is incomplete">;
def err_dependent_nested_name_spec : Error<
"nested name specifier for a declaration cannot depend on a template "
"parameter">;
def err_nested_name_member_ref_lookup_ambiguous : Error<
"lookup of %0 in member access expression is ambiguous">;
def ext_nested_name_member_ref_lookup_ambiguous : ExtWarn<
"lookup of %0 in member access expression is ambiguous; using member of %1">,
InGroup<AmbigMemberTemplate>;
def note_ambig_member_ref_object_type : Note<
"lookup in the object type %0 refers here">;
def note_ambig_member_ref_scope : Note<
"lookup from the current scope refers here">;
def err_qualified_member_nonclass : Error<
"qualified member access refers to a member in %0">;
def err_incomplete_member_access : Error<
"member access into incomplete type %0">;
def err_incomplete_type : Error<
"incomplete type %0 where a complete type is required">;
def warn_cxx98_compat_enum_nested_name_spec : Warning<
"enumeration type in nested name specifier is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_nested_name_spec_is_not_class : Error<
"%0 cannot appear before '::' because it is not a class"
"%select{ or namespace|, namespace, or enumeration}1; did you mean ':'?">;
def ext_nested_name_spec_is_enum : ExtWarn<
"use of enumeration in a nested name specifier is a C++11 extension">,
InGroup<CXX11>;
def err_out_of_line_qualified_id_type_names_constructor : Error<
"qualified reference to %0 is a constructor name rather than a "
"%select{template name|type}1 in this context">;
def ext_out_of_line_qualified_id_type_names_constructor : ExtWarn<
"ISO C++ specifies that "
"qualified reference to %0 is a constructor name rather than a "
"%select{template name|type}1 in this context, despite preceding "
"%select{'typename'|'template'}2 keyword">, SFINAEFailure,
InGroup<DiagGroup<"injected-class-name">>;
// C++ class members
def err_storageclass_invalid_for_member : Error<
"storage class specified for a member declaration">;
def err_mutable_function : Error<"'mutable' cannot be applied to functions">;
def err_mutable_reference : Error<"'mutable' cannot be applied to references">;
def ext_mutable_reference : ExtWarn<
"'mutable' on a reference type is a Microsoft extension">,
InGroup<MicrosoftMutableReference>;
def err_mutable_const : Error<"'mutable' and 'const' cannot be mixed">;
def err_mutable_nonmember : Error<
"'mutable' can only be applied to member variables">;
def err_virtual_in_union : Error<
"unions cannot have virtual functions">;
def err_virtual_non_function : Error<
"'virtual' can only appear on non-static member functions">;
def err_virtual_out_of_class : Error<
"'virtual' can only be specified inside the class definition">;
def err_virtual_member_function_template : Error<
"'virtual' cannot be specified on member function templates">;
def err_static_overrides_virtual : Error<
"'static' member function %0 overrides a virtual function in a base class">;
def err_explicit_non_function : Error<
"'explicit' can only appear on non-static member functions">;
def err_explicit_out_of_class : Error<
"'explicit' can only be specified inside the class definition">;
def err_explicit_non_ctor_or_conv_function : Error<
"'explicit' can only be applied to a constructor or conversion function">;
def err_static_not_bitfield : Error<"static member %0 cannot be a bit-field">;
def err_static_out_of_line : Error<
"'static' can only be specified inside the class definition">;
def ext_static_out_of_line : ExtWarn<
err_static_out_of_line.Text>,
InGroup<MicrosoftTemplate>;
def err_storage_class_for_static_member : Error<
"static data member definition cannot specify a storage class">;
def err_typedef_not_bitfield : Error<"typedef member %0 cannot be a bit-field">;
def err_not_integral_type_bitfield : Error<
"bit-field %0 has non-integral type %1">;
def err_not_integral_type_anon_bitfield : Error<
"anonymous bit-field has non-integral type %0">;
def err_anon_bitfield_qualifiers : Error<
"anonymous bit-field cannot have qualifiers">;
def err_member_function_initialization : Error<
"initializer on function does not look like a pure-specifier">;
def err_non_virtual_pure : Error<
"%0 is not virtual and cannot be declared pure">;
def ext_pure_function_definition : ExtWarn<
"function definition with pure-specifier is a Microsoft extension">,
InGroup<MicrosoftPureDefinition>;
def err_qualified_member_of_unrelated : Error<
"%q0 is not a member of class %1">;
def err_member_function_call_bad_cvr : Error<
"'this' argument to member function %0 has type %1, but function is not marked "
"%select{const|restrict|const or restrict|volatile|const or volatile|"
"volatile or restrict|const, volatile, or restrict}2">;
def err_member_function_call_bad_ref : Error<
"'this' argument to member function %0 is an %select{lvalue|rvalue}1, "
"but function has %select{non-const lvalue|rvalue}2 ref-qualifier">;
def err_member_function_call_bad_type : Error<
"cannot initialize object parameter of type %0 with an expression "
"of type %1">;
def warn_call_to_pure_virtual_member_function_from_ctor_dtor : Warning<
"call to pure virtual member function %0 has undefined behavior; "
"overrides of %0 in subclasses are not available in the "
"%select{constructor|destructor}1 of %2">, InGroup<PureVirtualCallFromCtorDtor>;
def select_special_member_kind : TextSubstitution<
"%select{default constructor|copy constructor|move constructor|"
"copy assignment operator|move assignment operator|destructor}0">;
def note_member_declared_at : Note<"member is declared here">;
def note_ivar_decl : Note<"instance variable is declared here">;
def note_bitfield_decl : Note<"bit-field is declared here">;
def note_implicit_param_decl : Note<"%0 is an implicit parameter">;
def note_member_synthesized_at : Note<
"in %select{implicit|defaulted}0 %sub{select_special_member_kind}1 for %2 "
"first required here">;
def note_comparison_synthesized_at : Note<
"in defaulted %sub{select_defaulted_comparison_kind}0 for %1 "
"first required here">;
def err_missing_default_ctor : Error<
"%select{constructor for %1 must explicitly initialize the|"
"implicit default constructor for %1 must explicitly initialize the|"
"cannot use constructor inherited from base class %4;}0 "
"%select{base class|member}2 %3 %select{which|which|of %1}0 "
"does not have a default constructor">;
def note_due_to_dllexported_class : Note<
"due to %0 being dllexported%select{|; try compiling in C++11 mode}1">;
def err_illegal_union_or_anon_struct_member : Error<
"%select{anonymous struct|union}0 member %1 has a non-trivial "
"%sub{select_special_member_kind}2">;
def warn_frame_address : Warning<
"calling '%0' with a nonzero argument is unsafe">,
InGroup<FrameAddress>, DefaultIgnore;
def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning<
"%select{anonymous struct|union}0 member %1 with a non-trivial "
"%sub{select_special_member_kind}2 is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def note_nontrivial_virtual_dtor : Note<
"destructor for %0 is not trivial because it is virtual">;
def note_nontrivial_has_virtual : Note<
"because type %0 has a virtual %select{member function|base class}1">;
def note_nontrivial_no_def_ctor : Note<
"because %select{base class of |field of |}0type %1 has no "
"default constructor">;
def note_user_declared_ctor : Note<
"implicit default constructor suppressed by user-declared constructor">;
def note_nontrivial_no_copy : Note<
"because no %select{<<ERROR>>|constructor|constructor|assignment operator|"
"assignment operator|<<ERROR>>}2 can be used to "
"%select{<<ERROR>>|copy|move|copy|move|<<ERROR>>}2 "
"%select{base class|field|an object}0 of type %3">;
def note_nontrivial_user_provided : Note<
"because %select{base class of |field of |}0type %1 has a user-provided "
"%sub{select_special_member_kind}2">;
def note_nontrivial_default_member_init : Note<
"because field %0 has an initializer">;
def note_nontrivial_param_type : Note<
"because its parameter is %diff{of type $, not $|of the wrong type}2,3">;
def note_nontrivial_default_arg : Note<"because it has a default argument">;
def note_nontrivial_variadic : Note<"because it is a variadic function">;
def note_nontrivial_subobject : Note<
"because the function selected to %select{construct|copy|move|copy|move|"
"destroy}2 %select{base class|field}0 of type %1 is not trivial">;
def note_nontrivial_objc_ownership : Note<
"because type %0 has a member with %select{no|no|__strong|__weak|"
"__autoreleasing}1 ownership">;
/// Selector for a TagTypeKind value.
def select_tag_type_kind : TextSubstitution<
"%select{struct|interface|union|class|enum}0">;
def err_static_data_member_not_allowed_in_anon_struct : Error<
"static data member %0 not allowed in anonymous "
"%sub{select_tag_type_kind}1">;
def ext_static_data_member_in_union : ExtWarn<
"static data member %0 in union is a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_static_data_member_in_union : Warning<
"static data member %0 in union is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def ext_union_member_of_reference_type : ExtWarn<
"union member %0 has reference type %1, which is a Microsoft extension">,
InGroup<MicrosoftUnionMemberReference>;
def err_union_member_of_reference_type : Error<
"union member %0 has reference type %1">;
def ext_anonymous_struct_union_qualified : Extension<
"anonymous %select{struct|union}0 cannot be '%1'">;
def err_different_return_type_for_overriding_virtual_function : Error<
"virtual function %0 has a different return type "
"%diff{($) than the function it overrides (which has return type $)|"
"than the function it overrides}1,2">;
def note_overridden_virtual_function : Note<
"overridden virtual function is here">;
def err_conflicting_overriding_cc_attributes : Error<
"virtual function %0 has different calling convention attributes "
"%diff{($) than the function it overrides (which has calling convention $)|"
"than the function it overrides}1,2">;
def warn_overriding_method_missing_noescape : Warning<
"parameter of overriding method should be annotated with "
"__attribute__((noescape))">, InGroup<MissingNoEscape>;
def note_overridden_marked_noescape : Note<
"parameter of overridden method is annotated with __attribute__((noescape))">;
def note_cat_conform_to_noescape_prot : Note<
"%select{category|class extension}0 conforms to protocol %1 which defines method %2">;
def err_covariant_return_inaccessible_base : Error<
"invalid covariant return for virtual function: %1 is a "
"%select{private|protected}2 base class of %0">, AccessControl;
def err_covariant_return_ambiguous_derived_to_base_conv : Error<
"return type of virtual function %3 is not covariant with the return type of "
"the function it overrides (ambiguous conversion from derived class "
"%0 to base class %1:%2)">;
def err_covariant_return_not_derived : Error<
"return type of virtual function %0 is not covariant with the return type of "
"the function it overrides (%1 is not derived from %2)">;
def err_covariant_return_incomplete : Error<
"return type of virtual function %0 is not covariant with the return type of "
"the function it overrides (%1 is incomplete)">;
def err_covariant_return_type_different_qualifications : Error<
"return type of virtual function %0 is not covariant with the return type of "
"the function it overrides (%1 has different qualifiers than %2)">;
def err_covariant_return_type_class_type_more_qualified : Error<
"return type of virtual function %0 is not covariant with the return type of "
"the function it overrides (class type %1 is more qualified than class "
"type %2">;
// C++ implicit special member functions
def note_in_declaration_of_implicit_special_member : Note<
"while declaring the implicit %sub{select_special_member_kind}1"
" for %0">;
// C++ constructors
def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">;
def err_invalid_qualified_constructor : Error<
"'%0' qualifier is not allowed on a constructor">;
def err_ref_qualifier_constructor : Error<
"ref-qualifier '%select{&&|&}0' is not allowed on a constructor">;
def err_constructor_return_type : Error<
"constructor cannot have a return type">;
def err_constructor_redeclared : Error<"constructor cannot be redeclared">;
def err_constructor_byvalue_arg : Error<
"copy constructor must pass its first argument by reference">;
def warn_no_constructor_for_refconst : Warning<
"%select{struct|interface|union|class|enum}0 %1 does not declare any "
"constructor to initialize its non-modifiable members">;
def note_refconst_member_not_initialized : Note<
"%select{const|reference}0 member %1 will never be initialized">;
def ext_ms_explicit_constructor_call : ExtWarn<
"explicit constructor calls are a Microsoft extension">,
InGroup<MicrosoftExplicitConstructorCall>;
// C++ destructors
def err_destructor_not_member : Error<
"destructor must be a non-static member function">;
def err_destructor_cannot_be : Error<"destructor cannot be declared '%0'">;
def err_invalid_qualified_destructor : Error<
"'%0' qualifier is not allowed on a destructor">;
def err_ref_qualifier_destructor : Error<
"ref-qualifier '%select{&&|&}0' is not allowed on a destructor">;
def err_destructor_return_type : Error<"destructor cannot have a return type">;
def err_destructor_redeclared : Error<"destructor cannot be redeclared">;
def err_destructor_with_params : Error<"destructor cannot have any parameters">;
def err_destructor_variadic : Error<"destructor cannot be variadic">;
def ext_destructor_typedef_name : ExtWarn<
"destructor cannot be declared using a %select{typedef|type alias}1 %0 "
"of the class name">, DefaultError, InGroup<DiagGroup<"dtor-typedef">>;
def err_undeclared_destructor_name : Error<
"undeclared identifier %0 in destructor name">;
def err_destructor_name : Error<
"expected the class name after '~' to name the enclosing class">;
def err_destructor_name_nontype : Error<
"identifier %0 after '~' in destructor name does not name a type">;
def err_destructor_expr_mismatch : Error<
"identifier %0 in object destruction expression does not name the type "
"%1 of the object being destroyed">;
def err_destructor_expr_nontype : Error<
"identifier %0 in object destruction expression does not name a type">;
def err_destructor_expr_type_mismatch : Error<
"destructor type %0 in object destruction expression does not match the "
"type %1 of the object being destroyed">;
def note_destructor_type_here : Note<
"type %0 found by destructor name lookup">;
def note_destructor_nontype_here : Note<
"non-type declaration found by destructor name lookup">;
def ext_dtor_named_in_wrong_scope : Extension<
"ISO C++ requires the name after '::~' to be found in the same scope as "
"the name before '::~'">, InGroup<DtorName>;
def ext_qualified_dtor_named_in_lexical_scope : ExtWarn<
"qualified destructor name only found in lexical scope; omit the qualifier "
"to find this type name by unqualified lookup">, InGroup<DtorName>;
def ext_dtor_name_ambiguous : Extension<
"ISO C++ considers this destructor name lookup to be ambiguous">,
InGroup<DtorName>;
def err_destroy_attr_on_non_static_var : Error<
"%select{no_destroy|always_destroy}0 attribute can only be applied to a"
" variable with static or thread storage duration">;
def err_destructor_template : Error<
"destructor cannot be declared as a template">;
// C++ initialization
def err_init_conversion_failed : Error<
"cannot initialize %select{a variable|a parameter|template parameter|"
"return object|statement expression result|an "
"exception object|a member subobject|an array element|a new value|a value|a "
"base class|a constructor delegation|a vector element|a block element|a "
"block element|a complex element|a lambda capture|a compound literal "
"initializer|a related result|a parameter of CF audited function}0 "
"%diff{of type $ with an %select{rvalue|lvalue}2 of type $|"
"with an %select{rvalue|lvalue}2 of incompatible type}1,3"
"%select{|: different classes%diff{ ($ vs $)|}5,6"
"|: different number of parameters (%5 vs %6)"
"|: type mismatch at %ordinal5 parameter%diff{ ($ vs $)|}6,7"
"|: different return type%diff{ ($ vs $)|}5,6"
"|: different qualifiers (%5 vs %6)"
"|: different exception specifications}4">;
def note_forward_class_conversion : Note<"%0 is not defined, but forward "
"declared here; conversion would be valid if it was derived from %1">;
def err_lvalue_to_rvalue_ref : Error<"rvalue reference %diff{to type $ cannot "
"bind to lvalue of type $|cannot bind to incompatible lvalue}0,1">;
def err_lvalue_reference_bind_to_initlist : Error<
"%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to an "
"initializer list temporary">;
def err_lvalue_reference_bind_to_temporary : Error<
"%select{non-const|volatile}0 lvalue reference %diff{to type $ cannot bind "
"to a temporary of type $|cannot bind to incompatible temporary}1,2">;
def err_lvalue_reference_bind_to_unrelated : Error<
"%select{non-const|volatile}0 lvalue reference "
"%diff{to type $ cannot bind to a value of unrelated type $|"
"cannot bind to a value of unrelated type}1,2">;
def err_reference_bind_drops_quals : Error<
"binding reference %diff{of type $ to value of type $|to value}0,1 "
"%select{drops %3 qualifier%plural{1:|2:|4:|:s}4|changes address space|"
"not permitted due to incompatible qualifiers}2">;
def err_reference_bind_failed : Error<
"reference %diff{to %select{type|incomplete type}1 $ could not bind to an "
"%select{rvalue|lvalue}2 of type $|could not bind to %select{rvalue|lvalue}2 of "
"incompatible type}0,3">;
def err_reference_bind_temporary_addrspace : Error<
"reference of type %0 cannot bind to a temporary object because of "
"address space mismatch">;
def err_reference_bind_init_list : Error<
"reference to type %0 cannot bind to an initializer list">;
def err_init_list_bad_dest_type : Error<
"%select{|non-aggregate }0type %1 cannot be initialized with an initializer "
"list">;
def warn_cxx20_compat_aggregate_init_with_ctors : Warning<
"aggregate initialization of type %0 with user-declared constructors "
"is incompatible with C++20">, DefaultIgnore, InGroup<CXX20Compat>;
def err_reference_bind_to_bitfield : Error<
"%select{non-const|volatile}0 reference cannot bind to "
"bit-field%select{| %1}2">;
def err_reference_bind_to_vector_element : Error<
"%select{non-const|volatile}0 reference cannot bind to vector element">;
def err_reference_bind_to_matrix_element : Error<
"%select{non-const|volatile}0 reference cannot bind to matrix element">;
def err_reference_var_requires_init : Error<
"declaration of reference variable %0 requires an initializer">;
def err_reference_without_init : Error<
"reference to type %0 requires an initializer">;
def note_value_initialization_here : Note<
"in value-initialization of type %0 here">;
def err_reference_has_multiple_inits : Error<
"reference cannot be initialized with multiple values">;
def err_init_non_aggr_init_list : Error<
"initialization of non-aggregate type %0 with an initializer list">;
def err_init_reference_member_uninitialized : Error<
"reference member of type %0 uninitialized">;
def note_uninit_reference_member : Note<
"uninitialized reference member is here">;
def warn_field_is_uninit : Warning<"field %0 is uninitialized when used here">,
InGroup<Uninitialized>;
def warn_base_class_is_uninit : Warning<
"base class %0 is uninitialized when used here to access %q1">,
InGroup<Uninitialized>;
def warn_reference_field_is_uninit : Warning<
"reference %0 is not yet bound to a value when used here">,
InGroup<Uninitialized>;
def note_uninit_in_this_constructor : Note<
"during field initialization in %select{this|the implicit default}0 "
"constructor">;
def warn_static_self_reference_in_init : Warning<
"static variable %0 is suspiciously used within its own initialization">,
InGroup<UninitializedStaticSelfInit>;
def warn_uninit_self_reference_in_init : Warning<
"variable %0 is uninitialized when used within its own initialization">,
InGroup<Uninitialized>;
def warn_uninit_self_reference_in_reference_init : Warning<
"reference %0 is not yet bound to a value when used within its own"
" initialization">,
InGroup<Uninitialized>;
def warn_uninit_var : Warning<
"variable %0 is uninitialized when %select{used here|captured by block}1">,
InGroup<Uninitialized>, DefaultIgnore;
def warn_sometimes_uninit_var : Warning<
"variable %0 is %select{used|captured}1 uninitialized whenever "
"%select{'%3' condition is %select{true|false}4|"
"'%3' loop %select{is entered|exits because its condition is false}4|"
"'%3' loop %select{condition is true|exits because its condition is false}4|"
"switch %3 is taken|"
"its declaration is reached|"
"%3 is called}2">,
InGroup<UninitializedSometimes>, DefaultIgnore;
def warn_maybe_uninit_var : Warning<
"variable %0 may be uninitialized when "
"%select{used here|captured by block}1">,
InGroup<UninitializedMaybe>, DefaultIgnore;
def note_var_declared_here : Note<"variable %0 is declared here">;
def note_uninit_var_use : Note<
"%select{uninitialized use occurs|variable is captured by block}0 here">;
def warn_uninit_byref_blockvar_captured_by_block : Warning<
"block pointer variable %0 is %select{uninitialized|null}1 when captured by "
"block">, InGroup<Uninitialized>, DefaultIgnore;
def note_block_var_fixit_add_initialization : Note<
"did you mean to use __block %0?">;
def note_in_omitted_aggregate_initializer : Note<
"in implicit initialization of %select{"
"array element %1 with omitted initializer|"
"field %1 with omitted initializer|"
"trailing array elements in runtime-sized array new}0">;
def note_in_reference_temporary_list_initializer : Note<
"in initialization of temporary of type %0 created to "
"list-initialize this reference">;
def note_var_fixit_add_initialization : Note<
"initialize the variable %0 to silence this warning">;
def note_uninit_fixit_remove_cond : Note<
"remove the %select{'%1' if its condition|condition if it}0 "
"is always %select{false|true}2">;
def err_init_incomplete_type : Error<"initialization of incomplete type %0">;
def err_list_init_in_parens : Error<
"cannot initialize %select{non-class|reference}0 type %1 with a "
"parenthesized initializer list">;
def warn_uninit_const_reference : Warning<
"variable %0 is uninitialized when passed as a const reference argument "
"here">, InGroup<UninitializedConstReference>, DefaultIgnore;
def warn_unsequenced_mod_mod : Warning<
"multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
def warn_unsequenced_mod_use : Warning<
"unsequenced modification and access to %0">, InGroup<Unsequenced>;
def select_initialized_entity_kind : TextSubstitution<
"%select{copying variable|copying parameter|initializing template parameter|"
"returning object|initializing statement expression result|"
"throwing object|copying member subobject|copying array element|"
"allocating object|copying temporary|initializing base subobject|"
"initializing vector element|capturing value}0">;
def err_temp_copy_no_viable : Error<
"no viable constructor %sub{select_initialized_entity_kind}0 of type %1">;
def ext_rvalue_to_reference_temp_copy_no_viable : Extension<
"no viable constructor %sub{select_initialized_entity_kind}0 of type %1; "
"C++98 requires a copy constructor when binding a reference to a temporary">,
InGroup<BindToTemporaryCopy>;
def err_temp_copy_ambiguous : Error<
"ambiguous constructor call when %sub{select_initialized_entity_kind}0 "
"of type %1">;
def err_temp_copy_deleted : Error<
"%sub{select_initialized_entity_kind}0 of type %1 "
"invokes deleted constructor">;
def err_temp_copy_incomplete : Error<
"copying a temporary object of incomplete type %0">;
def warn_cxx98_compat_temp_copy : Warning<
"%sub{select_initialized_entity_kind}1 "
"of type %2 when binding a reference to a temporary would %select{invoke "
"an inaccessible constructor|find no viable constructor|find ambiguous "
"constructors|invoke a deleted constructor}0 in C++98">,
InGroup<CXX98CompatBindToTemporaryCopy>, DefaultIgnore;
def err_selected_explicit_constructor : Error<
"chosen constructor is explicit in copy-initialization">;
def note_explicit_ctor_deduction_guide_here : Note<
"explicit %select{constructor|deduction guide}0 declared here">;
// C++11 decltype
def err_decltype_in_declarator : Error<
"'decltype' cannot be used to name a declaration">;
// C++11 auto
def warn_cxx98_compat_auto_type_specifier : Warning<
"'auto' type specifier is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_auto_variable_cannot_appear_in_own_initializer : Error<
"variable %0 declared with deduced type %1 "
"cannot appear in its own initializer">;
def err_binding_cannot_appear_in_own_initializer : Error<
"binding %0 cannot appear in the initializer of its own "
"decomposition declaration">;
def err_illegal_decl_array_of_auto : Error<
"'%0' declared as array of %1">;
def err_new_array_of_auto : Error<
"cannot allocate array of 'auto'">;
def err_auto_not_allowed : Error<
"%select{'auto'|'decltype(auto)'|'__auto_type'|"
"use of "
"%select{class template|function template|variable template|alias template|"
"template template parameter|concept|template}2 %3 requires template "
"arguments; argument deduction}0 not allowed "
"%select{in function prototype"
"|in non-static struct member|in struct member"
"|in non-static union member|in union member"
"|in non-static class member|in interface member"
"|in exception declaration|in template parameter until C++17|in block literal"
"|in template argument|in typedef|in type alias|in function return type"
"|in conversion function type|here|in lambda parameter"
"|in type allocated by 'new'|in K&R-style function parameter"
"|in template parameter|in friend declaration|in function prototype that is "
"not a function declaration|in requires expression parameter}1">;
def err_dependent_deduced_tst : Error<
"typename specifier refers to "
"%select{class template|function template|variable template|alias template|"
"template template parameter|template}0 member in %1; "
"argument deduction not allowed here">;
def err_deduced_tst : Error<
"typename specifier refers to "
"%select{class template|function template|variable template|alias template|"
"template template parameter|template}0; argument deduction not allowed "
"here">;
def err_auto_not_allowed_var_inst : Error<
"'auto' variable template instantiation is not allowed">;
def err_auto_var_requires_init : Error<
"declaration of variable %0 with deduced type %1 requires an initializer">;
def err_auto_new_requires_ctor_arg : Error<
"new expression for type %0 requires a constructor argument">;
def ext_auto_new_list_init : Extension<
"ISO C++ standards before C++17 do not allow new expression for "
"type %0 to use list-initialization">, InGroup<CXX17>;
def err_auto_var_init_no_expression : Error<
"initializer for variable %0 with type %1 is empty">;
def err_auto_expr_init_no_expression : Error<
"initializer for functional-style cast to %0 is empty">;
def err_auto_var_init_multiple_expressions : Error<
"initializer for variable %0 with type %1 contains multiple expressions">;
def err_auto_expr_init_multiple_expressions : Error<
"initializer for functional-style cast to %0 contains multiple expressions">;
def err_auto_var_init_paren_braces : Error<
"cannot deduce type for variable %1 with type %2 from "
"%select{parenthesized|nested}0 initializer list">;
def err_auto_new_ctor_multiple_expressions : Error<
"new expression for type %0 contains multiple constructor arguments">;
def err_auto_expr_init_paren_braces : Error<
"cannot deduce actual type for %1 from "
"%select{parenthesized|nested}0 initializer list">;
def warn_cxx20_compat_auto_expr : Warning<
"'auto' as a functional-style cast is incompatible with C++ standards "
"before C++2b">, InGroup<CXXPre2bCompat>, DefaultIgnore;
def err_auto_missing_trailing_return : Error<
"'auto' return without trailing return type; deduced return types are a "
"C++14 extension">;
def err_deduced_return_type : Error<
"deduced return types are a C++14 extension">;
def err_trailing_return_without_auto : Error<
"function with trailing return type must specify return type 'auto', not %0">;
def err_trailing_return_in_parens : Error<
"trailing return type may not be nested within parentheses">;
def err_auto_var_deduction_failure : Error<
"variable %0 with type %1 has incompatible initializer of type %2">;
def err_auto_var_deduction_failure_from_init_list : Error<
"cannot deduce actual type for variable %0 with type %1 from initializer list">;
def err_auto_expr_deduction_failure : Error<
"functional-style cast to %0 has incompatible initializer of type %1">;
def err_auto_new_deduction_failure : Error<
"new expression for type %0 has incompatible constructor argument of type %1">;
def err_auto_inconsistent_deduction : Error<
"deduced conflicting types %diff{($ vs $) |}0,1"
"for initializer list element type">;
def err_auto_different_deductions : Error<
"%select{'auto'|'decltype(auto)'|'__auto_type'|template arguments}0 "
"deduced as %1 in declaration of %2 and "
"deduced as %3 in declaration of %4">;
def err_auto_non_deduced_not_alone : Error<
"%select{function with deduced return type|"
"declaration with trailing return type}0 "
"must be the only declaration in its group">;
def err_implied_std_initializer_list_not_found : Error<
"cannot deduce type of initializer list because std::initializer_list was "
"not found; include <initializer_list>">;
def err_malformed_std_initializer_list : Error<
"std::initializer_list must be a class template with a single type parameter">;
def err_auto_init_list_from_c : Error<
"cannot use __auto_type with initializer list in C">;
def err_auto_bitfield : Error<
"cannot pass bit-field as __auto_type initializer in C">;
// C++1y decltype(auto) type
def err_decltype_auto_invalid : Error<
"'decltype(auto)' not allowed here">;
def err_decltype_auto_cannot_be_combined : Error<
"'decltype(auto)' cannot be combined with other type specifiers">;
def err_decltype_auto_function_declarator_not_declaration : Error<
"'decltype(auto)' can only be used as a return type "
"in a function declaration">;
def err_decltype_auto_compound_type : Error<
"cannot form %select{pointer to|reference to|array of}0 'decltype(auto)'">;
def err_decltype_auto_initializer_list : Error<
"cannot deduce 'decltype(auto)' from initializer list">;
// C++17 deduced class template specialization types
def err_deduced_class_template_compound_type : Error<
"cannot %select{form pointer to|form reference to|form array of|"
"form function returning|use parentheses when declaring variable with}0 "
"deduced class template specialization type">;
def err_deduced_non_class_template_specialization_type : Error<
"%select{<error>|function template|variable template|alias template|"
"template template parameter|concept|template}0 %1 requires template "
"arguments; argument deduction only allowed for class templates">;
def err_deduced_class_template_ctor_ambiguous : Error<
"ambiguous deduction for template arguments of %0">;
def err_deduced_class_template_ctor_no_viable : Error<
"no viable constructor or deduction guide for deduction of "
"template arguments of %0">;
def err_deduced_class_template_incomplete : Error<
"template %0 has no definition and no %select{|viable }1deduction guides "
"for deduction of template arguments">;
def err_deduced_class_template_deleted : Error<
"class template argument deduction for %0 selected a deleted constructor">;
def err_deduced_class_template_explicit : Error<
"class template argument deduction for %0 selected an explicit "
"%select{constructor|deduction guide}1 for copy-list-initialization">;
def err_deduction_guide_no_trailing_return_type : Error<
"deduction guide declaration without trailing return type">;
def err_deduction_guide_bad_trailing_return_type : Error<
"deduced type %1 of deduction guide is not %select{|written as }2"
"a specialization of template %0">;
def err_deduction_guide_with_complex_decl : Error<
"cannot specify any part of a return type in the "
"declaration of a deduction guide">;
def err_deduction_guide_invalid_specifier : Error<
"deduction guide cannot be declared '%0'">;
def err_deduction_guide_name_not_class_template : Error<
"cannot specify deduction guide for "
"%select{<error>|function template|variable template|alias template|"
"template template parameter|concept|dependent template name}0 %1">;
def err_deduction_guide_wrong_scope : Error<
"deduction guide must be declared in the same scope as template %q0">;
def err_deduction_guide_defines_function : Error<
"deduction guide cannot have a function definition">;
def err_deduction_guide_redeclared : Error<
"redeclaration of deduction guide">;
def err_deduction_guide_specialized : Error<"deduction guide cannot be "
"%select{explicitly instantiated|explicitly specialized}0">;
def err_deduction_guide_template_not_deducible : Error<
"deduction guide template contains "
"%select{a template parameter|template parameters}0 that cannot be "
"deduced">;
def err_deduction_guide_wrong_access : Error<
"deduction guide has different access from the corresponding "
"member template">;
def note_deduction_guide_template_access : Note<
"member template declared %0 here">;
def note_deduction_guide_access : Note<
"deduction guide declared %0 by intervening access specifier">;
def warn_cxx14_compat_class_template_argument_deduction : Warning<
"class template argument deduction is incompatible with C++ standards "
"before C++17%select{|; for compatibility, use explicit type name %1}0">,
InGroup<CXXPre17Compat>, DefaultIgnore;
def warn_ctad_maybe_unsupported : Warning<
"%0 may not intend to support class template argument deduction">,
InGroup<CTADMaybeUnsupported>, DefaultIgnore;
def note_suppress_ctad_maybe_unsupported : Note<
"add a deduction guide to suppress this warning">;
// C++14 deduced return types
def err_auto_fn_deduction_failure : Error<
"cannot deduce return type %0 from returned value of type %1">;
def err_auto_fn_different_deductions : Error<
"'%select{auto|decltype(auto)}0' in return type deduced as %1 here but "
"deduced as %2 in earlier return statement">;
def err_auto_fn_used_before_defined : Error<
"function %0 with deduced return type cannot be used before it is defined">;
def err_auto_fn_no_return_but_not_auto : Error<
"cannot deduce return type %0 for function with no return statements">;
def err_auto_fn_return_void_but_not_auto : Error<
"cannot deduce return type %0 from omitted return expression">;
def err_auto_fn_return_init_list : Error<
"cannot deduce return type from initializer list">;
def err_auto_fn_virtual : Error<
"function with deduced return type cannot be virtual">;
def warn_cxx11_compat_deduced_return_type : Warning<
"return type deduction is incompatible with C++ standards before C++14">,
InGroup<CXXPre14Compat>, DefaultIgnore;
// C++11 override control
def override_keyword_only_allowed_on_virtual_member_functions : Error<
"only virtual member functions can be marked '%0'">;
def override_keyword_hides_virtual_member_function : Error<
"non-virtual member function marked '%0' hides virtual member "
"%select{function|functions}1">;
def err_function_marked_override_not_overriding : Error<
"%0 marked 'override' but does not override any member functions">;
def warn_destructor_marked_not_override_overriding : TextSubstitution <
"%0 overrides a destructor but is not marked 'override'">;
def warn_function_marked_not_override_overriding : TextSubstitution <
"%0 overrides a member function but is not marked 'override'">;
def warn_inconsistent_destructor_marked_not_override_overriding : Warning <
"%sub{warn_destructor_marked_not_override_overriding}0">,
InGroup<CXX11WarnInconsistentOverrideDestructor>, DefaultIgnore;
def warn_inconsistent_function_marked_not_override_overriding : Warning <
"%sub{warn_function_marked_not_override_overriding}0">,
InGroup<CXX11WarnInconsistentOverrideMethod>;
def warn_suggest_destructor_marked_not_override_overriding : Warning <
"%sub{warn_destructor_marked_not_override_overriding}0">,
InGroup<CXX11WarnSuggestOverrideDestructor>, DefaultIgnore;
def warn_suggest_function_marked_not_override_overriding : Warning <
"%sub{warn_function_marked_not_override_overriding}0">,
InGroup<CXX11WarnSuggestOverride>, DefaultIgnore;
def err_class_marked_final_used_as_base : Error<
"base %0 is marked '%select{final|sealed}1'">;
def warn_abstract_final_class : Warning<
"abstract class is marked '%select{final|sealed}0'">, InGroup<AbstractFinalClass>;
def warn_final_dtor_non_final_class : Warning<
"class with destructor marked '%select{final|sealed}0' cannot be inherited from">,
InGroup<FinalDtorNonFinalClass>;
def note_final_dtor_non_final_class_silence : Note<
"mark %0 as '%select{final|sealed}1' to silence this warning">;
// C++11 attributes
def err_repeat_attribute : Error<"%0 attribute cannot be repeated">;
// C++11 final
def err_final_function_overridden : Error<
"declaration of %0 overrides a '%select{final|sealed}1' function">;
// C++11 scoped enumerations
def err_enum_invalid_underlying : Error<
"non-integral type %0 is an invalid underlying type">;
def err_enumerator_too_large : Error<
"enumerator value is not representable in the underlying type %0">;
def ext_enumerator_too_large : Extension<
"enumerator value is not representable in the underlying type %0">,
InGroup<MicrosoftEnumValue>;
def err_enumerator_wrapped : Error<
"enumerator value %0 is not representable in the underlying type %1">;
def err_enum_redeclare_type_mismatch : Error<
"enumeration redeclared with different underlying type %0 (was %1)">;
def err_enum_redeclare_fixed_mismatch : Error<
"enumeration previously declared with %select{non|}0fixed underlying type">;
def err_enum_redeclare_scoped_mismatch : Error<
"enumeration previously declared as %select{un|}0scoped">;
def err_only_enums_have_underlying_types : Error<
"only enumeration types have underlying types">;
def err_underlying_type_of_incomplete_enum : Error<
"cannot determine underlying type of incomplete enumeration type %0">;
// C++11 delegating constructors
def err_delegating_ctor : Error<
"delegating constructors are permitted only in C++11">;
def warn_cxx98_compat_delegating_ctor : Warning<
"delegating constructors are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_delegating_initializer_alone : Error<
"an initializer for a delegating constructor must appear alone">;
def warn_delegating_ctor_cycle : Warning<
"constructor for %0 creates a delegation cycle">, DefaultError,
InGroup<DelegatingCtorCycles>;
def note_it_delegates_to : Note<"it delegates to">;
def note_which_delegates_to : Note<"which delegates to">;
// C++11 range-based for loop
def err_for_range_decl_must_be_var : Error<
"for range declaration must declare a variable">;
def err_for_range_storage_class : Error<
"loop variable %0 may not be declared %select{'extern'|'static'|"
"'__private_extern__'|'auto'|'register'|'constexpr'|'thread_local'}1">;
def err_type_defined_in_for_range : Error<
"types may not be defined in a for range declaration">;
def err_for_range_deduction_failure : Error<
"cannot use type %0 as a range">;
def err_for_range_incomplete_type : Error<
"cannot use incomplete type %0 as a range">;
def err_for_range_iter_deduction_failure : Error<
"cannot use type %0 as an iterator">;
def ext_for_range_begin_end_types_differ : ExtWarn<
"'begin' and 'end' returning different types (%0 and %1) is a C++17 extension">,
InGroup<CXX17>;
def warn_for_range_begin_end_types_differ : Warning<
"'begin' and 'end' returning different types (%0 and %1) is incompatible "
"with C++ standards before C++17">, InGroup<CXXPre17Compat>, DefaultIgnore;
def note_in_for_range: Note<
"when looking up '%select{begin|end}0' function for range expression "
"of type %1">;
def err_for_range_invalid: Error<
"invalid range expression of type %0; no viable '%select{begin|end}1' "
"function available">;
def note_for_range_member_begin_end_ignored : Note<
"member is not a candidate because range type %0 has no '%select{end|begin}1' member">;
def err_range_on_array_parameter : Error<
"cannot build range expression with array function parameter %0 since "
"parameter with array type %1 is treated as pointer type %2">;
def err_for_range_dereference : Error<
"invalid range expression of type %0; did you mean to dereference it "
"with '*'?">;
def note_for_range_invalid_iterator : Note <
"in implicit call to 'operator%select{!=|*|++}0' for iterator of type %1">;
def note_for_range_begin_end : Note<
"selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">;
def warn_for_range_const_ref_binds_temp_built_from_ref : Warning<
"loop variable %0 "
"%diff{of type $ binds to a temporary constructed from type $"
"|binds to a temporary constructed from a different type}1,2">,
InGroup<RangeLoopConstruct>, DefaultIgnore;
def note_use_type_or_non_reference : Note<
"use non-reference type %0 to make construction explicit or type %1 to prevent copying">;
def warn_for_range_ref_binds_ret_temp : Warning<
"loop variable %0 binds to a temporary value produced by a range of type %1">,
InGroup<RangeLoopBindReference>, DefaultIgnore;
def note_use_non_reference_type : Note<"use non-reference type %0">;
def warn_for_range_copy : Warning<
"loop variable %0 creates a copy from type %1">,
InGroup<RangeLoopConstruct>, DefaultIgnore;
def note_use_reference_type : Note<"use reference type %0 to prevent copying">;
def err_objc_for_range_init_stmt : Error<
"initialization statement is not supported when iterating over Objective-C "
"collection">;
// C++11 constexpr
def warn_cxx98_compat_constexpr : Warning<
"'constexpr' specifier is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
// FIXME: Maybe this should also go in -Wc++14-compat?
def warn_cxx14_compat_constexpr_not_const : Warning<
"'constexpr' non-static member function will not be implicitly 'const' "
"in C++14; add 'const' to avoid a change in behavior">,
InGroup<DiagGroup<"constexpr-not-const">>;
def err_invalid_consteval_take_address : Error<
"cannot take address of consteval function %0 outside"
" of an immediate invocation">;
def err_invalid_consteval_call : Error<
"call to consteval function %q0 is not a constant expression">;
def err_invalid_consteval_decl_kind : Error<
"%0 cannot be declared consteval">;
def err_invalid_constexpr : Error<
"%select{function parameter|typedef}0 "
"cannot be %sub{select_constexpr_spec_kind}1">;
def err_invalid_constexpr_member : Error<"non-static data member cannot be "
"constexpr%select{; did you intend to make it %select{const|static}0?|}1">;
def err_constexpr_tag : Error<
"%select{class|struct|interface|union|enum}0 "
"cannot be marked %sub{select_constexpr_spec_kind}1">;
def err_constexpr_dtor : Error<
"destructor cannot be declared %sub{select_constexpr_spec_kind}0">;
def err_constexpr_dtor_subobject : Error<
"destructor cannot be declared %sub{select_constexpr_spec_kind}0 because "
"%select{data member %2|base class %3}1 does not have a "
"constexpr destructor">;
def note_constexpr_dtor_subobject : Note<
"%select{data member %1|base class %2}0 declared here">;
def err_constexpr_wrong_decl_kind : Error<
"%sub{select_constexpr_spec_kind}0 can only be used "
"in %select{|variable and function|function|variable}0 declarations">;
def err_invalid_constexpr_var_decl : Error<
"constexpr variable declaration must be a definition">;
def err_constexpr_static_mem_var_requires_init : Error<
"declaration of constexpr static data member %0 requires an initializer">;
def err_constexpr_var_non_literal : Error<
"constexpr variable cannot have non-literal type %0">;
def err_constexpr_var_requires_const_init : Error<
"constexpr variable %0 must be initialized by a constant expression">;
def err_constexpr_var_requires_const_destruction : Error<
"constexpr variable %0 must have constant destruction">;
def err_constexpr_redecl_mismatch : Error<
"%select{non-constexpr|constexpr|consteval}1 declaration of %0"
" follows %select{non-constexpr|constexpr|consteval}2 declaration">;
def err_constexpr_virtual : Error<"virtual function cannot be constexpr">;
def warn_cxx17_compat_constexpr_virtual : Warning<
"virtual constexpr functions are incompatible with "
"C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
def err_constexpr_virtual_base : Error<
"constexpr %select{member function|constructor}0 not allowed in "
"%select{struct|interface|class}1 with virtual base "
"%plural{1:class|:classes}2">;
def note_non_literal_incomplete : Note<
"incomplete type %0 is not a literal type">;
def note_non_literal_virtual_base : Note<"%select{struct|interface|class}0 "
"with virtual base %plural{1:class|:classes}1 is not a literal type">;
def note_constexpr_virtual_base_here : Note<"virtual base class declared here">;
def err_constexpr_non_literal_return : Error<
"%select{constexpr|consteval}0 function's return type %1 is not a literal type">;
def err_constexpr_non_literal_param : Error<
"%select{constexpr|consteval}2 %select{function|constructor}1's %ordinal0 parameter type %3 is "
"not a literal type">;
def err_constexpr_body_invalid_stmt : Error<
"statement not allowed in %select{constexpr|consteval}1 %select{function|constructor}0">;
def ext_constexpr_body_invalid_stmt : ExtWarn<
"use of this statement in a constexpr %select{function|constructor}0 "
"is a C++14 extension">, InGroup<CXX14>;
def warn_cxx11_compat_constexpr_body_invalid_stmt : Warning<
"use of this statement in a constexpr %select{function|constructor}0 "
"is incompatible with C++ standards before C++14">,
InGroup<CXXPre14Compat>, DefaultIgnore;
def ext_constexpr_body_invalid_stmt_cxx20 : ExtWarn<
"use of this statement in a constexpr %select{function|constructor}0 "
"is a C++20 extension">, InGroup<CXX20>;
def warn_cxx17_compat_constexpr_body_invalid_stmt : Warning<
"use of this statement in a constexpr %select{function|constructor}0 "
"is incompatible with C++ standards before C++20">,
InGroup<CXXPre20Compat>, DefaultIgnore;
def ext_constexpr_body_invalid_stmt_cxx2b : ExtWarn<
"use of this statement in a constexpr %select{function|constructor}0 "
"is a C++2b extension">, InGroup<CXX2b>;
def warn_cxx20_compat_constexpr_body_invalid_stmt : Warning<
"use of this statement in a constexpr %select{function|constructor}0 "
"is incompatible with C++ standards before C++2b">,
InGroup<CXXPre2bCompat>, DefaultIgnore;
def ext_constexpr_type_definition : ExtWarn<
"type definition in a constexpr %select{function|constructor}0 "
"is a C++14 extension">, InGroup<CXX14>;
def warn_cxx11_compat_constexpr_type_definition : Warning<
"type definition in a constexpr %select{function|constructor}0 "
"is incompatible with C++ standards before C++14">,
InGroup<CXXPre14Compat>, DefaultIgnore;
def err_constexpr_vla : Error<
"variably-modified type %0 cannot be used in a constexpr "
"%select{function|constructor}1">;
def ext_constexpr_local_var : ExtWarn<
"variable declaration in a constexpr %select{function|constructor}0 "
"is a C++14 extension">, InGroup<CXX14>;
def warn_cxx11_compat_constexpr_local_var : Warning<
"variable declaration in a constexpr %select{function|constructor}0 "
"is incompatible with C++ standards before C++14">,
InGroup<CXXPre14Compat>, DefaultIgnore;
def ext_constexpr_static_var : ExtWarn<
"definition of a %select{static|thread_local}1 variable "
"in a constexpr %select{function|constructor}0 "
"is a C++2b extension">, InGroup<CXX2b>;
def warn_cxx20_compat_constexpr_var : Warning<
"definition of a %select{static variable|thread_local variable|variable "
"of non-literal type}1 in a constexpr %select{function|constructor}0 "
"is incompatible with C++ standards before C++2b">,
InGroup<CXXPre2bCompat>, DefaultIgnore;
def err_constexpr_local_var_non_literal_type : Error<
"variable of non-literal type %1 cannot be defined in a constexpr "
"%select{function|constructor}0 before C++2b">;
def ext_constexpr_local_var_no_init : ExtWarn<
"uninitialized variable in a constexpr %select{function|constructor}0 "
"is a C++20 extension">, InGroup<CXX20>;
def warn_cxx17_compat_constexpr_local_var_no_init : Warning<
"uninitialized variable in a constexpr %select{function|constructor}0 "
"is incompatible with C++ standards before C++20">,
InGroup<CXXPre20Compat>, DefaultIgnore;
def ext_constexpr_function_never_constant_expr : ExtWarn<
"%select{constexpr|consteval}1 %select{function|constructor}0 never produces a "
"constant expression">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError;
def err_attr_cond_never_constant_expr : Error<
"%0 attribute expression never produces a constant expression">;
def err_diagnose_if_invalid_diagnostic_type : Error<
"invalid diagnostic type for 'diagnose_if'; use \"error\" or \"warning\" "
"instead">;
def err_constexpr_body_no_return : Error<
"no return statement in %select{constexpr|consteval}0 function">;
def err_constexpr_return_missing_expr : Error<
"non-void %select{constexpr|consteval}1 function %0 should return a value">;
def warn_cxx11_compat_constexpr_body_no_return : Warning<
"constexpr function with no return statements is incompatible with C++ "
"standards before C++14">, InGroup<CXXPre14Compat>, DefaultIgnore;
def ext_constexpr_body_multiple_return : ExtWarn<
"multiple return statements in constexpr function is a C++14 extension">,
InGroup<CXX14>;
def warn_cxx11_compat_constexpr_body_multiple_return : Warning<
"multiple return statements in constexpr function "
"is incompatible with C++ standards before C++14">,
InGroup<CXXPre14Compat>, DefaultIgnore;
def note_constexpr_body_previous_return : Note<
"previous return statement is here">;
// C++20 function try blocks in constexpr
def ext_constexpr_function_try_block_cxx20 : ExtWarn<
"function try block in constexpr %select{function|constructor}0 is "
"a C++20 extension">, InGroup<CXX20>;
def warn_cxx17_compat_constexpr_function_try_block : Warning<
"function try block in constexpr %select{function|constructor}0 is "
"incompatible with C++ standards before C++20">,
InGroup<CXXPre20Compat>, DefaultIgnore;
def ext_constexpr_union_ctor_no_init : ExtWarn<
"constexpr union constructor that does not initialize any member "
"is a C++20 extension">, InGroup<CXX20>;
def warn_cxx17_compat_constexpr_union_ctor_no_init : Warning<
"constexpr union constructor that does not initialize any member "
"is incompatible with C++ standards before C++20">,
InGroup<CXXPre20Compat>, DefaultIgnore;
def ext_constexpr_ctor_missing_init : ExtWarn<
"constexpr constructor that does not initialize all members "
"is a C++20 extension">, InGroup<CXX20>;
def warn_cxx17_compat_constexpr_ctor_missing_init : Warning<
"constexpr constructor that does not initialize all members "
"is incompatible with C++ standards before C++20">,
InGroup<CXXPre20Compat>, DefaultIgnore;
def note_constexpr_ctor_missing_init : Note<
"member not initialized by constructor">;
def note_non_literal_no_constexpr_ctors : Note<
"%0 is not literal because it is not an aggregate and has no constexpr "
"constructors other than copy or move constructors">;
def note_non_literal_base_class : Note<
"%0 is not literal because it has base class %1 of non-literal type">;
def note_non_literal_field : Note<
"%0 is not literal because it has data member %1 of "
"%select{non-literal|volatile}3 type %2">;
def note_non_literal_user_provided_dtor : Note<
"%0 is not literal because it has a user-provided destructor">;
def note_non_literal_nontrivial_dtor : Note<
"%0 is not literal because it has a non-trivial destructor">;
def note_non_literal_non_constexpr_dtor : Note<
"%0 is not literal because its destructor is not constexpr">;
def note_non_literal_lambda : Note<
"lambda closure types are non-literal types before C++17">;
def warn_private_extern : Warning<
"use of __private_extern__ on a declaration may not produce external symbol "
"private to the linkage unit and is deprecated">, InGroup<PrivateExtern>;
def note_private_extern : Note<
"use __attribute__((visibility(\"hidden\"))) attribute instead">;
// C++ Concepts
def err_concept_decls_may_only_appear_in_global_namespace_scope : Error<
"concept declarations may only appear in global or namespace scope">;
def err_concept_no_parameters : Error<
"concept template parameter list must have at least one parameter; explicit "
"specialization of concepts is not allowed">;
def err_concept_extra_headers : Error<
"extraneous template parameter list in concept definition">;
def err_concept_no_associated_constraints : Error<
"concept cannot have associated constraints">;
def err_non_constant_constraint_expression : Error<
"substitution into constraint expression resulted in a non-constant "
"expression">;
def err_non_bool_atomic_constraint : Error<
"atomic constraint must be of type 'bool' (found %0)">;
def err_template_arg_list_constraints_not_satisfied : Error<
"constraints not satisfied for %select{class template|function template|variable template|alias template|"
"template template parameter|template}0 %1%2">;
def note_substituted_constraint_expr_is_ill_formed : Note<
"because substituted constraint expression is ill-formed%0">;
def note_atomic_constraint_evaluated_to_false : Note<
"%select{and|because}0 '%1' evaluated to false">;
def note_concept_specialization_constraint_evaluated_to_false : Note<
"%select{and|because}0 '%1' evaluated to false">;
def note_single_arg_concept_specialization_constraint_evaluated_to_false : Note<
"%select{and|because}0 %1 does not satisfy %2">;
def note_atomic_constraint_evaluated_to_false_elaborated : Note<
"%select{and|because}0 '%1' (%2 %3 %4) evaluated to false">;
def err_constrained_virtual_method : Error<
"virtual function cannot have a requires clause">;
def err_trailing_requires_clause_on_deduction_guide : Error<
"deduction guide cannot have a requires clause">;
def err_constrained_non_templated_function
: Error<"non-templated function cannot have a requires clause">;
def err_reference_to_function_with_unsatisfied_constraints : Error<
"invalid reference to function %0: constraints not satisfied">;
def err_requires_expr_local_parameter_default_argument : Error<
"default arguments not allowed for parameters of a requires expression">;
def err_requires_expr_parameter_referenced_in_evaluated_context : Error<
"constraint variable %0 cannot be used in an evaluated context">;
def note_expr_requirement_expr_substitution_error : Note<
"%select{and|because}0 '%1' would be invalid: %2">;
def note_expr_requirement_expr_unknown_substitution_error : Note<
"%select{and|because}0 '%1' would be invalid">;
def note_expr_requirement_noexcept_not_met : Note<
"%select{and|because}0 '%1' may throw an exception">;
def note_expr_requirement_type_requirement_substitution_error : Note<
"%select{and|because}0 '%1' would be invalid: %2">;
def note_expr_requirement_type_requirement_unknown_substitution_error : Note<
"%select{and|because}0 '%1' would be invalid">;
def note_expr_requirement_constraints_not_satisfied : Note<
"%select{and|because}0 type constraint '%1' was not satisfied:">;
def note_expr_requirement_constraints_not_satisfied_simple : Note<
"%select{and|because}0 %1 does not satisfy %2:">;
def note_type_requirement_substitution_error : Note<
"%select{and|because}0 '%1' would be invalid: %2">;
def note_type_requirement_unknown_substitution_error : Note<
"%select{and|because}0 '%1' would be invalid">;
def note_nested_requirement_substitution_error : Note<
"%select{and|because}0 '%1' would be invalid: %2">;
def note_nested_requirement_unknown_substitution_error : Note<
"%select{and|because}0 '%1' would be invalid">;
def note_ambiguous_atomic_constraints : Note<
"similar constraint expressions not considered equivalent; constraint "
"expressions cannot be considered equivalent unless they originate from the "
"same concept">;
def note_ambiguous_atomic_constraints_similar_expression : Note<
"similar constraint expression here">;
def err_unsupported_placeholder_constraint : Error<
"constrained placeholder types other than simple 'auto' on non-type template "
"parameters not supported yet">;
def err_template_different_requires_clause : Error<
"requires clause differs in template redeclaration">;
def err_template_different_type_constraint : Error<
"type constraint differs in template redeclaration">;
def err_template_template_parameter_not_at_least_as_constrained : Error<
"template template argument %0 is more constrained than template template "
"parameter %1">;
def err_type_constraint_non_type_concept : Error<
"concept named in type constraint is not a type concept">;
def err_type_constraint_missing_arguments : Error<
"%0 requires more than 1 template argument; provide the remaining arguments "
"explicitly to use it here">;
def err_placeholder_constraints_not_satisfied : Error<
"deduced type %0 does not satisfy %1">;
// C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning<
"'%0' type specifier is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def warn_cxx17_compat_unicode_type : Warning<
"'char8_t' type specifier is incompatible with C++ standards before C++20">,
InGroup<CXXPre20Compat>, DefaultIgnore;
// __make_integer_seq
def err_integer_sequence_negative_length : Error<
"integer sequences must have non-negative sequence length">;
def err_integer_sequence_integral_element_type : Error<
"integer sequences must have integral element type">;
// __type_pack_element
def err_type_pack_element_out_of_bounds : Error<
"a parameter pack may not be accessed at an out of bounds index">;
// Objective-C++
def err_objc_decls_may_only_appear_in_global_scope : Error<
"Objective-C declarations may only appear in global scope">;
def warn_auto_var_is_id : Warning<
"'auto' deduced as 'id' in declaration of %0">,
InGroup<DiagGroup<"auto-var-id">>;
// Attributes
def warn_attribute_ignored_no_calls_in_stmt: Warning<
"%0 attribute is ignored because there exists no call expression inside the "
"statement">,
InGroup<IgnoredAttributes>;
def warn_function_attribute_ignored_in_stmt : Warning<
"attribute is ignored on this statement as it only applies to functions; "
"use '%0' on statements">,
InGroup<IgnoredAttributes>;
def err_musttail_needs_trivial_args : Error<
"tail call requires that the return value, all parameters, and any "
"temporaries created by the expression are trivially destructible">;
def err_musttail_needs_call : Error<
"%0 attribute requires that the return value is the result of a function call"
>;
def err_musttail_needs_prototype : Error<
"%0 attribute requires that both caller and callee functions have a "
"prototype">;
def note_musttail_fix_non_prototype : Note<
"add 'void' to the parameter list to turn an old-style K&R function "
"declaration into a prototype">;
def err_musttail_structors_forbidden : Error<"cannot perform a tail call "
"%select{from|to}0 a %select{constructor|destructor}1">;
def note_musttail_structors_forbidden : Note<"target "
"%select{constructor|destructor}0 is declared here">;
def err_musttail_forbidden_from_this_context : Error<
"%0 attribute cannot be used from "
"%select{a block|an Objective-C function|this context}1">;
def err_musttail_member_mismatch : Error<
"%select{non-member|static member|non-static member}0 "
"function cannot perform a tail call to "
"%select{non-member|static member|non-static member|pointer-to-member}1 "
"function%select{| %3}2">;
def note_musttail_callee_defined_here : Note<"%0 declared here">;
def note_tail_call_required : Note<"tail call required by %0 attribute here">;
def err_musttail_mismatch : Error<
"cannot perform a tail call to function%select{| %1}0 because its signature "
"is incompatible with the calling function">;
def note_musttail_mismatch : Note<
"target function "
"%select{is a member of different class%diff{ (expected $ but has $)|}1,2"
"|has different number of parameters (expected %1 but has %2)"
"|has type mismatch at %ordinal3 parameter"
"%diff{ (expected $ but has $)|}1,2"
"|has different return type%diff{ ($ expected but has $)|}1,2}0">;
def err_musttail_callconv_mismatch : Error<
"cannot perform a tail call to function%select{| %1}0 because it uses an "
"incompatible calling convention">;
def note_musttail_callconv_mismatch : Note<
"target function has calling convention %1 (expected %0)">;
def err_musttail_scope : Error<
"cannot perform a tail call from this return statement">;
def err_musttail_no_variadic : Error<
"%0 attribute may not be used with variadic functions">;
def err_nsobject_attribute : Error<
"'NSObject' attribute is for pointer types only">;
def err_attributes_are_not_compatible : Error<
"%0 and %1 attributes are not compatible">;
def err_attribute_invalid_argument : Error<
"%select{a reference type|an array type|a non-vector or "
"non-vectorizable scalar type}0 is an invalid argument to attribute %1">;
def err_attribute_wrong_number_arguments : Error<
"%0 attribute %plural{0:takes no arguments|1:takes one argument|"
":requires exactly %1 arguments}1">;
def err_attribute_wrong_number_arguments_for : Error <
"%0 attribute references function %1, which %plural{0:takes no arguments|1:takes one argument|"
":takes exactly %2 arguments}2">;
def err_attribute_bounds_for_function : Error<
"%0 attribute references parameter %1, but the function %2 has only %3 parameters">;
def err_attribute_no_member_function : Error<
"%0 attribute cannot be applied to non-static member functions">;
def err_attribute_parameter_types : Error<
"%0 attribute parameter types do not match: parameter %1 of function %2 has type %3, "
"but parameter %4 of function %5 has type %6">;
def err_attribute_too_many_arguments : Error<
"%0 attribute takes no more than %1 argument%s1">;
def err_attribute_too_few_arguments : Error<
"%0 attribute takes at least %1 argument%s1">;
def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">;
def err_attribute_invalid_matrix_type : Error<"invalid matrix element type %0">;
def err_attribute_bad_neon_vector_size : Error<
"Neon vector size must be 64 or 128 bits">;
def err_attribute_invalid_sve_type : Error<
"%0 attribute applied to non-SVE type %1">;
def err_attribute_bad_sve_vector_size : Error<
"invalid SVE vector size '%0', must match value set by "
"'-msve-vector-bits' ('%1')">;
def err_attribute_arm_feature_sve_bits_unsupported : Error<
"%0 is only supported when '-msve-vector-bits=<bits>' is specified with a "
"value of 128, 256, 512, 1024 or 2048.">;
def err_attribute_requires_positive_integer : Error<
"%0 attribute requires a %select{positive|non-negative}1 "
"integral compile time constant expression">;
def err_attribute_requires_opencl_version : Error<
"attribute %0 is supported in the OpenCL version %1%select{| onwards}2">;
def err_invalid_branch_protection_spec : Error<
"invalid or misplaced branch protection specification '%0'">;
def warn_unsupported_branch_protection_spec : Warning<
"unsupported branch protection specification '%0'">, InGroup<BranchProtection>;
def warn_unsupported_target_attribute
: Warning<"%select{unsupported|duplicate|unknown}0%select{| architecture|"
" tune CPU}1 '%2' in the '%select{target|target_clones}3' "
"attribute string; '%select{target|target_clones}3' "
"attribute ignored">,
InGroup<IgnoredAttributes>;
def err_attribute_unsupported
: Error<"%0 attribute is not supported on targets missing %1;"
" specify an appropriate -march= or -mcpu=">;
// The err_*_attribute_argument_not_int are separate because they're used by
// VerifyIntegerConstantExpression.
def err_aligned_attribute_argument_not_int : Error<
"'aligned' attribute requires integer constant">;
def err_align_value_attribute_argument_not_int : Error<
"'align_value' attribute requires integer constant">;
def err_alignas_attribute_wrong_decl_type : Error<
"%0 attribute cannot be applied to %select{a function parameter|"
"a variable with 'register' storage class|a 'catch' variable|a bit-field|"
"an enumeration}1">;
def err_alignas_missing_on_definition : Error<
"%0 must be specified on definition if it is specified on any declaration">;
def note_alignas_on_declaration : Note<"declared with %0 attribute here">;
def err_alignas_mismatch : Error<
"redeclaration has different alignment requirement (%1 vs %0)">;
def err_alignas_underaligned : Error<
"requested alignment is less than minimum alignment of %1 for type %0">;
def warn_aligned_attr_underaligned : Warning<err_alignas_underaligned.Text>,
InGroup<IgnoredAttributes>;
def err_attribute_sizeless_type : Error<
"%0 attribute cannot be applied to sizeless type %1">;
def err_attribute_argument_n_type : Error<
"%0 attribute requires parameter %1 to be %select{int or bool|an integer "
"constant|a string|an identifier|a constant expression|a builtin function}2">;
def err_attribute_argument_type : Error<
"%0 attribute requires %select{int or bool|an integer "
"constant|a string|an identifier}1">;
def err_attribute_argument_out_of_range : Error<
"%0 attribute requires integer constant between %1 and %2 inclusive">;
def err_init_priority_object_attr : Error<
"can only use 'init_priority' attribute on file-scope definitions "
"of objects of class type">;
def err_attribute_argument_out_of_bounds : Error<
"%0 attribute parameter %1 is out of bounds">;
def err_attribute_only_once_per_parameter : Error<
"%0 attribute can only be applied once per parameter">;
def err_mismatched_uuid : Error<"uuid does not match previous declaration">;
def note_previous_uuid : Note<"previous uuid specified here">;
def warn_attribute_pointers_only : Warning<
"%0 attribute only applies to%select{| constant}1 pointer arguments">,
InGroup<IgnoredAttributes>;
def err_attribute_pointers_only : Error<warn_attribute_pointers_only.Text>;
def err_attribute_integers_only : Error<
"%0 attribute argument may only refer to a function parameter of integer "
"type">;
def warn_attribute_return_pointers_only : Warning<
"%0 attribute only applies to return values that are pointers">,
InGroup<IgnoredAttributes>;
def warn_attribute_return_pointers_refs_only : Warning<
"%0 attribute only applies to return values that are pointers or references">,
InGroup<IgnoredAttributes>;
def warn_attribute_pointer_or_reference_only : Warning<
"%0 attribute only applies to a pointer or reference (%1 is invalid)">,
InGroup<IgnoredAttributes>;
def err_attribute_no_member_pointers : Error<
"%0 attribute cannot be used with pointers to members">;
def err_attribute_invalid_implicit_this_argument : Error<
"%0 attribute is invalid for the implicit this argument">;
def err_ownership_type : Error<
"%0 attribute only applies to %select{pointer|integer}1 arguments">;
def err_ownership_returns_index_mismatch : Error<
"'ownership_returns' attribute index does not match; here it is %0">;
def note_ownership_returns_index_mismatch : Note<
"declared with index %0 here">;
def err_format_strftime_third_parameter : Error<
"strftime format attribute requires 3rd parameter to be 0">;
def err_format_attribute_not : Error<"format argument not a string type">;
def err_format_attribute_result_not : Error<"function does not return %0">;
def err_format_attribute_implicit_this_format_string : Error<
"format attribute cannot specify the implicit this argument as the format "
"string">;
def err_callback_attribute_no_callee : Error<
"'callback' attribute specifies no callback callee">;
def err_callback_attribute_invalid_callee : Error<
"'callback' attribute specifies invalid callback callee">;
def err_callback_attribute_multiple : Error<
"multiple 'callback' attributes specified">;
def err_callback_attribute_argument_unknown : Error<
"'callback' attribute argument %0 is not a known function parameter">;
def err_callback_callee_no_function_type : Error<
"'callback' attribute callee does not have function type">;
def err_callback_callee_is_variadic : Error<
"'callback' attribute callee may not be variadic">;
def err_callback_implicit_this_not_available : Error<
"'callback' argument at position %0 references unavailable implicit 'this'">;
def err_init_method_bad_return_type : Error<
"init methods must return an object pointer type, not %0">;
def err_attribute_invalid_size : Error<
"vector size not an integral multiple of component size">;
def err_attribute_zero_size : Error<"zero %0 size">;
def err_attribute_size_too_large : Error<"%0 size too large">;
def err_typecheck_sve_ambiguous : Error<
"cannot combine fixed-length and sizeless SVE vectors in expression, result is ambiguous (%0 and %1)">;
def err_typecheck_sve_gnu_ambiguous : Error<
"cannot combine GNU and SVE vectors in expression, result is ambiguous (%0 and %1)">;
def err_typecheck_vector_not_convertable_implict_truncation : Error<
"cannot convert between %select{scalar|vector}0 type %1 and vector type"
" %2 as implicit conversion would cause truncation">;
def err_typecheck_vector_not_convertable : Error<
"cannot convert between vector values of different size (%0 and %1)">;
def err_typecheck_vector_not_convertable_non_scalar : Error<
"cannot convert between vector and non-scalar values (%0 and %1)">;
def err_typecheck_vector_lengths_not_equal : Error<
"vector operands do not have the same number of elements (%0 and %1)">;
def warn_typecheck_vector_element_sizes_not_equal : Warning<
"vector operands do not have the same elements sizes (%0 and %1)">,
InGroup<DiagGroup<"vec-elem-size">>, DefaultError;
def err_ext_vector_component_exceeds_length : Error<
"vector component access exceeds type %0">;
def err_ext_vector_component_name_illegal : Error<
"illegal vector component name '%0'">;
def err_attribute_address_space_negative : Error<
"address space is negative">;
def err_attribute_address_space_too_high : Error<
"address space is larger than the maximum supported (%0)">;
def err_attribute_address_multiple_qualifiers : Error<
"multiple address spaces specified for type">;
def warn_attribute_address_multiple_identical_qualifiers : Warning<
"multiple identical address spaces specified for type">,
InGroup<DuplicateDeclSpecifier>;
def err_attribute_not_clinkage : Error<
"function type with %0 attribute must have C linkage">;
def err_function_decl_cmse_ns_call : Error<
"functions may not be declared with 'cmse_nonsecure_call' attribute">;
def err_attribute_address_function_type : Error<
"function type may not be qualified with an address space">;
def err_as_qualified_auto_decl : Error<
"automatic variable qualified with an%select{| invalid}0 address space">;
def err_arg_with_address_space : Error<
"parameter may not be qualified with an address space">;
def err_field_with_address_space : Error<
"field may not be qualified with an address space">;
def err_compound_literal_with_address_space : Error<
"compound literal in function scope may not be qualified with an address space">;
def err_address_space_mismatch_templ_inst : Error<
"conflicting address space qualifiers are provided between types %0 and %1">;
def err_attr_objc_ownership_redundant : Error<
"the type %0 is already explicitly ownership-qualified">;
def err_invalid_nsnumber_type : Error<
"%0 is not a valid literal type for NSNumber">;
def err_objc_illegal_boxed_expression_type : Error<
"illegal type %0 used in a boxed expression">;
def err_objc_non_trivially_copyable_boxed_expression_type : Error<
"non-trivially copyable type %0 cannot be used in a boxed expression">;
def err_objc_incomplete_boxed_expression_type : Error<
"incomplete type %0 used in a boxed expression">;
def err_undeclared_objc_literal_class : Error<
"definition of class %0 must be available to use Objective-C "
"%select{array literals|dictionary literals|numeric literals|boxed expressions|"
"string literals}1">;
def err_undeclared_boxing_method : Error<
"declaration of %0 is missing in %1 class">;
def err_objc_literal_method_sig : Error<
"literal construction method %0 has incompatible signature">;
def note_objc_literal_method_param : Note<
"%select{first|second|third}0 parameter has unexpected type %1 "
"(should be %2)">;
def note_objc_literal_method_return : Note<
"method returns unexpected type %0 (should be an object type)">;
def err_invalid_collection_element : Error<
"collection element of type %0 is not an Objective-C object">;
def err_box_literal_collection : Error<
"%select{string|character|boolean|numeric}0 literal must be prefixed by '@' "
"in a collection">;
def warn_objc_literal_comparison : Warning<
"direct comparison of %select{an array literal|a dictionary literal|"
"a numeric literal|a boxed expression|}0 has undefined behavior">,
InGroup<ObjCLiteralComparison>;
def err_missing_atsign_prefix : Error<
"%select{string|numeric}0 literal must be prefixed by '@'">;
def warn_objc_string_literal_comparison : Warning<
"direct comparison of a string literal has undefined behavior">,
InGroup<ObjCStringComparison>;
def warn_concatenated_literal_array_init : Warning<
"suspicious concatenation of string literals in an array initialization; "
"did you mean to separate the elements with a comma?">,
InGroup<StringConcatation>, DefaultIgnore;
def warn_concatenated_nsarray_literal : Warning<
"concatenated NSString literal for an NSArray expression - "
"possibly missing a comma">,
InGroup<ObjCStringConcatenation>;
def note_objc_literal_comparison_isequal : Note<
"use 'isEqual:' instead">;
def warn_objc_collection_literal_element : Warning<
"object of type %0 is not compatible with "
"%select{array element type|dictionary key type|dictionary value type}1 %2">,
InGroup<ObjCLiteralConversion>;
def warn_nsdictionary_duplicate_key : Warning<
"duplicate key in dictionary literal">,
InGroup<DiagGroup<"objc-dictionary-duplicate-keys">>;
def note_nsdictionary_duplicate_key_here : Note<
"previous equal key is here">;
def err_swift_param_attr_not_swiftcall : Error<
"'%0' parameter can only be used with swiftcall%select{ or swiftasynccall|}1 "
"calling convention%select{|s}1">;
def err_swift_indirect_result_not_first : Error<
"'swift_indirect_result' parameters must be first parameters of function">;
def err_swift_error_result_not_after_swift_context : Error<
"'swift_error_result' parameter must follow 'swift_context' parameter">;
def err_swift_abi_parameter_wrong_type : Error<
"'%0' parameter must have pointer%select{| to unqualified pointer}1 type; "
"type here is %2">;
def err_attribute_argument_invalid : Error<
"%0 attribute argument is invalid: %select{max must be 0 since min is 0|"
"min must not be greater than max}1">;
def err_attribute_argument_is_zero : Error<
"%0 attribute must be greater than 0">;
def warn_attribute_argument_n_negative : Warning<
"%0 attribute parameter %1 is negative and will be ignored">,
InGroup<CudaCompat>;
def err_property_function_in_objc_container : Error<
"use of Objective-C property in function nested in Objective-C "
"container not supported, move function outside its container">;
let CategoryName = "Cocoa API Issue" in {
def warn_objc_redundant_literal_use : Warning<
"using %0 with a literal is redundant">, InGroup<ObjCRedundantLiteralUse>;
}
def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", "
"\"local-dynamic\", \"initial-exec\" or \"local-exec\"">;
def err_aix_attr_unsupported_tls_model : Error<"TLS model '%0' is not yet supported on AIX">;
def err_tls_var_aligned_over_maximum : Error<
"alignment (%0) of thread-local variable %1 is greater than the maximum supported "
"alignment (%2) for a thread-local variable on this target">;
def err_only_annotate_after_access_spec : Error<
"access specifier can only have annotation attributes">;
def err_attribute_section_invalid_for_target : Error<
"argument to %select{'code_seg'|'section'}1 attribute is not valid for this target: %0">;
def err_pragma_section_invalid_for_target : Error<
"argument to #pragma section is not valid for this target: %0">;
def warn_attribute_section_drectve : Warning<
"#pragma %0(\".drectve\") has undefined behavior, "
"use #pragma comment(linker, ...) instead">, InGroup<MicrosoftDrectveSection>;
def warn_mismatched_section : Warning<
"%select{codeseg|section}0 does not match previous declaration">, InGroup<Section>;
def warn_attribute_section_on_redeclaration : Warning<
"section attribute is specified on redeclared variable">, InGroup<Section>;
def err_mismatched_code_seg_base : Error<
"derived class must specify the same code segment as its base classes">;
def err_mismatched_code_seg_override : Error<
"overriding virtual function must specify the same code segment as its overridden function">;
def err_conflicting_codeseg_attribute : Error<
"conflicting code segment specifiers">;
def warn_duplicate_codeseg_attribute : Warning<
"duplicate code segment specifiers">, InGroup<Section>;
def err_anonymous_property: Error<
"anonymous property is not supported">;
def err_property_is_variably_modified : Error<
"property %0 has a variably modified type">;
def err_no_accessor_for_property : Error<
"no %select{getter|setter}0 defined for property %1">;
def err_cannot_find_suitable_accessor : Error<
"cannot find suitable %select{getter|setter}0 for property %1">;
def warn_alloca : Warning<
"use of function %0 is discouraged; there is no way to check for failure but "
"failure may still occur, resulting in a possibly exploitable security vulnerability">,
InGroup<DiagGroup<"alloca">>, DefaultIgnore;
def warn_alloca_align_alignof : Warning<
"second argument to __builtin_alloca_with_align is supposed to be in bits">,
InGroup<DiagGroup<"alloca-with-align-alignof">>;
def err_alignment_too_small : Error<
"requested alignment must be %0 or greater">;
def err_alignment_too_big : Error<
"requested alignment must be %0 or smaller">;
def err_alignment_not_power_of_two : Error<
"requested alignment is not a power of 2">;
def warn_alignment_not_power_of_two : Warning<
err_alignment_not_power_of_two.Text>,
InGroup<DiagGroup<"non-power-of-two-alignment">>;
def err_alignment_dependent_typedef_name : Error<
"requested alignment is dependent but declaration is not dependent">;
def warn_alignment_builtin_useless : Warning<
"%select{aligning a value|the result of checking whether a value is aligned}0"
" to 1 byte is %select{a no-op|always true}0">, InGroup<TautologicalCompare>;
def err_attribute_aligned_too_great : Error<
"requested alignment must be %0 bytes or smaller">;
def warn_assume_aligned_too_great
: Warning<"requested alignment must be %0 bytes or smaller; maximum "
"alignment assumed">,
InGroup<DiagGroup<"builtin-assume-aligned-alignment">>;
def warn_not_xl_compatible
: Warning<"alignment of 16 bytes for a struct member is not binary "
"compatible with IBM XL C/C++ for AIX 16.1.0 or older">,
InGroup<AIXCompat>;
def note_misaligned_member_used_here : Note<
"passing byval argument %0 with potentially incompatible alignment here">;
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
"%q0 redeclared without %1 attribute: previous %1 ignored">,
InGroup<MicrosoftInconsistentDllImport>;
def warn_redeclaration_without_import_attribute : Warning<
"%q0 redeclared without 'dllimport' attribute: 'dllexport' attribute added">,
InGroup<MicrosoftInconsistentDllImport>;
def warn_dllimport_dropped_from_inline_function : Warning<
"%q0 redeclared inline; %1 attribute ignored">,
InGroup<IgnoredAttributes>;
def warn_nothrow_attribute_ignored : Warning<"'nothrow' attribute conflicts with"
" exception specification; attribute ignored">,
InGroup<IgnoredAttributes>;
def warn_attribute_ignored_on_non_definition :
Warning<"%0 attribute ignored on a non-definition declaration">,
InGroup<IgnoredAttributes>;
def warn_attribute_ignored_on_inline :
Warning<"%0 attribute ignored on inline function">,
InGroup<IgnoredAttributes>;
def warn_nocf_check_attribute_ignored :
Warning<"'nocf_check' attribute ignored; use -fcf-protection to enable the attribute">,
InGroup<IgnoredAttributes>;
def warn_attribute_after_definition_ignored : Warning<
"attribute %0 after definition is ignored">,
InGroup<IgnoredAttributes>;
def warn_attributes_likelihood_ifstmt_conflict
: Warning<"conflicting attributes %0 are ignored">,
InGroup<IgnoredAttributes>;
def warn_cxx11_gnu_attribute_on_type : Warning<
"attribute %0 ignored, because it cannot be applied to a type">,
InGroup<IgnoredAttributes>;
def warn_unhandled_ms_attribute_ignored : Warning<
"__declspec attribute %0 is not supported">,
InGroup<IgnoredAttributes>;
def warn_attribute_has_no_effect_on_infinite_loop : Warning<
"attribute %0 has no effect when annotating an infinite loop">,
InGroup<IgnoredAttributes>;
def note_attribute_has_no_effect_on_infinite_loop_here : Note<
"annotating the infinite loop here">;
def warn_attribute_has_no_effect_on_compile_time_if : Warning<
"attribute %0 has no effect when annotating an 'if %select{constexpr|consteval}1' statement">,
InGroup<IgnoredAttributes>;
def note_attribute_has_no_effect_on_compile_time_if_here : Note<
"annotating the 'if %select{constexpr|consteval}0' statement here">;
def err_decl_attribute_invalid_on_stmt : Error<
"%0 attribute cannot be applied to a statement">;
def err_attribute_invalid_on_decl : Error<
"%0 attribute cannot be applied to a declaration">;
def warn_type_attribute_deprecated_on_decl : Warning<
"applying attribute %0 to a declaration is deprecated; apply it to the type instead">,
InGroup<DeprecatedAttributes>;
def warn_declspec_attribute_ignored : Warning<
"attribute %0 is ignored, place it after "
"\"%select{class|struct|interface|union|enum}1\" to apply attribute to "
"type declaration">, InGroup<IgnoredAttributes>;
def warn_attribute_precede_definition : Warning<
"attribute declaration must precede definition">,
InGroup<IgnoredAttributes>;
def warn_attribute_void_function_method : Warning<
"attribute %0 cannot be applied to "
"%select{functions|Objective-C method}1 without return value">,
InGroup<IgnoredAttributes>;
def warn_attribute_weak_on_field : Warning<
"__weak attribute cannot be specified on a field declaration">,
InGroup<IgnoredAttributes>;
def warn_gc_attribute_weak_on_local : Warning<
"Objective-C GC does not allow weak variables on the stack">,
InGroup<IgnoredAttributes>;
def warn_nsobject_attribute : Warning<
"'NSObject' attribute may be put on a typedef only; attribute is ignored">,
InGroup<NSobjectAttribute>;
def warn_independentclass_attribute : Warning<
"'objc_independent_class' attribute may be put on a typedef only; "
"attribute is ignored">,
InGroup<IndependentClassAttribute>;
def warn_ptr_independentclass_attribute : Warning<
"'objc_independent_class' attribute may be put on Objective-C object "
"pointer type only; attribute is ignored">,
InGroup<IndependentClassAttribute>;
def warn_attribute_weak_on_local : Warning<
"__weak attribute cannot be specified on an automatic variable when ARC "
"is not enabled">,
InGroup<IgnoredAttributes>;
def warn_weak_identifier_undeclared : Warning<
"weak identifier %0 never declared">;
def warn_attribute_cmse_entry_static : Warning<
"'cmse_nonsecure_entry' cannot be applied to functions with internal linkage">,
InGroup<IgnoredAttributes>;
def warn_cmse_nonsecure_union : Warning<
"passing union across security boundary via %select{parameter %1|return value}0 "
"may leak information">,
InGroup<DiagGroup<"cmse-union-leak">>;
def err_attribute_weak_static : Error<
"weak declaration cannot have internal linkage">;
def err_attribute_selectany_non_extern_data : Error<
"'selectany' can only be applied to data items with external linkage">;
def err_declspec_thread_on_thread_variable : Error<
"'__declspec(thread)' applied to variable that already has a "
"thread-local storage specifier">;
def err_attribute_dll_not_extern : Error<
"%q0 must have external linkage when declared %q1">;
def err_attribute_dll_thread_local : Error<
"%q0 cannot be thread local when declared %q1">;
def err_attribute_dll_lambda : Error<
"lambda cannot be declared %0">;
def warn_attribute_invalid_on_definition : Warning<
"'%0' attribute cannot be specified on a definition">,
InGroup<IgnoredAttributes>;
def err_attribute_dll_redeclaration : Error<
"redeclaration of %q0 cannot add %q1 attribute">;
def warn_attribute_dll_redeclaration : Warning<
"redeclaration of %q0 should not add %q1 attribute">,
InGroup<DiagGroup<"dll-attribute-on-redeclaration">>;
def err_attribute_dllimport_function_definition : Error<
"dllimport cannot be applied to non-inline function definition">;
def err_attribute_dll_deleted : Error<
"attribute %q0 cannot be applied to a deleted function">;
def err_attribute_dllimport_data_definition : Error<
"definition of dllimport data">;
def err_attribute_dllimport_static_field_definition : Error<
"definition of dllimport static field not allowed">;
def warn_attribute_dllimport_static_field_definition : Warning<
"definition of dllimport static field">,
InGroup<DiagGroup<"dllimport-static-field-def">>;
def warn_attribute_dllexport_explicit_instantiation_decl : Warning<
"explicit instantiation declaration should not be 'dllexport'">,
InGroup<DllexportExplicitInstantiationDecl>;
def warn_attribute_dllexport_explicit_instantiation_def : Warning<
"'dllexport' attribute ignored on explicit instantiation definition">,
InGroup<IgnoredAttributes>;
def warn_invalid_initializer_from_system_header : Warning<
"invalid constructor from class in system header, should not be explicit">,
InGroup<DiagGroup<"invalid-initializer-from-system-header">>;
def note_used_in_initialization_here : Note<"used in initialization here">;
def err_attribute_dll_member_of_dll_class : Error<
"attribute %q0 cannot be applied to member of %q1 class">;
def warn_attribute_dll_instantiated_base_class : Warning<
"propagating dll attribute to %select{already instantiated|explicitly specialized}0 "
"base class template without dll attribute is not supported">,
InGroup<DiagGroup<"unsupported-dll-base-class-template">>, DefaultIgnore;
def err_attribute_dll_ambiguous_default_ctor : Error<
"'__declspec(dllexport)' cannot be applied to more than one default constructor in %0">;
def err_attribute_weakref_not_static : Error<
"weakref declaration must have internal linkage">;
def err_attribute_weakref_not_global_context : Error<
"weakref declaration of %0 must be in a global context">;
def err_attribute_weakref_without_alias : Error<
"weakref declaration of %0 must also have an alias attribute">;
def err_alias_not_supported_on_darwin : Error <
"aliases are not supported on darwin">;
def warn_attribute_wrong_decl_type_str : Warning<
"%0 attribute only applies to %1">, InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type_str : Error<
warn_attribute_wrong_decl_type_str.Text>;
def warn_attribute_wrong_decl_type : Warning<
"%0 attribute only applies to %select{"
"functions"
"|unions"
"|variables and functions"
"|functions and methods"
"|functions, methods and blocks"
"|functions, methods, and parameters"
"|variables"
"|variables and fields"
"|variables, data members and tag types"
"|types and namespaces"
"|variables, functions and classes"
"|kernel functions"
"|non-K&R-style functions}1">,
InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
def warn_type_attribute_wrong_type : Warning<
"'%0' only applies to %select{function|pointer|"
"Objective-C object or block pointer}1 types; type here is %2">,
InGroup<IgnoredAttributes>;
def warn_incomplete_encoded_type : Warning<
"encoding of %0 type is incomplete because %1 component has unknown encoding">,
InGroup<DiagGroup<"encode-type">>;
def warn_gnu_inline_attribute_requires_inline : Warning<
"'gnu_inline' attribute requires function to be marked 'inline',"
" attribute ignored">,
InGroup<IgnoredAttributes>;
def warn_gnu_inline_cplusplus_without_extern : Warning<
"'gnu_inline' attribute without 'extern' in C++ treated as externally"
" available, this changed in Clang 10">,
InGroup<DiagGroup<"gnu-inline-cpp-without-extern">>;
def err_attribute_vecreturn_only_vector_member : Error<
"the vecreturn attribute can only be used on a class or structure with one member, which must be a vector">;
def err_attribute_vecreturn_only_pod_record : Error<
"the vecreturn attribute can only be used on a POD (plain old data) class or structure (i.e. no virtual functions)">;
def err_cconv_change : Error<
"function declared '%0' here was previously declared "
"%select{'%2'|without calling convention}1">;
def warn_cconv_unsupported : Warning<
"%0 calling convention is not supported %select{"
// Use CallingConventionIgnoredReason Enum to specify these.
"for this target"
"|on variadic function"
"|on constructor/destructor"
"|on builtin function"
"}1">,
InGroup<IgnoredAttributes>;
def error_cconv_unsupported : Error<warn_cconv_unsupported.Text>;
def err_cconv_knr : Error<
"function with no prototype cannot use the %0 calling convention">;
def warn_cconv_knr : Warning<
err_cconv_knr.Text>,
InGroup<DiagGroup<"missing-prototype-for-cc">>;
def err_cconv_varargs : Error<
"variadic function cannot use %0 calling convention">;
def err_regparm_mismatch : Error<"function declared with regparm(%0) "
"attribute was previously declared "
"%plural{0:without the regparm|:with the regparm(%1)}1 attribute">;
def err_function_attribute_mismatch : Error<
"function declared with %0 attribute "
"was previously declared without the %0 attribute">;
def err_objc_precise_lifetime_bad_type : Error<
"objc_precise_lifetime only applies to retainable types; type here is %0">;
def warn_objc_precise_lifetime_meaningless : Error<
"objc_precise_lifetime is not meaningful for "
"%select{__unsafe_unretained|__autoreleasing}0 objects">;
def err_invalid_pcs : Error<"invalid PCS type">;
def warn_attribute_not_on_decl : Warning<
"%0 attribute ignored when parsing type">, InGroup<IgnoredAttributes>;
def err_base_specifier_attribute : Error<
"%0 attribute cannot be applied to a base specifier">;
def warn_declspec_allocator_nonpointer : Warning<
"ignoring __declspec(allocator) because the function return type %0 is not "
"a pointer or reference type">, InGroup<IgnoredAttributes>;
def err_cconv_incomplete_param_type : Error<
"parameter %0 must have a complete type to use function %1 with the %2 "
"calling convention">;
def err_attribute_output_parameter : Error<
"attribute only applies to output parameters">;
def ext_cannot_use_trivial_abi : ExtWarn<
"'trivial_abi' cannot be applied to %0">, InGroup<IgnoredAttributes>;
def note_cannot_use_trivial_abi_reason : Note<
"'trivial_abi' is disallowed on %0 because %select{"
"its copy constructors and move constructors are all deleted|"
"it is polymorphic|"
"it has a base of a non-trivial class type|it has a virtual base|"
"it has a __weak field|it has a field of a non-trivial class type}1">;
// Availability attribute
def warn_availability_unknown_platform : Warning<
"unknown platform %0 in availability macro">, InGroup<Availability>;
def warn_availability_version_ordering : Warning<
"feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version "
"%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; "
"attribute ignored">, InGroup<Availability>;
def warn_mismatched_availability: Warning<
"availability does not match previous declaration">, InGroup<Availability>;
def warn_mismatched_availability_override : Warning<
"%select{|overriding }4method %select{introduced after|"
"deprecated before|obsoleted before}0 "
"%select{the protocol method it implements|overridden method}4 "
"on %1 (%2 vs. %3)">, InGroup<Availability>;
def warn_mismatched_availability_override_unavail : Warning<
"%select{|overriding }1method cannot be unavailable on %0 when "
"%select{the protocol method it implements|its overridden method}1 is "
"available">,
InGroup<Availability>;
def warn_availability_on_static_initializer : Warning<
"ignoring availability attribute %select{on '+load' method|"
"with constructor attribute|with destructor attribute}0">,
InGroup<Availability>;
def note_overridden_method : Note<
"overridden method is here">;
def warn_availability_swift_unavailable_deprecated_only : Warning<
"only 'unavailable' and 'deprecated' are supported for Swift availability">,
InGroup<Availability>;
def note_protocol_method : Note<
"protocol method is here">;
def warn_availability_fuchsia_unavailable_minor : Warning<
"Fuchsia API Level prohibits specifying a minor or sub-minor version">,
InGroup<Availability>;
def warn_unguarded_availability :
Warning<"%0 is only available on %1 %2 or newer">,
InGroup<UnguardedAvailability>, DefaultIgnore;
def warn_unguarded_availability_new :
Warning<warn_unguarded_availability.Text>,
InGroup<UnguardedAvailabilityNew>;
def note_decl_unguarded_availability_silence : Note<
"annotate %select{%1|anonymous %1}0 with an availability attribute to silence this warning">;
def note_unguarded_available_silence : Note<
"enclose %0 in %select{an @available|a __builtin_available}1 check to silence"
" this warning">;
def warn_at_available_unchecked_use : Warning<
"%select{@available|__builtin_available}0 does not guard availability here; "
"use if (%select{@available|__builtin_available}0) instead">,
InGroup<DiagGroup<"unsupported-availability-guard">>;
def warn_missing_sdksettings_for_availability_checking : Warning<
"%0 availability is ignored without a valid 'SDKSettings.json' in the SDK">,
InGroup<DiagGroup<"ignored-availability-without-sdk-settings">>;
// Thread Safety Attributes
def warn_thread_attribute_ignored : Warning<
"ignoring %0 attribute because its argument is invalid">,
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
def warn_thread_attribute_not_on_non_static_member : Warning<
"%0 attribute without capability arguments can only be applied to non-static "
"methods of a class">,
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
def warn_thread_attribute_not_on_capability_member : Warning<
"%0 attribute without capability arguments refers to 'this', but %1 isn't "
"annotated with 'capability' or 'scoped_lockable' attribute">,
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
def warn_thread_attribute_argument_not_lockable : Warning<
"%0 attribute requires arguments whose type is annotated "
"with 'capability' attribute; type here is %1">,
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
def warn_thread_attribute_decl_not_lockable : Warning<
"%0 attribute can only be applied in a context annotated "
"with 'capability' attribute">,
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
def warn_thread_attribute_decl_not_pointer : Warning<
"%0 only applies to pointer types; type here is %1">,
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
def err_attribute_argument_out_of_bounds_extra_info : Error<
"%0 attribute parameter %1 is out of bounds: "
"%plural{0:no parameters to index into|"
"1:can only be 1, since there is one parameter|"
":must be between 1 and %2}2">;
// Thread Safety Analysis
def warn_unlock_but_no_lock : Warning<"releasing %0 '%1' that was not held">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_unlock_kind_mismatch : Warning<
"releasing %0 '%1' using %select{shared|exclusive}2 access, expected "
"%select{shared|exclusive}3 access">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_double_lock : Warning<"acquiring %0 '%1' that is already held">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_no_unlock : Warning<
"%0 '%1' is still held at the end of function">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_expecting_locked : Warning<
"expecting %0 '%1' to be held at the end of function">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
// FIXME: improve the error message about locks not in scope
def warn_lock_some_predecessors : Warning<
"%0 '%1' is not held on every path through here">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_expecting_lock_held_on_loop : Warning<
"expecting %0 '%1' to be held at start of each loop">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def note_locked_here : Note<"%0 acquired here">;
def note_unlocked_here : Note<"%0 released here">;
def warn_lock_exclusive_and_shared : Warning<
"%0 '%1' is acquired exclusively and shared in the same scope">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def note_lock_exclusive_and_shared : Note<
"the other acquisition of %0 '%1' is here">;
def warn_variable_requires_any_lock : Warning<
"%select{reading|writing}1 variable %0 requires holding "
"%select{any mutex|any mutex exclusively}1">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_var_deref_requires_any_lock : Warning<
"%select{reading|writing}1 the value pointed to by %0 requires holding "
"%select{any mutex|any mutex exclusively}1">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_fun_excludes_mutex : Warning<
"cannot call function '%1' while %0 '%2' is held">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_cannot_resolve_lock : Warning<
"cannot resolve lock expression">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_acquired_before : Warning<
"%0 '%1' must be acquired before '%2'">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_acquired_before_after_cycle : Warning<
"Cycle in acquired_before/after dependencies, starting with '%0'">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
// Thread safety warnings negative capabilities
def warn_acquire_requires_negative_cap : Warning<
"acquiring %0 '%1' requires negative capability '%2'">,
InGroup<ThreadSafetyNegative>, DefaultIgnore;
def warn_fun_requires_negative_cap : Warning<
"calling function %0 requires negative capability '%1'">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
// Thread safety warnings on pass by reference
def warn_guarded_pass_by_reference : Warning<
"passing variable %1 by reference requires holding %0 "
"%select{'%2'|'%2' exclusively}3">,
InGroup<ThreadSafetyReference>, DefaultIgnore;
def warn_pt_guarded_pass_by_reference : Warning<
"passing the value that %1 points to by reference requires holding %0 "
"%select{'%2'|'%2' exclusively}3">,
InGroup<ThreadSafetyReference>, DefaultIgnore;
// Imprecise thread safety warnings
def warn_variable_requires_lock : Warning<
"%select{reading|writing}3 variable %1 requires holding %0 "
"%select{'%2'|'%2' exclusively}3">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_var_deref_requires_lock : Warning<
"%select{reading|writing}3 the value pointed to by %1 requires "
"holding %0 %select{'%2'|'%2' exclusively}3">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_fun_requires_lock : Warning<
"calling function %1 requires holding %0 %select{'%2'|'%2' exclusively}3">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
// Precise thread safety warnings
def warn_variable_requires_lock_precise :
Warning<warn_variable_requires_lock.Text>,
InGroup<ThreadSafetyPrecise>, DefaultIgnore;
def warn_var_deref_requires_lock_precise :
Warning<warn_var_deref_requires_lock.Text>,
InGroup<ThreadSafetyPrecise>, DefaultIgnore;
def warn_fun_requires_lock_precise :
Warning<warn_fun_requires_lock.Text>,
InGroup<ThreadSafetyPrecise>, DefaultIgnore;
def note_found_mutex_near_match : Note<"found near match '%0'">;
// Verbose thread safety warnings
def warn_thread_safety_verbose : Warning<"thread safety verbose warning">,
InGroup<ThreadSafetyVerbose>, DefaultIgnore;
def note_thread_warning_in_fun : Note<"thread warning in function %0">;
def note_guarded_by_declared_here : Note<"guarded_by declared here">;
// Dummy warning that will trigger "beta" warnings from the analysis if enabled.
def warn_thread_safety_beta : Warning<"thread safety beta warning">,
InGroup<ThreadSafetyBeta>, DefaultIgnore;
// Consumed warnings
def warn_use_in_invalid_state : Warning<
"invalid invocation of method '%0' on object '%1' while it is in the '%2' "
"state">, InGroup<Consumed>, DefaultIgnore;
def warn_use_of_temp_in_invalid_state : Warning<
"invalid invocation of method '%0' on a temporary object while it is in the "
"'%1' state">, InGroup<Consumed>, DefaultIgnore;
def warn_attr_on_unconsumable_class : Warning<
"consumed analysis attribute is attached to member of class %0 which isn't "
"marked as consumable">, InGroup<Consumed>, DefaultIgnore;
def warn_return_typestate_for_unconsumable_type : Warning<
"return state set for an unconsumable type '%0'">, InGroup<Consumed>,
DefaultIgnore;
def warn_return_typestate_mismatch : Warning<
"return value not in expected state; expected '%0', observed '%1'">,
InGroup<Consumed>, DefaultIgnore;
def warn_loop_state_mismatch : Warning<
"state of variable '%0' must match at the entry and exit of loop">,
InGroup<Consumed>, DefaultIgnore;
def warn_param_return_typestate_mismatch : Warning<
"parameter '%0' not in expected state when the function returns: expected "
"'%1', observed '%2'">, InGroup<Consumed>, DefaultIgnore;
def warn_param_typestate_mismatch : Warning<
"argument not in expected state; expected '%0', observed '%1'">,
InGroup<Consumed>, DefaultIgnore;
// no_sanitize attribute
def warn_unknown_sanitizer_ignored : Warning<
"unknown sanitizer '%0' ignored">, InGroup<UnknownSanitizers>;
def warn_impcast_vector_scalar : Warning<
"implicit conversion turns vector to scalar: %0 to %1">,
InGroup<Conversion>, DefaultIgnore;
def warn_impcast_complex_scalar : Warning<
"implicit conversion discards imaginary component: %0 to %1">,
InGroup<Conversion>, DefaultIgnore;
def err_impcast_complex_scalar : Error<
"implicit conversion from %0 to %1 is not permitted in C++">;
def warn_impcast_float_precision : Warning<
"implicit conversion loses floating-point precision: %0 to %1">,
InGroup<ImplicitFloatConversion>, DefaultIgnore;
def warn_impcast_float_result_precision : Warning<
"implicit conversion when assigning computation result loses floating-point precision: %0 to %1">,
InGroup<ImplicitFloatConversion>, DefaultIgnore;
def warn_impcast_double_promotion : Warning<
"implicit conversion increases floating-point precision: %0 to %1">,
InGroup<DoublePromotion>, DefaultIgnore;
def warn_impcast_integer_sign : Warning<
"implicit conversion changes signedness: %0 to %1">,
InGroup<SignConversion>, DefaultIgnore;
def warn_impcast_integer_sign_conditional : Warning<
"operand of ? changes signedness: %0 to %1">,
InGroup<SignConversion>, DefaultIgnore;
def warn_impcast_integer_precision : Warning<
"implicit conversion loses integer precision: %0 to %1">,
InGroup<ImplicitIntConversion>, DefaultIgnore;
def warn_impcast_high_order_zero_bits : Warning<
"higher order bits are zeroes after implicit conversion">,
InGroup<ImplicitIntConversion>, DefaultIgnore;
def warn_impcast_nonnegative_result : Warning<
"the resulting value is always non-negative after implicit conversion">,
InGroup<SignConversion>, DefaultIgnore;
def warn_impcast_integer_64_32 : Warning<
"implicit conversion loses integer precision: %0 to %1">,
InGroup<Shorten64To32>, DefaultIgnore;
def warn_impcast_integer_precision_constant : Warning<
"implicit conversion from %2 to %3 changes value from %0 to %1">,
InGroup<ConstantConversion>;
def warn_impcast_bitfield_precision_constant : Warning<
"implicit truncation from %2 to bit-field changes value from %0 to %1">,
InGroup<BitFieldConstantConversion>;
def warn_impcast_constant_value_to_objc_bool : Warning<
"implicit conversion from constant value %0 to 'BOOL'; "
"the only well defined values for 'BOOL' are YES and NO">,
InGroup<ObjCBoolConstantConversion>;
def warn_impcast_fixed_point_range : Warning<
"implicit conversion from %0 cannot fit within the range of values for %1">,
InGroup<ImplicitFixedPointConversion>;
def warn_impcast_literal_float_to_integer : Warning<
"implicit conversion from %0 to %1 changes value from %2 to %3">,
InGroup<LiteralConversion>;
def warn_impcast_literal_float_to_integer_out_of_range : Warning<
"implicit conversion of out of range value from %0 to %1 is undefined">,
InGroup<LiteralConversion>;
def warn_impcast_float_integer : Warning<
"implicit conversion turns floating-point number into integer: %0 to %1">,
InGroup<FloatConversion>, DefaultIgnore;
def warn_impcast_float_to_objc_signed_char_bool : Warning<
"implicit conversion from floating-point type %0 to 'BOOL'">,
InGroup<ObjCSignedCharBoolImplicitFloatConversion>;
def warn_impcast_int_to_objc_signed_char_bool : Warning<
"implicit conversion from integral type %0 to 'BOOL'">,
InGroup<ObjCSignedCharBoolImplicitIntConversion>, DefaultIgnore;
// Implicit int -> float conversion precision loss warnings.
def warn_impcast_integer_float_precision : Warning<
"implicit conversion from %0 to %1 may lose precision">,
InGroup<ImplicitIntFloatConversion>, DefaultIgnore;
def warn_impcast_integer_float_precision_constant : Warning<
"implicit conversion from %2 to %3 changes value from %0 to %1">,
InGroup<ImplicitConstIntFloatConversion>;
def warn_impcast_float_to_integer : Warning<
"implicit conversion from %0 to %1 changes value from %2 to %3">,
InGroup<FloatOverflowConversion>, DefaultIgnore;
def warn_impcast_float_to_integer_out_of_range : Warning<
"implicit conversion of out of range value from %0 to %1 is undefined">,
InGroup<FloatOverflowConversion>, DefaultIgnore;
def warn_impcast_float_to_integer_zero : Warning<
"implicit conversion from %0 to %1 changes non-zero value from %2 to %3">,
InGroup<FloatZeroConversion>, DefaultIgnore;
def warn_impcast_string_literal_to_bool : Warning<
"implicit conversion turns string literal into bool: %0 to %1">,
InGroup<StringConversion>, DefaultIgnore;
def warn_impcast_different_enum_types : Warning<
"implicit conversion from enumeration type %0 to different enumeration type "
"%1">, InGroup<EnumConversion>;
def warn_impcast_bool_to_null_pointer : Warning<
"initialization of pointer of type %0 to null from a constant boolean "
"expression">, InGroup<BoolConversion>;
def warn_non_literal_null_pointer : Warning<
"expression which evaluates to zero treated as a null pointer constant of "
"type %0">, InGroup<NonLiteralNullConversion>;
def warn_pointer_compare : Warning<
"comparing a pointer to a null character constant; did you mean "
"to compare to %select{NULL|(void *)0}0?">,
InGroup<DiagGroup<"pointer-compare">>;
def warn_impcast_null_pointer_to_integer : Warning<
"implicit conversion of %select{NULL|nullptr}0 constant to %1">,
InGroup<NullConversion>;
def warn_impcast_floating_point_to_bool : Warning<
"implicit conversion turns floating-point number into bool: %0 to %1">,
InGroup<ImplicitConversionFloatingPointToBool>;
def ext_ms_impcast_fn_obj : ExtWarn<
"implicit conversion between pointer-to-function and pointer-to-object is a "
"Microsoft extension">, InGroup<MicrosoftCast>;
def warn_impcast_pointer_to_bool : Warning<
"address of%select{| function| array}0 '%1' will always evaluate to "
"'true'">,
InGroup<PointerBoolConversion>;
def warn_cast_nonnull_to_bool : Warning<
"nonnull %select{function call|parameter}0 '%1' will evaluate to "
"'true' on first encounter">,
InGroup<PointerBoolConversion>;
def warn_this_bool_conversion : Warning<
"'this' pointer cannot be null in well-defined C++ code; pointer may be "
"assumed to always convert to true">, InGroup<UndefinedBoolConversion>;
def warn_address_of_reference_bool_conversion : Warning<
"reference cannot be bound to dereferenced null pointer in well-defined C++ "
"code; pointer may be assumed to always convert to true">,
InGroup<UndefinedBoolConversion>;
def warn_xor_used_as_pow : Warning<
"result of '%0' is %1; did you mean exponentiation?">,
InGroup<XorUsedAsPow>;
def warn_xor_used_as_pow_base_extra : Warning<
"result of '%0' is %1; did you mean '%2' (%3)?">,
InGroup<XorUsedAsPow>;
def warn_xor_used_as_pow_base : Warning<
"result of '%0' is %1; did you mean '%2'?">,
InGroup<XorUsedAsPow>;
def note_xor_used_as_pow_silence : Note<
"replace expression with '%0' %select{|or use 'xor' instead of '^' }1to silence this warning">;
def warn_null_pointer_compare : Warning<
"comparison of %select{address of|function|array}0 '%1' %select{not |}2"
"equal to a null pointer is always %select{true|false}2">,
InGroup<TautologicalPointerCompare>;
def warn_nonnull_expr_compare : Warning<
"comparison of nonnull %select{function call|parameter}0 '%1' "
"%select{not |}2equal to a null pointer is '%select{true|false}2' on first "
"encounter">,
InGroup<TautologicalPointerCompare>;
def warn_this_null_compare : Warning<
"'this' pointer cannot be null in well-defined C++ code; comparison may be "
"assumed to always evaluate to %select{true|false}0">,
InGroup<TautologicalUndefinedCompare>;
def warn_address_of_reference_null_compare : Warning<
"reference cannot be bound to dereferenced null pointer in well-defined C++ "
"code; comparison may be assumed to always evaluate to "
"%select{true|false}0">,
InGroup<TautologicalUndefinedCompare>;
def note_reference_is_return_value : Note<"%0 returns a reference">;
def note_pointer_declared_here : Note<
"pointer %0 declared here">;
def warn_division_sizeof_ptr : Warning<
"'%0' will return the size of the pointer, not the array itself">,
InGroup<DiagGroup<"sizeof-pointer-div">>;
def warn_division_sizeof_array : Warning<
"expression does not compute the number of elements in this array; element "
"type is %0, not %1">,
InGroup<DiagGroup<"sizeof-array-div">>;
def note_function_warning_silence : Note<
"prefix with the address-of operator to silence this warning">;
def note_function_to_function_call : Note<
"suffix with parentheses to turn this into a function call">;
def warn_impcast_objective_c_literal_to_bool : Warning<
"implicit boolean conversion of Objective-C object literal always "
"evaluates to true">,
InGroup<ObjCLiteralConversion>;
def warn_cast_align : Warning<
"cast from %0 to %1 increases required alignment from %2 to %3">,
InGroup<CastAlign>, DefaultIgnore;
def warn_old_style_cast : Warning<
"use of old-style cast">, InGroup<OldStyleCast>, DefaultIgnore,
SuppressInSystemMacro;
// Separate between casts to void* and non-void* pointers.
// Some APIs use (abuse) void* for something like a user context,
// and often that value is an integer even if it isn't a pointer itself.
// Having a separate warning flag allows users to control the warning
// for their workflow.
def warn_int_to_pointer_cast : Warning<
"cast to %1 from smaller integer type %0">,
InGroup<IntToPointerCast>;
def warn_int_to_void_pointer_cast : Warning<
"cast to %1 from smaller integer type %0">,
InGroup<IntToVoidPointerCast>;
def warn_pointer_to_int_cast : Warning<
"cast to smaller integer type %1 from %0">,
InGroup<PointerToIntCast>;
def warn_pointer_to_enum_cast : Warning<
warn_pointer_to_int_cast.Text>,
InGroup<PointerToEnumCast>;
def warn_void_pointer_to_int_cast : Warning<
"cast to smaller integer type %1 from %0">,
InGroup<VoidPointerToIntCast>;
def warn_void_pointer_to_enum_cast : Warning<
warn_void_pointer_to_int_cast.Text>,
InGroup<VoidPointerToEnumCast>;
def warn_attribute_ignored_for_field_of_type : Warning<
"%0 attribute ignored for field of type %1">,
InGroup<IgnoredAttributes>;
def warn_no_underlying_type_specified_for_enum_bitfield : Warning<
"enums in the Microsoft ABI are signed integers by default; consider giving "
"the enum %0 an unsigned underlying type to make this code portable">,
InGroup<SignedEnumBitfield>, DefaultIgnore;
def warn_attribute_packed_for_bitfield : Warning<
"'packed' attribute was ignored on bit-fields with single-byte alignment "
"in older versions of GCC and Clang">,
InGroup<DiagGroup<"attribute-packed-for-bitfield">>;
def warn_transparent_union_attribute_field_size_align : Warning<
"%select{alignment|size}0 of field %1 (%2 bits) does not match the "
"%select{alignment|size}0 of the first field in transparent union; "
"transparent_union attribute ignored">,
InGroup<IgnoredAttributes>;
def note_transparent_union_first_field_size_align : Note<
"%select{alignment|size}0 of first field is %1 bits">;
def warn_transparent_union_attribute_not_definition : Warning<
"transparent_union attribute can only be applied to a union definition; "
"attribute ignored">,
InGroup<IgnoredAttributes>;
def warn_transparent_union_attribute_floating : Warning<
"first field of a transparent union cannot have %select{floating point|"
"vector}0 type %1; transparent_union attribute ignored">,
InGroup<IgnoredAttributes>;
def warn_transparent_union_attribute_zero_fields : Warning<
"transparent union definition must contain at least one field; "
"transparent_union attribute ignored">,
InGroup<IgnoredAttributes>;
def warn_attribute_type_not_supported : Warning<
"%0 attribute argument not supported: %1">,
InGroup<IgnoredAttributes>;
def warn_attribute_unknown_visibility : Warning<"unknown visibility %0">,
InGroup<IgnoredAttributes>;
def warn_attribute_protected_visibility :
Warning<"target does not support 'protected' visibility; using 'default'">,
InGroup<DiagGroup<"unsupported-visibility">>;
def err_mismatched_visibility: Error<"visibility does not match previous declaration">;
def note_previous_attribute : Note<"previous attribute is here">;
def note_conflicting_attribute : Note<"conflicting attribute is here">;
def note_attribute : Note<"attribute is here">;
def err_mismatched_ms_inheritance : Error<
"inheritance model does not match %select{definition|previous declaration}0">;
def warn_ignored_ms_inheritance : Warning<
"inheritance model ignored on %select{primary template|partial specialization}0">,
InGroup<IgnoredAttributes>;
def note_previous_ms_inheritance : Note<
"previous inheritance model specified here">;
def err_machine_mode : Error<"%select{unknown|unsupported}0 machine mode %1">;
def err_mode_not_primitive : Error<
"mode attribute only supported for integer and floating-point types">;
def err_mode_wrong_type : Error<
"type of machine mode does not match type of base type">;
def warn_vector_mode_deprecated : Warning<
"specifying vector types with the 'mode' attribute is deprecated; "
"use the 'vector_size' attribute instead">,
InGroup<DeprecatedAttributes>;
def warn_deprecated_noreturn_spelling : Warning<
"the '[[_Noreturn]]' attribute spelling is deprecated in C2x; use "
"'[[noreturn]]' instead">, InGroup<DeprecatedAttributes>;
def err_complex_mode_vector_type : Error<
"type of machine mode does not support base vector types">;
def err_enum_mode_vector_type : Error<
"mode %0 is not supported for enumeration types">;
def warn_attribute_nonnull_no_pointers : Warning<
"'nonnull' attribute applied to function with no pointer arguments">,
InGroup<IgnoredAttributes>;
def warn_attribute_nonnull_parm_no_args : Warning<
"'nonnull' attribute when used on parameters takes no arguments">,
InGroup<IgnoredAttributes>;
def warn_function_stmt_attribute_precedence : Warning<
"statement attribute %0 has higher precedence than function attribute "
"'%select{always_inline|flatten|noinline}1'">,
InGroup<IgnoredAttributes>;
def note_declared_nonnull : Note<
"declared %select{'returns_nonnull'|'nonnull'}0 here">;
def warn_attribute_sentinel_named_arguments : Warning<
"'sentinel' attribute requires named arguments">,
InGroup<IgnoredAttributes>;
def warn_attribute_sentinel_not_variadic : Warning<
"'sentinel' attribute only supported for variadic %select{functions|blocks}0">,
InGroup<IgnoredAttributes>;
def warn_deprecated_ignored_on_using : Warning<
"%0 currently has no effect on a using declaration">,
InGroup<IgnoredAttributes>;
def err_attribute_sentinel_less_than_zero : Error<
"'sentinel' parameter 1 less than zero">;
def err_attribute_sentinel_not_zero_or_one : Error<
"'sentinel' parameter 2 not 0 or 1">;
def warn_cleanup_ext : Warning<
"GCC does not allow the 'cleanup' attribute argument to be anything other "
"than a simple identifier">,
InGroup<GccCompat>;
def err_attribute_cleanup_arg_not_function : Error<
"'cleanup' argument %select{|%1 |%1 }0is not a %select{||single }0function">;
def err_attribute_cleanup_func_must_take_one_arg : Error<
"'cleanup' function %0 must take 1 parameter">;
def err_attribute_cleanup_func_arg_incompatible_type : Error<
"'cleanup' function %0 parameter has "
"%diff{type $ which is incompatible with type $|incompatible type}1,2">;
def err_attribute_regparm_wrong_platform : Error<
"'regparm' is not valid on this platform">;
def err_attribute_regparm_invalid_number : Error<
"'regparm' parameter must be between 0 and %0 inclusive">;
def err_attribute_not_supported_in_lang : Error<
"%0 attribute is not supported in %select{C|C++|Objective-C}1">;
def err_attribute_not_supported_on_arch
: Error<"%0 attribute is not supported on '%1'">;
def warn_gcc_ignores_type_attr : Warning<
"GCC does not allow the %0 attribute to be written on a type">,
InGroup<GccCompat>;
def warn_gcc_requires_variadic_function : Warning<
"GCC requires a function with the %0 attribute to be variadic">,
InGroup<GccCompat>;
// Clang-Specific Attributes
def warn_attribute_iboutlet : Warning<
"%0 attribute can only be applied to instance variables or properties">,
InGroup<IgnoredAttributes>;
def err_iboutletcollection_type : Error<
"invalid type %0 as argument of iboutletcollection attribute">;
def err_iboutletcollection_builtintype : Error<
"type argument of iboutletcollection attribute cannot be a builtin type">;
def warn_iboutlet_object_type : Warning<
"%select{instance variable|property}2 with %0 attribute must "
"be an object type (invalid %1)">, InGroup<ObjCInvalidIBOutletProperty>;
def warn_iboutletcollection_property_assign : Warning<
"IBOutletCollection properties should be copy/strong and not assign">,
InGroup<ObjCInvalidIBOutletProperty>;
def err_attribute_overloadable_mismatch : Error<
"redeclaration of %0 must %select{not |}1have the 'overloadable' attribute">;
def note_attribute_overloadable_prev_overload : Note<
"previous %select{unmarked |}0overload of function is here">;
def err_attribute_overloadable_no_prototype : Error<
"'overloadable' function %0 must have a prototype">;
def err_attribute_overloadable_multiple_unmarked_overloads : Error<
"at most one overload for a given name may lack the 'overloadable' "
"attribute">;
def warn_attribute_no_builtin_invalid_builtin_name : Warning<
"'%0' is not a valid builtin name for %1">,
InGroup<DiagGroup<"invalid-no-builtin-names">>;
def err_attribute_no_builtin_wildcard_or_builtin_name : Error<
"empty %0 cannot be composed with named ones">;
def err_attribute_no_builtin_on_non_definition : Error<
"%0 attribute is permitted on definitions only">;
def err_attribute_no_builtin_on_defaulted_deleted_function : Error<
"%0 attribute has no effect on defaulted or deleted functions">;
def warn_ns_attribute_wrong_return_type : Warning<
"%0 attribute only applies to %select{functions|methods|properties}1 that "
"return %select{an Objective-C object|a pointer|a non-retainable pointer}2">,
InGroup<IgnoredAttributes>;
def err_ns_attribute_wrong_parameter_type : Error<
"%0 attribute only applies to "
"%select{Objective-C object|pointer|pointer-to-CF-pointer}1 parameters">;
def warn_ns_attribute_wrong_parameter_type : Warning<
"%0 attribute only applies to "
"%select{Objective-C object|pointer|pointer-to-CF-pointer|pointer/reference-to-OSObject-pointer}1 parameters">,
InGroup<IgnoredAttributes>;
def warn_objc_requires_super_protocol : Warning<
"%0 attribute cannot be applied to %select{methods in protocols|dealloc}1">,
InGroup<DiagGroup<"requires-super-attribute">>;
def note_protocol_decl : Note<
"protocol is declared here">;
def note_protocol_decl_undefined : Note<
"protocol %0 has no definition">;
def err_attribute_preferred_name_arg_invalid : Error<
"argument %0 to 'preferred_name' attribute is not a typedef for "
"a specialization of %1">;
def err_attribute_builtin_alias : Error<
"%0 attribute can only be applied to a ARM, HLSL or RISC-V builtin">;
// called-once attribute diagnostics.
def err_called_once_attribute_wrong_type : Error<
"'called_once' attribute only applies to function-like parameters">;
def warn_completion_handler_never_called : Warning<
"%select{|captured }1completion handler is never called">,
InGroup<CompletionHandler>, DefaultIgnore;
def warn_called_once_never_called : Warning<
"%select{|captured }1%0 parameter marked 'called_once' is never called">,
InGroup<CalledOnceParameter>;
def warn_completion_handler_never_called_when : Warning<
"completion handler is never %select{used|called}1 when "
"%select{taking true branch|taking false branch|"
"handling this case|none of the cases applies|"
"entering the loop|skipping the loop|taking one of the branches}2">,
InGroup<CompletionHandler>, DefaultIgnore;
def warn_called_once_never_called_when : Warning<
"%0 parameter marked 'called_once' is never %select{used|called}1 when "
"%select{taking true branch|taking false branch|"
"handling this case|none of the cases applies|"
"entering the loop|skipping the loop|taking one of the branches}2">,
InGroup<CalledOnceParameter>;
def warn_completion_handler_called_twice : Warning<
"completion handler is called twice">,
InGroup<CompletionHandler>, DefaultIgnore;
def warn_called_once_gets_called_twice : Warning<
"%0 parameter marked 'called_once' is called twice">,
InGroup<CalledOnceParameter>;
def note_called_once_gets_called_twice : Note<
"previous call is here%select{; set to nil to indicate "
"it cannot be called afterwards|}0">;
// objc_designated_initializer attribute diagnostics.
def warn_objc_designated_init_missing_super_call : Warning<
"designated initializer missing a 'super' call to a designated initializer of the super class">,
InGroup<ObjCDesignatedInit>;
def note_objc_designated_init_marked_here : Note<
"method marked as designated initializer of the class here">;
def warn_objc_designated_init_non_super_designated_init_call : Warning<
"designated initializer should only invoke a designated initializer on 'super'">,
InGroup<ObjCDesignatedInit>;
def warn_objc_designated_init_non_designated_init_call : Warning<
"designated initializer invoked a non-designated initializer">,
InGroup<ObjCDesignatedInit>;
def warn_objc_secondary_init_super_init_call : Warning<
"convenience initializer should not invoke an initializer on 'super'">,
InGroup<ObjCDesignatedInit>;
def warn_objc_secondary_init_missing_init_call : Warning<
"convenience initializer missing a 'self' call to another initializer">,
InGroup<ObjCDesignatedInit>;
def warn_objc_implementation_missing_designated_init_override : Warning<
"method override for the designated initializer of the superclass %objcinstance0 not found">,
InGroup<ObjCDesignatedInit>;
def err_designated_init_attr_non_init : Error<
"'objc_designated_initializer' attribute only applies to init methods "
"of interface or class extension declarations">;
// objc_bridge attribute diagnostics.
def err_objc_attr_not_id : Error<
"parameter of %0 attribute must be a single name of an Objective-C %select{class|protocol}1">;
def err_objc_attr_typedef_not_id : Error<
"parameter of %0 attribute must be 'id' when used on a typedef">;
def err_objc_attr_typedef_not_void_pointer : Error<
"'objc_bridge(id)' is only allowed on structs and typedefs of void pointers">;
def err_objc_cf_bridged_not_interface : Error<
"CF object of type %0 is bridged to %1, which is not an Objective-C class">;
def err_objc_ns_bridged_invalid_cfobject : Error<
"ObjectiveC object of type %0 is bridged to %1, which is not valid CF object">;
def warn_objc_invalid_bridge : Warning<
"%0 bridges to %1, not %2">, InGroup<ObjCBridge>;
def warn_objc_invalid_bridge_to_cf : Warning<
"%0 cannot bridge to %1">, InGroup<ObjCBridge>;
// objc_bridge_related attribute diagnostics.
def err_objc_bridged_related_invalid_class : Error<
"could not find Objective-C class %0 to convert %1 to %2">;
def err_objc_bridged_related_invalid_class_name : Error<
"%0 must be name of an Objective-C class to be able to convert %1 to %2">;
def err_objc_bridged_related_known_method : Error<
"%0 must be explicitly converted to %1; use %select{%objcclass2|%objcinstance2}3 "
"method for this conversion">;
def err_objc_attr_protocol_requires_definition : Error<
"attribute %0 can only be applied to @protocol definitions, not forward declarations">;
// Swift attributes.
def warn_attr_swift_name_function
: Warning<"%0 attribute argument must be a string literal specifying a Swift function name">,
InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_invalid_identifier
: Warning<"%0 attribute has invalid identifier for the %select{base|context|parameter}1 name">,
InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_decl_kind
: Warning<"%0 attribute cannot be applied to this declaration">,
InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_subscript_invalid_parameter
: Warning<"%0 attribute for 'subscript' must %select{be a getter or setter|"
"have at least one parameter|"
"have a 'self:' parameter}1">,
InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_missing_parameters
: Warning<"%0 attribute is missing parameter label clause">,
InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_setter_parameters
: Warning<"%0 attribute for setter must have one parameter for new value">,
InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_multiple_selfs
: Warning<"%0 attribute cannot specify more than one 'self:' parameter">,
InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_getter_parameters
: Warning<"%0 attribute for getter must not have any parameters besides 'self:'">,
InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_subscript_setter_no_newValue
: Warning<"%0 attribute for 'subscript' setter must have a 'newValue:' parameter">,
InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_subscript_setter_multiple_newValues
: Warning<"%0 attribute for 'subscript' setter cannot have multiple 'newValue:' parameters">,
InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_subscript_getter_newValue
: Warning<"%0 attribute for 'subscript' getter cannot have a 'newValue:' parameter">,
InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_num_params
: Warning<"too %select{few|many}0 parameters in the signature specified by "
"the %1 attribute (expected %2; got %3)">,
InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_decl_missing_params
: Warning<"%0 attribute cannot be applied to a %select{function|method}1 "
"with no parameters">,
InGroup<SwiftNameAttribute>;
def err_attr_swift_error_no_error_parameter : Error<
"%0 attribute can only be applied to a %select{function|method}1 with an "
"error parameter">;
def err_attr_swift_error_return_type : Error<
"%0 attribute with '%1' convention can only be applied to a "
"%select{function|method}2 returning %select{an integral type|a pointer}3">;
def err_swift_async_no_access : Error<
"first argument to 'swift_async' must be either 'none', 'swift_private', or "
"'not_swift_private'">;
def err_swift_async_bad_block_type : Error<
"'swift_async' completion handler parameter must have block type returning"
" 'void', type here is %0">;
def err_swift_async_error_without_swift_async : Error<
"%0 attribute must be applied to a %select{function|method}1 annotated "
"with non-'none' attribute 'swift_async'">;
def err_swift_async_error_no_error_parameter : Error<
"%0 attribute with 'nonnull_error' convention can only be applied to a "
"%select{function|method}1 with a completion handler with an error "
"parameter">;
def err_swift_async_error_non_integral : Error<
"%0 attribute with '%1' convention must have an integral-typed parameter "
"in completion handler at index %2, type here is %3">;
def warn_ignored_objc_externally_retained : Warning<
"'objc_externally_retained' can only be applied to local variables "
"%select{of retainable type|with strong ownership}0">,
InGroup<IgnoredAttributes>;
// Function Parameter Semantic Analysis.
def err_param_with_void_type : Error<"argument may not have 'void' type">;
def err_void_only_param : Error<
"'void' must be the first and only parameter if specified">;
def err_void_param_qualified : Error<
"'void' as parameter must not have type qualifiers">;
def err_ident_list_in_fn_declaration : Error<
"a parameter list without types is only allowed in a function definition">;
def ext_param_not_declared : ExtWarn<
"parameter %0 was not declared, defaults to 'int'; ISO C99 and later do not "
- "support implicit int">, InGroup<ImplicitInt>, DefaultError;
+ "support implicit int">, InGroup<ImplicitInt>;
def err_param_default_argument : Error<
"C does not support default arguments">;
def err_param_default_argument_redefinition : Error<
"redefinition of default argument">;
def ext_param_default_argument_redefinition : ExtWarn<
err_param_default_argument_redefinition.Text>,
InGroup<MicrosoftDefaultArgRedefinition>;
def err_param_default_argument_missing : Error<
"missing default argument on parameter">;
def err_param_default_argument_missing_name : Error<
"missing default argument on parameter %0">;
def err_param_default_argument_references_param : Error<
"default argument references parameter %0">;
def err_param_default_argument_references_local : Error<
"default argument references local variable %0 of enclosing function">;
def err_param_default_argument_references_this : Error<
"default argument references 'this'">;
def err_param_default_argument_nonfunc : Error<
"default arguments can only be specified for parameters in a function "
"declaration">;
def err_param_default_argument_template_redecl : Error<
"default arguments cannot be added to a function template that has already "
"been declared">;
def err_param_default_argument_member_template_redecl : Error<
"default arguments cannot be added to an out-of-line definition of a member "
"of a %select{class template|class template partial specialization|nested "
"class in a template}0">;
def err_param_default_argument_on_parameter_pack : Error<
"parameter pack cannot have a default argument">;
def err_uninitialized_member_for_assign : Error<
"cannot define the implicit copy assignment operator for %0, because "
"non-static %select{reference|const}1 member %2 cannot use copy "
"assignment operator">;
def err_uninitialized_member_in_ctor : Error<
"%select{constructor for %1|"
"implicit default constructor for %1|"
"cannot use constructor inherited from %1:}0 must explicitly "
"initialize the %select{reference|const}2 member %3">;
def err_default_arg_makes_ctor_special : Error<
"addition of default argument on redeclaration makes this constructor a "
"%select{default|copy|move}0 constructor">;
def err_stmt_expr_in_default_arg : Error<
"default %select{argument|non-type template argument}0 may not use a GNU "
"statement expression">;
def err_use_of_default_argument_to_function_declared_later : Error<
"use of default argument to function %0 that is declared later in class %1">;
def note_default_argument_declared_here : Note<
"default argument declared here">;
def err_recursive_default_argument : Error<"recursive evaluation of default argument">;
def note_recursive_default_argument_used_here : Note<
"default argument used here">;
def ext_param_promoted_not_compatible_with_prototype : ExtWarn<
"%diff{promoted type $ of K&R function parameter is not compatible with the "
"parameter type $|promoted type of K&R function parameter is not compatible "
"with parameter type}0,1 declared in a previous prototype">,
InGroup<KNRPromotedParameter>;
// C++ Overloading Semantic Analysis.
def err_ovl_diff_return_type : Error<
"functions that differ only in their return type cannot be overloaded">;
def err_ovl_static_nonstatic_member : Error<
"static and non-static member functions with the same parameter types "
"cannot be overloaded">;
let Deferrable = 1 in {
def err_ovl_no_viable_function_in_call : Error<
"no matching function for call to %0">;
def err_ovl_no_viable_member_function_in_call : Error<
"no matching member function for call to %0">;
def err_ovl_ambiguous_call : Error<
"call to %0 is ambiguous">;
def err_ovl_deleted_call : Error<"call to deleted function %0">;
def err_ovl_ambiguous_member_call : Error<
"call to member function %0 is ambiguous">;
def err_ovl_deleted_member_call : Error<
"call to deleted member function %0">;
def note_ovl_too_many_candidates : Note<
"remaining %0 candidate%s0 omitted; "
"pass -fshow-overloads=all to show them">;
def select_ovl_candidate_kind : TextSubstitution<
"%select{function|function|function (with reversed parameter order)|"
"constructor|"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
"constructor (the implicit move constructor)|"
"function (the implicit copy assignment operator)|"
"function (the implicit move assignment operator)|"
"function (the implicit 'operator==' for this 'operator<=>)'|"
"inherited constructor}0%select{| template| %2}1">;
def note_ovl_candidate : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,3"
"%select{| has different class%diff{ (expected $ but has $)|}5,6"
"| has different number of parameters (expected %5 but has %6)"
"| has type mismatch at %ordinal5 parameter"
"%diff{ (expected $ but has $)|}6,7"
"| has different return type%diff{ ($ expected but has $)|}5,6"
"| has different qualifiers (expected %5 but found %6)"
"| has different exception specification}4">;
def note_ovl_candidate_explicit : Note<
"explicit %select{constructor|conversion function|deduction guide}0 "
"is not a candidate%select{| (explicit specifier evaluates to true)}1">;
def note_ovl_candidate_inherited_constructor : Note<
"constructor from base class %0 inherited here">;
def note_ovl_candidate_inherited_constructor_slice : Note<
"candidate %select{constructor|template}0 ignored: "
"inherited constructor cannot be used to %select{copy|move}1 object">;
def note_ovl_candidate_illegal_constructor : Note<
"candidate %select{constructor|template}0 ignored: "
"instantiation %select{takes|would take}0 its own class type by value">;
def note_ovl_candidate_illegal_constructor_adrspace_mismatch : Note<
"candidate constructor ignored: cannot be used to construct an object "
"in address space %0">;
def note_ovl_candidate_bad_deduction : Note<
"candidate template ignored: failed template argument deduction">;
def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: "
"couldn't infer template argument %0">;
def note_ovl_candidate_incomplete_deduction_pack : Note<
"candidate template ignored: "
"deduced too few arguments for expanded pack %0; no argument for %ordinal1 "
"expanded parameter in deduced argument pack %2">;
def note_ovl_candidate_inconsistent_deduction : Note<
"candidate template ignored: deduced %select{conflicting types|"
"conflicting values|conflicting templates|packs of different lengths}0 "
"for parameter %1%diff{ ($ vs. $)|}2,3">;
def note_ovl_candidate_inconsistent_deduction_types : Note<
"candidate template ignored: deduced values %diff{"
"of conflicting types for parameter %0 (%1 of type $ vs. %3 of type $)|"
"%1 and %3 of conflicting types for parameter %0}2,4">;
def note_ovl_candidate_explicit_arg_mismatch_named : Note<
"candidate template ignored: invalid explicitly-specified argument "
"for template parameter %0">;
def note_ovl_candidate_unsatisfied_constraints : Note<
"candidate template ignored: constraints not satisfied%0">;
def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note<
"candidate template ignored: invalid explicitly-specified argument "
"for %ordinal0 template parameter">;
def note_ovl_candidate_instantiation_depth : Note<
"candidate template ignored: substitution exceeded maximum template "
"instantiation depth">;
def note_ovl_candidate_underqualified : Note<
"candidate template ignored: cannot deduce a type for %0 that would "
"make %2 equal %1">;
def note_ovl_candidate_substitution_failure : Note<
"candidate template ignored: substitution failure%0%1">;
def note_ovl_candidate_disabled_by_enable_if : Note<
"candidate template ignored: disabled by %0%1">;
def note_ovl_candidate_disabled_by_requirement : Note<
"candidate template ignored: requirement '%0' was not satisfied%1">;
def note_ovl_candidate_has_pass_object_size_params: Note<
"candidate address cannot be taken because parameter %0 has "
"pass_object_size attribute">;
def err_diagnose_if_succeeded : Error<"%0">;
def warn_diagnose_if_succeeded : Warning<"%0">, InGroup<UserDefinedWarnings>,
ShowInSystemHeader;
def note_ovl_candidate_disabled_by_function_cond_attr : Note<
"candidate disabled: %0">;
def err_addrof_function_disabled_by_enable_if_attr : Error<
"cannot take address of function %0 because it has one or more "
"non-tautological enable_if conditions">;
def err_addrof_function_constraints_not_satisfied : Error<
"cannot take address of function %0 because its constraints are not "
"satisfied">;
def note_addrof_ovl_candidate_disabled_by_enable_if_attr : Note<
"candidate function made ineligible by enable_if">;
def note_ovl_candidate_deduced_mismatch : Note<
"candidate template ignored: deduced type "
"%diff{$ of %select{|element of }4%ordinal0 parameter does not match "
"adjusted type $ of %select{|element of }4argument"
"|of %select{|element of }4%ordinal0 parameter does not match "
"adjusted type of %select{|element of }4argument}1,2%3">;
def note_ovl_candidate_non_deduced_mismatch : Note<
"candidate template ignored: could not match %diff{$ against $|types}0,1">;
// This note is needed because the above note would sometimes print two
// different types with the same name. Remove this note when the above note
// can handle that case properly.
def note_ovl_candidate_non_deduced_mismatch_qualified : Note<
"candidate template ignored: could not match %q0 against %q1">;
// Note that we don't treat templates differently for this diagnostic.
def note_ovl_candidate_arity : Note<"candidate "
"%sub{select_ovl_candidate_kind}0,1,2 not viable: "
"requires%select{ at least| at most|}3 %4 argument%s4, but %5 "
"%plural{1:was|:were}5 provided">;
def note_ovl_candidate_arity_one : Note<"candidate "
"%sub{select_ovl_candidate_kind}0,1,2 not viable: "
"%select{requires at least|allows at most single|requires single}3 "
"argument %4, but %plural{0:no|:%5}5 arguments were provided">;
def note_ovl_candidate_deleted : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 has been "
"%select{explicitly made unavailable|explicitly deleted|"
"implicitly deleted}3">;
// Giving the index of the bad argument really clutters this message, and
// it's relatively unimportant because 1) it's generally obvious which
// argument(s) are of the given object type and 2) the fix is usually
// to complete the type, which doesn't involve changes to the call line
// anyway. If people complain, we can change it.
def note_ovl_candidate_bad_conv_incomplete : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"cannot convert argument of incomplete type "
"%diff{$ to $|to parameter type}3,4 for "
"%select{%ordinal6 argument|object argument}5"
"%select{|; dereference the argument with *|"
"; take the address of the argument with &|"
"; remove *|"
"; remove &}7">;
def note_ovl_candidate_bad_list_argument : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"%select{cannot convert initializer list|too few initializers in list"
"|too many initializers in list}7 argument to %4">;
def note_ovl_candidate_bad_overload : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"no overload of %4 matching %3 for %ordinal5 argument">;
def note_ovl_candidate_bad_conv : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"no known conversion "
"%diff{from $ to $|from argument type to parameter type}3,4 for "
"%select{%ordinal6 argument|object argument}5"
"%select{|; dereference the argument with *|"
"; take the address of the argument with &|"
"; remove *|"
"; remove &}7">;
def note_ovl_candidate_bad_arc_conv : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"cannot implicitly convert argument "
"%diff{of type $ to $|type to parameter type}3,4 for "
"%select{%ordinal6 argument|object argument}5 under ARC">;
def note_ovl_candidate_bad_value_category : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"expects an %select{lvalue|rvalue}5 for "
"%select{%ordinal4 argument|object argument}3">;
def note_ovl_candidate_bad_addrspace : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"cannot %select{pass pointer to|bind reference in}5 %3 "
"%select{as a pointer to|to object in}5 %4 in %ordinal6 "
"argument">;
def note_ovl_candidate_bad_addrspace_this : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"'this' object is in %3, but method expects object in %4">;
def note_ovl_candidate_bad_gc : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"%select{%ordinal7|'this'}6 argument (%3) has %select{no|__weak|__strong}4 "
"ownership, but parameter has %select{no|__weak|__strong}5 ownership">;
def note_ovl_candidate_bad_ownership : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"%select{%ordinal7|'this'}6 argument (%3) has "
"%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}4 ownership,"
" but parameter has %select{no|__unsafe_unretained|__strong|__weak|"
"__autoreleasing}5 ownership">;
def note_ovl_candidate_bad_cvr_this : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"'this' argument has type %3, but method is not marked "
"%select{const|restrict|const or restrict|volatile|const or volatile|"
"volatile or restrict|const, volatile, or restrict}4">;
def note_ovl_candidate_bad_cvr : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"%ordinal5 argument (%3) would lose "
"%select{const|restrict|const and restrict|volatile|const and volatile|"
"volatile and restrict|const, volatile, and restrict}4 qualifier"
"%select{||s||s|s|s}4">;
def note_ovl_candidate_bad_unaligned : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"%ordinal5 argument (%3) would lose __unaligned qualifier">;
def note_ovl_candidate_bad_base_to_derived_conv : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"cannot %select{convert from|convert from|bind}3 "
"%select{base class pointer|superclass|base class object of type}3 %4 to "
"%select{derived class pointer|subclass|derived class reference}3 %5 for "
"%ordinal6 argument">;
def note_ovl_candidate_bad_target : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"call to "
"%select{__device__|__global__|__host__|__host__ __device__|invalid}3 function from"
" %select{__device__|__global__|__host__|__host__ __device__|invalid}4 function">;
def note_ovl_candidate_constraints_not_satisfied : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: constraints "
"not satisfied">;
def note_implicit_member_target_infer_collision : Note<
"implicit %sub{select_special_member_kind}0 inferred target collision: call to both "
"%select{__device__|__global__|__host__|__host__ __device__}1 and "
"%select{__device__|__global__|__host__|__host__ __device__}2 members">;
def note_ambiguous_type_conversion: Note<
"because of ambiguity in conversion %diff{of $ to $|between types}0,1">;
def note_ovl_builtin_candidate : Note<"built-in candidate %0">;
def err_ovl_no_viable_function_in_init : Error<
"no matching constructor for initialization of %0">;
def err_ovl_no_conversion_in_cast : Error<
"cannot convert %1 to %2 without a conversion operator">;
def err_ovl_no_viable_conversion_in_cast : Error<
"no matching conversion for %select{|static_cast|reinterpret_cast|"
"dynamic_cast|C-style cast|functional-style cast|}0 from %1 to %2">;
def err_ovl_ambiguous_conversion_in_cast : Error<
"ambiguous conversion for %select{|static_cast|reinterpret_cast|"
"dynamic_cast|C-style cast|functional-style cast|}0 from %1 to %2">;
def err_ovl_deleted_conversion_in_cast : Error<
"%select{|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
"functional-style cast|}0 from %1 to %2 uses deleted function">;
def err_ovl_ambiguous_init : Error<"call to constructor of %0 is ambiguous">;
def err_ref_init_ambiguous : Error<
"reference initialization of type %0 with initializer of type %1 is ambiguous">;
def err_ovl_deleted_init : Error<
"call to deleted constructor of %0">;
def err_ovl_deleted_special_init : Error<
"call to implicitly-deleted %select{default constructor|copy constructor|"
"move constructor|copy assignment operator|move assignment operator|"
"destructor|function}0 of %1">;
def err_ovl_ambiguous_oper_unary : Error<
"use of overloaded operator '%0' is ambiguous (operand type %1)">;
def err_ovl_ambiguous_oper_binary : Error<
"use of overloaded operator '%0' is ambiguous (with operand types %1 and %2)">;
def ext_ovl_ambiguous_oper_binary_reversed : ExtWarn<
"ISO C++20 considers use of overloaded operator '%0' (with operand types %1 "
"and %2) to be ambiguous despite there being a unique best viable function"
"%select{ with non-reversed arguments|}3">,
InGroup<DiagGroup<"ambiguous-reversed-operator">>, SFINAEFailure;
def note_ovl_ambiguous_oper_binary_reversed_self : Note<
"ambiguity is between a regular call to this operator and a call with the "
"argument order reversed">;
def note_ovl_ambiguous_oper_binary_selected_candidate : Note<
"candidate function with non-reversed arguments">;
def note_ovl_ambiguous_oper_binary_reversed_candidate : Note<
"ambiguous candidate function with reversed arguments">;
def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">;
def note_assign_lhs_incomplete : Note<"type %0 is incomplete">;
def err_ovl_deleted_oper : Error<
"overload resolution selected deleted operator '%0'">;
def err_ovl_deleted_special_oper : Error<
"object of type %0 cannot be %select{constructed|copied|moved|assigned|"
"assigned|destroyed}1 because its %sub{select_special_member_kind}1 is "
"implicitly deleted">;
def err_ovl_deleted_comparison : Error<
"object of type %0 cannot be compared because its %1 is implicitly deleted">;
def err_ovl_rewrite_equalequal_not_bool : Error<
"return type %0 of selected 'operator==' function for rewritten "
"'%1' comparison is not 'bool'">;
def ext_ovl_rewrite_equalequal_not_bool : ExtWarn<
"ISO C++20 requires return type of selected 'operator==' function for "
"rewritten '%1' comparison to be 'bool', not %0">,
InGroup<DiagGroup<"rewrite-not-bool">>, SFINAEFailure;
def err_ovl_no_viable_subscript :
Error<"no viable overloaded operator[] for type %0">;
def err_ovl_no_oper :
Error<"type %0 does not provide a %select{subscript|call}1 operator">;
def err_ovl_unresolvable : Error<
"reference to %select{overloaded|multiversioned}1 function could not be "
"resolved; did you mean to call it%select{| with no arguments}0?">;
def err_bound_member_function : Error<
"reference to non-static member function must be called"
"%select{|; did you mean to call it with no arguments?}0">;
def note_possible_target_of_call : Note<"possible target for call">;
def err_no_viable_destructor : Error<
"no viable destructor found for class %0">;
def err_ambiguous_destructor : Error<
"destructor of class %0 is ambiguous">;
def err_ovl_no_viable_object_call : Error<
"no matching function for call to object of type %0">;
def err_ovl_ambiguous_object_call : Error<
"call to object of type %0 is ambiguous">;
def err_ovl_ambiguous_subscript_call : Error<
"call to subscript operator of type %0 is ambiguous">;
def err_ovl_deleted_object_call : Error<
"call to deleted function call operator in type %0">;
def note_ovl_surrogate_cand : Note<"conversion candidate of type %0">;
def err_member_call_without_object : Error<
"call to non-static member function without an object argument">;
// C++ Address of Overloaded Function
def err_addr_ovl_no_viable : Error<
"address of overloaded function %0 does not match required type %1">;
def err_addr_ovl_ambiguous : Error<
"address of overloaded function %0 is ambiguous">;
def err_addr_ovl_not_func_ptrref : Error<
"address of overloaded function %0 cannot be converted to type %1">;
def err_addr_ovl_no_qualifier : Error<
"cannot form member pointer of type %0 without '&' and class name">;
} // let Deferrable
// C++11 Literal Operators
def err_ovl_no_viable_literal_operator : Error<
"no matching literal operator for call to %0"
"%select{| with argument of type %2| with arguments of types %2 and %3}1"
"%select{| or 'const char *'}4"
"%select{|, and no matching literal operator template}5">;
// C++ Template Declarations
def err_template_param_shadow : Error<
"declaration of %0 shadows template parameter">;
def ext_template_param_shadow : ExtWarn<
err_template_param_shadow.Text>, InGroup<MicrosoftTemplateShadow>;
def note_template_param_here : Note<"template parameter is declared here">;
def warn_template_export_unsupported : Warning<
"exported templates are unsupported">;
def err_template_outside_namespace_or_class_scope : Error<
"templates can only be declared in namespace or class scope">;
def err_template_inside_local_class : Error<
"templates cannot be declared inside of a local class">;
def err_template_linkage : Error<"templates must have C++ linkage">;
def err_template_typedef : Error<"a typedef cannot be a template">;
def err_template_unnamed_class : Error<
"cannot declare a class template with no name">;
def err_template_param_list_different_arity : Error<
"%select{too few|too many}0 template parameters in template "
"%select{|template parameter }1redeclaration">;
def note_template_param_list_different_arity : Note<
"%select{too few|too many}0 template parameters in template template "
"argument">;
def note_template_prev_declaration : Note<
"previous template %select{declaration|template parameter}0 is here">;
def err_template_param_different_kind : Error<
"template parameter has a different kind in template "
"%select{|template parameter }0redeclaration">;
def note_template_param_different_kind : Note<
"template parameter has a different kind in template argument">;
def err_invalid_decl_specifier_in_nontype_parm : Error<
"invalid declaration specifier in template non-type parameter">;
def err_template_nontype_parm_different_type : Error<
"template non-type parameter has a different type %0 in template "
"%select{|template parameter }1redeclaration">;
def note_template_nontype_parm_different_type : Note<
"template non-type parameter has a different type %0 in template argument">;
def note_template_nontype_parm_prev_declaration : Note<
"previous non-type template parameter with type %0 is here">;
def err_template_nontype_parm_bad_type : Error<
"a non-type template parameter cannot have type %0">;
def err_template_nontype_parm_bad_structural_type : Error<
"a non-type template parameter cannot have type %0 before C++20">;
def err_template_nontype_parm_incomplete : Error<
"non-type template parameter has incomplete type %0">;
def err_template_nontype_parm_not_literal : Error<
"non-type template parameter has non-literal type %0">;
def err_template_nontype_parm_rvalue_ref : Error<
"non-type template parameter has rvalue reference type %0">;
def err_template_nontype_parm_not_structural : Error<
"type %0 of non-type template parameter is not a structural type">;
def note_not_structural_non_public : Note<
"%0 is not a structural type because it has a "
"%select{non-static data member|base class}1 that is not public">;
def note_not_structural_mutable_field : Note<
"%0 is not a structural type because it has a mutable "
"non-static data member">;
def note_not_structural_rvalue_ref_field : Note<
"%0 is not a structural type because it has a non-static data member "
"of rvalue reference type">;
def note_not_structural_subobject : Note<
"%0 is not a structural type because it has a "
"%select{non-static data member|base class}1 of non-structural type %2">;
def warn_cxx17_compat_template_nontype_parm_type : Warning<
"non-type template parameter of type %0 is incompatible with "
"C++ standards before C++20">,
DefaultIgnore, InGroup<CXXPre20Compat>;
def warn_cxx14_compat_template_nontype_parm_auto_type : Warning<
"non-type template parameters declared with %0 are incompatible with C++ "
"standards before C++17">,
DefaultIgnore, InGroup<CXXPre17Compat>;
def err_template_param_default_arg_redefinition : Error<
"template parameter redefines default argument">;
def err_template_param_default_arg_inconsistent_redefinition : Error<
"template parameter default argument is inconsistent with previous definition">;
def note_template_param_prev_default_arg : Note<
"previous default template argument defined here">;
def note_template_param_prev_default_arg_in_other_module : Note<
"previous default template argument defined in module %0">;
def err_template_param_default_arg_missing : Error<
"template parameter missing a default argument">;
def ext_template_parameter_default_in_function_template : ExtWarn<
"default template arguments for a function template are a C++11 extension">,
InGroup<CXX11>;
def warn_cxx98_compat_template_parameter_default_in_function_template : Warning<
"default template arguments for a function template are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_template_parameter_default_template_member : Error<
"cannot add a default template argument to the definition of a member of a "
"class template">;
def err_template_parameter_default_friend_template : Error<
"default template argument not permitted on a friend template">;
def err_template_template_parm_no_parms : Error<
"template template parameter must have its own template parameters">;
def ext_variable_template : ExtWarn<"variable templates are a C++14 extension">,
InGroup<CXX14>;
def warn_cxx11_compat_variable_template : Warning<
"variable templates are incompatible with C++ standards before C++14">,
InGroup<CXXPre14Compat>, DefaultIgnore;
def err_template_variable_noparams : Error<
"extraneous 'template<>' in declaration of variable %0">;
def err_template_member : Error<"member %0 declared as a template">;
def err_member_with_template_arguments : Error<"member %0 cannot have template arguments">;
def err_template_member_noparams : Error<
"extraneous 'template<>' in declaration of member %0">;
def err_template_tag_noparams : Error<
"extraneous 'template<>' in declaration of %0 %1">;
def warn_cxx17_compat_adl_only_template_id : Warning<
"use of function template name with no prior function template "
"declaration in function call with explicit template arguments "
"is incompatible with C++ standards before C++20">,
InGroup<CXXPre20Compat>, DefaultIgnore;
def ext_adl_only_template_id : ExtWarn<
"use of function template name with no prior declaration in function call "
"with explicit template arguments is a C++20 extension">, InGroup<CXX20>;
def warn_unqualified_call_to_std_cast_function : Warning<
"unqualified call to '%0'">, InGroup<DiagGroup<"unqualified-std-cast-call">>;
// C++ Template Argument Lists
def err_template_missing_args : Error<
"use of "
"%select{class template|function template|variable template|alias template|"
"template template parameter|concept|template}0 %1 requires template "
"arguments">;
def err_template_arg_list_different_arity : Error<
"%select{too few|too many}0 template arguments for "
"%select{class template|function template|variable template|alias template|"
"template template parameter|concept|template}1 %2">;
def note_template_decl_here : Note<"template is declared here">;
def err_template_arg_must_be_type : Error<
"template argument for template type parameter must be a type">;
def err_template_arg_must_be_type_suggest : Error<
"template argument for template type parameter must be a type; "
"did you forget 'typename'?">;
def ext_ms_template_type_arg_missing_typename : ExtWarn<
"template argument for template type parameter must be a type; "
"omitted 'typename' is a Microsoft extension">,
InGroup<MicrosoftTemplate>;
def err_template_arg_must_be_expr : Error<
"template argument for non-type template parameter must be an expression">;
def err_template_arg_nontype_ambig : Error<
"template argument for non-type template parameter is treated as function type %0">;
def err_template_arg_must_be_template : Error<
"template argument for template template parameter must be a class template%select{| or type alias template}0">;
def ext_template_arg_local_type : ExtWarn<
"template argument uses local type %0">, InGroup<LocalTypeTemplateArgs>;
def ext_template_arg_unnamed_type : ExtWarn<
"template argument uses unnamed type">, InGroup<UnnamedTypeTemplateArgs>;
def warn_cxx98_compat_template_arg_local_type : Warning<
"local type %0 as template argument is incompatible with C++98">,
InGroup<CXX98CompatLocalTypeTemplateArgs>, DefaultIgnore;
def warn_cxx98_compat_template_arg_unnamed_type : Warning<
"unnamed type as template argument is incompatible with C++98">,
InGroup<CXX98CompatUnnamedTypeTemplateArgs>, DefaultIgnore;
def note_template_unnamed_type_here : Note<
"unnamed type used in template argument was declared here">;
def err_template_arg_overload_type : Error<
"template argument is the type of an unresolved overloaded function">;
def err_template_arg_not_valid_template : Error<
"template argument does not refer to a class or alias template, or template "
"template parameter">;
def note_template_arg_refers_here_func : Note<
"template argument refers to function template %0, here">;
def err_template_arg_template_params_mismatch : Error<
"template template argument has different template parameters than its "
"corresponding template template parameter">;
def err_template_arg_not_integral_or_enumeral : Error<
"non-type template argument of type %0 must have an integral or enumeration"
" type">;
def err_template_arg_not_ice : Error<
"non-type template argument of type %0 is not an integral constant "
"expression">;
def err_template_arg_not_address_constant : Error<
"non-type template argument of type %0 is not a constant expression">;
def warn_cxx98_compat_template_arg_null : Warning<
"use of null pointer as non-type template argument is incompatible with "
"C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def err_template_arg_untyped_null_constant : Error<
"null non-type template argument must be cast to template parameter type %0">;
def err_template_arg_wrongtype_null_constant : Error<
"null non-type template argument of type %0 does not match template parameter "
"of type %1">;
def err_non_type_template_parm_type_deduction_failure : Error<
"non-type template parameter %0 with type %1 has incompatible initializer of type %2">;
def err_deduced_non_type_template_arg_type_mismatch : Error<
"deduced non-type template argument does not have the same type as the "
"corresponding template parameter%diff{ ($ vs $)|}0,1">;
def err_non_type_template_arg_subobject : Error<
"non-type template argument refers to subobject '%0'">;
def err_non_type_template_arg_addr_label_diff : Error<
"template argument / label address difference / what did you expect?">;
def err_non_type_template_arg_unsupported : Error<
"sorry, non-type template argument of type %0 is not yet supported">;
def err_template_arg_not_convertible : Error<
"non-type template argument of type %0 cannot be converted to a value "
"of type %1">;
def warn_template_arg_negative : Warning<
"non-type template argument with value '%0' converted to '%1' for unsigned "
"template parameter of type %2">, InGroup<Conversion>, DefaultIgnore;
def warn_template_arg_too_large : Warning<
"non-type template argument value '%0' truncated to '%1' for "
"template parameter of type %2">, InGroup<Conversion>, DefaultIgnore;
def err_template_arg_no_ref_bind : Error<
"non-type template parameter of reference type "
"%diff{$ cannot bind to template argument of type $"
"|cannot bind to template of incompatible argument type}0,1">;
def err_template_arg_ref_bind_ignores_quals : Error<
"reference binding of non-type template parameter "
"%diff{of type $ to template argument of type $|to template argument}0,1 "
"ignores qualifiers">;
def err_template_arg_not_decl_ref : Error<
"non-type template argument does not refer to any declaration">;
def err_template_arg_not_address_of : Error<
"non-type template argument for template parameter of pointer type %0 must "
"have its address taken">;
def err_template_arg_address_of_non_pointer : Error<
"address taken in non-type template argument for template parameter of "
"reference type %0">;
def err_template_arg_reference_var : Error<
"non-type template argument of reference type %0 is not an object">;
def err_template_arg_field : Error<
"non-type template argument refers to non-static data member %0">;
def err_template_arg_method : Error<
"non-type template argument refers to non-static member function %0">;
def err_template_arg_object_no_linkage : Error<
"non-type template argument refers to %select{function|object}0 %1 that "
"does not have linkage">;
def warn_cxx98_compat_template_arg_object_internal : Warning<
"non-type template argument referring to %select{function|object}0 %1 with "
"internal linkage is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def ext_template_arg_object_internal : ExtWarn<
"non-type template argument referring to %select{function|object}0 %1 with "
"internal linkage is a C++11 extension">, InGroup<CXX11>;
def err_template_arg_thread_local : Error<
"non-type template argument refers to thread-local object">;
def note_template_arg_internal_object : Note<
"non-type template argument refers to %select{function|object}0 here">;
def note_template_arg_refers_here : Note<
"non-type template argument refers here">;
def err_template_arg_not_object_or_func : Error<
"non-type template argument does not refer to an object or function">;
def err_template_arg_not_pointer_to_member_form : Error<
"non-type template argument is not a pointer to member constant">;
def err_template_arg_member_ptr_base_derived_not_supported : Error<
"sorry, non-type template argument of pointer-to-member type %1 that refers "
"to member %q0 of a different class is not supported yet">;
def ext_template_arg_extra_parens : ExtWarn<
"address non-type template argument cannot be surrounded by parentheses">;
def warn_cxx98_compat_template_arg_extra_parens : Warning<
"redundant parentheses surrounding address non-type template argument are "
"incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def err_pointer_to_member_type : Error<
"invalid use of pointer to member type after %select{.*|->*}0">;
def err_pointer_to_member_call_drops_quals : Error<
"call to pointer to member function of type %0 drops '%1' qualifier%s2">;
def err_pointer_to_member_oper_value_classify: Error<
"pointer-to-member function type %0 can only be called on an "
"%select{rvalue|lvalue}1">;
def ext_pointer_to_const_ref_member_on_rvalue : Extension<
"invoking a pointer to a 'const &' member function on an rvalue is a C++20 extension">,
InGroup<CXX20>, SFINAEFailure;
def warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : Warning<
"invoking a pointer to a 'const &' member function on an rvalue is "
"incompatible with C++ standards before C++20">,
InGroup<CXXPre20CompatPedantic>, DefaultIgnore;
def ext_ms_deref_template_argument: ExtWarn<
"non-type template argument containing a dereference operation is a "
"Microsoft extension">, InGroup<MicrosoftTemplate>;
def ext_ms_delayed_template_argument: ExtWarn<
"using the undeclared type %0 as a default template argument is a "
"Microsoft extension">, InGroup<MicrosoftTemplate>;
def err_template_arg_deduced_incomplete_pack : Error<
"deduced incomplete pack %0 for template parameter %1">;
// C++ template specialization
def err_template_spec_unknown_kind : Error<
"can only provide an explicit specialization for a class template, function "
"template, variable template, or a member function, static data member, "
"%select{or member class|member class, or member enumeration}0 of a "
"class template">;
def note_specialized_entity : Note<
"explicitly specialized declaration is here">;
def err_template_spec_decl_function_scope : Error<
"explicit specialization of %0 in function scope">;
def err_template_spec_decl_friend : Error<
"cannot declare an explicit specialization in a friend">;
def err_template_spec_redecl_out_of_scope : Error<
"%select{class template|class template partial|variable template|"
"variable template partial|function template|member "
"function|static data member|member class|member enumeration}0 "
"specialization of %1 not in %select{a namespace enclosing %2|"
"class %2 or an enclosing namespace}3">;
def ext_ms_template_spec_redecl_out_of_scope: ExtWarn<
"%select{class template|class template partial|variable template|"
"variable template partial|function template|member "
"function|static data member|member class|member enumeration}0 "
"specialization of %1 not in %select{a namespace enclosing %2|"
"class %2 or an enclosing namespace}3 "
"is a Microsoft extension">, InGroup<MicrosoftTemplate>;
def err_template_spec_redecl_global_scope : Error<
"%select{class template|class template partial|variable template|"
"variable template partial|function template|member "
"function|static data member|member class|member enumeration}0 "
"specialization of %1 must occur at global scope">;
def err_spec_member_not_instantiated : Error<
"specialization of member %q0 does not specialize an instantiated member">;
def note_specialized_decl : Note<"attempt to specialize declaration here">;
def err_specialization_after_instantiation : Error<
"explicit specialization of %0 after instantiation">;
def note_instantiation_required_here : Note<
"%select{implicit|explicit}0 instantiation first required here">;
def err_template_spec_friend : Error<
"template specialization declaration cannot be a friend">;
def err_template_spec_default_arg : Error<
"default argument not permitted on an explicit "
"%select{instantiation|specialization}0 of function %1">;
def err_not_class_template_specialization : Error<
"cannot specialize a %select{dependent template|template template "
"parameter}0">;
def ext_explicit_specialization_storage_class : ExtWarn<
"explicit specialization cannot have a storage class">;
def err_explicit_specialization_inconsistent_storage_class : Error<
"explicit specialization has extraneous, inconsistent storage class "
"'%select{none|extern|static|__private_extern__|auto|register}0'">;
def err_dependent_function_template_spec_no_match : Error<
"no candidate function template was found for dependent"
" friend function template specialization">;
def note_dependent_function_template_spec_discard_reason : Note<
"candidate ignored: %select{not a function template"
"|not a member of the enclosing namespace;"
" did you mean to explicitly qualify the specialization?}0">;
// C++ class template specializations and out-of-line definitions
def err_template_spec_needs_header : Error<
"template specialization requires 'template<>'">;
def err_template_spec_needs_template_parameters : Error<
"template specialization or definition requires a template parameter list "
"corresponding to the nested type %0">;
def err_template_param_list_matches_nontemplate : Error<
"template parameter list matching the non-templated nested type %0 should "
"be empty ('template<>')">;
def err_alias_template_extra_headers : Error<
"extraneous template parameter list in alias template declaration">;
def err_template_spec_extra_headers : Error<
"extraneous template parameter list in template specialization or "
"out-of-line template definition">;
def warn_template_spec_extra_headers : Warning<
"extraneous template parameter list in template specialization">;
def note_explicit_template_spec_does_not_need_header : Note<
"'template<>' header not required for explicitly-specialized class %0 "
"declared here">;
def err_template_qualified_declarator_no_match : Error<
"nested name specifier '%0' for declaration does not refer into a class, "
"class template or class template partial specialization">;
def err_specialize_member_of_template : Error<
"cannot specialize %select{|(with 'template<>') }0a member of an "
"unspecialized template">;
// C++ Class Template Partial Specialization
def err_default_arg_in_partial_spec : Error<
"default template argument in a class template partial specialization">;
def err_dependent_non_type_arg_in_partial_spec : Error<
"type of specialized non-type template argument depends on a template "
"parameter of the partial specialization">;
def note_dependent_non_type_default_arg_in_partial_spec : Note<
"template parameter is used in default argument declared here">;
def err_dependent_typed_non_type_arg_in_partial_spec : Error<
"non-type template argument specializes a template parameter with "
"dependent type %0">;
def err_partial_spec_args_match_primary_template : Error<
"%select{class|variable}0 template partial specialization does not "
"specialize any template argument; to %select{declare|define}1 the "
"primary template, remove the template argument list">;
def ext_partial_spec_not_more_specialized_than_primary : ExtWarn<
"%select{class|variable}0 template partial specialization is not "
"more specialized than the primary template">, DefaultError,
InGroup<DiagGroup<"invalid-partial-specialization">>;
def note_partial_spec_not_more_specialized_than_primary : Note<"%0">;
def ext_partial_specs_not_deducible : ExtWarn<
"%select{class|variable}0 template partial specialization contains "
"%select{a template parameter|template parameters}1 that cannot be "
"deduced; this partial specialization will never be used">,
DefaultError, InGroup<DiagGroup<"unusable-partial-specialization">>;
def note_non_deducible_parameter : Note<
"non-deducible template parameter %0">;
def err_partial_spec_ordering_ambiguous : Error<
"ambiguous partial specializations of %0">;
def note_partial_spec_match : Note<"partial specialization matches %0">;
def err_partial_spec_redeclared : Error<
"class template partial specialization %0 cannot be redeclared">;
def note_prev_partial_spec_here : Note<
"previous declaration of class template partial specialization %0 is here">;
def err_partial_spec_fully_specialized : Error<
"partial specialization of %0 does not use any of its template parameters">;
// C++ Variable Template Partial Specialization
def err_var_partial_spec_redeclared : Error<
"variable template partial specialization %0 cannot be redefined">;
def note_var_prev_partial_spec_here : Note<
"previous declaration of variable template partial specialization is here">;
def err_var_spec_no_template : Error<
"no variable template matches%select{| partial}0 specialization">;
def err_var_spec_no_template_but_method : Error<
"no variable template matches specialization; "
"did you mean to use %0 as function template instead?">;
// C++ Function template specializations
def err_function_template_spec_no_match : Error<
"no function template matches function template specialization %0">;
def err_function_template_spec_ambiguous : Error<
"function template specialization %0 ambiguously refers to more than one "
"function template; explicitly specify%select{| additional}1 template "
"arguments to identify a particular function template">;
def note_function_template_spec_matched : Note<
"function template %q0 matches specialization %1">;
def err_function_template_partial_spec : Error<
"function template partial specialization is not allowed">;
// C++ Template Instantiation
def err_template_recursion_depth_exceeded : Error<
"recursive template instantiation exceeded maximum depth of %0">,
DefaultFatal, NoSFINAE;
def note_template_recursion_depth : Note<
"use -ftemplate-depth=N to increase recursive template instantiation depth">;
def err_template_instantiate_within_definition : Error<
"%select{implicit|explicit}0 instantiation of template %1 within its"
" own definition">;
def err_template_instantiate_undefined : Error<
"%select{implicit|explicit}0 instantiation of undefined template %1">;
def err_implicit_instantiate_member_undefined : Error<
"implicit instantiation of undefined member %0">;
def note_template_class_instantiation_was_here : Note<
"class template %0 was instantiated here">;
def note_template_class_explicit_specialization_was_here : Note<
"class template %0 was explicitly specialized here">;
def note_template_class_instantiation_here : Note<
"in instantiation of template class %q0 requested here">;
def note_template_member_class_here : Note<
"in instantiation of member class %q0 requested here">;
def note_template_member_function_here : Note<
"in instantiation of member function %q0 requested here">;
def note_function_template_spec_here : Note<
"in instantiation of function template specialization %q0 requested here">;
def note_template_static_data_member_def_here : Note<
"in instantiation of static data member %q0 requested here">;
def note_template_variable_def_here : Note<
"in instantiation of variable template specialization %q0 requested here">;
def note_template_enum_def_here : Note<
"in instantiation of enumeration %q0 requested here">;
def note_template_nsdmi_here : Note<
"in instantiation of default member initializer %q0 requested here">;
def note_template_type_alias_instantiation_here : Note<
"in instantiation of template type alias %0 requested here">;
def note_template_exception_spec_instantiation_here : Note<
"in instantiation of exception specification for %0 requested here">;
def note_template_requirement_instantiation_here : Note<
"in instantiation of requirement here">;
def warn_var_template_missing : Warning<"instantiation of variable %q0 "
"required here, but no definition is available">,
InGroup<UndefinedVarTemplate>;
def warn_func_template_missing : Warning<"instantiation of function %q0 "
"required here, but no definition is available">,
InGroup<UndefinedFuncTemplate>, DefaultIgnore;
def note_forward_template_decl : Note<
"forward declaration of template entity is here">;
def note_inst_declaration_hint : Note<"add an explicit instantiation "
"declaration to suppress this warning if %q0 is explicitly instantiated in "
"another translation unit">;
def note_evaluating_exception_spec_here : Note<
"in evaluation of exception specification for %q0 needed here">;
def note_default_arg_instantiation_here : Note<
"in instantiation of default argument for '%0' required here">;
def note_default_function_arg_instantiation_here : Note<
"in instantiation of default function argument expression "
"for '%0' required here">;
def note_explicit_template_arg_substitution_here : Note<
"while substituting explicitly-specified template arguments into function "
"template %0 %1">;
def note_function_template_deduction_instantiation_here : Note<
"while substituting deduced template arguments into function template %0 "
"%1">;
def note_deduced_template_arg_substitution_here : Note<
"during template argument deduction for %select{class|variable}0 template "
"%select{partial specialization |}1%2 %3">;
def note_prior_template_arg_substitution : Note<
"while substituting prior template arguments into %select{non-type|template}0"
" template parameter%1 %2">;
def note_template_default_arg_checking : Note<
"while checking a default template argument used here">;
def note_concept_specialization_here : Note<
"while checking the satisfaction of concept '%0' requested here">;
def note_nested_requirement_here : Note<
"while checking the satisfaction of nested requirement requested here">;
def note_checking_constraints_for_template_id_here : Note<
"while checking constraint satisfaction for template '%0' required here">;
def note_checking_constraints_for_var_spec_id_here : Note<
"while checking constraint satisfaction for variable template "
"partial specialization '%0' required here">;
def note_checking_constraints_for_class_spec_id_here : Note<
"while checking constraint satisfaction for class template partial "
"specialization '%0' required here">;
def note_checking_constraints_for_function_here : Note<
"while checking constraint satisfaction for function '%0' required here">;
def note_constraint_substitution_here : Note<
"while substituting template arguments into constraint expression here">;
def note_constraint_normalization_here : Note<
"while calculating associated constraint of template '%0' here">;
def note_parameter_mapping_substitution_here : Note<
"while substituting into concept arguments here; substitution failures not "
"allowed in concept arguments">;
def note_instantiation_contexts_suppressed : Note<
"(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to "
"see all)">;
def err_field_instantiates_to_function : Error<
"data member instantiated with function type %0">;
def err_variable_instantiates_to_function : Error<
"%select{variable|static data member}0 instantiated with function type %1">;
def err_nested_name_spec_non_tag : Error<
"type %0 cannot be used prior to '::' because it has no members">;
def err_using_pack_expansion_empty : Error<
"%select{|member}0 using declaration %1 instantiates to an empty pack">;
// C++ Explicit Instantiation
def err_explicit_instantiation_duplicate : Error<
"duplicate explicit instantiation of %0">;
def ext_explicit_instantiation_duplicate : ExtWarn<
"duplicate explicit instantiation of %0 ignored as a Microsoft extension">,
InGroup<MicrosoftTemplate>;
def note_previous_explicit_instantiation : Note<
"previous explicit instantiation is here">;
def warn_explicit_instantiation_after_specialization : Warning<
"explicit instantiation of %0 that occurs after an explicit "
"specialization has no effect">,
InGroup<DiagGroup<"instantiation-after-specialization">>;
def note_previous_template_specialization : Note<
"previous template specialization is here">;
def err_explicit_instantiation_nontemplate_type : Error<
"explicit instantiation of non-templated type %0">;
def note_nontemplate_decl_here : Note<
"non-templated declaration is here">;
def err_explicit_instantiation_in_class : Error<
"explicit instantiation of %0 in class scope">;
def err_explicit_instantiation_out_of_scope : Error<
"explicit instantiation of %0 not in a namespace enclosing %1">;
def err_explicit_instantiation_must_be_global : Error<
"explicit instantiation of %0 must occur at global scope">;
def warn_explicit_instantiation_out_of_scope_0x : Warning<
"explicit instantiation of %0 not in a namespace enclosing %1">,
InGroup<CXX11Compat>, DefaultIgnore;
def warn_explicit_instantiation_must_be_global_0x : Warning<
"explicit instantiation of %0 must occur at global scope">,
InGroup<CXX11Compat>, DefaultIgnore;
def err_explicit_instantiation_requires_name : Error<
"explicit instantiation declaration requires a name">;
def err_explicit_instantiation_of_typedef : Error<
"explicit instantiation of typedef %0">;
def err_explicit_instantiation_storage_class : Error<
"explicit instantiation cannot have a storage class">;
def err_explicit_instantiation_internal_linkage : Error<
"explicit instantiation declaration of %0 with internal linkage">;
def err_explicit_instantiation_not_known : Error<
"explicit instantiation of %0 does not refer to a function template, "
"variable template, member function, member class, or static data member">;
def note_explicit_instantiation_here : Note<
"explicit instantiation refers here">;
def err_explicit_instantiation_data_member_not_instantiated : Error<
"explicit instantiation refers to static data member %q0 that is not an "
"instantiation">;
def err_explicit_instantiation_member_function_not_instantiated : Error<
"explicit instantiation refers to member function %q0 that is not an "
"instantiation">;
def err_explicit_instantiation_ambiguous : Error<
"partial ordering for explicit instantiation of %0 is ambiguous">;
def note_explicit_instantiation_candidate : Note<
"explicit instantiation candidate function %q0 template here %1">;
def err_explicit_instantiation_inline : Error<
"explicit instantiation cannot be 'inline'">;
def warn_explicit_instantiation_inline_0x : Warning<
"explicit instantiation cannot be 'inline'">, InGroup<CXX11Compat>,
DefaultIgnore;
def err_explicit_instantiation_constexpr : Error<
"explicit instantiation cannot be 'constexpr'">;
def ext_explicit_instantiation_without_qualified_id : Extension<
"qualifier in explicit instantiation of %q0 requires a template-id "
"(a typedef is not permitted)">;
def err_explicit_instantiation_without_template_id : Error<
"explicit instantiation of %q0 must specify a template argument list">;
def err_explicit_instantiation_unqualified_wrong_namespace : Error<
"explicit instantiation of %q0 must occur in namespace %1">;
def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning<
"explicit instantiation of %q0 must occur in namespace %1">,
InGroup<CXX11Compat>, DefaultIgnore;
def err_explicit_instantiation_undefined_member : Error<
"explicit instantiation of undefined %select{member class|member function|"
"static data member}0 %1 of class template %2">;
def err_explicit_instantiation_undefined_func_template : Error<
"explicit instantiation of undefined function template %0">;
def err_explicit_instantiation_undefined_var_template : Error<
"explicit instantiation of undefined variable template %q0">;
def err_explicit_instantiation_declaration_after_definition : Error<
"explicit instantiation declaration (with 'extern') follows explicit "
"instantiation definition (without 'extern')">;
def note_explicit_instantiation_definition_here : Note<
"explicit instantiation definition is here">;
def err_invalid_var_template_spec_type : Error<"type %2 "
"of %select{explicit instantiation|explicit specialization|"
"partial specialization|redeclaration}0 of %1 does not match"
" expected type %3">;
def err_mismatched_exception_spec_explicit_instantiation : Error<
"exception specification in explicit instantiation does not match "
"instantiated one">;
def ext_mismatched_exception_spec_explicit_instantiation : ExtWarn<
err_mismatched_exception_spec_explicit_instantiation.Text>,
InGroup<MicrosoftExceptionSpec>;
def err_explicit_instantiation_dependent : Error<
"explicit instantiation has dependent template arguments">;
// C++ typename-specifiers
def err_typename_nested_not_found : Error<"no type named %0 in %1">;
def err_typename_nested_not_found_enable_if : Error<
"no type named 'type' in %0; 'enable_if' cannot be used to disable "
"this declaration">;
def err_typename_nested_not_found_requirement : Error<
"failed requirement '%0'; 'enable_if' cannot be used to disable this "
"declaration">;
def err_typename_nested_not_type : Error<
"typename specifier refers to non-type member %0 in %1">;
def err_typename_not_type : Error<
"typename specifier refers to non-type %0">;
def note_typename_member_refers_here : Note<
"referenced member %0 is declared here">;
def note_typename_refers_here : Note<
"referenced %0 is declared here">;
def err_typename_missing : Error<
"missing 'typename' prior to dependent type name '%0%1'">;
def err_typename_missing_template : Error<
"missing 'typename' prior to dependent type template name '%0%1'">;
def ext_typename_missing : ExtWarn<
"missing 'typename' prior to dependent type name '%0%1'">,
InGroup<DiagGroup<"typename-missing">>;
def ext_typename_outside_of_template : ExtWarn<
"'typename' occurs outside of a template">, InGroup<CXX11>;
def warn_cxx98_compat_typename_outside_of_template : Warning<
"use of 'typename' outside of a template is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_typename_refers_to_using_value_decl : Error<
"typename specifier refers to a dependent using declaration for a value "
"%0 in %1">;
def note_using_value_decl_missing_typename : Note<
"add 'typename' to treat this using declaration as a type">;
def err_template_kw_refers_to_non_template : Error<
"%0%select{| following the 'template' keyword}1 "
"does not refer to a template">;
def note_template_kw_refers_to_non_template : Note<
"declared as a non-template here">;
def err_template_kw_refers_to_dependent_non_template : Error<
"%0%select{| following the 'template' keyword}1 "
"cannot refer to a dependent template">;
def err_template_kw_refers_to_class_template : Error<
"'%0%1' instantiated to a class template, not a function template">;
def note_referenced_class_template : Note<
"class template declared here">;
def err_template_kw_missing : Error<
"missing 'template' keyword prior to dependent template name '%0%1'">;
def ext_template_outside_of_template : ExtWarn<
"'template' keyword outside of a template">, InGroup<CXX11>;
def warn_cxx98_compat_template_outside_of_template : Warning<
"use of 'template' keyword outside of a template is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_non_type_template_in_nested_name_specifier : Error<
"qualified name refers into a specialization of %select{function|variable}0 "
"template %1">;
def err_template_id_not_a_type : Error<
"template name refers to non-type template %0">;
def note_template_declared_here : Note<
"%select{function template|class template|variable template"
"|type alias template|template template parameter}0 "
"%1 declared here">;
def err_template_expansion_into_fixed_list : Error<
"pack expansion used as argument for non-pack parameter of %select{alias "
"template|concept}0">;
def note_parameter_type : Note<
"parameter of type %0 is declared here">;
// C++11 Variadic Templates
def err_template_param_pack_default_arg : Error<
"template parameter pack cannot have a default argument">;
def err_template_param_pack_must_be_last_template_parameter : Error<
"template parameter pack must be the last template parameter">;
def err_template_parameter_pack_non_pack : Error<
"%select{template type|non-type template|template template}0 parameter"
"%select{| pack}1 conflicts with previous %select{template type|"
"non-type template|template template}0 parameter%select{ pack|}1">;
def note_template_parameter_pack_non_pack : Note<
"%select{template type|non-type template|template template}0 parameter"
"%select{| pack}1 does not match %select{template type|non-type template"
"|template template}0 parameter%select{ pack|}1 in template argument">;
def note_template_parameter_pack_here : Note<
"previous %select{template type|non-type template|template template}0 "
"parameter%select{| pack}1 declared here">;
def err_unexpanded_parameter_pack : Error<
"%select{expression|base type|declaration type|data member type|bit-field "
"size|static assertion|fixed underlying type|enumerator value|"
"using declaration|friend declaration|qualifier|initializer|default argument|"
"non-type template parameter type|exception type|partial specialization|"
"__if_exists name|__if_not_exists name|lambda|block|type constraint|"
"requirement|requires clause}0 "
"contains%plural{0: an|:}1 unexpanded parameter pack"
"%plural{0:|1: %2|2:s %2 and %3|:s %2, %3, ...}1">;
def err_pack_expansion_without_parameter_packs : Error<
"pack expansion does not contain any unexpanded parameter packs">;
def err_pack_expansion_length_conflict : Error<
"pack expansion contains parameter packs %0 and %1 that have different "
"lengths (%2 vs. %3)">;
def err_pack_expansion_length_conflict_multilevel : Error<
"pack expansion contains parameter pack %0 that has a different "
"length (%1 vs. %2) from outer parameter packs">;
def err_pack_expansion_length_conflict_partial : Error<
"pack expansion contains parameter pack %0 that has a different "
"length (at least %1 vs. %2) from outer parameter packs">;
def err_pack_expansion_member_init : Error<
"pack expansion for initialization of member %0">;
def err_function_parameter_pack_without_parameter_packs : Error<
"type %0 of function parameter pack does not contain any unexpanded "
"parameter packs">;
def err_ellipsis_in_declarator_not_parameter : Error<
"only function and template parameters can be parameter packs">;
def err_sizeof_pack_no_pack_name : Error<
"%0 does not refer to the name of a parameter pack">;
def err_fold_expression_packs_both_sides : Error<
"binary fold expression has unexpanded parameter packs in both operands">;
def err_fold_expression_empty : Error<
"unary fold expression has empty expansion for operator '%0' "
"with no fallback value">;
def err_fold_expression_bad_operand : Error<
"expression not permitted as operand of fold expression">;
def err_fold_expression_limit_exceeded: Error<
"instantiating fold expression with %0 arguments exceeded expression nesting "
"limit of %1">, DefaultFatal, NoSFINAE;
def err_unexpected_typedef : Error<
"unexpected type name %0: expected expression">;
def err_unexpected_namespace : Error<
"unexpected namespace name %0: expected expression">;
def err_undeclared_var_use : Error<"use of undeclared identifier %0">;
def ext_undeclared_unqual_id_with_dependent_base : ExtWarn<
"use of undeclared identifier %0; "
"unqualified lookup into dependent bases of class template %1 is a Microsoft extension">,
InGroup<MicrosoftTemplate>;
def err_found_in_dependent_base : Error<
"explicit qualification required to use member %0 from dependent base class">;
def ext_found_in_dependent_base : ExtWarn<"use of member %0 "
"found via unqualified lookup into dependent bases of class templates is a "
"Microsoft extension">, InGroup<MicrosoftTemplate>;
def err_found_later_in_class : Error<"member %0 used before its declaration">;
def ext_found_later_in_class : ExtWarn<
"use of member %0 before its declaration is a Microsoft extension">,
InGroup<MicrosoftTemplate>;
def ext_unqualified_base_class : ExtWarn<
"unqualified base initializer of class templates is a Microsoft extension">,
InGroup<MicrosoftTemplate>;
def note_dependent_member_use : Note<
"must qualify identifier to find this declaration in dependent base class">;
def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neither "
"visible in the template definition nor found by argument-dependent lookup">;
def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to the "
"call site%select{| or in %2| or in an associated namespace of one of its arguments}1">;
def err_undeclared_use : Error<"use of undeclared %0">;
def warn_deprecated : Warning<"%0 is deprecated">,
InGroup<DeprecatedDeclarations>;
def note_from_diagnose_if : Note<"from 'diagnose_if' attribute on %0:">;
def warn_property_method_deprecated :
Warning<"property access is using %0 method which is deprecated">,
InGroup<DeprecatedDeclarations>;
def warn_deprecated_message : Warning<"%0 is deprecated: %1">,
InGroup<DeprecatedDeclarations>;
def warn_deprecated_anonymous_namespace : Warning<
"'deprecated' attribute on anonymous namespace ignored">,
InGroup<IgnoredAttributes>;
def warn_deprecated_fwdclass_message : Warning<
"%0 may be deprecated because the receiver type is unknown">,
InGroup<DeprecatedDeclarations>;
def warn_deprecated_def : Warning<
"implementing deprecated %select{method|class|category}0">,
InGroup<DeprecatedImplementations>, DefaultIgnore;
def warn_unavailable_def : Warning<
"implementing unavailable method">,
InGroup<DeprecatedImplementations>, DefaultIgnore;
def warn_deprecated_builtin : Warning<
"builtin %0 is deprecated; use %1 instead">,
InGroup<DeprecatedBuiltins>;
def err_unavailable : Error<"%0 is unavailable">;
def err_property_method_unavailable :
Error<"property access is using %0 method which is unavailable">;
def err_unavailable_message : Error<"%0 is unavailable: %1">;
def warn_unavailable_fwdclass_message : Warning<
"%0 may be unavailable because the receiver type is unknown">,
InGroup<UnavailableDeclarations>;
def note_availability_specified_here : Note<
"%0 has been explicitly marked "
"%select{unavailable|deleted|deprecated}1 here">;
def note_partial_availability_specified_here : Note<
"%0 has been marked as being introduced in %1 %2 here, "
"but the deployment target is %1 %3">;
def note_implicitly_deleted : Note<
"explicitly defaulted function was implicitly deleted here">;
def warn_not_enough_argument : Warning<
"not enough variable arguments in %0 declaration to fit a sentinel">,
InGroup<Sentinel>;
def warn_missing_sentinel : Warning <
"missing sentinel in %select{function call|method dispatch|block call}0">,
InGroup<Sentinel>;
def note_sentinel_here : Note<
"%select{function|method|block}0 has been explicitly marked sentinel here">;
def warn_strict_uses_without_prototype : Warning<
"passing arguments to %select{a function|%1}0 without a prototype is "
"deprecated in all versions of C and is not supported in C2x">,
InGroup<DeprecatedNonPrototype>;
def warn_missing_prototype : Warning<
"no previous prototype for function %0">,
InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore;
def note_declaration_not_a_prototype : Note<
"this declaration is not a prototype; add %select{'void'|parameter declarations}0 "
"to make it %select{a prototype for a zero-parameter function|one}0">;
// This is not actually an extension, but we only want it to be enabled in
// -pedantic mode and this is the most direct way of accomplishing that.
def warn_strict_prototypes : Extension<
"a %select{function|block}0 declaration without a prototype is deprecated "
"%select{in all versions of C|}0">, InGroup<StrictPrototypes>;
def warn_non_prototype_changes_behavior : Warning<
"a function %select{declaration|definition}0 without a prototype is "
"deprecated in all versions of C %select{and is not supported in C2x|and is "
"treated as a zero-parameter prototype in C2x, conflicting with a "
"%select{previous|subsequent}2 %select{declaration|definition}3}1">,
InGroup<DeprecatedNonPrototype>;
def note_conflicting_prototype : Note<"conflicting prototype is here">;
def warn_missing_variable_declarations : Warning<
"no previous extern declaration for non-static variable %0">,
InGroup<DiagGroup<"missing-variable-declarations">>, DefaultIgnore;
def note_static_for_internal_linkage : Note<
"declare 'static' if the %select{variable|function}0 is not intended to be "
"used outside of this translation unit">;
def err_static_data_member_reinitialization :
Error<"static data member %0 already has an initializer">;
def err_redefinition : Error<"redefinition of %0">;
def err_alias_after_tentative :
Error<"alias definition of %0 after tentative definition">;
def err_alias_is_definition :
Error<"definition %0 cannot also be an %select{alias|ifunc}1">;
def err_definition_of_implicitly_declared_member : Error<
"definition of implicitly declared %select{default constructor|copy "
"constructor|move constructor|copy assignment operator|move assignment "
"operator|destructor|function}1">;
def err_definition_of_explicitly_defaulted_member : Error<
"definition of explicitly defaulted %select{default constructor|copy "
"constructor|move constructor|copy assignment operator|move assignment "
"operator|destructor|function}0">;
def err_redefinition_extern_inline : Error<
"redefinition of a 'extern inline' function %0 is not supported in "
"%select{C99 mode|C++}1">;
def warn_attr_abi_tag_namespace : Warning<
"'abi_tag' attribute on %select{non-inline|anonymous}0 namespace ignored">,
InGroup<IgnoredAttributes>;
def err_abi_tag_on_redeclaration : Error<
"cannot add 'abi_tag' attribute in a redeclaration">;
def err_new_abi_tag_on_redeclaration : Error<
"'abi_tag' %0 missing in original declaration">;
def note_use_ifdef_guards : Note<
"unguarded header; consider using #ifdef guards or #pragma once">;
def note_deleted_dtor_no_operator_delete : Note<
"virtual destructor requires an unambiguous, accessible 'operator delete'">;
def note_deleted_special_member_class_subobject : Note<
"%select{default constructor of|copy constructor of|move constructor of|"
"copy assignment operator of|move assignment operator of|destructor of|"
"constructor inherited by}0 "
"%1 is implicitly deleted because "
"%select{base class %3|%select{||||variant }4field %3}2 "
"%select{has "
"%select{no|a deleted|multiple|an inaccessible|a non-trivial}4 "
"%select{%select{default constructor|copy constructor|move constructor|copy "
"assignment operator|move assignment operator|destructor|"
"%select{default|corresponding|default|default|default}4 constructor}0|"
"destructor}5"
"%select{||s||}4"
"|is an ObjC pointer}6">;
def note_deleted_default_ctor_uninit_field : Note<
"%select{default constructor of|constructor inherited by}0 "
"%1 is implicitly deleted because field %2 of "
"%select{reference|const-qualified}4 type %3 would not be initialized">;
def note_deleted_default_ctor_all_const : Note<
"%select{default constructor of|constructor inherited by}0 "
"%1 is implicitly deleted because all "
"%select{data members|data members of an anonymous union member}2"
" are const-qualified">;
def note_deleted_copy_ctor_rvalue_reference : Note<
"copy constructor of %0 is implicitly deleted because field %1 is of "
"rvalue reference type %2">;
def note_deleted_copy_user_declared_move : Note<
"copy %select{constructor|assignment operator}0 is implicitly deleted because"
" %1 has a user-declared move %select{constructor|assignment operator}2">;
def note_deleted_assign_field : Note<
"%select{copy|move}0 assignment operator of %1 is implicitly deleted "
"because field %2 is of %select{reference|const-qualified}4 type %3">;
// These should be errors.
def warn_undefined_internal : Warning<
"%select{function|variable}0 %q1 has internal linkage but is not defined">,
InGroup<DiagGroup<"undefined-internal">>;
def err_undefined_internal_type : Error<
"%select{function|variable}0 %q1 is used but not defined in this "
"translation unit, and cannot be defined in any other translation unit "
"because its type does not have linkage">;
def ext_undefined_internal_type : Extension<
"ISO C++ requires a definition in this translation unit for "
"%select{function|variable}0 %q1 because its type does not have linkage">,
InGroup<DiagGroup<"undefined-internal-type">>;
def warn_undefined_inline : Warning<"inline function %q0 is not defined">,
InGroup<DiagGroup<"undefined-inline">>;
def err_undefined_inline_var : Error<"inline variable %q0 is not defined">;
def note_used_here : Note<"used here">;
def err_attribute_missing_on_first_decl : Error<
"%0 attribute does not appear on the first declaration">;
def warn_internal_linkage_local_storage : Warning<
"'internal_linkage' attribute on a non-static local variable is ignored">,
InGroup<IgnoredAttributes>;
def ext_internal_in_extern_inline : ExtWarn<
"static %select{function|variable}0 %1 is used in an inline function with "
"external linkage">, InGroup<StaticInInline>;
def ext_internal_in_extern_inline_quiet : Extension<
"static %select{function|variable}0 %1 is used in an inline function with "
"external linkage">, InGroup<StaticInInline>;
def warn_static_local_in_extern_inline : Warning<
"non-constant static local variable in inline function may be different "
"in different files">, InGroup<StaticLocalInInline>;
def note_convert_inline_to_static : Note<
"use 'static' to give inline function %0 internal linkage">;
def ext_redefinition_of_typedef : ExtWarn<
"redefinition of typedef %0 is a C11 feature">,
InGroup<DiagGroup<"typedef-redefinition"> >;
def err_redefinition_variably_modified_typedef : Error<
"redefinition of %select{typedef|type alias}0 for variably-modified type %1">;
def err_inline_decl_follows_def : Error<
"inline declaration of %0 follows non-inline definition">;
def err_inline_declaration_block_scope : Error<
"inline declaration of %0 not allowed in block scope">;
def err_static_non_static : Error<
"static declaration of %0 follows non-static declaration">;
def err_different_language_linkage : Error<
"declaration of %0 has a different language linkage">;
def ext_retained_language_linkage : Extension<
"friend function %0 retaining previous language linkage is an extension">,
InGroup<DiagGroup<"retained-language-linkage">>;
def err_extern_c_global_conflict : Error<
"declaration of %1 %select{with C language linkage|in global scope}0 "
"conflicts with declaration %select{in global scope|with C language linkage}0">;
def note_extern_c_global_conflict : Note<
"declared %select{in global scope|with C language linkage}0 here">;
def note_extern_c_begins_here : Note<
"extern \"C\" language linkage specification begins here">;
def warn_weak_import : Warning <
"an already-declared variable is made a weak_import declaration %0">;
def ext_static_non_static : Extension<
"redeclaring non-static %0 as static is a Microsoft extension">,
InGroup<MicrosoftRedeclareStatic>;
def err_non_static_static : Error<
"non-static declaration of %0 follows static declaration">;
def err_extern_non_extern : Error<
"extern declaration of %0 follows non-extern declaration">;
def err_non_extern_extern : Error<
"non-extern declaration of %0 follows extern declaration">;
def err_non_thread_thread : Error<
"non-thread-local declaration of %0 follows thread-local declaration">;
def err_thread_non_thread : Error<
"thread-local declaration of %0 follows non-thread-local declaration">;
def err_thread_thread_different_kind : Error<
"thread-local declaration of %0 with %select{static|dynamic}1 initialization "
"follows declaration with %select{dynamic|static}1 initialization">;
def err_mismatched_owning_module : Error<
"declaration of %0 in %select{the global module|module %2}1 follows "
"declaration in %select{the global module|module %4}3">;
def err_redefinition_different_type : Error<
"redefinition of %0 with a different type%diff{: $ vs $|}1,2">;
def err_redefinition_different_kind : Error<
"redefinition of %0 as different kind of symbol">;
def err_redefinition_different_namespace_alias : Error<
"redefinition of %0 as an alias for a different namespace">;
def note_previous_namespace_alias : Note<
"previously defined as an alias for %0">;
def warn_forward_class_redefinition : Warning<
"redefinition of forward class %0 of a typedef name of an object type is ignored">,
InGroup<DiagGroup<"objc-forward-class-redefinition">>;
def err_redefinition_different_typedef : Error<
"%select{typedef|type alias|type alias template}0 "
"redefinition with different types%diff{ ($ vs $)|}1,2">;
def err_redefinition_different_concept : Error<
"redefinition of concept %0 with different template parameters or requirements">;
def err_tag_reference_non_tag : Error<
"%select{non-struct type|non-class type|non-union type|non-enum "
"type|typedef|type alias|template|type alias template|template "
"template argument}1 %0 cannot be referenced with a "
"%select{struct|interface|union|class|enum}2 specifier">;
def err_tag_reference_conflict : Error<
"implicit declaration introduced by elaborated type conflicts with a "
"%select{non-struct type|non-class type|non-union type|non-enum "
"type|typedef|type alias|template|type alias template|template "
"template argument}0 of the same name">;
def err_dependent_tag_decl : Error<
"%select{declaration|definition}0 of "
"%select{struct|interface|union|class|enum}1 in a dependent scope">;
def err_tag_definition_of_typedef : Error<
"definition of type %0 conflicts with %select{typedef|type alias}1 of the same name">;
def err_conflicting_types : Error<"conflicting types for %0">;
def err_different_pass_object_size_params : Error<
"conflicting pass_object_size attributes on parameters">;
def err_late_asm_label_name : Error<
"cannot apply asm label to %select{variable|function}0 after its first use">;
def err_different_asm_label : Error<"conflicting asm label">;
def err_nested_redefinition : Error<"nested redefinition of %0">;
def err_use_with_wrong_tag : Error<
"use of %0 with tag type that does not match previous declaration">;
def warn_struct_class_tag_mismatch : Warning<
"%select{struct|interface|class}0%select{| template}1 %2 was previously "
"declared as a %select{struct|interface|class}3%select{| template}1; "
"this is valid, but may result in linker errors under the Microsoft C++ ABI">,
InGroup<MismatchedTags>, DefaultIgnore;
def warn_struct_class_previous_tag_mismatch : Warning<
"%2 defined as %select{a struct|an interface|a class}0%select{| template}1 "
"here but previously declared as "
"%select{a struct|an interface|a class}3%select{| template}1; "
"this is valid, but may result in linker errors under the Microsoft C++ ABI">,
InGroup<MismatchedTags>, DefaultIgnore;
def note_struct_class_suggestion : Note<
"did you mean %select{struct|interface|class}0 here?">;
def ext_forward_ref_enum : Extension<
"ISO C forbids forward references to 'enum' types">;
def err_forward_ref_enum : Error<
"ISO C++ forbids forward references to 'enum' types">;
def ext_ms_forward_ref_enum : ExtWarn<
"forward references to 'enum' types are a Microsoft extension">,
InGroup<MicrosoftEnumForwardReference>;
def ext_forward_ref_enum_def : Extension<
"redeclaration of already-defined enum %0 is a GNU extension">,
InGroup<GNURedeclaredEnum>;
def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
def err_duplicate_member : Error<"duplicate member %0">;
def err_misplaced_ivar : Error<
"instance variables may not be placed in %select{categories|class extension}0">;
def warn_ivars_in_interface : Warning<
"declaration of instance variables in the interface is deprecated">,
InGroup<DiagGroup<"objc-interface-ivars">>, DefaultIgnore;
def ext_enum_value_not_int : Extension<
"ISO C restricts enumerator values to range of 'int' (%0 is too "
"%select{small|large}1)">;
def ext_enum_too_large : ExtWarn<
"enumeration values exceed range of largest integer">, InGroup<EnumTooLarge>;
def ext_enumerator_increment_too_large : ExtWarn<
"incremented enumerator value %0 is not representable in the "
"largest integer type">, InGroup<EnumTooLarge>;
def warn_flag_enum_constant_out_of_range : Warning<
"enumeration value %0 is out of range of flags in enumeration type %1">,
InGroup<FlagEnum>;
def err_vm_decl_in_file_scope : Error<
"variably modified type declaration not allowed at file scope">;
def err_vm_decl_has_extern_linkage : Error<
"variably modified type declaration cannot have 'extern' linkage">;
def err_typecheck_field_variable_size : Error<
"fields must have a constant size: 'variable length array in structure' "
"extension will never be supported">;
def err_vm_func_decl : Error<
"function declaration cannot have variably modified type">;
def err_array_too_large : Error<
"array is too large (%0 elements)">;
def err_typecheck_negative_array_size : Error<"array size is negative">;
def warn_typecheck_function_qualifiers_ignored : Warning<
"'%0' qualifier on function type %1 has no effect">,
InGroup<IgnoredQualifiers>;
def warn_typecheck_function_qualifiers_unspecified : Warning<
"'%0' qualifier on function type %1 has unspecified behavior">;
def warn_typecheck_reference_qualifiers : Warning<
"'%0' qualifier on reference type %1 has no effect">,
InGroup<IgnoredReferenceQualifiers>;
def err_typecheck_invalid_restrict_not_pointer : Error<
"restrict requires a pointer or reference (%0 is invalid)">;
def err_typecheck_invalid_restrict_not_pointer_noarg : Error<
"restrict requires a pointer or reference">;
def err_typecheck_invalid_restrict_invalid_pointee : Error<
"pointer to function type %0 may not be 'restrict' qualified">;
def ext_typecheck_zero_array_size : Extension<
"zero size arrays are an extension">, InGroup<ZeroLengthArray>;
def err_typecheck_zero_array_size : Error<
"zero-length arrays are not permitted in %select{C++|SYCL device code}0">;
def err_array_size_non_int : Error<"size of array has non-integer type %0">;
def err_init_element_not_constant : Error<
"initializer element is not a compile-time constant">;
def ext_aggregate_init_not_constant : Extension<
"initializer for aggregate is not a compile-time constant">, InGroup<C99>;
def err_local_cant_init : Error<
"'__local' variable cannot have an initializer">;
def err_loader_uninitialized_cant_init
: Error<"variable with 'loader_uninitialized' attribute cannot have an "
"initializer">;
def err_loader_uninitialized_trivial_ctor
: Error<"variable with 'loader_uninitialized' attribute must have a "
"trivial default constructor">;
def err_loader_uninitialized_redeclaration
: Error<"redeclaration cannot add 'loader_uninitialized' attribute">;
def err_loader_uninitialized_extern_decl
: Error<"variable %0 cannot be declared both 'extern' and with the "
"'loader_uninitialized' attribute">;
def err_block_extern_cant_init : Error<
"'extern' variable cannot have an initializer">;
def warn_extern_init : Warning<"'extern' variable has an initializer">,
InGroup<DiagGroup<"extern-initializer">>;
def err_variable_object_no_init : Error<
"variable-sized object may not be initialized">;
def err_excess_initializers : Error<
"excess elements in %select{array|vector|scalar|union|struct}0 initializer">;
def ext_excess_initializers : ExtWarn<
"excess elements in %select{array|vector|scalar|union|struct}0 initializer">,
InGroup<ExcessInitializers>;
def err_excess_initializers_for_sizeless_type : Error<
"excess elements in initializer for indivisible sizeless type %0">;
def ext_excess_initializers_for_sizeless_type : ExtWarn<
"excess elements in initializer for indivisible sizeless type %0">,
InGroup<ExcessInitializers>;
def err_excess_initializers_in_char_array_initializer : Error<
"excess elements in char array initializer">;
def ext_excess_initializers_in_char_array_initializer : ExtWarn<
"excess elements in char array initializer">,
InGroup<ExcessInitializers>;
def err_initializer_string_for_char_array_too_long : Error<
"initializer-string for char array is too long">;
def ext_initializer_string_for_char_array_too_long : ExtWarn<
"initializer-string for char array is too long">,
InGroup<ExcessInitializers>;
def warn_missing_field_initializers : Warning<
"missing field %0 initializer">,
InGroup<MissingFieldInitializers>, DefaultIgnore;
def warn_braces_around_init : Warning<
"braces around %select{scalar |}0initializer">,
InGroup<DiagGroup<"braced-scalar-init">>;
def ext_many_braces_around_init : ExtWarn<
"too many braces around %select{scalar |}0initializer">,
InGroup<DiagGroup<"many-braces-around-scalar-init">>, SFINAEFailure;
def ext_complex_component_init : Extension<
"complex initialization specifying real and imaginary components "
"is an extension">, InGroup<DiagGroup<"complex-component-init">>;
def err_empty_scalar_initializer : Error<"scalar initializer cannot be empty">;
def err_empty_sizeless_initializer : Error<
"initializer for sizeless type %0 cannot be empty">;
def warn_cxx98_compat_empty_scalar_initializer : Warning<
"scalar initialized from empty initializer list is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def warn_cxx98_compat_empty_sizeless_initializer : Warning<
"initializing %0 from an empty initializer list is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def warn_cxx98_compat_reference_list_init : Warning<
"reference initialized from initializer list is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def warn_cxx98_compat_initializer_list_init : Warning<
"initialization of initializer_list object is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def warn_cxx98_compat_ctor_list_init : Warning<
"constructor call from initializer list is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_illegal_initializer : Error<
"illegal initializer (only variables can be initialized)">;
def err_illegal_initializer_type : Error<"illegal initializer type %0">;
def ext_init_list_type_narrowing : ExtWarn<
"type %0 cannot be narrowed to %1 in initializer list">,
InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
def ext_init_list_variable_narrowing : ExtWarn<
"non-constant-expression cannot be narrowed from type %0 to %1 in "
"initializer list">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
def ext_init_list_constant_narrowing : ExtWarn<
"constant expression evaluates to %0 which cannot be narrowed to type %1">,
InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
def warn_init_list_type_narrowing : Warning<
"type %0 cannot be narrowed to %1 in initializer list in C++11">,
InGroup<CXX11Narrowing>, DefaultIgnore;
def warn_init_list_variable_narrowing : Warning<
"non-constant-expression cannot be narrowed from type %0 to %1 in "
"initializer list in C++11">,
InGroup<CXX11Narrowing>, DefaultIgnore;
def warn_init_list_constant_narrowing : Warning<
"constant expression evaluates to %0 which cannot be narrowed to type %1 in "
"C++11">,
InGroup<CXX11Narrowing>, DefaultIgnore;
def note_init_list_narrowing_silence : Note<
"insert an explicit cast to silence this issue">;
def err_init_objc_class : Error<
"cannot initialize Objective-C class type %0">;
def err_implicit_empty_initializer : Error<
"initializer for aggregate with no elements requires explicit braces">;
def err_bitfield_has_negative_width : Error<
"bit-field %0 has negative width (%1)">;
def err_anon_bitfield_has_negative_width : Error<
"anonymous bit-field has negative width (%0)">;
def err_bitfield_has_zero_width : Error<"named bit-field %0 has zero width">;
def err_bitfield_width_exceeds_type_width : Error<
"width of%select{ anonymous|}0 bit-field%select{| %1}0 (%2 bits) exceeds the "
"%select{width|size}3 of its type (%4 bit%s4)">;
def err_incorrect_number_of_vector_initializers : Error<
"number of elements must be either one or match the size of the vector">;
// Used by C++ which allows bit-fields that are wider than the type.
def warn_bitfield_width_exceeds_type_width: Warning<
"width of bit-field %0 (%1 bits) exceeds the width of its type; value will "
"be truncated to %2 bit%s2">, InGroup<BitFieldWidth>;
def err_bitfield_too_wide : Error<
"%select{bit-field %1|anonymous bit-field}0 is too wide (%2 bits)">;
def warn_bitfield_too_small_for_enum : Warning<
"bit-field %0 is not wide enough to store all enumerators of %1">,
InGroup<BitFieldEnumConversion>, DefaultIgnore;
def note_widen_bitfield : Note<
"widen this field to %0 bits to store all values of %1">;
def warn_unsigned_bitfield_assigned_signed_enum : Warning<
"assigning value of signed enum type %1 to unsigned bit-field %0; "
"negative enumerators of enum %1 will be converted to positive values">,
InGroup<BitFieldEnumConversion>, DefaultIgnore;
def warn_signed_bitfield_enum_conversion : Warning<
"signed bit-field %0 needs an extra bit to represent the largest positive "
"enumerators of %1">,
InGroup<BitFieldEnumConversion>, DefaultIgnore;
def note_change_bitfield_sign : Note<
"consider making the bitfield type %select{unsigned|signed}0">;
def warn_missing_braces : Warning<
"suggest braces around initialization of subobject">,
InGroup<MissingBraces>, DefaultIgnore;
def err_redefinition_of_label : Error<"redefinition of label %0">;
def err_undeclared_label_use : Error<"use of undeclared label %0">;
def err_goto_ms_asm_label : Error<
"cannot jump from this goto statement to label %0 inside an inline assembly block">;
def note_goto_ms_asm_label : Note<
"inline assembly label %0 declared here">;
def warn_unused_label : Warning<"unused label %0">,
InGroup<UnusedLabel>, DefaultIgnore;
def err_continue_from_cond_var_init : Error<
"cannot jump from this continue statement to the loop increment; "
"jump bypasses initialization of loop condition variable">;
def err_goto_into_protected_scope : Error<
"cannot jump from this goto statement to its label">;
def ext_goto_into_protected_scope : ExtWarn<
"jump from this goto statement to its label is a Microsoft extension">,
InGroup<MicrosoftGoto>;
def warn_cxx98_compat_goto_into_protected_scope : Warning<
"jump from this goto statement to its label is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_switch_into_protected_scope : Error<
"cannot jump from switch statement to this case label">;
def warn_cxx98_compat_switch_into_protected_scope : Warning<
"jump from switch statement to this case label is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_indirect_goto_without_addrlabel : Error<
"indirect goto in function with no address-of-label expressions">;
def err_indirect_goto_in_protected_scope : Error<
"cannot jump from this %select{indirect|asm}0 goto statement to one of its possible targets">;
def warn_cxx98_compat_indirect_goto_in_protected_scope : Warning<
"jump from this %select{indirect|asm}0 goto statement to one of its possible targets "
"is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def note_indirect_goto_target : Note<
"possible target of %select{indirect|asm}0 goto statement">;
def note_protected_by_variable_init : Note<
"jump bypasses variable initialization">;
def note_protected_by_variable_nontriv_destructor : Note<
"jump bypasses variable with a non-trivial destructor">;
def note_protected_by_variable_non_pod : Note<
"jump bypasses initialization of non-POD variable">;
def note_protected_by_cleanup : Note<
"jump bypasses initialization of variable with __attribute__((cleanup))">;
def note_protected_by_vla_typedef : Note<
"jump bypasses initialization of VLA typedef">;
def note_protected_by_vla_type_alias : Note<
"jump bypasses initialization of VLA type alias">;
def note_protected_by_constexpr_if : Note<
"jump enters controlled statement of constexpr if">;
def note_protected_by_consteval_if : Note<
"jump enters controlled statement of consteval if">;
def note_protected_by_if_available : Note<
"jump enters controlled statement of if available">;
def note_protected_by_vla : Note<
"jump bypasses initialization of variable length array">;
def note_protected_by_objc_fast_enumeration : Note<
"jump enters Objective-C fast enumeration loop">;
def note_protected_by_objc_try : Note<
"jump bypasses initialization of @try block">;
def note_protected_by_objc_catch : Note<
"jump bypasses initialization of @catch block">;
def note_protected_by_objc_finally : Note<
"jump bypasses initialization of @finally block">;
def note_protected_by_objc_synchronized : Note<
"jump bypasses initialization of @synchronized block">;
def note_protected_by_objc_autoreleasepool : Note<
"jump bypasses auto release push of @autoreleasepool block">;
def note_protected_by_cxx_try : Note<
"jump bypasses initialization of try block">;
def note_protected_by_cxx_catch : Note<
"jump bypasses initialization of catch block">;
def note_protected_by_seh_try : Note<
"jump bypasses initialization of __try block">;
def note_protected_by_seh_except : Note<
"jump bypasses initialization of __except block">;
def note_protected_by_seh_finally : Note<
"jump bypasses initialization of __finally block">;
def note_protected_by___block : Note<
"jump bypasses setup of __block variable">;
def note_protected_by_objc_strong_init : Note<
"jump bypasses initialization of __strong variable">;
def note_protected_by_objc_weak_init : Note<
"jump bypasses initialization of __weak variable">;
def note_protected_by_non_trivial_c_struct_init : Note<
"jump bypasses initialization of variable of non-trivial C struct type">;
def note_enters_block_captures_cxx_obj : Note<
"jump enters lifetime of block which captures a destructible C++ object">;
def note_enters_block_captures_strong : Note<
"jump enters lifetime of block which strongly captures a variable">;
def note_enters_block_captures_weak : Note<
"jump enters lifetime of block which weakly captures a variable">;
def note_enters_block_captures_non_trivial_c_struct : Note<
"jump enters lifetime of block which captures a C struct that is non-trivial "
"to destroy">;
def note_enters_compound_literal_scope : Note<
"jump enters lifetime of a compound literal that is non-trivial to destruct">;
def note_exits_cleanup : Note<
"jump exits scope of variable with __attribute__((cleanup))">;
def note_exits_dtor : Note<
"jump exits scope of variable with non-trivial destructor">;
def note_exits_temporary_dtor : Note<
"jump exits scope of lifetime-extended temporary with non-trivial "
"destructor">;
def note_exits___block : Note<
"jump exits scope of __block variable">;
def note_exits_objc_try : Note<
"jump exits @try block">;
def note_exits_objc_catch : Note<
"jump exits @catch block">;
def note_exits_objc_finally : Note<
"jump exits @finally block">;
def note_exits_objc_synchronized : Note<
"jump exits @synchronized block">;
def note_exits_cxx_try : Note<
"jump exits try block">;
def note_exits_cxx_catch : Note<
"jump exits catch block">;
def note_exits_seh_try : Note<
"jump exits __try block">;
def note_exits_seh_except : Note<
"jump exits __except block">;
def note_exits_seh_finally : Note<
"jump exits __finally block">;
def note_exits_objc_autoreleasepool : Note<
"jump exits autoreleasepool block">;
def note_exits_objc_strong : Note<
"jump exits scope of __strong variable">;
def note_exits_objc_weak : Note<
"jump exits scope of __weak variable">;
def note_exits_block_captures_cxx_obj : Note<
"jump exits lifetime of block which captures a destructible C++ object">;
def note_exits_block_captures_strong : Note<
"jump exits lifetime of block which strongly captures a variable">;
def note_exits_block_captures_weak : Note<
"jump exits lifetime of block which weakly captures a variable">;
def note_exits_block_captures_non_trivial_c_struct : Note<
"jump exits lifetime of block which captures a C struct that is non-trivial "
"to destroy">;
def note_exits_compound_literal_scope : Note<
"jump exits lifetime of a compound literal that is non-trivial to destruct">;
def err_func_returning_qualified_void : ExtWarn<
"function cannot return qualified void type %0">,
InGroup<DiagGroup<"qualified-void-return-type">>;
def err_func_returning_array_function : Error<
"function cannot return %select{array|function}0 type %1">;
def err_field_declared_as_function : Error<"field %0 declared as a function">;
def err_field_incomplete_or_sizeless : Error<
"field has %select{incomplete|sizeless}0 type %1">;
def ext_variable_sized_type_in_struct : ExtWarn<
"field %0 with variable sized type %1 not at the end of a struct or class is"
" a GNU extension">, InGroup<GNUVariableSizedTypeNotAtEnd>;
def ext_c99_flexible_array_member : Extension<
"flexible array members are a C99 feature">, InGroup<C99>;
def err_flexible_array_virtual_base : Error<
"flexible array member %0 not allowed in "
"%select{struct|interface|union|class|enum}1 which has a virtual base class">;
def err_flexible_array_empty_aggregate : Error<
"flexible array member %0 not allowed in otherwise empty "
"%select{struct|interface|union|class|enum}1">;
def err_flexible_array_has_nontrivial_dtor : Error<
"flexible array member %0 of type %1 with non-trivial destruction">;
def ext_flexible_array_in_struct : Extension<
"%0 may not be nested in a struct due to flexible array member">,
InGroup<FlexibleArrayExtensions>;
def ext_flexible_array_in_array : Extension<
"%0 may not be used as an array element due to flexible array member">,
InGroup<FlexibleArrayExtensions>;
def err_flexible_array_init : Error<
"initialization of flexible array member is not allowed">;
def ext_flexible_array_empty_aggregate_ms : Extension<
"flexible array member %0 in otherwise empty "
"%select{struct|interface|union|class|enum}1 is a Microsoft extension">,
InGroup<MicrosoftFlexibleArray>;
def err_flexible_array_union : Error<
"flexible array member %0 in a union is not allowed">;
def ext_flexible_array_union_ms : Extension<
"flexible array member %0 in a union is a Microsoft extension">,
InGroup<MicrosoftFlexibleArray>;
def ext_flexible_array_empty_aggregate_gnu : Extension<
"flexible array member %0 in otherwise empty "
"%select{struct|interface|union|class|enum}1 is a GNU extension">,
InGroup<GNUEmptyStruct>;
def ext_flexible_array_union_gnu : Extension<
"flexible array member %0 in a union is a GNU extension">, InGroup<GNUFlexibleArrayUnionMember>;
def err_flexible_array_not_at_end : Error<
"flexible array member %0 with type %1 is not at the end of"
" %select{struct|interface|union|class|enum}2">;
def err_objc_variable_sized_type_not_at_end : Error<
"field %0 with variable sized type %1 is not at the end of class">;
def note_next_field_declaration : Note<
"next field declaration is here">;
def note_next_ivar_declaration : Note<
"next %select{instance variable declaration|synthesized instance variable}0"
" is here">;
def err_synthesize_variable_sized_ivar : Error<
"synthesized property with variable size type %0"
" requires an existing instance variable">;
def err_flexible_array_arc_retainable : Error<
"ARC forbids flexible array members with retainable object type">;
def warn_variable_sized_ivar_visibility : Warning<
"field %0 with variable sized type %1 is not visible to subclasses and"
" can conflict with their instance variables">, InGroup<ObjCFlexibleArray>;
def warn_superclass_variable_sized_type_not_at_end : Warning<
"field %0 can overwrite instance variable %1 with variable sized type %2"
" in superclass %3">, InGroup<ObjCFlexibleArray>;
let CategoryName = "ARC Semantic Issue" in {
// ARC-mode diagnostics.
let CategoryName = "ARC Weak References" in {
def err_arc_weak_no_runtime : Error<
"cannot create __weak reference because the current deployment target "
"does not support weak references">;
def err_arc_weak_disabled : Error<
"cannot create __weak reference in file using manual reference counting">;
def err_synthesizing_arc_weak_property_disabled : Error<
"cannot synthesize weak property in file using manual reference counting">;
def err_synthesizing_arc_weak_property_no_runtime : Error<
"cannot synthesize weak property because the current deployment target "
"does not support weak references">;
def err_arc_unsupported_weak_class : Error<
"class is incompatible with __weak references">;
def err_arc_weak_unavailable_assign : Error<
"assignment of a weak-unavailable object to a __weak object">;
def err_arc_weak_unavailable_property : Error<
"synthesizing __weak instance variable of type %0, which does not "
"support weak references">;
def note_implemented_by_class : Note<
"when implemented by class %0">;
def err_arc_convesion_of_weak_unavailable : Error<
"%select{implicit conversion|cast}0 of weak-unavailable object of type %1 to"
" a __weak object of type %2">;
} // end "ARC Weak References" category
let CategoryName = "ARC Restrictions" in {
def err_unavailable_in_arc : Error<
"%0 is unavailable in ARC">;
def note_arc_forbidden_type : Note<
"declaration uses type that is ill-formed in ARC">;
def note_performs_forbidden_arc_conversion : Note<
"inline function performs a conversion which is forbidden in ARC">;
def note_arc_init_returns_unrelated : Note<
"init method must return a type related to its receiver type">;
def note_arc_weak_disabled : Note<
"declaration uses __weak, but ARC is disabled">;
def note_arc_weak_no_runtime : Note<"declaration uses __weak, which "
"the current deployment target does not support">;
def note_arc_field_with_ownership : Note<
"field has non-trivial ownership qualification">;
def err_arc_illegal_explicit_message : Error<
"ARC forbids explicit message send of %0">;
def err_arc_unused_init_message : Error<
"the result of a delegate init call must be immediately returned "
"or assigned to 'self'">;
def err_arc_mismatched_cast : Error<
"%select{implicit conversion|cast}0 of "
"%select{%2|a non-Objective-C pointer type %2|a block pointer|"
"an Objective-C pointer|an indirect pointer to an Objective-C pointer}1"
" to %3 is disallowed with ARC">;
def err_arc_nolifetime_behavior : Error<
"explicit ownership qualifier on cast result has no effect">;
def err_arc_objc_property_default_assign_on_object : Error<
"ARC forbids synthesizing a property of an Objective-C object "
"with unspecified ownership or storage attribute">;
def err_arc_illegal_selector : Error<
"ARC forbids use of %0 in a @selector">;
def err_arc_illegal_method_def : Error<
"ARC forbids %select{implementation|synthesis}0 of %1">;
def warn_arc_strong_pointer_objc_pointer : Warning<
"method parameter of type %0 with no explicit ownership">,
InGroup<DiagGroup<"explicit-ownership-type">>, DefaultIgnore;
} // end "ARC Restrictions" category
def err_arc_lost_method_convention : Error<
"method was declared as %select{an 'alloc'|a 'copy'|an 'init'|a 'new'}0 "
"method, but its implementation doesn't match because %select{"
"its result type is not an object pointer|"
"its result type is unrelated to its receiver type}1">;
def note_arc_lost_method_convention : Note<"declaration in interface">;
def err_arc_gained_method_convention : Error<
"method implementation does not match its declaration">;
def note_arc_gained_method_convention : Note<
"declaration in interface is not in the '%select{alloc|copy|init|new}0' "
"family because %select{its result type is not an object pointer|"
"its result type is unrelated to its receiver type}1">;
def err_typecheck_arc_assign_self : Error<
"cannot assign to 'self' outside of a method in the init family">;
def err_typecheck_arc_assign_self_class_method : Error<
"cannot assign to 'self' in a class method">;
def err_typecheck_arr_assign_enumeration : Error<
"fast enumeration variables cannot be modified in ARC by default; "
"declare the variable __strong to allow this">;
def err_typecheck_arc_assign_externally_retained : Error<
"variable declared with 'objc_externally_retained' "
"cannot be modified in ARC">;
def warn_arc_retained_assign : Warning<
"assigning retained object to %select{weak|unsafe_unretained}0 "
"%select{property|variable}1"
"; object will be released after assignment">,
InGroup<ARCUnsafeRetainedAssign>;
def warn_arc_retained_property_assign : Warning<
"assigning retained object to unsafe property"
"; object will be released after assignment">,
InGroup<ARCUnsafeRetainedAssign>;
def warn_arc_literal_assign : Warning<
"assigning %select{array literal|dictionary literal|numeric literal|boxed expression|<should not happen>|block literal}0"
" to a weak %select{property|variable}1"
"; object will be released after assignment">,
InGroup<ARCUnsafeRetainedAssign>;
def err_arc_new_array_without_ownership : Error<
"'new' cannot allocate an array of %0 with no explicit ownership">;
def err_arc_autoreleasing_var : Error<
"%select{__block variables|global variables|fields|instance variables}0 cannot have "
"__autoreleasing ownership">;
def err_arc_autoreleasing_capture : Error<
"cannot capture __autoreleasing variable in a "
"%select{block|lambda by copy}0">;
def err_arc_thread_ownership : Error<
"thread-local variable has non-trivial ownership: type is %0">;
def err_arc_indirect_no_ownership : Error<
"%select{pointer|reference}1 to non-const type %0 with no explicit ownership">;
def err_arc_array_param_no_ownership : Error<
"must explicitly describe intended ownership of an object array parameter">;
def err_arc_pseudo_dtor_inconstant_quals : Error<
"pseudo-destructor destroys object of type %0 with inconsistently-qualified "
"type %1">;
def err_arc_init_method_unrelated_result_type : Error<
"init methods must return a type related to the receiver type">;
def err_arc_nonlocal_writeback : Error<
"passing address of %select{non-local|non-scalar}0 object to "
"__autoreleasing parameter for write-back">;
def err_arc_method_not_found : Error<
"no known %select{instance|class}1 method for selector %0">;
def err_arc_receiver_forward_class : Error<
"receiver %0 for class message is a forward declaration">;
def err_arc_may_not_respond : Error<
"no visible @interface for %0 declares the selector %1">;
def err_arc_receiver_forward_instance : Error<
"receiver type %0 for instance message is a forward declaration">;
def warn_receiver_forward_instance : Warning<
"receiver type %0 for instance message is a forward declaration">,
InGroup<ForwardClassReceiver>, DefaultIgnore;
def err_arc_collection_forward : Error<
"collection expression type %0 is a forward declaration">;
def err_arc_multiple_method_decl : Error<
"multiple methods named %0 found with mismatched result, "
"parameter type or attributes">;
def warn_arc_lifetime_result_type : Warning<
"ARC %select{unused|__unsafe_unretained|__strong|__weak|__autoreleasing}0 "
"lifetime qualifier on return type is ignored">,
InGroup<IgnoredQualifiers>;
let CategoryName = "ARC Retain Cycle" in {
def warn_arc_retain_cycle : Warning<
"capturing %0 strongly in this block is likely to lead to a retain cycle">,
InGroup<ARCRetainCycles>;
def note_arc_retain_cycle_owner : Note<
"block will be retained by %select{the captured object|an object strongly "
"retained by the captured object}0">;
} // end "ARC Retain Cycle" category
def warn_arc_object_memaccess : Warning<
"%select{destination for|source of}0 this %1 call is a pointer to "
"ownership-qualified type %2">, InGroup<ARCNonPodMemAccess>;
let CategoryName = "ARC and @properties" in {
def err_arc_strong_property_ownership : Error<
"existing instance variable %1 for strong property %0 may not be "
"%select{|__unsafe_unretained||__weak}2">;
def err_arc_assign_property_ownership : Error<
"existing instance variable %1 for property %0 with %select{unsafe_unretained|assign}2 "
"attribute must be __unsafe_unretained">;
def err_arc_inconsistent_property_ownership : Error<
"%select{|unsafe_unretained|strong|weak}1 property %0 may not also be "
"declared %select{|__unsafe_unretained|__strong|__weak|__autoreleasing}2">;
} // end "ARC and @properties" category
def warn_block_capture_autoreleasing : Warning<
"block captures an autoreleasing out-parameter, which may result in "
"use-after-free bugs">,
InGroup<BlockCaptureAutoReleasing>;
def note_declare_parameter_strong : Note<
"declare the parameter __strong or capture a __block __strong variable to "
"keep values alive across autorelease pools">;
def err_arc_atomic_ownership : Error<
"cannot perform atomic operation on a pointer to type %0: type has "
"non-trivial ownership">;
let CategoryName = "ARC Casting Rules" in {
def err_arc_bridge_cast_incompatible : Error<
"incompatible types casting %0 to %1 with a %select{__bridge|"
"__bridge_transfer|__bridge_retained}2 cast">;
def err_arc_bridge_cast_wrong_kind : Error<
"cast of %select{Objective-C|block|C}0 pointer type %1 to "
"%select{Objective-C|block|C}2 pointer type %3 cannot use %select{__bridge|"
"__bridge_transfer|__bridge_retained}4">;
def err_arc_cast_requires_bridge : Error<
"%select{cast|implicit conversion}0 of %select{Objective-C|block|C}1 "
"pointer type %2 to %select{Objective-C|block|C}3 pointer type %4 "
"requires a bridged cast">;
def note_arc_bridge : Note<
"use __bridge to convert directly (no change in ownership)">;
def note_arc_cstyle_bridge : Note<
"use __bridge with C-style cast to convert directly (no change in ownership)">;
def note_arc_bridge_transfer : Note<
"use %select{__bridge_transfer|CFBridgingRelease call}1 to transfer "
"ownership of a +1 %0 into ARC">;
def note_arc_cstyle_bridge_transfer : Note<
"use __bridge_transfer with C-style cast to transfer "
"ownership of a +1 %0 into ARC">;
def note_arc_bridge_retained : Note<
"use %select{__bridge_retained|CFBridgingRetain call}1 to make an "
"ARC object available as a +1 %0">;
def note_arc_cstyle_bridge_retained : Note<
"use __bridge_retained with C-style cast to make an "
"ARC object available as a +1 %0">;
} // ARC Casting category
} // ARC category name
def err_flexible_array_init_needs_braces : Error<
"flexible array requires brace-enclosed initializer">;
def err_illegal_decl_array_of_functions : Error<
"'%0' declared as array of functions of type %1">;
def err_array_incomplete_or_sizeless_type : Error<
"array has %select{incomplete|sizeless}0 element type %1">;
def err_illegal_message_expr_incomplete_type : Error<
"Objective-C message has incomplete result type %0">;
def err_illegal_decl_array_of_references : Error<
"'%0' declared as array of references of type %1">;
def err_decl_negative_array_size : Error<
"'%0' declared as an array with a negative size">;
def err_array_static_outside_prototype : Error<
"%0 used in array declarator outside of function prototype">;
def err_array_static_not_outermost : Error<
"%0 used in non-outermost array type derivation">;
def err_array_star_outside_prototype : Error<
"star modifier used outside of function prototype">;
def err_illegal_decl_pointer_to_reference : Error<
"'%0' declared as a pointer to a reference of type %1">;
def err_illegal_decl_mempointer_to_reference : Error<
"'%0' declared as a member pointer to a reference of type %1">;
def err_illegal_decl_mempointer_to_void : Error<
"'%0' declared as a member pointer to void">;
def err_illegal_decl_mempointer_in_nonclass : Error<
"'%0' does not point into a class">;
def err_mempointer_in_nonclass_type : Error<
"member pointer refers into non-class type %0">;
def err_reference_to_void : Error<"cannot form a reference to 'void'">;
def err_nonfunction_block_type : Error<
"block pointer to non-function type is invalid">;
def err_return_block_has_expr : Error<"void block should not return a value">;
def err_block_return_missing_expr : Error<
"non-void block should return a value">;
def err_func_def_incomplete_result : Error<
"incomplete result type %0 in function definition">;
def err_atomic_specifier_bad_type
: Error<"_Atomic cannot be applied to "
"%select{incomplete |array |function |reference |atomic |qualified "
"|sizeless ||integer }0type "
"%1 %select{|||||||which is not trivially copyable|}0">;
def warn_atomic_member_access : Warning<
"accessing a member of an atomic structure or union is undefined behavior">,
InGroup<DiagGroup<"atomic-access">>, DefaultError;
// Expressions.
def ext_sizeof_alignof_function_type : Extension<
"invalid application of '%0' to a function type">, InGroup<PointerArith>;
def ext_sizeof_alignof_void_type : Extension<
"invalid application of '%0' to a void type">, InGroup<PointerArith>;
def err_opencl_sizeof_alignof_type : Error<
"invalid application of '%0' to a void type">;
def err_sizeof_alignof_incomplete_or_sizeless_type : Error<
"invalid application of '%0' to %select{an incomplete|sizeless}1 type %2">;
def err_sizeof_alignof_function_type : Error<
"invalid application of '%0' to a function type">;
def err_openmp_default_simd_align_expr : Error<
"invalid application of '__builtin_omp_required_simd_align' to an expression, only type is allowed">;
def err_sizeof_alignof_typeof_bitfield : Error<
"invalid application of '%select{sizeof|alignof|typeof}0' to bit-field">;
def err_alignof_member_of_incomplete_type : Error<
"invalid application of 'alignof' to a field of a class still being defined">;
def err_vecstep_non_scalar_vector_type : Error<
"'vec_step' requires built-in scalar or vector type, %0 invalid">;
def err_offsetof_incomplete_type : Error<
"offsetof of incomplete type %0">;
def err_offsetof_record_type : Error<
"offsetof requires struct, union, or class type, %0 invalid">;
def err_offsetof_array_type : Error<"offsetof requires array type, %0 invalid">;
def ext_offsetof_non_pod_type : ExtWarn<"offset of on non-POD type %0">,
InGroup<InvalidOffsetof>;
def ext_offsetof_non_standardlayout_type : ExtWarn<
"offset of on non-standard-layout type %0">, InGroup<InvalidOffsetof>;
def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">;
def err_offsetof_field_of_virtual_base : Error<
"invalid application of 'offsetof' to a field of a virtual base">;
def warn_sub_ptr_zero_size_types : Warning<
"subtraction of pointers to type %0 of zero size has undefined behavior">,
InGroup<PointerArith>;
def warn_pointer_arith_null_ptr : Warning<
"performing pointer arithmetic on a null pointer has undefined behavior%select{| if the offset is nonzero}0">,
InGroup<NullPointerArithmetic>, DefaultIgnore;
def warn_gnu_null_ptr_arith : Extension<
"arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension">,
InGroup<GNUNullPointerArithmetic>;
def warn_pointer_sub_null_ptr : Warning<
"performing pointer subtraction with a null pointer %select{has|may have}0 undefined behavior">,
InGroup<NullPointerSubtraction>, DefaultIgnore;
def warn_floatingpoint_eq : Warning<
"comparing floating point with == or != is unsafe">,
InGroup<DiagGroup<"float-equal">>, DefaultIgnore;
def err_setting_eval_method_used_in_unsafe_context : Error <
"%select{'#pragma clang fp eval_method'|option 'ffp-eval-method'}0 cannot be used with "
"%select{option 'fapprox-func'|option 'mreassociate'|option 'freciprocal'|option 'ffp-eval-method'|'#pragma clang fp reassociate'}1">;
def warn_remainder_division_by_zero : Warning<
"%select{remainder|division}0 by zero is undefined">,
InGroup<DivZero>;
def warn_shift_lhs_negative : Warning<"shifting a negative signed value is undefined">,
InGroup<DiagGroup<"shift-negative-value">>;
def warn_shift_negative : Warning<"shift count is negative">,
InGroup<DiagGroup<"shift-count-negative">>;
def warn_shift_gt_typewidth : Warning<"shift count >= width of type">,
InGroup<DiagGroup<"shift-count-overflow">>;
def warn_shift_result_gt_typewidth : Warning<
"signed shift result (%0) requires %1 bits to represent, but %2 only has "
"%3 bits">, InGroup<DiagGroup<"shift-overflow">>;
def warn_shift_result_sets_sign_bit : Warning<
"signed shift result (%0) sets the sign bit of the shift expression's "
"type (%1) and becomes negative">,
InGroup<DiagGroup<"shift-sign-overflow">>, DefaultIgnore;
def warn_precedence_bitwise_rel : Warning<
"%0 has lower precedence than %1; %1 will be evaluated first">,
InGroup<Parentheses>;
def note_precedence_bitwise_first : Note<
"place parentheses around the %0 expression to evaluate it first">;
def note_precedence_silence : Note<
"place parentheses around the '%0' expression to silence this warning">;
def warn_precedence_conditional : Warning<
"operator '?:' has lower precedence than '%0'; '%0' will be evaluated first">,
InGroup<Parentheses>;
def warn_precedence_bitwise_conditional : Warning<
"operator '?:' has lower precedence than '%0'; '%0' will be evaluated first">,
InGroup<BitwiseConditionalParentheses>;
def note_precedence_conditional_first : Note<
"place parentheses around the '?:' expression to evaluate it first">;
def warn_enum_constant_in_bool_context : Warning<
"converting the enum constant to a boolean">,
InGroup<IntInBoolContext>, DefaultIgnore;
def warn_left_shift_in_bool_context : Warning<
"converting the result of '<<' to a boolean; did you mean '(%0) != 0'?">,
InGroup<IntInBoolContext>, DefaultIgnore;
def warn_logical_instead_of_bitwise : Warning<
"use of logical '%0' with constant operand">,
InGroup<DiagGroup<"constant-logical-operand">>;
def note_logical_instead_of_bitwise_change_operator : Note<
"use '%0' for a bitwise operation">;
def note_logical_instead_of_bitwise_remove_constant : Note<
"remove constant to silence this warning">;
def warn_bitwise_op_in_bitwise_op : Warning<
"'%0' within '%1'">, InGroup<BitwiseOpParentheses>, DefaultIgnore;
def warn_logical_and_in_logical_or : Warning<
"'&&' within '||'">, InGroup<LogicalOpParentheses>, DefaultIgnore;
def warn_overloaded_shift_in_comparison :Warning<
"overloaded operator %select{>>|<<}0 has higher precedence than "
"comparison operator">,
InGroup<OverloadedShiftOpParentheses>;
def note_evaluate_comparison_first :Note<
"place parentheses around comparison expression to evaluate it first">;
def note_concatenated_string_literal_silence :Note<
"place parentheses around the string literal to silence warning">;
def warn_addition_in_bitshift : Warning<
"operator '%0' has lower precedence than '%1'; "
"'%1' will be evaluated first">, InGroup<ShiftOpParentheses>;
def warn_self_assignment_builtin : Warning<
"explicitly assigning value of variable of type %0 to itself%select{|; did "
"you mean to assign to member %2?}1">,
InGroup<SelfAssignment>, DefaultIgnore;
def warn_self_assignment_overloaded : Warning<
"explicitly assigning value of variable of type %0 to itself%select{|; did "
"you mean to assign to member %2?}1">,
InGroup<SelfAssignmentOverloaded>, DefaultIgnore;
def warn_self_move : Warning<
"explicitly moving variable of type %0 to itself%select{|; did you mean to "
"move to member %2?}1">,
InGroup<SelfMove>, DefaultIgnore;
def err_builtin_move_forward_unsupported : Error<
"unsupported signature for %q0">;
def err_use_of_unaddressable_function : Error<
"taking address of non-addressable standard library function">;
// FIXME: This should also be in -Wc++23-compat once we have it.
def warn_cxx20_compat_use_of_unaddressable_function : Warning<
"taking address of non-addressable standard library function "
"is incompatible with C++20">, InGroup<CXX20Compat>;
def warn_redundant_move_on_return : Warning<
"redundant move in return statement">,
InGroup<RedundantMove>, DefaultIgnore;
def warn_pessimizing_move_on_return : Warning<
"moving a local object in a return statement prevents copy elision">,
InGroup<PessimizingMove>, DefaultIgnore;
def warn_pessimizing_move_on_initialization : Warning<
"moving a temporary object prevents copy elision">,
InGroup<PessimizingMove>, DefaultIgnore;
def note_remove_move : Note<"remove std::move call here">;
def warn_string_plus_int : Warning<
"adding %0 to a string does not append to the string">,
InGroup<StringPlusInt>;
def warn_string_plus_char : Warning<
"adding %0 to a string pointer does not append to the string">,
InGroup<StringPlusChar>;
def note_string_plus_scalar_silence : Note<
"use array indexing to silence this warning">;
def warn_sizeof_array_param : Warning<
"sizeof on array function parameter will return size of %0 instead of %1">,
InGroup<SizeofArrayArgument>;
def warn_sizeof_array_decay : Warning<
"sizeof on pointer operation will return size of %0 instead of %1">,
InGroup<SizeofArrayDecay>;
def err_sizeof_nonfragile_interface : Error<
"application of '%select{alignof|sizeof}1' to interface %0 is "
"not supported on this architecture and platform">;
def err_atdef_nonfragile_interface : Error<
"use of @defs is not supported on this architecture and platform">;
def err_subscript_nonfragile_interface : Error<
"subscript requires size of interface %0, which is not constant for "
"this architecture and platform">;
def err_arithmetic_nonfragile_interface : Error<
"arithmetic on pointer to interface %0, which is not a constant size for "
"this architecture and platform">;
def warn_deprecated_comma_subscript : Warning<
"top-level comma expression in array subscript is deprecated "
"in C++20 and unsupported in C++2b">,
InGroup<DeprecatedCommaSubscript>;
def ext_subscript_non_lvalue : Extension<
"ISO C90 does not allow subscripting non-lvalue array">;
def err_typecheck_subscript_value : Error<
"subscripted value is not an array, pointer, or vector">;
def err_typecheck_subscript_not_integer : Error<
"array subscript is not an integer">;
def err_subscript_function_type : Error<
"subscript of pointer to function type %0">;
def err_subscript_incomplete_or_sizeless_type : Error<
"subscript of pointer to %select{incomplete|sizeless}0 type %1">;
def err_subscript_svbool_t : Error<
"subscript of svbool_t is not allowed">;
def err_dereference_incomplete_type : Error<
"dereference of pointer to incomplete type %0">;
def ext_gnu_subscript_void_type : Extension<
"subscript of a pointer to void is a GNU extension">,
InGroup<GNUPointerArith>;
def err_typecheck_member_reference_struct_union : Error<
"member reference base type %0 is not a structure or union">;
def err_typecheck_member_reference_ivar : Error<
"%0 does not have a member named %1">;
def err_arc_weak_ivar_access : Error<
"dereferencing a __weak pointer is not allowed due to possible "
"null value caused by race condition, assign it to strong variable first">;
def err_typecheck_member_reference_arrow : Error<
"member reference type %0 is not a pointer">;
def err_typecheck_member_reference_suggestion : Error<
"member reference type %0 is %select{a|not a}1 pointer; did you mean to use '%select{->|.}1'?">;
def note_typecheck_member_reference_suggestion : Note<
"did you mean to use '.' instead?">;
def note_member_reference_arrow_from_operator_arrow : Note<
"'->' applied to return value of the operator->() declared here">;
def err_typecheck_member_reference_type : Error<
"cannot refer to type member %0 in %1 with '%select{.|->}2'">;
def err_typecheck_member_reference_unknown : Error<
"cannot refer to member %0 in %1 with '%select{.|->}2'">;
def err_member_reference_needs_call : Error<
"base of member reference is a function; perhaps you meant to call "
"it%select{| with no arguments}0?">;
def warn_subscript_is_char : Warning<"array subscript is of type 'char'">,
InGroup<CharSubscript>, DefaultIgnore;
def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">;
def err_no_member : Error<"no member named %0 in %1">;
def err_no_member_overloaded_arrow : Error<
"no member named %0 in %1; did you mean to use '->' instead of '.'?">;
def err_member_not_yet_instantiated : Error<
"no member %0 in %1; it has not yet been instantiated">;
def note_non_instantiated_member_here : Note<
"not-yet-instantiated member is declared here">;
def err_enumerator_does_not_exist : Error<
"enumerator %0 does not exist in instantiation of %1">;
def note_enum_specialized_here : Note<
"enum %0 was explicitly specialized here">;
def err_specialization_not_primary_template : Error<
"cannot reference member of primary template because deduced class "
"template specialization %0 is %select{instantiated from a partial|"
"an explicit}1 specialization">;
def err_member_redeclared : Error<"class member cannot be redeclared">;
def ext_member_redeclared : ExtWarn<"class member cannot be redeclared">,
InGroup<RedeclaredClassMember>;
def err_member_redeclared_in_instantiation : Error<
"multiple overloads of %0 instantiate to the same signature %1">;
def err_member_name_of_class : Error<"member %0 has the same name as its class">;
def err_member_def_undefined_record : Error<
"out-of-line definition of %0 from class %1 without definition">;
def err_member_decl_does_not_match : Error<
"out-of-line %select{declaration|definition}2 of %0 "
"does not match any declaration in %1">;
def err_friend_decl_with_def_arg_must_be_def : Error<
"friend declaration specifying a default argument must be a definition">;
def err_friend_decl_with_def_arg_redeclared : Error<
"friend declaration specifying a default argument must be the only declaration">;
def err_friend_decl_does_not_match : Error<
"friend declaration of %0 does not match any declaration in %1">;
def err_member_decl_does_not_match_suggest : Error<
"out-of-line %select{declaration|definition}2 of %0 "
"does not match any declaration in %1; did you mean %3?">;
def err_member_def_does_not_match_ret_type : Error<
"return type of out-of-line definition of %q0 differs from "
"that in the declaration">;
def err_nonstatic_member_out_of_line : Error<
"non-static data member defined out-of-line">;
def err_qualified_typedef_declarator : Error<
"typedef declarator cannot be qualified">;
def err_qualified_param_declarator : Error<
"parameter declarator cannot be qualified">;
def ext_out_of_line_declaration : ExtWarn<
"out-of-line declaration of a member must be a definition">,
InGroup<OutOfLineDeclaration>, DefaultError;
def err_member_extra_qualification : Error<
"extra qualification on member %0">;
def warn_member_extra_qualification : Warning<
err_member_extra_qualification.Text>, InGroup<MicrosoftExtraQualification>;
def warn_namespace_member_extra_qualification : Warning<
"extra qualification on member %0">,
InGroup<DiagGroup<"extra-qualification">>;
def err_member_qualification : Error<
"non-friend class member %0 cannot have a qualified name">;
def note_member_def_close_match : Note<"member declaration nearly matches">;
def note_member_def_close_const_match : Note<
"member declaration does not match because "
"it %select{is|is not}0 const qualified">;
def note_member_def_close_param_match : Note<
"type of %ordinal0 parameter of member declaration does not match definition"
"%diff{ ($ vs $)|}1,2">;
def note_local_decl_close_match : Note<"local declaration nearly matches">;
def note_local_decl_close_param_match : Note<
"type of %ordinal0 parameter of local declaration does not match definition"
"%diff{ ($ vs $)|}1,2">;
def err_typecheck_ivar_variable_size : Error<
"instance variables must have a constant size">;
def err_ivar_reference_type : Error<
"instance variables cannot be of reference type">;
def err_typecheck_illegal_increment_decrement : Error<
"cannot %select{decrement|increment}1 value of type %0">;
def err_typecheck_expect_int : Error<
"used type %0 where integer is required">;
def err_typecheck_arithmetic_incomplete_or_sizeless_type : Error<
"arithmetic on a pointer to %select{an incomplete|sizeless}0 type %1">;
def err_typecheck_pointer_arith_function_type : Error<
"arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 "
"function type%select{|s}2 %1%select{| and %3}2">;
def err_typecheck_pointer_arith_void_type : Error<
"arithmetic on%select{ a|}0 pointer%select{|s}0 to void">;
def err_typecheck_decl_incomplete_type : Error<
"variable has incomplete type %0">;
def ext_typecheck_decl_incomplete_type : ExtWarn<
"tentative definition of variable with internal linkage has incomplete non-array type %0">,
InGroup<DiagGroup<"tentative-definition-incomplete-type">>;
def err_tentative_def_incomplete_type : Error<
"tentative definition has type %0 that is never completed">;
def warn_tentative_incomplete_array : Warning<
"tentative array definition assumed to have one element">;
def err_typecheck_incomplete_array_needs_initializer : Error<
"definition of variable with array type needs an explicit size "
"or an initializer">;
def err_array_init_not_init_list : Error<
"array initializer must be an initializer "
"list%select{| or string literal| or wide string literal}0">;
def err_array_init_narrow_string_into_wchar : Error<
"initializing wide char array with non-wide string literal">;
def err_array_init_wide_string_into_char : Error<
"initializing char array with wide string literal">;
def err_array_init_incompat_wide_string_into_wchar : Error<
"initializing wide char array with incompatible wide string literal">;
def err_array_init_plain_string_into_char8_t : Error<
"initializing 'char8_t' array with plain string literal">;
def note_array_init_plain_string_into_char8_t : Note<
"add 'u8' prefix to form a 'char8_t' string literal">;
def err_array_init_utf8_string_into_char : Error<
"%select{|ISO C++20 does not permit }0initialization of char array with "
"UTF-8 string literal%select{ is not permitted by '-fchar8_t'|}0">;
def warn_cxx20_compat_utf8_string : Warning<
"type of UTF-8 string literal will change from array of const char to "
"array of const char8_t in C++20">, InGroup<CXX20Compat>, DefaultIgnore;
def note_cxx20_compat_utf8_string_remove_u8 : Note<
"remove 'u8' prefix to avoid a change of behavior; "
"Clang encodes unprefixed narrow string literals as UTF-8">;
def err_array_init_different_type : Error<
"cannot initialize array %diff{of type $ with array of type $|"
"with different type of array}0,1">;
def err_array_init_non_constant_array : Error<
"cannot initialize array %diff{of type $ with non-constant array of type $|"
"with different type of array}0,1">;
def ext_array_init_copy : Extension<
"initialization of an array "
"%diff{of type $ from a compound literal of type $|"
"from a compound literal}0,1 is a GNU extension">, InGroup<GNUCompoundLiteralInitializer>;
// This is intentionally not disabled by -Wno-gnu.
def ext_array_init_parens : ExtWarn<
"parenthesized initialization of a member array is a GNU extension">,
InGroup<DiagGroup<"gnu-array-member-paren-init">>, DefaultError;
def warn_deprecated_string_literal_conversion : Warning<
"conversion from string literal to %0 is deprecated">,
InGroup<CXX11CompatDeprecatedWritableStr>;
def ext_deprecated_string_literal_conversion : ExtWarn<
"ISO C++11 does not allow conversion from string literal to %0">,
InGroup<WritableStrings>, SFINAEFailure;
def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">;
def err_typecheck_sclass_fscope : Error<
"illegal storage class on file-scoped variable">;
def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">,
InGroup<MissingDeclarations>;
def ext_standalone_specifier : ExtWarn<"'%0' is not permitted on a declaration "
"of a type">, InGroup<MissingDeclarations>;
def err_standalone_class_nested_name_specifier : Error<
"forward declaration of %select{class|struct|interface|union|enum}0 cannot "
"have a nested name specifier">;
def err_typecheck_sclass_func : Error<"illegal storage class on function">;
def err_static_block_func : Error<
"function declared in block scope cannot have 'static' storage class">;
def err_typecheck_address_of : Error<"address of %select{bit-field"
"|vector element|property expression|register variable|matrix element}0 requested">;
def ext_typecheck_addrof_void : Extension<
"ISO C forbids taking the address of an expression of type 'void'">;
def err_unqualified_pointer_member_function : Error<
"must explicitly qualify name of member function when taking its address">;
def err_invalid_form_pointer_member_function : Error<
"cannot create a non-constant pointer to member function">;
def err_address_of_function_with_pass_object_size_params: Error<
"cannot take address of function %0 because parameter %1 has "
"pass_object_size attribute">;
def err_parens_pointer_member_function : Error<
"cannot parenthesize the name of a method when forming a member pointer">;
def err_typecheck_invalid_lvalue_addrof_addrof_function : Error<
"extra '&' taking address of overloaded function">;
def err_typecheck_invalid_lvalue_addrof : Error<
"cannot take the address of an rvalue of type %0">;
def ext_typecheck_addrof_temporary : ExtWarn<
"taking the address of a temporary object of type %0">,
InGroup<AddressOfTemporary>, DefaultError;
def err_typecheck_addrof_temporary : Error<
"taking the address of a temporary object of type %0">;
def err_typecheck_addrof_dtor : Error<
"taking the address of a destructor">;
def err_typecheck_unary_expr : Error<
"invalid argument type %0 to unary expression">;
def err_typecheck_indirection_requires_pointer : Error<
"indirection requires pointer operand (%0 invalid)">;
def ext_typecheck_indirection_through_void_pointer : ExtWarn<
"ISO C++ does not allow indirection on operand of type %0">,
InGroup<DiagGroup<"void-ptr-dereference">>;
def warn_indirection_through_null : Warning<
"indirection of non-volatile null pointer will be deleted, not trap">,
InGroup<NullDereference>;
def warn_binding_null_to_reference : Warning<
"binding dereferenced null pointer to reference has undefined behavior">,
InGroup<NullDereference>;
def note_indirection_through_null : Note<
"consider using __builtin_trap() or qualifying pointer with 'volatile'">;
def warn_pointer_indirection_from_incompatible_type : Warning<
"dereference of type %1 that was reinterpret_cast from type %0 has undefined "
"behavior">,
InGroup<UndefinedReinterpretCast>, DefaultIgnore;
def warn_taking_address_of_packed_member : Warning<
"taking address of packed member %0 of class or structure %q1 may result in an unaligned pointer value">,
InGroup<DiagGroup<"address-of-packed-member">>;
def warn_param_mismatched_alignment : Warning<
"passing %0-byte aligned argument to %1-byte aligned parameter %2%select{| of %4}3 may result in an unaligned pointer access">,
InGroup<DiagGroup<"align-mismatch">>;
def err_objc_object_assignment : Error<
"cannot assign to class object (%0 invalid)">;
def err_typecheck_invalid_operands : Error<
"invalid operands to binary expression (%0 and %1)">, Deferrable;
def note_typecheck_invalid_operands_converted : Note<
"%select{first|second}0 operand was implicitly converted to type %1">;
def err_typecheck_logical_vector_expr_gnu_cpp_restrict : Error<
"logical expression with vector %select{type %1 and non-vector type %2|types"
" %1 and %2}0 is only supported in C++">;
def err_typecheck_sub_ptr_compatible : Error<
"%diff{$ and $ are not pointers to compatible types|"
"pointers to incompatible types}0,1">;
def ext_typecheck_ordered_comparison_of_pointer_integer : ExtWarn<
"ordered comparison between pointer and integer (%0 and %1)">;
def ext_typecheck_ordered_comparison_of_pointer_and_zero : Extension<
"ordered comparison between pointer and zero (%0 and %1) is an extension">;
def err_typecheck_ordered_comparison_of_pointer_and_zero : Error<
"ordered comparison between pointer and zero (%0 and %1)">;
def err_typecheck_three_way_comparison_of_pointer_and_zero : Error<
"three-way comparison between pointer and zero">;
def ext_typecheck_compare_complete_incomplete_pointers : Extension<
"pointer comparisons before C11 "
"need to be between two complete or two incomplete types; "
"%0 is %select{|in}2complete and "
"%1 is %select{|in}3complete">,
InGroup<C11>;
def warn_typecheck_ordered_comparison_of_function_pointers : Warning<
"ordered comparison of function pointers (%0 and %1)">,
InGroup<OrderedCompareFunctionPointers>;
def ext_typecheck_ordered_comparison_of_function_pointers : ExtWarn<
"ordered comparison of function pointers (%0 and %1)">,
InGroup<OrderedCompareFunctionPointers>;
def err_typecheck_ordered_comparison_of_function_pointers : Error<
"ordered comparison of function pointers (%0 and %1)">;
def ext_typecheck_comparison_of_fptr_to_void : Extension<
"equality comparison between function pointer and void pointer (%0 and %1)">;
def err_typecheck_comparison_of_fptr_to_void : Error<
"equality comparison between function pointer and void pointer (%0 and %1)">;
def ext_typecheck_comparison_of_pointer_integer : ExtWarn<
"comparison between pointer and integer (%0 and %1)">,
InGroup<DiagGroup<"pointer-integer-compare">>;
def err_typecheck_comparison_of_pointer_integer : Error<
"comparison between pointer and integer (%0 and %1)">;
def ext_typecheck_comparison_of_distinct_pointers : ExtWarn<
"comparison of distinct pointer types%diff{ ($ and $)|}0,1">,
InGroup<CompareDistinctPointerType>;
def ext_typecheck_cond_incompatible_operands : ExtWarn<
"incompatible operand types (%0 and %1)">;
def err_cond_voidptr_arc : Error <
"operands to conditional of types%diff{ $ and $|}0,1 are incompatible "
"in ARC mode">;
def err_typecheck_comparison_of_distinct_pointers : Error<
"comparison of distinct pointer types%diff{ ($ and $)|}0,1">;
def err_typecheck_op_on_nonoverlapping_address_space_pointers : Error<
"%select{comparison between %diff{ ($ and $)|}0,1"
"|arithmetic operation with operands of type %diff{ ($ and $)|}0,1"
"|conditional operator with the second and third operands of type "
"%diff{ ($ and $)|}0,1}2"
" which are pointers to non-overlapping address spaces">;
def select_arith_conv_kind : TextSubstitution<
"%select{arithmetic between|bitwise operation between|comparison of|"
"conditional expression between|compound assignment of}0">;
def warn_arith_conv_enum_float : Warning<
"%sub{select_arith_conv_kind}0 "
"%select{floating-point|enumeration}1 type %2 "
"%plural{2:with|4:from|:and}0 "
"%select{enumeration|floating-point}1 type %3">,
InGroup<EnumFloatConversion>, DefaultIgnore;
def warn_arith_conv_enum_float_cxx20 : Warning<
"%sub{select_arith_conv_kind}0 "
"%select{floating-point|enumeration}1 type %2 "
"%plural{2:with|4:from|:and}0 "
"%select{enumeration|floating-point}1 type %3 is deprecated">,
InGroup<DeprecatedEnumFloatConversion>;
def warn_arith_conv_mixed_enum_types : Warning<
"%sub{select_arith_conv_kind}0 "
"different enumeration types%diff{ ($ and $)|}1,2">,
InGroup<EnumEnumConversion>, DefaultIgnore;
def warn_arith_conv_mixed_enum_types_cxx20 : Warning<
"%sub{select_arith_conv_kind}0 "
"different enumeration types%diff{ ($ and $)|}1,2 is deprecated">,
InGroup<DeprecatedEnumEnumConversion>;
def warn_arith_conv_mixed_anon_enum_types : Warning<
warn_arith_conv_mixed_enum_types.Text>,
InGroup<AnonEnumEnumConversion>, DefaultIgnore;
def warn_arith_conv_mixed_anon_enum_types_cxx20 : Warning<
warn_arith_conv_mixed_enum_types_cxx20.Text>,
InGroup<DeprecatedAnonEnumEnumConversion>;
def warn_conditional_mixed_enum_types : Warning<
warn_arith_conv_mixed_enum_types.Text>,
InGroup<EnumCompareConditional>, DefaultIgnore;
def warn_conditional_mixed_enum_types_cxx20 : Warning<
warn_arith_conv_mixed_enum_types_cxx20.Text>,
InGroup<DeprecatedEnumCompareConditional>;
def warn_comparison_mixed_enum_types : Warning<
warn_arith_conv_mixed_enum_types.Text>,
InGroup<EnumCompare>;
def warn_comparison_mixed_enum_types_cxx20 : Warning<
warn_arith_conv_mixed_enum_types_cxx20.Text>,
InGroup<DeprecatedEnumCompare>;
def warn_comparison_of_mixed_enum_types_switch : Warning<
"comparison of different enumeration types in switch statement"
"%diff{ ($ and $)|}0,1">,
InGroup<EnumCompareSwitch>;
def err_typecheck_assign_const : Error<
"%select{"
"cannot assign to return value because function %1 returns a const value|"
"cannot assign to variable %1 with const-qualified type %2|"
"cannot assign to %select{non-|}1static data member %2 "
"with const-qualified type %3|"
"cannot assign to non-static data member within const member function %1|"
"cannot assign to %select{variable %2|non-static data member %2|lvalue}1 "
"with %select{|nested }3const-qualified data member %4|"
"read-only variable is not assignable}0">;
def note_typecheck_assign_const : Note<
"%select{"
"function %1 which returns const-qualified type %2 declared here|"
"variable %1 declared const here|"
"%select{non-|}1static data member %2 declared const here|"
"member function %q1 is declared const here|"
"%select{|nested }1data member %2 declared const here}0">;
def warn_unsigned_always_true_comparison : Warning<
"result of comparison of %select{%3|unsigned expression}0 %2 "
"%select{unsigned expression|%3}0 is always %4">,
InGroup<TautologicalUnsignedZeroCompare>, DefaultIgnore;
def warn_unsigned_char_always_true_comparison : Warning<
"result of comparison of %select{%3|char expression}0 %2 "
"%select{char expression|%3}0 is always %4, since char is interpreted as "
"unsigned">, InGroup<TautologicalUnsignedCharZeroCompare>, DefaultIgnore;
def warn_unsigned_enum_always_true_comparison : Warning<
"result of comparison of %select{%3|unsigned enum expression}0 %2 "
"%select{unsigned enum expression|%3}0 is always %4">,
InGroup<TautologicalUnsignedEnumZeroCompare>, DefaultIgnore;
def warn_tautological_constant_compare : Warning<
"result of comparison %select{%3|%1}0 %2 "
"%select{%1|%3}0 is always %4">,
InGroup<TautologicalTypeLimitCompare>, DefaultIgnore;
def warn_tautological_compare_objc_bool : Warning<
"result of comparison of constant %0 with expression of type 'BOOL'"
" is always %1, as the only well defined values for 'BOOL' are YES and NO">,
InGroup<TautologicalObjCBoolCompare>;
def subst_int_range : TextSubstitution<"%0-bit %select{signed|unsigned}1 value">;
def warn_tautological_compare_value_range : Warning<
"result of comparison of "
"%select{%4|%sub{subst_int_range}1,2}0 %3 "
"%select{%sub{subst_int_range}1,2|%4}0 is always %5">,
InGroup<TautologicalValueRangeCompare>, DefaultIgnore;
def warn_mixed_sign_comparison : Warning<
"comparison of integers of different signs: %0 and %1">,
InGroup<SignCompare>, DefaultIgnore;
def warn_out_of_range_compare : Warning<
"result of comparison of %select{constant %0|true|false}1 with "
"%select{expression of type %2|boolean expression}3 is always %4">,
InGroup<TautologicalOutOfRangeCompare>;
def warn_tautological_bool_compare : Warning<warn_out_of_range_compare.Text>,
InGroup<TautologicalConstantCompare>;
def warn_integer_constants_in_conditional_always_true : Warning<
"converting the result of '?:' with integer constants to a boolean always "
"evaluates to 'true'">,
InGroup<TautologicalConstantCompare>;
def warn_left_shift_always : Warning<
"converting the result of '<<' to a boolean always evaluates "
"to %select{false|true}0">,
InGroup<TautologicalConstantCompare>;
def warn_null_in_arithmetic_operation : Warning<
"use of NULL in arithmetic operation">,
InGroup<NullArithmetic>;
def warn_null_in_comparison_operation : Warning<
"comparison between NULL and non-pointer "
"%select{(%1 and NULL)|(NULL and %1)}0">,
InGroup<NullArithmetic>;
def err_shift_rhs_only_vector : Error<
"requested shift is a vector of type %0 but the first operand is not a "
"vector (%1)">;
def warn_logical_not_on_lhs_of_check : Warning<
"logical not is only applied to the left hand side of this "
"%select{comparison|bitwise operator}0">,
InGroup<LogicalNotParentheses>;
def note_logical_not_fix : Note<
"add parentheses after the '!' to evaluate the "
"%select{comparison|bitwise operator}0 first">;
def note_logical_not_silence_with_parens : Note<
"add parentheses around left hand side expression to silence this warning">;
def err_invalid_this_use : Error<
"invalid use of 'this' outside of a non-static member function">;
def err_this_static_member_func : Error<
"'this' cannot be%select{| implicitly}0 used in a static member function "
"declaration">;
def err_invalid_member_use_in_static_method : Error<
"invalid use of member %0 in static member function">;
def err_invalid_qualified_function_type : Error<
"%select{non-member function|static member function|deduction guide}0 "
"%select{of type %2 |}1cannot have '%3' qualifier">;
def err_compound_qualified_function_type : Error<
"%select{block pointer|pointer|reference}0 to function type %select{%2 |}1"
"cannot have '%3' qualifier">;
def err_qualified_function_typeid : Error<
"type operand %0 of 'typeid' cannot have '%1' qualifier">;
def err_ref_qualifier_overload : Error<
"cannot overload a member function %select{without a ref-qualifier|with "
"ref-qualifier '&'|with ref-qualifier '&&'}0 with a member function %select{"
"without a ref-qualifier|with ref-qualifier '&'|with ref-qualifier '&&'}1">;
def err_invalid_non_static_member_use : Error<
"invalid use of non-static data member %0">;
def err_nested_non_static_member_use : Error<
"%select{call to non-static member function|use of non-static data member}0 "
"%2 of %1 from nested type %3">;
def warn_cxx98_compat_non_static_member_use : Warning<
"use of non-static data member %0 in an unevaluated context is "
"incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def err_invalid_incomplete_type_use : Error<
"invalid use of incomplete type %0">;
def err_builtin_func_cast_more_than_one_arg : Error<
"function-style cast to a builtin type can only take one argument">;
def err_value_init_for_array_type : Error<
"array types cannot be value-initialized">;
def err_init_for_function_type : Error<
"cannot create object of function type %0">;
def warn_format_nonliteral_noargs : Warning<
"format string is not a string literal (potentially insecure)">,
InGroup<FormatSecurity>;
def warn_format_nonliteral : Warning<
"format string is not a string literal">,
InGroup<FormatNonLiteral>, DefaultIgnore;
def err_unexpected_interface : Error<
"unexpected interface name %0: expected expression">;
def err_ref_non_value : Error<"%0 does not refer to a value">;
def err_ref_vm_type : Error<
"cannot refer to declaration with a variably modified type inside block">;
def err_ref_flexarray_type : Error<
"cannot refer to declaration of structure variable with flexible array member "
"inside block">;
def err_ref_array_type : Error<
"cannot refer to declaration with an array type inside block">;
def err_property_not_found : Error<
"property %0 not found on object of type %1">;
def err_invalid_property_name : Error<
"%0 is not a valid property name (accessing an object of type %1)">;
def err_getter_not_found : Error<
"no getter method for read from property">;
def err_objc_subscript_method_not_found : Error<
"expected method to %select{read|write}1 %select{dictionary|array}2 element not "
"found on object of type %0">;
def err_objc_subscript_index_type : Error<
"method index parameter type %0 is not integral type">;
def err_objc_subscript_key_type : Error<
"method key parameter type %0 is not object type">;
def err_objc_subscript_dic_object_type : Error<
"method object parameter type %0 is not object type">;
def err_objc_subscript_object_type : Error<
"cannot assign to this %select{dictionary|array}1 because assigning method's "
"2nd parameter of type %0 is not an Objective-C pointer type">;
def err_objc_subscript_base_type : Error<
"%select{dictionary|array}1 subscript base type %0 is not an Objective-C object">;
def err_objc_multiple_subscript_type_conversion : Error<
"indexing expression is invalid because subscript type %0 has "
"multiple type conversion functions">;
def err_objc_subscript_type_conversion : Error<
"indexing expression is invalid because subscript type %0 is not an integral"
" or Objective-C pointer type">;
def err_objc_subscript_pointer : Error<
"indexing expression is invalid because subscript type %0 is not an"
" Objective-C pointer">;
def err_objc_indexing_method_result_type : Error<
"method for accessing %select{dictionary|array}1 element must have Objective-C"
" object return type instead of %0">;
def err_objc_index_incomplete_class_type : Error<
"Objective-C index expression has incomplete class type %0">;
def err_illegal_container_subscripting_op : Error<
"illegal operation on Objective-C container subscripting">;
def err_property_not_found_forward_class : Error<
"property %0 cannot be found in forward class object %1">;
def err_property_not_as_forward_class : Error<
"property %0 refers to an incomplete Objective-C class %1 "
"(with no @interface available)">;
def note_forward_class : Note<
"forward declaration of class here">;
def err_duplicate_property : Error<
"property has a previous declaration">;
def ext_gnu_void_ptr : Extension<
"arithmetic on%select{ a|}0 pointer%select{|s}0 to void is a GNU extension">,
InGroup<GNUPointerArith>;
def ext_gnu_ptr_func_arith : Extension<
"arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 function "
"type%select{|s}2 %1%select{| and %3}2 is a GNU extension">,
InGroup<GNUPointerArith>;
def err_readonly_message_assignment : Error<
"assigning to 'readonly' return result of an Objective-C message not allowed">;
def ext_integer_increment_complex : Extension<
"ISO C does not support '++'/'--' on complex integer type %0">;
def ext_integer_complement_complex : Extension<
"ISO C does not support '~' for complex conjugation of %0">;
def err_nosetter_property_assignment : Error<
"%select{assignment to readonly property|"
"no setter method %1 for assignment to property}0">;
def err_nosetter_property_incdec : Error<
"%select{%select{increment|decrement}1 of readonly property|"
"no setter method %2 for %select{increment|decrement}1 of property}0">;
def err_nogetter_property_compound_assignment : Error<
"a getter method is needed to perform a compound assignment on a property">;
def err_nogetter_property_incdec : Error<
"no getter method %1 for %select{increment|decrement}0 of property">;
def err_no_subobject_property_setting : Error<
"expression is not assignable">;
def err_qualified_objc_access : Error<
"%select{property|instance variable}0 access cannot be qualified with '%1'">;
def ext_freestanding_complex : Extension<
"complex numbers are an extension in a freestanding C99 implementation">;
// FIXME: Remove when we support imaginary.
def err_imaginary_not_supported : Error<"imaginary types are not supported">;
// Obj-c expressions
def warn_root_inst_method_not_found : Warning<
"instance method %0 is being used on 'Class' which is not in the root class">,
InGroup<MethodAccess>;
def warn_class_method_not_found : Warning<
"class method %objcclass0 not found (return type defaults to 'id')">,
InGroup<MethodAccess>;
def warn_instance_method_on_class_found : Warning<
"instance method %0 found instead of class method %1">,
InGroup<MethodAccess>;
def warn_inst_method_not_found : Warning<
"instance method %objcinstance0 not found (return type defaults to 'id')">,
InGroup<MethodAccess>;
def warn_instance_method_not_found_with_typo : Warning<
"instance method %objcinstance0 not found (return type defaults to 'id')"
"; did you mean %objcinstance2?">, InGroup<MethodAccess>;
def warn_class_method_not_found_with_typo : Warning<
"class method %objcclass0 not found (return type defaults to 'id')"
"; did you mean %objcclass2?">, InGroup<MethodAccess>;
def err_method_not_found_with_typo : Error<
"%select{instance|class}1 method %0 not found "
"; did you mean %2?">;
def err_no_super_class_message : Error<
"no @interface declaration found in class messaging of %0">;
def err_root_class_cannot_use_super : Error<
"%0 cannot use 'super' because it is a root class">;
def err_invalid_receiver_to_message_super : Error<
"'super' is only valid in a method body">;
def err_invalid_receiver_class_message : Error<
"receiver type %0 is not an Objective-C class">;
def err_missing_open_square_message_send : Error<
"missing '[' at start of message send expression">;
def warn_bad_receiver_type : Warning<
"receiver type %0 is not 'id' or interface pointer, consider "
"casting it to 'id'">,InGroup<ObjCReceiver>;
def err_bad_receiver_type : Error<"bad receiver type %0">;
def err_incomplete_receiver_type : Error<"incomplete receiver type %0">;
def err_unknown_receiver_suggest : Error<
"unknown receiver %0; did you mean %1?">;
def err_objc_throw_expects_object : Error<
"@throw requires an Objective-C object type (%0 invalid)">;
def err_objc_synchronized_expects_object : Error<
"@synchronized requires an Objective-C object type (%0 invalid)">;
def err_rethrow_used_outside_catch : Error<
"@throw (rethrow) used outside of a @catch block">;
def err_attribute_multiple_objc_gc : Error<
"multiple garbage collection attributes specified for type">;
def err_catch_param_not_objc_type : Error<
"@catch parameter is not a pointer to an interface type">;
def err_illegal_qualifiers_on_catch_parm : Error<
"illegal qualifiers on @catch parameter">;
def err_storage_spec_on_catch_parm : Error<
"@catch parameter cannot have storage specifier '%0'">;
def warn_register_objc_catch_parm : Warning<
"'register' storage specifier on @catch parameter will be ignored">;
def err_qualified_objc_catch_parm : Error<
"@catch parameter declarator cannot be qualified">;
def warn_objc_pointer_cxx_catch_fragile : Warning<
"cannot catch an exception thrown with @throw in C++ in the non-unified "
"exception model">, InGroup<ObjCNonUnifiedException>;
def err_objc_object_catch : Error<
"cannot catch an Objective-C object by value">;
def err_incomplete_type_objc_at_encode : Error<
"'@encode' of incomplete type %0">;
def warn_objc_circular_container : Warning<
"adding %0 to %1 might cause circular dependency in container">,
InGroup<DiagGroup<"objc-circular-container">>;
def note_objc_circular_container_declared_here : Note<"%0 declared here">;
def warn_objc_unsafe_perform_selector : Warning<
"%0 is incompatible with selectors that return a "
"%select{struct|union|vector}1 type">,
InGroup<DiagGroup<"objc-unsafe-perform-selector">>;
def note_objc_unsafe_perform_selector_method_declared_here : Note<
"method %0 that returns %1 declared here">;
def err_attribute_arm_builtin_alias : Error<
"'__clang_arm_builtin_alias' attribute can only be applied to an ARM builtin">;
def err_attribute_arm_mve_polymorphism : Error<
"'__clang_arm_mve_strict_polymorphism' attribute can only be applied to an MVE/NEON vector type">;
def warn_setter_getter_impl_required : Warning<
"property %0 requires method %1 to be defined - "
"use @synthesize, @dynamic or provide a method implementation "
"in this class implementation">,
InGroup<ObjCPropertyImpl>;
def warn_setter_getter_impl_required_in_category : Warning<
"property %0 requires method %1 to be defined - "
"use @dynamic or provide a method implementation in this category">,
InGroup<ObjCPropertyImpl>;
def note_parameter_named_here : Note<
"passing argument to parameter %0 here">;
def note_parameter_here : Note<
"passing argument to parameter here">;
def note_method_return_type_change : Note<
"compiler has implicitly changed method %0 return type">;
def warn_impl_required_for_class_property : Warning<
"class property %0 requires method %1 to be defined - "
"use @dynamic or provide a method implementation "
"in this class implementation">,
InGroup<ObjCPropertyImpl>;
def warn_impl_required_in_category_for_class_property : Warning<
"class property %0 requires method %1 to be defined - "
"use @dynamic or provide a method implementation in this category">,
InGroup<ObjCPropertyImpl>;
// C++ casts
// These messages adhere to the TryCast pattern: %0 is an int specifying the
// cast type, %1 is the source type, %2 is the destination type.
def err_bad_reinterpret_cast_overload : Error<
"reinterpret_cast cannot resolve overloaded function %0 to type %1">;
def warn_reinterpret_different_from_static : Warning<
"'reinterpret_cast' %select{from|to}3 class %0 %select{to|from}3 its "
"%select{virtual base|base at non-zero offset}2 %1 behaves differently from "
"'static_cast'">, InGroup<ReinterpretBaseClass>;
def note_reinterpret_updowncast_use_static: Note<
"use 'static_cast' to adjust the pointer correctly while "
"%select{upcasting|downcasting}0">;
def err_bad_static_cast_overload : Error<
"address of overloaded function %0 cannot be static_cast to type %1">;
def err_bad_cstyle_cast_overload : Error<
"address of overloaded function %0 cannot be cast to type %1">;
def err_bad_cxx_cast_generic : Error<
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|"
"C-style cast|functional-style cast|addrspace_cast}0 from %1 to %2 is not allowed">;
def err_bad_cxx_cast_unrelated_class : Error<
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
"functional-style cast|}0 from %1 to %2, which are not related by "
"inheritance, is not allowed">;
def note_type_incomplete : Note<"%0 is incomplete">;
def err_bad_cxx_cast_rvalue : Error<
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
"functional-style cast|addrspace_cast}0 from rvalue to reference type %2">;
def err_bad_cxx_cast_bitfield : Error<
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
"functional-style cast|}0 from bit-field lvalue to reference type %2">;
def err_bad_cxx_cast_qualifiers_away : Error<
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
"functional-style cast|}0 from %1 to %2 casts away qualifiers">;
def err_bad_cxx_cast_addr_space_mismatch : Error<
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|"
"C-style cast|functional-style cast|addrspace_cast}0 from %1 to %2 converts between mismatching address"
" spaces">;
def ext_bad_cxx_cast_qualifiers_away_incoherent : ExtWarn<
"ISO C++ does not allow "
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
"functional-style cast|}0 from %1 to %2 because it casts away qualifiers, "
"even though the source and destination types are unrelated">,
SFINAEFailure, InGroup<DiagGroup<"cast-qual-unrelated">>;
def err_bad_const_cast_dest : Error<
"%select{const_cast||||C-style cast|functional-style cast|}0 to %2, "
"which is not a reference, pointer-to-object, or pointer-to-data-member">;
def ext_cast_fn_obj : Extension<
"cast between pointer-to-function and pointer-to-object is an extension">;
def ext_ms_cast_fn_obj : ExtWarn<
"static_cast between pointer-to-function and pointer-to-object is a "
"Microsoft extension">, InGroup<MicrosoftCast>;
def warn_cxx98_compat_cast_fn_obj : Warning<
"cast between pointer-to-function and pointer-to-object is incompatible with C++98">,
InGroup<CXX98CompatPedantic>, DefaultIgnore;
def err_bad_reinterpret_cast_small_int : Error<
"cast from pointer to smaller type %2 loses information">;
def err_bad_cxx_cast_vector_to_scalar_different_size : Error<
"%select{||reinterpret_cast||C-style cast||}0 from vector %1 "
"to scalar %2 of different size">;
def err_bad_cxx_cast_scalar_to_vector_different_size : Error<
"%select{||reinterpret_cast||C-style cast||}0 from scalar %1 "
"to vector %2 of different size">;
def err_bad_cxx_cast_vector_to_vector_different_size : Error<
"%select{||reinterpret_cast||C-style cast||}0 from vector %1 "
"to vector %2 of different size">;
def warn_bad_cxx_cast_nested_pointer_addr_space : Warning<
"%select{reinterpret_cast|C-style cast}0 from %1 to %2 "
"changes address space of nested pointers">,
InGroup<IncompatiblePointerTypesDiscardsQualifiers>;
def err_bad_lvalue_to_rvalue_cast : Error<
"cannot cast from lvalue of type %1 to rvalue reference type %2; types are "
"not compatible">;
def err_bad_rvalue_to_rvalue_cast : Error<
"cannot cast from rvalue of type %1 to rvalue reference type %2; types are "
"not compatible">;
def err_bad_static_cast_pointer_nonpointer : Error<
"cannot cast from type %1 to pointer type %2">;
def err_bad_static_cast_member_pointer_nonmp : Error<
"cannot cast from type %1 to member pointer type %2">;
def err_bad_cxx_cast_member_pointer_size : Error<
"cannot %select{||reinterpret_cast||C-style cast||}0 from member pointer "
"type %1 to member pointer type %2 of different size">;
def err_bad_reinterpret_cast_reference : Error<
"reinterpret_cast of a %0 to %1 needs its address, which is not allowed">;
def warn_undefined_reinterpret_cast : Warning<
"reinterpret_cast from %0 to %1 has undefined behavior">,
InGroup<UndefinedReinterpretCast>, DefaultIgnore;
// These messages don't adhere to the pattern.
// FIXME: Display the path somehow better.
def err_ambiguous_base_to_derived_cast : Error<
"ambiguous cast from base %0 to derived %1:%2">;
def err_static_downcast_via_virtual : Error<
"cannot cast %0 to %1 via virtual base %2">;
def err_downcast_from_inaccessible_base : Error<
"cannot cast %select{private|protected}2 base class %1 to %0">;
def err_upcast_to_inaccessible_base : Error<
"cannot cast %0 to its %select{private|protected}2 base class %1">;
def err_bad_dynamic_cast_not_ref_or_ptr : Error<
"invalid target type %0 for dynamic_cast; target type must be a reference or pointer type to a defined class">;
def err_bad_dynamic_cast_not_class : Error<"%0 is not a class type">;
def err_bad_cast_incomplete : Error<"%0 is an incomplete type">;
def err_bad_dynamic_cast_not_ptr : Error<"cannot use dynamic_cast to convert from %0 to %1">;
def err_bad_dynamic_cast_not_polymorphic : Error<"%0 is not polymorphic">;
// Other C++ expressions
def err_need_header_before_typeid : Error<
"you need to include <typeinfo> before using the 'typeid' operator">;
def err_need_header_before_placement_new : Error<
"no matching %0 function for non-allocating placement new expression; "
"include <new>">;
def err_ms___leave_not_in___try : Error<
"'__leave' statement not in __try block">;
def err_uuidof_without_guid : Error<
"cannot call operator __uuidof on a type with no GUID">;
def err_uuidof_with_multiple_guids : Error<
"cannot call operator __uuidof on a type with multiple GUIDs">;
def err_incomplete_typeid : Error<"'typeid' of incomplete type %0">;
def err_variably_modified_typeid : Error<"'typeid' of variably modified type %0">;
def err_static_illegal_in_new : Error<
"the 'static' modifier for the array size is not legal in new expressions">;
def err_array_new_needs_size : Error<
"array size must be specified in new expression with no initializer">;
def err_bad_new_type : Error<
"cannot allocate %select{function|reference}1 type %0 with new">;
def err_new_incomplete_or_sizeless_type : Error<
"allocation of %select{incomplete|sizeless}0 type %1">;
def err_new_array_nonconst : Error<
"only the first dimension of an allocated array may have dynamic size">;
def err_new_array_size_unknown_from_init : Error<
"cannot determine allocated array size from initializer">;
def err_new_array_init_args : Error<
"array 'new' cannot have initialization arguments">;
def ext_new_paren_array_nonconst : ExtWarn<
"when type is in parentheses, array cannot have dynamic size">;
def err_placement_new_non_placement_delete : Error<
"'new' expression with placement arguments refers to non-placement "
"'operator delete'">;
def err_array_size_not_integral : Error<
"array size expression must have integral or %select{|unscoped }0"
"enumeration type, not %1">;
def err_array_size_incomplete_type : Error<
"array size expression has incomplete class type %0">;
def err_array_size_explicit_conversion : Error<
"array size expression of type %0 requires explicit conversion to type %1">;
def note_array_size_conversion : Note<
"conversion to %select{integral|enumeration}0 type %1 declared here">;
def err_array_size_ambiguous_conversion : Error<
"ambiguous conversion of array size expression of type %0 to an integral or "
"enumeration type">;
def ext_array_size_conversion : Extension<
"implicit conversion from array size expression of type %0 to "
"%select{integral|enumeration}1 type %2 is a C++11 extension">,
InGroup<CXX11>;
def warn_cxx98_compat_array_size_conversion : Warning<
"implicit conversion from array size expression of type %0 to "
"%select{integral|enumeration}1 type %2 is incompatible with C++98">,
InGroup<CXX98CompatPedantic>, DefaultIgnore;
def err_address_space_qualified_new : Error<
"'new' cannot allocate objects of type %0 in address space '%1'">;
def err_address_space_qualified_delete : Error<
"'delete' cannot delete objects of type %0 in address space '%1'">;
def err_default_init_const : Error<
"default initialization of an object of const type %0"
"%select{| without a user-provided default constructor}1">;
def ext_default_init_const : ExtWarn<
"default initialization of an object of const type %0"
"%select{| without a user-provided default constructor}1 "
"is a Microsoft extension">,
InGroup<MicrosoftConstInit>;
def err_delete_operand : Error<"cannot delete expression of type %0">;
def ext_delete_void_ptr_operand : ExtWarn<
"cannot delete expression with pointer-to-'void' type %0">,
InGroup<DeleteIncomplete>;
def err_ambiguous_delete_operand : Error<
"ambiguous conversion of delete expression of type %0 to a pointer">;
def warn_delete_incomplete : Warning<
"deleting pointer to incomplete type %0 may cause undefined behavior">,
InGroup<DeleteIncomplete>;
def err_delete_incomplete_class_type : Error<
"deleting incomplete class type %0; no conversions to pointer type">;
def err_delete_explicit_conversion : Error<
"converting delete expression from type %0 to type %1 invokes an explicit "
"conversion function">;
def note_delete_conversion : Note<"conversion to pointer type %0">;
def warn_delete_array_type : Warning<
"'delete' applied to a pointer-to-array type %0 treated as 'delete[]'">;
def warn_mismatched_delete_new : Warning<
"'delete%select{|[]}0' applied to a pointer that was allocated with "
"'new%select{[]|}0'; did you mean 'delete%select{[]|}0'?">,
InGroup<DiagGroup<"mismatched-new-delete">>;
def note_allocated_here : Note<"allocated with 'new%select{[]|}0' here">;
def err_no_suitable_delete_member_function_found : Error<
"no suitable member %0 in %1">;
def err_ambiguous_suitable_delete_member_function_found : Error<
"multiple suitable %0 functions in %1">;
def warn_ambiguous_suitable_delete_function_found : Warning<
"multiple suitable %0 functions for %1; no 'operator delete' function "
"will be invoked if initialization throws an exception">,
InGroup<DiagGroup<"ambiguous-delete">>;
def note_member_declared_here : Note<
"member %0 declared here">;
def note_member_first_declared_here : Note<
"member %0 first declared here">;
def warn_bitwise_instead_of_logical : Warning<
"use of bitwise '%0' with boolean operands">,
InGroup<BitwiseInsteadOfLogical>, DefaultIgnore;
def warn_bitwise_negation_bool : Warning<
"bitwise negation of a boolean expression%select{;| always evaluates to 'true';}0 "
"did you mean logical negation?">,
InGroup<BoolOperation>, DefaultIgnore;
def err_decrement_bool : Error<"cannot decrement expression of type bool">;
def warn_increment_bool : Warning<
"incrementing expression of type bool is deprecated and "
"incompatible with C++17">, InGroup<DeprecatedIncrementBool>;
def ext_increment_bool : ExtWarn<
"ISO C++17 does not allow incrementing expression of type bool">,
DefaultError, InGroup<IncrementBool>;
def err_increment_decrement_enum : Error<
"cannot %select{decrement|increment}0 expression of enum type %1">;
def warn_deprecated_increment_decrement_volatile : Warning<
"%select{decrement|increment}0 of object of volatile-qualified type %1 "
"is deprecated">, InGroup<DeprecatedVolatile>;
def warn_deprecated_simple_assign_volatile : Warning<
"use of result of assignment to object of volatile-qualified type %0 "
"is deprecated">, InGroup<DeprecatedVolatile>;
def warn_deprecated_compound_assign_volatile : Warning<
"compound assignment to object of volatile-qualified type %0 is deprecated">,
InGroup<DeprecatedVolatile>;
def warn_deprecated_volatile_return : Warning<
"volatile-qualified return type %0 is deprecated">,
InGroup<DeprecatedVolatile>;
def warn_deprecated_volatile_param : Warning<
"volatile-qualified parameter type %0 is deprecated">,
InGroup<DeprecatedVolatile>;
def warn_deprecated_volatile_structured_binding : Warning<
"volatile qualifier in structured binding declaration is deprecated">,
InGroup<DeprecatedVolatile>;
def warn_deprecated_altivec_src_compat : Warning<
"Current handling of vector bool and vector pixel types in this context are "
"deprecated. The default behaviour will soon change to that implied by the "
"'-altivec-compat=xl' option">,
InGroup<DiagGroup<"deprecated-altivec-src-compat">>;
def warn_deprecated_lax_vec_conv_all : Warning<
"Implicit conversion between vector types ('%0' and '%1') is deprecated. "
"In the future, the behavior implied by '-fno-lax-vector-conversions' "
"will be the default.">,
InGroup<DiagGroup<"deprecate-lax-vec-conv-all">>;
def err_catch_incomplete_ptr : Error<
"cannot catch pointer to incomplete type %0">;
def err_catch_incomplete_ref : Error<
"cannot catch reference to incomplete type %0">;
def err_catch_incomplete : Error<"cannot catch incomplete type %0">;
def err_catch_sizeless : Error<
"cannot catch %select{|reference to }0sizeless type %1">;
def err_catch_rvalue_ref : Error<"cannot catch exceptions by rvalue reference">;
def err_catch_variably_modified : Error<
"cannot catch variably modified type %0">;
def err_qualified_catch_declarator : Error<
"exception declarator cannot be qualified">;
def err_early_catch_all : Error<"catch-all handler must come last">;
def err_bad_memptr_rhs : Error<
"right hand operand to %0 has non-pointer-to-member type %1">;
def err_bad_memptr_lhs : Error<
"left hand operand to %0 must be a %select{|pointer to }1class "
"compatible with the right hand operand, but is %2">;
def err_memptr_incomplete : Error<
"member pointer has incomplete base type %0">;
def warn_exception_caught_by_earlier_handler : Warning<
"exception of type %0 will be caught by earlier handler">,
InGroup<Exceptions>;
def note_previous_exception_handler : Note<"for type %0">;
def err_exceptions_disabled : Error<
"cannot use '%0' with exceptions disabled">;
def err_objc_exceptions_disabled : Error<
"cannot use '%0' with Objective-C exceptions disabled">;
def warn_throw_in_noexcept_func : Warning<
"%0 has a non-throwing exception specification but can still throw">,
InGroup<Exceptions>;
def note_throw_in_dtor : Note<
"%select{destructor|deallocator}0 has a %select{non-throwing|implicit "
"non-throwing}1 exception specification">;
def note_throw_in_function : Note<"function declared non-throwing here">;
def err_seh_try_outside_functions : Error<
"cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">;
def err_mixing_cxx_try_seh_try : Error<
"cannot use %select{C++ 'try'|Objective-C '@try'}0 "
"in the same function as SEH '__try'">;
def err_seh_try_unsupported : Error<
"SEH '__try' is not supported on this target">;
def note_conflicting_try_here : Note<
"conflicting %0 here">;
def warn_jump_out_of_seh_finally : Warning<
"jump out of __finally block has undefined behavior">,
InGroup<DiagGroup<"jump-seh-finally">>;
def warn_non_virtual_dtor : Warning<
"%0 has virtual functions but non-virtual destructor">,
InGroup<NonVirtualDtor>, DefaultIgnore;
def warn_delete_non_virtual_dtor : Warning<
"%select{delete|destructor}0 called on non-final %1 that has "
"virtual functions but non-virtual destructor">,
InGroup<DeleteNonAbstractNonVirtualDtor>, DefaultIgnore, ShowInSystemHeader;
def note_delete_non_virtual : Note<
"qualify call to silence this warning">;
def warn_delete_abstract_non_virtual_dtor : Warning<
"%select{delete|destructor}0 called on %1 that is abstract but has "
"non-virtual destructor">, InGroup<DeleteAbstractNonVirtualDtor>, ShowInSystemHeader;
def warn_overloaded_virtual : Warning<
"%q0 hides overloaded virtual %select{function|functions}1">,
InGroup<OverloadedVirtual>, DefaultIgnore;
def note_hidden_overloaded_virtual_declared_here : Note<
"hidden overloaded virtual function %q0 declared here"
"%select{|: different classes%diff{ ($ vs $)|}2,3"
"|: different number of parameters (%2 vs %3)"
"|: type mismatch at %ordinal2 parameter%diff{ ($ vs $)|}3,4"
"|: different return type%diff{ ($ vs $)|}2,3"
"|: different qualifiers (%2 vs %3)"
"|: different exception specifications}1">;
def warn_using_directive_in_header : Warning<
"using namespace directive in global context in header">,
InGroup<HeaderHygiene>, DefaultIgnore;
def warn_overaligned_type : Warning<
"type %0 requires %1 bytes of alignment and the default allocator only "
"guarantees %2 bytes">,
InGroup<OveralignedType>, DefaultIgnore;
def err_aligned_allocation_unavailable : Error<
"aligned %select{allocation|deallocation}0 function of type '%1' is "
"%select{only|not}4 available on %2%select{ %3 or newer|}4">;
def note_silence_aligned_allocation_unavailable : Note<
"if you supply your own aligned allocation functions, use "
"-faligned-allocation to silence this diagnostic">;
def err_conditional_void_nonvoid : Error<
"%select{left|right}1 operand to ? is void, but %select{right|left}1 operand "
"is of type %0">;
def err_conditional_ambiguous : Error<
"conditional expression is ambiguous; "
"%diff{$ can be converted to $ and vice versa|"
"types can be convert to each other}0,1">;
def err_conditional_ambiguous_ovl : Error<
"conditional expression is ambiguous; %diff{$ and $|types}0,1 "
"can be converted to several common types">;
def err_conditional_vector_size : Error<
"vector condition type %0 and result type %1 do not have the same number "
"of elements">;
def err_conditional_vector_element_size : Error<
"vector condition type %0 and result type %1 do not have elements of the "
"same size">;
def err_conditional_vector_has_void : Error<
"GNU vector conditional operand cannot be %select{void|a throw expression}0">;
def err_conditional_vector_operand_type
: Error<"enumeration type %0 is not allowed in a vector conditional">;
def err_conditional_vector_cond_result_mismatch
: Error<"cannot mix vectors and extended vectors in a vector conditional">;
def err_conditional_vector_mismatched
: Error<"vector operands to the vector conditional must be the same type "
"%diff{($ and $)|}0,1}">;
def err_throw_incomplete : Error<
"cannot throw object of incomplete type %0">;
def err_throw_incomplete_ptr : Error<
"cannot throw pointer to object of incomplete type %0">;
def err_throw_sizeless : Error<
"cannot throw object of sizeless type %0">;
def warn_throw_underaligned_obj : Warning<
"underaligned exception object thrown">,
InGroup<UnderalignedExceptionObject>;
def note_throw_underaligned_obj : Note<
"required alignment of type %0 (%1 bytes) is larger than the supported "
"alignment of C++ exception objects on this target (%2 bytes)">;
def err_return_in_constructor_handler : Error<
"return in the catch of a function try block of a constructor is illegal">;
def warn_cdtor_function_try_handler_mem_expr : Warning<
"cannot refer to a non-static member from the handler of a "
"%select{constructor|destructor}0 function try block">, InGroup<Exceptions>;
let CategoryName = "Lambda Issue" in {
def err_capture_more_than_once : Error<
"%0 can appear only once in a capture list">;
def err_reference_capture_with_reference_default : Error<
"'&' cannot precede a capture when the capture default is '&'">;
def err_copy_capture_with_copy_default : Error<
"'&' must precede a capture when the capture default is '='">;
def err_capture_does_not_name_variable : Error<
"%0 in capture list does not name a variable">;
def err_capture_non_automatic_variable : Error<
"%0 cannot be captured because it does not have automatic storage "
"duration">;
def err_this_capture : Error<
"'this' cannot be %select{implicitly |}0captured in this context">;
def note_lambda_this_capture_fixit : Note<
"explicitly capture 'this'">;
def err_lambda_capture_anonymous_var : Error<
"unnamed variable cannot be implicitly captured in a lambda expression">;
def err_lambda_capture_flexarray_type : Error<
"variable %0 with flexible array member cannot be captured in "
"a lambda expression">;
def err_lambda_impcap : Error<
"variable %0 cannot be implicitly captured in a lambda with no "
"capture-default specified">;
def note_lambda_variable_capture_fixit : Note<
"capture %0 by %select{value|reference}1">;
def note_lambda_default_capture_fixit : Note<
"default capture by %select{value|reference}0">;
def note_lambda_decl : Note<"lambda expression begins here">;
def err_lambda_unevaluated_operand : Error<
"lambda expression in an unevaluated operand">;
def err_lambda_in_constant_expression : Error<
"a lambda expression may not appear inside of a constant expression">;
def err_lambda_in_invalid_context : Error<
"a lambda expression cannot appear in this context">;
def err_lambda_return_init_list : Error<
"cannot deduce lambda return type from initializer list">;
def err_lambda_capture_default_arg : Error<
"lambda expression in default argument cannot capture any entity">;
def err_lambda_incomplete_result : Error<
"incomplete result type %0 in lambda expression">;
def err_noreturn_lambda_has_return_expr : Error<
"lambda declared 'noreturn' should not return">;
def warn_maybe_falloff_nonvoid_lambda : Warning<
"non-void lambda does not return a value in all control paths">,
InGroup<ReturnType>;
def warn_falloff_nonvoid_lambda : Warning<
"non-void lambda does not return a value">,
InGroup<ReturnType>;
def err_access_lambda_capture : Error<
// The ERRORs represent other special members that aren't constructors, in
// hopes that someone will bother noticing and reporting if they appear
"capture of variable '%0' as type %1 calls %select{private|protected}3 "
"%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}2constructor">,
AccessControl;
def note_lambda_to_block_conv : Note<
"implicit capture of lambda object due to conversion to block pointer "
"here">;
def note_var_explicitly_captured_here : Note<"variable %0 is"
"%select{| explicitly}1 captured here">;
// C++14 lambda init-captures.
def warn_cxx11_compat_init_capture : Warning<
"initialized lambda captures are incompatible with C++ standards "
"before C++14">, InGroup<CXXPre14Compat>, DefaultIgnore;
def ext_init_capture : ExtWarn<
"initialized lambda captures are a C++14 extension">, InGroup<CXX14>;
def err_init_capture_no_expression : Error<
"initializer missing for lambda capture %0">;
def err_init_capture_multiple_expressions : Error<
"initializer for lambda capture %0 contains multiple expressions">;
def err_init_capture_paren_braces : Error<
"cannot deduce type for lambda capture %1 from "
"%select{parenthesized|nested}0 initializer list">;
def err_init_capture_deduction_failure : Error<
"cannot deduce type for lambda capture %0 from initializer of type %2">;
def err_init_capture_deduction_failure_from_init_list : Error<
"cannot deduce type for lambda capture %0 from initializer list">;
def warn_cxx17_compat_init_capture_pack : Warning<
"initialized lambda capture packs are incompatible with C++ standards "
"before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
def ext_init_capture_pack : ExtWarn<
"initialized lambda pack captures are a C++20 extension">, InGroup<CXX20>;
// C++14 generic lambdas.
def warn_cxx11_compat_generic_lambda : Warning<
"generic lambdas are incompatible with C++11">,
InGroup<CXXPre14Compat>, DefaultIgnore;
// C++17 '*this' captures.
def warn_cxx14_compat_star_this_lambda_capture : Warning<
"by value capture of '*this' is incompatible with C++ standards before C++17">,
InGroup<CXXPre17Compat>, DefaultIgnore;
def ext_star_this_lambda_capture_cxx17 : ExtWarn<
"capture of '*this' by copy is a C++17 extension">, InGroup<CXX17>;
// C++17 parameter shadows capture
def err_parameter_shadow_capture : Error<
"a lambda parameter cannot shadow an explicitly captured entity">;
// C++20 [=, this] captures.
def warn_cxx17_compat_equals_this_lambda_capture : Warning<
"explicit capture of 'this' with a capture default of '=' is incompatible "
"with C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
def ext_equals_this_lambda_capture_cxx20 : ExtWarn<
"explicit capture of 'this' with a capture default of '=' "
"is a C++20 extension">, InGroup<CXX20>;
def warn_deprecated_this_capture : Warning<
"implicit capture of 'this' with a capture default of '=' is deprecated">,
InGroup<DeprecatedThisCapture>, DefaultIgnore;
def note_deprecated_this_capture : Note<
"add an explicit capture of 'this' to capture '*this' by reference">;
// C++20 default constructible / assignable lambdas.
def warn_cxx17_compat_lambda_def_ctor_assign : Warning<
"%select{default construction|assignment}0 of lambda is incompatible with "
"C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
}
def err_return_in_captured_stmt : Error<
"cannot return from %0">;
def err_capture_block_variable : Error<
"__block variable %0 cannot be captured in a "
"%select{lambda expression|captured statement}1">;
def err_operator_arrow_circular : Error<
"circular pointer delegation detected">;
def err_operator_arrow_depth_exceeded : Error<
"use of 'operator->' on type %0 would invoke a sequence of more than %1 "
"'operator->' calls">;
def note_operator_arrow_here : Note<
"'operator->' declared here produces an object of type %0">;
def note_operator_arrows_suppressed : Note<
"(skipping %0 'operator->'%s0 in backtrace)">;
def note_operator_arrow_depth : Note<
"use -foperator-arrow-depth=N to increase 'operator->' limit">;
def err_pseudo_dtor_base_not_scalar : Error<
"object expression of non-scalar type %0 cannot be used in a "
"pseudo-destructor expression">;
def ext_pseudo_dtor_on_void : ExtWarn<
"pseudo-destructors on type void are a Microsoft extension">,
InGroup<MicrosoftVoidPseudoDtor>;
def err_pseudo_dtor_type_mismatch : Error<
"the type of object expression "
"%diff{($) does not match the type being destroyed ($)|"
"does not match the type being destroyed}0,1 "
"in pseudo-destructor expression">;
def err_pseudo_dtor_call_with_args : Error<
"call to pseudo-destructor cannot have any arguments">;
def err_dtor_expr_without_call : Error<
"reference to %select{destructor|pseudo-destructor}0 must be called"
"%select{|; did you mean to call it with no arguments?}1">;
def err_pseudo_dtor_destructor_non_type : Error<
"%0 does not refer to a type name in pseudo-destructor expression; expected "
"the name of type %1">;
def err_invalid_use_of_function_type : Error<
"a function type is not allowed here">;
def err_invalid_use_of_array_type : Error<"an array type is not allowed here">;
def err_typecheck_bool_condition : Error<
"value of type %0 is not contextually convertible to 'bool'">;
def err_typecheck_ambiguous_condition : Error<
"conversion %diff{from $ to $|between types}0,1 is ambiguous">;
def err_typecheck_nonviable_condition : Error<
"no viable conversion%select{%diff{ from $ to $|}1,2|"
"%diff{ from returned value of type $ to function return type $|}1,2}0">;
def err_typecheck_nonviable_condition_incomplete : Error<
"no viable conversion%diff{ from $ to incomplete type $|}0,1">;
def err_typecheck_deleted_function : Error<
"conversion function %diff{from $ to $|between types}0,1 "
"invokes a deleted function">;
def err_expected_class_or_namespace : Error<"%0 is not a class"
"%select{ or namespace|, namespace, or enumeration}1">;
def err_invalid_declarator_scope : Error<"cannot define or redeclare %0 here "
"because namespace %1 does not enclose namespace %2">;
def err_export_non_namespace_scope_name : Error<
"cannot export %0 as it is not at namespace scope">;
def err_redeclaration_non_exported : Error <
"cannot export redeclaration %0 here since the previous declaration "
"%select{is not exported|has internal linkage|has module linkage}1">;
def err_invalid_declarator_global_scope : Error<
"definition or redeclaration of %0 cannot name the global scope">;
def err_invalid_declarator_in_function : Error<
"definition or redeclaration of %0 not allowed inside a function">;
def err_invalid_declarator_in_block : Error<
"definition or redeclaration of %0 not allowed inside a block">;
def err_not_tag_in_scope : Error<
"no %select{struct|interface|union|class|enum}0 named %1 in %2">;
def err_no_typeid_with_fno_rtti : Error<
"use of typeid requires -frtti">;
def err_no_dynamic_cast_with_fno_rtti : Error<
"use of dynamic_cast requires -frtti">;
def warn_no_dynamic_cast_with_rtti_disabled: Warning<
"dynamic_cast will not work since RTTI data is disabled by "
"%select{-fno-rtti-data|/GR-}0">, InGroup<RTTI>;
def warn_no_typeid_with_rtti_disabled: Warning<
"typeid will not work since RTTI data is disabled by "
"%select{-fno-rtti-data|/GR-}0">, InGroup<RTTI>;
def err_cannot_form_pointer_to_member_of_reference_type : Error<
"cannot form a pointer-to-member to member %0 of reference type %1">;
def err_incomplete_object_call : Error<
"incomplete type in call to object of type %0">;
def warn_condition_is_assignment : Warning<"using the result of an "
"assignment as a condition without parentheses">,
InGroup<Parentheses>;
def warn_free_nonheap_object
: Warning<"attempt to call %0 on non-heap %select{object %2|object: block expression|object: lambda-to-function-pointer conversion}1">,
InGroup<FreeNonHeapObject>;
// Completely identical except off by default.
def warn_condition_is_idiomatic_assignment : Warning<"using the result "
"of an assignment as a condition without parentheses">,
InGroup<DiagGroup<"idiomatic-parentheses">>, DefaultIgnore;
def note_condition_assign_to_comparison : Note<
"use '==' to turn this assignment into an equality comparison">;
def note_condition_or_assign_to_comparison : Note<
"use '!=' to turn this compound assignment into an inequality comparison">;
def note_condition_assign_silence : Note<
"place parentheses around the assignment to silence this warning">;
def warn_equality_with_extra_parens : Warning<"equality comparison with "
"extraneous parentheses">, InGroup<ParenthesesOnEquality>;
def note_equality_comparison_to_assign : Note<
"use '=' to turn this equality comparison into an assignment">;
def note_equality_comparison_silence : Note<
"remove extraneous parentheses around the comparison to silence this warning">;
// assignment related diagnostics (also for argument passing, returning, etc).
// In most of these diagnostics the %2 is a value from the
// Sema::AssignmentAction enumeration
def err_typecheck_convert_incompatible : Error<
"%select{%diff{assigning to $ from incompatible type $|"
"assigning to type from incompatible type}0,1"
"|%diff{passing $ to parameter of incompatible type $|"
"passing type to parameter of incompatible type}0,1"
"|%diff{returning $ from a function with incompatible result type $|"
"returning type from a function with incompatible result type}0,1"
"|%diff{converting $ to incompatible type $|"
"converting type to incompatible type}0,1"
"|%diff{initializing $ with an expression of incompatible type $|"
"initializing type with an expression of incompatible type}0,1"
"|%diff{sending $ to parameter of incompatible type $|"
"sending type to parameter of incompatible type}0,1"
"|%diff{casting $ to incompatible type $|"
"casting type to incompatible type}0,1}2"
"%select{|; dereference with *|"
"; take the address with &|"
"; remove *|"
"; remove &}3"
"%select{|: different classes%diff{ ($ vs $)|}5,6"
"|: different number of parameters (%5 vs %6)"
"|: type mismatch at %ordinal5 parameter%diff{ ($ vs $)|}6,7"
"|: different return type%diff{ ($ vs $)|}5,6"
"|: different qualifiers (%5 vs %6)"
"|: different exception specifications}4">;
def err_typecheck_missing_return_type_incompatible : Error<
"%diff{return type $ must match previous return type $|"
"return type must match previous return type}0,1 when %select{block "
"literal|lambda expression}2 has unspecified explicit return type">;
def note_incomplete_class_and_qualified_id : Note<
"conformance of forward class %0 to protocol %1 can not be confirmed">;
def warn_incompatible_qualified_id : Warning<
"%select{%diff{assigning to $ from incompatible type $|"
"assigning to type from incompatible type}0,1"
"|%diff{passing $ to parameter of incompatible type $|"
"passing type to parameter of incompatible type}0,1"
"|%diff{returning $ from a function with incompatible result type $|"
"returning type from a function with incompatible result type}0,1"
"|%diff{converting $ to incompatible type $|"
"converting type to incompatible type}0,1"
"|%diff{initializing $ with an expression of incompatible type $|"
"initializing type with an expression of incompatible type}0,1"
"|%diff{sending $ to parameter of incompatible type $|"
"sending type to parameter of incompatible type}0,1"
"|%diff{casting $ to incompatible type $|"
"casting type to incompatible type}0,1}2">;
def err_incompatible_qualified_id : Error<
"%select{%diff{assigning to $ from incompatible type $|"
"assigning to type from incompatible type}0,1"
"|%diff{passing $ to parameter of incompatible type $|"
"passing type to parameter of incompatible type}0,1"
"|%diff{returning $ from a function with incompatible result type $|"
"returning type from a function with incompatible result type}0,1"
"|%diff{converting $ to incompatible type $|"
"converting type to incompatible type}0,1"
"|%diff{initializing $ with an expression of incompatible type $|"
"initializing type with an expression of incompatible type}0,1"
"|%diff{sending $ to parameter of incompatible type $|"
"sending type to parameter of incompatible type}0,1"
"|%diff{casting $ to incompatible type $|"
"casting type to incompatible type}0,1}2">;
def err_typecheck_convert_pointer_int : Error<
"incompatible pointer to integer conversion "
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
"%select{|; dereference with *|"
"; take the address with &|"
"; remove *|"
"; remove &}3">;
def ext_typecheck_convert_pointer_int : ExtWarn<
err_typecheck_convert_pointer_int.Text>,
InGroup<IntConversion>, DefaultError;
def err_typecheck_convert_int_pointer : Error<
"incompatible integer to pointer conversion "
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
"%select{|; dereference with *|"
"; take the address with &|"
"; remove *|"
"; remove &}3">;
def ext_typecheck_convert_int_pointer : ExtWarn<
err_typecheck_convert_int_pointer.Text>,
InGroup<IntConversion>, DefaultError;
def ext_typecheck_convert_pointer_void_func : Extension<
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
" converts between void pointer and function pointer">;
def err_typecheck_convert_pointer_void_func : Error<
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
" converts between void pointer and function pointer">;
def ext_typecheck_convert_incompatible_pointer_sign : ExtWarn<
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
" converts between pointers to integer types %select{with different sign|"
"where one is of the unique plain 'char' type and the other is not}3">,
InGroup<DiagGroup<"pointer-sign">>;
def err_typecheck_convert_incompatible_pointer_sign :
Error<ext_typecheck_convert_incompatible_pointer_sign.Text>;
def ext_typecheck_convert_incompatible_pointer : ExtWarn<
"incompatible pointer types "
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
"%select{|; dereference with *|"
"; take the address with &|"
"; remove *|"
"; remove &}3">,
InGroup<IncompatiblePointerTypes>;
def err_typecheck_convert_incompatible_pointer : Error<
"incompatible pointer types "
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
"%select{|; dereference with *|"
"; take the address with &|"
"; remove *|"
"; remove &}3">;
def ext_typecheck_convert_incompatible_function_pointer : ExtWarn<
"incompatible function pointer types "
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
"%select{|; dereference with *|"
"; take the address with &|"
"; remove *|"
"; remove &}3">,
InGroup<IncompatibleFunctionPointerTypes>;
def err_typecheck_convert_incompatible_function_pointer : Error<
"incompatible function pointer types "
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
"%select{|; dereference with *|"
"; take the address with &|"
"; remove *|"
"; remove &}3">;
def ext_typecheck_convert_discards_qualifiers : ExtWarn<
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
" discards qualifiers">,
InGroup<IncompatiblePointerTypesDiscardsQualifiers>;
def err_typecheck_convert_discards_qualifiers : Error<
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
" discards qualifiers">;
def ext_nested_pointer_qualifier_mismatch : ExtWarn<
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
" discards qualifiers in nested pointer types">,
InGroup<IncompatiblePointerTypesDiscardsQualifiers>;
def err_nested_pointer_qualifier_mismatch : Error<
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
" discards qualifiers in nested pointer types">;
def warn_incompatible_vectors : Warning<
"incompatible vector types "
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2">,
InGroup<VectorConversion>, DefaultIgnore;
def err_incompatible_vectors : Error<
"incompatible vector types "
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2">;
def err_int_to_block_pointer : Error<
"invalid block pointer conversion "
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2">;
def err_typecheck_convert_incompatible_block_pointer : Error<
"incompatible block pointer types "
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2">;
def err_typecheck_incompatible_address_space : Error<
"%select{%diff{assigning $ to $|assigning to different types}1,0"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
" changes address space of pointer">;
def err_typecheck_incompatible_nested_address_space : Error<
"%select{%diff{assigning $ to $|assigning to different types}1,0"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
" changes address space of nested pointer">;
def err_typecheck_incompatible_ownership : Error<
"%select{%diff{assigning $ to $|assigning to different types}1,0"
"|%diff{passing $ to parameter of type $|"
"passing to parameter of different type}0,1"
"|%diff{returning $ from a function with result type $|"
"returning from function with different return type}0,1"
"|%diff{converting $ to type $|converting between types}0,1"
"|%diff{initializing $ with an expression of type $|"
"initializing with expression of different type}0,1"
"|%diff{sending $ to parameter of type $|"
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
" changes retain/release properties of pointer">;
def err_typecheck_comparison_of_distinct_blocks : Error<
"comparison of distinct block types%diff{ ($ and $)|}0,1">;
def err_typecheck_array_not_modifiable_lvalue : Error<
"array type %0 is not assignable">;
def err_typecheck_non_object_not_modifiable_lvalue : Error<
"non-object type %0 is not assignable">;
def err_typecheck_expression_not_modifiable_lvalue : Error<
"expression is not assignable">;
def err_typecheck_incomplete_type_not_modifiable_lvalue : Error<
"incomplete type %0 is not assignable">;
def err_typecheck_lvalue_casts_not_supported : Error<
"assignment to cast is illegal, lvalue casts are not supported">;
def err_typecheck_duplicate_vector_components_not_mlvalue : Error<
"vector is not assignable (contains duplicate components)">;
def err_block_decl_ref_not_modifiable_lvalue : Error<
"variable is not assignable (missing __block type specifier)">;
def err_lambda_decl_ref_not_modifiable_lvalue : Error<
"cannot assign to a variable captured by copy in a non-mutable lambda">;
def err_typecheck_call_not_function : Error<
"called object type %0 is not a function or function pointer">;
def err_call_incomplete_return : Error<
"calling function with incomplete return type %0">;
def err_call_function_incomplete_return : Error<
"calling %0 with incomplete return type %1">;
def err_call_incomplete_argument : Error<
"argument type %0 is incomplete">;
def err_typecheck_call_too_few_args : Error<
"too few %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"expected %1, have %2">;
def err_typecheck_call_too_few_args_one : Error<
"too few %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"single argument %1 was not specified">;
def err_typecheck_call_too_few_args_at_least : Error<
"too few %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"expected at least %1, have %2">;
def err_typecheck_call_too_few_args_at_least_one : Error<
"too few %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"at least argument %1 must be specified">;
def err_typecheck_call_too_few_args_suggest : Error<
"too few %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"expected %1, have %2; did you mean %3?">;
def err_typecheck_call_too_few_args_at_least_suggest : Error<
"too few %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"expected at least %1, have %2; did you mean %3?">;
def err_typecheck_call_too_many_args : Error<
"too many %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"expected %1, have %2">;
def err_typecheck_call_too_many_args_one : Error<
"too many %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"expected single argument %1, have %2 arguments">;
def err_typecheck_call_too_many_args_at_most : Error<
"too many %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"expected at most %1, have %2">;
def err_typecheck_call_too_many_args_at_most_one : Error<
"too many %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"expected at most single argument %1, have %2 arguments">;
def err_typecheck_call_too_many_args_suggest : Error<
"too many %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"expected %1, have %2; did you mean %3?">;
def err_typecheck_call_too_many_args_at_most_suggest : Error<
"too many %select{|||execution configuration }0arguments to "
"%select{function|block|method|kernel function}0 call, "
"expected at most %1, have %2; did you mean %3?">;
def err_arc_typecheck_convert_incompatible_pointer : Error<
"incompatible pointer types passing retainable parameter of type %0"
"to a CF function expecting %1 type">;
def err_builtin_fn_use : Error<"builtin functions must be directly called">;
def warn_call_wrong_number_of_arguments : Warning<
"too %select{few|many}0 arguments in call to %1">;
def err_atomic_builtin_must_be_pointer : Error<
"address argument to atomic builtin must be a pointer (%0 invalid)">;
def err_atomic_builtin_must_be_pointer_intptr : Error<
"address argument to atomic builtin must be a pointer to integer or pointer"
" (%0 invalid)">;
def err_atomic_builtin_cannot_be_const : Error<
"address argument to atomic builtin cannot be const-qualified (%0 invalid)">;
def err_atomic_builtin_must_be_pointer_intfltptr : Error<
"address argument to atomic builtin must be a pointer to integer,"
" floating-point or pointer (%0 invalid)">;
def err_atomic_builtin_pointer_size : Error<
"address argument to atomic builtin must be a pointer to 1,2,4,8 or 16 byte "
"type (%0 invalid)">;
def err_atomic_exclusive_builtin_pointer_size : Error<
"address argument to load or store exclusive builtin must be a pointer to"
" 1,2,4 or 8 byte type (%0 invalid)">;
def err_atomic_builtin_ext_int_size : Error<
"Atomic memory operand must have a power-of-two size">;
def err_atomic_builtin_bit_int_prohibit : Error<
"argument to atomic builtin of type '_BitInt' is not supported">;
def err_atomic_op_needs_atomic : Error<
"address argument to atomic operation must be a pointer to _Atomic "
"type (%0 invalid)">;
def err_atomic_op_needs_non_const_atomic : Error<
"address argument to atomic operation must be a pointer to non-%select{const|constant}0 _Atomic "
"type (%1 invalid)">;
def err_atomic_op_needs_non_const_pointer : Error<
"address argument to atomic operation must be a pointer to non-const "
"type (%0 invalid)">;
def err_atomic_op_needs_trivial_copy : Error<
"address argument to atomic operation must be a pointer to a "
"trivially-copyable type (%0 invalid)">;
def err_atomic_op_needs_atomic_int_ptr_or_fp : Error<
"address argument to atomic operation must be a pointer to %select{|atomic }0"
"integer, pointer or supported floating point type (%1 invalid)">;
def err_atomic_op_needs_atomic_int_or_ptr : Error<
"address argument to atomic operation must be a pointer to %select{|atomic }0"
"integer or pointer (%1 invalid)">;
def err_atomic_op_needs_atomic_int : Error<
"address argument to atomic operation must be a pointer to "
"%select{|atomic }0integer (%1 invalid)">;
def warn_atomic_op_has_invalid_memory_order : Warning<
"memory order argument to atomic operation is invalid">,
InGroup<DiagGroup<"atomic-memory-ordering">>;
def err_atomic_op_has_invalid_synch_scope : Error<
"synchronization scope argument to atomic operation is invalid">;
def warn_atomic_implicit_seq_cst : Warning<
"implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary">,
InGroup<DiagGroup<"atomic-implicit-seq-cst">>, DefaultIgnore;
def err_overflow_builtin_must_be_int : Error<
"operand argument to overflow builtin must be an integer (%0 invalid)">;
def err_overflow_builtin_must_be_ptr_int : Error<
"result argument to overflow builtin must be a pointer "
"to a non-const integer (%0 invalid)">;
def err_overflow_builtin_bit_int_max_size : Error<
"__builtin_mul_overflow does not support 'signed _BitInt' operands of more "
"than %0 bits">;
def err_expected_struct_pointer_argument : Error<
"expected pointer to struct as %ordinal0 argument to %1, found %2">;
def err_expected_callable_argument : Error<
"expected a callable expression as %ordinal0 argument to %1, found %2">;
def note_building_builtin_dump_struct_call : Note<
"in call to printing function with arguments '(%0)' while dumping struct">;
def err_atomic_load_store_uses_lib : Error<
"atomic %select{load|store}0 requires runtime support that is not "
"available for this target">;
def err_nontemporal_builtin_must_be_pointer : Error<
"address argument to nontemporal builtin must be a pointer (%0 invalid)">;
def err_nontemporal_builtin_must_be_pointer_intfltptr_or_vector : Error<
"address argument to nontemporal builtin must be a pointer to integer, float, "
"pointer, or a vector of such types (%0 invalid)">;
def err_deleted_function_use : Error<"attempt to use a deleted function">;
def err_deleted_inherited_ctor_use : Error<
"constructor inherited by %0 from base class %1 is implicitly deleted">;
def note_called_by : Note<"called by %0">;
def err_kern_type_not_void_return : Error<
"kernel function type %0 must have void return type">;
def err_kern_is_nonstatic_method : Error<
"kernel function %0 must be a free function or static member function">;
def err_config_scalar_return : Error<
"CUDA special function '%0' must have scalar return type">;
def err_kern_call_not_global_function : Error<
"kernel call to non-global function %0">;
def err_global_call_not_config : Error<
"call to global function %0 not configured">;
def err_ref_bad_target : Error<
"reference to %select{__device__|__global__|__host__|__host__ __device__}0 "
"%select{function|variable}1 %2 in %select{__device__|__global__|__host__|__host__ __device__}3 function">;
def note_cuda_const_var_unpromoted : Note<
"const variable cannot be emitted on device side due to dynamic initialization">;
def note_cuda_host_var : Note<
"host variable declared here">;
def err_ref_bad_target_global_initializer : Error<
"reference to %select{__device__|__global__|__host__|__host__ __device__}0 "
"function %1 in global initializer">;
def err_capture_bad_target : Error<
"capture host variable %0 by reference in device or host device lambda function">;
def warn_maybe_capture_bad_target_this_ptr : Warning<
"capture host side class data member by this pointer in device or host device lambda function "
"may result in invalid memory access if this pointer is not accessible on device side">,
InGroup<DiagGroup<"gpu-maybe-wrong-side">>;
def warn_kern_is_method : Extension<
"kernel function %0 is a member function; this may not be accepted by nvcc">,
InGroup<CudaCompat>;
def warn_kern_is_inline : Warning<
"ignored 'inline' attribute on kernel function %0">,
InGroup<CudaCompat>;
def err_variadic_device_fn : Error<
"CUDA device code does not support variadic functions">;
def err_va_arg_in_device : Error<
"CUDA device code does not support va_arg">;
def err_alias_not_supported_on_nvptx : Error<"CUDA does not support aliases">;
def err_cuda_unattributed_constexpr_cannot_overload_device : Error<
"constexpr function %0 without __host__ or __device__ attributes cannot "
"overload __device__ function with same signature. Add a __host__ "
"attribute, or build with -fno-cuda-host-device-constexpr.">;
def note_cuda_conflicting_device_function_declared_here : Note<
"conflicting __device__ function declared here">;
def err_cuda_device_exceptions : Error<
"cannot use '%0' in "
"%select{__device__|__global__|__host__|__host__ __device__}1 function">;
def err_dynamic_var_init : Error<
"dynamic initialization is not supported for "
"__device__, __constant__, __shared__, and __managed__ variables.">;
def err_shared_var_init : Error<
"initialization is not supported for __shared__ variables.">;
def err_cuda_vla : Error<
"cannot use variable-length arrays in "
"%select{__device__|__global__|__host__|__host__ __device__}0 functions">;
def err_cuda_extern_shared : Error<"__shared__ variable %0 cannot be 'extern'">;
def err_cuda_host_shared : Error<
"__shared__ local variables not allowed in "
"%select{__device__|__global__|__host__|__host__ __device__}0 functions">;
def err_cuda_nonstatic_constdev: Error<"__constant__, __device__, and "
"__managed__ are not allowed on non-static local variables">;
def err_cuda_ovl_target : Error<
"%select{__device__|__global__|__host__|__host__ __device__}0 function %1 "
"cannot overload %select{__device__|__global__|__host__|__host__ __device__}2 function %3">;
def note_cuda_ovl_candidate_target_mismatch : Note<
"candidate template ignored: target attributes do not match">;
def err_cuda_device_builtin_surftex_cls_template : Error<
"illegal device builtin %select{surface|texture}0 reference "
"class template %1 declared here">;
def note_cuda_device_builtin_surftex_cls_should_have_n_args : Note<
"%0 needs to have exactly %1 template parameters">;
def note_cuda_device_builtin_surftex_cls_should_have_match_arg : Note<
"the %select{1st|2nd|3rd}1 template parameter of %0 needs to be "
"%select{a type|an integer or enum value}2">;
def err_cuda_device_builtin_surftex_ref_decl : Error<
"illegal device builtin %select{surface|texture}0 reference "
"type %1 declared here">;
def note_cuda_device_builtin_surftex_should_be_template_class : Note<
"%0 needs to be instantiated from a class template with proper "
"template arguments">;
def err_hip_invalid_args_builtin_mangled_name : Error<
"invalid argument: symbol must be a device-side function or global variable">;
def warn_non_pod_vararg_with_format_string : Warning<
"cannot pass %select{non-POD|non-trivial}0 object of type %1 to variadic "
"%select{function|block|method|constructor}2; expected type from format "
"string was %3">, InGroup<NonPODVarargs>, DefaultError;
// The arguments to this diagnostic should match the warning above.
def err_cannot_pass_objc_interface_to_vararg_format : Error<
"cannot pass object with interface type %1 by value to variadic "
"%select{function|block|method|constructor}2; expected type from format "
"string was %3">;
def err_cannot_pass_non_trivial_c_struct_to_vararg : Error<
"cannot pass non-trivial C object of type %0 by value to variadic "
"%select{function|block|method|constructor}1">;
def err_cannot_pass_objc_interface_to_vararg : Error<
"cannot pass object with interface type %0 by value through variadic "
"%select{function|block|method|constructor}1">;
def warn_cannot_pass_non_pod_arg_to_vararg : Warning<
"cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic"
" %select{function|block|method|constructor}2; call will abort at runtime">,
InGroup<NonPODVarargs>, DefaultError;
def warn_cxx98_compat_pass_non_pod_arg_to_vararg : Warning<
"passing object of trivial but non-POD type %0 through variadic"
" %select{function|block|method|constructor}1 is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def warn_pass_class_arg_to_vararg : Warning<
"passing object of class type %0 through variadic "
"%select{function|block|method|constructor}1"
"%select{|; did you mean to call '%3'?}2">,
InGroup<ClassVarargs>, DefaultIgnore;
def err_cannot_pass_to_vararg : Error<
"cannot pass %select{expression of type %1|initializer list}0 to variadic "
"%select{function|block|method|constructor}2">;
def err_cannot_pass_to_vararg_format : Error<
"cannot pass %select{expression of type %1|initializer list}0 to variadic "
"%select{function|block|method|constructor}2; expected type from format "
"string was %3">;
def err_typecheck_call_invalid_ordered_compare : Error<
"ordered compare requires two args of floating point type"
"%diff{ ($ and $)|}0,1">;
def err_typecheck_call_invalid_unary_fp : Error<
"floating point classification requires argument of floating point type "
"(passed in %0)">;
def err_typecheck_cond_expect_int_float : Error<
"used type %0 where integer or floating point type is required">;
def err_typecheck_cond_expect_scalar : Error<
"used type %0 where arithmetic or pointer type is required">;
def err_typecheck_cond_expect_nonfloat : Error<
"used type %0 where floating point type is not allowed">;
def ext_typecheck_cond_one_void : Extension<
"C99 forbids conditional expressions with only one void side">;
def err_typecheck_cast_to_incomplete : Error<
"cast to incomplete type %0">;
def ext_typecheck_cast_nonscalar : Extension<
"C99 forbids casting nonscalar type %0 to the same type">;
def ext_typecheck_cast_to_union : Extension<
"cast to union type is a GNU extension">,
InGroup<GNUUnionCast>;
def err_typecheck_cast_to_union_no_type : Error<
"cast to union type from type %0 not present in union">;
def err_cast_pointer_from_non_pointer_int : Error<
"operand of type %0 cannot be cast to a pointer type">;
def warn_cast_pointer_from_sel : Warning<
"cast of type %0 to %1 is deprecated; use sel_getName instead">,
InGroup<SelTypeCast>;
def warn_function_def_in_objc_container : Warning<
"function definition inside an Objective-C container is deprecated">,
InGroup<FunctionDefInObjCContainer>;
def err_typecheck_call_requires_real_fp : Error<
"argument type %0 is not a real floating point type">;
def err_typecheck_call_different_arg_types : Error<
"arguments are of different types%diff{ ($ vs $)|}0,1">;
def warn_cast_calling_conv : Warning<
"cast between incompatible calling conventions '%0' and '%1'; "
"calls through this pointer may abort at runtime">,
InGroup<DiagGroup<"cast-calling-convention">>;
def note_change_calling_conv_fixit : Note<
"consider defining %0 with the '%1' calling convention">;
def warn_bad_function_cast : Warning<
"cast from function call of type %0 to non-matching type %1">,
InGroup<BadFunctionCast>, DefaultIgnore;
def warn_cast_function_type : Warning<
"cast %diff{from $ to $ |}0,1converts to incompatible function type">,
InGroup<CastFunctionType>, DefaultIgnore;
def err_cast_pointer_to_non_pointer_int : Error<
"pointer cannot be cast to type %0">;
def err_cast_to_bfloat16 : Error<"cannot type-cast to __bf16">;
def err_cast_from_bfloat16 : Error<"cannot type-cast from __bf16">;
def err_typecheck_expect_scalar_operand : Error<
"operand of type %0 where arithmetic or pointer type is required">;
def err_typecheck_cond_incompatible_operands : Error<
"incompatible operand types%diff{ ($ and $)|}0,1">;
def err_typecheck_expect_flt_or_vector : Error<
"invalid operand of type %0 where floating, complex or "
"a vector of such types is required">;
def err_cast_selector_expr : Error<
"cannot type cast @selector expression">;
def ext_typecheck_cond_incompatible_pointers : ExtWarn<
"pointer type mismatch%diff{ ($ and $)|}0,1">,
InGroup<DiagGroup<"pointer-type-mismatch">>;
def ext_typecheck_cond_pointer_integer_mismatch : ExtWarn<
"pointer/integer type mismatch in conditional expression"
"%diff{ ($ and $)|}0,1">,
InGroup<DiagGroup<"conditional-type-mismatch">>;
def err_typecheck_choose_expr_requires_constant : Error<
"'__builtin_choose_expr' requires a constant expression">;
def warn_unused_expr : Warning<"expression result unused">,
InGroup<UnusedValue>;
def warn_unused_comma_left_operand : Warning<
"left operand of comma operator has no effect">,
InGroup<UnusedValue>;
def warn_unused_voidptr : Warning<
"expression result unused; should this cast be to 'void'?">,
InGroup<UnusedValue>;
def warn_unused_property_expr : Warning<
"property access result unused - getters should not be used for side effects">,
InGroup<UnusedGetterReturnValue>;
def warn_unused_container_subscript_expr : Warning<
"container access result unused - container access should not be used for side effects">,
InGroup<UnusedValue>;
def warn_unused_call : Warning<
"ignoring return value of function declared with %0 attribute">,
InGroup<UnusedValue>;
def warn_unused_constructor : Warning<
"ignoring temporary created by a constructor declared with %0 attribute">,
InGroup<UnusedValue>;
def warn_unused_constructor_msg : Warning<
"ignoring temporary created by a constructor declared with %0 attribute: %1">,
InGroup<UnusedValue>;
def warn_side_effects_unevaluated_context : Warning<
"expression with side effects has no effect in an unevaluated context">,
InGroup<UnevaluatedExpression>;
def warn_side_effects_typeid : Warning<
"expression with side effects will be evaluated despite being used as an "
"operand to 'typeid'">, InGroup<PotentiallyEvaluatedExpression>;
def warn_unused_result : Warning<
"ignoring return value of function declared with %0 attribute">,
InGroup<UnusedResult>;
def warn_unused_result_msg : Warning<
"ignoring return value of function declared with %0 attribute: %1">,
InGroup<UnusedResult>;
def warn_unused_result_typedef_unsupported_spelling : Warning<
"'[[%select{nodiscard|gnu::warn_unused_result}0]]' attribute ignored when "
"applied to a typedef; consider using '__attribute__((warn_unused_result))' "
"or '[[clang::warn_unused_result]]' instead">, InGroup<IgnoredAttributes>;
def warn_unused_volatile : Warning<
"expression result unused; assign into a variable to force a volatile load">,
InGroup<DiagGroup<"unused-volatile-lvalue">>;
def ext_cxx14_attr : Extension<
"use of the %0 attribute is a C++14 extension">, InGroup<CXX14Attrs>;
def ext_cxx17_attr : Extension<
"use of the %0 attribute is a C++17 extension">, InGroup<CXX17Attrs>;
def ext_cxx20_attr : Extension<
"use of the %0 attribute is a C++20 extension">, InGroup<CXX20Attrs>;
def warn_unused_comparison : Warning<
"%select{equality|inequality|relational|three-way}0 comparison result unused">,
InGroup<UnusedComparison>;
def note_inequality_comparison_to_or_assign : Note<
"use '|=' to turn this inequality comparison into an or-assignment">;
def err_incomplete_type_used_in_type_trait_expr : Error<
"incomplete type %0 used in type trait expression">;
// C++20 constinit and require_constant_initialization attribute
def warn_cxx20_compat_constinit : Warning<
"'constinit' specifier is incompatible with C++ standards before C++20">,
InGroup<CXX20Compat>, DefaultIgnore;
def err_constinit_local_variable : Error<
"local variable cannot be declared 'constinit'">;
def err_require_constant_init_failed : Error<
"variable does not have a constant initializer">;
def note_declared_required_constant_init_here : Note<
"required by %select{'require_constant_initialization' attribute|"
"'constinit' specifier}0 here">;
def ext_constinit_missing : ExtWarn<
"'constinit' specifier missing on initializing declaration of %0">,
InGroup<DiagGroup<"missing-constinit">>;
def note_constinit_specified_here : Note<"variable declared constinit here">;
def err_constinit_added_too_late : Error<
"'constinit' specifier added after initialization of variable">;
def warn_require_const_init_added_too_late : Warning<
"'require_constant_initialization' attribute added after initialization "
"of variable">, InGroup<IgnoredAttributes>;
def note_constinit_missing_here : Note<
"add the "
"%select{'require_constant_initialization' attribute|'constinit' specifier}0 "
"to the initializing declaration here">;
def err_dimension_expr_not_constant_integer : Error<
"dimension expression does not evaluate to a constant unsigned int">;
def err_typecheck_cond_incompatible_operands_null : Error<
"non-pointer operand type %0 incompatible with %select{NULL|nullptr}1">;
def ext_empty_struct_union : Extension<
"empty %select{struct|union}0 is a GNU extension">, InGroup<GNUEmptyStruct>;
def ext_no_named_members_in_struct_union : Extension<
"%select{struct|union}0 without named members is a GNU extension">, InGroup<GNUEmptyStruct>;
def warn_zero_size_struct_union_compat : Warning<"%select{|empty }0"
"%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">,
InGroup<CXXCompat>, DefaultIgnore;
def warn_zero_size_struct_union_in_extern_c : Warning<"%select{|empty }0"
"%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">,
InGroup<ExternCCompat>;
def warn_cast_qual : Warning<"cast from %0 to %1 drops %select{const and "
"volatile qualifiers|const qualifier|volatile qualifier}2">,
InGroup<CastQual>, DefaultIgnore;
def warn_cast_qual2 : Warning<"cast from %0 to %1 must have all intermediate "
"pointers const qualified to be safe">, InGroup<CastQual>, DefaultIgnore;
def warn_redefine_extname_not_applied : Warning<
"#pragma redefine_extname is applicable to external C declarations only; "
"not applied to %select{function|variable}0 %1">,
InGroup<Pragmas>;
} // End of general sema category.
// inline asm.
let CategoryName = "Inline Assembly Issue" in {
def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">;
def err_asm_invalid_output_constraint : Error<
"invalid output constraint '%0' in asm">;
def err_asm_invalid_lvalue_in_input : Error<
"invalid lvalue in asm input for constraint '%0'">;
def err_asm_invalid_input_constraint : Error<
"invalid input constraint '%0' in asm">;
def err_asm_tying_incompatible_types : Error<
"unsupported inline asm: input with type "
"%diff{$ matching output with type $|}0,1">;
def err_asm_unexpected_constraint_alternatives : Error<
"asm constraint has an unexpected number of alternatives: %0 vs %1">;
def err_asm_incomplete_type : Error<"asm operand has incomplete type %0">;
def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">;
def err_asm_unwind_and_goto : Error<"unwind clobber can't be used with asm goto">;
def err_asm_invalid_global_var_reg : Error<"register '%0' unsuitable for "
"global register variables on this target">;
def err_asm_register_size_mismatch : Error<"size of register '%0' does not "
"match variable size">;
def err_asm_bad_register_type : Error<"bad type for named register variable">;
def err_asm_invalid_input_size : Error<
"invalid input size for constraint '%0'">;
def err_asm_invalid_output_size : Error<
"invalid output size for constraint '%0'">;
def err_invalid_asm_cast_lvalue : Error<
"invalid use of a cast in a inline asm context requiring an lvalue: "
"remove the cast or build with -fheinous-gnu-extensions">;
def err_invalid_asm_value_for_constraint
: Error <"value '%0' out of range for constraint '%1'">;
def err_asm_non_addr_value_in_memory_constraint : Error <
"reference to a %select{bit-field|vector element|global register variable}0"
" in asm %select{input|output}1 with a memory constraint '%2'">;
def err_asm_input_duplicate_match : Error<
"more than one input constraint matches the same output '%0'">;
def err_store_value_to_reg : Error<
"impossible constraint in asm: can't store value into a register">;
def warn_asm_label_on_auto_decl : Warning<
"ignored asm label '%0' on automatic variable">;
def warn_invalid_asm_cast_lvalue : Warning<
"invalid use of a cast in an inline asm context requiring an lvalue: "
"accepted due to -fheinous-gnu-extensions, but clang may remove support "
"for this in the future">;
def warn_asm_mismatched_size_modifier : Warning<
"value size does not match register size specified by the constraint "
"and modifier">,
InGroup<ASMOperandWidths>;
def note_asm_missing_constraint_modifier : Note<
"use constraint modifier \"%0\"">;
def note_asm_input_duplicate_first : Note<
"constraint '%0' is already present here">;
def error_duplicate_asm_operand_name : Error<
"duplicate use of asm operand name \"%0\"">;
def note_duplicate_asm_operand_name : Note<
"asm operand name \"%0\" first referenced here">;
}
def error_inoutput_conflict_with_clobber : Error<
"asm-specifier for input or output variable conflicts with asm"
" clobber list">;
let CategoryName = "Semantic Issue" in {
def err_invalid_conversion_between_matrixes : Error<
"conversion between matrix types%diff{ $ and $|}0,1 of different size is not allowed">;
def err_invalid_conversion_between_matrix_and_type : Error<
"conversion between matrix type %0 and incompatible type %1 is not allowed">;
def err_invalid_conversion_between_vectors : Error<
"invalid conversion between vector type%diff{ $ and $|}0,1 of different "
"size">;
def err_invalid_conversion_between_vector_and_integer : Error<
"invalid conversion between vector type %0 and integer type %1 "
"of different size">;
def err_opencl_function_pointer : Error<
"%select{pointers|references}0 to functions are not allowed">;
def err_opencl_taking_address_capture : Error<
"taking address of a capture is not allowed">;
def err_invalid_conversion_between_vector_and_scalar : Error<
"invalid conversion between vector type %0 and scalar type %1">;
// C++ member initializers.
def err_only_constructors_take_base_inits : Error<
"only constructors take base initializers">;
def err_multiple_mem_initialization : Error <
"multiple initializations given for non-static member %0">;
def err_multiple_mem_union_initialization : Error <
"initializing multiple members of union">;
def err_multiple_base_initialization : Error <
"multiple initializations given for base %0">;
def err_mem_init_not_member_or_class : Error<
"member initializer %0 does not name a non-static data member or base "
"class">;
def warn_initializer_out_of_order : Warning<
"%select{field|base class}0 %1 will be initialized after "
"%select{field|base}2 %3">,
InGroup<ReorderCtor>, DefaultIgnore;
def warn_some_initializers_out_of_order : Warning<
"initializer order does not match the declaration order">,
InGroup<ReorderCtor>, DefaultIgnore;
def note_initializer_out_of_order : Note<
"%select{field|base class}0 %1 will be initialized after "
"%select{field|base}2 %3">;
def warn_abstract_vbase_init_ignored : Warning<
"initializer for virtual base class %0 of abstract class %1 "
"will never be used">,
InGroup<DiagGroup<"abstract-vbase-init">>, DefaultIgnore;
def err_base_init_does_not_name_class : Error<
"constructor initializer %0 does not name a class">;
def err_base_init_direct_and_virtual : Error<
"base class initializer %0 names both a direct base class and an "
"inherited virtual base class">;
def err_not_direct_base_or_virtual : Error<
"type %0 is not a direct or virtual base of %1">;
def err_in_class_initializer_non_const : Error<
"non-const static data member must be initialized out of line">;
def err_in_class_initializer_volatile : Error<
"static const volatile data member must be initialized out of line">;
def err_in_class_initializer_bad_type : Error<
"static data member of type %0 must be initialized out of line">;
def ext_in_class_initializer_float_type : ExtWarn<
"in-class initializer for static data member of type %0 is a GNU extension">,
InGroup<GNUStaticFloatInit>;
def ext_in_class_initializer_float_type_cxx11 : ExtWarn<
"in-class initializer for static data member of type %0 requires "
"'constexpr' specifier">, InGroup<StaticFloatInit>, DefaultError;
def note_in_class_initializer_float_type_cxx11 : Note<"add 'constexpr'">;
def err_in_class_initializer_literal_type : Error<
"in-class initializer for static data member of type %0 requires "
"'constexpr' specifier">;
def err_in_class_initializer_non_constant : Error<
"in-class initializer for static data member is not a constant expression">;
def err_default_member_initializer_not_yet_parsed : Error<
"default member initializer for %1 needed within definition of enclosing "
"class %0 outside of member functions">;
def note_default_member_initializer_not_yet_parsed : Note<
"default member initializer declared here">;
def err_default_member_initializer_cycle
: Error<"default member initializer for %0 uses itself">;
def ext_in_class_initializer_non_constant : Extension<
"in-class initializer for static data member is not a constant expression; "
"folding it to a constant is a GNU extension">, InGroup<GNUFoldingConstant>;
def err_thread_dynamic_init : Error<
"initializer for thread-local variable must be a constant expression">;
def err_thread_nontrivial_dtor : Error<
"type of thread-local variable has non-trivial destruction">;
def note_use_thread_local : Note<
"use 'thread_local' to allow this">;
// C++ anonymous unions and GNU anonymous structs/unions
def ext_anonymous_union : Extension<
"anonymous unions are a C11 extension">, InGroup<C11>;
def ext_gnu_anonymous_struct : Extension<
"anonymous structs are a GNU extension">, InGroup<GNUAnonymousStruct>;
def ext_c11_anonymous_struct : Extension<
"anonymous structs are a C11 extension">, InGroup<C11>;
def err_anonymous_union_not_static : Error<
"anonymous unions at namespace or global scope must be declared 'static'">;
def err_anonymous_union_with_storage_spec : Error<
"anonymous union at class scope must not have a storage specifier">;
def err_anonymous_struct_not_member : Error<
"anonymous %select{structs|structs and classes}0 must be "
"%select{struct or union|class}0 members">;
def err_anonymous_record_member_redecl : Error<
"member of anonymous %select{struct|union}0 redeclares %1">;
def err_anonymous_record_with_type : Error<
"types cannot be declared in an anonymous %select{struct|union}0">;
def ext_anonymous_record_with_type : Extension<
"types declared in an anonymous %select{struct|union}0 are a Microsoft "
"extension">, InGroup<MicrosoftAnonTag>;
def ext_anonymous_record_with_anonymous_type : Extension<
"anonymous types declared in an anonymous %select{struct|union}0 "
"are an extension">, InGroup<DiagGroup<"nested-anon-types">>;
def err_anonymous_record_with_function : Error<
"functions cannot be declared in an anonymous %select{struct|union}0">;
def err_anonymous_record_with_static : Error<
"static members cannot be declared in an anonymous %select{struct|union}0">;
def err_anonymous_record_bad_member : Error<
"anonymous %select{struct|union}0 can only contain non-static data members">;
def err_anonymous_record_nonpublic_member : Error<
"anonymous %select{struct|union}0 cannot contain a "
"%select{private|protected}1 data member">;
def ext_ms_anonymous_record : ExtWarn<
"anonymous %select{structs|unions}0 are a Microsoft extension">,
InGroup<MicrosoftAnonTag>;
// C++ local classes
def err_reference_to_local_in_enclosing_context : Error<
"reference to local %select{variable|binding}1 %0 declared in enclosing "
"%select{%3|block literal|lambda expression|context}2">;
def err_static_data_member_not_allowed_in_local_class : Error<
"static data member %0 not allowed in local %sub{select_tag_type_kind}2 %1">;
// C++ derived classes
def err_base_clause_on_union : Error<"unions cannot have base classes">;
def err_base_must_be_class : Error<"base specifier must name a class">;
def err_union_as_base_class : Error<"unions cannot be base classes">;
def err_circular_inheritance : Error<
"circular inheritance between %0 and %1">;
def err_base_class_has_flexible_array_member : Error<
"base class %0 has a flexible array member">;
def err_incomplete_base_class : Error<"base class has incomplete type">;
def err_duplicate_base_class : Error<
"base class %0 specified more than once as a direct base class">;
def warn_inaccessible_base_class : Warning<
"direct base %0 is inaccessible due to ambiguity:%1">,
InGroup<DiagGroup<"inaccessible-base">>;
// FIXME: better way to display derivation? Pass entire thing into diagclient?
def err_ambiguous_derived_to_base_conv : Error<
"ambiguous conversion from derived class %0 to base class %1:%2">;
def err_ambiguous_memptr_conv : Error<
"ambiguous conversion from pointer to member of %select{base|derived}0 "
"class %1 to pointer to member of %select{derived|base}0 class %2:%3">;
def ext_ms_ambiguous_direct_base : ExtWarn<
"accessing inaccessible direct base %0 of %1 is a Microsoft extension">,
InGroup<MicrosoftInaccessibleBase>;
def err_memptr_conv_via_virtual : Error<
"conversion from pointer to member of class %0 to pointer to member "
"of class %1 via virtual base %2 is not allowed">;
// C++ member name lookup
def err_ambiguous_member_multiple_subobjects : Error<
"non-static member %0 found in multiple base-class subobjects of type %1:%2">;
def err_ambiguous_member_multiple_subobject_types : Error<
"member %0 found in multiple base classes of different types">;
def note_ambiguous_member_found : Note<"member found by ambiguous name lookup">;
def note_ambiguous_member_type_found : Note<
"member type %0 found by ambiguous name lookup">;
def err_ambiguous_reference : Error<"reference to %0 is ambiguous">;
def note_ambiguous_candidate : Note<"candidate found by name lookup is %q0">;
def err_ambiguous_tag_hiding : Error<"a type named %0 is hidden by a "
"declaration in a different namespace">;
def note_hidden_tag : Note<"type declaration hidden">;
def note_hiding_object : Note<"declaration hides type">;
// C++ operator overloading
def err_operator_overload_needs_class_or_enum : Error<
"overloaded %0 must have at least one parameter of class "
"or enumeration type">;
def err_operator_overload_variadic : Error<"overloaded %0 cannot be variadic">;
def err_operator_overload_static : Error<
"overloaded %0 cannot be a static member function">;
def err_operator_overload_default_arg : Error<
"parameter of overloaded %0 cannot have a default argument">;
def ext_subscript_overload : ExtWarn<
"overloaded %0 with %select{no|a defaulted|more than one}1 parameter is a C++2b extension">, InGroup<CXXPre2bCompat>, DefaultIgnore;
def error_subscript_overload : Error<
"overloaded %0 cannot have %select{no|a defaulted|more than one}1 parameter before C++2b">;
def err_operator_overload_must_be : Error<
"overloaded %0 must be a %select{unary|binary|unary or binary}2 operator "
"(has %1 parameter%s1)">;
def err_operator_overload_must_be_member : Error<
"overloaded %0 must be a non-static member function">;
def err_operator_overload_post_incdec_must_be_int : Error<
"parameter of overloaded post-%select{increment|decrement}1 operator must "
"have type 'int' (not %0)">;
// C++ allocation and deallocation functions.
def err_operator_new_delete_declared_in_namespace : Error<
"%0 cannot be declared inside a namespace">;
def err_operator_new_delete_declared_static : Error<
"%0 cannot be declared static in global scope">;
def ext_operator_new_delete_declared_inline : ExtWarn<
"replacement function %0 cannot be declared 'inline'">,
InGroup<DiagGroup<"inline-new-delete">>;
def err_operator_new_delete_invalid_result_type : Error<
"%0 must return type %1">;
def err_operator_new_delete_dependent_result_type : Error<
"%0 cannot have a dependent return type; use %1 instead">;
def err_operator_new_delete_too_few_parameters : Error<
"%0 must have at least one parameter">;
def err_operator_new_delete_template_too_few_parameters : Error<
"%0 template must have at least two parameters">;
def warn_operator_new_returns_null : Warning<
"%0 should not return a null pointer unless it is declared 'throw()'"
"%select{| or 'noexcept'}1">, InGroup<OperatorNewReturnsNull>;
def err_operator_new_dependent_param_type : Error<
"%0 cannot take a dependent type as first parameter; "
"use size_t (%1) instead">;
def err_operator_new_param_type : Error<
"%0 takes type size_t (%1) as first parameter">;
def err_operator_new_default_arg: Error<
"parameter of %0 cannot have a default argument">;
def err_operator_delete_dependent_param_type : Error<
"%0 cannot take a dependent type as first parameter; use %1 instead">;
def err_operator_delete_param_type : Error<
"first parameter of %0 must have type %1">;
def err_destroying_operator_delete_not_usual : Error<
"destroying operator delete can have only an optional size and optional "
"alignment parameter">;
def note_implicit_delete_this_in_destructor_here : Note<
"while checking implicit 'delete this' for virtual destructor">;
def err_builtin_operator_new_delete_not_usual : Error<
"call to '%select{__builtin_operator_new|__builtin_operator_delete}0' "
"selects non-usual %select{allocation|deallocation}0 function">;
def note_non_usual_function_declared_here : Note<
"non-usual %0 declared here">;
// C++ literal operators
def err_literal_operator_outside_namespace : Error<
"literal operator %0 must be in a namespace or global scope">;
def err_literal_operator_id_outside_namespace : Error<
"non-namespace scope '%0' cannot have a literal operator member">;
def err_literal_operator_default_argument : Error<
"literal operator cannot have a default argument">;
def err_literal_operator_bad_param_count : Error<
"non-template literal operator must have one or two parameters">;
def err_literal_operator_invalid_param : Error<
"parameter of literal operator must have type 'unsigned long long', 'long double', 'char', 'wchar_t', 'char16_t', 'char32_t', or 'const char *'">;
def err_literal_operator_param : Error<
"invalid literal operator parameter type %0, did you mean %1?">;
def err_literal_operator_template_with_params : Error<
"literal operator template cannot have any parameters">;
def err_literal_operator_template : Error<
"template parameter list for literal operator must be either 'char...' or 'typename T, T...'">;
def err_literal_operator_extern_c : Error<
"literal operator must have C++ linkage">;
def ext_string_literal_operator_template : ExtWarn<
"string literal operator templates are a GNU extension">,
InGroup<GNUStringLiteralOperatorTemplate>;
def warn_user_literal_reserved : Warning<
"user-defined literal suffixes not starting with '_' are reserved"
"%select{; no literal will invoke this operator|}0">,
InGroup<UserDefinedLiterals>;
// C++ conversion functions
def err_conv_function_not_member : Error<
"conversion function must be a non-static member function">;
def err_conv_function_return_type : Error<
"conversion function cannot have a return type">;
def err_conv_function_with_params : Error<
"conversion function cannot have any parameters">;
def err_conv_function_variadic : Error<
"conversion function cannot be variadic">;
def err_conv_function_to_array : Error<
"conversion function cannot convert to an array type">;
def err_conv_function_to_function : Error<
"conversion function cannot convert to a function type">;
def err_conv_function_with_complex_decl : Error<
"cannot specify any part of a return type in the "
"declaration of a conversion function"
"%select{"
"; put the complete type after 'operator'|"
"; use a typedef to declare a conversion to %1|"
"; use an alias template to declare a conversion to %1|"
"}0">;
def err_conv_function_redeclared : Error<
"conversion function cannot be redeclared">;
def warn_conv_to_self_not_used : Warning<
"conversion function converting %0 to itself will never be used">,
InGroup<ClassConversion>;
def warn_conv_to_base_not_used : Warning<
"conversion function converting %0 to its base class %1 will never be used">,
InGroup<ClassConversion>;
def warn_conv_to_void_not_used : Warning<
"conversion function converting %0 to %1 will never be used">,
InGroup<ClassConversion>;
def warn_not_compound_assign : Warning<
"use of unary operator that may be intended as compound assignment (%0=)">;
// C++11 explicit conversion operators
def ext_explicit_conversion_functions : ExtWarn<
"explicit conversion functions are a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_explicit_conversion_functions : Warning<
"explicit conversion functions are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
// C++11 defaulted functions
def err_defaulted_special_member_params : Error<
"an explicitly-defaulted %select{|copy |move }0constructor cannot "
"have default arguments">;
def err_defaulted_special_member_variadic : Error<
"an explicitly-defaulted %select{|copy |move }0constructor cannot "
"be variadic">;
def err_defaulted_special_member_return_type : Error<
"explicitly-defaulted %select{copy|move}0 assignment operator must "
"return %1">;
def err_defaulted_special_member_quals : Error<
"an explicitly-defaulted %select{copy|move}0 assignment operator may not "
"have 'const'%select{, 'constexpr'|}1 or 'volatile' qualifiers">;
def err_defaulted_special_member_volatile_param : Error<
"the parameter for an explicitly-defaulted %sub{select_special_member_kind}0 "
"may not be volatile">;
def err_defaulted_special_member_move_const_param : Error<
"the parameter for an explicitly-defaulted move "
"%select{constructor|assignment operator}0 may not be const">;
def err_defaulted_special_member_copy_const_param : Error<
"the parameter for this explicitly-defaulted copy "
"%select{constructor|assignment operator}0 is const, but a member or base "
"requires it to be non-const">;
def err_defaulted_copy_assign_not_ref : Error<
"the parameter for an explicitly-defaulted copy assignment operator must be an "
"lvalue reference type">;
def err_incorrect_defaulted_constexpr : Error<
"defaulted definition of %sub{select_special_member_kind}0 "
"is not constexpr">;
def err_incorrect_defaulted_consteval : Error<
"defaulted declaration of %sub{select_special_member_kind}0 "
"cannot be consteval because implicit definition is not constexpr">;
def warn_defaulted_method_deleted : Warning<
"explicitly defaulted %sub{select_special_member_kind}0 is implicitly "
"deleted">, InGroup<DefaultedFunctionDeleted>;
def err_out_of_line_default_deletes : Error<
"defaulting this %sub{select_special_member_kind}0 "
"would delete it after its first declaration">;
def note_deleted_type_mismatch : Note<
"function is implicitly deleted because its declared type does not match "
"the type of an implicit %sub{select_special_member_kind}0">;
def warn_cxx17_compat_defaulted_method_type_mismatch : Warning<
"explicitly defaulting this %sub{select_special_member_kind}0 with a type "
"different from the implicit type is incompatible with C++ standards before "
"C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
def warn_vbase_moved_multiple_times : Warning<
"defaulted move assignment operator of %0 will move assign virtual base "
"class %1 multiple times">, InGroup<DiagGroup<"multiple-move-vbase">>;
def note_vbase_moved_here : Note<
"%select{%1 is a virtual base class of base class %2 declared here|"
"virtual base class %1 declared here}0">;
// C++20 defaulted comparisons
// This corresponds to values of Sema::DefaultedComparisonKind.
def select_defaulted_comparison_kind : TextSubstitution<
"%select{<ERROR>|equality|three-way|equality|relational}0 comparison "
"operator">;
def ext_defaulted_comparison : ExtWarn<
"defaulted comparison operators are a C++20 extension">, InGroup<CXX20>;
def warn_cxx17_compat_defaulted_comparison : Warning<
"defaulted comparison operators are incompatible with C++ standards "
"before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
def err_defaulted_comparison_template : Error<
"comparison operator template cannot be defaulted">;
def err_defaulted_comparison_num_args : Error<
"%select{non-member|member}0 %sub{select_defaulted_comparison_kind}1"
" comparison operator must have %select{2|1}0 parameters">;
def err_defaulted_comparison_param : Error<
"invalid parameter type for defaulted %sub{select_defaulted_comparison_kind}0"
"; found %1, expected %2%select{| or %4}3">;
def err_defaulted_comparison_param_unknown : Error<
"invalid parameter type for non-member defaulted"
" %sub{select_defaulted_comparison_kind}0"
"; found %1, expected class or reference to a constant class">;
def err_defaulted_comparison_param_mismatch : Error<
"parameters for defaulted %sub{select_defaulted_comparison_kind}0 "
"must have the same type%diff{ (found $ vs $)|}1,2">;
def err_defaulted_comparison_not_friend : Error<
"%sub{select_defaulted_comparison_kind}0 is not a friend of"
" %select{|incomplete class }1%2">;
def err_defaulted_comparison_non_const : Error<
"defaulted member %sub{select_defaulted_comparison_kind}0 must be "
"const-qualified">;
def err_defaulted_comparison_return_type_not_bool : Error<
"return type for defaulted %sub{select_defaulted_comparison_kind}0 "
"must be 'bool', not %1">;
def err_defaulted_comparison_deduced_return_type_not_auto : Error<
"deduced return type for defaulted %sub{select_defaulted_comparison_kind}0 "
"must be 'auto', not %1">;
def warn_defaulted_comparison_deleted : Warning<
"explicitly defaulted %sub{select_defaulted_comparison_kind}0 is implicitly "
"deleted">, InGroup<DefaultedFunctionDeleted>;
def err_non_first_default_compare_deletes : Error<
"defaulting %select{this %sub{select_defaulted_comparison_kind}1|"
"the corresponding implicit 'operator==' for this defaulted 'operator<=>'}0 "
"would delete it after its first declaration">;
def note_defaulted_comparison_union : Note<
"defaulted %0 is implicitly deleted because "
"%2 is a %select{union-like class|union}1 with variant members">;
def note_defaulted_comparison_reference_member : Note<
"defaulted %0 is implicitly deleted because "
"class %1 has a reference member">;
def note_defaulted_comparison_ambiguous : Note<
"defaulted %0 is implicitly deleted because implied %select{|'==' |'<' }1"
"comparison %select{|for member %3 |for base class %3 }2is ambiguous">;
def note_defaulted_comparison_inaccessible : Note<
"defaulted %0 is implicitly deleted because it would invoke a "
"%select{private|protected}3 %4%select{ member of %6|"
" member of %6 to compare member %2| to compare base class %2}1">;
def note_defaulted_comparison_calls_deleted : Note<
"defaulted %0 is implicitly deleted because it would invoke a deleted "
"comparison function%select{| for member %2| for base class %2}1">;
def note_defaulted_comparison_no_viable_function : Note<
"defaulted %0 is implicitly deleted because there is no viable "
"%select{three-way comparison function|'operator=='}1 for "
"%select{|member |base class }2%3">;
def note_defaulted_comparison_no_viable_function_synthesized : Note<
"three-way comparison cannot be synthesized because there is no viable "
"function for %select{'=='|'<'}0 comparison">;
def note_defaulted_comparison_not_rewritten_callee : Note<
"defaulted %0 is implicitly deleted because this non-rewritten comparison "
"function would be the best match for the comparison">;
def note_defaulted_comparison_not_rewritten_conversion : Note<
"defaulted %0 is implicitly deleted because a builtin comparison function "
"using this conversion would be the best match for the comparison">;
def note_defaulted_comparison_cannot_deduce : Note<
"return type of defaulted 'operator<=>' cannot be deduced because "
"return type %2 of three-way comparison for %select{|member|base class}0 %1 "
"is not a standard comparison category type">;
def err_defaulted_comparison_cannot_deduce_undeduced_auto : Error<
"return type of defaulted 'operator<=>' cannot be deduced because "
"three-way comparison for %select{|member|base class}0 %1 "
"has a deduced return type and is not yet defined">;
def note_defaulted_comparison_cannot_deduce_undeduced_auto : Note<
"%select{|member|base class}0 %1 declared here">;
def note_defaulted_comparison_cannot_deduce_callee : Note<
"selected 'operator<=>' for %select{|member|base class}0 %1 declared here">;
def err_incorrect_defaulted_comparison_constexpr : Error<
"defaulted definition of %select{%sub{select_defaulted_comparison_kind}1|"
"three-way comparison operator}0 "
"cannot be declared %select{constexpr|consteval}2 because "
"%select{it|the corresponding implicit 'operator=='}0 "
"invokes a non-constexpr comparison function">;
def note_defaulted_comparison_not_constexpr : Note<
"non-constexpr comparison function would be used to compare "
"%select{|member %1|base class %1}0">;
def note_defaulted_comparison_not_constexpr_here : Note<
"non-constexpr comparison function declared here">;
def note_in_declaration_of_implicit_equality_comparison : Note<
"while declaring the corresponding implicit 'operator==' "
"for this defaulted 'operator<=>'">;
def ext_implicit_exception_spec_mismatch : ExtWarn<
"function previously declared with an %select{explicit|implicit}0 exception "
"specification redeclared with an %select{implicit|explicit}0 exception "
"specification">, InGroup<DiagGroup<"implicit-exception-spec-mismatch">>;
def warn_ptr_arith_precedes_bounds : Warning<
"the pointer decremented by %0 refers before the beginning of the array">,
InGroup<ArrayBoundsPointerArithmetic>, DefaultIgnore;
def warn_ptr_arith_exceeds_bounds : Warning<
"the pointer incremented by %0 refers past the end of the array (that "
"contains %1 element%s2)">,
InGroup<ArrayBoundsPointerArithmetic>, DefaultIgnore;
def warn_array_index_precedes_bounds : Warning<
"array index %0 is before the beginning of the array">,
InGroup<ArrayBounds>;
def warn_array_index_exceeds_bounds : Warning<
"array index %0 is past the end of the array (which contains %1 "
"element%s2)">, InGroup<ArrayBounds>;
def warn_ptr_arith_exceeds_max_addressable_bounds : Warning<
"the pointer incremented by %0 refers past the last possible element for an array in %1-bit "
"address space containing %2-bit (%3-byte) elements (max possible %4 element%s5)">,
InGroup<ArrayBounds>;
def warn_array_index_exceeds_max_addressable_bounds : Warning<
"array index %0 refers past the last possible element for an array in %1-bit "
"address space containing %2-bit (%3-byte) elements (max possible %4 element%s5)">,
InGroup<ArrayBounds>;
def note_array_declared_here : Note<
"array %0 declared here">;
def warn_inconsistent_array_form : Warning<
"argument %0 of type %1 with mismatched bound">,
InGroup<ArrayParameter>, DefaultIgnore;
def note_previous_declaration_as : Note<
"previously declared as %0 here">;
def warn_printf_insufficient_data_args : Warning<
"more '%%' conversions than data arguments">, InGroup<FormatInsufficientArgs>;
def warn_printf_data_arg_not_used : Warning<
"data argument not used by format string">, InGroup<FormatExtraArgs>;
def warn_format_invalid_conversion : Warning<
"invalid conversion specifier '%0'">, InGroup<FormatInvalidSpecifier>;
def warn_printf_incomplete_specifier : Warning<
"incomplete format specifier">, InGroup<Format>;
def warn_missing_format_string : Warning<
"format string missing">, InGroup<Format>;
def warn_scanf_nonzero_width : Warning<
"zero field width in scanf format string is unused">,
InGroup<Format>;
def warn_format_conversion_argument_type_mismatch : Warning<
"format specifies type %0 but the argument has "
"%select{type|underlying type}2 %1">,
InGroup<Format>;
def warn_format_conversion_argument_type_mismatch_pedantic : Extension<
warn_format_conversion_argument_type_mismatch.Text>,
InGroup<FormatPedantic>;
def warn_format_conversion_argument_type_mismatch_confusion : Warning<
warn_format_conversion_argument_type_mismatch.Text>,
InGroup<FormatTypeConfusion>, DefaultIgnore;
def warn_format_argument_needs_cast : Warning<
"%select{values of type|enum values with underlying type}2 '%0' should not "
"be used as format arguments; add an explicit cast to %1 instead">,
InGroup<Format>;
def warn_format_argument_needs_cast_pedantic : Warning<
warn_format_argument_needs_cast.Text>,
InGroup<FormatPedantic>, DefaultIgnore;
def warn_printf_positional_arg_exceeds_data_args : Warning <
"data argument position '%0' exceeds the number of data arguments (%1)">,
InGroup<Format>;
def warn_format_zero_positional_specifier : Warning<
"position arguments in format strings start counting at 1 (not 0)">,
InGroup<Format>;
def warn_format_invalid_positional_specifier : Warning<
"invalid position specified for %select{field width|field precision}0">,
InGroup<Format>;
def warn_format_mix_positional_nonpositional_args : Warning<
"cannot mix positional and non-positional arguments in format string">,
InGroup<Format>;
def warn_static_array_too_small : Warning<
"array argument is too small; %select{contains %0 elements|is of size %0}2,"
" callee requires at least %1">,
InGroup<ArrayBounds>;
def note_callee_static_array : Note<
"callee declares array parameter as static here">;
def warn_empty_format_string : Warning<
"format string is empty">, InGroup<FormatZeroLength>;
def warn_format_string_is_wide_literal : Warning<
"format string should not be a wide string">, InGroup<Format>;
def warn_printf_format_string_contains_null_char : Warning<
"format string contains '\\0' within the string body">, InGroup<Format>;
def warn_printf_format_string_not_null_terminated : Warning<
"format string is not null-terminated">, InGroup<Format>;
def warn_printf_asterisk_missing_arg : Warning<
"'%select{*|.*}0' specified field %select{width|precision}0 is missing a matching 'int' argument">,
InGroup<Format>;
def warn_printf_asterisk_wrong_type : Warning<
"field %select{width|precision}0 should have type %1, but argument has type %2">,
InGroup<Format>;
def warn_printf_nonsensical_optional_amount: Warning<
"%select{field width|precision}0 used with '%1' conversion specifier, resulting in undefined behavior">,
InGroup<Format>;
def warn_printf_nonsensical_flag: Warning<
"flag '%0' results in undefined behavior with '%1' conversion specifier">,
InGroup<Format>;
def warn_format_nonsensical_length: Warning<
"length modifier '%0' results in undefined behavior or no effect with '%1' conversion specifier">,
InGroup<Format>;
def warn_format_non_standard_positional_arg: Warning<
"positional arguments are not supported by ISO C">, InGroup<FormatNonStandard>, DefaultIgnore;
def warn_format_non_standard: Warning<
"'%0' %select{length modifier|conversion specifier}1 is not supported by ISO C">,
InGroup<FormatNonStandard>, DefaultIgnore;
def warn_format_non_standard_conversion_spec: Warning<
"using length modifier '%0' with conversion specifier '%1' is not supported by ISO C">,
InGroup<FormatNonStandard>, DefaultIgnore;
def err_invalid_mask_type_size : Error<
"mask type size must be between 1-byte and 8-bytes">;
def warn_format_invalid_annotation : Warning<
"using '%0' format specifier annotation outside of os_log()/os_trace()">,
InGroup<Format>;
def warn_format_P_no_precision : Warning<
"using '%%P' format specifier without precision">,
InGroup<Format>;
def warn_printf_ignored_flag: Warning<
"flag '%0' is ignored when flag '%1' is present">,
InGroup<Format>;
def warn_printf_empty_objc_flag: Warning<
"missing object format flag">,
InGroup<Format>;
def warn_printf_ObjCflags_without_ObjCConversion: Warning<
"object format flags cannot be used with '%0' conversion specifier">,
InGroup<Format>;
def warn_printf_invalid_objc_flag: Warning<
"'%0' is not a valid object format flag">,
InGroup<Format>;
def warn_printf_narg_not_supported : Warning<
"'%%n' specifier not supported on this platform">,
InGroup<Format>;
def warn_scanf_scanlist_incomplete : Warning<
"no closing ']' for '%%[' in scanf format string">,
InGroup<Format>;
def warn_format_bool_as_character : Warning<
"using '%0' format specifier, but argument has boolean value">,
InGroup<Format>;
def note_format_string_defined : Note<"format string is defined here">;
def note_format_fix_specifier : Note<"did you mean to use '%0'?">;
def note_printf_c_str: Note<"did you mean to call the %0 method?">;
def note_format_security_fixit: Note<
"treat the string as an argument to avoid this">;
def warn_null_arg : Warning<
"null passed to a callee that requires a non-null argument">,
InGroup<NonNull>;
def warn_null_ret : Warning<
"null returned from %select{function|method}0 that requires a non-null return value">,
InGroup<NonNull>;
def err_lifetimebound_no_object_param : Error<
"'lifetimebound' attribute cannot be applied; %select{static |non-}0member "
"function has no implicit object parameter">;
def err_lifetimebound_ctor_dtor : Error<
"'lifetimebound' attribute cannot be applied to a "
"%select{constructor|destructor}0">;
// CHECK: returning address/reference of stack memory
def warn_ret_stack_addr_ref : Warning<
"%select{address of|reference to}0 stack memory associated with "
"%select{local variable|parameter}2 %1 returned">,
InGroup<ReturnStackAddress>;
def warn_ret_local_temp_addr_ref : Warning<
"returning %select{address of|reference to}0 local temporary object">,
InGroup<ReturnStackAddress>;
def warn_ret_addr_label : Warning<
"returning address of label, which is local">,
InGroup<ReturnStackAddress>;
def err_ret_local_block : Error<
"returning block that lives on the local stack">;
def note_local_var_initializer : Note<
"%select{via initialization of|binding reference}0 variable "
"%select{%2 |}1here">;
def note_lambda_capture_initializer : Note<
"%select{implicitly |}2captured%select{| by reference}3"
"%select{%select{ due to use|}2 here|"
" via initialization of lambda capture %0}1">;
def note_init_with_default_member_initalizer : Note<
"initializing field %0 with default member initializer">;
// Check for initializing a member variable with the address or a reference to
// a constructor parameter.
def warn_bind_ref_member_to_parameter : Warning<
"binding reference member %0 to stack allocated "
"%select{variable|parameter}2 %1">, InGroup<DanglingField>;
def warn_init_ptr_member_to_parameter_addr : Warning<
"initializing pointer member %0 with the stack address of "
"%select{variable|parameter}2 %1">, InGroup<DanglingField>;
def note_ref_or_ptr_member_declared_here : Note<
"%select{reference|pointer}0 member declared here">;
def err_dangling_member : Error<
"%select{reference|backing array for 'std::initializer_list'}2 "
"%select{|subobject of }1member %0 "
"%select{binds to|is}2 a temporary object "
"whose lifetime would be shorter than the lifetime of "
"the constructed object">;
def warn_dangling_member : Warning<
"%select{reference|backing array for 'std::initializer_list'}2 "
"%select{|subobject of }1member %0 "
"%select{binds to|is}2 a temporary object "
"whose lifetime is shorter than the lifetime of the constructed object">,
InGroup<DanglingField>;
def warn_dangling_lifetime_pointer_member : Warning<
"initializing pointer member %0 to point to a temporary object "
"whose lifetime is shorter than the lifetime of the constructed object">,
InGroup<DanglingGsl>;
def note_lifetime_extending_member_declared_here : Note<
"%select{%select{reference|'std::initializer_list'}0 member|"
"member with %select{reference|'std::initializer_list'}0 subobject}1 "
"declared here">;
def warn_dangling_variable : Warning<
"%select{temporary %select{whose address is used as value of|"
"%select{|implicitly }2bound to}4 "
"%select{%select{|reference }4member of local variable|"
"local %select{variable|reference}4}1|"
"array backing "
"%select{initializer list subobject of local variable|"
"local initializer list}1}0 "
"%select{%3 |}2will be destroyed at the end of the full-expression">,
InGroup<Dangling>;
def warn_new_dangling_reference : Warning<
"temporary bound to reference member of allocated object "
"will be destroyed at the end of the full-expression">,
InGroup<DanglingField>;
def warn_dangling_lifetime_pointer : Warning<
"object backing the pointer "
"will be destroyed at the end of the full-expression">,
InGroup<DanglingGsl>;
def warn_new_dangling_initializer_list : Warning<
"array backing "
"%select{initializer list subobject of the allocated object|"
"the allocated initializer list}0 "
"will be destroyed at the end of the full-expression">,
InGroup<DanglingInitializerList>;
def warn_unsupported_lifetime_extension : Warning<
"sorry, lifetime extension of "
"%select{temporary|backing array of initializer list}0 created "
"by aggregate initialization using default member initializer "
"is not supported; lifetime of %select{temporary|backing array}0 "
"will end at the end of the full-expression">, InGroup<Dangling>;
// For non-floating point, expressions of the form x == x or x != x
// should result in a warning, since these always evaluate to a constant.
// Array comparisons have similar warnings
def warn_comparison_always : Warning<
"%select{self-|array }0comparison always evaluates to "
"%select{a constant|true|false|'std::strong_ordering::equal'}1">,
InGroup<TautologicalCompare>;
def warn_comparison_bitwise_always : Warning<
"bitwise comparison always evaluates to %select{false|true}0">,
InGroup<TautologicalBitwiseCompare>, DefaultIgnore;
def warn_comparison_bitwise_or : Warning<
"bitwise or with non-zero value always evaluates to true">,
InGroup<TautologicalBitwiseCompare>, DefaultIgnore;
def warn_tautological_overlap_comparison : Warning<
"overlapping comparisons always evaluate to %select{false|true}0">,
InGroup<TautologicalOverlapCompare>, DefaultIgnore;
def warn_depr_array_comparison : Warning<
"comparison between two arrays is deprecated; "
"to compare array addresses, use unary '+' to decay operands to pointers">,
InGroup<DeprecatedArrayCompare>;
def warn_stringcompare : Warning<
"result of comparison against %select{a string literal|@encode}0 is "
"unspecified (use an explicit string comparison function instead)">,
InGroup<StringCompare>;
def warn_identity_field_assign : Warning<
"assigning %select{field|instance variable}0 to itself">,
InGroup<SelfAssignmentField>;
// Type safety attributes
def err_type_tag_for_datatype_not_ice : Error<
"'type_tag_for_datatype' attribute requires the initializer to be "
"an %select{integer|integral}0 constant expression">;
def err_type_tag_for_datatype_too_large : Error<
"'type_tag_for_datatype' attribute requires the initializer to be "
"an %select{integer|integral}0 constant expression "
"that can be represented by a 64 bit integer">;
def err_tag_index_out_of_range : Error<
"%select{type tag|argument}0 index %1 is greater than the number of arguments specified">;
def warn_type_tag_for_datatype_wrong_kind : Warning<
"this type tag was not designed to be used with this function">,
InGroup<TypeSafety>;
def warn_type_safety_type_mismatch : Warning<
"argument type %0 doesn't match specified %1 type tag "
"%select{that requires %3|}2">, InGroup<TypeSafety>;
def warn_type_safety_null_pointer_required : Warning<
"specified %0 type tag requires a null pointer">, InGroup<TypeSafety>;
// Generic selections.
def err_assoc_type_incomplete : Error<
"type %0 in generic association incomplete">;
def err_assoc_type_nonobject : Error<
"type %0 in generic association not an object type">;
def err_assoc_type_variably_modified : Error<
"type %0 in generic association is a variably modified type">;
def err_assoc_compatible_types : Error<
"type %0 in generic association compatible with previously specified type %1">;
def note_compat_assoc : Note<
"compatible type %0 specified here">;
def err_generic_sel_no_match : Error<
"controlling expression type %0 not compatible with any generic association type">;
def err_generic_sel_multi_match : Error<
"controlling expression type %0 compatible with %1 generic association types">;
// Blocks
def err_blocks_disable : Error<"blocks support disabled - compile with -fblocks"
" or %select{pick a deployment target that supports them|for OpenCL C 2.0"
" or OpenCL C 3.0 with __opencl_c_device_enqueue feature}0">;
def err_block_returning_array_function : Error<
"block cannot return %select{array|function}0 type %1">;
// Builtin annotation
def err_builtin_annotation_first_arg : Error<
"first argument to __builtin_annotation must be an integer">;
def err_builtin_annotation_second_arg : Error<
"second argument to __builtin_annotation must be a non-wide string constant">;
def err_msvc_annotation_wide_str : Error<
"arguments to __annotation must be wide string constants">;
// CFString checking
def err_cfstring_literal_not_string_constant : Error<
"CFString literal is not a string constant">;
def warn_cfstring_truncated : Warning<
"input conversion stopped due to an input byte that does not "
"belong to the input codeset UTF-8">,
InGroup<DiagGroup<"CFString-literal">>;
// os_log checking
// TODO: separate diagnostic for os_trace()
def err_os_log_format_not_string_constant : Error<
"os_log() format argument is not a string constant">;
def err_os_log_argument_too_big : Error<
"os_log() argument %0 is too big (%1 bytes, max %2)">;
def warn_os_log_format_narg : Error<
"os_log() '%%n' format specifier is not allowed">, DefaultError;
// Statements.
def err_continue_not_in_loop : Error<
"'continue' statement not in loop statement">;
def err_break_not_in_loop_or_switch : Error<
"'break' statement not in loop or switch statement">;
def warn_loop_ctrl_binds_to_inner : Warning<
"'%0' is bound to current loop, GCC binds it to the enclosing loop">,
InGroup<GccCompat>;
def warn_break_binds_to_switch : Warning<
"'break' is bound to loop, GCC binds it to switch">,
InGroup<GccCompat>;
def err_default_not_in_switch : Error<
"'default' statement not in switch statement">;
def err_case_not_in_switch : Error<"'case' statement not in switch statement">;
def warn_bool_switch_condition : Warning<
"switch condition has boolean value">, InGroup<SwitchBool>;
def warn_case_value_overflow : Warning<
"overflow converting case value to switch condition type (%0 to %1)">,
InGroup<Switch>;
def err_duplicate_case : Error<"duplicate case value '%0'">;
def err_duplicate_case_differing_expr : Error<
"duplicate case value: '%0' and '%1' both equal '%2'">;
def warn_case_empty_range : Warning<"empty case range specified">;
def warn_missing_case_for_condition :
Warning<"no case matching constant switch condition '%0'">;
def warn_def_missing_case : Warning<"%plural{"
"1:enumeration value %1 not explicitly handled in switch|"
"2:enumeration values %1 and %2 not explicitly handled in switch|"
"3:enumeration values %1, %2, and %3 not explicitly handled in switch|"
":%0 enumeration values not explicitly handled in switch: %1, %2, %3...}0">,
InGroup<SwitchEnum>, DefaultIgnore;
def warn_missing_case : Warning<"%plural{"
"1:enumeration value %1 not handled in switch|"
"2:enumeration values %1 and %2 not handled in switch|"
"3:enumeration values %1, %2, and %3 not handled in switch|"
":%0 enumeration values not handled in switch: %1, %2, %3...}0">,
InGroup<Switch>;
def warn_unannotated_fallthrough : Warning<
"unannotated fall-through between switch labels">,
InGroup<ImplicitFallthrough>, DefaultIgnore;
def warn_unannotated_fallthrough_per_function : Warning<
"unannotated fall-through between switch labels in partly-annotated "
"function">, InGroup<ImplicitFallthroughPerFunction>, DefaultIgnore;
def note_insert_fallthrough_fixit : Note<
"insert '%0;' to silence this warning">;
def note_insert_break_fixit : Note<
"insert 'break;' to avoid fall-through">;
def err_fallthrough_attr_wrong_target : Error<
"%0 attribute is only allowed on empty statements">;
def note_fallthrough_insert_semi_fixit : Note<"did you forget ';'?">;
def err_fallthrough_attr_outside_switch : Error<
"fallthrough annotation is outside switch statement">;
def err_fallthrough_attr_invalid_placement : Error<
"fallthrough annotation does not directly precede switch label">;
def warn_unreachable_default : Warning<
"default label in switch which covers all enumeration values">,
InGroup<CoveredSwitchDefault>, DefaultIgnore;
def warn_not_in_enum : Warning<"case value not in enumerated type %0">,
InGroup<Switch>;
def warn_not_in_enum_assignment : Warning<"integer constant not in range "
"of enumerated type %0">, InGroup<DiagGroup<"assign-enum">>, DefaultIgnore;
def err_typecheck_statement_requires_scalar : Error<
"statement requires expression of scalar type (%0 invalid)">;
def err_typecheck_statement_requires_integer : Error<
"statement requires expression of integer type (%0 invalid)">;
def err_multiple_default_labels_defined : Error<
"multiple default labels in one switch">;
def err_switch_multiple_conversions : Error<
"multiple conversions from switch condition type %0 to an integral or "
"enumeration type">;
def note_switch_conversion : Note<
"conversion to %select{integral|enumeration}0 type %1">;
def err_switch_explicit_conversion : Error<
"switch condition type %0 requires explicit conversion to %1">;
def err_switch_incomplete_class_type : Error<
"switch condition has incomplete class type %0">;
def warn_empty_if_body : Warning<
"if statement has empty body">, InGroup<EmptyBody>;
def warn_empty_for_body : Warning<
"for loop has empty body">, InGroup<EmptyBody>;
def warn_empty_range_based_for_body : Warning<
"range-based for loop has empty body">, InGroup<EmptyBody>;
def warn_empty_while_body : Warning<
"while loop has empty body">, InGroup<EmptyBody>;
def warn_empty_switch_body : Warning<
"switch statement has empty body">, InGroup<EmptyBody>;
def note_empty_body_on_separate_line : Note<
"put the semicolon on a separate line to silence this warning">;
def err_va_start_captured_stmt : Error<
"'va_start' cannot be used in a captured statement">;
def err_va_start_outside_function : Error<
"'va_start' cannot be used outside a function">;
def err_va_start_fixed_function : Error<
"'va_start' used in function with fixed args">;
def err_va_start_used_in_wrong_abi_function : Error<
"'va_start' used in %select{System V|Win64}0 ABI function">;
def err_ms_va_start_used_in_sysv_function : Error<
"'__builtin_ms_va_start' used in System V ABI function">;
def warn_second_arg_of_va_start_not_last_named_param : Warning<
"second argument to 'va_start' is not the last named parameter">,
InGroup<Varargs>;
def warn_va_start_type_is_undefined : Warning<
"passing %select{an object that undergoes default argument promotion|"
"an object of reference type|a parameter declared with the 'register' "
"keyword}0 to 'va_start' has undefined behavior">, InGroup<Varargs>;
def err_first_argument_to_va_arg_not_of_type_va_list : Error<
"first argument to 'va_arg' is of type %0 and not 'va_list'">;
def err_second_parameter_to_va_arg_incomplete: Error<
"second argument to 'va_arg' is of incomplete type %0">;
def err_second_parameter_to_va_arg_abstract: Error<
"second argument to 'va_arg' is of abstract type %0">;
def warn_second_parameter_to_va_arg_not_pod : Warning<
"second argument to 'va_arg' is of non-POD type %0">,
InGroup<NonPODVarargs>, DefaultError;
def warn_second_parameter_to_va_arg_ownership_qualified : Warning<
"second argument to 'va_arg' is of ARC ownership-qualified type %0">,
InGroup<NonPODVarargs>, DefaultError;
def warn_second_parameter_to_va_arg_never_compatible : Warning<
"second argument to 'va_arg' is of promotable type %0; this va_arg has "
"undefined behavior because arguments will be promoted to %1">, InGroup<Varargs>;
def warn_return_missing_expr : Warning<
"non-void %select{function|method}1 %0 should return a value">, DefaultError,
InGroup<ReturnType>;
def ext_return_missing_expr : ExtWarn<
"non-void %select{function|method}1 %0 should return a value">, DefaultError,
InGroup<ReturnType>;
def ext_return_has_expr : ExtWarn<
"%select{void function|void method|constructor|destructor}1 %0 "
"should not return a value">,
DefaultError, InGroup<ReturnType>;
def ext_return_has_void_expr : Extension<
"void %select{function|method|block}1 %0 should not return void expression">;
def err_return_init_list : Error<
"%select{void function|void method|constructor|destructor}1 %0 "
"must not return a value">;
def err_ctor_dtor_returns_void : Error<
"%select{constructor|destructor}1 %0 must not return void expression">;
def warn_noreturn_function_has_return_expr : Warning<
"function %0 declared 'noreturn' should not return">,
InGroup<InvalidNoreturn>;
def warn_falloff_noreturn_function : Warning<
"function declared 'noreturn' should not return">,
InGroup<InvalidNoreturn>;
def err_noreturn_block_has_return_expr : Error<
"block declared 'noreturn' should not return">;
def err_carries_dependency_missing_on_first_decl : Error<
"%select{function|parameter}0 declared '[[carries_dependency]]' "
"after its first declaration">;
def note_carries_dependency_missing_first_decl : Note<
"declaration missing '[[carries_dependency]]' attribute is here">;
def err_carries_dependency_param_not_function_decl : Error<
"'[[carries_dependency]]' attribute only allowed on parameter in a function "
"declaration or lambda">;
def err_block_on_nonlocal : Error<
"__block attribute not allowed, only allowed on local variables">;
def err_block_on_vm : Error<
"__block attribute not allowed on declaration with a variably modified type">;
def err_sizeless_nonlocal : Error<
"non-local variable with sizeless type %0">;
def err_vec_builtin_non_vector : Error<
"first two arguments to %0 must be vectors">;
def err_vec_builtin_incompatible_vector : Error<
"first two arguments to %0 must have the same type">;
def err_vsx_builtin_nonconstant_argument : Error<
"argument %0 to %1 must be a 2-bit unsigned literal (i.e. 0, 1, 2 or 3)">;
def err_shufflevector_nonconstant_argument : Error<
"index for __builtin_shufflevector must be a constant integer">;
def err_shufflevector_argument_too_large : Error<
"index for __builtin_shufflevector must be less than the total number "
"of vector elements">;
def err_convertvector_non_vector : Error<
"first argument to __builtin_convertvector must be a vector">;
def err_convertvector_non_vector_type : Error<
"second argument to __builtin_convertvector must be a vector type">;
def err_convertvector_incompatible_vector : Error<
"first two arguments to __builtin_convertvector must have the same number of elements">;
def err_first_argument_to_cwsc_not_call : Error<
"first argument to __builtin_call_with_static_chain must be a non-member call expression">;
def err_first_argument_to_cwsc_block_call : Error<
"first argument to __builtin_call_with_static_chain must not be a block call">;
def err_first_argument_to_cwsc_builtin_call : Error<
"first argument to __builtin_call_with_static_chain must not be a builtin call">;
def err_first_argument_to_cwsc_pdtor_call : Error<
"first argument to __builtin_call_with_static_chain must not be a pseudo-destructor call">;
def err_second_argument_to_cwsc_not_pointer : Error<
"second argument to __builtin_call_with_static_chain must be of pointer type">;
def err_vector_incorrect_num_initializers : Error<
"%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">;
def err_altivec_empty_initializer : Error<"expected initializer">;
def err_invalid_neon_type_code : Error<
"incompatible constant for this __builtin_neon function">;
def err_argument_invalid_range : Error<
"argument value %0 is outside the valid range [%1, %2]">;
def warn_argument_invalid_range : Warning<
"argument value %0 is outside the valid range [%1, %2]">, DefaultError,
InGroup<DiagGroup<"argument-outside-range">>;
def warn_argument_undefined_behaviour : Warning<
"argument value %0 will result in undefined behaviour">,
InGroup<DiagGroup<"argument-undefined-behaviour">>;
def err_argument_not_multiple : Error<
"argument should be a multiple of %0">;
def err_argument_not_power_of_2 : Error<
"argument should be a power of 2">;
def err_argument_not_shifted_byte : Error<
"argument should be an 8-bit value shifted by a multiple of 8 bits">;
def err_argument_not_shifted_byte_or_xxff : Error<
"argument should be an 8-bit value shifted by a multiple of 8 bits, or in the form 0x??FF">;
def err_argument_not_contiguous_bit_field : Error<
"argument %0 value should represent a contiguous bit field">;
def err_rotation_argument_to_cadd
: Error<"argument should be the value 90 or 270">;
def err_rotation_argument_to_cmla
: Error<"argument should be the value 0, 90, 180 or 270">;
def warn_neon_vector_initializer_non_portable : Warning<
"vector initializers are not compatible with NEON intrinsics in big endian "
"mode">, InGroup<DiagGroup<"nonportable-vector-initialization">>;
def note_neon_vector_initializer_non_portable : Note<
"consider using vld1_%0%1() to initialize a vector from memory, or "
"vcreate_%0%1() to initialize from an integer constant">;
def note_neon_vector_initializer_non_portable_q : Note<
"consider using vld1q_%0%1() to initialize a vector from memory, or "
"vcombine_%0%1(vcreate_%0%1(), vcreate_%0%1()) to initialize from integer "
"constants">;
def err_systemz_invalid_tabort_code : Error<
"invalid transaction abort code">;
def err_64_bit_builtin_32_bit_tgt : Error<
"this builtin is only available on 64-bit targets">;
def err_32_bit_builtin_64_bit_tgt : Error<
"this builtin is only available on 32-bit targets">;
def err_builtin_x64_aarch64_only : Error<
"this builtin is only available on x86-64 and aarch64 targets">;
def err_mips_builtin_requires_dsp : Error<
"this builtin requires 'dsp' ASE, please use -mdsp">;
def err_mips_builtin_requires_dspr2 : Error<
"this builtin requires 'dsp r2' ASE, please use -mdspr2">;
def err_mips_builtin_requires_msa : Error<
"this builtin requires 'msa' ASE, please use -mmsa">;
def err_ppc_builtin_only_on_arch : Error<
"this builtin is only valid on POWER%0 or later CPUs">;
def err_ppc_builtin_requires_vsx : Error<
"this builtin requires VSX to be enabled">;
def err_ppc_builtin_requires_htm : Error<
"this builtin requires HTM to be enabled">;
def err_ppc_builtin_requires_abi : Error<
"this builtin requires ABI -mabi=%0">;
def err_ppc_invalid_use_mma_type : Error<
"invalid use of PPC MMA type">;
def err_ppc_invalid_test_data_class_type : Error<
"expected a 'float' or 'double' for the first argument">;
def err_x86_builtin_invalid_rounding : Error<
"invalid rounding argument">;
def err_x86_builtin_invalid_scale : Error<
"scale argument must be 1, 2, 4, or 8">;
def err_x86_builtin_tile_arg_duplicate : Error<
"tile arguments must refer to different tiles">;
def err_builtin_target_unsupported : Error<
"builtin is not supported on this target">;
def err_builtin_longjmp_unsupported : Error<
"__builtin_longjmp is not supported for the current target">;
def err_builtin_setjmp_unsupported : Error<
"__builtin_setjmp is not supported for the current target">;
def err_builtin_longjmp_invalid_val : Error<
"argument to __builtin_longjmp must be a constant 1">;
def err_builtin_requires_language : Error<"'%0' is only available in %1">;
def err_constant_integer_arg_type : Error<
"argument to %0 must be a constant integer">;
def ext_mixed_decls_code : Extension<
"mixing declarations and code is a C99 extension">,
InGroup<DeclarationAfterStatement>;
def warn_mixed_decls_code : Warning<
"mixing declarations and code is incompatible with standards before C99">,
InGroup<DeclarationAfterStatement>, DefaultIgnore;
def err_non_local_variable_decl_in_for : Error<
"declaration of non-local variable in 'for' loop">;
def err_non_variable_decl_in_for : Error<
"non-variable declaration in 'for' loop">;
def err_toomany_element_decls : Error<
"only one element declaration is allowed">;
def err_selector_element_not_lvalue : Error<
"selector element is not a valid lvalue">;
def err_selector_element_type : Error<
"selector element type %0 is not a valid object">;
def err_selector_element_const_type : Error<
"selector element of type %0 cannot be a constant lvalue expression">;
def err_collection_expr_type : Error<
"the type %0 is not a pointer to a fast-enumerable object">;
def warn_collection_expr_type : Warning<
"collection expression type %0 may not respond to %1">;
def err_invalid_conversion_between_ext_vectors : Error<
"invalid conversion between ext-vector type %0 and %1">;
def warn_duplicate_attribute_exact : Warning<
"attribute %0 is already applied">, InGroup<IgnoredAttributes>;
def warn_duplicate_attribute : Warning<
"attribute %0 is already applied with different arguments">,
InGroup<IgnoredAttributes>;
def err_disallowed_duplicate_attribute : Error<
"attribute %0 cannot appear more than once on a declaration">;
def warn_sync_fetch_and_nand_semantics_change : Warning<
"the semantics of this intrinsic changed with GCC "
"version 4.4 - the newer semantics are provided here">,
InGroup<DiagGroup<"sync-fetch-and-nand-semantics-changed">>;
// Type
def ext_wchar_t_sign_spec : ExtWarn<"'%0' cannot be signed or unsigned">,
InGroup<DiagGroup<"signed-unsigned-wchar">>, DefaultError;
def warn_receiver_forward_class : Warning<
"receiver %0 is a forward class and corresponding @interface may not exist">,
InGroup<ForwardClassReceiver>;
def note_method_sent_forward_class : Note<"method %0 is used for the forward class">;
def ext_missing_type_specifier : ExtWarn<
"type specifier missing, defaults to 'int'; ISO C99 and later do not support "
- "implicit int">, InGroup<ImplicitInt>, DefaultError;
+ "implicit int">, InGroup<ImplicitInt>;
def err_missing_type_specifier : Error<
"a type specifier is required for all declarations">;
def err_decimal_unsupported : Error<
"GNU decimal type extension not supported">;
def err_objc_array_of_interfaces : Error<
"array of interface %0 is invalid (probably should be an array of pointers)">;
def ext_c99_array_usage : Extension<
"%select{qualifier in |static |}0array size %select{||'[*] '}0is a C99 "
"feature">, InGroup<C99>;
def err_c99_array_usage_cxx : Error<
"%select{qualifier in |static |}0array size %select{||'[*] '}0is a C99 "
"feature, not permitted in C++">;
def err_type_unsupported : Error<
"%0 is not supported on this target">;
def err_nsconsumed_attribute_mismatch : Error<
"overriding method has mismatched ns_consumed attribute on its"
" parameter">;
def err_nsreturns_retained_attribute_mismatch : Error<
"overriding method has mismatched ns_returns_%select{not_retained|retained}0"
" attributes">;
def err_nserrordomain_invalid_decl : Error<
"domain argument %select{|%1 }0does not refer to global constant">;
def err_nserrordomain_wrong_type : Error<
"domain argument %0 does not point to an NSString or CFString constant">;
def warn_nsconsumed_attribute_mismatch : Warning<
err_nsconsumed_attribute_mismatch.Text>, InGroup<NSConsumedMismatch>;
def warn_nsreturns_retained_attribute_mismatch : Warning<
err_nsreturns_retained_attribute_mismatch.Text>, InGroup<NSReturnsMismatch>;
def note_getter_unavailable : Note<
"or because setter is declared here, but no getter method %0 is found">;
def err_invalid_protocol_qualifiers : Error<
"invalid protocol qualifiers on non-ObjC type">;
def warn_ivar_use_hidden : Warning<
"local declaration of %0 hides instance variable">,
InGroup<ShadowIvar>;
def warn_direct_initialize_call : Warning<
"explicit call to +initialize results in duplicate call to +initialize">,
InGroup<ExplicitInitializeCall>;
def warn_direct_super_initialize_call : Warning<
"explicit call to [super initialize] should only be in implementation "
"of +initialize">,
InGroup<ExplicitInitializeCall>;
def err_ivar_use_in_class_method : Error<
"instance variable %0 accessed in class method">;
def err_private_ivar_access : Error<"instance variable %0 is private">,
AccessControl;
def err_protected_ivar_access : Error<"instance variable %0 is protected">,
AccessControl;
def warn_maynot_respond : Warning<"%0 may not respond to %1">;
def ext_typecheck_base_super : Warning<
"method parameter type "
"%diff{$ does not match super class method parameter type $|"
"does not match super class method parameter type}0,1">,
InGroup<SuperSubClassMismatch>, DefaultIgnore;
def warn_missing_method_return_type : Warning<
"method has no return type specified; defaults to 'id'">,
InGroup<MissingMethodReturnType>, DefaultIgnore;
def warn_direct_ivar_access : Warning<"instance variable %0 is being "
"directly accessed">, InGroup<DiagGroup<"direct-ivar-access">>, DefaultIgnore;
// Spell-checking diagnostics
def err_unknown_typename : Error<
"unknown type name %0">;
def err_unknown_type_or_class_name_suggest : Error<
"unknown %select{type|class}1 name %0; did you mean %2?">;
def err_unknown_typename_suggest : Error<
"unknown type name %0; did you mean %1?">;
def err_unknown_nested_typename_suggest : Error<
"no type named %0 in %1; did you mean %select{|simply }2%3?">;
def err_no_member_suggest : Error<"no member named %0 in %1; did you mean %select{|simply }2%3?">;
def err_undeclared_use_suggest : Error<
"use of undeclared %0; did you mean %1?">;
def err_undeclared_var_use_suggest : Error<
"use of undeclared identifier %0; did you mean %1?">;
def err_no_template : Error<"no template named %0">;
def err_no_template_suggest : Error<"no template named %0; did you mean %1?">;
def err_no_member_template : Error<"no template named %0 in %1">;
def err_no_member_template_suggest : Error<
"no template named %0 in %1; did you mean %select{|simply }2%3?">;
def err_non_template_in_template_id : Error<
"%0 does not name a template but is followed by template arguments">;
def err_non_template_in_template_id_suggest : Error<
"%0 does not name a template but is followed by template arguments; "
"did you mean %1?">;
def err_non_template_in_member_template_id_suggest : Error<
"member %0 of %1 is not a template; did you mean %select{|simply }2%3?">;
def note_non_template_in_template_id_found : Note<
"non-template declaration found by name lookup">;
def err_mem_init_not_member_or_class_suggest : Error<
"initializer %0 does not name a non-static data member or base "
"class; did you mean the %select{base class|member}1 %2?">;
def err_field_designator_unknown_suggest : Error<
"field designator %0 does not refer to any field in type %1; did you mean "
"%2?">;
def err_typecheck_member_reference_ivar_suggest : Error<
"%0 does not have a member named %1; did you mean %2?">;
def err_property_not_found_suggest : Error<
"property %0 not found on object of type %1; did you mean %2?">;
def err_class_property_found : Error<
"property %0 is a class property; did you mean to access it with class '%1'?">;
def err_ivar_access_using_property_syntax_suggest : Error<
"property %0 not found on object of type %1; did you mean to access instance variable %2?">;
def warn_property_access_suggest : Warning<
"property %0 not found on object of type %1; did you mean to access property %2?">,
InGroup<PropertyAccessDotSyntax>;
def err_property_found_suggest : Error<
"property %0 found on object of type %1; did you mean to access "
"it with the \".\" operator?">;
def err_undef_interface_suggest : Error<
"cannot find interface declaration for %0; did you mean %1?">;
def warn_undef_interface_suggest : Warning<
"cannot find interface declaration for %0; did you mean %1?">;
def err_undef_superclass_suggest : Error<
"cannot find interface declaration for %0, superclass of %1; did you mean "
"%2?">;
def err_undeclared_protocol_suggest : Error<
"cannot find protocol declaration for %0; did you mean %1?">;
def note_base_class_specified_here : Note<
"base class %0 specified here">;
def err_using_directive_suggest : Error<
"no namespace named %0; did you mean %1?">;
def err_using_directive_member_suggest : Error<
"no namespace named %0 in %1; did you mean %select{|simply }2%3?">;
def note_namespace_defined_here : Note<"namespace %0 defined here">;
def err_sizeof_pack_no_pack_name_suggest : Error<
"%0 does not refer to the name of a parameter pack; did you mean %1?">;
def note_parameter_pack_here : Note<"parameter pack %0 declared here">;
def err_uncasted_use_of_unknown_any : Error<
"%0 has unknown type; cast it to its declared type to use it">;
def err_uncasted_call_of_unknown_any : Error<
"%0 has unknown return type; cast the call to its declared return type">;
def err_uncasted_send_to_unknown_any_method : Error<
"no known method %select{%objcinstance1|%objcclass1}0; cast the "
"message send to the method's return type">;
def err_unsupported_unknown_any_decl : Error<
"%0 has unknown type, which is not supported for this kind of declaration">;
def err_unsupported_unknown_any_expr : Error<
"unsupported expression with unknown type">;
def err_unsupported_unknown_any_call : Error<
"call to unsupported expression with unknown type">;
def err_unknown_any_addrof : Error<
"the address of a declaration with unknown type "
"can only be cast to a pointer type">;
def err_unknown_any_addrof_call : Error<
"address-of operator cannot be applied to a call to a function with "
"unknown return type">;
def err_unknown_any_var_function_type : Error<
"variable %0 with unknown type cannot be given a function type">;
def err_unknown_any_function : Error<
"function %0 with unknown type must be given a function type">;
def err_filter_expression_integral : Error<
"filter expression has non-integral type %0">;
def err_non_asm_stmt_in_naked_function : Error<
"non-ASM statement in naked function is not supported">;
def err_asm_naked_this_ref : Error<
"'this' pointer references not allowed in naked functions">;
def err_asm_naked_parm_ref : Error<
"parameter references not allowed in naked functions">;
// OpenCL warnings and errors.
def err_invalid_astype_of_different_size : Error<
"invalid reinterpretation: sizes of %0 and %1 must match">;
def err_static_kernel : Error<
"kernel functions cannot be declared static">;
def err_method_kernel : Error<
"kernel functions cannot be class members">;
def err_template_kernel : Error<
"kernel functions cannot be used in a template declaration, instantiation or specialization">;
def err_opencl_ptrptr_kernel_param : Error<
"kernel parameter cannot be declared as a pointer to a pointer">;
def err_kernel_arg_address_space : Error<
"pointer arguments to kernel functions must reside in '__global', "
"'__constant' or '__local' address space">;
def err_opencl_ext_vector_component_invalid_length : Error<
"vector component access has invalid length %0. Supported: 1,2,3,4,8,16.">;
def err_opencl_function_variable : Error<
"%select{non-kernel function|function scope}0 variable cannot be declared in %1 address space">;
def err_opencl_addrspace_scope : Error<
"variables in the %0 address space can only be declared in the outermost "
"scope of a kernel function">;
def err_static_function_scope : Error<
"variables in function scope cannot be declared static">;
def err_opencl_bitfields : Error<
"bit-fields are not supported in OpenCL">;
def err_opencl_vla : Error<
"variable length arrays are not supported in OpenCL">;
def err_opencl_scalar_type_rank_greater_than_vector_type : Error<
"scalar operand type has greater rank than the type of the vector "
"element. (%0 and %1)">;
def err_bad_kernel_param_type : Error<
"%0 cannot be used as the type of a kernel parameter">;
def err_record_with_pointers_kernel_param : Error<
"%select{struct|union}0 kernel parameters may not contain pointers">;
def note_within_field_of_type : Note<
"within field of type %0 declared here">;
def note_illegal_field_declared_here : Note<
"field of illegal %select{type|pointer type}0 %1 declared here">;
def err_opencl_type_struct_or_union_field : Error<
"the %0 type cannot be used to declare a structure or union field">;
def err_event_t_addr_space_qual : Error<
"the event_t type can only be used with __private address space qualifier">;
def err_expected_kernel_void_return_type : Error<
"kernel must have void return type">;
def err_sampler_initializer_not_integer : Error<
"sampler_t initialization requires 32-bit integer, not %0">;
def warn_sampler_initializer_invalid_bits : Warning<
"sampler initializer has invalid %0 bits">, InGroup<SpirCompat>, DefaultIgnore;
def err_sampler_argument_required : Error<
"sampler_t variable required - got %0">;
def err_wrong_sampler_addressspace: Error<
"sampler type cannot be used with the __local and __global address space qualifiers">;
def err_opencl_nonconst_global_sampler : Error<
"global sampler requires a const or constant address space qualifier">;
def err_opencl_cast_non_zero_to_event_t : Error<
"cannot cast non-zero value '%0' to 'event_t'">;
def err_opencl_global_invalid_addr_space : Error<
"%select{program scope|static local|extern}0 variable must reside in %1 address space">;
def err_missing_actual_pipe_type : Error<
"missing actual type specifier for pipe">;
def err_reference_pipe_type : Error <
"pipes packet types cannot be of reference type">;
def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">;
def err_opencl_kernel_attr :
Error<"attribute %0 can only be applied to an OpenCL kernel function">;
def err_opencl_return_value_with_address_space : Error<
"return value cannot be qualified with address space">;
def err_opencl_constant_no_init : Error<
"variable in constant address space must be initialized">;
def err_opencl_atomic_init: Error<
"atomic variable can be %select{assigned|initialized}0 to a variable only "
"in global address space">;
def err_opencl_implicit_vector_conversion : Error<
"implicit conversions between vector types (%0 and %1) are not permitted">;
def err_opencl_invalid_type_array : Error<
"array of %0 type is invalid in OpenCL">;
def err_opencl_ternary_with_block : Error<
"block type cannot be used as expression in ternary expression in OpenCL">;
def err_opencl_pointer_to_type : Error<
"pointer to type %0 is invalid in OpenCL">;
def err_opencl_type_can_only_be_used_as_function_parameter : Error <
"type %0 can only be used as a function parameter in OpenCL">;
def err_opencl_type_not_found : Error<
"%0 type %1 not found; include the base header with -finclude-default-header">;
def warn_opencl_attr_deprecated_ignored : Warning <
"%0 attribute is deprecated and ignored in %1">, InGroup<IgnoredAttributes>;
def err_opencl_variadic_function : Error<
"invalid prototype, variadic arguments are not allowed in OpenCL">;
def err_opencl_requires_extension : Error<
"use of %select{type|declaration}0 %1 requires %2 support">;
def ext_opencl_double_without_pragma : Extension<
"Clang permits use of type 'double' regardless pragma if 'cl_khr_fp64' is"
" supported">;
def warn_opencl_generic_address_space_arg : Warning<
"passing non-generic address space pointer to %0"
" may cause dynamic conversion affecting performance">,
InGroup<Conversion>, DefaultIgnore;
// OpenCL v2.0 s6.13.6 -- Builtin Pipe Functions
def err_opencl_builtin_pipe_first_arg : Error<
"first argument to %0 must be a pipe type">;
def err_opencl_builtin_pipe_arg_num : Error<
"invalid number of arguments to function: %0">;
def err_opencl_builtin_pipe_invalid_arg : Error<
"invalid argument type to function %0 (expecting %1 having %2)">;
def err_opencl_builtin_pipe_invalid_access_modifier : Error<
"invalid pipe access modifier (expecting %0)">;
// OpenCL access qualifier
def err_opencl_invalid_access_qualifier : Error<
"access qualifier can only be used for pipe and image type">;
def err_opencl_invalid_read_write : Error<
"access qualifier %0 can not be used for %1 %select{|prior to OpenCL C version 2.0 or in version 3.0 "
"and without __opencl_c_read_write_images feature}2">;
def err_opencl_multiple_access_qualifiers : Error<
"multiple access qualifiers">;
def note_opencl_typedef_access_qualifier : Note<
"previously declared '%0' here">;
// OpenCL v2.0 s6.12.5 Blocks restrictions
def err_opencl_block_storage_type : Error<
"the __block storage type is not permitted">;
def err_opencl_invalid_block_declaration : Error<
"invalid block variable declaration - must be %select{const qualified|initialized}0">;
def err_opencl_extern_block_declaration : Error<
"invalid block variable declaration - using 'extern' storage class is disallowed">;
def err_opencl_block_ref_block : Error<
"cannot refer to a block inside block">;
// OpenCL v2.0 s6.13.9 - Address space qualifier functions.
def err_opencl_builtin_to_addr_invalid_arg : Error<
"invalid argument %0 to function: %1, expecting a generic pointer argument">;
// OpenCL v2.0 s6.13.17 Enqueue kernel restrictions.
def err_opencl_enqueue_kernel_incorrect_args : Error<
"illegal call to enqueue_kernel, incorrect argument types">;
def err_opencl_enqueue_kernel_local_size_args : Error<
"mismatch in number of block parameters and local size arguments passed">;
def err_opencl_enqueue_kernel_invalid_local_size_type : Error<
"illegal call to enqueue_kernel, parameter needs to be specified as integer type">;
def err_opencl_enqueue_kernel_blocks_non_local_void_args : Error<
"blocks used in enqueue_kernel call are expected to have parameters of type 'local void*'">;
def err_opencl_enqueue_kernel_blocks_no_args : Error<
"blocks with parameters are not accepted in this prototype of enqueue_kernel call">;
def err_opencl_builtin_expected_type : Error<
"illegal call to %0, expected %1 argument type">;
// OpenCL v3.0 s6.3.7 - Vector Components
def ext_opencl_ext_vector_type_rgba_selector: ExtWarn<
"vector component name '%0' is a feature from OpenCL version 3.0 onwards">,
InGroup<OpenCLUnsupportedRGBA>;
def err_openclcxx_placement_new : Error<
"use of placement new requires explicit declaration">;
// MIG routine annotations.
def warn_mig_server_routine_does_not_return_kern_return_t : Warning<
"'mig_server_routine' attribute only applies to routines that return a kern_return_t">,
InGroup<IgnoredAttributes>;
def warn_imp_cast_drops_unaligned : Warning<
"implicit cast from type %0 to type %1 drops __unaligned qualifier">,
InGroup<DiagGroup<"unaligned-qualifier-implicit-cast">>;
} // end of sema category
let CategoryName = "OpenMP Issue" in {
// OpenMP support.
def err_omp_expected_var_arg : Error<
"%0 is not a global variable, static local variable or static data member">;
def err_omp_expected_var_arg_suggest : Error<
"%0 is not a global variable, static local variable or static data member; "
"did you mean %1">;
def err_omp_global_var_arg : Error<
"arguments of '#pragma omp %0' must have %select{global storage|static storage duration}1">;
def err_omp_ref_type_arg : Error<
"arguments of '#pragma omp %0' cannot be of reference type %1">;
def err_omp_region_not_file_context : Error<
"directive must be at file or namespace scope">;
def err_omp_var_scope : Error<
"'#pragma omp %0' must appear in the scope of the %q1 variable declaration">;
def err_omp_var_used : Error<
"'#pragma omp %0' must precede all references to variable %q1">;
def err_omp_var_thread_local : Error<
"variable %0 cannot be threadprivate because it is %select{thread-local|a global named register variable}1">;
def err_omp_private_incomplete_type : Error<
"a private variable with incomplete type %0">;
def err_omp_firstprivate_incomplete_type : Error<
"a firstprivate variable with incomplete type %0">;
def err_omp_lastprivate_incomplete_type : Error<
"a lastprivate variable with incomplete type %0">;
def err_omp_reduction_incomplete_type : Error<
"a reduction list item with incomplete type %0">;
def err_omp_unexpected_clause_value : Error<
"expected %0 in OpenMP clause '%1'">;
def err_omp_expected_var_name_member_expr : Error<
"expected variable name%select{| or data member of current class}0">;
def err_omp_expected_var_name_member_expr_or_array_item : Error<
"expected variable name%select{|, data member of current class}0, array element or array section">;
def err_omp_expected_addressable_lvalue_or_array_item : Error<
"expected addressable lvalue expression, array element%select{ or array section|, array section or array shaping expression}0%select{| of non 'omp_depend_t' type}1">;
def err_omp_expected_named_var_member_or_array_expression: Error<
"expected expression containing only member accesses and/or array sections based on named variables">;
def err_omp_bit_fields_forbidden_in_clause : Error<
"bit fields cannot be used to specify storage in a '%0' clause">;
def err_array_section_does_not_specify_contiguous_storage : Error<
"array section does not specify contiguous storage">;
def err_array_section_does_not_specify_length : Error<
"array section does not specify length for outermost dimension">;
def err_omp_union_type_not_allowed : Error<
"mapping of union members is not allowed">;
def err_omp_expected_access_to_data_field : Error<
"expected access to data field">;
def err_omp_multiple_array_items_in_map_clause : Error<
"multiple array elements associated with the same variable are not allowed in map clauses of the same construct">;
def err_omp_duplicate_map_type_modifier : Error<
"same map type modifier has been specified more than once">;
def err_omp_duplicate_motion_modifier : Error<
"same motion modifier has been specified more than once">;
def err_omp_pointer_mapped_along_with_derived_section : Error<
"pointer cannot be mapped along with a section derived from itself">;
def err_omp_original_storage_is_shared_and_does_not_contain : Error<
"original storage of expression in data environment is shared but data environment do not fully contain mapped expression storage">;
def err_omp_same_pointer_dereferenced : Error<
"same pointer dereferenced in multiple different ways in map clause expressions">;
def note_omp_task_predetermined_firstprivate_here : Note<
"predetermined as a firstprivate in a task construct here">;
def err_omp_threadprivate_incomplete_type : Error<
"threadprivate variable with incomplete type %0">;
def err_omp_no_dsa_for_variable : Error<
"variable %0 must have explicitly specified data sharing attributes">;
def err_omp_defaultmap_no_attr_for_variable : Error<
"variable %0 must have explicitly specified data sharing attributes, data mapping attributes, or in an is_device_ptr clause">;
def note_omp_default_dsa_none : Note<
"explicit data sharing attribute requested here">;
def note_omp_defaultmap_attr_none : Note<
"explicit data sharing attribute, data mapping attribute, or is_device_ptr clause requested here">;
def err_omp_wrong_dsa : Error<
"%0 variable cannot be %1">;
def err_omp_variably_modified_type_not_supported : Error<
"arguments of OpenMP clause '%0' in '#pragma omp %2' directive cannot be of variably-modified type %1">;
def note_omp_explicit_dsa : Note<
"defined as %0">;
def note_omp_predetermined_dsa : Note<
"%select{static data member is predetermined as shared|"
"variable with static storage duration is predetermined as shared|"
"loop iteration variable is predetermined as private|"
"loop iteration variable is predetermined as linear|"
"loop iteration variable is predetermined as lastprivate|"
"constant variable is predetermined as shared|"
"global variable is predetermined as shared|"
"non-shared variable in a task construct is predetermined as firstprivate|"
"variable with automatic storage duration is predetermined as private}0"
"%select{|; perhaps you forget to enclose 'omp %2' directive into a parallel or another task region?}1">;
def note_omp_implicit_dsa : Note<
"implicitly determined as %0">;
def err_omp_loop_var_dsa : Error<
"loop iteration variable in the associated loop of 'omp %1' directive may not be %0, predetermined as %2">;
def err_omp_not_for : Error<
"%select{statement after '#pragma omp %1' must be a for loop|"
"expected %2 for loops after '#pragma omp %1'%select{|, but found only %4}3}0">;
def note_omp_collapse_ordered_expr : Note<
"as specified in %select{'collapse'|'ordered'|'collapse' and 'ordered'}0 clause%select{||s}0">;
def err_omp_negative_expression_in_clause : Error<
"argument to '%0' clause must be a %select{non-negative|strictly positive}1 integer value">;
def err_omp_not_integral : Error<
"expression must have integral or unscoped enumeration "
"type, not %0">;
def err_omp_threadprivate_in_target : Error<
"threadprivate variables cannot be used in target constructs">;
def err_omp_incomplete_type : Error<
"expression has incomplete class type %0">;
def err_omp_explicit_conversion : Error<
"expression requires explicit conversion from %0 to %1">;
def note_omp_conversion_here : Note<
"conversion to %select{integral|enumeration}0 type %1 declared here">;
def err_omp_ambiguous_conversion : Error<
"ambiguous conversion from type %0 to an integral or unscoped "
"enumeration type">;
def err_omp_iterator_not_integral_or_pointer : Error<
"expected integral or pointer type as the iterator-type, not %0">;
def err_omp_iterator_step_not_integral : Error<
"iterator step expression %0 is not the integral expression">;
def err_omp_iterator_step_constant_zero : Error<
"iterator step expression %0 evaluates to 0">;
def err_omp_required_access : Error<
"%0 variable must be %1">;
def err_omp_const_variable : Error<
"const-qualified variable cannot be %0">;
def err_omp_const_not_mutable_variable : Error<
"const-qualified variable without mutable fields cannot be %0">;
def err_omp_const_list_item : Error<
"const-qualified list item cannot be %0">;
def err_omp_linear_incomplete_type : Error<
"a linear variable with incomplete type %0">;
def err_omp_linear_expected_int_or_ptr : Error<
"argument of a linear clause should be of integral or pointer "
"type, not %0">;
def warn_omp_linear_step_zero : Warning<
"zero linear step (%0 %select{|and other variables in clause }1should probably be const)">,
InGroup<OpenMPClauses>;
def warn_omp_alignment_not_power_of_two : Warning<
"aligned clause will be ignored because the requested alignment is not a power of 2">,
InGroup<OpenMPClauses>;
def err_omp_invalid_target_decl : Error<
"%0 used in declare target directive is not a variable or a function name">;
def err_omp_declare_target_to_and_link : Error<
"%0 must not appear in both clauses 'to' and 'link'">;
def warn_omp_not_in_target_context : Warning<
"declaration is not declared in any declare target region">,
InGroup<OpenMPTarget>;
def err_omp_function_in_link_clause : Error<
"function name is not allowed in 'link' clause">;
def err_omp_aligned_expected_array_or_ptr : Error<
"argument of aligned clause should be array"
"%select{ or pointer|, pointer, reference to array or reference to pointer}1"
", not %0">;
def err_omp_used_in_clause_twice : Error<
"%select{a variable|a parameter|'this'}0 cannot appear in more than one %1 clause">;
def err_omp_local_var_in_threadprivate_init : Error<
"variable with local storage in initial value of threadprivate variable">;
def err_omp_loop_not_canonical_init : Error<
"initialization clause of OpenMP for loop is not in canonical form "
"('var = init' or 'T var = init')">;
def ext_omp_loop_not_canonical_init : ExtWarn<
"initialization clause of OpenMP for loop is not in canonical form "
"('var = init' or 'T var = init')">, InGroup<OpenMPLoopForm>;
def err_omp_loop_not_canonical_cond : Error<
"condition of OpenMP for loop must be a relational comparison "
"('<', '<=', '>', %select{or '>='|'>=', or '!='}0) of loop variable %1">;
def err_omp_loop_not_canonical_incr : Error<
"increment clause of OpenMP for loop must perform simple addition "
"or subtraction on loop variable %0">;
def err_omp_loop_variable_type : Error<
"variable must be of integer or %select{pointer|random access iterator}0 type">;
def err_omp_loop_incr_not_compatible : Error<
"increment expression must cause %0 to %select{decrease|increase}1 "
"on each iteration of OpenMP for loop">;
def note_omp_loop_cond_requres_compatible_incr : Note<
"loop step is expected to be %select{negative|positive}0 due to this condition">;
def err_omp_loop_diff_cxx : Error<
"could not calculate number of iterations calling 'operator-' with "
"upper and lower loop bounds">;
def err_omp_loop_cannot_use_stmt : Error<
"'%0' statement cannot be used in OpenMP for loop">;
def err_omp_simd_region_cannot_use_stmt : Error<
"'%0' statement cannot be used in OpenMP simd region">;
def warn_omp_loop_64_bit_var : Warning<
"OpenMP loop iteration variable cannot have more than 64 bits size and will be narrowed">,
InGroup<OpenMPLoopForm>;
def err_omp_unknown_reduction_identifier : Error<
"incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', "
"'&&', '||', 'min' or 'max' or declare reduction for type %0">;
def err_omp_not_resolved_reduction_identifier : Error<
"unable to resolve declare reduction construct for type %0">;
def err_omp_reduction_ref_type_arg : Error<
"argument of OpenMP clause '%0' must reference the same object in all threads">;
def err_omp_clause_not_arithmetic_type_arg : Error<
"arguments of OpenMP clause '%0' for 'min' or 'max' must be of %select{scalar|arithmetic}1 type">;
def err_omp_clause_floating_type_arg : Error<
"arguments of OpenMP clause '%0' with bitwise operators cannot be of floating type">;
def err_omp_once_referenced : Error<
"variable can appear only once in OpenMP '%0' clause">;
def err_omp_once_referenced_in_target_update : Error<
"variable can appear only once in OpenMP 'target update' construct">;
def note_omp_referenced : Note<
"previously referenced here">;
def err_omp_reduction_in_task : Error<
"reduction variables may not be accessed in an explicit task">;
def err_omp_reduction_id_not_compatible : Error<
"list item of type %0 is not valid for specified reduction operation: unable to provide default initialization value">;
def err_omp_reduction_identifier_mismatch : Error<
"in_reduction variable must have the same reduction operation as in a task_reduction clause">;
def note_omp_previous_reduction_identifier : Note<
"previously marked as task_reduction with different reduction operation">;
def err_omp_prohibited_region : Error<
"region cannot be%select{| closely}0 nested inside '%1' region"
"%select{|; perhaps you forget to enclose 'omp %3' directive into a parallel region?|"
"; perhaps you forget to enclose 'omp %3' directive into a for or a parallel for region with 'ordered' clause?|"
"; perhaps you forget to enclose 'omp %3' directive into a target region?|"
"; perhaps you forget to enclose 'omp %3' directive into a teams region?|"
"; perhaps you forget to enclose 'omp %3' directive into a for, simd, for simd, parallel for, or parallel for simd region?}2">;
def err_omp_prohibited_region_simd : Error<
"OpenMP constructs may not be nested inside a simd region%select{| except for ordered simd, simd, scan, or atomic directive}0">;
def err_omp_prohibited_region_atomic : Error<
"OpenMP constructs may not be nested inside an atomic region">;
def err_omp_prohibited_region_critical_same_name : Error<
"cannot nest 'critical' regions having the same name %0">;
def note_omp_previous_critical_region : Note<
"previous 'critical' region starts here">;
def err_omp_several_directives_in_region : Error<
"exactly one '%0' directive must appear in the loop body of an enclosing directive">;
def note_omp_previous_directive : Note<
"previous '%0' directive used here">;
def err_omp_sections_not_compound_stmt : Error<
"the statement for '#pragma omp sections' must be a compound statement">;
def err_omp_parallel_sections_not_compound_stmt : Error<
"the statement for '#pragma omp parallel sections' must be a compound statement">;
def err_omp_orphaned_section_directive : Error<
"%select{orphaned 'omp section' directives are prohibited, it|'omp section' directive}0"
" must be closely nested to a sections region%select{|, not a %1 region}0">;
def err_omp_sections_substmt_not_section : Error<
"statement in 'omp sections' directive must be enclosed into a section region">;
def err_omp_parallel_sections_substmt_not_section : Error<
"statement in 'omp parallel sections' directive must be enclosed into a section region">;
def err_omp_parallel_reduction_in_task_firstprivate : Error<
"argument of a reduction clause of a %0 construct must not appear in a firstprivate clause on a task construct">;
def err_omp_atomic_read_not_expression_statement : Error<
"the statement for 'atomic read' must be an expression statement of form 'v = x;',"
" where v and x are both lvalue expressions with scalar type">;
def note_omp_atomic_read_write: Note<
"%select{expected an expression statement|expected built-in assignment operator|expected expression of scalar type|expected lvalue expression}0">;
def err_omp_atomic_write_not_expression_statement : Error<
"the statement for 'atomic write' must be an expression statement of form 'x = expr;',"
" where x is a lvalue expression with scalar type">;
def err_omp_atomic_update_not_expression_statement : Error<
"the statement for 'atomic update' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x',"
" where x is an lvalue expression with scalar type">;
def err_omp_atomic_not_expression_statement : Error<
"the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x',"
" where x is an lvalue expression with scalar type">;
def note_omp_atomic_update: Note<
"%select{expected an expression statement|expected built-in binary or unary operator|expected unary decrement/increment operation|"
"expected expression of scalar type|expected assignment expression|expected built-in binary operator|"
"expected one of '+', '*', '-', '/', '&', '^', '%|', '<<', or '>>' built-in operations|expected in right hand side of expression}0">;
def err_omp_atomic_capture_not_expression_statement : Error<
"the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x',"
" where x and v are both lvalue expressions with scalar type">;
def err_omp_atomic_capture_not_compound_statement : Error<
"the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}',"
" '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}',"
" '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}'"
" where x is an lvalue expression with scalar type">;
def note_omp_atomic_capture: Note<
"%select{expected assignment expression|expected compound statement|expected exactly two expression statements|expected in right hand side of the first expression}0">;
def err_omp_atomic_compare : Error<
"the statement for 'atomic compare' must be a compound statement of form '{x = expr ordop x ? expr : x;}', '{x = x ordop expr? expr : x;}',"
" '{x = x == e ? d : x;}', '{x = e == x ? d : x;}', or 'if(expr ordop x) {x = expr;}', 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}',"
" 'if(e == x) {x = d;}' where 'x' is an lvalue expression with scalar type, 'expr', 'e', and 'd' are expressions with scalar type,"
" and 'ordop' is one of '<' or '>'.">;
def err_omp_atomic_compare_capture : Error<
"the statement for 'atomic compare capture' must be a compound statement of form '{v = x; cond-up-stmt}', ''{cond-up-stmt v = x;}', '{if(x == e) {x = d;} else {v = x;}}',"
" '{r = x == e; if(r) {x = d;}}', or '{r = x == e; if(r) {x = d;} else {v = x;}}', where 'cond-update-stmt' can have one of the following forms: 'if(expr ordop x) {x = expr;}',"
" 'if(x ordop expr) {x = expr;}', 'if(x == e) {x = d;}', or 'if(e == x) {x = d;}' where 'x', 'r', and 'v' are lvalue expressions with scalar type, 'expr', 'e', and 'd' are expressions with scalar type,"
" and 'ordop' is one of '<' or '>'.">;
def note_omp_atomic_compare: Note<
"%select{expected compound statement|expected exactly one expression statement|expected assignment statement|expected conditional operator|expect result value to be at false expression|"
"expect binary operator in conditional expression|expect '<', '>' or '==' as order operator|expect comparison in a form of 'x == e', 'e == x', 'x ordop expr', or 'expr ordop x'|"
"expect lvalue for result value|expect scalar value|expect integer value|unexpected 'else' statement|expect '==' operator|expect an assignment statement 'v = x'|"
"expect a 'if' statement|expect no more than two statements|expect a compound statement|expect 'else' statement|expect a form 'r = x == e; if (r) ...'}0">;
def err_omp_atomic_several_clauses : Error<
"directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause">;
def err_omp_several_mem_order_clauses : Error<
"directive '#pragma omp %0' cannot contain more than one %select{'seq_cst', 'relaxed', |}1'acq_rel', 'acquire' or 'release' clause">;
def err_omp_atomic_incompatible_mem_order_clause : Error<
"directive '#pragma omp atomic%select{ %0|}1' cannot be used with '%2' clause">;
def note_omp_previous_mem_order_clause : Note<
"'%0' clause used here">;
def err_omp_target_contains_not_only_teams : Error<
"target construct with nested teams region contains statements outside of the teams construct">;
def note_omp_nested_teams_construct_here : Note<
"nested teams construct here">;
def note_omp_nested_statement_here : Note<
"%select{statement|directive}0 outside teams construct here">;
def err_omp_single_copyprivate_with_nowait : Error<
"the 'copyprivate' clause must not be used with the 'nowait' clause">;
def note_omp_nowait_clause_here : Note<
"'nowait' clause is here">;
def err_omp_single_decl_in_declare_simd_variant : Error<
"single declaration is expected after 'declare %select{simd|variant}0' directive">;
def err_omp_function_expected : Error<
"'#pragma omp declare %select{simd|variant}0' can only be applied to functions">;
def err_omp_wrong_cancel_region : Error<
"one of 'for', 'parallel', 'sections' or 'taskgroup' is expected">;
def err_omp_parent_cancel_region_nowait : Error<
"parent region for 'omp %select{cancellation point|cancel}0' construct cannot be nowait">;
def err_omp_parent_cancel_region_ordered : Error<
"parent region for 'omp %select{cancellation point|cancel}0' construct cannot be ordered">;
def err_omp_reduction_wrong_type : Error<"reduction type cannot be %select{qualified with 'const', 'volatile' or 'restrict'|a function|a reference|an array}0 type">;
def err_omp_wrong_var_in_declare_reduction : Error<"only %select{'omp_priv' or 'omp_orig'|'omp_in' or 'omp_out'}0 variables are allowed in %select{initializer|combiner}0 expression">;
def err_omp_declare_reduction_redefinition : Error<"redefinition of user-defined reduction for type %0">;
def err_omp_mapper_wrong_type : Error<
"mapper type must be of struct, union or class type">;
def err_omp_declare_mapper_wrong_var : Error<
"only variable %0 is allowed in map clauses of this 'omp declare mapper' directive">;
def err_omp_declare_mapper_redefinition : Error<
"redefinition of user-defined mapper for type %0 with name %1">;
def err_omp_invalid_mapper: Error<
"cannot find a valid user-defined mapper for type %0 with name %1">;
def err_omp_array_section_use : Error<"OpenMP array section is not allowed here">;
def err_omp_array_shaping_use : Error<"OpenMP array shaping operation is not allowed here">;
def err_omp_iterator_use : Error<"OpenMP iterator is not allowed here">;
def err_omp_typecheck_section_value : Error<
"subscripted value is not an array or pointer">;
def err_omp_typecheck_section_not_integer : Error<
"array section %select{lower bound|length}0 is not an integer">;
def err_omp_typecheck_shaping_not_integer : Error<
"array shaping operation dimension is not an integer">;
def err_omp_shaping_dimension_not_positive : Error<
"array shaping dimension is evaluated to a non-positive value %0">;
def err_omp_section_function_type : Error<
"section of pointer to function type %0">;
def warn_omp_section_is_char : Warning<"array section %select{lower bound|length}0 is of type 'char'">,
InGroup<CharSubscript>, DefaultIgnore;
def err_omp_section_incomplete_type : Error<
"section of pointer to incomplete type %0">;
def err_omp_section_not_subset_of_array : Error<
"array section must be a subset of the original array">;
def err_omp_section_length_negative : Error<
"section length is evaluated to a negative value %0">;
def err_omp_section_stride_non_positive : Error<
"section stride is evaluated to a non-positive value %0">;
def err_omp_section_length_undefined : Error<
"section length is unspecified and cannot be inferred because subscripted value is %select{not an array|an array of unknown bound}0">;
def err_omp_wrong_linear_modifier : Error<
"expected %select{'val' modifier|one of 'ref', val' or 'uval' modifiers}0">;
def err_omp_wrong_linear_modifier_non_reference : Error<
"variable of non-reference type %0 can be used only with 'val' modifier, but used with '%1'">;
def err_omp_wrong_simdlen_safelen_values : Error<
"the value of 'simdlen' parameter must be less than or equal to the value of the 'safelen' parameter">;
def err_omp_wrong_if_directive_name_modifier : Error<
"directive name modifier '%0' is not allowed for '#pragma omp %1'">;
def err_omp_no_more_if_clause : Error<
"no more 'if' clause is allowed">;
def err_omp_unnamed_if_clause : Error<
"expected%select{| one of}0 %1 directive name modifier%select{|s}0">;
def note_omp_previous_named_if_clause : Note<
"previous clause with directive name modifier specified here">;
def err_omp_ordered_directive_with_param : Error<
"'ordered' directive %select{without any clauses|with 'threads' clause}0 cannot be closely nested inside ordered region with specified parameter">;
def err_omp_ordered_directive_without_param : Error<
"'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter">;
def note_omp_ordered_param : Note<
"'ordered' clause%select{| with specified parameter}0">;
def err_omp_expected_base_var_name : Error<
"expected variable name as a base of the array %select{subscript|section}0">;
def err_omp_map_shared_storage : Error<
"variable already marked as mapped in current construct">;
def err_omp_invalid_map_type_for_directive : Error<
"%select{map type '%1' is not allowed|map type must be specified}0 for '#pragma omp %2'">;
def err_omp_invalid_map_type_modifier_for_directive : Error<
"map type modifier '%0' is not allowed for '#pragma omp %1'">;
def err_omp_no_clause_for_directive : Error<
"expected at least one %0 clause for '#pragma omp %1'">;
def err_omp_threadprivate_in_clause : Error<
"threadprivate variables are not allowed in '%0' clause">;
def err_omp_wrong_ordered_loop_count : Error<
"the parameter of the 'ordered' clause must be greater than or equal to the parameter of the 'collapse' clause">;
def note_collapse_loop_count : Note<
"parameter of the 'collapse' clause">;
def err_omp_clauses_mutually_exclusive : Error<
"'%0' and '%1' clause are mutually exclusive and may not appear on the same directive">;
def note_omp_previous_clause : Note<
"'%0' clause is specified here">;
def err_omp_hint_clause_no_name : Error<
"the name of the construct must be specified in presence of 'hint' clause">;
def err_omp_critical_with_hint : Error<
"constructs with the same name must have a 'hint' clause with the same value">;
def note_omp_critical_hint_here : Note<
"%select{|previous }0'hint' clause with value '%1'">;
def note_omp_critical_no_hint : Note<
"%select{|previous }0directive with no 'hint' clause specified">;
def err_omp_depend_clause_thread_simd : Error<
"'depend' clauses cannot be mixed with '%0' clause">;
def err_omp_depend_sink_expected_loop_iteration : Error<
"expected%select{| %1}0 loop iteration variable">;
def err_omp_depend_sink_unexpected_expr : Error<
"unexpected expression: number of expressions is larger than the number of associated loops">;
def err_omp_depend_sink_expected_plus_minus : Error<
"expected '+' or '-' operation">;
def err_omp_taskwait_depend_mutexinoutset_not_allowed : Error<
"'mutexinoutset' modifier not allowed in 'depend' clause on 'taskwait' directive">;
def err_omp_depend_sink_source_not_allowed : Error<
"'depend(%select{source|sink:vec}0)' clause%select{|s}0 cannot be mixed with 'depend(%select{sink:vec|source}0)' clause%select{s|}0">;
def err_omp_depend_zero_length_array_section_not_allowed : Error<
"zero-length array section is not allowed in 'depend' clause">;
def err_omp_depend_sink_source_with_modifier : Error<
"depend modifier cannot be used with 'sink' or 'source' depend type">;
def err_omp_depend_modifier_not_iterator : Error<
"expected iterator specification as depend modifier">;
def err_omp_linear_ordered : Error<
"'linear' clause cannot be specified along with 'ordered' clause with a parameter">;
def err_omp_unexpected_schedule_modifier : Error<
"modifier '%0' cannot be used along with modifier '%1'">;
def err_omp_schedule_nonmonotonic_static : Error<
"'nonmonotonic' modifier can only be specified with 'dynamic' or 'guided' schedule kind">;
def err_omp_simple_clause_incompatible_with_ordered : Error<
"'%0' clause with '%1' modifier cannot be specified if an 'ordered' clause is specified">;
def err_omp_ordered_simd : Error<
"'ordered' clause with a parameter can not be specified in '#pragma omp %0' directive">;
def err_omp_variable_in_given_clause_and_dsa : Error<
"%0 variable cannot be in a %1 clause in '#pragma omp %2' directive">;
def err_omp_param_or_this_in_clause : Error<
"expected reference to one of the parameters of function %0%select{| or 'this'}1">;
def err_omp_expected_uniform_param : Error<
"expected a reference to a parameter specified in a 'uniform' clause">;
def err_omp_expected_int_param : Error<
"expected a reference to an integer-typed parameter">;
def err_omp_at_least_one_motion_clause_required : Error<
"expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'">;
def err_omp_cannot_update_with_internal_linkage : Error<
"the host cannot update a declare target variable that is not externally visible.">;
def err_omp_usedeviceptr_not_a_pointer : Error<
"expected pointer or reference to pointer in 'use_device_ptr' clause">;
def err_omp_argument_type_isdeviceptr : Error <
"expected pointer, array, reference to pointer, or reference to array in 'is_device_ptr clause'">;
def warn_omp_nesting_simd : Warning<
"OpenMP only allows an ordered construct with the simd clause nested in a simd construct">,
InGroup<SourceUsesOpenMP>;
def err_omp_orphaned_device_directive : Error<
"orphaned 'omp %0' directives are prohibited"
"; perhaps you forget to enclose the directive into a "
"%select{|||target |teams|for, simd, for simd, parallel for, or parallel for simd }1region?">;
def err_omp_reduction_non_addressable_expression : Error<
"expected addressable reduction item for the task-based directives">;
def err_omp_reduction_with_nogroup : Error<
"'reduction' clause cannot be used with 'nogroup' clause">;
def err_omp_reduction_vla_unsupported : Error<
"cannot generate code for reduction on %select{|array section, which requires a }0variable length array">;
def err_omp_linear_distribute_var_non_loop_iteration : Error<
"only loop iteration variables are allowed in 'linear' clause in distribute directives">;
def warn_omp_non_trivial_type_mapped : Warning<
"Type %0 is not trivially copyable and not guaranteed to be mapped correctly">,
InGroup<OpenMPMapping>;
def err_omp_requires_clause_redeclaration : Error <
"Only one %0 clause can appear on a requires directive in a single translation unit">;
def note_omp_requires_previous_clause : Note <
"%0 clause previously used here">;
def err_omp_directive_before_requires : Error <
"'%0' region encountered before requires directive with '%1' clause">;
def note_omp_requires_encountered_directive : Note <
"'%0' previously encountered here">;
def err_omp_device_ancestor_without_requires_reverse_offload : Error <
"Device clause with ancestor device-modifier used without specifying 'requires reverse_offload'">;
def err_omp_invalid_scope : Error <
"'#pragma omp %0' directive must appear only in file scope">;
def note_omp_invalid_length_on_this_ptr_mapping : Note <
"expected length on mapping of 'this' array section expression to be '1'">;
def note_omp_invalid_lower_bound_on_this_ptr_mapping : Note <
"expected lower bound on mapping of 'this' array section expression to be '0' or not specified">;
def note_omp_invalid_subscript_on_this_ptr_map : Note <
"expected 'this' subscript expression on map clause to be 'this[0]'">;
def err_omp_invalid_map_this_expr : Error <
"invalid 'this' expression on 'map' clause">;
def err_omp_implied_type_not_found : Error<
"'%0' type not found; include <omp.h>">;
def err_omp_expected_omp_depend_t_lvalue : Error<
"expected lvalue expression%select{ of 'omp_depend_t' type, not %1|}0">;
def err_omp_depobj_expected : Error<
"expected depobj expression">;
def err_omp_depobj_single_clause_expected : Error<
"exactly one of 'depend', 'destroy', or 'update' clauses is expected">;
def err_omp_scan_single_clause_expected : Error<
"exactly one of 'inclusive' or 'exclusive' clauses is expected">;
def err_omp_inclusive_exclusive_not_reduction : Error<
"the list item must appear in 'reduction' clause with the 'inscan' modifier "
"of the parent directive">;
def err_omp_reduction_not_inclusive_exclusive : Error<
"the inscan reduction list item must appear as a list item in an 'inclusive' or"
" 'exclusive' clause on an inner 'omp scan' directive">;
def err_omp_wrong_inscan_reduction : Error<
"'inscan' modifier can be used only in 'omp for', 'omp simd', 'omp for simd',"
" 'omp parallel for', or 'omp parallel for simd' directive">;
def err_omp_inscan_reduction_expected : Error<
"expected 'reduction' clause with the 'inscan' modifier">;
def note_omp_previous_inscan_reduction : Note<
"'reduction' clause with 'inscan' modifier is used here">;
def err_omp_expected_predefined_allocator : Error<
"expected one of the predefined allocators for the variables with the static "
"storage: 'omp_default_mem_alloc', 'omp_large_cap_mem_alloc', "
"'omp_const_mem_alloc', 'omp_high_bw_mem_alloc', 'omp_low_lat_mem_alloc', "
"'omp_cgroup_mem_alloc', 'omp_pteam_mem_alloc' or 'omp_thread_mem_alloc'">;
def warn_omp_used_different_allocator : Warning<
"allocate directive specifies %select{default|'%1'}0 allocator while "
"previously used %select{default|'%3'}2">,
InGroup<OpenMPClauses>;
def note_omp_previous_allocator : Note<
"previous allocator is specified here">;
def err_expected_allocator_clause : Error<"expected an 'allocator' clause "
"inside of the target region; provide an 'allocator' clause or use 'requires'"
" directive with the 'dynamic_allocators' clause">;
def err_expected_allocator_expression : Error<"expected an allocator expression "
"inside of the target region; provide an allocator expression or use 'requires'"
" directive with the 'dynamic_allocators' clause">;
def warn_omp_allocate_thread_on_task_target_directive : Warning<
"allocator with the 'thread' trait access has unspecified behavior on '%0' directive">,
InGroup<OpenMPClauses>;
def err_omp_expected_private_copy_for_allocate : Error<
"the referenced item is not found in any private clause on the same directive">;
def err_omp_stmt_depends_on_loop_counter : Error<
"the loop %select{initializer|condition}0 expression depends on the current loop control variable">;
def err_omp_invariant_dependency : Error<
"expected loop invariant expression">;
def err_omp_invariant_or_linear_dependency : Error<
"expected loop invariant expression or '<invariant1> * %0 + <invariant2>' kind of expression">;
def err_omp_wrong_dependency_iterator_type : Error<
"expected an integer or a pointer type of the outer loop counter '%0' for non-rectangular nests">;
def err_target_unsupported_type
: Error<"%0 requires %select{|%2 bit size}1 %3 %select{|return }4type support,"
" but target '%5' does not support it">;
def err_omp_lambda_capture_in_declare_target_not_to : Error<
"variable captured in declare target region must appear in a to clause">;
def err_omp_device_type_mismatch : Error<
"'device_type(%0)' does not match previously specified 'device_type(%1)' for the same declaration">;
def err_omp_wrong_device_function_call : Error<
"function with 'device_type(%0)' is not available on %select{device|host}1">;
def note_omp_marked_device_type_here : Note<"marked as 'device_type(%0)' here">;
def warn_omp_declare_target_after_first_use : Warning<
"declaration marked as declare target after first use, it may lead to incorrect results">,
InGroup<OpenMPTarget>;
def err_omp_declare_variant_incompat_attributes : Error<
"'#pragma omp declare variant' is not compatible with any target-specific attributes">;
def warn_omp_declare_variant_score_not_constant
: Warning<"score expressions in the OpenMP context selector need to be "
"constant; %0 is not and will be ignored">,
InGroup<SourceUsesOpenMP>;
def err_omp_declare_variant_user_condition_not_constant
: Error<"the user condition in the OpenMP context selector needs to be "
"constant; %0 is not">;
def warn_omp_declare_variant_after_used : Warning<
"'#pragma omp declare variant' cannot be applied for function after first "
"usage; the original function might be used">, InGroup<SourceUsesOpenMP>;
def warn_omp_declare_variant_after_emitted : Warning<
"'#pragma omp declare variant' cannot be applied to the function that was defined already;"
" the original function might be used">, InGroup<SourceUsesOpenMP>;
def err_omp_declare_variant_doesnt_support : Error<
"'#pragma omp declare variant' does not "
"support %select{function templates|virtual functions|"
"deduced return types|constructors|destructors|deleted functions|"
"defaulted functions|constexpr functions|consteval function}0">;
def err_omp_declare_variant_diff : Error<
"function with '#pragma omp declare variant' has a different %select{calling convention"
"|return type|constexpr specification|inline specification|storage class|"
"linkage}0">;
def err_omp_declare_variant_prototype_required : Error<
"function with '#pragma omp declare variant' must have a prototype when "
"'append_args' is used">;
def err_omp_interop_type_not_found : Error<
"'omp_interop_t' must be defined when 'append_args' clause is used; include <omp.h>">;
def err_omp_declare_variant_incompat_types : Error<
"variant in '#pragma omp declare variant' with type %0 is incompatible with"
" type %1%select{| with appended arguments}2">;
def err_omp_declare_variant_same_base_function : Error<
"variant in '#pragma omp declare variant' is the same as the base function">;
def warn_omp_declare_variant_marked_as_declare_variant : Warning<
"variant function in '#pragma omp declare variant' is itself marked as '#pragma omp declare variant'"
>, InGroup<SourceUsesOpenMP>;
def note_omp_marked_declare_variant_here : Note<"marked as 'declare variant' here">;
def err_omp_one_defaultmap_each_category: Error<
"at most one defaultmap clause for each variable-category can appear on the directive">;
def err_omp_lastprivate_conditional_non_scalar : Error<
"expected list item of scalar type in 'lastprivate' clause with 'conditional' modifier"
>;
def err_omp_flush_order_clause_and_list : Error<
"'flush' directive with memory order clause '%0' cannot have the list">;
def note_omp_flush_order_clause_here : Note<
"memory order clause '%0' is specified here">;
def err_omp_non_lvalue_in_map_or_motion_clauses: Error<
"expected addressable lvalue in '%0' clause">;
def err_omp_var_expected : Error<
"expected variable of the '%0' type%select{|, not %2}1">;
def err_omp_non_pointer_type_array_shaping_base : Error<
"expected expression with a pointer to a complete type as a base of an array "
"shaping operation">;
def err_omp_reduction_task_not_parallel_or_worksharing : Error<
"'reduction' clause with 'task' modifier allowed only on non-simd parallel or"
" worksharing constructs">;
def err_omp_expected_array_alloctraits : Error<
"expected constant sized array of 'omp_alloctrait_t' elements, not %0">;
def err_omp_predefined_allocator_with_traits : Error<
"predefined allocator cannot have traits specified">;
def note_omp_predefined_allocator : Note<
"predefined trait '%0' used here">;
def err_omp_nonpredefined_allocator_without_traits : Error<
"non-predefined allocator must have traits specified">;
def err_omp_allocator_used_in_clauses : Error<
"allocators used in 'uses_allocators' clause cannot appear in other "
"data-sharing or data-mapping attribute clauses">;
def err_omp_allocator_not_in_uses_allocators : Error<
"allocator must be specified in the 'uses_allocators' clause">;
def note_omp_protected_structured_block
: Note<"jump bypasses OpenMP structured block">;
def note_omp_exits_structured_block
: Note<"jump exits scope of OpenMP structured block">;
def err_omp_lastprivate_loop_var_non_loop_iteration : Error<
"only loop iteration variables are allowed in 'lastprivate' clause in "
"'omp %0' directives">;
def err_omp_interop_variable_expected : Error<
"expected%select{| non-const}0 variable of type 'omp_interop_t'">;
def err_omp_interop_variable_wrong_type : Error<
"interop variable must be of type 'omp_interop_t'">;
def err_omp_interop_prefer_type : Error<
"prefer_list item must be a string literal or constant integral "
"expression">;
def err_omp_interop_bad_depend_clause : Error<
"'depend' clause requires the 'targetsync' interop type">;
def err_omp_interop_var_multiple_actions : Error<
"interop variable %0 used in multiple action clauses">;
def err_omp_dispatch_statement_call
: Error<"statement after '#pragma omp dispatch' must be a direct call"
" to a target function or an assignment to one">;
def err_omp_unroll_full_variable_trip_count : Error<
"loop to be fully unrolled must have a constant trip count">;
def note_omp_directive_here : Note<"'%0' directive found here">;
def err_omp_instantiation_not_supported
: Error<"instantiation of '%0' not supported yet">;
def err_omp_adjust_arg_multiple_clauses : Error<
"'adjust_arg' argument %0 used in multiple clauses">;
def err_omp_clause_requires_dispatch_construct : Error<
"'%0' clause requires 'dispatch' context selector">;
def err_omp_append_args_with_varargs : Error<
"'append_args' is not allowed with varargs functions">;
def err_openmp_vla_in_task_untied : Error<
"variable length arrays are not supported in OpenMP tasking regions with 'untied' clause">;
def warn_omp_unterminated_declare_target : Warning<
"expected '#pragma omp end declare target' at end of file to match '#pragma omp %0'">,
InGroup<SourceUsesOpenMP>;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
// Objective-C related result type compatibility
def warn_related_result_type_compatibility_class : Warning<
"method is expected to return an instance of its class type "
"%diff{$, but is declared to return $|"
", but is declared to return different type}0,1">;
def warn_related_result_type_compatibility_protocol : Warning<
"protocol method is expected to return an instance of the implementing "
"class, but is declared to return %0">;
def note_related_result_type_family : Note<
"%select{overridden|current}0 method is part of the '%select{|alloc|copy|init|"
"mutableCopy|new|autorelease|dealloc|finalize|release|retain|retainCount|"
"self}1' method family%select{| and is expected to return an instance of its "
"class type}0">;
def note_related_result_type_overridden : Note<
"overridden method returns an instance of its class type">;
def note_related_result_type_inferred : Note<
"%select{class|instance}0 method %1 is assumed to return an instance of "
"its receiver type (%2)">;
def note_related_result_type_explicit : Note<
"%select{overridden|current}0 method is explicitly declared 'instancetype'"
"%select{| and is expected to return an instance of its class type}0">;
def err_invalid_type_for_program_scope_var : Error<
"the %0 type cannot be used to declare a program scope variable">;
}
let CategoryName = "Modules Issue" in {
def err_module_decl_in_module_map_module : Error<
"'module' declaration found while building module from module map">;
def err_module_decl_in_header_module : Error<
"'module' declaration found while building header unit">;
def err_module_interface_implementation_mismatch : Error<
"missing 'export' specifier in module declaration while "
"building module interface">;
def err_current_module_name_mismatch : Error<
"module name '%0' specified on command line does not match name of module">;
def err_module_redefinition : Error<
"redefinition of module '%0'">;
def note_prev_module_definition : Note<"previously defined here">;
def note_prev_module_definition_from_ast_file : Note<"module loaded from '%0'">;
def err_module_not_defined : Error<
"definition of module '%0' is not available; use -fmodule-file= to specify "
"path to precompiled module interface">;
def err_module_redeclaration : Error<
"translation unit contains multiple module declarations">;
def note_prev_module_declaration : Note<"previous module declaration is here">;
def err_module_declaration_missing : Error<
"missing 'export module' declaration in module interface unit">;
def err_module_declaration_missing_after_global_module_introducer : Error<
"missing 'module' declaration at end of global module fragment "
"introduced here">;
def err_module_private_specialization : Error<
"%select{template|partial|member}0 specialization cannot be "
"declared __module_private__">;
def err_module_private_local : Error<
"%select{local variable|parameter|typedef}0 %1 cannot be declared "
"__module_private__">;
def err_module_private_local_class : Error<
"local %select{struct|interface|union|class|enum}0 cannot be declared "
"__module_private__">;
def err_module_unimported_use : Error<
"%select{declaration|definition|default argument|"
"explicit specialization|partial specialization}0 of %1 must be imported "
"from module '%2' before it is required">;
def err_module_unimported_use_header : Error<
"%select{missing '#include'|missing '#include %3'}2; "
"%select{||default argument of |explicit specialization of |"
"partial specialization of }0%1 must be "
"%select{declared|defined|defined|declared|declared}0 "
"before it is used">;
def err_module_unimported_use_multiple : Error<
"%select{declaration|definition|default argument|"
"explicit specialization|partial specialization}0 of %1 must be imported "
"from one of the following modules before it is required:%2">;
def note_unreachable_entity : Note<
"%select{declaration|definition|default argument declared|"
"explicit specialization declared|partial specialization declared}0 here "
"is not %select{visible|reachable|reachable|reachable|reachable|reachable}0">;
def ext_module_import_in_extern_c : ExtWarn<
"import of C++ module '%0' appears within extern \"C\" language linkage "
"specification">, DefaultError,
InGroup<DiagGroup<"module-import-in-extern-c">>;
def err_module_import_not_at_top_level_fatal : Error<
"import of module '%0' appears within %1">, DefaultFatal;
def ext_module_import_not_at_top_level_noop : ExtWarn<
"redundant #include of module '%0' appears within %1">, DefaultError,
InGroup<DiagGroup<"modules-import-nested-redundant">>;
def note_module_import_not_at_top_level : Note<"%0 begins here">;
def err_module_self_import : Error<
"import of module '%0' appears within same top-level module '%1'">;
def err_module_self_import_cxx20 : Error<
"import of module '%0' appears within its own %select{interface|implementation}1">;
def err_module_import_in_implementation : Error<
"@import of module '%0' in implementation of '%1'; use #import">;
// C++ Modules
def err_module_decl_not_at_start : Error<
"module declaration must occur at the start of the translation unit">;
def note_global_module_introducer_missing : Note<
"add 'module;' to the start of the file to introduce a "
"global module fragment">;
def err_export_within_anonymous_namespace : Error<
"export declaration appears within anonymous namespace">;
def note_anonymous_namespace : Note<"anonymous namespace begins here">;
def ext_export_no_name_block : ExtWarn<
"ISO C++20 does not permit %select{an empty|a static_assert}0 declaration "
"to appear in an export block">, InGroup<ExportUnnamed>;
def ext_export_no_names : ExtWarn<
"ISO C++20 does not permit a declaration that does not introduce any names "
"to be exported">, InGroup<ExportUnnamed>;
def introduces_no_names : Error<
"declaration does not introduce any names to be exported">;
def note_export : Note<"export block begins here">;
def err_export_no_name : Error<
"%select{empty|static_assert|asm}0 declaration cannot be exported">;
def ext_export_using_directive : ExtWarn<
"ISO C++20 does not permit using directive to be exported">,
InGroup<DiagGroup<"export-using-directive">>;
def err_export_within_export : Error<
"export declaration appears within another export declaration">;
def err_export_internal : Error<
"declaration of %0 with internal linkage cannot be exported">;
def err_export_using_internal : Error<
"using declaration referring to %1 with %select{internal|module|unknown}0 "
"linkage cannot be exported">;
def err_export_not_in_module_interface : Error<
"export declaration can only be used within a module interface unit"
"%select{ after the module declaration|}0">;
def err_export_partition_impl : Error<
"module partition implementations cannot be exported">;
def err_export_in_private_module_fragment : Error<
"export declaration cannot be used in a private module fragment">;
def note_private_module_fragment : Note<
"private module fragment begins here">;
def err_private_module_fragment_not_module : Error<
"private module fragment declaration with no preceding module declaration">;
def err_private_module_fragment_redefined : Error<
"private module fragment redefined">;
def err_private_module_fragment_not_module_interface : Error<
"private module fragment in module implementation unit">;
def note_not_module_interface_add_export : Note<
"add 'export' here if this is intended to be a module interface unit">;
def ext_equivalent_internal_linkage_decl_in_modules : ExtWarn<
"ambiguous use of internal linkage declaration %0 defined in multiple modules">,
InGroup<DiagGroup<"modules-ambiguous-internal-linkage">>;
def note_equivalent_internal_linkage_decl : Note<
"declared here%select{ in module '%1'|}0">;
def note_redefinition_modules_same_file : Note<
"'%0' included multiple times, additional include site in header from module '%1'">;
def note_redefinition_include_same_file : Note<
"'%0' included multiple times, additional include site here">;
}
let CategoryName = "Coroutines Issue" in {
def err_return_in_coroutine : Error<
"return statement not allowed in coroutine; did you mean 'co_return'?">;
def note_declared_coroutine_here : Note<
"function is a coroutine due to use of '%0' here">;
def err_coroutine_objc_method : Error<
"Objective-C methods as coroutines are not yet supported">;
def err_coroutine_unevaluated_context : Error<
"'%0' cannot be used in an unevaluated context">;
def err_coroutine_within_handler : Error<
"'%0' cannot be used in the handler of a try block">;
def err_coroutine_outside_function : Error<
"'%0' cannot be used outside a function">;
def err_coroutine_invalid_func_context : Error<
"'%1' cannot be used in %select{a constructor|a destructor"
"|the 'main' function|a constexpr function"
"|a function with a deduced return type|a varargs function"
"|a consteval function}0">;
def err_implied_coroutine_type_not_found : Error<
"%0 type was not found; include <coroutine> before defining "
"a coroutine; include <experimental/coroutine> if your version "
"of libcxx is less than 14.0">;
def warn_deprecated_coroutine_namespace : Warning<
"support for std::experimental::%0 will be removed in LLVM 15; "
"use std::%0 instead">,
InGroup<DeprecatedExperimentalCoroutine>;
def err_mixed_use_std_and_experimental_namespace_for_coroutine : Error<
"conflicting mixed use of std and std::experimental namespaces for "
"coroutine components">;
def err_implicit_coroutine_std_nothrow_type_not_found : Error<
"std::nothrow was not found; include <new> before defining a coroutine which "
"uses get_return_object_on_allocation_failure()">;
def err_malformed_std_nothrow : Error<
"std::nothrow must be a valid variable declaration">;
def err_malformed_std_coroutine_handle : Error<
"std::coroutine_handle isn't a class template">;
def err_coroutine_handle_missing_member : Error<
"std::coroutine_handle must have a member named '%0'">;
def err_malformed_std_coroutine_traits : Error<
"std::coroutine_traits isn't a class template">;
def err_implied_std_coroutine_traits_promise_type_not_found : Error<
"this function cannot be a coroutine: %q0 has no member named 'promise_type'">;
def err_implied_std_coroutine_traits_promise_type_not_class : Error<
"this function cannot be a coroutine: %0 is not a class">;
def err_coroutine_promise_type_incomplete : Error<
"this function cannot be a coroutine: %0 is an incomplete type">;
def err_coroutine_type_missing_specialization : Error<
"this function cannot be a coroutine: missing definition of "
"specialization %0">;
def err_coroutine_promise_incompatible_return_functions : Error<
"the coroutine promise type %0 declares both 'return_value' and 'return_void'">;
def note_coroutine_promise_implicit_await_transform_required_here : Note<
"call to 'await_transform' implicitly required by 'co_await' here">;
def note_coroutine_promise_suspend_implicitly_required : Note<
"call to '%select{initial_suspend|final_suspend}0' implicitly "
"required by the %select{initial suspend point|final suspend point}0">;
def err_coroutine_promise_unhandled_exception_required : Error<
"%0 is required to declare the member 'unhandled_exception()'">;
def warn_coroutine_promise_unhandled_exception_required_with_exceptions : Warning<
"%0 is required to declare the member 'unhandled_exception()' when exceptions are enabled">,
InGroup<CoroutineMissingUnhandledException>;
def err_coroutine_promise_get_return_object_on_allocation_failure : Error<
"%0: 'get_return_object_on_allocation_failure()' must be a static member function">;
def err_seh_in_a_coroutine_with_cxx_exceptions : Error<
"cannot use SEH '__try' in a coroutine when C++ exceptions are enabled">;
def err_coroutine_promise_new_requires_nothrow : Error<
"%0 is required to have a non-throwing noexcept specification when the promise "
"type declares 'get_return_object_on_allocation_failure()'">;
def note_coroutine_promise_call_implicitly_required : Note<
"call to %0 implicitly required by coroutine function here">;
def err_await_suspend_invalid_return_type : Error<
"return type of 'await_suspend' is required to be 'void' or 'bool' (have %0)"
>;
def note_await_ready_no_bool_conversion : Note<
"return type of 'await_ready' is required to be contextually convertible to 'bool'"
>;
def warn_coroutine_handle_address_invalid_return_type : Warning <
"return type of 'coroutine_handle<>::address should be 'void*' (have %0) in order to get capability with existing async C API.">,
InGroup<Coroutine>;
def err_coroutine_promise_final_suspend_requires_nothrow : Error<
"the expression 'co_await __promise.final_suspend()' is required to be non-throwing"
>;
def note_coroutine_function_declare_noexcept : Note<
"must be declared with 'noexcept'"
>;
def warn_always_inline_coroutine : Warning<
"this coroutine may be split into pieces; not every piece is guaranteed to be inlined"
>,
InGroup<AlwaysInlineCoroutine>;
def err_coroutine_unusable_new : Error<
"'operator new' provided by %0 is not usable with the function signature of %1"
>;
} // end of coroutines issue category
let CategoryName = "Documentation Issue" in {
def warn_not_a_doxygen_trailing_member_comment : Warning<
"not a Doxygen trailing comment">, InGroup<Documentation>, DefaultIgnore;
} // end of documentation issue category
let CategoryName = "Nullability Issue" in {
def warn_mismatched_nullability_attr : Warning<
"nullability specifier %0 conflicts with existing specifier %1">,
InGroup<Nullability>;
def warn_nullability_declspec : Warning<
"nullability specifier %0 cannot be applied "
"to non-pointer type %1; did you mean to apply the specifier to the "
"%select{pointer|block pointer|member pointer|function pointer|"
"member function pointer}2?">,
InGroup<NullabilityDeclSpec>,
DefaultError;
def note_nullability_here : Note<"%0 specified here">;
def err_nullability_nonpointer : Error<
"nullability specifier %0 cannot be applied to non-pointer type %1">;
def warn_nullability_lost : Warning<
"implicit conversion from nullable pointer %0 to non-nullable pointer "
"type %1">,
InGroup<NullableToNonNullConversion>, DefaultIgnore;
def warn_zero_as_null_pointer_constant : Warning<
"zero as null pointer constant">,
InGroup<DiagGroup<"zero-as-null-pointer-constant">>, DefaultIgnore;
def err_nullability_cs_multilevel : Error<
"nullability keyword %0 cannot be applied to multi-level pointer type %1">;
def note_nullability_type_specifier : Note<
"use nullability type specifier %0 to affect the innermost "
"pointer type of %1">;
def warn_null_resettable_setter : Warning<
"synthesized setter %0 for null_resettable property %1 does not handle nil">,
InGroup<Nullability>;
def warn_nullability_missing : Warning<
"%select{pointer|block pointer|member pointer}0 is missing a nullability "
"type specifier (_Nonnull, _Nullable, or _Null_unspecified)">,
InGroup<NullabilityCompleteness>;
def warn_nullability_missing_array : Warning<
"array parameter is missing a nullability type specifier (_Nonnull, "
"_Nullable, or _Null_unspecified)">,
InGroup<NullabilityCompletenessOnArrays>;
def note_nullability_fix_it : Note<
"insert '%select{_Nonnull|_Nullable|_Null_unspecified}0' if the "
"%select{pointer|block pointer|member pointer|array parameter}1 "
"%select{should never be null|may be null|should not declare nullability}0">;
def warn_nullability_inferred_on_nested_type : Warning<
"inferring '_Nonnull' for pointer type within %select{array|reference}0 is "
"deprecated">,
InGroup<NullabilityInferredOnNestedType>;
def err_objc_type_arg_explicit_nullability : Error<
"type argument %0 cannot explicitly specify nullability">;
def err_objc_type_param_bound_explicit_nullability : Error<
"type parameter %0 bound %1 cannot explicitly specify nullability">;
}
let CategoryName = "Generics Issue" in {
def err_objc_type_param_bound_nonobject : Error<
"type bound %0 for type parameter %1 is not an Objective-C pointer type">;
def err_objc_type_param_bound_missing_pointer : Error<
"missing '*' in type bound %0 for type parameter %1">;
def err_objc_type_param_bound_qualified : Error<
"type bound %1 for type parameter %0 cannot be qualified with '%2'">;
def err_objc_type_param_redecl : Error<
"redeclaration of type parameter %0">;
def err_objc_type_param_arity_mismatch : Error<
"%select{forward class declaration|class definition|category|extension}0 has "
"too %select{few|many}1 type parameters (expected %2, have %3)">;
def err_objc_type_param_bound_conflict : Error<
"type bound %0 for type parameter %1 conflicts with "
"%select{implicit|previous}2 bound %3%select{for type parameter %5|}4">;
def err_objc_type_param_variance_conflict : Error<
"%select{in|co|contra}0variant type parameter %1 conflicts with previous "
"%select{in|co|contra}2variant type parameter %3">;
def note_objc_type_param_here : Note<"type parameter %0 declared here">;
def err_objc_type_param_bound_missing : Error<
"missing type bound %0 for type parameter %1 in %select{@interface|@class}2">;
def err_objc_parameterized_category_nonclass : Error<
"%select{extension|category}0 of non-parameterized class %1 cannot have type "
"parameters">;
def err_objc_parameterized_forward_class : Error<
"forward declaration of non-parameterized class %0 cannot have type "
"parameters">;
def err_objc_parameterized_forward_class_first : Error<
"class %0 previously declared with type parameters">;
def err_objc_type_arg_missing_star : Error<
"type argument %0 must be a pointer (requires a '*')">;
def err_objc_type_arg_qualified : Error<
"type argument %0 cannot be qualified with '%1'">;
def err_objc_type_arg_missing : Error<
"no type or protocol named %0">;
def err_objc_type_args_and_protocols : Error<
"angle brackets contain both a %select{type|protocol}0 (%1) and a "
"%select{protocol|type}0 (%2)">;
def err_objc_type_args_non_class : Error<
"type arguments cannot be applied to non-class type %0">;
def err_objc_type_args_non_parameterized_class : Error<
"type arguments cannot be applied to non-parameterized class %0">;
def err_objc_type_args_specialized_class : Error<
"type arguments cannot be applied to already-specialized class type %0">;
def err_objc_type_args_wrong_arity : Error<
"too %select{many|few}0 type arguments for class %1 (have %2, expected %3)">;
}
def err_objc_type_arg_not_id_compatible : Error<
"type argument %0 is neither an Objective-C object nor a block type">;
def err_objc_type_arg_does_not_match_bound : Error<
"type argument %0 does not satisfy the bound (%1) of type parameter %2">;
def warn_objc_redundant_qualified_class_type : Warning<
"parameterized class %0 already conforms to the protocols listed; did you "
"forget a '*'?">, InGroup<ObjCProtocolQualifiers>;
def warn_block_literal_attributes_on_omitted_return_type : Warning<
"attribute %0 ignored, because it cannot be applied to omitted return type">,
InGroup<IgnoredAttributes>;
def warn_block_literal_qualifiers_on_omitted_return_type : Warning<
"'%0' qualifier on omitted return type %1 has no effect">,
InGroup<IgnoredQualifiers>;
def warn_shadow_field : Warning<
"%select{parameter|non-static data member}3 %0 %select{|of %1 }3shadows "
"member inherited from type %2">, InGroup<ShadowField>, DefaultIgnore;
def note_shadow_field : Note<"declared here">;
def err_multiversion_required_in_redecl : Error<
"function declaration is missing %select{'target'|'cpu_specific' or "
"'cpu_dispatch'}0 attribute in a multiversioned function">;
def note_multiversioning_caused_here : Note<
"function multiversioning caused by this declaration">;
def err_multiversion_after_used : Error<
"function declaration cannot become a multiversioned function after first "
"usage">;
def err_bad_multiversion_option : Error<
"function multiversioning doesn't support %select{feature|architecture}0 "
"'%1'">;
def err_multiversion_duplicate : Error<
"multiversioned function redeclarations require identical target attributes">;
def err_multiversion_noproto : Error<
"multiversioned function must have a prototype">;
def err_multiversion_disallowed_other_attr
: Error<"attribute "
"'%select{|target|cpu_specific|cpu_dispatch|target_clones}0' "
"multiversioning cannot be combined"
" with attribute %1">;
def err_multiversion_diff : Error<
"multiversioned function declaration has a different %select{calling convention"
"|return type|constexpr specification|inline specification|linkage|"
"language linkage}0">;
def err_multiversion_doesnt_support
: Error<"attribute "
"'%select{|target|cpu_specific|cpu_dispatch|target_clones}0' "
"multiversioned functions do not "
"yet support %select{function templates|virtual functions|"
"deduced return types|constructors|destructors|deleted functions|"
"defaulted functions|constexpr functions|consteval "
"function|lambdas}1">;
def err_multiversion_not_allowed_on_main : Error<
"'main' cannot be a multiversioned function">;
def err_multiversion_not_supported : Error<
"function multiversioning is not supported on the current target">;
def err_multiversion_types_mixed : Error<
"multiversioning attributes cannot be combined">;
def err_cpu_dispatch_mismatch : Error<
"'cpu_dispatch' function redeclared with different CPUs">;
def err_cpu_specific_multiple_defs : Error<
"multiple 'cpu_specific' functions cannot specify the same CPU: %0">;
def warn_multiversion_duplicate_entries : Warning<
"CPU list contains duplicate entries; attribute ignored">,
InGroup<FunctionMultiVersioning>;
def warn_dispatch_body_ignored : Warning<
"body of cpu_dispatch function will be ignored">,
InGroup<FunctionMultiVersioning>;
def err_target_clone_must_have_default
: Error<"'target_clones' multiversioning requires a default target">;
def err_target_clone_doesnt_match
: Error<"'target_clones' attribute does not match previous declaration">;
def warn_target_clone_mixed_values
: ExtWarn<
"mixing 'target_clones' specifier mechanisms is permitted for GCC "
"compatibility; use a comma separated sequence of string literals, "
"or a string literal containing a comma-separated list of versions">,
InGroup<TargetClonesMixedSpecifiers>;
def warn_target_clone_duplicate_options
: Warning<"version list contains duplicate entries">,
InGroup<FunctionMultiVersioning>;
// three-way comparison operator diagnostics
def err_implied_comparison_category_type_not_found : Error<
"cannot %select{use builtin operator '<=>'|default 'operator<=>'}1 "
"because type '%0' was not found; include <compare>">;
def err_spaceship_argument_narrowing : Error<
"argument to 'operator<=>' "
"%select{cannot be narrowed from type %1 to %2|"
"evaluates to %1, which cannot be narrowed to type %2}0">;
def err_std_compare_type_not_supported : Error<
"standard library implementation of %0 is not supported; "
"%select{member '%2' does not have expected form|"
"member '%2' is missing|"
"the type is not trivially copyable|"
"the type does not have the expected form}1">;
def note_rewriting_operator_as_spaceship : Note<
"while rewriting comparison as call to 'operator<=>' declared here">;
def err_three_way_vector_comparison : Error<
"three-way comparison between vectors is not supported">;
// Memory Tagging Extensions (MTE) diagnostics
def err_memtag_arg_null_or_pointer : Error<
"%0 argument of MTE builtin function must be a null or a pointer (%1 invalid)">;
def err_memtag_any2arg_pointer : Error<
"at least one argument of MTE builtin function must be a pointer (%0, %1 invalid)">;
def err_memtag_arg_must_be_pointer : Error<
"%0 argument of MTE builtin function must be a pointer (%1 invalid)">;
def err_memtag_arg_must_be_integer : Error<
"%0 argument of MTE builtin function must be an integer type (%1 invalid)">;
def warn_dereference_of_noderef_type : Warning<
"dereferencing %0; was declared with a 'noderef' type">, InGroup<NoDeref>;
def warn_dereference_of_noderef_type_no_decl : Warning<
"dereferencing expression marked as 'noderef'">, InGroup<NoDeref>;
def warn_noderef_on_non_pointer_or_array : Warning<
"'noderef' can only be used on an array or pointer type">, InGroup<IgnoredAttributes>;
def warn_noderef_to_dereferenceable_pointer : Warning<
"casting to dereferenceable pointer removes 'noderef' attribute">, InGroup<NoDeref>;
def err_builtin_launder_invalid_arg : Error<
"%select{non-pointer|function pointer|void pointer}0 argument to "
"'__builtin_launder' is not allowed">;
def err_builtin_invalid_arg_type: Error <
"%ordinal0 argument must be a "
"%select{vector, integer or floating point type|matrix|"
"pointer to a valid matrix element type|"
"signed integer or floating point type|vector type|"
"floating point type|"
"vector of integers}1 (was %2)">;
def err_builtin_matrix_disabled: Error<
"matrix types extension is disabled. Pass -fenable-matrix to enable it">;
def err_matrix_index_not_integer: Error<
"matrix %select{row|column}0 index is not an integer">;
def err_matrix_index_outside_range: Error<
"matrix %select{row|column}0 index is outside the allowed range [0, %1)">;
def err_matrix_incomplete_index: Error<
"single subscript expressions are not allowed for matrix values">;
def err_matrix_separate_incomplete_index: Error<
"matrix row and column subscripts cannot be separated by any expression">;
def err_matrix_subscript_comma: Error<
"comma expressions are not allowed as indices in matrix subscript expressions">;
def err_builtin_matrix_scalar_unsigned_arg: Error<
"%0 argument must be a constant unsigned integer expression">;
def err_builtin_matrix_pointer_arg_mismatch: Error<
"the pointee of the 2nd argument must match the element type of the 1st argument (%0 != %1)">;
def err_builtin_matrix_store_to_const: Error<
"cannot store matrix to read-only pointer">;
def err_builtin_matrix_stride_too_small: Error<
"stride must be greater or equal to the number of rows">;
def err_builtin_matrix_invalid_dimension: Error<
"%0 dimension is outside the allowed range [1, %1]">;
def warn_mismatched_import : Warning<
"import %select{module|name}0 (%1) does not match the import %select{module|name}0 (%2) of the "
"previous declaration">,
InGroup<IgnoredAttributes>;
def warn_import_on_definition : Warning<
"import %select{module|name}0 cannot be applied to a function with a definition">,
InGroup<IgnoredAttributes>;
def err_preserve_field_info_not_field : Error<
"__builtin_preserve_field_info argument %0 not a field access">;
def err_preserve_field_info_not_const: Error<
"__builtin_preserve_field_info argument %0 not a constant">;
def err_btf_type_id_not_const: Error<
"__builtin_btf_type_id argument %0 not a constant">;
def err_preserve_type_info_invalid : Error<
"__builtin_preserve_type_info argument %0 invalid">;
def err_preserve_type_info_not_const: Error<
"__builtin_preserve_type_info argument %0 not a constant">;
def err_preserve_enum_value_invalid : Error<
"__builtin_preserve_enum_value argument %0 invalid">;
def err_preserve_enum_value_not_const: Error<
"__builtin_preserve_enum_value argument %0 not a constant">;
def err_bit_cast_non_trivially_copyable : Error<
"__builtin_bit_cast %select{source|destination}0 type must be trivially copyable">;
def err_bit_cast_type_size_mismatch : Error<
"__builtin_bit_cast source size does not equal destination size (%0 vs %1)">;
// SYCL-specific diagnostics
def warn_sycl_kernel_num_of_template_params : Warning<
"'sycl_kernel' attribute only applies to a function template with at least"
" two template parameters">, InGroup<IgnoredAttributes>;
def warn_sycl_kernel_invalid_template_param_type : Warning<
"template parameter of a function template with the 'sycl_kernel' attribute"
" cannot be a non-type template parameter">, InGroup<IgnoredAttributes>;
def warn_sycl_kernel_num_of_function_params : Warning<
"function template with 'sycl_kernel' attribute must have a single parameter">,
InGroup<IgnoredAttributes>;
def warn_sycl_kernel_return_type : Warning<
"function template with 'sycl_kernel' attribute must have a 'void' return type">,
InGroup<IgnoredAttributes>;
def err_sycl_special_type_num_init_method : Error<
"types with 'sycl_special_class' attribute must have one and only one '__init' "
"method defined">;
def err_bit_int_bad_size : Error<"%select{signed|unsigned}0 _BitInt must "
"have a bit size of at least %select{2|1}0">;
def err_bit_int_max_size : Error<"%select{signed|unsigned}0 _BitInt of bit "
"sizes greater than %1 not supported">;
// errors of expect.with.probability
def err_probability_not_constant_float : Error<
"probability argument to __builtin_expect_with_probability must be constant "
"floating-point expression">;
def err_probability_out_of_range : Error<
"probability argument to __builtin_expect_with_probability is outside the "
"range [0.0, 1.0]">;
// TCB warnings
def err_tcb_conflicting_attributes : Error<
"attributes '%0(\"%2\")' and '%1(\"%2\")' are mutually exclusive">;
def warn_tcb_enforcement_violation : Warning<
"calling %0 is a violation of trusted computing base '%1'">,
InGroup<DiagGroup<"tcb-enforcement">>;
// RISC-V builtin required extension warning
def err_riscv_builtin_requires_extension : Error<
"builtin requires at least one of the following extensions support to be enabled : %0">;
def err_riscv_builtin_invalid_lmul : Error<
"LMUL argument must be in the range [0,3] or [5,7]">;
def err_std_source_location_impl_not_found : Error<
"'std::source_location::__impl' was not found; it must be defined before '__builtin_source_location' is called">;
def err_std_source_location_impl_malformed : Error<
"'std::source_location::__impl' must be standard-layout and have only two 'const char *' fields '_M_file_name' and '_M_function_name', and two integral fields '_M_line' and '_M_column'">;
// HLSL Diagnostics
def err_hlsl_attr_unsupported_in_stage : Error<"attribute %0 is unsupported in %select{Pixel|Vertex|Geometry|Hull|Domain|Compute|Library|RayGeneration|Intersection|AnyHit|ClosestHit|Miss|Callable|Mesh|Amplification|Invalid}1 shaders, requires %2">;
def err_hlsl_numthreads_argument_oor : Error<"argument '%select{X|Y|Z}0' to numthreads attribute cannot exceed %1">;
def err_hlsl_numthreads_invalid : Error<"total number of threads cannot exceed %0">;
def err_hlsl_attribute_param_mismatch : Error<"%0 attribute parameters do not match the previous declaration">;
def err_hlsl_pointers_unsupported : Error<
"%select{pointers|references}0 are unsupported in HLSL">;
def err_hlsl_operator_unsupported : Error<
"the '%select{&|*|->}0' operator is unsupported in HLSL">;
// Layout randomization diagnostics.
def err_non_designated_init_used : Error<
"a randomized struct can only be initialized with a designated initializer">;
def err_cast_from_randomized_struct : Error<
"casting from randomized structure pointer type %0 to %1">;
} // end of sema component.
diff --git a/contrib/llvm-project/clang/lib/AST/StmtPrinter.cpp b/contrib/llvm-project/clang/lib/AST/StmtPrinter.cpp
index 8d778500d103..625048c69a86 100644
--- a/contrib/llvm-project/clang/lib/AST/StmtPrinter.cpp
+++ b/contrib/llvm-project/clang/lib/AST/StmtPrinter.cpp
@@ -1,2757 +1,2757 @@
//===- StmtPrinter.cpp - Printing implementation for Stmt ASTs ------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the Stmt::dumpPretty/Stmt::printPretty methods, which
// pretty print the AST back out to C code.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/OpenMPClause.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/ExpressionTraits.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/JsonSupport.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Lambda.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/TypeTraits.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <string>
using namespace clang;
//===----------------------------------------------------------------------===//
// StmtPrinter Visitor
//===----------------------------------------------------------------------===//
namespace {
class StmtPrinter : public StmtVisitor<StmtPrinter> {
raw_ostream &OS;
unsigned IndentLevel;
PrinterHelper* Helper;
PrintingPolicy Policy;
std::string NL;
const ASTContext *Context;
public:
StmtPrinter(raw_ostream &os, PrinterHelper *helper,
const PrintingPolicy &Policy, unsigned Indentation = 0,
StringRef NL = "\n", const ASTContext *Context = nullptr)
: OS(os), IndentLevel(Indentation), Helper(helper), Policy(Policy),
NL(NL), Context(Context) {}
void PrintStmt(Stmt *S) { PrintStmt(S, Policy.Indentation); }
void PrintStmt(Stmt *S, int SubIndent) {
IndentLevel += SubIndent;
if (S && isa<Expr>(S)) {
// If this is an expr used in a stmt context, indent and newline it.
Indent();
Visit(S);
OS << ";" << NL;
} else if (S) {
Visit(S);
} else {
Indent() << "<<<NULL STATEMENT>>>" << NL;
}
IndentLevel -= SubIndent;
}
void PrintInitStmt(Stmt *S, unsigned PrefixWidth) {
// FIXME: Cope better with odd prefix widths.
IndentLevel += (PrefixWidth + 1) / 2;
if (auto *DS = dyn_cast<DeclStmt>(S))
PrintRawDeclStmt(DS);
else
PrintExpr(cast<Expr>(S));
OS << "; ";
IndentLevel -= (PrefixWidth + 1) / 2;
}
void PrintControlledStmt(Stmt *S) {
if (auto *CS = dyn_cast<CompoundStmt>(S)) {
OS << " ";
PrintRawCompoundStmt(CS);
OS << NL;
} else {
OS << NL;
PrintStmt(S);
}
}
void PrintRawCompoundStmt(CompoundStmt *S);
void PrintRawDecl(Decl *D);
void PrintRawDeclStmt(const DeclStmt *S);
void PrintRawIfStmt(IfStmt *If);
void PrintRawCXXCatchStmt(CXXCatchStmt *Catch);
void PrintCallArgs(CallExpr *E);
void PrintRawSEHExceptHandler(SEHExceptStmt *S);
void PrintRawSEHFinallyStmt(SEHFinallyStmt *S);
void PrintOMPExecutableDirective(OMPExecutableDirective *S,
bool ForceNoStmt = false);
void PrintFPPragmas(CompoundStmt *S);
void PrintExpr(Expr *E) {
if (E)
Visit(E);
else
OS << "<null expr>";
}
raw_ostream &Indent(int Delta = 0) {
for (int i = 0, e = IndentLevel+Delta; i < e; ++i)
OS << " ";
return OS;
}
void Visit(Stmt* S) {
if (Helper && Helper->handledStmt(S,OS))
return;
else StmtVisitor<StmtPrinter>::Visit(S);
}
void VisitStmt(Stmt *Node) LLVM_ATTRIBUTE_UNUSED {
Indent() << "<<unknown stmt type>>" << NL;
}
void VisitExpr(Expr *Node) LLVM_ATTRIBUTE_UNUSED {
OS << "<<unknown expr type>>";
}
void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
#define ABSTRACT_STMT(CLASS)
#define STMT(CLASS, PARENT) \
void Visit##CLASS(CLASS *Node);
#include "clang/AST/StmtNodes.inc"
};
} // namespace
//===----------------------------------------------------------------------===//
// Stmt printing methods.
//===----------------------------------------------------------------------===//
/// PrintRawCompoundStmt - Print a compound stmt without indenting the {, and
/// with no newline after the }.
void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) {
OS << "{" << NL;
PrintFPPragmas(Node);
for (auto *I : Node->body())
PrintStmt(I);
Indent() << "}";
}
void StmtPrinter::PrintFPPragmas(CompoundStmt *S) {
if (!S->hasStoredFPFeatures())
return;
FPOptionsOverride FPO = S->getStoredFPFeatures();
bool FEnvAccess = false;
if (FPO.hasAllowFEnvAccessOverride()) {
FEnvAccess = FPO.getAllowFEnvAccessOverride();
Indent() << "#pragma STDC FENV_ACCESS " << (FEnvAccess ? "ON" : "OFF")
<< NL;
}
if (FPO.hasSpecifiedExceptionModeOverride()) {
LangOptions::FPExceptionModeKind EM =
FPO.getSpecifiedExceptionModeOverride();
if (!FEnvAccess || EM != LangOptions::FPE_Strict) {
Indent() << "#pragma clang fp exceptions(";
switch (FPO.getSpecifiedExceptionModeOverride()) {
default:
break;
case LangOptions::FPE_Ignore:
OS << "ignore";
break;
case LangOptions::FPE_MayTrap:
OS << "maytrap";
break;
case LangOptions::FPE_Strict:
OS << "strict";
break;
}
OS << ")\n";
}
}
if (FPO.hasConstRoundingModeOverride()) {
LangOptions::RoundingMode RM = FPO.getConstRoundingModeOverride();
Indent() << "#pragma STDC FENV_ROUND ";
switch (RM) {
case llvm::RoundingMode::TowardZero:
OS << "FE_TOWARDZERO";
break;
case llvm::RoundingMode::NearestTiesToEven:
OS << "FE_TONEAREST";
break;
case llvm::RoundingMode::TowardPositive:
OS << "FE_UPWARD";
break;
case llvm::RoundingMode::TowardNegative:
OS << "FE_DOWNWARD";
break;
case llvm::RoundingMode::NearestTiesToAway:
OS << "FE_TONEARESTFROMZERO";
break;
case llvm::RoundingMode::Dynamic:
OS << "FE_DYNAMIC";
break;
default:
llvm_unreachable("Invalid rounding mode");
}
OS << NL;
}
}
void StmtPrinter::PrintRawDecl(Decl *D) {
D->print(OS, Policy, IndentLevel);
}
void StmtPrinter::PrintRawDeclStmt(const DeclStmt *S) {
SmallVector<Decl *, 2> Decls(S->decls());
Decl::printGroup(Decls.data(), Decls.size(), OS, Policy, IndentLevel);
}
void StmtPrinter::VisitNullStmt(NullStmt *Node) {
Indent() << ";" << NL;
}
void StmtPrinter::VisitDeclStmt(DeclStmt *Node) {
Indent();
PrintRawDeclStmt(Node);
OS << ";" << NL;
}
void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) {
Indent();
PrintRawCompoundStmt(Node);
OS << "" << NL;
}
void StmtPrinter::VisitCaseStmt(CaseStmt *Node) {
Indent(-1) << "case ";
PrintExpr(Node->getLHS());
if (Node->getRHS()) {
OS << " ... ";
PrintExpr(Node->getRHS());
}
OS << ":" << NL;
PrintStmt(Node->getSubStmt(), 0);
}
void StmtPrinter::VisitDefaultStmt(DefaultStmt *Node) {
Indent(-1) << "default:" << NL;
PrintStmt(Node->getSubStmt(), 0);
}
void StmtPrinter::VisitLabelStmt(LabelStmt *Node) {
Indent(-1) << Node->getName() << ":" << NL;
PrintStmt(Node->getSubStmt(), 0);
}
void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) {
for (const auto *Attr : Node->getAttrs()) {
Attr->printPretty(OS, Policy);
}
PrintStmt(Node->getSubStmt(), 0);
}
void StmtPrinter::PrintRawIfStmt(IfStmt *If) {
if (If->isConsteval()) {
OS << "if ";
if (If->isNegatedConsteval())
OS << "!";
OS << "consteval";
OS << NL;
PrintStmt(If->getThen());
if (Stmt *Else = If->getElse()) {
Indent();
OS << "else";
PrintStmt(Else);
OS << NL;
}
return;
}
OS << "if (";
if (If->getInit())
PrintInitStmt(If->getInit(), 4);
if (const DeclStmt *DS = If->getConditionVariableDeclStmt())
PrintRawDeclStmt(DS);
else
PrintExpr(If->getCond());
OS << ')';
if (auto *CS = dyn_cast<CompoundStmt>(If->getThen())) {
OS << ' ';
PrintRawCompoundStmt(CS);
OS << (If->getElse() ? " " : NL);
} else {
OS << NL;
PrintStmt(If->getThen());
if (If->getElse()) Indent();
}
if (Stmt *Else = If->getElse()) {
OS << "else";
if (auto *CS = dyn_cast<CompoundStmt>(Else)) {
OS << ' ';
PrintRawCompoundStmt(CS);
OS << NL;
} else if (auto *ElseIf = dyn_cast<IfStmt>(Else)) {
OS << ' ';
PrintRawIfStmt(ElseIf);
} else {
OS << NL;
PrintStmt(If->getElse());
}
}
}
void StmtPrinter::VisitIfStmt(IfStmt *If) {
Indent();
PrintRawIfStmt(If);
}
void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) {
Indent() << "switch (";
if (Node->getInit())
PrintInitStmt(Node->getInit(), 8);
if (const DeclStmt *DS = Node->getConditionVariableDeclStmt())
PrintRawDeclStmt(DS);
else
PrintExpr(Node->getCond());
OS << ")";
PrintControlledStmt(Node->getBody());
}
void StmtPrinter::VisitWhileStmt(WhileStmt *Node) {
Indent() << "while (";
if (const DeclStmt *DS = Node->getConditionVariableDeclStmt())
PrintRawDeclStmt(DS);
else
PrintExpr(Node->getCond());
OS << ")" << NL;
PrintStmt(Node->getBody());
}
void StmtPrinter::VisitDoStmt(DoStmt *Node) {
Indent() << "do ";
if (auto *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
PrintRawCompoundStmt(CS);
OS << " ";
} else {
OS << NL;
PrintStmt(Node->getBody());
Indent();
}
OS << "while (";
PrintExpr(Node->getCond());
OS << ");" << NL;
}
void StmtPrinter::VisitForStmt(ForStmt *Node) {
Indent() << "for (";
if (Node->getInit())
PrintInitStmt(Node->getInit(), 5);
else
OS << (Node->getCond() ? "; " : ";");
if (Node->getCond())
PrintExpr(Node->getCond());
OS << ";";
if (Node->getInc()) {
OS << " ";
PrintExpr(Node->getInc());
}
OS << ")";
PrintControlledStmt(Node->getBody());
}
void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) {
Indent() << "for (";
if (auto *DS = dyn_cast<DeclStmt>(Node->getElement()))
PrintRawDeclStmt(DS);
else
PrintExpr(cast<Expr>(Node->getElement()));
OS << " in ";
PrintExpr(Node->getCollection());
OS << ")";
PrintControlledStmt(Node->getBody());
}
void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) {
Indent() << "for (";
if (Node->getInit())
PrintInitStmt(Node->getInit(), 5);
PrintingPolicy SubPolicy(Policy);
SubPolicy.SuppressInitializers = true;
Node->getLoopVariable()->print(OS, SubPolicy, IndentLevel);
OS << " : ";
PrintExpr(Node->getRangeInit());
OS << ")";
PrintControlledStmt(Node->getBody());
}
void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) {
Indent();
if (Node->isIfExists())
OS << "__if_exists (";
else
OS << "__if_not_exists (";
if (NestedNameSpecifier *Qualifier
= Node->getQualifierLoc().getNestedNameSpecifier())
Qualifier->print(OS, Policy);
OS << Node->getNameInfo() << ") ";
PrintRawCompoundStmt(Node->getSubStmt());
}
void StmtPrinter::VisitGotoStmt(GotoStmt *Node) {
Indent() << "goto " << Node->getLabel()->getName() << ";";
if (Policy.IncludeNewlines) OS << NL;
}
void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) {
Indent() << "goto *";
PrintExpr(Node->getTarget());
OS << ";";
if (Policy.IncludeNewlines) OS << NL;
}
void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) {
Indent() << "continue;";
if (Policy.IncludeNewlines) OS << NL;
}
void StmtPrinter::VisitBreakStmt(BreakStmt *Node) {
Indent() << "break;";
if (Policy.IncludeNewlines) OS << NL;
}
void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) {
Indent() << "return";
if (Node->getRetValue()) {
OS << " ";
PrintExpr(Node->getRetValue());
}
OS << ";";
if (Policy.IncludeNewlines) OS << NL;
}
void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
Indent() << "asm ";
if (Node->isVolatile())
OS << "volatile ";
if (Node->isAsmGoto())
OS << "goto ";
OS << "(";
VisitStringLiteral(Node->getAsmString());
// Outputs
if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 ||
Node->getNumClobbers() != 0 || Node->getNumLabels() != 0)
OS << " : ";
for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) {
if (i != 0)
OS << ", ";
if (!Node->getOutputName(i).empty()) {
OS << '[';
OS << Node->getOutputName(i);
OS << "] ";
}
VisitStringLiteral(Node->getOutputConstraintLiteral(i));
OS << " (";
Visit(Node->getOutputExpr(i));
OS << ")";
}
// Inputs
if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0 ||
Node->getNumLabels() != 0)
OS << " : ";
for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) {
if (i != 0)
OS << ", ";
if (!Node->getInputName(i).empty()) {
OS << '[';
OS << Node->getInputName(i);
OS << "] ";
}
VisitStringLiteral(Node->getInputConstraintLiteral(i));
OS << " (";
Visit(Node->getInputExpr(i));
OS << ")";
}
// Clobbers
if (Node->getNumClobbers() != 0 || Node->getNumLabels())
OS << " : ";
for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) {
if (i != 0)
OS << ", ";
VisitStringLiteral(Node->getClobberStringLiteral(i));
}
// Labels
if (Node->getNumLabels() != 0)
OS << " : ";
for (unsigned i = 0, e = Node->getNumLabels(); i != e; ++i) {
if (i != 0)
OS << ", ";
OS << Node->getLabelName(i);
}
OS << ");";
if (Policy.IncludeNewlines) OS << NL;
}
void StmtPrinter::VisitMSAsmStmt(MSAsmStmt *Node) {
// FIXME: Implement MS style inline asm statement printer.
Indent() << "__asm ";
if (Node->hasBraces())
OS << "{" << NL;
OS << Node->getAsmString() << NL;
if (Node->hasBraces())
Indent() << "}" << NL;
}
void StmtPrinter::VisitCapturedStmt(CapturedStmt *Node) {
PrintStmt(Node->getCapturedDecl()->getBody());
}
void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
Indent() << "@try";
if (auto *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) {
PrintRawCompoundStmt(TS);
OS << NL;
}
for (ObjCAtCatchStmt *catchStmt : Node->catch_stmts()) {
Indent() << "@catch(";
if (Decl *DS = catchStmt->getCatchParamDecl())
PrintRawDecl(DS);
OS << ")";
if (auto *CS = dyn_cast<CompoundStmt>(catchStmt->getCatchBody())) {
PrintRawCompoundStmt(CS);
OS << NL;
}
}
if (auto *FS = static_cast<ObjCAtFinallyStmt *>(Node->getFinallyStmt())) {
Indent() << "@finally";
PrintRawCompoundStmt(dyn_cast<CompoundStmt>(FS->getFinallyBody()));
OS << NL;
}
}
void StmtPrinter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Node) {
}
void StmtPrinter::VisitObjCAtCatchStmt (ObjCAtCatchStmt *Node) {
Indent() << "@catch (...) { /* todo */ } " << NL;
}
void StmtPrinter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *Node) {
Indent() << "@throw";
if (Node->getThrowExpr()) {
OS << " ";
PrintExpr(Node->getThrowExpr());
}
OS << ";" << NL;
}
void StmtPrinter::VisitObjCAvailabilityCheckExpr(
ObjCAvailabilityCheckExpr *Node) {
OS << "@available(...)";
}
void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) {
Indent() << "@synchronized (";
PrintExpr(Node->getSynchExpr());
OS << ")";
PrintRawCompoundStmt(Node->getSynchBody());
OS << NL;
}
void StmtPrinter::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *Node) {
Indent() << "@autoreleasepool";
PrintRawCompoundStmt(dyn_cast<CompoundStmt>(Node->getSubStmt()));
OS << NL;
}
void StmtPrinter::PrintRawCXXCatchStmt(CXXCatchStmt *Node) {
OS << "catch (";
if (Decl *ExDecl = Node->getExceptionDecl())
PrintRawDecl(ExDecl);
else
OS << "...";
OS << ") ";
PrintRawCompoundStmt(cast<CompoundStmt>(Node->getHandlerBlock()));
}
void StmtPrinter::VisitCXXCatchStmt(CXXCatchStmt *Node) {
Indent();
PrintRawCXXCatchStmt(Node);
OS << NL;
}
void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) {
Indent() << "try ";
PrintRawCompoundStmt(Node->getTryBlock());
for (unsigned i = 0, e = Node->getNumHandlers(); i < e; ++i) {
OS << " ";
PrintRawCXXCatchStmt(Node->getHandler(i));
}
OS << NL;
}
void StmtPrinter::VisitSEHTryStmt(SEHTryStmt *Node) {
Indent() << (Node->getIsCXXTry() ? "try " : "__try ");
PrintRawCompoundStmt(Node->getTryBlock());
SEHExceptStmt *E = Node->getExceptHandler();
SEHFinallyStmt *F = Node->getFinallyHandler();
if(E)
PrintRawSEHExceptHandler(E);
else {
assert(F && "Must have a finally block...");
PrintRawSEHFinallyStmt(F);
}
OS << NL;
}
void StmtPrinter::PrintRawSEHFinallyStmt(SEHFinallyStmt *Node) {
OS << "__finally ";
PrintRawCompoundStmt(Node->getBlock());
OS << NL;
}
void StmtPrinter::PrintRawSEHExceptHandler(SEHExceptStmt *Node) {
OS << "__except (";
VisitExpr(Node->getFilterExpr());
OS << ")" << NL;
PrintRawCompoundStmt(Node->getBlock());
OS << NL;
}
void StmtPrinter::VisitSEHExceptStmt(SEHExceptStmt *Node) {
Indent();
PrintRawSEHExceptHandler(Node);
OS << NL;
}
void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) {
Indent();
PrintRawSEHFinallyStmt(Node);
OS << NL;
}
void StmtPrinter::VisitSEHLeaveStmt(SEHLeaveStmt *Node) {
Indent() << "__leave;";
if (Policy.IncludeNewlines) OS << NL;
}
//===----------------------------------------------------------------------===//
// OpenMP directives printing methods
//===----------------------------------------------------------------------===//
void StmtPrinter::VisitOMPCanonicalLoop(OMPCanonicalLoop *Node) {
PrintStmt(Node->getLoopStmt());
}
void StmtPrinter::PrintOMPExecutableDirective(OMPExecutableDirective *S,
bool ForceNoStmt) {
OMPClausePrinter Printer(OS, Policy);
ArrayRef<OMPClause *> Clauses = S->clauses();
for (auto *Clause : Clauses)
if (Clause && !Clause->isImplicit()) {
OS << ' ';
Printer.Visit(Clause);
}
OS << NL;
if (!ForceNoStmt && S->hasAssociatedStmt())
PrintStmt(S->getRawStmt());
}
void StmtPrinter::VisitOMPMetaDirective(OMPMetaDirective *Node) {
Indent() << "#pragma omp metadirective";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) {
Indent() << "#pragma omp parallel";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPSimdDirective(OMPSimdDirective *Node) {
Indent() << "#pragma omp simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTileDirective(OMPTileDirective *Node) {
Indent() << "#pragma omp tile";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPUnrollDirective(OMPUnrollDirective *Node) {
Indent() << "#pragma omp unroll";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPForDirective(OMPForDirective *Node) {
Indent() << "#pragma omp for";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPForSimdDirective(OMPForSimdDirective *Node) {
Indent() << "#pragma omp for simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPSectionsDirective(OMPSectionsDirective *Node) {
Indent() << "#pragma omp sections";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPSectionDirective(OMPSectionDirective *Node) {
Indent() << "#pragma omp section";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPSingleDirective(OMPSingleDirective *Node) {
Indent() << "#pragma omp single";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPMasterDirective(OMPMasterDirective *Node) {
Indent() << "#pragma omp master";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPCriticalDirective(OMPCriticalDirective *Node) {
Indent() << "#pragma omp critical";
if (Node->getDirectiveName().getName()) {
OS << " (";
Node->getDirectiveName().printName(OS, Policy);
OS << ")";
}
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPParallelForDirective(OMPParallelForDirective *Node) {
Indent() << "#pragma omp parallel for";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPParallelForSimdDirective(
OMPParallelForSimdDirective *Node) {
Indent() << "#pragma omp parallel for simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPParallelMasterDirective(
OMPParallelMasterDirective *Node) {
Indent() << "#pragma omp parallel master";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPParallelMaskedDirective(
OMPParallelMaskedDirective *Node) {
Indent() << "#pragma omp parallel masked";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPParallelSectionsDirective(
OMPParallelSectionsDirective *Node) {
Indent() << "#pragma omp parallel sections";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTaskDirective(OMPTaskDirective *Node) {
Indent() << "#pragma omp task";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *Node) {
Indent() << "#pragma omp taskyield";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPBarrierDirective(OMPBarrierDirective *Node) {
Indent() << "#pragma omp barrier";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *Node) {
Indent() << "#pragma omp taskwait";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *Node) {
Indent() << "#pragma omp taskgroup";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPFlushDirective(OMPFlushDirective *Node) {
Indent() << "#pragma omp flush";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPDepobjDirective(OMPDepobjDirective *Node) {
Indent() << "#pragma omp depobj";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPScanDirective(OMPScanDirective *Node) {
Indent() << "#pragma omp scan";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPOrderedDirective(OMPOrderedDirective *Node) {
Indent() << "#pragma omp ordered";
PrintOMPExecutableDirective(Node, Node->hasClausesOfKind<OMPDependClause>());
}
void StmtPrinter::VisitOMPAtomicDirective(OMPAtomicDirective *Node) {
Indent() << "#pragma omp atomic";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetDirective(OMPTargetDirective *Node) {
Indent() << "#pragma omp target";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetDataDirective(OMPTargetDataDirective *Node) {
Indent() << "#pragma omp target data";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetEnterDataDirective(
OMPTargetEnterDataDirective *Node) {
Indent() << "#pragma omp target enter data";
PrintOMPExecutableDirective(Node, /*ForceNoStmt=*/true);
}
void StmtPrinter::VisitOMPTargetExitDataDirective(
OMPTargetExitDataDirective *Node) {
Indent() << "#pragma omp target exit data";
PrintOMPExecutableDirective(Node, /*ForceNoStmt=*/true);
}
void StmtPrinter::VisitOMPTargetParallelDirective(
OMPTargetParallelDirective *Node) {
Indent() << "#pragma omp target parallel";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetParallelForDirective(
OMPTargetParallelForDirective *Node) {
Indent() << "#pragma omp target parallel for";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTeamsDirective(OMPTeamsDirective *Node) {
Indent() << "#pragma omp teams";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPCancellationPointDirective(
OMPCancellationPointDirective *Node) {
Indent() << "#pragma omp cancellation point "
<< getOpenMPDirectiveName(Node->getCancelRegion());
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPCancelDirective(OMPCancelDirective *Node) {
Indent() << "#pragma omp cancel "
<< getOpenMPDirectiveName(Node->getCancelRegion());
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTaskLoopDirective(OMPTaskLoopDirective *Node) {
Indent() << "#pragma omp taskloop";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTaskLoopSimdDirective(
OMPTaskLoopSimdDirective *Node) {
Indent() << "#pragma omp taskloop simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPMasterTaskLoopDirective(
OMPMasterTaskLoopDirective *Node) {
Indent() << "#pragma omp master taskloop";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPMaskedTaskLoopDirective(
OMPMaskedTaskLoopDirective *Node) {
Indent() << "#pragma omp masked taskloop";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPMasterTaskLoopSimdDirective(
OMPMasterTaskLoopSimdDirective *Node) {
Indent() << "#pragma omp master taskloop simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPMaskedTaskLoopSimdDirective(
OMPMaskedTaskLoopSimdDirective *Node) {
Indent() << "#pragma omp masked taskloop simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPParallelMasterTaskLoopDirective(
OMPParallelMasterTaskLoopDirective *Node) {
Indent() << "#pragma omp parallel master taskloop";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPParallelMaskedTaskLoopDirective(
OMPParallelMaskedTaskLoopDirective *Node) {
Indent() << "#pragma omp parallel masked taskloop";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPParallelMasterTaskLoopSimdDirective(
OMPParallelMasterTaskLoopSimdDirective *Node) {
Indent() << "#pragma omp parallel master taskloop simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPParallelMaskedTaskLoopSimdDirective(
OMPParallelMaskedTaskLoopSimdDirective *Node) {
Indent() << "#pragma omp parallel masked taskloop simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPDistributeDirective(OMPDistributeDirective *Node) {
Indent() << "#pragma omp distribute";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetUpdateDirective(
OMPTargetUpdateDirective *Node) {
Indent() << "#pragma omp target update";
PrintOMPExecutableDirective(Node, /*ForceNoStmt=*/true);
}
void StmtPrinter::VisitOMPDistributeParallelForDirective(
OMPDistributeParallelForDirective *Node) {
Indent() << "#pragma omp distribute parallel for";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPDistributeParallelForSimdDirective(
OMPDistributeParallelForSimdDirective *Node) {
Indent() << "#pragma omp distribute parallel for simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPDistributeSimdDirective(
OMPDistributeSimdDirective *Node) {
Indent() << "#pragma omp distribute simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetParallelForSimdDirective(
OMPTargetParallelForSimdDirective *Node) {
Indent() << "#pragma omp target parallel for simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetSimdDirective(OMPTargetSimdDirective *Node) {
Indent() << "#pragma omp target simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTeamsDistributeDirective(
OMPTeamsDistributeDirective *Node) {
Indent() << "#pragma omp teams distribute";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTeamsDistributeSimdDirective(
OMPTeamsDistributeSimdDirective *Node) {
Indent() << "#pragma omp teams distribute simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTeamsDistributeParallelForSimdDirective(
OMPTeamsDistributeParallelForSimdDirective *Node) {
Indent() << "#pragma omp teams distribute parallel for simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTeamsDistributeParallelForDirective(
OMPTeamsDistributeParallelForDirective *Node) {
Indent() << "#pragma omp teams distribute parallel for";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetTeamsDirective(OMPTargetTeamsDirective *Node) {
Indent() << "#pragma omp target teams";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetTeamsDistributeDirective(
OMPTargetTeamsDistributeDirective *Node) {
Indent() << "#pragma omp target teams distribute";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetTeamsDistributeParallelForDirective(
OMPTargetTeamsDistributeParallelForDirective *Node) {
Indent() << "#pragma omp target teams distribute parallel for";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetTeamsDistributeParallelForSimdDirective(
OMPTargetTeamsDistributeParallelForSimdDirective *Node) {
Indent() << "#pragma omp target teams distribute parallel for simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetTeamsDistributeSimdDirective(
OMPTargetTeamsDistributeSimdDirective *Node) {
Indent() << "#pragma omp target teams distribute simd";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPInteropDirective(OMPInteropDirective *Node) {
Indent() << "#pragma omp interop";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPDispatchDirective(OMPDispatchDirective *Node) {
Indent() << "#pragma omp dispatch";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPMaskedDirective(OMPMaskedDirective *Node) {
Indent() << "#pragma omp masked";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPGenericLoopDirective(OMPGenericLoopDirective *Node) {
Indent() << "#pragma omp loop";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTeamsGenericLoopDirective(
OMPTeamsGenericLoopDirective *Node) {
Indent() << "#pragma omp teams loop";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetTeamsGenericLoopDirective(
OMPTargetTeamsGenericLoopDirective *Node) {
Indent() << "#pragma omp target teams loop";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPParallelGenericLoopDirective(
OMPParallelGenericLoopDirective *Node) {
Indent() << "#pragma omp parallel loop";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPTargetParallelGenericLoopDirective(
OMPTargetParallelGenericLoopDirective *Node) {
Indent() << "#pragma omp target parallel loop";
PrintOMPExecutableDirective(Node);
}
//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//
void StmtPrinter::VisitSourceLocExpr(SourceLocExpr *Node) {
OS << Node->getBuiltinStr() << "()";
}
void StmtPrinter::VisitConstantExpr(ConstantExpr *Node) {
PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
if (const auto *OCED = dyn_cast<OMPCapturedExprDecl>(Node->getDecl())) {
OCED->getInit()->IgnoreImpCasts()->printPretty(OS, nullptr, Policy);
return;
}
if (const auto *TPOD = dyn_cast<TemplateParamObjectDecl>(Node->getDecl())) {
TPOD->printAsExpr(OS, Policy);
return;
}
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
if (Policy.CleanUglifiedParameters &&
isa<ParmVarDecl, NonTypeTemplateParmDecl>(Node->getDecl()) &&
Node->getDecl()->getIdentifier())
OS << Node->getDecl()->getIdentifier()->deuglifiedName();
else
Node->getNameInfo().printName(OS, Policy);
if (Node->hasExplicitTemplateArgs()) {
const TemplateParameterList *TPL = nullptr;
if (!Node->hadMultipleCandidates())
if (auto *TD = dyn_cast<TemplateDecl>(Node->getDecl()))
TPL = TD->getTemplateParameters();
printTemplateArgumentList(OS, Node->template_arguments(), Policy, TPL);
}
}
void StmtPrinter::VisitDependentScopeDeclRefExpr(
DependentScopeDeclRefExpr *Node) {
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
printTemplateArgumentList(OS, Node->template_arguments(), Policy);
}
void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
if (Node->getQualifier())
Node->getQualifier()->print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
printTemplateArgumentList(OS, Node->template_arguments(), Policy);
}
static bool isImplicitSelf(const Expr *E) {
if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
if (const auto *PD = dyn_cast<ImplicitParamDecl>(DRE->getDecl())) {
if (PD->getParameterKind() == ImplicitParamDecl::ObjCSelf &&
DRE->getBeginLoc().isInvalid())
return true;
}
}
return false;
}
void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
if (Node->getBase()) {
if (!Policy.SuppressImplicitBase ||
!isImplicitSelf(Node->getBase()->IgnoreImpCasts())) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
}
}
OS << *Node->getDecl();
}
void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
if (Node->isSuperReceiver())
OS << "super.";
else if (Node->isObjectReceiver() && Node->getBase()) {
PrintExpr(Node->getBase());
OS << ".";
} else if (Node->isClassReceiver() && Node->getClassReceiver()) {
OS << Node->getClassReceiver()->getName() << ".";
}
if (Node->isImplicitProperty()) {
if (const auto *Getter = Node->getImplicitPropertyGetter())
Getter->getSelector().print(OS);
else
OS << SelectorTable::getPropertyNameFromSetterSelector(
Node->getImplicitPropertySetter()->getSelector());
} else
OS << Node->getExplicitProperty()->getName();
}
void StmtPrinter::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) {
PrintExpr(Node->getBaseExpr());
OS << "[";
PrintExpr(Node->getKeyExpr());
OS << "]";
}
void StmtPrinter::VisitSYCLUniqueStableNameExpr(
SYCLUniqueStableNameExpr *Node) {
OS << "__builtin_sycl_unique_stable_name(";
Node->getTypeSourceInfo()->getType().print(OS, Policy);
OS << ")";
}
void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
OS << PredefinedExpr::getIdentKindName(Node->getIdentKind());
}
void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
CharacterLiteral::print(Node->getValue(), Node->getKind(), OS);
}
/// Prints the given expression using the original source text. Returns true on
/// success, false otherwise.
static bool printExprAsWritten(raw_ostream &OS, Expr *E,
const ASTContext *Context) {
if (!Context)
return false;
bool Invalid = false;
StringRef Source = Lexer::getSourceText(
CharSourceRange::getTokenRange(E->getSourceRange()),
Context->getSourceManager(), Context->getLangOpts(), &Invalid);
if (!Invalid) {
OS << Source;
return true;
}
return false;
}
void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
if (Policy.ConstantsAsWritten && printExprAsWritten(OS, Node, Context))
return;
bool isSigned = Node->getType()->isSignedIntegerType();
OS << toString(Node->getValue(), 10, isSigned);
if (isa<BitIntType>(Node->getType())) {
OS << (isSigned ? "wb" : "uwb");
return;
}
// Emit suffixes. Integer literals are always a builtin integer type.
switch (Node->getType()->castAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("Unexpected type for integer literal!");
case BuiltinType::Char_S:
case BuiltinType::Char_U: OS << "i8"; break;
case BuiltinType::UChar: OS << "Ui8"; break;
case BuiltinType::Short: OS << "i16"; break;
case BuiltinType::UShort: OS << "Ui16"; break;
case BuiltinType::Int: break; // no suffix.
case BuiltinType::UInt: OS << 'U'; break;
case BuiltinType::Long: OS << 'L'; break;
case BuiltinType::ULong: OS << "UL"; break;
case BuiltinType::LongLong: OS << "LL"; break;
case BuiltinType::ULongLong: OS << "ULL"; break;
case BuiltinType::Int128:
break; // no suffix.
case BuiltinType::UInt128:
break; // no suffix.
}
}
void StmtPrinter::VisitFixedPointLiteral(FixedPointLiteral *Node) {
if (Policy.ConstantsAsWritten && printExprAsWritten(OS, Node, Context))
return;
OS << Node->getValueAsString(/*Radix=*/10);
switch (Node->getType()->castAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("Unexpected type for fixed point literal!");
case BuiltinType::ShortFract: OS << "hr"; break;
case BuiltinType::ShortAccum: OS << "hk"; break;
case BuiltinType::UShortFract: OS << "uhr"; break;
case BuiltinType::UShortAccum: OS << "uhk"; break;
case BuiltinType::Fract: OS << "r"; break;
case BuiltinType::Accum: OS << "k"; break;
case BuiltinType::UFract: OS << "ur"; break;
case BuiltinType::UAccum: OS << "uk"; break;
case BuiltinType::LongFract: OS << "lr"; break;
case BuiltinType::LongAccum: OS << "lk"; break;
case BuiltinType::ULongFract: OS << "ulr"; break;
case BuiltinType::ULongAccum: OS << "ulk"; break;
}
}
static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node,
bool PrintSuffix) {
SmallString<16> Str;
Node->getValue().toString(Str);
OS << Str;
if (Str.find_first_not_of("-0123456789") == StringRef::npos)
OS << '.'; // Trailing dot in order to separate from ints.
if (!PrintSuffix)
return;
// Emit suffixes. Float literals are always a builtin float type.
switch (Node->getType()->castAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("Unexpected type for float literal!");
case BuiltinType::Half: break; // FIXME: suffix?
case BuiltinType::Ibm128: break; // FIXME: No suffix for ibm128 literal
case BuiltinType::Double: break; // no suffix.
case BuiltinType::Float16: OS << "F16"; break;
case BuiltinType::Float: OS << 'F'; break;
case BuiltinType::LongDouble: OS << 'L'; break;
case BuiltinType::Float128: OS << 'Q'; break;
}
}
void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
if (Policy.ConstantsAsWritten && printExprAsWritten(OS, Node, Context))
return;
PrintFloatingLiteral(OS, Node, /*PrintSuffix=*/true);
}
void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) {
PrintExpr(Node->getSubExpr());
OS << "i";
}
void StmtPrinter::VisitStringLiteral(StringLiteral *Str) {
Str->outputString(OS);
}
void StmtPrinter::VisitParenExpr(ParenExpr *Node) {
OS << "(";
PrintExpr(Node->getSubExpr());
OS << ")";
}
void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) {
if (!Node->isPostfix()) {
OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
// Print a space if this is an "identifier operator" like __real, or if
// it might be concatenated incorrectly like '+'.
switch (Node->getOpcode()) {
default: break;
case UO_Real:
case UO_Imag:
case UO_Extension:
OS << ' ';
break;
case UO_Plus:
case UO_Minus:
if (isa<UnaryOperator>(Node->getSubExpr()))
OS << ' ';
break;
}
}
PrintExpr(Node->getSubExpr());
if (Node->isPostfix())
OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
}
void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
OS << "__builtin_offsetof(";
Node->getTypeSourceInfo()->getType().print(OS, Policy);
OS << ", ";
bool PrintedSomething = false;
for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) {
OffsetOfNode ON = Node->getComponent(i);
if (ON.getKind() == OffsetOfNode::Array) {
// Array node
OS << "[";
PrintExpr(Node->getIndexExpr(ON.getArrayExprIndex()));
OS << "]";
PrintedSomething = true;
continue;
}
// Skip implicit base indirections.
if (ON.getKind() == OffsetOfNode::Base)
continue;
// Field or identifier node.
IdentifierInfo *Id = ON.getFieldName();
if (!Id)
continue;
if (PrintedSomething)
OS << ".";
else
PrintedSomething = true;
OS << Id->getName();
}
OS << ")";
}
void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(
UnaryExprOrTypeTraitExpr *Node) {
const char *Spelling = getTraitSpelling(Node->getKind());
if (Node->getKind() == UETT_AlignOf) {
if (Policy.Alignof)
Spelling = "alignof";
else if (Policy.UnderscoreAlignof)
Spelling = "_Alignof";
else
Spelling = "__alignof";
}
OS << Spelling;
if (Node->isArgumentType()) {
OS << '(';
Node->getArgumentType().print(OS, Policy);
OS << ')';
} else {
OS << " ";
PrintExpr(Node->getArgumentExpr());
}
}
void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) {
OS << "_Generic(";
PrintExpr(Node->getControllingExpr());
for (const GenericSelectionExpr::Association Assoc : Node->associations()) {
OS << ", ";
QualType T = Assoc.getType();
if (T.isNull())
OS << "default";
else
T.print(OS, Policy);
OS << ": ";
PrintExpr(Assoc.getAssociationExpr());
}
OS << ")";
}
void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
PrintExpr(Node->getLHS());
OS << "[";
PrintExpr(Node->getRHS());
OS << "]";
}
void StmtPrinter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *Node) {
PrintExpr(Node->getBase());
OS << "[";
PrintExpr(Node->getRowIdx());
OS << "]";
OS << "[";
PrintExpr(Node->getColumnIdx());
OS << "]";
}
void StmtPrinter::VisitOMPArraySectionExpr(OMPArraySectionExpr *Node) {
PrintExpr(Node->getBase());
OS << "[";
if (Node->getLowerBound())
PrintExpr(Node->getLowerBound());
if (Node->getColonLocFirst().isValid()) {
OS << ":";
if (Node->getLength())
PrintExpr(Node->getLength());
}
if (Node->getColonLocSecond().isValid()) {
OS << ":";
if (Node->getStride())
PrintExpr(Node->getStride());
}
OS << "]";
}
void StmtPrinter::VisitOMPArrayShapingExpr(OMPArrayShapingExpr *Node) {
OS << "(";
for (Expr *E : Node->getDimensions()) {
OS << "[";
PrintExpr(E);
OS << "]";
}
OS << ")";
PrintExpr(Node->getBase());
}
void StmtPrinter::VisitOMPIteratorExpr(OMPIteratorExpr *Node) {
OS << "iterator(";
for (unsigned I = 0, E = Node->numOfIterators(); I < E; ++I) {
auto *VD = cast<ValueDecl>(Node->getIteratorDecl(I));
VD->getType().print(OS, Policy);
const OMPIteratorExpr::IteratorRange Range = Node->getIteratorRange(I);
OS << " " << VD->getName() << " = ";
PrintExpr(Range.Begin);
OS << ":";
PrintExpr(Range.End);
if (Range.Step) {
OS << ":";
PrintExpr(Range.Step);
}
if (I < E - 1)
OS << ", ";
}
OS << ")";
}
void StmtPrinter::PrintCallArgs(CallExpr *Call) {
for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) {
if (isa<CXXDefaultArgExpr>(Call->getArg(i))) {
// Don't print any defaulted arguments
break;
}
if (i) OS << ", ";
PrintExpr(Call->getArg(i));
}
}
void StmtPrinter::VisitCallExpr(CallExpr *Call) {
PrintExpr(Call->getCallee());
OS << "(";
PrintCallArgs(Call);
OS << ")";
}
static bool isImplicitThis(const Expr *E) {
if (const auto *TE = dyn_cast<CXXThisExpr>(E))
return TE->isImplicit();
return false;
}
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
if (!Policy.SuppressImplicitBase || !isImplicitThis(Node->getBase())) {
PrintExpr(Node->getBase());
auto *ParentMember = dyn_cast<MemberExpr>(Node->getBase());
FieldDecl *ParentDecl =
ParentMember ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl())
: nullptr;
if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion())
OS << (Node->isArrow() ? "->" : ".");
}
if (auto *FD = dyn_cast<FieldDecl>(Node->getMemberDecl()))
if (FD->isAnonymousStructOrUnion())
return;
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
const TemplateParameterList *TPL = nullptr;
if (auto *FD = dyn_cast<FunctionDecl>(Node->getMemberDecl())) {
if (!Node->hadMultipleCandidates())
if (auto *FTD = FD->getPrimaryTemplate())
TPL = FTD->getTemplateParameters();
} else if (auto *VTSD =
dyn_cast<VarTemplateSpecializationDecl>(Node->getMemberDecl()))
TPL = VTSD->getSpecializedTemplate()->getTemplateParameters();
if (Node->hasExplicitTemplateArgs())
printTemplateArgumentList(OS, Node->template_arguments(), Policy, TPL);
}
void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->isa" : ".isa");
}
void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
PrintExpr(Node->getBase());
OS << ".";
OS << Node->getAccessor().getName();
}
void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) {
OS << '(';
Node->getTypeAsWritten().print(OS, Policy);
OS << ')';
PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
OS << '(';
Node->getType().print(OS, Policy);
OS << ')';
PrintExpr(Node->getInitializer());
}
void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
// No need to print anything, simply forward to the subexpression.
PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) {
PrintExpr(Node->getLHS());
OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
PrintExpr(Node->getRHS());
}
void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
PrintExpr(Node->getLHS());
OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
PrintExpr(Node->getRHS());
}
void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) {
PrintExpr(Node->getCond());
OS << " ? ";
PrintExpr(Node->getLHS());
OS << " : ";
PrintExpr(Node->getRHS());
}
// GNU extensions.
void
StmtPrinter::VisitBinaryConditionalOperator(BinaryConditionalOperator *Node) {
PrintExpr(Node->getCommon());
OS << " ?: ";
PrintExpr(Node->getFalseExpr());
}
void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) {
OS << "&&" << Node->getLabel()->getName();
}
void StmtPrinter::VisitStmtExpr(StmtExpr *E) {
OS << "(";
PrintRawCompoundStmt(E->getSubStmt());
OS << ")";
}
void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) {
OS << "__builtin_choose_expr(";
PrintExpr(Node->getCond());
OS << ", ";
PrintExpr(Node->getLHS());
OS << ", ";
PrintExpr(Node->getRHS());
OS << ")";
}
void StmtPrinter::VisitGNUNullExpr(GNUNullExpr *) {
OS << "__null";
}
void StmtPrinter::VisitShuffleVectorExpr(ShuffleVectorExpr *Node) {
OS << "__builtin_shufflevector(";
for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) {
if (i) OS << ", ";
PrintExpr(Node->getExpr(i));
}
OS << ")";
}
void StmtPrinter::VisitConvertVectorExpr(ConvertVectorExpr *Node) {
OS << "__builtin_convertvector(";
PrintExpr(Node->getSrcExpr());
OS << ", ";
Node->getType().print(OS, Policy);
OS << ")";
}
void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
if (Node->getSyntacticForm()) {
Visit(Node->getSyntacticForm());
return;
}
OS << "{";
for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
if (i) OS << ", ";
if (Node->getInit(i))
PrintExpr(Node->getInit(i));
else
OS << "{}";
}
OS << "}";
}
void StmtPrinter::VisitArrayInitLoopExpr(ArrayInitLoopExpr *Node) {
// There's no way to express this expression in any of our supported
// languages, so just emit something terse and (hopefully) clear.
OS << "{";
PrintExpr(Node->getSubExpr());
OS << "}";
}
void StmtPrinter::VisitArrayInitIndexExpr(ArrayInitIndexExpr *Node) {
OS << "*";
}
void StmtPrinter::VisitParenListExpr(ParenListExpr* Node) {
OS << "(";
for (unsigned i = 0, e = Node->getNumExprs(); i != e; ++i) {
if (i) OS << ", ";
PrintExpr(Node->getExpr(i));
}
OS << ")";
}
void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
bool NeedsEquals = true;
for (const DesignatedInitExpr::Designator &D : Node->designators()) {
if (D.isFieldDesignator()) {
if (D.getDotLoc().isInvalid()) {
if (IdentifierInfo *II = D.getFieldName()) {
OS << II->getName() << ":";
NeedsEquals = false;
}
} else {
OS << "." << D.getFieldName()->getName();
}
} else {
OS << "[";
if (D.isArrayDesignator()) {
PrintExpr(Node->getArrayIndex(D));
} else {
PrintExpr(Node->getArrayRangeStart(D));
OS << " ... ";
PrintExpr(Node->getArrayRangeEnd(D));
}
OS << "]";
}
}
if (NeedsEquals)
OS << " = ";
else
OS << " ";
PrintExpr(Node->getInit());
}
void StmtPrinter::VisitDesignatedInitUpdateExpr(
DesignatedInitUpdateExpr *Node) {
OS << "{";
OS << "/*base*/";
PrintExpr(Node->getBase());
OS << ", ";
OS << "/*updater*/";
PrintExpr(Node->getUpdater());
OS << "}";
}
void StmtPrinter::VisitNoInitExpr(NoInitExpr *Node) {
OS << "/*no init*/";
}
void StmtPrinter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *Node) {
if (Node->getType()->getAsCXXRecordDecl()) {
OS << "/*implicit*/";
Node->getType().print(OS, Policy);
OS << "()";
} else {
OS << "/*implicit*/(";
Node->getType().print(OS, Policy);
OS << ')';
if (Node->getType()->isRecordType())
OS << "{}";
else
OS << 0;
}
}
void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
OS << "__builtin_va_arg(";
PrintExpr(Node->getSubExpr());
OS << ", ";
Node->getType().print(OS, Policy);
OS << ")";
}
void StmtPrinter::VisitPseudoObjectExpr(PseudoObjectExpr *Node) {
PrintExpr(Node->getSyntacticForm());
}
void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
const char *Name = nullptr;
switch (Node->getOp()) {
#define BUILTIN(ID, TYPE, ATTRS)
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \
case AtomicExpr::AO ## ID: \
Name = #ID "("; \
break;
#include "clang/Basic/Builtins.def"
}
OS << Name;
// AtomicExpr stores its subexpressions in a permuted order.
PrintExpr(Node->getPtr());
if (Node->getOp() != AtomicExpr::AO__c11_atomic_load &&
Node->getOp() != AtomicExpr::AO__atomic_load_n &&
Node->getOp() != AtomicExpr::AO__opencl_atomic_load &&
Node->getOp() != AtomicExpr::AO__hip_atomic_load) {
OS << ", ";
PrintExpr(Node->getVal1());
}
if (Node->getOp() == AtomicExpr::AO__atomic_exchange ||
Node->isCmpXChg()) {
OS << ", ";
PrintExpr(Node->getVal2());
}
if (Node->getOp() == AtomicExpr::AO__atomic_compare_exchange ||
Node->getOp() == AtomicExpr::AO__atomic_compare_exchange_n) {
OS << ", ";
PrintExpr(Node->getWeak());
}
if (Node->getOp() != AtomicExpr::AO__c11_atomic_init &&
Node->getOp() != AtomicExpr::AO__opencl_atomic_init) {
OS << ", ";
PrintExpr(Node->getOrder());
}
if (Node->isCmpXChg()) {
OS << ", ";
PrintExpr(Node->getOrderFail());
}
OS << ")";
}
// C++
void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
OverloadedOperatorKind Kind = Node->getOperator();
if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) {
if (Node->getNumArgs() == 1) {
OS << getOperatorSpelling(Kind) << ' ';
PrintExpr(Node->getArg(0));
} else {
PrintExpr(Node->getArg(0));
OS << ' ' << getOperatorSpelling(Kind);
}
} else if (Kind == OO_Arrow) {
PrintExpr(Node->getArg(0));
} else if (Kind == OO_Call || Kind == OO_Subscript) {
PrintExpr(Node->getArg(0));
OS << (Kind == OO_Call ? '(' : '[');
for (unsigned ArgIdx = 1; ArgIdx < Node->getNumArgs(); ++ArgIdx) {
if (ArgIdx > 1)
OS << ", ";
if (!isa<CXXDefaultArgExpr>(Node->getArg(ArgIdx)))
PrintExpr(Node->getArg(ArgIdx));
}
OS << (Kind == OO_Call ? ')' : ']');
} else if (Node->getNumArgs() == 1) {
OS << getOperatorSpelling(Kind) << ' ';
PrintExpr(Node->getArg(0));
} else if (Node->getNumArgs() == 2) {
PrintExpr(Node->getArg(0));
OS << ' ' << getOperatorSpelling(Kind) << ' ';
PrintExpr(Node->getArg(1));
} else {
llvm_unreachable("unknown overloaded operator");
}
}
void StmtPrinter::VisitCXXMemberCallExpr(CXXMemberCallExpr *Node) {
// If we have a conversion operator call only print the argument.
CXXMethodDecl *MD = Node->getMethodDecl();
if (MD && isa<CXXConversionDecl>(MD)) {
PrintExpr(Node->getImplicitObjectArgument());
return;
}
VisitCallExpr(cast<CallExpr>(Node));
}
void StmtPrinter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *Node) {
PrintExpr(Node->getCallee());
OS << "<<<";
PrintCallArgs(Node->getConfig());
OS << ">>>(";
PrintCallArgs(Node);
OS << ")";
}
void StmtPrinter::VisitCXXRewrittenBinaryOperator(
CXXRewrittenBinaryOperator *Node) {
CXXRewrittenBinaryOperator::DecomposedForm Decomposed =
Node->getDecomposedForm();
PrintExpr(const_cast<Expr*>(Decomposed.LHS));
OS << ' ' << BinaryOperator::getOpcodeStr(Decomposed.Opcode) << ' ';
PrintExpr(const_cast<Expr*>(Decomposed.RHS));
}
void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
OS << Node->getCastName() << '<';
Node->getTypeAsWritten().print(OS, Policy);
OS << ">(";
PrintExpr(Node->getSubExpr());
OS << ")";
}
void StmtPrinter::VisitCXXStaticCastExpr(CXXStaticCastExpr *Node) {
VisitCXXNamedCastExpr(Node);
}
void StmtPrinter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *Node) {
VisitCXXNamedCastExpr(Node);
}
void StmtPrinter::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *Node) {
VisitCXXNamedCastExpr(Node);
}
void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) {
VisitCXXNamedCastExpr(Node);
}
void StmtPrinter::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *Node) {
OS << "__builtin_bit_cast(";
Node->getTypeInfoAsWritten()->getType().print(OS, Policy);
OS << ", ";
PrintExpr(Node->getSubExpr());
OS << ")";
}
void StmtPrinter::VisitCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *Node) {
VisitCXXNamedCastExpr(Node);
}
void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
OS << "typeid(";
if (Node->isTypeOperand()) {
Node->getTypeOperandSourceInfo()->getType().print(OS, Policy);
} else {
PrintExpr(Node->getExprOperand());
}
OS << ")";
}
void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) {
OS << "__uuidof(";
if (Node->isTypeOperand()) {
Node->getTypeOperandSourceInfo()->getType().print(OS, Policy);
} else {
PrintExpr(Node->getExprOperand());
}
OS << ")";
}
void StmtPrinter::VisitMSPropertyRefExpr(MSPropertyRefExpr *Node) {
PrintExpr(Node->getBaseExpr());
if (Node->isArrow())
OS << "->";
else
OS << ".";
if (NestedNameSpecifier *Qualifier =
Node->getQualifierLoc().getNestedNameSpecifier())
Qualifier->print(OS, Policy);
OS << Node->getPropertyDecl()->getDeclName();
}
void StmtPrinter::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *Node) {
PrintExpr(Node->getBase());
OS << "[";
PrintExpr(Node->getIdx());
OS << "]";
}
void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) {
switch (Node->getLiteralOperatorKind()) {
case UserDefinedLiteral::LOK_Raw:
OS << cast<StringLiteral>(Node->getArg(0)->IgnoreImpCasts())->getString();
break;
case UserDefinedLiteral::LOK_Template: {
const auto *DRE = cast<DeclRefExpr>(Node->getCallee()->IgnoreImpCasts());
const TemplateArgumentList *Args =
cast<FunctionDecl>(DRE->getDecl())->getTemplateSpecializationArgs();
assert(Args);
- if (Args->size() != 1) {
+ if (Args->size() != 1 || Args->get(0).getKind() != TemplateArgument::Pack) {
const TemplateParameterList *TPL = nullptr;
if (!DRE->hadMultipleCandidates())
if (const auto *TD = dyn_cast<TemplateDecl>(DRE->getDecl()))
TPL = TD->getTemplateParameters();
OS << "operator\"\"" << Node->getUDSuffix()->getName();
printTemplateArgumentList(OS, Args->asArray(), Policy, TPL);
OS << "()";
return;
}
const TemplateArgument &Pack = Args->get(0);
for (const auto &P : Pack.pack_elements()) {
char C = (char)P.getAsIntegral().getZExtValue();
OS << C;
}
break;
}
case UserDefinedLiteral::LOK_Integer: {
// Print integer literal without suffix.
const auto *Int = cast<IntegerLiteral>(Node->getCookedLiteral());
OS << toString(Int->getValue(), 10, /*isSigned*/false);
break;
}
case UserDefinedLiteral::LOK_Floating: {
// Print floating literal without suffix.
auto *Float = cast<FloatingLiteral>(Node->getCookedLiteral());
PrintFloatingLiteral(OS, Float, /*PrintSuffix=*/false);
break;
}
case UserDefinedLiteral::LOK_String:
case UserDefinedLiteral::LOK_Character:
PrintExpr(Node->getCookedLiteral());
break;
}
OS << Node->getUDSuffix()->getName();
}
void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
OS << (Node->getValue() ? "true" : "false");
}
void StmtPrinter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *Node) {
OS << "nullptr";
}
void StmtPrinter::VisitCXXThisExpr(CXXThisExpr *Node) {
OS << "this";
}
void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) {
if (!Node->getSubExpr())
OS << "throw";
else {
OS << "throw ";
PrintExpr(Node->getSubExpr());
}
}
void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) {
// Nothing to print: we picked up the default argument.
}
void StmtPrinter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Node) {
// Nothing to print: we picked up the default initializer.
}
void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
auto TargetType = Node->getType();
auto *Auto = TargetType->getContainedDeducedType();
bool Bare = Auto && Auto->isDeduced();
// Parenthesize deduced casts.
if (Bare)
OS << '(';
TargetType.print(OS, Policy);
if (Bare)
OS << ')';
// No extra braces surrounding the inner construct.
if (!Node->isListInitialization())
OS << '(';
PrintExpr(Node->getSubExpr());
if (!Node->isListInitialization())
OS << ')';
}
void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
Node->getType().print(OS, Policy);
if (Node->isStdInitListInitialization())
/* Nothing to do; braces are part of creating the std::initializer_list. */;
else if (Node->isListInitialization())
OS << "{";
else
OS << "(";
for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(),
ArgEnd = Node->arg_end();
Arg != ArgEnd; ++Arg) {
if ((*Arg)->isDefaultArgument())
break;
if (Arg != Node->arg_begin())
OS << ", ";
PrintExpr(*Arg);
}
if (Node->isStdInitListInitialization())
/* See above. */;
else if (Node->isListInitialization())
OS << "}";
else
OS << ")";
}
void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
OS << '[';
bool NeedComma = false;
switch (Node->getCaptureDefault()) {
case LCD_None:
break;
case LCD_ByCopy:
OS << '=';
NeedComma = true;
break;
case LCD_ByRef:
OS << '&';
NeedComma = true;
break;
}
for (LambdaExpr::capture_iterator C = Node->explicit_capture_begin(),
CEnd = Node->explicit_capture_end();
C != CEnd;
++C) {
if (C->capturesVLAType())
continue;
if (NeedComma)
OS << ", ";
NeedComma = true;
switch (C->getCaptureKind()) {
case LCK_This:
OS << "this";
break;
case LCK_StarThis:
OS << "*this";
break;
case LCK_ByRef:
if (Node->getCaptureDefault() != LCD_ByRef || Node->isInitCapture(C))
OS << '&';
OS << C->getCapturedVar()->getName();
break;
case LCK_ByCopy:
OS << C->getCapturedVar()->getName();
break;
case LCK_VLAType:
llvm_unreachable("VLA type in explicit captures.");
}
if (C->isPackExpansion())
OS << "...";
if (Node->isInitCapture(C)) {
VarDecl *D = C->getCapturedVar();
llvm::StringRef Pre;
llvm::StringRef Post;
if (D->getInitStyle() == VarDecl::CallInit &&
!isa<ParenListExpr>(D->getInit())) {
Pre = "(";
Post = ")";
} else if (D->getInitStyle() == VarDecl::CInit) {
Pre = " = ";
}
OS << Pre;
PrintExpr(D->getInit());
OS << Post;
}
}
OS << ']';
if (!Node->getExplicitTemplateParameters().empty()) {
Node->getTemplateParameterList()->print(
OS, Node->getLambdaClass()->getASTContext(),
/*OmitTemplateKW*/true);
}
if (Node->hasExplicitParameters()) {
OS << '(';
CXXMethodDecl *Method = Node->getCallOperator();
NeedComma = false;
for (const auto *P : Method->parameters()) {
if (NeedComma) {
OS << ", ";
} else {
NeedComma = true;
}
std::string ParamStr =
(Policy.CleanUglifiedParameters && P->getIdentifier())
? P->getIdentifier()->deuglifiedName().str()
: P->getNameAsString();
P->getOriginalType().print(OS, Policy, ParamStr);
}
if (Method->isVariadic()) {
if (NeedComma)
OS << ", ";
OS << "...";
}
OS << ')';
if (Node->isMutable())
OS << " mutable";
auto *Proto = Method->getType()->castAs<FunctionProtoType>();
Proto->printExceptionSpecification(OS, Policy);
// FIXME: Attributes
// Print the trailing return type if it was specified in the source.
if (Node->hasExplicitResultType()) {
OS << " -> ";
Proto->getReturnType().print(OS, Policy);
}
}
// Print the body.
OS << ' ';
if (Policy.TerseOutput)
OS << "{}";
else
PrintRawCompoundStmt(Node->getCompoundStmtBody());
}
void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) {
if (TypeSourceInfo *TSInfo = Node->getTypeSourceInfo())
TSInfo->getType().print(OS, Policy);
else
Node->getType().print(OS, Policy);
OS << "()";
}
void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
if (E->isGlobalNew())
OS << "::";
OS << "new ";
unsigned NumPlace = E->getNumPlacementArgs();
if (NumPlace > 0 && !isa<CXXDefaultArgExpr>(E->getPlacementArg(0))) {
OS << "(";
PrintExpr(E->getPlacementArg(0));
for (unsigned i = 1; i < NumPlace; ++i) {
if (isa<CXXDefaultArgExpr>(E->getPlacementArg(i)))
break;
OS << ", ";
PrintExpr(E->getPlacementArg(i));
}
OS << ") ";
}
if (E->isParenTypeId())
OS << "(";
std::string TypeS;
if (E->isArray()) {
llvm::raw_string_ostream s(TypeS);
s << '[';
if (Optional<Expr *> Size = E->getArraySize())
(*Size)->printPretty(s, Helper, Policy);
s << ']';
}
E->getAllocatedType().print(OS, Policy, TypeS);
if (E->isParenTypeId())
OS << ")";
CXXNewExpr::InitializationStyle InitStyle = E->getInitializationStyle();
if (InitStyle != CXXNewExpr::NoInit) {
bool Bare = InitStyle == CXXNewExpr::CallInit &&
!isa<ParenListExpr>(E->getInitializer());
if (Bare)
OS << "(";
PrintExpr(E->getInitializer());
if (Bare)
OS << ")";
}
}
void StmtPrinter::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
if (E->isGlobalDelete())
OS << "::";
OS << "delete ";
if (E->isArrayForm())
OS << "[] ";
PrintExpr(E->getArgument());
}
void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
PrintExpr(E->getBase());
if (E->isArrow())
OS << "->";
else
OS << '.';
if (E->getQualifier())
E->getQualifier()->print(OS, Policy);
OS << "~";
if (IdentifierInfo *II = E->getDestroyedTypeIdentifier())
OS << II->getName();
else
E->getDestroyedType().print(OS, Policy);
}
void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
if (E->isListInitialization() && !E->isStdInitListInitialization())
OS << "{";
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
if (isa<CXXDefaultArgExpr>(E->getArg(i))) {
// Don't print any defaulted arguments
break;
}
if (i) OS << ", ";
PrintExpr(E->getArg(i));
}
if (E->isListInitialization() && !E->isStdInitListInitialization())
OS << "}";
}
void StmtPrinter::VisitCXXInheritedCtorInitExpr(CXXInheritedCtorInitExpr *E) {
// Parens are printed by the surrounding context.
OS << "<forwarded>";
}
void StmtPrinter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
PrintExpr(E->getSubExpr());
}
void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
// Just forward to the subexpression.
PrintExpr(E->getSubExpr());
}
void StmtPrinter::VisitCXXUnresolvedConstructExpr(
CXXUnresolvedConstructExpr *Node) {
Node->getTypeAsWritten().print(OS, Policy);
if (!Node->isListInitialization())
OS << '(';
for (auto Arg = Node->arg_begin(), ArgEnd = Node->arg_end(); Arg != ArgEnd;
++Arg) {
if (Arg != Node->arg_begin())
OS << ", ";
PrintExpr(*Arg);
}
if (!Node->isListInitialization())
OS << ')';
}
void StmtPrinter::VisitCXXDependentScopeMemberExpr(
CXXDependentScopeMemberExpr *Node) {
if (!Node->isImplicitAccess()) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
}
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
if (Node->hasExplicitTemplateArgs())
printTemplateArgumentList(OS, Node->template_arguments(), Policy);
}
void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
if (!Node->isImplicitAccess()) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
}
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
if (Node->hasExplicitTemplateArgs())
printTemplateArgumentList(OS, Node->template_arguments(), Policy);
}
void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) {
OS << getTraitSpelling(E->getTrait()) << "(";
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
if (I > 0)
OS << ", ";
E->getArg(I)->getType().print(OS, Policy);
}
OS << ")";
}
void StmtPrinter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
OS << getTraitSpelling(E->getTrait()) << '(';
E->getQueriedType().print(OS, Policy);
OS << ')';
}
void StmtPrinter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
OS << getTraitSpelling(E->getTrait()) << '(';
PrintExpr(E->getQueriedExpression());
OS << ')';
}
void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
OS << "noexcept(";
PrintExpr(E->getOperand());
OS << ")";
}
void StmtPrinter::VisitPackExpansionExpr(PackExpansionExpr *E) {
PrintExpr(E->getPattern());
OS << "...";
}
void StmtPrinter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
OS << "sizeof...(" << *E->getPack() << ")";
}
void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *Node) {
OS << *Node->getParameterPack();
}
void StmtPrinter::VisitSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *Node) {
Visit(Node->getReplacement());
}
void StmtPrinter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
OS << *E->getParameterPack();
}
void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){
PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) {
OS << "(";
if (E->getLHS()) {
PrintExpr(E->getLHS());
OS << " " << BinaryOperator::getOpcodeStr(E->getOperator()) << " ";
}
OS << "...";
if (E->getRHS()) {
OS << " " << BinaryOperator::getOpcodeStr(E->getOperator()) << " ";
PrintExpr(E->getRHS());
}
OS << ")";
}
void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc();
if (NNS)
NNS.getNestedNameSpecifier()->print(OS, Policy);
if (E->getTemplateKWLoc().isValid())
OS << "template ";
OS << E->getFoundDecl()->getName();
printTemplateArgumentList(OS, E->getTemplateArgsAsWritten()->arguments(),
Policy,
E->getNamedConcept()->getTemplateParameters());
}
void StmtPrinter::VisitRequiresExpr(RequiresExpr *E) {
OS << "requires ";
auto LocalParameters = E->getLocalParameters();
if (!LocalParameters.empty()) {
OS << "(";
for (ParmVarDecl *LocalParam : LocalParameters) {
PrintRawDecl(LocalParam);
if (LocalParam != LocalParameters.back())
OS << ", ";
}
OS << ") ";
}
OS << "{ ";
auto Requirements = E->getRequirements();
for (concepts::Requirement *Req : Requirements) {
if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) {
if (TypeReq->isSubstitutionFailure())
OS << "<<error-type>>";
else
TypeReq->getType()->getType().print(OS, Policy);
} else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) {
if (ExprReq->isCompound())
OS << "{ ";
if (ExprReq->isExprSubstitutionFailure())
OS << "<<error-expression>>";
else
PrintExpr(ExprReq->getExpr());
if (ExprReq->isCompound()) {
OS << " }";
if (ExprReq->getNoexceptLoc().isValid())
OS << " noexcept";
const auto &RetReq = ExprReq->getReturnTypeRequirement();
if (!RetReq.isEmpty()) {
OS << " -> ";
if (RetReq.isSubstitutionFailure())
OS << "<<error-type>>";
else if (RetReq.isTypeConstraint())
RetReq.getTypeConstraint()->print(OS, Policy);
}
}
} else {
auto *NestedReq = cast<concepts::NestedRequirement>(Req);
OS << "requires ";
if (NestedReq->isSubstitutionFailure())
OS << "<<error-expression>>";
else
PrintExpr(NestedReq->getConstraintExpr());
}
OS << "; ";
}
OS << "}";
}
// C++ Coroutines TS
void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
Visit(S->getBody());
}
void StmtPrinter::VisitCoreturnStmt(CoreturnStmt *S) {
OS << "co_return";
if (S->getOperand()) {
OS << " ";
Visit(S->getOperand());
}
OS << ";";
}
void StmtPrinter::VisitCoawaitExpr(CoawaitExpr *S) {
OS << "co_await ";
PrintExpr(S->getOperand());
}
void StmtPrinter::VisitDependentCoawaitExpr(DependentCoawaitExpr *S) {
OS << "co_await ";
PrintExpr(S->getOperand());
}
void StmtPrinter::VisitCoyieldExpr(CoyieldExpr *S) {
OS << "co_yield ";
PrintExpr(S->getOperand());
}
// Obj-C
void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
OS << "@";
VisitStringLiteral(Node->getString());
}
void StmtPrinter::VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
OS << "@";
Visit(E->getSubExpr());
}
void StmtPrinter::VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
OS << "@[ ";
ObjCArrayLiteral::child_range Ch = E->children();
for (auto I = Ch.begin(), E = Ch.end(); I != E; ++I) {
if (I != Ch.begin())
OS << ", ";
Visit(*I);
}
OS << " ]";
}
void StmtPrinter::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
OS << "@{ ";
for (unsigned I = 0, N = E->getNumElements(); I != N; ++I) {
if (I > 0)
OS << ", ";
ObjCDictionaryElement Element = E->getKeyValueElement(I);
Visit(Element.Key);
OS << " : ";
Visit(Element.Value);
if (Element.isPackExpansion())
OS << "...";
}
OS << " }";
}
void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
OS << "@encode(";
Node->getEncodedType().print(OS, Policy);
OS << ')';
}
void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
OS << "@selector(";
Node->getSelector().print(OS);
OS << ')';
}
void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
OS << "@protocol(" << *Node->getProtocol() << ')';
}
void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
OS << "[";
switch (Mess->getReceiverKind()) {
case ObjCMessageExpr::Instance:
PrintExpr(Mess->getInstanceReceiver());
break;
case ObjCMessageExpr::Class:
Mess->getClassReceiver().print(OS, Policy);
break;
case ObjCMessageExpr::SuperInstance:
case ObjCMessageExpr::SuperClass:
OS << "Super";
break;
}
OS << ' ';
Selector selector = Mess->getSelector();
if (selector.isUnarySelector()) {
OS << selector.getNameForSlot(0);
} else {
for (unsigned i = 0, e = Mess->getNumArgs(); i != e; ++i) {
if (i < selector.getNumArgs()) {
if (i > 0) OS << ' ';
if (selector.getIdentifierInfoForSlot(i))
OS << selector.getIdentifierInfoForSlot(i)->getName() << ':';
else
OS << ":";
}
else OS << ", "; // Handle variadic methods.
PrintExpr(Mess->getArg(i));
}
}
OS << "]";
}
void StmtPrinter::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Node) {
OS << (Node->getValue() ? "__objc_yes" : "__objc_no");
}
void
StmtPrinter::VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
PrintExpr(E->getSubExpr());
}
void
StmtPrinter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
OS << '(' << E->getBridgeKindName();
E->getType().print(OS, Policy);
OS << ')';
PrintExpr(E->getSubExpr());
}
void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
BlockDecl *BD = Node->getBlockDecl();
OS << "^";
const FunctionType *AFT = Node->getFunctionType();
if (isa<FunctionNoProtoType>(AFT)) {
OS << "()";
} else if (!BD->param_empty() || cast<FunctionProtoType>(AFT)->isVariadic()) {
OS << '(';
for (BlockDecl::param_iterator AI = BD->param_begin(),
E = BD->param_end(); AI != E; ++AI) {
if (AI != BD->param_begin()) OS << ", ";
std::string ParamStr = (*AI)->getNameAsString();
(*AI)->getType().print(OS, Policy, ParamStr);
}
const auto *FT = cast<FunctionProtoType>(AFT);
if (FT->isVariadic()) {
if (!BD->param_empty()) OS << ", ";
OS << "...";
}
OS << ')';
}
OS << "{ }";
}
void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
PrintExpr(Node->getSourceExpr());
}
void StmtPrinter::VisitTypoExpr(TypoExpr *Node) {
// TODO: Print something reasonable for a TypoExpr, if necessary.
llvm_unreachable("Cannot print TypoExpr nodes");
}
void StmtPrinter::VisitRecoveryExpr(RecoveryExpr *Node) {
OS << "<recovery-expr>(";
const char *Sep = "";
for (Expr *E : Node->subExpressions()) {
OS << Sep;
PrintExpr(E);
Sep = ", ";
}
OS << ')';
}
void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
OS << "__builtin_astype(";
PrintExpr(Node->getSrcExpr());
OS << ", ";
Node->getType().print(OS, Policy);
OS << ")";
}
//===----------------------------------------------------------------------===//
// Stmt method implementations
//===----------------------------------------------------------------------===//
void Stmt::dumpPretty(const ASTContext &Context) const {
printPretty(llvm::errs(), nullptr, PrintingPolicy(Context.getLangOpts()));
}
void Stmt::printPretty(raw_ostream &Out, PrinterHelper *Helper,
const PrintingPolicy &Policy, unsigned Indentation,
StringRef NL, const ASTContext *Context) const {
StmtPrinter P(Out, Helper, Policy, Indentation, NL, Context);
P.Visit(const_cast<Stmt *>(this));
}
void Stmt::printPrettyControlled(raw_ostream &Out, PrinterHelper *Helper,
const PrintingPolicy &Policy,
unsigned Indentation, StringRef NL,
const ASTContext *Context) const {
StmtPrinter P(Out, Helper, Policy, Indentation, NL, Context);
P.PrintControlledStmt(const_cast<Stmt *>(this));
}
void Stmt::printJson(raw_ostream &Out, PrinterHelper *Helper,
const PrintingPolicy &Policy, bool AddQuotes) const {
std::string Buf;
llvm::raw_string_ostream TempOut(Buf);
printPretty(TempOut, Helper, Policy);
Out << JsonFormat(TempOut.str(), AddQuotes);
}
//===----------------------------------------------------------------------===//
// PrinterHelper
//===----------------------------------------------------------------------===//
// Implement virtual destructor.
PrinterHelper::~PrinterHelper() = default;
diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGStmt.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGStmt.cpp
index 481438de0e53..9935fcc0d3ea 100644
--- a/contrib/llvm-project/clang/lib/CodeGen/CGStmt.cpp
+++ b/contrib/llvm-project/clang/lib/CodeGen/CGStmt.cpp
@@ -1,2894 +1,2909 @@
//===--- CGStmt.cpp - Emit LLVM Code from Statements ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This contains code to emit Stmt nodes as LLVM code.
//
//===----------------------------------------------------------------------===//
#include "CGDebugInfo.h"
#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Assumptions.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace CodeGen;
//===----------------------------------------------------------------------===//
// Statement Emission
//===----------------------------------------------------------------------===//
void CodeGenFunction::EmitStopPoint(const Stmt *S) {
if (CGDebugInfo *DI = getDebugInfo()) {
SourceLocation Loc;
Loc = S->getBeginLoc();
DI->EmitLocation(Builder, Loc);
LastStopPoint = Loc;
}
}
void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
assert(S && "Null statement?");
PGO.setCurrentStmt(S);
// These statements have their own debug info handling.
if (EmitSimpleStmt(S, Attrs))
return;
// Check if we are generating unreachable code.
if (!HaveInsertPoint()) {
// If so, and the statement doesn't contain a label, then we do not need to
// generate actual code. This is safe because (1) the current point is
// unreachable, so we don't need to execute the code, and (2) we've already
// handled the statements which update internal data structures (like the
// local variable map) which could be used by subsequent statements.
if (!ContainsLabel(S)) {
// Verify that any decl statements were handled as simple, they may be in
// scope of subsequent reachable statements.
assert(!isa<DeclStmt>(*S) && "Unexpected DeclStmt!");
return;
}
// Otherwise, make a new block to hold the code.
EnsureInsertPoint();
}
// Generate a stoppoint if we are emitting debug info.
EmitStopPoint(S);
// Ignore all OpenMP directives except for simd if OpenMP with Simd is
// enabled.
if (getLangOpts().OpenMP && getLangOpts().OpenMPSimd) {
if (const auto *D = dyn_cast<OMPExecutableDirective>(S)) {
EmitSimpleOMPExecutableDirective(*D);
return;
}
}
switch (S->getStmtClass()) {
case Stmt::NoStmtClass:
case Stmt::CXXCatchStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::SEHFinallyStmtClass:
case Stmt::MSDependentExistsStmtClass:
llvm_unreachable("invalid statement class to emit generically");
case Stmt::NullStmtClass:
case Stmt::CompoundStmtClass:
case Stmt::DeclStmtClass:
case Stmt::LabelStmtClass:
case Stmt::AttributedStmtClass:
case Stmt::GotoStmtClass:
case Stmt::BreakStmtClass:
case Stmt::ContinueStmtClass:
case Stmt::DefaultStmtClass:
case Stmt::CaseStmtClass:
case Stmt::SEHLeaveStmtClass:
llvm_unreachable("should have emitted these statements as simple");
#define STMT(Type, Base)
#define ABSTRACT_STMT(Op)
#define EXPR(Type, Base) \
case Stmt::Type##Class:
#include "clang/AST/StmtNodes.inc"
{
// Remember the block we came in on.
llvm::BasicBlock *incoming = Builder.GetInsertBlock();
assert(incoming && "expression emission must have an insertion point");
EmitIgnoredExpr(cast<Expr>(S));
llvm::BasicBlock *outgoing = Builder.GetInsertBlock();
assert(outgoing && "expression emission cleared block!");
// The expression emitters assume (reasonably!) that the insertion
// point is always set. To maintain that, the call-emission code
// for noreturn functions has to enter a new block with no
// predecessors. We want to kill that block and mark the current
// insertion point unreachable in the common case of a call like
// "exit();". Since expression emission doesn't otherwise create
// blocks with no predecessors, we can just test for that.
// However, we must be careful not to do this to our incoming
// block, because *statement* emission does sometimes create
// reachable blocks which will have no predecessors until later in
// the function. This occurs with, e.g., labels that are not
// reachable by fallthrough.
if (incoming != outgoing && outgoing->use_empty()) {
outgoing->eraseFromParent();
Builder.ClearInsertionPoint();
}
break;
}
case Stmt::IndirectGotoStmtClass:
EmitIndirectGotoStmt(cast<IndirectGotoStmt>(*S)); break;
case Stmt::IfStmtClass: EmitIfStmt(cast<IfStmt>(*S)); break;
case Stmt::WhileStmtClass: EmitWhileStmt(cast<WhileStmt>(*S), Attrs); break;
case Stmt::DoStmtClass: EmitDoStmt(cast<DoStmt>(*S), Attrs); break;
case Stmt::ForStmtClass: EmitForStmt(cast<ForStmt>(*S), Attrs); break;
case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break;
case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
case Stmt::GCCAsmStmtClass: // Intentional fall-through.
case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
case Stmt::CoroutineBodyStmtClass:
EmitCoroutineBody(cast<CoroutineBodyStmt>(*S));
break;
case Stmt::CoreturnStmtClass:
EmitCoreturnStmt(cast<CoreturnStmt>(*S));
break;
case Stmt::CapturedStmtClass: {
const CapturedStmt *CS = cast<CapturedStmt>(S);
EmitCapturedStmt(*CS, CS->getCapturedRegionKind());
}
break;
case Stmt::ObjCAtTryStmtClass:
EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S));
break;
case Stmt::ObjCAtCatchStmtClass:
llvm_unreachable(
"@catch statements should be handled by EmitObjCAtTryStmt");
case Stmt::ObjCAtFinallyStmtClass:
llvm_unreachable(
"@finally statements should be handled by EmitObjCAtTryStmt");
case Stmt::ObjCAtThrowStmtClass:
EmitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(*S));
break;
case Stmt::ObjCAtSynchronizedStmtClass:
EmitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(*S));
break;
case Stmt::ObjCForCollectionStmtClass:
EmitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(*S));
break;
case Stmt::ObjCAutoreleasePoolStmtClass:
EmitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(*S));
break;
case Stmt::CXXTryStmtClass:
EmitCXXTryStmt(cast<CXXTryStmt>(*S));
break;
case Stmt::CXXForRangeStmtClass:
EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S), Attrs);
break;
case Stmt::SEHTryStmtClass:
EmitSEHTryStmt(cast<SEHTryStmt>(*S));
break;
case Stmt::OMPMetaDirectiveClass:
EmitOMPMetaDirective(cast<OMPMetaDirective>(*S));
break;
case Stmt::OMPCanonicalLoopClass:
EmitOMPCanonicalLoop(cast<OMPCanonicalLoop>(S));
break;
case Stmt::OMPParallelDirectiveClass:
EmitOMPParallelDirective(cast<OMPParallelDirective>(*S));
break;
case Stmt::OMPSimdDirectiveClass:
EmitOMPSimdDirective(cast<OMPSimdDirective>(*S));
break;
case Stmt::OMPTileDirectiveClass:
EmitOMPTileDirective(cast<OMPTileDirective>(*S));
break;
case Stmt::OMPUnrollDirectiveClass:
EmitOMPUnrollDirective(cast<OMPUnrollDirective>(*S));
break;
case Stmt::OMPForDirectiveClass:
EmitOMPForDirective(cast<OMPForDirective>(*S));
break;
case Stmt::OMPForSimdDirectiveClass:
EmitOMPForSimdDirective(cast<OMPForSimdDirective>(*S));
break;
case Stmt::OMPSectionsDirectiveClass:
EmitOMPSectionsDirective(cast<OMPSectionsDirective>(*S));
break;
case Stmt::OMPSectionDirectiveClass:
EmitOMPSectionDirective(cast<OMPSectionDirective>(*S));
break;
case Stmt::OMPSingleDirectiveClass:
EmitOMPSingleDirective(cast<OMPSingleDirective>(*S));
break;
case Stmt::OMPMasterDirectiveClass:
EmitOMPMasterDirective(cast<OMPMasterDirective>(*S));
break;
case Stmt::OMPCriticalDirectiveClass:
EmitOMPCriticalDirective(cast<OMPCriticalDirective>(*S));
break;
case Stmt::OMPParallelForDirectiveClass:
EmitOMPParallelForDirective(cast<OMPParallelForDirective>(*S));
break;
case Stmt::OMPParallelForSimdDirectiveClass:
EmitOMPParallelForSimdDirective(cast<OMPParallelForSimdDirective>(*S));
break;
case Stmt::OMPParallelMasterDirectiveClass:
EmitOMPParallelMasterDirective(cast<OMPParallelMasterDirective>(*S));
break;
case Stmt::OMPParallelSectionsDirectiveClass:
EmitOMPParallelSectionsDirective(cast<OMPParallelSectionsDirective>(*S));
break;
case Stmt::OMPTaskDirectiveClass:
EmitOMPTaskDirective(cast<OMPTaskDirective>(*S));
break;
case Stmt::OMPTaskyieldDirectiveClass:
EmitOMPTaskyieldDirective(cast<OMPTaskyieldDirective>(*S));
break;
case Stmt::OMPBarrierDirectiveClass:
EmitOMPBarrierDirective(cast<OMPBarrierDirective>(*S));
break;
case Stmt::OMPTaskwaitDirectiveClass:
EmitOMPTaskwaitDirective(cast<OMPTaskwaitDirective>(*S));
break;
case Stmt::OMPTaskgroupDirectiveClass:
EmitOMPTaskgroupDirective(cast<OMPTaskgroupDirective>(*S));
break;
case Stmt::OMPFlushDirectiveClass:
EmitOMPFlushDirective(cast<OMPFlushDirective>(*S));
break;
case Stmt::OMPDepobjDirectiveClass:
EmitOMPDepobjDirective(cast<OMPDepobjDirective>(*S));
break;
case Stmt::OMPScanDirectiveClass:
EmitOMPScanDirective(cast<OMPScanDirective>(*S));
break;
case Stmt::OMPOrderedDirectiveClass:
EmitOMPOrderedDirective(cast<OMPOrderedDirective>(*S));
break;
case Stmt::OMPAtomicDirectiveClass:
EmitOMPAtomicDirective(cast<OMPAtomicDirective>(*S));
break;
case Stmt::OMPTargetDirectiveClass:
EmitOMPTargetDirective(cast<OMPTargetDirective>(*S));
break;
case Stmt::OMPTeamsDirectiveClass:
EmitOMPTeamsDirective(cast<OMPTeamsDirective>(*S));
break;
case Stmt::OMPCancellationPointDirectiveClass:
EmitOMPCancellationPointDirective(cast<OMPCancellationPointDirective>(*S));
break;
case Stmt::OMPCancelDirectiveClass:
EmitOMPCancelDirective(cast<OMPCancelDirective>(*S));
break;
case Stmt::OMPTargetDataDirectiveClass:
EmitOMPTargetDataDirective(cast<OMPTargetDataDirective>(*S));
break;
case Stmt::OMPTargetEnterDataDirectiveClass:
EmitOMPTargetEnterDataDirective(cast<OMPTargetEnterDataDirective>(*S));
break;
case Stmt::OMPTargetExitDataDirectiveClass:
EmitOMPTargetExitDataDirective(cast<OMPTargetExitDataDirective>(*S));
break;
case Stmt::OMPTargetParallelDirectiveClass:
EmitOMPTargetParallelDirective(cast<OMPTargetParallelDirective>(*S));
break;
case Stmt::OMPTargetParallelForDirectiveClass:
EmitOMPTargetParallelForDirective(cast<OMPTargetParallelForDirective>(*S));
break;
case Stmt::OMPTaskLoopDirectiveClass:
EmitOMPTaskLoopDirective(cast<OMPTaskLoopDirective>(*S));
break;
case Stmt::OMPTaskLoopSimdDirectiveClass:
EmitOMPTaskLoopSimdDirective(cast<OMPTaskLoopSimdDirective>(*S));
break;
case Stmt::OMPMasterTaskLoopDirectiveClass:
EmitOMPMasterTaskLoopDirective(cast<OMPMasterTaskLoopDirective>(*S));
break;
case Stmt::OMPMaskedTaskLoopDirectiveClass:
llvm_unreachable("masked taskloop directive not supported yet.");
break;
case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
EmitOMPMasterTaskLoopSimdDirective(
cast<OMPMasterTaskLoopSimdDirective>(*S));
break;
case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
llvm_unreachable("masked taskloop simd directive not supported yet.");
break;
case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
EmitOMPParallelMasterTaskLoopDirective(
cast<OMPParallelMasterTaskLoopDirective>(*S));
break;
case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
llvm_unreachable("parallel masked taskloop directive not supported yet.");
break;
case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
EmitOMPParallelMasterTaskLoopSimdDirective(
cast<OMPParallelMasterTaskLoopSimdDirective>(*S));
break;
case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
llvm_unreachable(
"parallel masked taskloop simd directive not supported yet.");
break;
case Stmt::OMPDistributeDirectiveClass:
EmitOMPDistributeDirective(cast<OMPDistributeDirective>(*S));
break;
case Stmt::OMPTargetUpdateDirectiveClass:
EmitOMPTargetUpdateDirective(cast<OMPTargetUpdateDirective>(*S));
break;
case Stmt::OMPDistributeParallelForDirectiveClass:
EmitOMPDistributeParallelForDirective(
cast<OMPDistributeParallelForDirective>(*S));
break;
case Stmt::OMPDistributeParallelForSimdDirectiveClass:
EmitOMPDistributeParallelForSimdDirective(
cast<OMPDistributeParallelForSimdDirective>(*S));
break;
case Stmt::OMPDistributeSimdDirectiveClass:
EmitOMPDistributeSimdDirective(cast<OMPDistributeSimdDirective>(*S));
break;
case Stmt::OMPTargetParallelForSimdDirectiveClass:
EmitOMPTargetParallelForSimdDirective(
cast<OMPTargetParallelForSimdDirective>(*S));
break;
case Stmt::OMPTargetSimdDirectiveClass:
EmitOMPTargetSimdDirective(cast<OMPTargetSimdDirective>(*S));
break;
case Stmt::OMPTeamsDistributeDirectiveClass:
EmitOMPTeamsDistributeDirective(cast<OMPTeamsDistributeDirective>(*S));
break;
case Stmt::OMPTeamsDistributeSimdDirectiveClass:
EmitOMPTeamsDistributeSimdDirective(
cast<OMPTeamsDistributeSimdDirective>(*S));
break;
case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
EmitOMPTeamsDistributeParallelForSimdDirective(
cast<OMPTeamsDistributeParallelForSimdDirective>(*S));
break;
case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
EmitOMPTeamsDistributeParallelForDirective(
cast<OMPTeamsDistributeParallelForDirective>(*S));
break;
case Stmt::OMPTargetTeamsDirectiveClass:
EmitOMPTargetTeamsDirective(cast<OMPTargetTeamsDirective>(*S));
break;
case Stmt::OMPTargetTeamsDistributeDirectiveClass:
EmitOMPTargetTeamsDistributeDirective(
cast<OMPTargetTeamsDistributeDirective>(*S));
break;
case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
EmitOMPTargetTeamsDistributeParallelForDirective(
cast<OMPTargetTeamsDistributeParallelForDirective>(*S));
break;
case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
EmitOMPTargetTeamsDistributeParallelForSimdDirective(
cast<OMPTargetTeamsDistributeParallelForSimdDirective>(*S));
break;
case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
EmitOMPTargetTeamsDistributeSimdDirective(
cast<OMPTargetTeamsDistributeSimdDirective>(*S));
break;
case Stmt::OMPInteropDirectiveClass:
EmitOMPInteropDirective(cast<OMPInteropDirective>(*S));
break;
case Stmt::OMPDispatchDirectiveClass:
llvm_unreachable("Dispatch directive not supported yet.");
break;
case Stmt::OMPMaskedDirectiveClass:
EmitOMPMaskedDirective(cast<OMPMaskedDirective>(*S));
break;
case Stmt::OMPGenericLoopDirectiveClass:
EmitOMPGenericLoopDirective(cast<OMPGenericLoopDirective>(*S));
break;
case Stmt::OMPTeamsGenericLoopDirectiveClass:
llvm_unreachable("teams loop directive not supported yet.");
break;
case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
llvm_unreachable("target teams loop directive not supported yet.");
break;
case Stmt::OMPParallelGenericLoopDirectiveClass:
llvm_unreachable("parallel loop directive not supported yet.");
break;
case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
llvm_unreachable("target parallel loop directive not supported yet.");
break;
case Stmt::OMPParallelMaskedDirectiveClass:
llvm_unreachable("parallel masked directive not supported yet.");
break;
}
}
bool CodeGenFunction::EmitSimpleStmt(const Stmt *S,
ArrayRef<const Attr *> Attrs) {
switch (S->getStmtClass()) {
default:
return false;
case Stmt::NullStmtClass:
break;
case Stmt::CompoundStmtClass:
EmitCompoundStmt(cast<CompoundStmt>(*S));
break;
case Stmt::DeclStmtClass:
EmitDeclStmt(cast<DeclStmt>(*S));
break;
case Stmt::LabelStmtClass:
EmitLabelStmt(cast<LabelStmt>(*S));
break;
case Stmt::AttributedStmtClass:
EmitAttributedStmt(cast<AttributedStmt>(*S));
break;
case Stmt::GotoStmtClass:
EmitGotoStmt(cast<GotoStmt>(*S));
break;
case Stmt::BreakStmtClass:
EmitBreakStmt(cast<BreakStmt>(*S));
break;
case Stmt::ContinueStmtClass:
EmitContinueStmt(cast<ContinueStmt>(*S));
break;
case Stmt::DefaultStmtClass:
EmitDefaultStmt(cast<DefaultStmt>(*S), Attrs);
break;
case Stmt::CaseStmtClass:
EmitCaseStmt(cast<CaseStmt>(*S), Attrs);
break;
case Stmt::SEHLeaveStmtClass:
EmitSEHLeaveStmt(cast<SEHLeaveStmt>(*S));
break;
}
return true;
}
/// EmitCompoundStmt - Emit a compound statement {..} node. If GetLast is true,
/// this captures the expression result of the last sub-statement and returns it
/// (for use by the statement expression extension).
Address CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
AggValueSlot AggSlot) {
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),S.getLBracLoc(),
"LLVM IR generation of compound statement ('{}')");
// Keep track of the current cleanup stack depth, including debug scopes.
LexicalScope Scope(*this, S.getSourceRange());
return EmitCompoundStmtWithoutScope(S, GetLast, AggSlot);
}
Address
CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S,
bool GetLast,
AggValueSlot AggSlot) {
const Stmt *ExprResult = S.getStmtExprResult();
assert((!GetLast || (GetLast && ExprResult)) &&
"If GetLast is true then the CompoundStmt must have a StmtExprResult");
Address RetAlloca = Address::invalid();
for (auto *CurStmt : S.body()) {
if (GetLast && ExprResult == CurStmt) {
// We have to special case labels here. They are statements, but when put
// at the end of a statement expression, they yield the value of their
// subexpression. Handle this by walking through all labels we encounter,
// emitting them before we evaluate the subexpr.
// Similar issues arise for attributed statements.
while (!isa<Expr>(ExprResult)) {
if (const auto *LS = dyn_cast<LabelStmt>(ExprResult)) {
EmitLabel(LS->getDecl());
ExprResult = LS->getSubStmt();
} else if (const auto *AS = dyn_cast<AttributedStmt>(ExprResult)) {
// FIXME: Update this if we ever have attributes that affect the
// semantics of an expression.
ExprResult = AS->getSubStmt();
} else {
llvm_unreachable("unknown value statement");
}
}
EnsureInsertPoint();
const Expr *E = cast<Expr>(ExprResult);
QualType ExprTy = E->getType();
if (hasAggregateEvaluationKind(ExprTy)) {
EmitAggExpr(E, AggSlot);
} else {
// We can't return an RValue here because there might be cleanups at
// the end of the StmtExpr. Because of that, we have to emit the result
// here into a temporary alloca.
RetAlloca = CreateMemTemp(ExprTy);
EmitAnyExprToMem(E, RetAlloca, Qualifiers(),
/*IsInit*/ false);
}
} else {
EmitStmt(CurStmt);
}
}
return RetAlloca;
}
void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) {
llvm::BranchInst *BI = dyn_cast<llvm::BranchInst>(BB->getTerminator());
// If there is a cleanup stack, then we it isn't worth trying to
// simplify this block (we would need to remove it from the scope map
// and cleanup entry).
if (!EHStack.empty())
return;
// Can only simplify direct branches.
if (!BI || !BI->isUnconditional())
return;
// Can only simplify empty blocks.
if (BI->getIterator() != BB->begin())
return;
BB->replaceAllUsesWith(BI->getSuccessor(0));
BI->eraseFromParent();
BB->eraseFromParent();
}
void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) {
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
// Fall out of the current block (if necessary).
EmitBranch(BB);
if (IsFinished && BB->use_empty()) {
delete BB;
return;
}
// Place the block after the current block, if possible, or else at
// the end of the function.
if (CurBB && CurBB->getParent())
CurFn->getBasicBlockList().insertAfter(CurBB->getIterator(), BB);
else
CurFn->getBasicBlockList().push_back(BB);
Builder.SetInsertPoint(BB);
}
void CodeGenFunction::EmitBranch(llvm::BasicBlock *Target) {
// Emit a branch from the current block to the target one if this
// was a real block. If this was just a fall-through block after a
// terminator, don't emit it.
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
if (!CurBB || CurBB->getTerminator()) {
// If there is no insert point or the previous block is already
// terminated, don't touch it.
} else {
// Otherwise, create a fall-through branch.
Builder.CreateBr(Target);
}
Builder.ClearInsertionPoint();
}
void CodeGenFunction::EmitBlockAfterUses(llvm::BasicBlock *block) {
bool inserted = false;
for (llvm::User *u : block->users()) {
if (llvm::Instruction *insn = dyn_cast<llvm::Instruction>(u)) {
CurFn->getBasicBlockList().insertAfter(insn->getParent()->getIterator(),
block);
inserted = true;
break;
}
}
if (!inserted)
CurFn->getBasicBlockList().push_back(block);
Builder.SetInsertPoint(block);
}
CodeGenFunction::JumpDest
CodeGenFunction::getJumpDestForLabel(const LabelDecl *D) {
JumpDest &Dest = LabelMap[D];
if (Dest.isValid()) return Dest;
// Create, but don't insert, the new block.
Dest = JumpDest(createBasicBlock(D->getName()),
EHScopeStack::stable_iterator::invalid(),
NextCleanupDestIndex++);
return Dest;
}
void CodeGenFunction::EmitLabel(const LabelDecl *D) {
// Add this label to the current lexical scope if we're within any
// normal cleanups. Jumps "in" to this label --- when permitted by
// the language --- may need to be routed around such cleanups.
if (EHStack.hasNormalCleanups() && CurLexicalScope)
CurLexicalScope->addLabel(D);
JumpDest &Dest = LabelMap[D];
// If we didn't need a forward reference to this label, just go
// ahead and create a destination at the current scope.
if (!Dest.isValid()) {
Dest = getJumpDestInCurrentScope(D->getName());
// Otherwise, we need to give this label a target depth and remove
// it from the branch-fixups list.
} else {
assert(!Dest.getScopeDepth().isValid() && "already emitted label!");
Dest.setScopeDepth(EHStack.stable_begin());
ResolveBranchFixups(Dest.getBlock());
}
EmitBlock(Dest.getBlock());
// Emit debug info for labels.
if (CGDebugInfo *DI = getDebugInfo()) {
if (CGM.getCodeGenOpts().hasReducedDebugInfo()) {
DI->setLocation(D->getLocation());
DI->EmitLabel(D, Builder);
}
}
incrementProfileCounter(D->getStmt());
}
/// Change the cleanup scope of the labels in this lexical scope to
/// match the scope of the enclosing context.
void CodeGenFunction::LexicalScope::rescopeLabels() {
assert(!Labels.empty());
EHScopeStack::stable_iterator innermostScope
= CGF.EHStack.getInnermostNormalCleanup();
// Change the scope depth of all the labels.
for (SmallVectorImpl<const LabelDecl*>::const_iterator
i = Labels.begin(), e = Labels.end(); i != e; ++i) {
assert(CGF.LabelMap.count(*i));
JumpDest &dest = CGF.LabelMap.find(*i)->second;
assert(dest.getScopeDepth().isValid());
assert(innermostScope.encloses(dest.getScopeDepth()));
dest.setScopeDepth(innermostScope);
}
// Reparent the labels if the new scope also has cleanups.
if (innermostScope != EHScopeStack::stable_end() && ParentScope) {
ParentScope->Labels.append(Labels.begin(), Labels.end());
}
}
void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
EmitLabel(S.getDecl());
// IsEHa - emit eha.scope.begin if it's a side entry of a scope
if (getLangOpts().EHAsynch && S.isSideEntry())
EmitSehCppScopeBegin();
EmitStmt(S.getSubStmt());
}
void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
bool nomerge = false;
bool noinline = false;
bool alwaysinline = false;
const CallExpr *musttail = nullptr;
for (const auto *A : S.getAttrs()) {
switch (A->getKind()) {
default:
break;
case attr::NoMerge:
nomerge = true;
break;
case attr::NoInline:
noinline = true;
break;
case attr::AlwaysInline:
alwaysinline = true;
break;
case attr::MustTail:
const Stmt *Sub = S.getSubStmt();
const ReturnStmt *R = cast<ReturnStmt>(Sub);
musttail = cast<CallExpr>(R->getRetValue()->IgnoreParens());
break;
}
}
SaveAndRestore<bool> save_nomerge(InNoMergeAttributedStmt, nomerge);
SaveAndRestore<bool> save_noinline(InNoInlineAttributedStmt, noinline);
SaveAndRestore<bool> save_alwaysinline(InAlwaysInlineAttributedStmt,
alwaysinline);
SaveAndRestore<const CallExpr *> save_musttail(MustTailCall, musttail);
EmitStmt(S.getSubStmt(), S.getAttrs());
}
void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
// If this code is reachable then emit a stop point (if generating
// debug info). We have to do this ourselves because we are on the
// "simple" statement path.
if (HaveInsertPoint())
EmitStopPoint(&S);
EmitBranchThroughCleanup(getJumpDestForLabel(S.getLabel()));
}
void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
if (const LabelDecl *Target = S.getConstantTarget()) {
EmitBranchThroughCleanup(getJumpDestForLabel(Target));
return;
}
// Ensure that we have an i8* for our PHI node.
llvm::Value *V = Builder.CreateBitCast(EmitScalarExpr(S.getTarget()),
Int8PtrTy, "addr");
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
// Get the basic block for the indirect goto.
llvm::BasicBlock *IndGotoBB = GetIndirectGotoBlock();
// The first instruction in the block has to be the PHI for the switch dest,
// add an entry for this branch.
cast<llvm::PHINode>(IndGotoBB->begin())->addIncoming(V, CurBB);
EmitBranch(IndGotoBB);
}
void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// The else branch of a consteval if statement is always the only branch that
// can be runtime evaluated.
if (S.isConsteval()) {
const Stmt *Executed = S.isNegatedConsteval() ? S.getThen() : S.getElse();
if (Executed) {
RunCleanupsScope ExecutedScope(*this);
EmitStmt(Executed);
}
return;
}
// C99 6.8.4.1: The first substatement is executed if the expression compares
// unequal to 0. The condition must be a scalar type.
LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
if (S.getInit())
EmitStmt(S.getInit());
if (S.getConditionVariable())
EmitDecl(*S.getConditionVariable());
// If the condition constant folds and can be elided, try to avoid emitting
// the condition and the dead arm of the if/else.
bool CondConstant;
if (ConstantFoldsToSimpleInteger(S.getCond(), CondConstant,
S.isConstexpr())) {
// Figure out which block (then or else) is executed.
const Stmt *Executed = S.getThen();
const Stmt *Skipped = S.getElse();
if (!CondConstant) // Condition false?
std::swap(Executed, Skipped);
// If the skipped block has no labels in it, just emit the executed block.
// This avoids emitting dead code and simplifies the CFG substantially.
if (S.isConstexpr() || !ContainsLabel(Skipped)) {
if (CondConstant)
incrementProfileCounter(&S);
if (Executed) {
RunCleanupsScope ExecutedScope(*this);
EmitStmt(Executed);
}
return;
}
}
// Otherwise, the condition did not fold, or we couldn't elide it. Just emit
// the conditional branch.
llvm::BasicBlock *ThenBlock = createBasicBlock("if.then");
llvm::BasicBlock *ContBlock = createBasicBlock("if.end");
llvm::BasicBlock *ElseBlock = ContBlock;
if (S.getElse())
ElseBlock = createBasicBlock("if.else");
// Prefer the PGO based weights over the likelihood attribute.
// When the build isn't optimized the metadata isn't used, so don't generate
// it.
Stmt::Likelihood LH = Stmt::LH_None;
uint64_t Count = getProfileCount(S.getThen());
if (!Count && CGM.getCodeGenOpts().OptimizationLevel)
LH = Stmt::getLikelihood(S.getThen(), S.getElse());
EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, Count, LH);
// Emit the 'then' code.
EmitBlock(ThenBlock);
incrementProfileCounter(&S);
{
RunCleanupsScope ThenScope(*this);
EmitStmt(S.getThen());
}
EmitBranch(ContBlock);
// Emit the 'else' code if present.
if (const Stmt *Else = S.getElse()) {
{
// There is no need to emit line number for an unconditional branch.
auto NL = ApplyDebugLocation::CreateEmpty(*this);
EmitBlock(ElseBlock);
}
{
RunCleanupsScope ElseScope(*this);
EmitStmt(Else);
}
{
// There is no need to emit line number for an unconditional branch.
auto NL = ApplyDebugLocation::CreateEmpty(*this);
EmitBranch(ContBlock);
}
}
// Emit the continuation block for code after the if.
EmitBlock(ContBlock, true);
}
void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
ArrayRef<const Attr *> WhileAttrs) {
// Emit the header for the loop, which will also become
// the continue target.
JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond");
EmitBlock(LoopHeader.getBlock());
// Create an exit block for when the condition fails, which will
// also become the break target.
JumpDest LoopExit = getJumpDestInCurrentScope("while.end");
// Store the blocks to use for break and continue.
BreakContinueStack.push_back(BreakContinue(LoopExit, LoopHeader));
// C++ [stmt.while]p2:
// When the condition of a while statement is a declaration, the
// scope of the variable that is declared extends from its point
// of declaration (3.3.2) to the end of the while statement.
// [...]
// The object created in a condition is destroyed and created
// with each iteration of the loop.
RunCleanupsScope ConditionScope(*this);
if (S.getConditionVariable())
EmitDecl(*S.getConditionVariable());
// Evaluate the conditional in the while header. C99 6.8.5.1: The
// evaluation of the controlling expression takes place before each
// execution of the loop body.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
// while(1) is common, avoid extra exit blocks. Be sure
// to correctly handle break/continue though.
llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal);
bool CondIsConstInt = C != nullptr;
bool EmitBoolCondBranch = !CondIsConstInt || !C->isOne();
const SourceRange &R = S.getSourceRange();
LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), CGM.getCodeGenOpts(),
WhileAttrs, SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()),
checkIfLoopMustProgress(CondIsConstInt));
// As long as the condition is true, go to the loop body.
llvm::BasicBlock *LoopBody = createBasicBlock("while.body");
if (EmitBoolCondBranch) {
llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
if (ConditionScope.requiresCleanups())
ExitBlock = createBasicBlock("while.exit");
llvm::MDNode *Weights =
createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody()));
if (!Weights && CGM.getCodeGenOpts().OptimizationLevel)
BoolCondVal = emitCondLikelihoodViaExpectIntrinsic(
BoolCondVal, Stmt::getLikelihood(S.getBody()));
Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock, Weights);
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
}
} else if (const Attr *A = Stmt::getLikelihoodAttr(S.getBody())) {
CGM.getDiags().Report(A->getLocation(),
diag::warn_attribute_has_no_effect_on_infinite_loop)
<< A << A->getRange();
CGM.getDiags().Report(
S.getWhileLoc(),
diag::note_attribute_has_no_effect_on_infinite_loop_here)
<< SourceRange(S.getWhileLoc(), S.getRParenLoc());
}
// Emit the loop body. We have to emit this in a cleanup scope
// because it might be a singleton DeclStmt.
{
RunCleanupsScope BodyScope(*this);
EmitBlock(LoopBody);
incrementProfileCounter(&S);
EmitStmt(S.getBody());
}
BreakContinueStack.pop_back();
// Immediately force cleanup.
ConditionScope.ForceCleanup();
EmitStopPoint(&S);
// Branch to the loop header again.
EmitBranch(LoopHeader.getBlock());
LoopStack.pop();
// Emit the exit block.
EmitBlock(LoopExit.getBlock(), true);
// The LoopHeader typically is just a branch if we skipped emitting
// a branch, try to erase it.
if (!EmitBoolCondBranch)
SimplifyForwardingBlocks(LoopHeader.getBlock());
}
void CodeGenFunction::EmitDoStmt(const DoStmt &S,
ArrayRef<const Attr *> DoAttrs) {
JumpDest LoopExit = getJumpDestInCurrentScope("do.end");
JumpDest LoopCond = getJumpDestInCurrentScope("do.cond");
uint64_t ParentCount = getCurrentProfileCount();
// Store the blocks to use for break and continue.
BreakContinueStack.push_back(BreakContinue(LoopExit, LoopCond));
// Emit the body of the loop.
llvm::BasicBlock *LoopBody = createBasicBlock("do.body");
EmitBlockWithFallThrough(LoopBody, &S);
{
RunCleanupsScope BodyScope(*this);
EmitStmt(S.getBody());
}
EmitBlock(LoopCond.getBlock());
// C99 6.8.5.2: "The evaluation of the controlling expression takes place
// after each execution of the loop body."
// Evaluate the conditional in the while header.
// C99 6.8.5p2/p4: The first substatement is executed if the expression
// compares unequal to 0. The condition must be a scalar type.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
BreakContinueStack.pop_back();
// "do {} while (0)" is common in macros, avoid extra blocks. Be sure
// to correctly handle break/continue though.
llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal);
bool CondIsConstInt = C;
bool EmitBoolCondBranch = !C || !C->isZero();
const SourceRange &R = S.getSourceRange();
LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs,
SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()),
checkIfLoopMustProgress(CondIsConstInt));
// As long as the condition is true, iterate the loop.
if (EmitBoolCondBranch) {
uint64_t BackedgeCount = getProfileCount(S.getBody()) - ParentCount;
Builder.CreateCondBr(
BoolCondVal, LoopBody, LoopExit.getBlock(),
createProfileWeightsForLoop(S.getCond(), BackedgeCount));
}
LoopStack.pop();
// Emit the exit block.
EmitBlock(LoopExit.getBlock());
// The DoCond block typically is just a branch if we skipped
// emitting a branch, try to erase it.
if (!EmitBoolCondBranch)
SimplifyForwardingBlocks(LoopCond.getBlock());
}
void CodeGenFunction::EmitForStmt(const ForStmt &S,
ArrayRef<const Attr *> ForAttrs) {
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
LexicalScope ForScope(*this, S.getSourceRange());
// Evaluate the first part before the loop.
if (S.getInit())
EmitStmt(S.getInit());
// Start the loop with a block that tests the condition.
// If there's an increment, the continue scope will be overwritten
// later.
JumpDest CondDest = getJumpDestInCurrentScope("for.cond");
llvm::BasicBlock *CondBlock = CondDest.getBlock();
EmitBlock(CondBlock);
Expr::EvalResult Result;
bool CondIsConstInt =
!S.getCond() || S.getCond()->EvaluateAsInt(Result, getContext());
const SourceRange &R = S.getSourceRange();
LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs,
SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()),
checkIfLoopMustProgress(CondIsConstInt));
// Create a cleanup scope for the condition variable cleanups.
LexicalScope ConditionScope(*this, S.getSourceRange());
// If the for loop doesn't have an increment we can just use the condition as
// the continue block. Otherwise, if there is no condition variable, we can
// form the continue block now. If there is a condition variable, we can't
// form the continue block until after we've emitted the condition, because
// the condition is in scope in the increment, but Sema's jump diagnostics
// ensure that there are no continues from the condition variable that jump
// to the loop increment.
JumpDest Continue;
if (!S.getInc())
Continue = CondDest;
else if (!S.getConditionVariable())
Continue = getJumpDestInCurrentScope("for.inc");
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
if (S.getCond()) {
// If the for statement has a condition scope, emit the local variable
// declaration.
if (S.getConditionVariable()) {
EmitDecl(*S.getConditionVariable());
// We have entered the condition variable's scope, so we're now able to
// jump to the continue block.
Continue = S.getInc() ? getJumpDestInCurrentScope("for.inc") : CondDest;
BreakContinueStack.back().ContinueBlock = Continue;
}
llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
// If there are any cleanups between here and the loop-exit scope,
// create a block to stage a loop exit along.
if (ForScope.requiresCleanups())
ExitBlock = createBasicBlock("for.cond.cleanup");
// As long as the condition is true, iterate the loop.
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
// C99 6.8.5p2/p4: The first substatement is executed if the expression
// compares unequal to 0. The condition must be a scalar type.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
llvm::MDNode *Weights =
createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody()));
if (!Weights && CGM.getCodeGenOpts().OptimizationLevel)
BoolCondVal = emitCondLikelihoodViaExpectIntrinsic(
BoolCondVal, Stmt::getLikelihood(S.getBody()));
Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights);
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
}
EmitBlock(ForBody);
} else {
// Treat it as a non-zero constant. Don't even create a new block for the
// body, just fall into it.
}
incrementProfileCounter(&S);
{
// Create a separate cleanup scope for the body, in case it is not
// a compound statement.
RunCleanupsScope BodyScope(*this);
EmitStmt(S.getBody());
}
// If there is an increment, emit it next.
if (S.getInc()) {
EmitBlock(Continue.getBlock());
EmitStmt(S.getInc());
}
BreakContinueStack.pop_back();
ConditionScope.ForceCleanup();
EmitStopPoint(&S);
EmitBranch(CondBlock);
ForScope.ForceCleanup();
LoopStack.pop();
// Emit the fall-through block.
EmitBlock(LoopExit.getBlock(), true);
}
void
CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
ArrayRef<const Attr *> ForAttrs) {
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
LexicalScope ForScope(*this, S.getSourceRange());
// Evaluate the first pieces before the loop.
if (S.getInit())
EmitStmt(S.getInit());
EmitStmt(S.getRangeStmt());
EmitStmt(S.getBeginStmt());
EmitStmt(S.getEndStmt());
// Start the loop with a block that tests the condition.
// If there's an increment, the continue scope will be overwritten
// later.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
EmitBlock(CondBlock);
const SourceRange &R = S.getSourceRange();
LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs,
SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()));
// If there are any cleanups between here and the loop-exit scope,
// create a block to stage a loop exit along.
llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
if (ForScope.requiresCleanups())
ExitBlock = createBasicBlock("for.cond.cleanup");
// The loop body, consisting of the specified body and the loop variable.
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
// The body is executed if the expression, contextually converted
// to bool, is true.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
llvm::MDNode *Weights =
createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody()));
if (!Weights && CGM.getCodeGenOpts().OptimizationLevel)
BoolCondVal = emitCondLikelihoodViaExpectIntrinsic(
BoolCondVal, Stmt::getLikelihood(S.getBody()));
Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights);
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
}
EmitBlock(ForBody);
incrementProfileCounter(&S);
// Create a block for the increment. In case of a 'continue', we jump there.
JumpDest Continue = getJumpDestInCurrentScope("for.inc");
// Store the blocks to use for break and continue.
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
{
// Create a separate cleanup scope for the loop variable and body.
LexicalScope BodyScope(*this, S.getSourceRange());
EmitStmt(S.getLoopVarStmt());
EmitStmt(S.getBody());
}
EmitStopPoint(&S);
// If there is an increment, emit it next.
EmitBlock(Continue.getBlock());
EmitStmt(S.getInc());
BreakContinueStack.pop_back();
EmitBranch(CondBlock);
ForScope.ForceCleanup();
LoopStack.pop();
// Emit the fall-through block.
EmitBlock(LoopExit.getBlock(), true);
}
void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
if (RV.isScalar()) {
Builder.CreateStore(RV.getScalarVal(), ReturnValue);
} else if (RV.isAggregate()) {
LValue Dest = MakeAddrLValue(ReturnValue, Ty);
LValue Src = MakeAddrLValue(RV.getAggregateAddress(), Ty);
EmitAggregateCopy(Dest, Src, Ty, getOverlapForReturnValue());
} else {
EmitStoreOfComplex(RV.getComplexVal(), MakeAddrLValue(ReturnValue, Ty),
/*init*/ true);
}
EmitBranchThroughCleanup(ReturnBlock);
}
namespace {
// RAII struct used to save and restore a return statment's result expression.
struct SaveRetExprRAII {
SaveRetExprRAII(const Expr *RetExpr, CodeGenFunction &CGF)
: OldRetExpr(CGF.RetExpr), CGF(CGF) {
CGF.RetExpr = RetExpr;
}
~SaveRetExprRAII() { CGF.RetExpr = OldRetExpr; }
const Expr *OldRetExpr;
CodeGenFunction &CGF;
};
} // namespace
/// If we have 'return f(...);', where both caller and callee are SwiftAsync,
/// codegen it as 'tail call ...; ret void;'.
static void makeTailCallIfSwiftAsync(const CallExpr *CE, CGBuilderTy &Builder,
const CGFunctionInfo *CurFnInfo) {
auto calleeQualType = CE->getCallee()->getType();
const FunctionType *calleeType = nullptr;
if (calleeQualType->isFunctionPointerType() ||
calleeQualType->isFunctionReferenceType() ||
calleeQualType->isBlockPointerType() ||
calleeQualType->isMemberFunctionPointerType()) {
calleeType = calleeQualType->getPointeeType()->castAs<FunctionType>();
} else if (auto *ty = dyn_cast<FunctionType>(calleeQualType)) {
calleeType = ty;
} else if (auto CMCE = dyn_cast<CXXMemberCallExpr>(CE)) {
if (auto methodDecl = CMCE->getMethodDecl()) {
// getMethodDecl() doesn't handle member pointers at the moment.
calleeType = methodDecl->getType()->castAs<FunctionType>();
} else {
return;
}
} else {
return;
}
if (calleeType->getCallConv() == CallingConv::CC_SwiftAsync &&
(CurFnInfo->getASTCallingConvention() == CallingConv::CC_SwiftAsync)) {
auto CI = cast<llvm::CallInst>(&Builder.GetInsertBlock()->back());
CI->setTailCallKind(llvm::CallInst::TCK_MustTail);
Builder.CreateRetVoid();
Builder.ClearInsertionPoint();
}
}
/// EmitReturnStmt - Note that due to GCC extensions, this can have an operand
/// if the function returns void, or may be missing one if the function returns
/// non-void. Fun stuff :).
void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
if (requiresReturnValueCheck()) {
llvm::Constant *SLoc = EmitCheckSourceLocation(S.getBeginLoc());
auto *SLocPtr =
new llvm::GlobalVariable(CGM.getModule(), SLoc->getType(), false,
llvm::GlobalVariable::PrivateLinkage, SLoc);
SLocPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
CGM.getSanitizerMetadata()->disableSanitizerForGlobal(SLocPtr);
assert(ReturnLocation.isValid() && "No valid return location");
Builder.CreateStore(Builder.CreateBitCast(SLocPtr, Int8PtrTy),
ReturnLocation);
}
// Returning from an outlined SEH helper is UB, and we already warn on it.
if (IsOutlinedSEHHelper) {
Builder.CreateUnreachable();
Builder.ClearInsertionPoint();
}
// Emit the result value, even if unused, to evaluate the side effects.
const Expr *RV = S.getRetValue();
// Record the result expression of the return statement. The recorded
// expression is used to determine whether a block capture's lifetime should
// end at the end of the full expression as opposed to the end of the scope
// enclosing the block expression.
//
// This permits a small, easily-implemented exception to our over-conservative
// rules about not jumping to statements following block literals with
// non-trivial cleanups.
SaveRetExprRAII SaveRetExpr(RV, *this);
RunCleanupsScope cleanupScope(*this);
if (const auto *EWC = dyn_cast_or_null<ExprWithCleanups>(RV))
RV = EWC->getSubExpr();
// FIXME: Clean this up by using an LValue for ReturnTemp,
// EmitStoreThroughLValue, and EmitAnyExpr.
// Check if the NRVO candidate was not globalized in OpenMP mode.
if (getLangOpts().ElideConstructors && S.getNRVOCandidate() &&
S.getNRVOCandidate()->isNRVOVariable() &&
(!getLangOpts().OpenMP ||
!CGM.getOpenMPRuntime()
.getAddressOfLocalVariable(*this, S.getNRVOCandidate())
.isValid())) {
// Apply the named return value optimization for this return statement,
// which means doing nothing: the appropriate result has already been
// constructed into the NRVO variable.
// If there is an NRVO flag for this variable, set it to 1 into indicate
// that the cleanup code should not destroy the variable.
if (llvm::Value *NRVOFlag = NRVOFlags[S.getNRVOCandidate()])
Builder.CreateFlagStore(Builder.getTrue(), NRVOFlag);
} else if (!ReturnValue.isValid() || (RV && RV->getType()->isVoidType())) {
// Make sure not to return anything, but evaluate the expression
// for side effects.
if (RV) {
EmitAnyExpr(RV);
if (auto *CE = dyn_cast<CallExpr>(RV))
makeTailCallIfSwiftAsync(CE, Builder, CurFnInfo);
}
} else if (!RV) {
// Do nothing (return value is left uninitialized)
} else if (FnRetTy->isReferenceType()) {
// If this function returns a reference, take the address of the expression
// rather than the value.
RValue Result = EmitReferenceBindingToExpr(RV);
Builder.CreateStore(Result.getScalarVal(), ReturnValue);
} else {
switch (getEvaluationKind(RV->getType())) {
case TEK_Scalar:
Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
break;
case TEK_Complex:
EmitComplexExprIntoLValue(RV, MakeAddrLValue(ReturnValue, RV->getType()),
/*isInit*/ true);
break;
case TEK_Aggregate:
EmitAggExpr(RV, AggValueSlot::forAddr(
ReturnValue, Qualifiers(),
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased,
getOverlapForReturnValue()));
break;
}
}
++NumReturnExprs;
if (!RV || RV->isEvaluatable(getContext()))
++NumSimpleReturnExprs;
cleanupScope.ForceCleanup();
EmitBranchThroughCleanup(ReturnBlock);
}
void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
// As long as debug info is modeled with instructions, we have to ensure we
// have a place to insert here and write the stop point here.
if (HaveInsertPoint())
EmitStopPoint(&S);
for (const auto *I : S.decls())
EmitDecl(*I);
}
void CodeGenFunction::EmitBreakStmt(const BreakStmt &S) {
assert(!BreakContinueStack.empty() && "break stmt not in a loop or switch!");
// If this code is reachable then emit a stop point (if generating
// debug info). We have to do this ourselves because we are on the
// "simple" statement path.
if (HaveInsertPoint())
EmitStopPoint(&S);
EmitBranchThroughCleanup(BreakContinueStack.back().BreakBlock);
}
void CodeGenFunction::EmitContinueStmt(const ContinueStmt &S) {
assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
// If this code is reachable then emit a stop point (if generating
// debug info). We have to do this ourselves because we are on the
// "simple" statement path.
if (HaveInsertPoint())
EmitStopPoint(&S);
EmitBranchThroughCleanup(BreakContinueStack.back().ContinueBlock);
}
/// EmitCaseStmtRange - If case statement range is not too big then
/// add multiple cases to switch instruction, one for each value within
/// the range. If range is too big then emit "if" condition check.
void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S,
ArrayRef<const Attr *> Attrs) {
assert(S.getRHS() && "Expected RHS value in CaseStmt");
llvm::APSInt LHS = S.getLHS()->EvaluateKnownConstInt(getContext());
llvm::APSInt RHS = S.getRHS()->EvaluateKnownConstInt(getContext());
// Emit the code for this case. We do this first to make sure it is
// properly chained from our predecessor before generating the
// switch machinery to enter this block.
llvm::BasicBlock *CaseDest = createBasicBlock("sw.bb");
EmitBlockWithFallThrough(CaseDest, &S);
EmitStmt(S.getSubStmt());
// If range is empty, do nothing.
if (LHS.isSigned() ? RHS.slt(LHS) : RHS.ult(LHS))
return;
Stmt::Likelihood LH = Stmt::getLikelihood(Attrs);
llvm::APInt Range = RHS - LHS;
// FIXME: parameters such as this should not be hardcoded.
if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) {
// Range is small enough to add multiple switch instruction cases.
uint64_t Total = getProfileCount(&S);
unsigned NCases = Range.getZExtValue() + 1;
// We only have one region counter for the entire set of cases here, so we
// need to divide the weights evenly between the generated cases, ensuring
// that the total weight is preserved. E.g., a weight of 5 over three cases
// will be distributed as weights of 2, 2, and 1.
uint64_t Weight = Total / NCases, Rem = Total % NCases;
for (unsigned I = 0; I != NCases; ++I) {
if (SwitchWeights)
SwitchWeights->push_back(Weight + (Rem ? 1 : 0));
else if (SwitchLikelihood)
SwitchLikelihood->push_back(LH);
if (Rem)
Rem--;
SwitchInsn->addCase(Builder.getInt(LHS), CaseDest);
++LHS;
}
return;
}
// The range is too big. Emit "if" condition into a new block,
// making sure to save and restore the current insertion point.
llvm::BasicBlock *RestoreBB = Builder.GetInsertBlock();
// Push this test onto the chain of range checks (which terminates
// in the default basic block). The switch's default will be changed
// to the top of this chain after switch emission is complete.
llvm::BasicBlock *FalseDest = CaseRangeBlock;
CaseRangeBlock = createBasicBlock("sw.caserange");
CurFn->getBasicBlockList().push_back(CaseRangeBlock);
Builder.SetInsertPoint(CaseRangeBlock);
// Emit range check.
llvm::Value *Diff =
Builder.CreateSub(SwitchInsn->getCondition(), Builder.getInt(LHS));
llvm::Value *Cond =
Builder.CreateICmpULE(Diff, Builder.getInt(Range), "inbounds");
llvm::MDNode *Weights = nullptr;
if (SwitchWeights) {
uint64_t ThisCount = getProfileCount(&S);
uint64_t DefaultCount = (*SwitchWeights)[0];
Weights = createProfileWeights(ThisCount, DefaultCount);
// Since we're chaining the switch default through each large case range, we
// need to update the weight for the default, ie, the first case, to include
// this case.
(*SwitchWeights)[0] += ThisCount;
} else if (SwitchLikelihood)
Cond = emitCondLikelihoodViaExpectIntrinsic(Cond, LH);
Builder.CreateCondBr(Cond, CaseDest, FalseDest, Weights);
// Restore the appropriate insertion point.
if (RestoreBB)
Builder.SetInsertPoint(RestoreBB);
else
Builder.ClearInsertionPoint();
}
void CodeGenFunction::EmitCaseStmt(const CaseStmt &S,
ArrayRef<const Attr *> Attrs) {
// If there is no enclosing switch instance that we're aware of, then this
// case statement and its block can be elided. This situation only happens
// when we've constant-folded the switch, are emitting the constant case,
// and part of the constant case includes another case statement. For
// instance: switch (4) { case 4: do { case 5: } while (1); }
if (!SwitchInsn) {
EmitStmt(S.getSubStmt());
return;
}
// Handle case ranges.
if (S.getRHS()) {
EmitCaseStmtRange(S, Attrs);
return;
}
llvm::ConstantInt *CaseVal =
Builder.getInt(S.getLHS()->EvaluateKnownConstInt(getContext()));
+
+ // Emit debuginfo for the case value if it is an enum value.
+ const ConstantExpr *CE;
+ if (auto ICE = dyn_cast<ImplicitCastExpr>(S.getLHS()))
+ CE = dyn_cast<ConstantExpr>(ICE->getSubExpr());
+ else
+ CE = dyn_cast<ConstantExpr>(S.getLHS());
+ if (CE) {
+ if (auto DE = dyn_cast<DeclRefExpr>(CE->getSubExpr()))
+ if (CGDebugInfo *Dbg = getDebugInfo())
+ if (CGM.getCodeGenOpts().hasReducedDebugInfo())
+ Dbg->EmitGlobalVariable(DE->getDecl(),
+ APValue(llvm::APSInt(CaseVal->getValue())));
+ }
+
if (SwitchLikelihood)
SwitchLikelihood->push_back(Stmt::getLikelihood(Attrs));
// If the body of the case is just a 'break', try to not emit an empty block.
// If we're profiling or we're not optimizing, leave the block in for better
// debug and coverage analysis.
if (!CGM.getCodeGenOpts().hasProfileClangInstr() &&
CGM.getCodeGenOpts().OptimizationLevel > 0 &&
isa<BreakStmt>(S.getSubStmt())) {
JumpDest Block = BreakContinueStack.back().BreakBlock;
// Only do this optimization if there are no cleanups that need emitting.
if (isObviouslyBranchWithoutCleanups(Block)) {
if (SwitchWeights)
SwitchWeights->push_back(getProfileCount(&S));
SwitchInsn->addCase(CaseVal, Block.getBlock());
// If there was a fallthrough into this case, make sure to redirect it to
// the end of the switch as well.
if (Builder.GetInsertBlock()) {
Builder.CreateBr(Block.getBlock());
Builder.ClearInsertionPoint();
}
return;
}
}
llvm::BasicBlock *CaseDest = createBasicBlock("sw.bb");
EmitBlockWithFallThrough(CaseDest, &S);
if (SwitchWeights)
SwitchWeights->push_back(getProfileCount(&S));
SwitchInsn->addCase(CaseVal, CaseDest);
// Recursively emitting the statement is acceptable, but is not wonderful for
// code where we have many case statements nested together, i.e.:
// case 1:
// case 2:
// case 3: etc.
// Handling this recursively will create a new block for each case statement
// that falls through to the next case which is IR intensive. It also causes
// deep recursion which can run into stack depth limitations. Handle
// sequential non-range case statements specially.
//
// TODO When the next case has a likelihood attribute the code returns to the
// recursive algorithm. Maybe improve this case if it becomes common practice
// to use a lot of attributes.
const CaseStmt *CurCase = &S;
const CaseStmt *NextCase = dyn_cast<CaseStmt>(S.getSubStmt());
// Otherwise, iteratively add consecutive cases to this switch stmt.
while (NextCase && NextCase->getRHS() == nullptr) {
CurCase = NextCase;
llvm::ConstantInt *CaseVal =
Builder.getInt(CurCase->getLHS()->EvaluateKnownConstInt(getContext()));
if (SwitchWeights)
SwitchWeights->push_back(getProfileCount(NextCase));
if (CGM.getCodeGenOpts().hasProfileClangInstr()) {
CaseDest = createBasicBlock("sw.bb");
EmitBlockWithFallThrough(CaseDest, CurCase);
}
// Since this loop is only executed when the CaseStmt has no attributes
// use a hard-coded value.
if (SwitchLikelihood)
SwitchLikelihood->push_back(Stmt::LH_None);
SwitchInsn->addCase(CaseVal, CaseDest);
NextCase = dyn_cast<CaseStmt>(CurCase->getSubStmt());
}
// Generate a stop point for debug info if the case statement is
// followed by a default statement. A fallthrough case before a
// default case gets its own branch target.
if (CurCase->getSubStmt()->getStmtClass() == Stmt::DefaultStmtClass)
EmitStopPoint(CurCase);
// Normal default recursion for non-cases.
EmitStmt(CurCase->getSubStmt());
}
void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S,
ArrayRef<const Attr *> Attrs) {
// If there is no enclosing switch instance that we're aware of, then this
// default statement can be elided. This situation only happens when we've
// constant-folded the switch.
if (!SwitchInsn) {
EmitStmt(S.getSubStmt());
return;
}
llvm::BasicBlock *DefaultBlock = SwitchInsn->getDefaultDest();
assert(DefaultBlock->empty() &&
"EmitDefaultStmt: Default block already defined?");
if (SwitchLikelihood)
SwitchLikelihood->front() = Stmt::getLikelihood(Attrs);
EmitBlockWithFallThrough(DefaultBlock, &S);
EmitStmt(S.getSubStmt());
}
/// CollectStatementsForCase - Given the body of a 'switch' statement and a
/// constant value that is being switched on, see if we can dead code eliminate
/// the body of the switch to a simple series of statements to emit. Basically,
/// on a switch (5) we want to find these statements:
/// case 5:
/// printf(...); <--
/// ++i; <--
/// break;
///
/// and add them to the ResultStmts vector. If it is unsafe to do this
/// transformation (for example, one of the elided statements contains a label
/// that might be jumped to), return CSFC_Failure. If we handled it and 'S'
/// should include statements after it (e.g. the printf() line is a substmt of
/// the case) then return CSFC_FallThrough. If we handled it and found a break
/// statement, then return CSFC_Success.
///
/// If Case is non-null, then we are looking for the specified case, checking
/// that nothing we jump over contains labels. If Case is null, then we found
/// the case and are looking for the break.
///
/// If the recursive walk actually finds our Case, then we set FoundCase to
/// true.
///
enum CSFC_Result { CSFC_Failure, CSFC_FallThrough, CSFC_Success };
static CSFC_Result CollectStatementsForCase(const Stmt *S,
const SwitchCase *Case,
bool &FoundCase,
SmallVectorImpl<const Stmt*> &ResultStmts) {
// If this is a null statement, just succeed.
if (!S)
return Case ? CSFC_Success : CSFC_FallThrough;
// If this is the switchcase (case 4: or default) that we're looking for, then
// we're in business. Just add the substatement.
if (const SwitchCase *SC = dyn_cast<SwitchCase>(S)) {
if (S == Case) {
FoundCase = true;
return CollectStatementsForCase(SC->getSubStmt(), nullptr, FoundCase,
ResultStmts);
}
// Otherwise, this is some other case or default statement, just ignore it.
return CollectStatementsForCase(SC->getSubStmt(), Case, FoundCase,
ResultStmts);
}
// If we are in the live part of the code and we found our break statement,
// return a success!
if (!Case && isa<BreakStmt>(S))
return CSFC_Success;
// If this is a switch statement, then it might contain the SwitchCase, the
// break, or neither.
if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) {
// Handle this as two cases: we might be looking for the SwitchCase (if so
// the skipped statements must be skippable) or we might already have it.
CompoundStmt::const_body_iterator I = CS->body_begin(), E = CS->body_end();
bool StartedInLiveCode = FoundCase;
unsigned StartSize = ResultStmts.size();
// If we've not found the case yet, scan through looking for it.
if (Case) {
// Keep track of whether we see a skipped declaration. The code could be
// using the declaration even if it is skipped, so we can't optimize out
// the decl if the kept statements might refer to it.
bool HadSkippedDecl = false;
// If we're looking for the case, just see if we can skip each of the
// substatements.
for (; Case && I != E; ++I) {
HadSkippedDecl |= CodeGenFunction::mightAddDeclToScope(*I);
switch (CollectStatementsForCase(*I, Case, FoundCase, ResultStmts)) {
case CSFC_Failure: return CSFC_Failure;
case CSFC_Success:
// A successful result means that either 1) that the statement doesn't
// have the case and is skippable, or 2) does contain the case value
// and also contains the break to exit the switch. In the later case,
// we just verify the rest of the statements are elidable.
if (FoundCase) {
// If we found the case and skipped declarations, we can't do the
// optimization.
if (HadSkippedDecl)
return CSFC_Failure;
for (++I; I != E; ++I)
if (CodeGenFunction::ContainsLabel(*I, true))
return CSFC_Failure;
return CSFC_Success;
}
break;
case CSFC_FallThrough:
// If we have a fallthrough condition, then we must have found the
// case started to include statements. Consider the rest of the
// statements in the compound statement as candidates for inclusion.
assert(FoundCase && "Didn't find case but returned fallthrough?");
// We recursively found Case, so we're not looking for it anymore.
Case = nullptr;
// If we found the case and skipped declarations, we can't do the
// optimization.
if (HadSkippedDecl)
return CSFC_Failure;
break;
}
}
if (!FoundCase)
return CSFC_Success;
assert(!HadSkippedDecl && "fallthrough after skipping decl");
}
// If we have statements in our range, then we know that the statements are
// live and need to be added to the set of statements we're tracking.
bool AnyDecls = false;
for (; I != E; ++I) {
AnyDecls |= CodeGenFunction::mightAddDeclToScope(*I);
switch (CollectStatementsForCase(*I, nullptr, FoundCase, ResultStmts)) {
case CSFC_Failure: return CSFC_Failure;
case CSFC_FallThrough:
// A fallthrough result means that the statement was simple and just
// included in ResultStmt, keep adding them afterwards.
break;
case CSFC_Success:
// A successful result means that we found the break statement and
// stopped statement inclusion. We just ensure that any leftover stmts
// are skippable and return success ourselves.
for (++I; I != E; ++I)
if (CodeGenFunction::ContainsLabel(*I, true))
return CSFC_Failure;
return CSFC_Success;
}
}
// If we're about to fall out of a scope without hitting a 'break;', we
// can't perform the optimization if there were any decls in that scope
// (we'd lose their end-of-lifetime).
if (AnyDecls) {
// If the entire compound statement was live, there's one more thing we
// can try before giving up: emit the whole thing as a single statement.
// We can do that unless the statement contains a 'break;'.
// FIXME: Such a break must be at the end of a construct within this one.
// We could emit this by just ignoring the BreakStmts entirely.
if (StartedInLiveCode && !CodeGenFunction::containsBreak(S)) {
ResultStmts.resize(StartSize);
ResultStmts.push_back(S);
} else {
return CSFC_Failure;
}
}
return CSFC_FallThrough;
}
// Okay, this is some other statement that we don't handle explicitly, like a
// for statement or increment etc. If we are skipping over this statement,
// just verify it doesn't have labels, which would make it invalid to elide.
if (Case) {
if (CodeGenFunction::ContainsLabel(S, true))
return CSFC_Failure;
return CSFC_Success;
}
// Otherwise, we want to include this statement. Everything is cool with that
// so long as it doesn't contain a break out of the switch we're in.
if (CodeGenFunction::containsBreak(S)) return CSFC_Failure;
// Otherwise, everything is great. Include the statement and tell the caller
// that we fall through and include the next statement as well.
ResultStmts.push_back(S);
return CSFC_FallThrough;
}
/// FindCaseStatementsForValue - Find the case statement being jumped to and
/// then invoke CollectStatementsForCase to find the list of statements to emit
/// for a switch on constant. See the comment above CollectStatementsForCase
/// for more details.
static bool FindCaseStatementsForValue(const SwitchStmt &S,
const llvm::APSInt &ConstantCondValue,
SmallVectorImpl<const Stmt*> &ResultStmts,
ASTContext &C,
const SwitchCase *&ResultCase) {
// First step, find the switch case that is being branched to. We can do this
// efficiently by scanning the SwitchCase list.
const SwitchCase *Case = S.getSwitchCaseList();
const DefaultStmt *DefaultCase = nullptr;
for (; Case; Case = Case->getNextSwitchCase()) {
// It's either a default or case. Just remember the default statement in
// case we're not jumping to any numbered cases.
if (const DefaultStmt *DS = dyn_cast<DefaultStmt>(Case)) {
DefaultCase = DS;
continue;
}
// Check to see if this case is the one we're looking for.
const CaseStmt *CS = cast<CaseStmt>(Case);
// Don't handle case ranges yet.
if (CS->getRHS()) return false;
// If we found our case, remember it as 'case'.
if (CS->getLHS()->EvaluateKnownConstInt(C) == ConstantCondValue)
break;
}
// If we didn't find a matching case, we use a default if it exists, or we
// elide the whole switch body!
if (!Case) {
// It is safe to elide the body of the switch if it doesn't contain labels
// etc. If it is safe, return successfully with an empty ResultStmts list.
if (!DefaultCase)
return !CodeGenFunction::ContainsLabel(&S);
Case = DefaultCase;
}
// Ok, we know which case is being jumped to, try to collect all the
// statements that follow it. This can fail for a variety of reasons. Also,
// check to see that the recursive walk actually found our case statement.
// Insane cases like this can fail to find it in the recursive walk since we
// don't handle every stmt kind:
// switch (4) {
// while (1) {
// case 4: ...
bool FoundCase = false;
ResultCase = Case;
return CollectStatementsForCase(S.getBody(), Case, FoundCase,
ResultStmts) != CSFC_Failure &&
FoundCase;
}
static Optional<SmallVector<uint64_t, 16>>
getLikelihoodWeights(ArrayRef<Stmt::Likelihood> Likelihoods) {
// Are there enough branches to weight them?
if (Likelihoods.size() <= 1)
return None;
uint64_t NumUnlikely = 0;
uint64_t NumNone = 0;
uint64_t NumLikely = 0;
for (const auto LH : Likelihoods) {
switch (LH) {
case Stmt::LH_Unlikely:
++NumUnlikely;
break;
case Stmt::LH_None:
++NumNone;
break;
case Stmt::LH_Likely:
++NumLikely;
break;
}
}
// Is there a likelihood attribute used?
if (NumUnlikely == 0 && NumLikely == 0)
return None;
// When multiple cases share the same code they can be combined during
// optimization. In that case the weights of the branch will be the sum of
// the individual weights. Make sure the combined sum of all neutral cases
// doesn't exceed the value of a single likely attribute.
// The additions both avoid divisions by 0 and make sure the weights of None
// don't exceed the weight of Likely.
const uint64_t Likely = INT32_MAX / (NumLikely + 2);
const uint64_t None = Likely / (NumNone + 1);
const uint64_t Unlikely = 0;
SmallVector<uint64_t, 16> Result;
Result.reserve(Likelihoods.size());
for (const auto LH : Likelihoods) {
switch (LH) {
case Stmt::LH_Unlikely:
Result.push_back(Unlikely);
break;
case Stmt::LH_None:
Result.push_back(None);
break;
case Stmt::LH_Likely:
Result.push_back(Likely);
break;
}
}
return Result;
}
void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
// Handle nested switch statements.
llvm::SwitchInst *SavedSwitchInsn = SwitchInsn;
SmallVector<uint64_t, 16> *SavedSwitchWeights = SwitchWeights;
SmallVector<Stmt::Likelihood, 16> *SavedSwitchLikelihood = SwitchLikelihood;
llvm::BasicBlock *SavedCRBlock = CaseRangeBlock;
// See if we can constant fold the condition of the switch and therefore only
// emit the live case statement (if any) of the switch.
llvm::APSInt ConstantCondValue;
if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue)) {
SmallVector<const Stmt*, 4> CaseStmts;
const SwitchCase *Case = nullptr;
if (FindCaseStatementsForValue(S, ConstantCondValue, CaseStmts,
getContext(), Case)) {
if (Case)
incrementProfileCounter(Case);
RunCleanupsScope ExecutedScope(*this);
if (S.getInit())
EmitStmt(S.getInit());
// Emit the condition variable if needed inside the entire cleanup scope
// used by this special case for constant folded switches.
if (S.getConditionVariable())
EmitDecl(*S.getConditionVariable());
// At this point, we are no longer "within" a switch instance, so
// we can temporarily enforce this to ensure that any embedded case
// statements are not emitted.
SwitchInsn = nullptr;
// Okay, we can dead code eliminate everything except this case. Emit the
// specified series of statements and we're good.
for (unsigned i = 0, e = CaseStmts.size(); i != e; ++i)
EmitStmt(CaseStmts[i]);
incrementProfileCounter(&S);
// Now we want to restore the saved switch instance so that nested
// switches continue to function properly
SwitchInsn = SavedSwitchInsn;
return;
}
}
JumpDest SwitchExit = getJumpDestInCurrentScope("sw.epilog");
RunCleanupsScope ConditionScope(*this);
if (S.getInit())
EmitStmt(S.getInit());
if (S.getConditionVariable())
EmitDecl(*S.getConditionVariable());
llvm::Value *CondV = EmitScalarExpr(S.getCond());
// Create basic block to hold stuff that comes after switch
// statement. We also need to create a default block now so that
// explicit case ranges tests can have a place to jump to on
// failure.
llvm::BasicBlock *DefaultBlock = createBasicBlock("sw.default");
SwitchInsn = Builder.CreateSwitch(CondV, DefaultBlock);
if (PGO.haveRegionCounts()) {
// Walk the SwitchCase list to find how many there are.
uint64_t DefaultCount = 0;
unsigned NumCases = 0;
for (const SwitchCase *Case = S.getSwitchCaseList();
Case;
Case = Case->getNextSwitchCase()) {
if (isa<DefaultStmt>(Case))
DefaultCount = getProfileCount(Case);
NumCases += 1;
}
SwitchWeights = new SmallVector<uint64_t, 16>();
SwitchWeights->reserve(NumCases);
// The default needs to be first. We store the edge count, so we already
// know the right weight.
SwitchWeights->push_back(DefaultCount);
} else if (CGM.getCodeGenOpts().OptimizationLevel) {
SwitchLikelihood = new SmallVector<Stmt::Likelihood, 16>();
// Initialize the default case.
SwitchLikelihood->push_back(Stmt::LH_None);
}
CaseRangeBlock = DefaultBlock;
// Clear the insertion point to indicate we are in unreachable code.
Builder.ClearInsertionPoint();
// All break statements jump to NextBlock. If BreakContinueStack is non-empty
// then reuse last ContinueBlock.
JumpDest OuterContinue;
if (!BreakContinueStack.empty())
OuterContinue = BreakContinueStack.back().ContinueBlock;
BreakContinueStack.push_back(BreakContinue(SwitchExit, OuterContinue));
// Emit switch body.
EmitStmt(S.getBody());
BreakContinueStack.pop_back();
// Update the default block in case explicit case range tests have
// been chained on top.
SwitchInsn->setDefaultDest(CaseRangeBlock);
// If a default was never emitted:
if (!DefaultBlock->getParent()) {
// If we have cleanups, emit the default block so that there's a
// place to jump through the cleanups from.
if (ConditionScope.requiresCleanups()) {
EmitBlock(DefaultBlock);
// Otherwise, just forward the default block to the switch end.
} else {
DefaultBlock->replaceAllUsesWith(SwitchExit.getBlock());
delete DefaultBlock;
}
}
ConditionScope.ForceCleanup();
// Emit continuation.
EmitBlock(SwitchExit.getBlock(), true);
incrementProfileCounter(&S);
// If the switch has a condition wrapped by __builtin_unpredictable,
// create metadata that specifies that the switch is unpredictable.
// Don't bother if not optimizing because that metadata would not be used.
auto *Call = dyn_cast<CallExpr>(S.getCond());
if (Call && CGM.getCodeGenOpts().OptimizationLevel != 0) {
auto *FD = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
if (FD && FD->getBuiltinID() == Builtin::BI__builtin_unpredictable) {
llvm::MDBuilder MDHelper(getLLVMContext());
SwitchInsn->setMetadata(llvm::LLVMContext::MD_unpredictable,
MDHelper.createUnpredictable());
}
}
if (SwitchWeights) {
assert(SwitchWeights->size() == 1 + SwitchInsn->getNumCases() &&
"switch weights do not match switch cases");
// If there's only one jump destination there's no sense weighting it.
if (SwitchWeights->size() > 1)
SwitchInsn->setMetadata(llvm::LLVMContext::MD_prof,
createProfileWeights(*SwitchWeights));
delete SwitchWeights;
} else if (SwitchLikelihood) {
assert(SwitchLikelihood->size() == 1 + SwitchInsn->getNumCases() &&
"switch likelihoods do not match switch cases");
Optional<SmallVector<uint64_t, 16>> LHW =
getLikelihoodWeights(*SwitchLikelihood);
if (LHW) {
llvm::MDBuilder MDHelper(CGM.getLLVMContext());
SwitchInsn->setMetadata(llvm::LLVMContext::MD_prof,
createProfileWeights(*LHW));
}
delete SwitchLikelihood;
}
SwitchInsn = SavedSwitchInsn;
SwitchWeights = SavedSwitchWeights;
SwitchLikelihood = SavedSwitchLikelihood;
CaseRangeBlock = SavedCRBlock;
}
static std::string
SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=nullptr) {
std::string Result;
while (*Constraint) {
switch (*Constraint) {
default:
Result += Target.convertConstraint(Constraint);
break;
// Ignore these
case '*':
case '?':
case '!':
case '=': // Will see this and the following in mult-alt constraints.
case '+':
break;
case '#': // Ignore the rest of the constraint alternative.
while (Constraint[1] && Constraint[1] != ',')
Constraint++;
break;
case '&':
case '%':
Result += *Constraint;
while (Constraint[1] && Constraint[1] == *Constraint)
Constraint++;
break;
case ',':
Result += "|";
break;
case 'g':
Result += "imr";
break;
case '[': {
assert(OutCons &&
"Must pass output names to constraints with a symbolic name");
unsigned Index;
bool result = Target.resolveSymbolicName(Constraint, *OutCons, Index);
assert(result && "Could not resolve symbolic name"); (void)result;
Result += llvm::utostr(Index);
break;
}
}
Constraint++;
}
return Result;
}
/// AddVariableConstraints - Look at AsmExpr and if it is a variable declared
/// as using a particular register add that as a constraint that will be used
/// in this asm stmt.
static std::string
AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr,
const TargetInfo &Target, CodeGenModule &CGM,
const AsmStmt &Stmt, const bool EarlyClobber,
std::string *GCCReg = nullptr) {
const DeclRefExpr *AsmDeclRef = dyn_cast<DeclRefExpr>(&AsmExpr);
if (!AsmDeclRef)
return Constraint;
const ValueDecl &Value = *AsmDeclRef->getDecl();
const VarDecl *Variable = dyn_cast<VarDecl>(&Value);
if (!Variable)
return Constraint;
if (Variable->getStorageClass() != SC_Register)
return Constraint;
AsmLabelAttr *Attr = Variable->getAttr<AsmLabelAttr>();
if (!Attr)
return Constraint;
StringRef Register = Attr->getLabel();
assert(Target.isValidGCCRegisterName(Register));
// We're using validateOutputConstraint here because we only care if
// this is a register constraint.
TargetInfo::ConstraintInfo Info(Constraint, "");
if (Target.validateOutputConstraint(Info) &&
!Info.allowsRegister()) {
CGM.ErrorUnsupported(&Stmt, "__asm__");
return Constraint;
}
// Canonicalize the register here before returning it.
Register = Target.getNormalizedGCCRegisterName(Register);
if (GCCReg != nullptr)
*GCCReg = Register.str();
return (EarlyClobber ? "&{" : "{") + Register.str() + "}";
}
std::pair<llvm::Value*, llvm::Type *> CodeGenFunction::EmitAsmInputLValue(
const TargetInfo::ConstraintInfo &Info, LValue InputValue,
QualType InputType, std::string &ConstraintStr, SourceLocation Loc) {
if (Info.allowsRegister() || !Info.allowsMemory()) {
if (CodeGenFunction::hasScalarEvaluationKind(InputType))
return {EmitLoadOfLValue(InputValue, Loc).getScalarVal(), nullptr};
llvm::Type *Ty = ConvertType(InputType);
uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty);
if ((Size <= 64 && llvm::isPowerOf2_64(Size)) ||
getTargetHooks().isScalarizableAsmOperand(*this, Ty)) {
Ty = llvm::IntegerType::get(getLLVMContext(), Size);
return {Builder.CreateLoad(Builder.CreateElementBitCast(
InputValue.getAddress(*this), Ty)),
nullptr};
}
}
Address Addr = InputValue.getAddress(*this);
ConstraintStr += '*';
return {Addr.getPointer(), Addr.getElementType()};
}
std::pair<llvm::Value *, llvm::Type *>
CodeGenFunction::EmitAsmInput(const TargetInfo::ConstraintInfo &Info,
const Expr *InputExpr,
std::string &ConstraintStr) {
// If this can't be a register or memory, i.e., has to be a constant
// (immediate or symbolic), try to emit it as such.
if (!Info.allowsRegister() && !Info.allowsMemory()) {
if (Info.requiresImmediateConstant()) {
Expr::EvalResult EVResult;
InputExpr->EvaluateAsRValue(EVResult, getContext(), true);
llvm::APSInt IntResult;
if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
getContext()))
return {llvm::ConstantInt::get(getLLVMContext(), IntResult), nullptr};
}
Expr::EvalResult Result;
if (InputExpr->EvaluateAsInt(Result, getContext()))
return {llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt()),
nullptr};
}
if (Info.allowsRegister() || !Info.allowsMemory())
if (CodeGenFunction::hasScalarEvaluationKind(InputExpr->getType()))
return {EmitScalarExpr(InputExpr), nullptr};
if (InputExpr->getStmtClass() == Expr::CXXThisExprClass)
return {EmitScalarExpr(InputExpr), nullptr};
InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
LValue Dest = EmitLValue(InputExpr);
return EmitAsmInputLValue(Info, Dest, InputExpr->getType(), ConstraintStr,
InputExpr->getExprLoc());
}
/// getAsmSrcLocInfo - Return the !srcloc metadata node to attach to an inline
/// asm call instruction. The !srcloc MDNode contains a list of constant
/// integers which are the source locations of the start of each line in the
/// asm.
static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
CodeGenFunction &CGF) {
SmallVector<llvm::Metadata *, 8> Locs;
// Add the location of the first line to the MDNode.
Locs.push_back(llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
CGF.Int64Ty, Str->getBeginLoc().getRawEncoding())));
StringRef StrVal = Str->getString();
if (!StrVal.empty()) {
const SourceManager &SM = CGF.CGM.getContext().getSourceManager();
const LangOptions &LangOpts = CGF.CGM.getLangOpts();
unsigned StartToken = 0;
unsigned ByteOffset = 0;
// Add the location of the start of each subsequent line of the asm to the
// MDNode.
for (unsigned i = 0, e = StrVal.size() - 1; i != e; ++i) {
if (StrVal[i] != '\n') continue;
SourceLocation LineLoc = Str->getLocationOfByte(
i + 1, SM, LangOpts, CGF.getTarget(), &StartToken, &ByteOffset);
Locs.push_back(llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(CGF.Int64Ty, LineLoc.getRawEncoding())));
}
}
return llvm::MDNode::get(CGF.getLLVMContext(), Locs);
}
static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect,
bool HasUnwindClobber, bool ReadOnly,
bool ReadNone, bool NoMerge, const AsmStmt &S,
const std::vector<llvm::Type *> &ResultRegTypes,
const std::vector<llvm::Type *> &ArgElemTypes,
CodeGenFunction &CGF,
std::vector<llvm::Value *> &RegResults) {
if (!HasUnwindClobber)
Result.addFnAttr(llvm::Attribute::NoUnwind);
if (NoMerge)
Result.addFnAttr(llvm::Attribute::NoMerge);
// Attach readnone and readonly attributes.
if (!HasSideEffect) {
if (ReadNone)
Result.addFnAttr(llvm::Attribute::ReadNone);
else if (ReadOnly)
Result.addFnAttr(llvm::Attribute::ReadOnly);
}
// Add elementtype attribute for indirect constraints.
for (auto Pair : llvm::enumerate(ArgElemTypes)) {
if (Pair.value()) {
auto Attr = llvm::Attribute::get(
CGF.getLLVMContext(), llvm::Attribute::ElementType, Pair.value());
Result.addParamAttr(Pair.index(), Attr);
}
}
// Slap the source location of the inline asm into a !srcloc metadata on the
// call.
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S))
Result.setMetadata("srcloc",
getAsmSrcLocInfo(gccAsmStmt->getAsmString(), CGF));
else {
// At least put the line number on MS inline asm blobs.
llvm::Constant *Loc =
llvm::ConstantInt::get(CGF.Int64Ty, S.getAsmLoc().getRawEncoding());
Result.setMetadata("srcloc",
llvm::MDNode::get(CGF.getLLVMContext(),
llvm::ConstantAsMetadata::get(Loc)));
}
if (CGF.getLangOpts().assumeFunctionsAreConvergent())
// Conservatively, mark all inline asm blocks in CUDA or OpenCL as
// convergent (meaning, they may call an intrinsically convergent op, such
// as bar.sync, and so can't have certain optimizations applied around
// them).
Result.addFnAttr(llvm::Attribute::Convergent);
// Extract all of the register value results from the asm.
if (ResultRegTypes.size() == 1) {
RegResults.push_back(&Result);
} else {
for (unsigned i = 0, e = ResultRegTypes.size(); i != e; ++i) {
llvm::Value *Tmp = CGF.Builder.CreateExtractValue(&Result, i, "asmresult");
RegResults.push_back(Tmp);
}
}
}
void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Pop all cleanup blocks at the end of the asm statement.
CodeGenFunction::RunCleanupsScope Cleanups(*this);
// Assemble the final asm string.
std::string AsmString = S.generateAsmString(getContext());
// Get all the output and input constraints together.
SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
StringRef Name;
if (const GCCAsmStmt *GAS = dyn_cast<GCCAsmStmt>(&S))
Name = GAS->getOutputName(i);
TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i), Name);
bool IsValid = getTarget().validateOutputConstraint(Info); (void)IsValid;
assert(IsValid && "Failed to parse output constraint");
OutputConstraintInfos.push_back(Info);
}
for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
StringRef Name;
if (const GCCAsmStmt *GAS = dyn_cast<GCCAsmStmt>(&S))
Name = GAS->getInputName(i);
TargetInfo::ConstraintInfo Info(S.getInputConstraint(i), Name);
bool IsValid =
getTarget().validateInputConstraint(OutputConstraintInfos, Info);
assert(IsValid && "Failed to parse input constraint"); (void)IsValid;
InputConstraintInfos.push_back(Info);
}
std::string Constraints;
std::vector<LValue> ResultRegDests;
std::vector<QualType> ResultRegQualTys;
std::vector<llvm::Type *> ResultRegTypes;
std::vector<llvm::Type *> ResultTruncRegTypes;
std::vector<llvm::Type *> ArgTypes;
std::vector<llvm::Type *> ArgElemTypes;
std::vector<llvm::Value*> Args;
llvm::BitVector ResultTypeRequiresCast;
llvm::BitVector ResultRegIsFlagReg;
// Keep track of inout constraints.
std::string InOutConstraints;
std::vector<llvm::Value*> InOutArgs;
std::vector<llvm::Type*> InOutArgTypes;
std::vector<llvm::Type*> InOutArgElemTypes;
// Keep track of out constraints for tied input operand.
std::vector<std::string> OutputConstraints;
// Keep track of defined physregs.
llvm::SmallSet<std::string, 8> PhysRegOutputs;
// An inline asm can be marked readonly if it meets the following conditions:
// - it doesn't have any sideeffects
// - it doesn't clobber memory
// - it doesn't return a value by-reference
// It can be marked readnone if it doesn't have any input memory constraints
// in addition to meeting the conditions listed above.
bool ReadOnly = true, ReadNone = true;
for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i];
// Simplify the output constraint.
std::string OutputConstraint(S.getOutputConstraint(i));
OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1,
getTarget(), &OutputConstraintInfos);
const Expr *OutExpr = S.getOutputExpr(i);
OutExpr = OutExpr->IgnoreParenNoopCasts(getContext());
std::string GCCReg;
OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr,
getTarget(), CGM, S,
Info.earlyClobber(),
&GCCReg);
// Give an error on multiple outputs to same physreg.
if (!GCCReg.empty() && !PhysRegOutputs.insert(GCCReg).second)
CGM.Error(S.getAsmLoc(), "multiple outputs to hard register: " + GCCReg);
OutputConstraints.push_back(OutputConstraint);
LValue Dest = EmitLValue(OutExpr);
if (!Constraints.empty())
Constraints += ',';
// If this is a register output, then make the inline asm return it
// by-value. If this is a memory result, return the value by-reference.
QualType QTy = OutExpr->getType();
const bool IsScalarOrAggregate = hasScalarEvaluationKind(QTy) ||
hasAggregateEvaluationKind(QTy);
if (!Info.allowsMemory() && IsScalarOrAggregate) {
Constraints += "=" + OutputConstraint;
ResultRegQualTys.push_back(QTy);
ResultRegDests.push_back(Dest);
bool IsFlagReg = llvm::StringRef(OutputConstraint).startswith("{@cc");
ResultRegIsFlagReg.push_back(IsFlagReg);
llvm::Type *Ty = ConvertTypeForMem(QTy);
const bool RequiresCast = Info.allowsRegister() &&
(getTargetHooks().isScalarizableAsmOperand(*this, Ty) ||
Ty->isAggregateType());
ResultTruncRegTypes.push_back(Ty);
ResultTypeRequiresCast.push_back(RequiresCast);
if (RequiresCast) {
unsigned Size = getContext().getTypeSize(QTy);
Ty = llvm::IntegerType::get(getLLVMContext(), Size);
}
ResultRegTypes.push_back(Ty);
// If this output is tied to an input, and if the input is larger, then
// we need to set the actual result type of the inline asm node to be the
// same as the input type.
if (Info.hasMatchingInput()) {
unsigned InputNo;
for (InputNo = 0; InputNo != S.getNumInputs(); ++InputNo) {
TargetInfo::ConstraintInfo &Input = InputConstraintInfos[InputNo];
if (Input.hasTiedOperand() && Input.getTiedOperand() == i)
break;
}
assert(InputNo != S.getNumInputs() && "Didn't find matching input!");
QualType InputTy = S.getInputExpr(InputNo)->getType();
QualType OutputType = OutExpr->getType();
uint64_t InputSize = getContext().getTypeSize(InputTy);
if (getContext().getTypeSize(OutputType) < InputSize) {
// Form the asm to return the value as a larger integer or fp type.
ResultRegTypes.back() = ConvertType(InputTy);
}
}
if (llvm::Type* AdjTy =
getTargetHooks().adjustInlineAsmType(*this, OutputConstraint,
ResultRegTypes.back()))
ResultRegTypes.back() = AdjTy;
else {
CGM.getDiags().Report(S.getAsmLoc(),
diag::err_asm_invalid_type_in_input)
<< OutExpr->getType() << OutputConstraint;
}
// Update largest vector width for any vector types.
if (auto *VT = dyn_cast<llvm::VectorType>(ResultRegTypes.back()))
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
VT->getPrimitiveSizeInBits().getKnownMinSize());
} else {
Address DestAddr = Dest.getAddress(*this);
// Matrix types in memory are represented by arrays, but accessed through
// vector pointers, with the alignment specified on the access operation.
// For inline assembly, update pointer arguments to use vector pointers.
// Otherwise there will be a mis-match if the matrix is also an
// input-argument which is represented as vector.
if (isa<MatrixType>(OutExpr->getType().getCanonicalType()))
DestAddr = Builder.CreateElementBitCast(
DestAddr, ConvertType(OutExpr->getType()));
ArgTypes.push_back(DestAddr.getType());
ArgElemTypes.push_back(DestAddr.getElementType());
Args.push_back(DestAddr.getPointer());
Constraints += "=*";
Constraints += OutputConstraint;
ReadOnly = ReadNone = false;
}
if (Info.isReadWrite()) {
InOutConstraints += ',';
const Expr *InputExpr = S.getOutputExpr(i);
llvm::Value *Arg;
llvm::Type *ArgElemType;
std::tie(Arg, ArgElemType) = EmitAsmInputLValue(
Info, Dest, InputExpr->getType(), InOutConstraints,
InputExpr->getExprLoc());
if (llvm::Type* AdjTy =
getTargetHooks().adjustInlineAsmType(*this, OutputConstraint,
Arg->getType()))
Arg = Builder.CreateBitCast(Arg, AdjTy);
// Update largest vector width for any vector types.
if (auto *VT = dyn_cast<llvm::VectorType>(Arg->getType()))
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
VT->getPrimitiveSizeInBits().getKnownMinSize());
// Only tie earlyclobber physregs.
if (Info.allowsRegister() && (GCCReg.empty() || Info.earlyClobber()))
InOutConstraints += llvm::utostr(i);
else
InOutConstraints += OutputConstraint;
InOutArgTypes.push_back(Arg->getType());
InOutArgElemTypes.push_back(ArgElemType);
InOutArgs.push_back(Arg);
}
}
// If this is a Microsoft-style asm blob, store the return registers (EAX:EDX)
// to the return value slot. Only do this when returning in registers.
if (isa<MSAsmStmt>(&S)) {
const ABIArgInfo &RetAI = CurFnInfo->getReturnInfo();
if (RetAI.isDirect() || RetAI.isExtend()) {
// Make a fake lvalue for the return value slot.
LValue ReturnSlot = MakeAddrLValueWithoutTBAA(ReturnValue, FnRetTy);
CGM.getTargetCodeGenInfo().addReturnRegisterOutputs(
*this, ReturnSlot, Constraints, ResultRegTypes, ResultTruncRegTypes,
ResultRegDests, AsmString, S.getNumOutputs());
SawAsmBlock = true;
}
}
for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
const Expr *InputExpr = S.getInputExpr(i);
TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
if (Info.allowsMemory())
ReadNone = false;
if (!Constraints.empty())
Constraints += ',';
// Simplify the input constraint.
std::string InputConstraint(S.getInputConstraint(i));
InputConstraint = SimplifyConstraint(InputConstraint.c_str(), getTarget(),
&OutputConstraintInfos);
InputConstraint = AddVariableConstraints(
InputConstraint, *InputExpr->IgnoreParenNoopCasts(getContext()),
getTarget(), CGM, S, false /* No EarlyClobber */);
std::string ReplaceConstraint (InputConstraint);
llvm::Value *Arg;
llvm::Type *ArgElemType;
std::tie(Arg, ArgElemType) = EmitAsmInput(Info, InputExpr, Constraints);
// If this input argument is tied to a larger output result, extend the
// input to be the same size as the output. The LLVM backend wants to see
// the input and output of a matching constraint be the same size. Note
// that GCC does not define what the top bits are here. We use zext because
// that is usually cheaper, but LLVM IR should really get an anyext someday.
if (Info.hasTiedOperand()) {
unsigned Output = Info.getTiedOperand();
QualType OutputType = S.getOutputExpr(Output)->getType();
QualType InputTy = InputExpr->getType();
if (getContext().getTypeSize(OutputType) >
getContext().getTypeSize(InputTy)) {
// Use ptrtoint as appropriate so that we can do our extension.
if (isa<llvm::PointerType>(Arg->getType()))
Arg = Builder.CreatePtrToInt(Arg, IntPtrTy);
llvm::Type *OutputTy = ConvertType(OutputType);
if (isa<llvm::IntegerType>(OutputTy))
Arg = Builder.CreateZExt(Arg, OutputTy);
else if (isa<llvm::PointerType>(OutputTy))
Arg = Builder.CreateZExt(Arg, IntPtrTy);
else if (OutputTy->isFloatingPointTy())
Arg = Builder.CreateFPExt(Arg, OutputTy);
}
// Deal with the tied operands' constraint code in adjustInlineAsmType.
ReplaceConstraint = OutputConstraints[Output];
}
if (llvm::Type* AdjTy =
getTargetHooks().adjustInlineAsmType(*this, ReplaceConstraint,
Arg->getType()))
Arg = Builder.CreateBitCast(Arg, AdjTy);
else
CGM.getDiags().Report(S.getAsmLoc(), diag::err_asm_invalid_type_in_input)
<< InputExpr->getType() << InputConstraint;
// Update largest vector width for any vector types.
if (auto *VT = dyn_cast<llvm::VectorType>(Arg->getType()))
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
VT->getPrimitiveSizeInBits().getKnownMinSize());
ArgTypes.push_back(Arg->getType());
ArgElemTypes.push_back(ArgElemType);
Args.push_back(Arg);
Constraints += InputConstraint;
}
// Append the "input" part of inout constraints.
for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) {
ArgTypes.push_back(InOutArgTypes[i]);
ArgElemTypes.push_back(InOutArgElemTypes[i]);
Args.push_back(InOutArgs[i]);
}
Constraints += InOutConstraints;
// Labels
SmallVector<llvm::BasicBlock *, 16> Transfer;
llvm::BasicBlock *Fallthrough = nullptr;
bool IsGCCAsmGoto = false;
if (const auto *GS = dyn_cast<GCCAsmStmt>(&S)) {
IsGCCAsmGoto = GS->isAsmGoto();
if (IsGCCAsmGoto) {
for (const auto *E : GS->labels()) {
JumpDest Dest = getJumpDestForLabel(E->getLabel());
Transfer.push_back(Dest.getBlock());
if (!Constraints.empty())
Constraints += ',';
Constraints += "!i";
}
Fallthrough = createBasicBlock("asm.fallthrough");
}
}
bool HasUnwindClobber = false;
// Clobbers
for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
StringRef Clobber = S.getClobber(i);
if (Clobber == "memory")
ReadOnly = ReadNone = false;
else if (Clobber == "unwind") {
HasUnwindClobber = true;
continue;
} else if (Clobber != "cc") {
Clobber = getTarget().getNormalizedGCCRegisterName(Clobber);
if (CGM.getCodeGenOpts().StackClashProtector &&
getTarget().isSPRegName(Clobber)) {
CGM.getDiags().Report(S.getAsmLoc(),
diag::warn_stack_clash_protection_inline_asm);
}
}
if (isa<MSAsmStmt>(&S)) {
if (Clobber == "eax" || Clobber == "edx") {
if (Constraints.find("=&A") != std::string::npos)
continue;
std::string::size_type position1 =
Constraints.find("={" + Clobber.str() + "}");
if (position1 != std::string::npos) {
Constraints.insert(position1 + 1, "&");
continue;
}
std::string::size_type position2 = Constraints.find("=A");
if (position2 != std::string::npos) {
Constraints.insert(position2 + 1, "&");
continue;
}
}
}
if (!Constraints.empty())
Constraints += ',';
Constraints += "~{";
Constraints += Clobber;
Constraints += '}';
}
assert(!(HasUnwindClobber && IsGCCAsmGoto) &&
"unwind clobber can't be used with asm goto");
// Add machine specific clobbers
std::string MachineClobbers = getTarget().getClobbers();
if (!MachineClobbers.empty()) {
if (!Constraints.empty())
Constraints += ',';
Constraints += MachineClobbers;
}
llvm::Type *ResultType;
if (ResultRegTypes.empty())
ResultType = VoidTy;
else if (ResultRegTypes.size() == 1)
ResultType = ResultRegTypes[0];
else
ResultType = llvm::StructType::get(getLLVMContext(), ResultRegTypes);
llvm::FunctionType *FTy =
llvm::FunctionType::get(ResultType, ArgTypes, false);
bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0;
llvm::InlineAsm::AsmDialect GnuAsmDialect =
CGM.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT
? llvm::InlineAsm::AD_ATT
: llvm::InlineAsm::AD_Intel;
llvm::InlineAsm::AsmDialect AsmDialect = isa<MSAsmStmt>(&S) ?
llvm::InlineAsm::AD_Intel : GnuAsmDialect;
llvm::InlineAsm *IA = llvm::InlineAsm::get(
FTy, AsmString, Constraints, HasSideEffect,
/* IsAlignStack */ false, AsmDialect, HasUnwindClobber);
std::vector<llvm::Value*> RegResults;
if (IsGCCAsmGoto) {
llvm::CallBrInst *Result =
Builder.CreateCallBr(IA, Fallthrough, Transfer, Args);
EmitBlock(Fallthrough);
UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, false,
ReadOnly, ReadNone, InNoMergeAttributedStmt, S,
ResultRegTypes, ArgElemTypes, *this, RegResults);
} else if (HasUnwindClobber) {
llvm::CallBase *Result = EmitCallOrInvoke(IA, Args, "");
UpdateAsmCallInst(*Result, HasSideEffect, true, ReadOnly, ReadNone,
InNoMergeAttributedStmt, S, ResultRegTypes, ArgElemTypes,
*this, RegResults);
} else {
llvm::CallInst *Result =
Builder.CreateCall(IA, Args, getBundlesForFunclet(IA));
UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, false,
ReadOnly, ReadNone, InNoMergeAttributedStmt, S,
ResultRegTypes, ArgElemTypes, *this, RegResults);
}
assert(RegResults.size() == ResultRegTypes.size());
assert(RegResults.size() == ResultTruncRegTypes.size());
assert(RegResults.size() == ResultRegDests.size());
// ResultRegDests can be also populated by addReturnRegisterOutputs() above,
// in which case its size may grow.
assert(ResultTypeRequiresCast.size() <= ResultRegDests.size());
assert(ResultRegIsFlagReg.size() <= ResultRegDests.size());
for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
llvm::Value *Tmp = RegResults[i];
llvm::Type *TruncTy = ResultTruncRegTypes[i];
if ((i < ResultRegIsFlagReg.size()) && ResultRegIsFlagReg[i]) {
// Target must guarantee the Value `Tmp` here is lowered to a boolean
// value.
llvm::Constant *Two = llvm::ConstantInt::get(Tmp->getType(), 2);
llvm::Value *IsBooleanValue =
Builder.CreateCmp(llvm::CmpInst::ICMP_ULT, Tmp, Two);
llvm::Function *FnAssume = CGM.getIntrinsic(llvm::Intrinsic::assume);
Builder.CreateCall(FnAssume, IsBooleanValue);
}
// If the result type of the LLVM IR asm doesn't match the result type of
// the expression, do the conversion.
if (ResultRegTypes[i] != ResultTruncRegTypes[i]) {
// Truncate the integer result to the right size, note that TruncTy can be
// a pointer.
if (TruncTy->isFloatingPointTy())
Tmp = Builder.CreateFPTrunc(Tmp, TruncTy);
else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) {
uint64_t ResSize = CGM.getDataLayout().getTypeSizeInBits(TruncTy);
Tmp = Builder.CreateTrunc(Tmp,
llvm::IntegerType::get(getLLVMContext(), (unsigned)ResSize));
Tmp = Builder.CreateIntToPtr(Tmp, TruncTy);
} else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) {
uint64_t TmpSize =CGM.getDataLayout().getTypeSizeInBits(Tmp->getType());
Tmp = Builder.CreatePtrToInt(Tmp,
llvm::IntegerType::get(getLLVMContext(), (unsigned)TmpSize));
Tmp = Builder.CreateTrunc(Tmp, TruncTy);
} else if (TruncTy->isIntegerTy()) {
Tmp = Builder.CreateZExtOrTrunc(Tmp, TruncTy);
} else if (TruncTy->isVectorTy()) {
Tmp = Builder.CreateBitCast(Tmp, TruncTy);
}
}
LValue Dest = ResultRegDests[i];
// ResultTypeRequiresCast elements correspond to the first
// ResultTypeRequiresCast.size() elements of RegResults.
if ((i < ResultTypeRequiresCast.size()) && ResultTypeRequiresCast[i]) {
unsigned Size = getContext().getTypeSize(ResultRegQualTys[i]);
Address A = Builder.CreateElementBitCast(Dest.getAddress(*this),
ResultRegTypes[i]);
if (getTargetHooks().isScalarizableAsmOperand(*this, TruncTy)) {
Builder.CreateStore(Tmp, A);
continue;
}
QualType Ty = getContext().getIntTypeForBitwidth(Size, /*Signed*/ false);
if (Ty.isNull()) {
const Expr *OutExpr = S.getOutputExpr(i);
CGM.getDiags().Report(OutExpr->getExprLoc(),
diag::err_store_value_to_reg);
return;
}
Dest = MakeAddrLValue(A, Ty);
}
EmitStoreThroughLValue(RValue::get(Tmp), Dest);
}
}
LValue CodeGenFunction::InitCapturedStruct(const CapturedStmt &S) {
const RecordDecl *RD = S.getCapturedRecordDecl();
QualType RecordTy = getContext().getRecordType(RD);
// Initialize the captured struct.
LValue SlotLV =
MakeAddrLValue(CreateMemTemp(RecordTy, "agg.captured"), RecordTy);
RecordDecl::field_iterator CurField = RD->field_begin();
for (CapturedStmt::const_capture_init_iterator I = S.capture_init_begin(),
E = S.capture_init_end();
I != E; ++I, ++CurField) {
LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField);
if (CurField->hasCapturedVLAType()) {
EmitLambdaVLACapture(CurField->getCapturedVLAType(), LV);
} else {
EmitInitializerForField(*CurField, LV, *I);
}
}
return SlotLV;
}
/// Generate an outlined function for the body of a CapturedStmt, store any
/// captured variables into the captured struct, and call the outlined function.
llvm::Function *
CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K) {
LValue CapStruct = InitCapturedStruct(S);
// Emit the CapturedDecl
CodeGenFunction CGF(CGM, true);
CGCapturedStmtRAII CapInfoRAII(CGF, new CGCapturedStmtInfo(S, K));
llvm::Function *F = CGF.GenerateCapturedStmtFunction(S);
delete CGF.CapturedStmtInfo;
// Emit call to the helper function.
EmitCallOrInvoke(F, CapStruct.getPointer(*this));
return F;
}
Address CodeGenFunction::GenerateCapturedStmtArgument(const CapturedStmt &S) {
LValue CapStruct = InitCapturedStruct(S);
return CapStruct.getAddress(*this);
}
/// Creates the outlined function for a CapturedStmt.
llvm::Function *
CodeGenFunction::GenerateCapturedStmtFunction(const CapturedStmt &S) {
assert(CapturedStmtInfo &&
"CapturedStmtInfo should be set when generating the captured function");
const CapturedDecl *CD = S.getCapturedDecl();
const RecordDecl *RD = S.getCapturedRecordDecl();
SourceLocation Loc = S.getBeginLoc();
assert(CD->hasBody() && "missing CapturedDecl body");
// Build the argument list.
ASTContext &Ctx = CGM.getContext();
FunctionArgList Args;
Args.append(CD->param_begin(), CD->param_end());
// Create the function declaration.
const CGFunctionInfo &FuncInfo =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args);
llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo);
llvm::Function *F =
llvm::Function::Create(FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
CapturedStmtInfo->getHelperName(), &CGM.getModule());
CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
if (CD->isNothrow())
F->addFnAttr(llvm::Attribute::NoUnwind);
// Generate the function.
StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getLocation(),
CD->getBody()->getBeginLoc());
// Set the context parameter in CapturedStmtInfo.
Address DeclPtr = GetAddrOfLocalVar(CD->getContextParam());
CapturedStmtInfo->setContextValue(Builder.CreateLoad(DeclPtr));
// Initialize variable-length arrays.
LValue Base = MakeNaturalAlignAddrLValue(CapturedStmtInfo->getContextValue(),
Ctx.getTagDeclType(RD));
for (auto *FD : RD->fields()) {
if (FD->hasCapturedVLAType()) {
auto *ExprArg =
EmitLoadOfLValue(EmitLValueForField(Base, FD), S.getBeginLoc())
.getScalarVal();
auto VAT = FD->getCapturedVLAType();
VLASizeMap[VAT->getSizeExpr()] = ExprArg;
}
}
// If 'this' is captured, load it into CXXThisValue.
if (CapturedStmtInfo->isCXXThisExprCaptured()) {
FieldDecl *FD = CapturedStmtInfo->getThisFieldDecl();
LValue ThisLValue = EmitLValueForField(Base, FD);
CXXThisValue = EmitLoadOfLValue(ThisLValue, Loc).getScalarVal();
}
PGO.assignRegionCounters(GlobalDecl(CD), F);
CapturedStmtInfo->EmitBody(*this, CD->getBody());
FinishFunction(CD->getBodyRBrace());
return F;
}
diff --git a/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp b/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp
index 0fe084b628da..836aabf80179 100644
--- a/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -1,1783 +1,1789 @@
//===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Instrumentation-based code coverage mapping generator
//
//===----------------------------------------------------------------------===//
#include "CoverageMappingGen.h"
#include "CodeGenFunction.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
#include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
// This selects the coverage mapping format defined when `InstrProfData.inc`
// is textually included.
#define COVMAP_V3
static llvm::cl::opt<bool> EmptyLineCommentCoverage(
"emptyline-comment-coverage",
llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only "
"disable it on test)"),
llvm::cl::init(true), llvm::cl::Hidden);
using namespace clang;
using namespace CodeGen;
using namespace llvm::coverage;
CoverageSourceInfo *
CoverageMappingModuleGen::setUpCoverageCallbacks(Preprocessor &PP) {
CoverageSourceInfo *CoverageInfo =
new CoverageSourceInfo(PP.getSourceManager());
PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(CoverageInfo));
if (EmptyLineCommentCoverage) {
PP.addCommentHandler(CoverageInfo);
PP.setEmptylineHandler(CoverageInfo);
PP.setPreprocessToken(true);
PP.setTokenWatcher([CoverageInfo](clang::Token Tok) {
// Update previous token location.
CoverageInfo->PrevTokLoc = Tok.getLocation();
if (Tok.getKind() != clang::tok::eod)
CoverageInfo->updateNextTokLoc(Tok.getLocation());
});
}
return CoverageInfo;
}
void CoverageSourceInfo::AddSkippedRange(SourceRange Range,
SkippedRange::Kind RangeKind) {
if (EmptyLineCommentCoverage && !SkippedRanges.empty() &&
PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
Range.getBegin()))
SkippedRanges.back().Range.setEnd(Range.getEnd());
else
SkippedRanges.push_back({Range, RangeKind, PrevTokLoc});
}
void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) {
AddSkippedRange(Range, SkippedRange::PPIfElse);
}
void CoverageSourceInfo::HandleEmptyline(SourceRange Range) {
AddSkippedRange(Range, SkippedRange::EmptyLine);
}
bool CoverageSourceInfo::HandleComment(Preprocessor &PP, SourceRange Range) {
AddSkippedRange(Range, SkippedRange::Comment);
return false;
}
void CoverageSourceInfo::updateNextTokLoc(SourceLocation Loc) {
if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
SkippedRanges.back().NextTokLoc = Loc;
}
namespace {
/// A region of source code that can be mapped to a counter.
class SourceMappingRegion {
/// Primary Counter that is also used for Branch Regions for "True" branches.
Counter Count;
/// Secondary Counter used for Branch Regions for "False" branches.
Optional<Counter> FalseCount;
/// The region's starting location.
Optional<SourceLocation> LocStart;
/// The region's ending location.
Optional<SourceLocation> LocEnd;
/// Whether this region is a gap region. The count from a gap region is set
/// as the line execution count if there are no other regions on the line.
bool GapRegion;
public:
SourceMappingRegion(Counter Count, Optional<SourceLocation> LocStart,
Optional<SourceLocation> LocEnd, bool GapRegion = false)
: Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion) {
}
SourceMappingRegion(Counter Count, Optional<Counter> FalseCount,
Optional<SourceLocation> LocStart,
Optional<SourceLocation> LocEnd, bool GapRegion = false)
: Count(Count), FalseCount(FalseCount), LocStart(LocStart),
LocEnd(LocEnd), GapRegion(GapRegion) {}
const Counter &getCounter() const { return Count; }
const Counter &getFalseCounter() const {
assert(FalseCount && "Region has no alternate counter");
return *FalseCount;
}
void setCounter(Counter C) { Count = C; }
bool hasStartLoc() const { return LocStart.has_value(); }
void setStartLoc(SourceLocation Loc) { LocStart = Loc; }
SourceLocation getBeginLoc() const {
assert(LocStart && "Region has no start location");
return *LocStart;
}
bool hasEndLoc() const { return LocEnd.has_value(); }
void setEndLoc(SourceLocation Loc) {
assert(Loc.isValid() && "Setting an invalid end location");
LocEnd = Loc;
}
SourceLocation getEndLoc() const {
assert(LocEnd && "Region has no end location");
return *LocEnd;
}
bool isGap() const { return GapRegion; }
void setGap(bool Gap) { GapRegion = Gap; }
bool isBranch() const { return FalseCount.has_value(); }
};
/// Spelling locations for the start and end of a source region.
struct SpellingRegion {
/// The line where the region starts.
unsigned LineStart;
/// The column where the region starts.
unsigned ColumnStart;
/// The line where the region ends.
unsigned LineEnd;
/// The column where the region ends.
unsigned ColumnEnd;
SpellingRegion(SourceManager &SM, SourceLocation LocStart,
SourceLocation LocEnd) {
LineStart = SM.getSpellingLineNumber(LocStart);
ColumnStart = SM.getSpellingColumnNumber(LocStart);
LineEnd = SM.getSpellingLineNumber(LocEnd);
ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
}
SpellingRegion(SourceManager &SM, SourceMappingRegion &R)
: SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {}
/// Check if the start and end locations appear in source order, i.e
/// top->bottom, left->right.
bool isInSourceOrder() const {
return (LineStart < LineEnd) ||
(LineStart == LineEnd && ColumnStart <= ColumnEnd);
}
};
/// Provides the common functionality for the different
/// coverage mapping region builders.
class CoverageMappingBuilder {
public:
CoverageMappingModuleGen &CVM;
SourceManager &SM;
const LangOptions &LangOpts;
private:
/// Map of clang's FileIDs to IDs used for coverage mapping.
llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
FileIDMapping;
public:
/// The coverage mapping regions for this function
llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
/// The source mapping regions for this function.
std::vector<SourceMappingRegion> SourceRegions;
/// A set of regions which can be used as a filter.
///
/// It is produced by emitExpansionRegions() and is used in
/// emitSourceRegions() to suppress producing code regions if
/// the same area is covered by expansion regions.
typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
SourceRegionFilter;
CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
const LangOptions &LangOpts)
: CVM(CVM), SM(SM), LangOpts(LangOpts) {}
/// Return the precise end location for the given token.
SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
// We avoid getLocForEndOfToken here, because it doesn't do what we want for
// macro locations, which we just treat as expanded files.
unsigned TokLen =
Lexer::MeasureTokenLength(SM.getSpellingLoc(Loc), SM, LangOpts);
return Loc.getLocWithOffset(TokLen);
}
/// Return the start location of an included file or expanded macro.
SourceLocation getStartOfFileOrMacro(SourceLocation Loc) {
if (Loc.isMacroID())
return Loc.getLocWithOffset(-SM.getFileOffset(Loc));
return SM.getLocForStartOfFile(SM.getFileID(Loc));
}
/// Return the end location of an included file or expanded macro.
SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
if (Loc.isMacroID())
return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) -
SM.getFileOffset(Loc));
return SM.getLocForEndOfFile(SM.getFileID(Loc));
}
/// Find out where the current file is included or macro is expanded.
SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) {
return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).getBegin()
: SM.getIncludeLoc(SM.getFileID(Loc));
}
/// Return true if \c Loc is a location in a built-in macro.
bool isInBuiltin(SourceLocation Loc) {
return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>";
}
/// Check whether \c Loc is included or expanded from \c Parent.
bool isNestedIn(SourceLocation Loc, FileID Parent) {
do {
Loc = getIncludeOrExpansionLoc(Loc);
if (Loc.isInvalid())
return false;
} while (!SM.isInFileID(Loc, Parent));
return true;
}
/// Get the start of \c S ignoring macro arguments and builtin macros.
SourceLocation getStart(const Stmt *S) {
SourceLocation Loc = S->getBeginLoc();
while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
Loc = SM.getImmediateExpansionRange(Loc).getBegin();
return Loc;
}
/// Get the end of \c S ignoring macro arguments and builtin macros.
SourceLocation getEnd(const Stmt *S) {
SourceLocation Loc = S->getEndLoc();
while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
Loc = SM.getImmediateExpansionRange(Loc).getBegin();
return getPreciseTokenLocEnd(Loc);
}
/// Find the set of files we have regions for and assign IDs
///
/// Fills \c Mapping with the virtual file mapping needed to write out
/// coverage and collects the necessary file information to emit source and
/// expansion regions.
void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) {
FileIDMapping.clear();
llvm::SmallSet<FileID, 8> Visited;
SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs;
for (const auto &Region : SourceRegions) {
SourceLocation Loc = Region.getBeginLoc();
FileID File = SM.getFileID(Loc);
if (!Visited.insert(File).second)
continue;
// Do not map FileID's associated with system headers.
if (SM.isInSystemHeader(SM.getSpellingLoc(Loc)))
continue;
unsigned Depth = 0;
for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
Parent.isValid(); Parent = getIncludeOrExpansionLoc(Parent))
++Depth;
FileLocs.push_back(std::make_pair(Loc, Depth));
}
llvm::stable_sort(FileLocs, llvm::less_second());
for (const auto &FL : FileLocs) {
SourceLocation Loc = FL.first;
FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first;
auto Entry = SM.getFileEntryForID(SpellingFile);
if (!Entry)
continue;
FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
Mapping.push_back(CVM.getFileID(Entry));
}
}
/// Get the coverage mapping file ID for \c Loc.
///
/// If such file id doesn't exist, return None.
Optional<unsigned> getCoverageFileID(SourceLocation Loc) {
auto Mapping = FileIDMapping.find(SM.getFileID(Loc));
if (Mapping != FileIDMapping.end())
return Mapping->second.first;
return None;
}
/// This shrinks the skipped range if it spans a line that contains a
/// non-comment token. If shrinking the skipped range would make it empty,
/// this returns None.
/// Note this function can potentially be expensive because
/// getSpellingLineNumber uses getLineNumber, which is expensive.
Optional<SpellingRegion> adjustSkippedRange(SourceManager &SM,
SourceLocation LocStart,
SourceLocation LocEnd,
SourceLocation PrevTokLoc,
SourceLocation NextTokLoc) {
SpellingRegion SR{SM, LocStart, LocEnd};
SR.ColumnStart = 1;
if (PrevTokLoc.isValid() && SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
SR.LineStart == SM.getSpellingLineNumber(PrevTokLoc))
SR.LineStart++;
if (NextTokLoc.isValid() && SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
SR.LineEnd == SM.getSpellingLineNumber(NextTokLoc)) {
SR.LineEnd--;
SR.ColumnEnd++;
}
if (SR.isInSourceOrder())
return SR;
return None;
}
/// Gather all the regions that were skipped by the preprocessor
/// using the constructs like #if or comments.
void gatherSkippedRegions() {
/// An array of the minimum lineStarts and the maximum lineEnds
/// for mapping regions from the appropriate source files.
llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
FileLineRanges.resize(
FileIDMapping.size(),
std::make_pair(std::numeric_limits<unsigned>::max(), 0));
for (const auto &R : MappingRegions) {
FileLineRanges[R.FileID].first =
std::min(FileLineRanges[R.FileID].first, R.LineStart);
FileLineRanges[R.FileID].second =
std::max(FileLineRanges[R.FileID].second, R.LineEnd);
}
auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges();
for (auto &I : SkippedRanges) {
SourceRange Range = I.Range;
auto LocStart = Range.getBegin();
auto LocEnd = Range.getEnd();
assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
"region spans multiple files");
auto CovFileID = getCoverageFileID(LocStart);
if (!CovFileID)
continue;
Optional<SpellingRegion> SR;
if (I.isComment())
SR = adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc,
I.NextTokLoc);
else if (I.isPPIfElse() || I.isEmptyLine())
SR = {SM, LocStart, LocEnd};
if (!SR)
continue;
auto Region = CounterMappingRegion::makeSkipped(
*CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
SR->ColumnEnd);
// Make sure that we only collect the regions that are inside
// the source code of this function.
if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
Region.LineEnd <= FileLineRanges[*CovFileID].second)
MappingRegions.push_back(Region);
}
}
/// Generate the coverage counter mapping regions from collected
/// source regions.
void emitSourceRegions(const SourceRegionFilter &Filter) {
for (const auto &Region : SourceRegions) {
assert(Region.hasEndLoc() && "incomplete region");
SourceLocation LocStart = Region.getBeginLoc();
assert(SM.getFileID(LocStart).isValid() && "region in invalid file");
// Ignore regions from system headers.
if (SM.isInSystemHeader(SM.getSpellingLoc(LocStart)))
continue;
auto CovFileID = getCoverageFileID(LocStart);
// Ignore regions that don't have a file, such as builtin macros.
if (!CovFileID)
continue;
SourceLocation LocEnd = Region.getEndLoc();
assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
"region spans multiple files");
// Don't add code regions for the area covered by expansion regions.
// This not only suppresses redundant regions, but sometimes prevents
// creating regions with wrong counters if, for example, a statement's
// body ends at the end of a nested macro.
if (Filter.count(std::make_pair(LocStart, LocEnd)))
continue;
// Find the spelling locations for the mapping region.
SpellingRegion SR{SM, LocStart, LocEnd};
assert(SR.isInSourceOrder() && "region start and end out of order");
if (Region.isGap()) {
MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
SR.LineEnd, SR.ColumnEnd));
} else if (Region.isBranch()) {
MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
Region.getCounter(), Region.getFalseCounter(), *CovFileID,
SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
} else {
MappingRegions.push_back(CounterMappingRegion::makeRegion(
Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
SR.LineEnd, SR.ColumnEnd));
}
}
}
/// Generate expansion regions for each virtual file we've seen.
SourceRegionFilter emitExpansionRegions() {
SourceRegionFilter Filter;
for (const auto &FM : FileIDMapping) {
SourceLocation ExpandedLoc = FM.second.second;
SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc);
if (ParentLoc.isInvalid())
continue;
auto ParentFileID = getCoverageFileID(ParentLoc);
if (!ParentFileID)
continue;
auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
assert(ExpandedFileID && "expansion in uncovered file");
SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
"region spans multiple files");
Filter.insert(std::make_pair(ParentLoc, LocEnd));
SpellingRegion SR{SM, ParentLoc, LocEnd};
assert(SR.isInSourceOrder() && "region start and end out of order");
MappingRegions.push_back(CounterMappingRegion::makeExpansion(
*ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
SR.LineEnd, SR.ColumnEnd));
}
return Filter;
}
};
/// Creates unreachable coverage regions for the functions that
/// are not emitted.
struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
const LangOptions &LangOpts)
: CoverageMappingBuilder(CVM, SM, LangOpts) {}
void VisitDecl(const Decl *D) {
if (!D->hasBody())
return;
auto Body = D->getBody();
SourceLocation Start = getStart(Body);
SourceLocation End = getEnd(Body);
if (!SM.isWrittenInSameFile(Start, End)) {
// Walk up to find the common ancestor.
// Correct the locations accordingly.
FileID StartFileID = SM.getFileID(Start);
FileID EndFileID = SM.getFileID(End);
while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
Start = getIncludeOrExpansionLoc(Start);
assert(Start.isValid() &&
"Declaration start location not nested within a known region");
StartFileID = SM.getFileID(Start);
}
while (StartFileID != EndFileID) {
End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
assert(End.isValid() &&
"Declaration end location not nested within a known region");
EndFileID = SM.getFileID(End);
}
}
SourceRegions.emplace_back(Counter(), Start, End);
}
/// Write the mapping data to the output stream
void write(llvm::raw_ostream &OS) {
SmallVector<unsigned, 16> FileIDMapping;
gatherFileIDs(FileIDMapping);
emitSourceRegions(SourceRegionFilter());
if (MappingRegions.empty())
return;
CoverageMappingWriter Writer(FileIDMapping, None, MappingRegions);
Writer.write(OS);
}
};
/// A StmtVisitor that creates coverage mapping regions which map
/// from the source code locations to the PGO counters.
struct CounterCoverageMappingBuilder
: public CoverageMappingBuilder,
public ConstStmtVisitor<CounterCoverageMappingBuilder> {
/// The map of statements to count values.
llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
/// A stack of currently live regions.
std::vector<SourceMappingRegion> RegionStack;
CounterExpressionBuilder Builder;
/// A location in the most recently visited file or macro.
///
/// This is used to adjust the active source regions appropriately when
/// expressions cross file or macro boundaries.
SourceLocation MostRecentLocation;
/// Whether the visitor at a terminate statement.
bool HasTerminateStmt = false;
/// Gap region counter after terminate statement.
Counter GapRegionCounter;
/// Return a counter for the subtraction of \c RHS from \c LHS
Counter subtractCounters(Counter LHS, Counter RHS, bool Simplify = true) {
return Builder.subtract(LHS, RHS, Simplify);
}
/// Return a counter for the sum of \c LHS and \c RHS.
Counter addCounters(Counter LHS, Counter RHS, bool Simplify = true) {
return Builder.add(LHS, RHS, Simplify);
}
Counter addCounters(Counter C1, Counter C2, Counter C3,
bool Simplify = true) {
return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
}
/// Return the region counter for the given statement.
///
/// This should only be called on statements that have a dedicated counter.
Counter getRegionCounter(const Stmt *S) {
return Counter::getCounter(CounterMap[S]);
}
/// Push a region onto the stack.
///
/// Returns the index on the stack where the region was pushed. This can be
/// used with popRegions to exit a "scope", ending the region that was pushed.
size_t pushRegion(Counter Count, Optional<SourceLocation> StartLoc = None,
Optional<SourceLocation> EndLoc = None,
Optional<Counter> FalseCount = None) {
if (StartLoc && !FalseCount) {
MostRecentLocation = *StartLoc;
}
RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc);
return RegionStack.size() - 1;
}
size_t locationDepth(SourceLocation Loc) {
size_t Depth = 0;
while (Loc.isValid()) {
Loc = getIncludeOrExpansionLoc(Loc);
Depth++;
}
return Depth;
}
/// Pop regions from the stack into the function's list of regions.
///
/// Adds all regions from \c ParentIndex to the top of the stack to the
/// function's \c SourceRegions.
void popRegions(size_t ParentIndex) {
assert(RegionStack.size() >= ParentIndex && "parent not in stack");
while (RegionStack.size() > ParentIndex) {
SourceMappingRegion &Region = RegionStack.back();
if (Region.hasStartLoc()) {
SourceLocation StartLoc = Region.getBeginLoc();
SourceLocation EndLoc = Region.hasEndLoc()
? Region.getEndLoc()
: RegionStack[ParentIndex].getEndLoc();
bool isBranch = Region.isBranch();
size_t StartDepth = locationDepth(StartLoc);
size_t EndDepth = locationDepth(EndLoc);
while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) {
bool UnnestStart = StartDepth >= EndDepth;
bool UnnestEnd = EndDepth >= StartDepth;
if (UnnestEnd) {
// The region ends in a nested file or macro expansion. If the
// region is not a branch region, create a separate region for each
// expansion, and for all regions, update the EndLoc. Branch
// regions should not be split in order to keep a straightforward
// correspondance between the region and its associated branch
// condition, even if the condition spans multiple depths.
SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
assert(SM.isWrittenInSameFile(NestedLoc, EndLoc));
if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
EndLoc);
EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
if (EndLoc.isInvalid())
llvm::report_fatal_error(
"File exit not handled before popRegions");
EndDepth--;
}
if (UnnestStart) {
// The region ends in a nested file or macro expansion. If the
// region is not a branch region, create a separate region for each
// expansion, and for all regions, update the StartLoc. Branch
// regions should not be split in order to keep a straightforward
// correspondance between the region and its associated branch
// condition, even if the condition spans multiple depths.
SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
assert(SM.isWrittenInSameFile(StartLoc, NestedLoc));
if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
SourceRegions.emplace_back(Region.getCounter(), StartLoc,
NestedLoc);
StartLoc = getIncludeOrExpansionLoc(StartLoc);
if (StartLoc.isInvalid())
llvm::report_fatal_error(
"File exit not handled before popRegions");
StartDepth--;
}
}
Region.setStartLoc(StartLoc);
Region.setEndLoc(EndLoc);
if (!isBranch) {
MostRecentLocation = EndLoc;
// If this region happens to span an entire expansion, we need to
// make sure we don't overlap the parent region with it.
if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
EndLoc == getEndOfFileOrMacro(EndLoc))
MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
}
assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
assert(SpellingRegion(SM, Region).isInSourceOrder());
SourceRegions.push_back(Region);
}
RegionStack.pop_back();
}
}
/// Return the currently active region.
SourceMappingRegion &getRegion() {
assert(!RegionStack.empty() && "statement has no region");
return RegionStack.back();
}
/// Propagate counts through the children of \p S if \p VisitChildren is true.
/// Otherwise, only emit a count for \p S itself.
Counter propagateCounts(Counter TopCount, const Stmt *S,
bool VisitChildren = true) {
SourceLocation StartLoc = getStart(S);
SourceLocation EndLoc = getEnd(S);
size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
if (VisitChildren)
Visit(S);
Counter ExitCount = getRegion().getCounter();
popRegions(Index);
// The statement may be spanned by an expansion. Make sure we handle a file
// exit out of this expansion before moving to the next statement.
if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc()))
MostRecentLocation = EndLoc;
return ExitCount;
}
/// Determine whether the given condition can be constant folded.
bool ConditionFoldsToBool(const Expr *Cond) {
Expr::EvalResult Result;
return (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext()));
}
/// Create a Branch Region around an instrumentable condition for coverage
/// and add it to the function's SourceRegions. A branch region tracks a
/// "True" counter and a "False" counter for boolean expressions that
/// result in the generation of a branch.
void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt) {
// Check for NULL conditions.
if (!C)
return;
// Ensure we are an instrumentable condition (i.e. no "&&" or "||"). Push
// region onto RegionStack but immediately pop it (which adds it to the
// function's SourceRegions) because it doesn't apply to any other source
// code other than the Condition.
if (CodeGenFunction::isInstrumentedCondition(C)) {
// If a condition can fold to true or false, the corresponding branch
// will be removed. Create a region with both counters hard-coded to
// zero. This allows us to visualize them in a special way.
// Alternatively, we can prevent any optimization done via
// constant-folding by ensuring that ConstantFoldsToSimpleInteger() in
// CodeGenFunction.c always returns false, but that is very heavy-handed.
if (ConditionFoldsToBool(C))
popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C),
Counter::getZero()));
else
// Otherwise, create a region with the True counter and False counter.
popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt));
}
}
/// Create a Branch Region around a SwitchCase for code coverage
/// and add it to the function's SourceRegions.
void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt,
Counter FalseCnt) {
// Push region onto RegionStack but immediately pop it (which adds it to
// the function's SourceRegions) because it doesn't apply to any other
// source other than the SwitchCase.
popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), FalseCnt));
}
/// Check whether a region with bounds \c StartLoc and \c EndLoc
/// is already added to \c SourceRegions.
bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
bool isBranch = false) {
return llvm::any_of(
llvm::reverse(SourceRegions), [&](const SourceMappingRegion &Region) {
return Region.getBeginLoc() == StartLoc &&
Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
});
}
/// Adjust the most recently visited location to \c EndLoc.
///
/// This should be used after visiting any statements in non-source order.
void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
MostRecentLocation = EndLoc;
// The code region for a whole macro is created in handleFileExit() when
// it detects exiting of the virtual file of that macro. If we visited
// statements in non-source order, we might already have such a region
// added, for example, if a body of a loop is divided among multiple
// macros. Avoid adding duplicate regions in such case.
if (getRegion().hasEndLoc() &&
MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
MostRecentLocation, getRegion().isBranch()))
MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
}
/// Adjust regions and state when \c NewLoc exits a file.
///
/// If moving from our most recently tracked location to \c NewLoc exits any
/// files, this adjusts our current region stack and creates the file regions
/// for the exited file.
void handleFileExit(SourceLocation NewLoc) {
if (NewLoc.isInvalid() ||
SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
return;
// If NewLoc is not in a file that contains MostRecentLocation, walk up to
// find the common ancestor.
SourceLocation LCA = NewLoc;
FileID ParentFile = SM.getFileID(LCA);
while (!isNestedIn(MostRecentLocation, ParentFile)) {
LCA = getIncludeOrExpansionLoc(LCA);
if (LCA.isInvalid() || SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
// Since there isn't a common ancestor, no file was exited. We just need
// to adjust our location to the new file.
MostRecentLocation = NewLoc;
return;
}
ParentFile = SM.getFileID(LCA);
}
llvm::SmallSet<SourceLocation, 8> StartLocs;
Optional<Counter> ParentCounter;
for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
if (!I.hasStartLoc())
continue;
SourceLocation Loc = I.getBeginLoc();
if (!isNestedIn(Loc, ParentFile)) {
ParentCounter = I.getCounter();
break;
}
while (!SM.isInFileID(Loc, ParentFile)) {
// The most nested region for each start location is the one with the
// correct count. We avoid creating redundant regions by stopping once
// we've seen this region.
if (StartLocs.insert(Loc).second) {
if (I.isBranch())
SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(), Loc,
getEndOfFileOrMacro(Loc), I.isBranch());
else
SourceRegions.emplace_back(I.getCounter(), Loc,
getEndOfFileOrMacro(Loc));
}
Loc = getIncludeOrExpansionLoc(Loc);
}
I.setStartLoc(getPreciseTokenLocEnd(Loc));
}
if (ParentCounter) {
// If the file is contained completely by another region and doesn't
// immediately start its own region, the whole file gets a region
// corresponding to the parent.
SourceLocation Loc = MostRecentLocation;
while (isNestedIn(Loc, ParentFile)) {
SourceLocation FileStart = getStartOfFileOrMacro(Loc);
if (StartLocs.insert(FileStart).second) {
SourceRegions.emplace_back(*ParentCounter, FileStart,
getEndOfFileOrMacro(Loc));
assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder());
}
Loc = getIncludeOrExpansionLoc(Loc);
}
}
MostRecentLocation = NewLoc;
}
/// Ensure that \c S is included in the current region.
void extendRegion(const Stmt *S) {
SourceMappingRegion &Region = getRegion();
SourceLocation StartLoc = getStart(S);
handleFileExit(StartLoc);
if (!Region.hasStartLoc())
Region.setStartLoc(StartLoc);
}
/// Mark \c S as a terminator, starting a zero region.
void terminateRegion(const Stmt *S) {
extendRegion(S);
SourceMappingRegion &Region = getRegion();
SourceLocation EndLoc = getEnd(S);
if (!Region.hasEndLoc())
Region.setEndLoc(EndLoc);
pushRegion(Counter::getZero());
HasTerminateStmt = true;
}
/// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
Optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
SourceLocation BeforeLoc) {
// If AfterLoc is in function-like macro, use the right parenthesis
// location.
if (AfterLoc.isMacroID()) {
FileID FID = SM.getFileID(AfterLoc);
const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion();
if (EI->isFunctionMacroExpansion())
AfterLoc = EI->getExpansionLocEnd();
}
size_t StartDepth = locationDepth(AfterLoc);
size_t EndDepth = locationDepth(BeforeLoc);
while (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
bool UnnestStart = StartDepth >= EndDepth;
bool UnnestEnd = EndDepth >= StartDepth;
if (UnnestEnd) {
assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
BeforeLoc));
BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
assert(BeforeLoc.isValid());
EndDepth--;
}
if (UnnestStart) {
assert(SM.isWrittenInSameFile(AfterLoc,
getEndOfFileOrMacro(AfterLoc)));
AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
assert(AfterLoc.isValid());
AfterLoc = getPreciseTokenLocEnd(AfterLoc);
assert(AfterLoc.isValid());
StartDepth--;
}
}
AfterLoc = getPreciseTokenLocEnd(AfterLoc);
// If the start and end locations of the gap are both within the same macro
// file, the range may not be in source order.
if (AfterLoc.isMacroID() || BeforeLoc.isMacroID())
return None;
if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
!SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder())
return None;
return {{AfterLoc, BeforeLoc}};
}
/// Emit a gap region between \p StartLoc and \p EndLoc with the given count.
void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
Counter Count) {
if (StartLoc == EndLoc)
return;
assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder());
handleFileExit(StartLoc);
size_t Index = pushRegion(Count, StartLoc, EndLoc);
getRegion().setGap(true);
handleFileExit(EndLoc);
popRegions(Index);
}
/// Keep counts of breaks and continues inside loops.
struct BreakContinue {
Counter BreakCount;
Counter ContinueCount;
};
SmallVector<BreakContinue, 8> BreakContinueStack;
CounterCoverageMappingBuilder(
CoverageMappingModuleGen &CVM,
llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM,
const LangOptions &LangOpts)
: CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap) {}
/// Write the mapping data to the output stream
void write(llvm::raw_ostream &OS) {
llvm::SmallVector<unsigned, 8> VirtualFileMapping;
gatherFileIDs(VirtualFileMapping);
SourceRegionFilter Filter = emitExpansionRegions();
emitSourceRegions(Filter);
gatherSkippedRegions();
if (MappingRegions.empty())
return;
CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
MappingRegions);
Writer.write(OS);
}
void VisitStmt(const Stmt *S) {
if (S->getBeginLoc().isValid())
extendRegion(S);
const Stmt *LastStmt = nullptr;
bool SaveTerminateStmt = HasTerminateStmt;
HasTerminateStmt = false;
GapRegionCounter = Counter::getZero();
for (const Stmt *Child : S->children())
if (Child) {
// If last statement contains terminate statements, add a gap area
// between the two statements. Skipping attributed statements, because
// they don't have valid start location.
if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child)) {
auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
if (Gap)
fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
GapRegionCounter);
SaveTerminateStmt = true;
HasTerminateStmt = false;
}
this->Visit(Child);
LastStmt = Child;
}
if (SaveTerminateStmt)
HasTerminateStmt = true;
handleFileExit(getEnd(S));
}
void VisitDecl(const Decl *D) {
Stmt *Body = D->getBody();
// Do not propagate region counts into system headers.
if (Body && SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body))))
return;
// Do not visit the artificial children nodes of defaulted methods. The
// lexer may not be able to report back precise token end locations for
// these children nodes (llvm.org/PR39822), and moreover users will not be
// able to see coverage for them.
bool Defaulted = false;
if (auto *Method = dyn_cast<CXXMethodDecl>(D))
Defaulted = Method->isDefaulted();
propagateCounts(getRegionCounter(Body), Body,
/*VisitChildren=*/!Defaulted);
assert(RegionStack.empty() && "Regions entered but never exited");
}
void VisitReturnStmt(const ReturnStmt *S) {
extendRegion(S);
if (S->getRetValue())
Visit(S->getRetValue());
terminateRegion(S);
}
void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
extendRegion(S);
Visit(S->getBody());
}
void VisitCoreturnStmt(const CoreturnStmt *S) {
extendRegion(S);
if (S->getOperand())
Visit(S->getOperand());
terminateRegion(S);
}
void VisitCXXThrowExpr(const CXXThrowExpr *E) {
extendRegion(E);
if (E->getSubExpr())
Visit(E->getSubExpr());
terminateRegion(E);
}
void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); }
void VisitLabelStmt(const LabelStmt *S) {
Counter LabelCount = getRegionCounter(S);
SourceLocation Start = getStart(S);
// We can't extendRegion here or we risk overlapping with our new region.
handleFileExit(Start);
pushRegion(LabelCount, Start);
Visit(S->getSubStmt());
}
void VisitBreakStmt(const BreakStmt *S) {
assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
BreakContinueStack.back().BreakCount = addCounters(
BreakContinueStack.back().BreakCount, getRegion().getCounter());
// FIXME: a break in a switch should terminate regions for all preceding
// case statements, not just the most recent one.
terminateRegion(S);
}
void VisitContinueStmt(const ContinueStmt *S) {
assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
BreakContinueStack.back().ContinueCount = addCounters(
BreakContinueStack.back().ContinueCount, getRegion().getCounter());
terminateRegion(S);
}
void VisitCallExpr(const CallExpr *E) {
VisitStmt(E);
// Terminate the region when we hit a noreturn function.
// (This is helpful dealing with switch statements.)
QualType CalleeType = E->getCallee()->getType();
if (getFunctionExtInfo(*CalleeType).getNoReturn())
terminateRegion(E);
}
void VisitWhileStmt(const WhileStmt *S) {
extendRegion(S);
Counter ParentCount = getRegion().getCounter();
Counter BodyCount = getRegionCounter(S);
// Handle the body first so that we can get the backedge count.
BreakContinueStack.push_back(BreakContinue());
extendRegion(S->getBody());
Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
BreakContinue BC = BreakContinueStack.pop_back_val();
bool BodyHasTerminateStmt = HasTerminateStmt;
HasTerminateStmt = false;
// Go back to handle the condition.
Counter CondCount =
addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
propagateCounts(CondCount, S->getCond());
adjustForOutOfOrderTraversal(getEnd(S));
// The body count applies to the area immediately after the increment.
auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
if (Gap)
fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
Counter OutCount =
addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
if (OutCount != ParentCount) {
pushRegion(OutCount);
GapRegionCounter = OutCount;
if (BodyHasTerminateStmt)
HasTerminateStmt = true;
}
// Create Branch Region around condition.
createBranchRegion(S->getCond(), BodyCount,
subtractCounters(CondCount, BodyCount));
}
void VisitDoStmt(const DoStmt *S) {
extendRegion(S);
Counter ParentCount = getRegion().getCounter();
Counter BodyCount = getRegionCounter(S);
BreakContinueStack.push_back(BreakContinue());
extendRegion(S->getBody());
Counter BackedgeCount =
propagateCounts(addCounters(ParentCount, BodyCount), S->getBody());
BreakContinue BC = BreakContinueStack.pop_back_val();
bool BodyHasTerminateStmt = HasTerminateStmt;
HasTerminateStmt = false;
Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
propagateCounts(CondCount, S->getCond());
Counter OutCount =
addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
if (OutCount != ParentCount) {
pushRegion(OutCount);
GapRegionCounter = OutCount;
}
// Create Branch Region around condition.
createBranchRegion(S->getCond(), BodyCount,
subtractCounters(CondCount, BodyCount));
if (BodyHasTerminateStmt)
HasTerminateStmt = true;
}
void VisitForStmt(const ForStmt *S) {
extendRegion(S);
if (S->getInit())
Visit(S->getInit());
Counter ParentCount = getRegion().getCounter();
Counter BodyCount = getRegionCounter(S);
// The loop increment may contain a break or continue.
if (S->getInc())
BreakContinueStack.emplace_back();
// Handle the body first so that we can get the backedge count.
BreakContinueStack.emplace_back();
extendRegion(S->getBody());
Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
BreakContinue BodyBC = BreakContinueStack.pop_back_val();
bool BodyHasTerminateStmt = HasTerminateStmt;
HasTerminateStmt = false;
// The increment is essentially part of the body but it needs to include
// the count for all the continue statements.
BreakContinue IncrementBC;
if (const Stmt *Inc = S->getInc()) {
propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
IncrementBC = BreakContinueStack.pop_back_val();
}
// Go back to handle the condition.
Counter CondCount = addCounters(
addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
IncrementBC.ContinueCount);
if (const Expr *Cond = S->getCond()) {
propagateCounts(CondCount, Cond);
adjustForOutOfOrderTraversal(getEnd(S));
}
// The body count applies to the area immediately after the increment.
auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
if (Gap)
fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
subtractCounters(CondCount, BodyCount));
if (OutCount != ParentCount) {
pushRegion(OutCount);
GapRegionCounter = OutCount;
if (BodyHasTerminateStmt)
HasTerminateStmt = true;
}
// Create Branch Region around condition.
createBranchRegion(S->getCond(), BodyCount,
subtractCounters(CondCount, BodyCount));
}
void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
extendRegion(S);
if (S->getInit())
Visit(S->getInit());
Visit(S->getLoopVarStmt());
Visit(S->getRangeStmt());
Counter ParentCount = getRegion().getCounter();
Counter BodyCount = getRegionCounter(S);
BreakContinueStack.push_back(BreakContinue());
extendRegion(S->getBody());
Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
BreakContinue BC = BreakContinueStack.pop_back_val();
bool BodyHasTerminateStmt = HasTerminateStmt;
HasTerminateStmt = false;
// The body count applies to the area immediately after the range.
auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
if (Gap)
fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
Counter LoopCount =
addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
Counter OutCount =
addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
if (OutCount != ParentCount) {
pushRegion(OutCount);
GapRegionCounter = OutCount;
if (BodyHasTerminateStmt)
HasTerminateStmt = true;
}
// Create Branch Region around condition.
createBranchRegion(S->getCond(), BodyCount,
subtractCounters(LoopCount, BodyCount));
}
void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
extendRegion(S);
Visit(S->getElement());
Counter ParentCount = getRegion().getCounter();
Counter BodyCount = getRegionCounter(S);
BreakContinueStack.push_back(BreakContinue());
extendRegion(S->getBody());
Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
BreakContinue BC = BreakContinueStack.pop_back_val();
// The body count applies to the area immediately after the collection.
auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
if (Gap)
fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
Counter LoopCount =
addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
Counter OutCount =
addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
if (OutCount != ParentCount) {
pushRegion(OutCount);
GapRegionCounter = OutCount;
}
}
void VisitSwitchStmt(const SwitchStmt *S) {
extendRegion(S);
if (S->getInit())
Visit(S->getInit());
Visit(S->getCond());
BreakContinueStack.push_back(BreakContinue());
const Stmt *Body = S->getBody();
extendRegion(Body);
if (const auto *CS = dyn_cast<CompoundStmt>(Body)) {
if (!CS->body_empty()) {
// Make a region for the body of the switch. If the body starts with
// a case, that case will reuse this region; otherwise, this covers
// the unreachable code at the beginning of the switch body.
size_t Index = pushRegion(Counter::getZero(), getStart(CS));
getRegion().setGap(true);
Visit(Body);
// Set the end for the body of the switch, if it isn't already set.
for (size_t i = RegionStack.size(); i != Index; --i) {
if (!RegionStack[i - 1].hasEndLoc())
RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
}
popRegions(Index);
}
} else
propagateCounts(Counter::getZero(), Body);
BreakContinue BC = BreakContinueStack.pop_back_val();
if (!BreakContinueStack.empty())
BreakContinueStack.back().ContinueCount = addCounters(
BreakContinueStack.back().ContinueCount, BC.ContinueCount);
Counter ParentCount = getRegion().getCounter();
Counter ExitCount = getRegionCounter(S);
SourceLocation ExitLoc = getEnd(S);
pushRegion(ExitCount);
GapRegionCounter = ExitCount;
// Ensure that handleFileExit recognizes when the end location is located
// in a different file.
MostRecentLocation = getStart(S);
handleFileExit(ExitLoc);
// Create a Branch Region around each Case. Subtract the case's
// counter from the Parent counter to track the "False" branch count.
Counter CaseCountSum;
bool HasDefaultCase = false;
const SwitchCase *Case = S->getSwitchCaseList();
for (; Case; Case = Case->getNextSwitchCase()) {
HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case);
CaseCountSum =
addCounters(CaseCountSum, getRegionCounter(Case), /*Simplify=*/false);
createSwitchCaseRegion(
Case, getRegionCounter(Case),
subtractCounters(ParentCount, getRegionCounter(Case)));
}
// Simplify is skipped while building the counters above: it can get really
// slow on top of switches with thousands of cases. Instead, trigger
// simplification by adding zero to the last counter.
CaseCountSum = addCounters(CaseCountSum, Counter::getZero());
// If no explicit default case exists, create a branch region to represent
// the hidden branch, which will be added later by the CodeGen. This region
// will be associated with the switch statement's condition.
if (!HasDefaultCase) {
Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum);
Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue);
createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse);
}
}
void VisitSwitchCase(const SwitchCase *S) {
extendRegion(S);
SourceMappingRegion &Parent = getRegion();
Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S));
// Reuse the existing region if it starts at our label. This is typical of
// the first case in a switch.
if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
Parent.setCounter(Count);
else
pushRegion(Count, getStart(S));
GapRegionCounter = Count;
if (const auto *CS = dyn_cast<CaseStmt>(S)) {
Visit(CS->getLHS());
if (const Expr *RHS = CS->getRHS())
Visit(RHS);
}
Visit(S->getSubStmt());
}
void VisitIfStmt(const IfStmt *S) {
extendRegion(S);
if (S->getInit())
Visit(S->getInit());
// Extend into the condition before we propagate through it below - this is
// needed to handle macros that generate the "if" but not the condition.
- extendRegion(S->getCond());
+ if (!S->isConsteval())
+ extendRegion(S->getCond());
Counter ParentCount = getRegion().getCounter();
Counter ThenCount = getRegionCounter(S);
- // Emitting a counter for the condition makes it easier to interpret the
- // counter for the body when looking at the coverage.
- propagateCounts(ParentCount, S->getCond());
+ if (!S->isConsteval()) {
+ // Emitting a counter for the condition makes it easier to interpret the
+ // counter for the body when looking at the coverage.
+ propagateCounts(ParentCount, S->getCond());
- // The 'then' count applies to the area immediately after the condition.
- auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
- if (Gap)
- fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
+ // The 'then' count applies to the area immediately after the condition.
+ Optional<SourceRange> Gap =
+ findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
+ if (Gap)
+ fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
+ }
extendRegion(S->getThen());
Counter OutCount = propagateCounts(ThenCount, S->getThen());
Counter ElseCount = subtractCounters(ParentCount, ThenCount);
if (const Stmt *Else = S->getElse()) {
bool ThenHasTerminateStmt = HasTerminateStmt;
HasTerminateStmt = false;
-
// The 'else' count applies to the area immediately after the 'then'.
- Gap = findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
+ Optional<SourceRange> Gap =
+ findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
if (Gap)
fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
extendRegion(Else);
OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
if (ThenHasTerminateStmt)
HasTerminateStmt = true;
} else
OutCount = addCounters(OutCount, ElseCount);
if (OutCount != ParentCount) {
pushRegion(OutCount);
GapRegionCounter = OutCount;
}
- // Create Branch Region around condition.
- createBranchRegion(S->getCond(), ThenCount,
- subtractCounters(ParentCount, ThenCount));
+ if (!S->isConsteval()) {
+ // Create Branch Region around condition.
+ createBranchRegion(S->getCond(), ThenCount,
+ subtractCounters(ParentCount, ThenCount));
+ }
}
void VisitCXXTryStmt(const CXXTryStmt *S) {
extendRegion(S);
// Handle macros that generate the "try" but not the rest.
extendRegion(S->getTryBlock());
Counter ParentCount = getRegion().getCounter();
propagateCounts(ParentCount, S->getTryBlock());
for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
Visit(S->getHandler(I));
Counter ExitCount = getRegionCounter(S);
pushRegion(ExitCount);
}
void VisitCXXCatchStmt(const CXXCatchStmt *S) {
propagateCounts(getRegionCounter(S), S->getHandlerBlock());
}
void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
extendRegion(E);
Counter ParentCount = getRegion().getCounter();
Counter TrueCount = getRegionCounter(E);
propagateCounts(ParentCount, E->getCond());
if (!isa<BinaryConditionalOperator>(E)) {
// The 'then' count applies to the area immediately after the condition.
auto Gap =
findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr()));
if (Gap)
fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
extendRegion(E->getTrueExpr());
propagateCounts(TrueCount, E->getTrueExpr());
}
extendRegion(E->getFalseExpr());
propagateCounts(subtractCounters(ParentCount, TrueCount),
E->getFalseExpr());
// Create Branch Region around condition.
createBranchRegion(E->getCond(), TrueCount,
subtractCounters(ParentCount, TrueCount));
}
void VisitBinLAnd(const BinaryOperator *E) {
extendRegion(E->getLHS());
propagateCounts(getRegion().getCounter(), E->getLHS());
handleFileExit(getEnd(E->getLHS()));
// Counter tracks the right hand side of a logical and operator.
extendRegion(E->getRHS());
propagateCounts(getRegionCounter(E), E->getRHS());
// Extract the RHS's Execution Counter.
Counter RHSExecCnt = getRegionCounter(E);
// Extract the RHS's "True" Instance Counter.
Counter RHSTrueCnt = getRegionCounter(E->getRHS());
// Extract the Parent Region Counter.
Counter ParentCnt = getRegion().getCounter();
// Create Branch Region around LHS condition.
createBranchRegion(E->getLHS(), RHSExecCnt,
subtractCounters(ParentCnt, RHSExecCnt));
// Create Branch Region around RHS condition.
createBranchRegion(E->getRHS(), RHSTrueCnt,
subtractCounters(RHSExecCnt, RHSTrueCnt));
}
void VisitBinLOr(const BinaryOperator *E) {
extendRegion(E->getLHS());
propagateCounts(getRegion().getCounter(), E->getLHS());
handleFileExit(getEnd(E->getLHS()));
// Counter tracks the right hand side of a logical or operator.
extendRegion(E->getRHS());
propagateCounts(getRegionCounter(E), E->getRHS());
// Extract the RHS's Execution Counter.
Counter RHSExecCnt = getRegionCounter(E);
// Extract the RHS's "False" Instance Counter.
Counter RHSFalseCnt = getRegionCounter(E->getRHS());
// Extract the Parent Region Counter.
Counter ParentCnt = getRegion().getCounter();
// Create Branch Region around LHS condition.
createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt),
RHSExecCnt);
// Create Branch Region around RHS condition.
createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
RHSFalseCnt);
}
void VisitLambdaExpr(const LambdaExpr *LE) {
// Lambdas are treated as their own functions for now, so we shouldn't
// propagate counts into them.
}
};
} // end anonymous namespace
static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
ArrayRef<CounterExpression> Expressions,
ArrayRef<CounterMappingRegion> Regions) {
OS << FunctionName << ":\n";
CounterMappingContext Ctx(Expressions);
for (const auto &R : Regions) {
OS.indent(2);
switch (R.Kind) {
case CounterMappingRegion::CodeRegion:
break;
case CounterMappingRegion::ExpansionRegion:
OS << "Expansion,";
break;
case CounterMappingRegion::SkippedRegion:
OS << "Skipped,";
break;
case CounterMappingRegion::GapRegion:
OS << "Gap,";
break;
case CounterMappingRegion::BranchRegion:
OS << "Branch,";
break;
}
OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
<< " -> " << R.LineEnd << ":" << R.ColumnEnd << " = ";
Ctx.dump(R.Count, OS);
if (R.Kind == CounterMappingRegion::BranchRegion) {
OS << ", ";
Ctx.dump(R.FalseCount, OS);
}
if (R.Kind == CounterMappingRegion::ExpansionRegion)
OS << " (Expanded file = " << R.ExpandedFileID << ")";
OS << "\n";
}
}
CoverageMappingModuleGen::CoverageMappingModuleGen(
CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
: CGM(CGM), SourceInfo(SourceInfo) {
CoveragePrefixMap = CGM.getCodeGenOpts().CoveragePrefixMap;
}
std::string CoverageMappingModuleGen::getCurrentDirname() {
if (!CGM.getCodeGenOpts().CoverageCompilationDir.empty())
return CGM.getCodeGenOpts().CoverageCompilationDir;
SmallString<256> CWD;
llvm::sys::fs::current_path(CWD);
return CWD.str().str();
}
std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
llvm::SmallString<256> Path(Filename);
llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
for (const auto &Entry : CoveragePrefixMap) {
if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
break;
}
return Path.str().str();
}
static std::string getInstrProfSection(const CodeGenModule &CGM,
llvm::InstrProfSectKind SK) {
return llvm::getInstrProfSectionName(
SK, CGM.getContext().getTargetInfo().getTriple().getObjectFormat());
}
void CoverageMappingModuleGen::emitFunctionMappingRecord(
const FunctionInfo &Info, uint64_t FilenamesRef) {
llvm::LLVMContext &Ctx = CGM.getLLVMContext();
// Assign a name to the function record. This is used to merge duplicates.
std::string FuncRecordName = "__covrec_" + llvm::utohexstr(Info.NameHash);
// A dummy description for a function included-but-not-used in a TU can be
// replaced by full description provided by a different TU. The two kinds of
// descriptions play distinct roles: therefore, assign them different names
// to prevent `linkonce_odr` merging.
if (Info.IsUsed)
FuncRecordName += "u";
// Create the function record type.
const uint64_t NameHash = Info.NameHash;
const uint64_t FuncHash = Info.FuncHash;
const std::string &CoverageMapping = Info.CoverageMapping;
#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
llvm::Type *FunctionRecordTypes[] = {
#include "llvm/ProfileData/InstrProfData.inc"
};
auto *FunctionRecordTy =
llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes),
/*isPacked=*/true);
// Create the function record constant.
#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
llvm::Constant *FunctionRecordVals[] = {
#include "llvm/ProfileData/InstrProfData.inc"
};
auto *FuncRecordConstant = llvm::ConstantStruct::get(
FunctionRecordTy, makeArrayRef(FunctionRecordVals));
// Create the function record global.
auto *FuncRecord = new llvm::GlobalVariable(
CGM.getModule(), FunctionRecordTy, /*isConstant=*/true,
llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
FuncRecordName);
FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
FuncRecord->setSection(getInstrProfSection(CGM, llvm::IPSK_covfun));
FuncRecord->setAlignment(llvm::Align(8));
if (CGM.supportsCOMDAT())
FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName));
// Make sure the data doesn't get deleted.
CGM.addUsedGlobal(FuncRecord);
}
void CoverageMappingModuleGen::addFunctionMappingRecord(
llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
const std::string &CoverageMapping, bool IsUsed) {
llvm::LLVMContext &Ctx = CGM.getLLVMContext();
const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
if (!IsUsed)
FunctionNames.push_back(
llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)));
if (CGM.getCodeGenOpts().DumpCoverageMapping) {
// Dump the coverage mapping data for this function by decoding the
// encoded data. This allows us to dump the mapping regions which were
// also processed by the CoverageMappingWriter which performs
// additional minimization operations such as reducing the number of
// expressions.
llvm::SmallVector<std::string, 16> FilenameStrs;
std::vector<StringRef> Filenames;
std::vector<CounterExpression> Expressions;
std::vector<CounterMappingRegion> Regions;
FilenameStrs.resize(FileEntries.size() + 1);
FilenameStrs[0] = normalizeFilename(getCurrentDirname());
for (const auto &Entry : FileEntries) {
auto I = Entry.second;
FilenameStrs[I] = normalizeFilename(Entry.first->getName());
}
ArrayRef<std::string> FilenameRefs = llvm::makeArrayRef(FilenameStrs);
RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
Expressions, Regions);
if (Reader.read())
return;
dump(llvm::outs(), NameValue, Expressions, Regions);
}
}
void CoverageMappingModuleGen::emit() {
if (FunctionRecords.empty())
return;
llvm::LLVMContext &Ctx = CGM.getLLVMContext();
auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
// Create the filenames and merge them with coverage mappings
llvm::SmallVector<std::string, 16> FilenameStrs;
FilenameStrs.resize(FileEntries.size() + 1);
// The first filename is the current working directory.
FilenameStrs[0] = normalizeFilename(getCurrentDirname());
for (const auto &Entry : FileEntries) {
auto I = Entry.second;
FilenameStrs[I] = normalizeFilename(Entry.first->getName());
}
std::string Filenames;
{
llvm::raw_string_ostream OS(Filenames);
CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
}
auto *FilenamesVal =
llvm::ConstantDataArray::getString(Ctx, Filenames, false);
const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
// Emit the function records.
for (const FunctionInfo &Info : FunctionRecords)
emitFunctionMappingRecord(Info, FilenamesRef);
const unsigned NRecords = 0;
const size_t FilenamesSize = Filenames.size();
const unsigned CoverageMappingSize = 0;
llvm::Type *CovDataHeaderTypes[] = {
#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
#include "llvm/ProfileData/InstrProfData.inc"
};
auto CovDataHeaderTy =
llvm::StructType::get(Ctx, makeArrayRef(CovDataHeaderTypes));
llvm::Constant *CovDataHeaderVals[] = {
#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
#include "llvm/ProfileData/InstrProfData.inc"
};
auto CovDataHeaderVal = llvm::ConstantStruct::get(
CovDataHeaderTy, makeArrayRef(CovDataHeaderVals));
// Create the coverage data record
llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes));
llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
auto CovDataVal =
llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals));
auto CovData = new llvm::GlobalVariable(
CGM.getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage,
CovDataVal, llvm::getCoverageMappingVarName());
CovData->setSection(getInstrProfSection(CGM, llvm::IPSK_covmap));
CovData->setAlignment(llvm::Align(8));
// Make sure the data doesn't get deleted.
CGM.addUsedGlobal(CovData);
// Create the deferred function records array
if (!FunctionNames.empty()) {
auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx),
FunctionNames.size());
auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
// This variable will *NOT* be emitted to the object file. It is used
// to pass the list of names referenced to codegen.
new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true,
llvm::GlobalValue::InternalLinkage, NamesArrVal,
llvm::getCoverageUnusedNamesVarName());
}
}
unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
auto It = FileEntries.find(File);
if (It != FileEntries.end())
return It->second;
unsigned FileID = FileEntries.size() + 1;
FileEntries.insert(std::make_pair(File, FileID));
return FileID;
}
void CoverageMappingGen::emitCounterMapping(const Decl *D,
llvm::raw_ostream &OS) {
assert(CounterMap);
CounterCoverageMappingBuilder Walker(CVM, *CounterMap, SM, LangOpts);
Walker.VisitDecl(D);
Walker.write(OS);
}
void CoverageMappingGen::emitEmptyMapping(const Decl *D,
llvm::raw_ostream &OS) {
EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
Walker.VisitDecl(D);
Walker.write(OS);
}
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaInit.cpp b/contrib/llvm-project/clang/lib/Sema/SemaInit.cpp
index d3b454843234..bf7ca718a36b 100644
--- a/contrib/llvm-project/clang/lib/Sema/SemaInit.cpp
+++ b/contrib/llvm-project/clang/lib/Sema/SemaInit.cpp
@@ -1,10298 +1,10298 @@
//===--- SemaInit.cpp - Semantic Analysis for Initializers ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis for initializers.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// Sema Initialization Checking
//===----------------------------------------------------------------------===//
/// Check whether T is compatible with a wide character type (wchar_t,
/// char16_t or char32_t).
static bool IsWideCharCompatible(QualType T, ASTContext &Context) {
if (Context.typesAreCompatible(Context.getWideCharType(), T))
return true;
if (Context.getLangOpts().CPlusPlus || Context.getLangOpts().C11) {
return Context.typesAreCompatible(Context.Char16Ty, T) ||
Context.typesAreCompatible(Context.Char32Ty, T);
}
return false;
}
enum StringInitFailureKind {
SIF_None,
SIF_NarrowStringIntoWideChar,
SIF_WideStringIntoChar,
SIF_IncompatWideStringIntoWideChar,
SIF_UTF8StringIntoPlainChar,
SIF_PlainStringIntoUTF8Char,
SIF_Other
};
/// Check whether the array of type AT can be initialized by the Init
/// expression by means of string initialization. Returns SIF_None if so,
/// otherwise returns a StringInitFailureKind that describes why the
/// initialization would not work.
static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT,
ASTContext &Context) {
if (!isa<ConstantArrayType>(AT) && !isa<IncompleteArrayType>(AT))
return SIF_Other;
// See if this is a string literal or @encode.
Init = Init->IgnoreParens();
// Handle @encode, which is a narrow string.
if (isa<ObjCEncodeExpr>(Init) && AT->getElementType()->isCharType())
return SIF_None;
// Otherwise we can only handle string literals.
StringLiteral *SL = dyn_cast<StringLiteral>(Init);
if (!SL)
return SIF_Other;
const QualType ElemTy =
Context.getCanonicalType(AT->getElementType()).getUnqualifiedType();
switch (SL->getKind()) {
case StringLiteral::UTF8:
// char8_t array can be initialized with a UTF-8 string.
if (ElemTy->isChar8Type())
return SIF_None;
LLVM_FALLTHROUGH;
case StringLiteral::Ordinary:
// char array can be initialized with a narrow string.
// Only allow char x[] = "foo"; not char x[] = L"foo";
if (ElemTy->isCharType())
return (SL->getKind() == StringLiteral::UTF8 &&
Context.getLangOpts().Char8)
? SIF_UTF8StringIntoPlainChar
: SIF_None;
if (ElemTy->isChar8Type())
return SIF_PlainStringIntoUTF8Char;
if (IsWideCharCompatible(ElemTy, Context))
return SIF_NarrowStringIntoWideChar;
return SIF_Other;
// C99 6.7.8p15 (with correction from DR343), or C11 6.7.9p15:
// "An array with element type compatible with a qualified or unqualified
// version of wchar_t, char16_t, or char32_t may be initialized by a wide
// string literal with the corresponding encoding prefix (L, u, or U,
// respectively), optionally enclosed in braces.
case StringLiteral::UTF16:
if (Context.typesAreCompatible(Context.Char16Ty, ElemTy))
return SIF_None;
if (ElemTy->isCharType() || ElemTy->isChar8Type())
return SIF_WideStringIntoChar;
if (IsWideCharCompatible(ElemTy, Context))
return SIF_IncompatWideStringIntoWideChar;
return SIF_Other;
case StringLiteral::UTF32:
if (Context.typesAreCompatible(Context.Char32Ty, ElemTy))
return SIF_None;
if (ElemTy->isCharType() || ElemTy->isChar8Type())
return SIF_WideStringIntoChar;
if (IsWideCharCompatible(ElemTy, Context))
return SIF_IncompatWideStringIntoWideChar;
return SIF_Other;
case StringLiteral::Wide:
if (Context.typesAreCompatible(Context.getWideCharType(), ElemTy))
return SIF_None;
if (ElemTy->isCharType() || ElemTy->isChar8Type())
return SIF_WideStringIntoChar;
if (IsWideCharCompatible(ElemTy, Context))
return SIF_IncompatWideStringIntoWideChar;
return SIF_Other;
}
llvm_unreachable("missed a StringLiteral kind?");
}
static StringInitFailureKind IsStringInit(Expr *init, QualType declType,
ASTContext &Context) {
const ArrayType *arrayType = Context.getAsArrayType(declType);
if (!arrayType)
return SIF_Other;
return IsStringInit(init, arrayType, Context);
}
bool Sema::IsStringInit(Expr *Init, const ArrayType *AT) {
return ::IsStringInit(Init, AT, Context) == SIF_None;
}
/// Update the type of a string literal, including any surrounding parentheses,
/// to match the type of the object which it is initializing.
static void updateStringLiteralType(Expr *E, QualType Ty) {
while (true) {
E->setType(Ty);
E->setValueKind(VK_PRValue);
if (isa<StringLiteral>(E) || isa<ObjCEncodeExpr>(E)) {
break;
} else if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
E = PE->getSubExpr();
} else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
assert(UO->getOpcode() == UO_Extension);
E = UO->getSubExpr();
} else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E)) {
E = GSE->getResultExpr();
} else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(E)) {
E = CE->getChosenSubExpr();
} else {
llvm_unreachable("unexpected expr in string literal init");
}
}
}
/// Fix a compound literal initializing an array so it's correctly marked
/// as an rvalue.
static void updateGNUCompoundLiteralRValue(Expr *E) {
while (true) {
E->setValueKind(VK_PRValue);
if (isa<CompoundLiteralExpr>(E)) {
break;
} else if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
E = PE->getSubExpr();
} else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
assert(UO->getOpcode() == UO_Extension);
E = UO->getSubExpr();
} else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E)) {
E = GSE->getResultExpr();
} else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(E)) {
E = CE->getChosenSubExpr();
} else {
llvm_unreachable("unexpected expr in array compound literal init");
}
}
}
static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
Sema &S) {
// Get the length of the string as parsed.
auto *ConstantArrayTy =
cast<ConstantArrayType>(Str->getType()->getAsArrayTypeUnsafe());
uint64_t StrLength = ConstantArrayTy->getSize().getZExtValue();
if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) {
// C99 6.7.8p14. We have an array of character type with unknown size
// being initialized to a string literal.
llvm::APInt ConstVal(32, StrLength);
// Return a new array type (C99 6.7.8p22).
DeclT = S.Context.getConstantArrayType(IAT->getElementType(),
ConstVal, nullptr,
ArrayType::Normal, 0);
updateStringLiteralType(Str, DeclT);
return;
}
const ConstantArrayType *CAT = cast<ConstantArrayType>(AT);
// We have an array of character type with known size. However,
// the size may be smaller or larger than the string we are initializing.
// FIXME: Avoid truncation for 64-bit length strings.
if (S.getLangOpts().CPlusPlus) {
if (StringLiteral *SL = dyn_cast<StringLiteral>(Str->IgnoreParens())) {
// For Pascal strings it's OK to strip off the terminating null character,
// so the example below is valid:
//
// unsigned char a[2] = "\pa";
if (SL->isPascal())
StrLength--;
}
// [dcl.init.string]p2
if (StrLength > CAT->getSize().getZExtValue())
S.Diag(Str->getBeginLoc(),
diag::err_initializer_string_for_char_array_too_long)
<< Str->getSourceRange();
} else {
// C99 6.7.8p14.
if (StrLength-1 > CAT->getSize().getZExtValue())
S.Diag(Str->getBeginLoc(),
diag::ext_initializer_string_for_char_array_too_long)
<< Str->getSourceRange();
}
// Set the type to the actual size that we are initializing. If we have
// something like:
// char x[1] = "foo";
// then this will set the string literal's type to char[1].
updateStringLiteralType(Str, DeclT);
}
//===----------------------------------------------------------------------===//
// Semantic checking for initializer lists.
//===----------------------------------------------------------------------===//
namespace {
/// Semantic checking for initializer lists.
///
/// The InitListChecker class contains a set of routines that each
/// handle the initialization of a certain kind of entity, e.g.,
/// arrays, vectors, struct/union types, scalars, etc. The
/// InitListChecker itself performs a recursive walk of the subobject
/// structure of the type to be initialized, while stepping through
/// the initializer list one element at a time. The IList and Index
/// parameters to each of the Check* routines contain the active
/// (syntactic) initializer list and the index into that initializer
/// list that represents the current initializer. Each routine is
/// responsible for moving that Index forward as it consumes elements.
///
/// Each Check* routine also has a StructuredList/StructuredIndex
/// arguments, which contains the current "structured" (semantic)
/// initializer list and the index into that initializer list where we
/// are copying initializers as we map them over to the semantic
/// list. Once we have completed our recursive walk of the subobject
/// structure, we will have constructed a full semantic initializer
/// list.
///
/// C99 designators cause changes in the initializer list traversal,
/// because they make the initialization "jump" into a specific
/// subobject and then continue the initialization from that
/// point. CheckDesignatedInitializer() recursively steps into the
/// designated subobject and manages backing out the recursion to
/// initialize the subobjects after the one designated.
///
/// If an initializer list contains any designators, we build a placeholder
/// structured list even in 'verify only' mode, so that we can track which
/// elements need 'empty' initializtion.
class InitListChecker {
Sema &SemaRef;
bool hadError = false;
bool VerifyOnly; // No diagnostics.
bool TreatUnavailableAsInvalid; // Used only in VerifyOnly mode.
bool InOverloadResolution;
InitListExpr *FullyStructuredList = nullptr;
NoInitExpr *DummyExpr = nullptr;
NoInitExpr *getDummyInit() {
if (!DummyExpr)
DummyExpr = new (SemaRef.Context) NoInitExpr(SemaRef.Context.VoidTy);
return DummyExpr;
}
void CheckImplicitInitList(const InitializedEntity &Entity,
InitListExpr *ParentIList, QualType T,
unsigned &Index, InitListExpr *StructuredList,
unsigned &StructuredIndex);
void CheckExplicitInitList(const InitializedEntity &Entity,
InitListExpr *IList, QualType &T,
InitListExpr *StructuredList,
bool TopLevelObject = false);
void CheckListElementTypes(const InitializedEntity &Entity,
InitListExpr *IList, QualType &DeclType,
bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
void CheckSubElementType(const InitializedEntity &Entity,
InitListExpr *IList, QualType ElemType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool DirectlyDesignated = false);
void CheckComplexType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
void CheckScalarType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
void CheckReferenceType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
void CheckVectorType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
void CheckStructUnionTypes(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
CXXRecordDecl::base_class_range Bases,
RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
void CheckArrayType(const InitializedEntity &Entity,
InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
bool CheckDesignatedInitializer(const InitializedEntity &Entity,
InitListExpr *IList, DesignatedInitExpr *DIE,
unsigned DesigIdx,
QualType &CurrentObjectType,
RecordDecl::field_iterator *NextField,
llvm::APSInt *NextElementIndex,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool FinishSubobjectInit,
bool TopLevelObject);
InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
QualType CurrentObjectType,
InitListExpr *StructuredList,
unsigned StructuredIndex,
SourceRange InitRange,
bool IsFullyOverwritten = false);
void UpdateStructuredListElement(InitListExpr *StructuredList,
unsigned &StructuredIndex,
Expr *expr);
InitListExpr *createInitListExpr(QualType CurrentObjectType,
SourceRange InitRange,
unsigned ExpectedNumInits);
int numArrayElements(QualType DeclType);
int numStructUnionElements(QualType DeclType);
ExprResult PerformEmptyInit(SourceLocation Loc,
const InitializedEntity &Entity);
/// Diagnose that OldInit (or part thereof) has been overridden by NewInit.
void diagnoseInitOverride(Expr *OldInit, SourceRange NewInitRange,
bool FullyOverwritten = true) {
// Overriding an initializer via a designator is valid with C99 designated
// initializers, but ill-formed with C++20 designated initializers.
unsigned DiagID = SemaRef.getLangOpts().CPlusPlus
? diag::ext_initializer_overrides
: diag::warn_initializer_overrides;
if (InOverloadResolution && SemaRef.getLangOpts().CPlusPlus) {
// In overload resolution, we have to strictly enforce the rules, and so
// don't allow any overriding of prior initializers. This matters for a
// case such as:
//
// union U { int a, b; };
// struct S { int a, b; };
// void f(U), f(S);
//
// Here, f({.a = 1, .b = 2}) is required to call the struct overload. For
// consistency, we disallow all overriding of prior initializers in
// overload resolution, not only overriding of union members.
hadError = true;
} else if (OldInit->getType().isDestructedType() && !FullyOverwritten) {
// If we'll be keeping around the old initializer but overwriting part of
// the object it initialized, and that object is not trivially
// destructible, this can leak. Don't allow that, not even as an
// extension.
//
// FIXME: It might be reasonable to allow this in cases where the part of
// the initializer that we're overriding has trivial destruction.
DiagID = diag::err_initializer_overrides_destructed;
} else if (!OldInit->getSourceRange().isValid()) {
// We need to check on source range validity because the previous
// initializer does not have to be an explicit initializer. e.g.,
//
// struct P { int a, b; };
// struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
//
// There is an overwrite taking place because the first braced initializer
// list "{ .a = 2 }" already provides value for .p.b (which is zero).
//
// Such overwrites are harmless, so we don't diagnose them. (Note that in
// C++, this cannot be reached unless we've already seen and diagnosed a
// different conformance issue, such as a mixture of designated and
// non-designated initializers or a multi-level designator.)
return;
}
if (!VerifyOnly) {
SemaRef.Diag(NewInitRange.getBegin(), DiagID)
<< NewInitRange << FullyOverwritten << OldInit->getType();
SemaRef.Diag(OldInit->getBeginLoc(), diag::note_previous_initializer)
<< (OldInit->HasSideEffects(SemaRef.Context) && FullyOverwritten)
<< OldInit->getSourceRange();
}
}
// Explanation on the "FillWithNoInit" mode:
//
// Assume we have the following definitions (Case#1):
// struct P { char x[6][6]; } xp = { .x[1] = "bar" };
// struct PP { struct P lp; } l = { .lp = xp, .lp.x[1][2] = 'f' };
//
// l.lp.x[1][0..1] should not be filled with implicit initializers because the
// "base" initializer "xp" will provide values for them; l.lp.x[1] will be "baf".
//
// But if we have (Case#2):
// struct PP l = { .lp = xp, .lp.x[1] = { [2] = 'f' } };
//
// l.lp.x[1][0..1] are implicitly initialized and do not use values from the
// "base" initializer; l.lp.x[1] will be "\0\0f\0\0\0".
//
// To distinguish Case#1 from Case#2, and also to avoid leaving many "holes"
// in the InitListExpr, the "holes" in Case#1 are filled not with empty
// initializers but with special "NoInitExpr" place holders, which tells the
// CodeGen not to generate any initializers for these parts.
void FillInEmptyInitForBase(unsigned Init, const CXXBaseSpecifier &Base,
const InitializedEntity &ParentEntity,
InitListExpr *ILE, bool &RequiresSecondPass,
bool FillWithNoInit);
void FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
const InitializedEntity &ParentEntity,
InitListExpr *ILE, bool &RequiresSecondPass,
bool FillWithNoInit = false);
void FillInEmptyInitializations(const InitializedEntity &Entity,
InitListExpr *ILE, bool &RequiresSecondPass,
InitListExpr *OuterILE, unsigned OuterIndex,
bool FillWithNoInit = false);
bool CheckFlexibleArrayInit(const InitializedEntity &Entity,
Expr *InitExpr, FieldDecl *Field,
bool TopLevelObject);
void CheckEmptyInitializable(const InitializedEntity &Entity,
SourceLocation Loc);
public:
InitListChecker(Sema &S, const InitializedEntity &Entity, InitListExpr *IL,
QualType &T, bool VerifyOnly, bool TreatUnavailableAsInvalid,
bool InOverloadResolution = false);
bool HadError() { return hadError; }
// Retrieves the fully-structured initializer list used for
// semantic analysis and code generation.
InitListExpr *getFullyStructuredList() const { return FullyStructuredList; }
};
} // end anonymous namespace
ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc,
const InitializedEntity &Entity) {
InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
true);
MultiExprArg SubInit;
Expr *InitExpr;
InitListExpr DummyInitList(SemaRef.Context, Loc, None, Loc);
// C++ [dcl.init.aggr]p7:
// If there are fewer initializer-clauses in the list than there are
// members in the aggregate, then each member not explicitly initialized
// ...
bool EmptyInitList = SemaRef.getLangOpts().CPlusPlus11 &&
Entity.getType()->getBaseElementTypeUnsafe()->isRecordType();
if (EmptyInitList) {
// C++1y / DR1070:
// shall be initialized [...] from an empty initializer list.
//
// We apply the resolution of this DR to C++11 but not C++98, since C++98
// does not have useful semantics for initialization from an init list.
// We treat this as copy-initialization, because aggregate initialization
// always performs copy-initialization on its elements.
//
// Only do this if we're initializing a class type, to avoid filling in
// the initializer list where possible.
InitExpr = VerifyOnly ? &DummyInitList : new (SemaRef.Context)
InitListExpr(SemaRef.Context, Loc, None, Loc);
InitExpr->setType(SemaRef.Context.VoidTy);
SubInit = InitExpr;
Kind = InitializationKind::CreateCopy(Loc, Loc);
} else {
// C++03:
// shall be value-initialized.
}
InitializationSequence InitSeq(SemaRef, Entity, Kind, SubInit);
// libstdc++4.6 marks the vector default constructor as explicit in
// _GLIBCXX_DEBUG mode, so recover using the C++03 logic in that case.
// stlport does so too. Look for std::__debug for libstdc++, and for
// std:: for stlport. This is effectively a compiler-side implementation of
// LWG2193.
if (!InitSeq && EmptyInitList && InitSeq.getFailureKind() ==
InitializationSequence::FK_ExplicitConstructor) {
OverloadCandidateSet::iterator Best;
OverloadingResult O =
InitSeq.getFailedCandidateSet()
.BestViableFunction(SemaRef, Kind.getLocation(), Best);
(void)O;
assert(O == OR_Success && "Inconsistent overload resolution");
CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
CXXRecordDecl *R = CtorDecl->getParent();
if (CtorDecl->getMinRequiredArguments() == 0 &&
CtorDecl->isExplicit() && R->getDeclName() &&
SemaRef.SourceMgr.isInSystemHeader(CtorDecl->getLocation())) {
bool IsInStd = false;
for (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(R->getDeclContext());
ND && !IsInStd; ND = dyn_cast<NamespaceDecl>(ND->getParent())) {
if (SemaRef.getStdNamespace()->InEnclosingNamespaceSetOf(ND))
IsInStd = true;
}
if (IsInStd && llvm::StringSwitch<bool>(R->getName())
.Cases("basic_string", "deque", "forward_list", true)
.Cases("list", "map", "multimap", "multiset", true)
.Cases("priority_queue", "queue", "set", "stack", true)
.Cases("unordered_map", "unordered_set", "vector", true)
.Default(false)) {
InitSeq.InitializeFrom(
SemaRef, Entity,
InitializationKind::CreateValue(Loc, Loc, Loc, true),
MultiExprArg(), /*TopLevelOfInitList=*/false,
TreatUnavailableAsInvalid);
// Emit a warning for this. System header warnings aren't shown
// by default, but people working on system headers should see it.
if (!VerifyOnly) {
SemaRef.Diag(CtorDecl->getLocation(),
diag::warn_invalid_initializer_from_system_header);
if (Entity.getKind() == InitializedEntity::EK_Member)
SemaRef.Diag(Entity.getDecl()->getLocation(),
diag::note_used_in_initialization_here);
else if (Entity.getKind() == InitializedEntity::EK_ArrayElement)
SemaRef.Diag(Loc, diag::note_used_in_initialization_here);
}
}
}
}
if (!InitSeq) {
if (!VerifyOnly) {
InitSeq.Diagnose(SemaRef, Entity, Kind, SubInit);
if (Entity.getKind() == InitializedEntity::EK_Member)
SemaRef.Diag(Entity.getDecl()->getLocation(),
diag::note_in_omitted_aggregate_initializer)
<< /*field*/1 << Entity.getDecl();
else if (Entity.getKind() == InitializedEntity::EK_ArrayElement) {
bool IsTrailingArrayNewMember =
Entity.getParent() &&
Entity.getParent()->isVariableLengthArrayNew();
SemaRef.Diag(Loc, diag::note_in_omitted_aggregate_initializer)
<< (IsTrailingArrayNewMember ? 2 : /*array element*/0)
<< Entity.getElementIndex();
}
}
hadError = true;
return ExprError();
}
return VerifyOnly ? ExprResult()
: InitSeq.Perform(SemaRef, Entity, Kind, SubInit);
}
void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity,
SourceLocation Loc) {
// If we're building a fully-structured list, we'll check this at the end
// once we know which elements are actually initialized. Otherwise, we know
// that there are no designators so we can just check now.
if (FullyStructuredList)
return;
PerformEmptyInit(Loc, Entity);
}
void InitListChecker::FillInEmptyInitForBase(
unsigned Init, const CXXBaseSpecifier &Base,
const InitializedEntity &ParentEntity, InitListExpr *ILE,
bool &RequiresSecondPass, bool FillWithNoInit) {
InitializedEntity BaseEntity = InitializedEntity::InitializeBase(
SemaRef.Context, &Base, false, &ParentEntity);
if (Init >= ILE->getNumInits() || !ILE->getInit(Init)) {
ExprResult BaseInit = FillWithNoInit
? new (SemaRef.Context) NoInitExpr(Base.getType())
: PerformEmptyInit(ILE->getEndLoc(), BaseEntity);
if (BaseInit.isInvalid()) {
hadError = true;
return;
}
if (!VerifyOnly) {
assert(Init < ILE->getNumInits() && "should have been expanded");
ILE->setInit(Init, BaseInit.getAs<Expr>());
}
} else if (InitListExpr *InnerILE =
dyn_cast<InitListExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(BaseEntity, InnerILE, RequiresSecondPass,
ILE, Init, FillWithNoInit);
} else if (DesignatedInitUpdateExpr *InnerDIUE =
dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(BaseEntity, InnerDIUE->getUpdater(),
RequiresSecondPass, ILE, Init,
/*FillWithNoInit =*/true);
}
}
void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
const InitializedEntity &ParentEntity,
InitListExpr *ILE,
bool &RequiresSecondPass,
bool FillWithNoInit) {
SourceLocation Loc = ILE->getEndLoc();
unsigned NumInits = ILE->getNumInits();
InitializedEntity MemberEntity
= InitializedEntity::InitializeMember(Field, &ParentEntity);
if (Init >= NumInits || !ILE->getInit(Init)) {
if (const RecordType *RType = ILE->getType()->getAs<RecordType>())
if (!RType->getDecl()->isUnion())
assert((Init < NumInits || VerifyOnly) &&
"This ILE should have been expanded");
if (FillWithNoInit) {
assert(!VerifyOnly && "should not fill with no-init in verify-only mode");
Expr *Filler = new (SemaRef.Context) NoInitExpr(Field->getType());
if (Init < NumInits)
ILE->setInit(Init, Filler);
else
ILE->updateInit(SemaRef.Context, Init, Filler);
return;
}
// C++1y [dcl.init.aggr]p7:
// If there are fewer initializer-clauses in the list than there are
// members in the aggregate, then each member not explicitly initialized
// shall be initialized from its brace-or-equal-initializer [...]
if (Field->hasInClassInitializer()) {
if (VerifyOnly)
return;
ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
if (DIE.isInvalid()) {
hadError = true;
return;
}
SemaRef.checkInitializerLifetime(MemberEntity, DIE.get());
if (Init < NumInits)
ILE->setInit(Init, DIE.get());
else {
ILE->updateInit(SemaRef.Context, Init, DIE.get());
RequiresSecondPass = true;
}
return;
}
if (Field->getType()->isReferenceType()) {
if (!VerifyOnly) {
// C++ [dcl.init.aggr]p9:
// If an incomplete or empty initializer-list leaves a
// member of reference type uninitialized, the program is
// ill-formed.
SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
- << Field->getType()
- << ILE->getSyntacticForm()->getSourceRange();
- SemaRef.Diag(Field->getLocation(),
- diag::note_uninit_reference_member);
+ << Field->getType()
+ << (ILE->isSyntacticForm() ? ILE : ILE->getSyntacticForm())
+ ->getSourceRange();
+ SemaRef.Diag(Field->getLocation(), diag::note_uninit_reference_member);
}
hadError = true;
return;
}
ExprResult MemberInit = PerformEmptyInit(Loc, MemberEntity);
if (MemberInit.isInvalid()) {
hadError = true;
return;
}
if (hadError || VerifyOnly) {
// Do nothing
} else if (Init < NumInits) {
ILE->setInit(Init, MemberInit.getAs<Expr>());
} else if (!isa<ImplicitValueInitExpr>(MemberInit.get())) {
// Empty initialization requires a constructor call, so
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
// through the initializer list.
ILE->updateInit(SemaRef.Context, Init, MemberInit.getAs<Expr>());
RequiresSecondPass = true;
}
} else if (InitListExpr *InnerILE
= dyn_cast<InitListExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(MemberEntity, InnerILE,
RequiresSecondPass, ILE, Init, FillWithNoInit);
} else if (DesignatedInitUpdateExpr *InnerDIUE =
dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(MemberEntity, InnerDIUE->getUpdater(),
RequiresSecondPass, ILE, Init,
/*FillWithNoInit =*/true);
}
}
/// Recursively replaces NULL values within the given initializer list
/// with expressions that perform value-initialization of the
/// appropriate type, and finish off the InitListExpr formation.
void
InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
InitListExpr *ILE,
bool &RequiresSecondPass,
InitListExpr *OuterILE,
unsigned OuterIndex,
bool FillWithNoInit) {
assert((ILE->getType() != SemaRef.Context.VoidTy) &&
"Should not have void type");
// We don't need to do any checks when just filling NoInitExprs; that can't
// fail.
if (FillWithNoInit && VerifyOnly)
return;
// If this is a nested initializer list, we might have changed its contents
// (and therefore some of its properties, such as instantiation-dependence)
// while filling it in. Inform the outer initializer list so that its state
// can be updated to match.
// FIXME: We should fully build the inner initializers before constructing
// the outer InitListExpr instead of mutating AST nodes after they have
// been used as subexpressions of other nodes.
struct UpdateOuterILEWithUpdatedInit {
InitListExpr *Outer;
unsigned OuterIndex;
~UpdateOuterILEWithUpdatedInit() {
if (Outer)
Outer->setInit(OuterIndex, Outer->getInit(OuterIndex));
}
} UpdateOuterRAII = {OuterILE, OuterIndex};
// A transparent ILE is not performing aggregate initialization and should
// not be filled in.
if (ILE->isTransparent())
return;
if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
const RecordDecl *RDecl = RType->getDecl();
if (RDecl->isUnion() && ILE->getInitializedFieldInUnion())
FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(),
Entity, ILE, RequiresSecondPass, FillWithNoInit);
else if (RDecl->isUnion() && isa<CXXRecordDecl>(RDecl) &&
cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) {
for (auto *Field : RDecl->fields()) {
if (Field->hasInClassInitializer()) {
FillInEmptyInitForField(0, Field, Entity, ILE, RequiresSecondPass,
FillWithNoInit);
break;
}
}
} else {
// The fields beyond ILE->getNumInits() are default initialized, so in
// order to leave them uninitialized, the ILE is expanded and the extra
// fields are then filled with NoInitExpr.
unsigned NumElems = numStructUnionElements(ILE->getType());
if (RDecl->hasFlexibleArrayMember())
++NumElems;
if (!VerifyOnly && ILE->getNumInits() < NumElems)
ILE->resizeInits(SemaRef.Context, NumElems);
unsigned Init = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RDecl)) {
for (auto &Base : CXXRD->bases()) {
if (hadError)
return;
FillInEmptyInitForBase(Init, Base, Entity, ILE, RequiresSecondPass,
FillWithNoInit);
++Init;
}
}
for (auto *Field : RDecl->fields()) {
if (Field->isUnnamedBitfield())
continue;
if (hadError)
return;
FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass,
FillWithNoInit);
if (hadError)
return;
++Init;
// Only look at the first initialization of a union.
if (RDecl->isUnion())
break;
}
}
return;
}
QualType ElementType;
InitializedEntity ElementEntity = Entity;
unsigned NumInits = ILE->getNumInits();
unsigned NumElements = NumInits;
if (const ArrayType *AType = SemaRef.Context.getAsArrayType(ILE->getType())) {
ElementType = AType->getElementType();
if (const auto *CAType = dyn_cast<ConstantArrayType>(AType))
NumElements = CAType->getSize().getZExtValue();
// For an array new with an unknown bound, ask for one additional element
// in order to populate the array filler.
if (Entity.isVariableLengthArrayNew())
++NumElements;
ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context,
0, Entity);
} else if (const VectorType *VType = ILE->getType()->getAs<VectorType>()) {
ElementType = VType->getElementType();
NumElements = VType->getNumElements();
ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context,
0, Entity);
} else
ElementType = ILE->getType();
bool SkipEmptyInitChecks = false;
for (unsigned Init = 0; Init != NumElements; ++Init) {
if (hadError)
return;
if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement ||
ElementEntity.getKind() == InitializedEntity::EK_VectorElement)
ElementEntity.setElementIndex(Init);
if (Init >= NumInits && (ILE->hasArrayFiller() || SkipEmptyInitChecks))
return;
Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr);
if (!InitExpr && Init < NumInits && ILE->hasArrayFiller())
ILE->setInit(Init, ILE->getArrayFiller());
else if (!InitExpr && !ILE->hasArrayFiller()) {
// In VerifyOnly mode, there's no point performing empty initialization
// more than once.
if (SkipEmptyInitChecks)
continue;
Expr *Filler = nullptr;
if (FillWithNoInit)
Filler = new (SemaRef.Context) NoInitExpr(ElementType);
else {
ExprResult ElementInit =
PerformEmptyInit(ILE->getEndLoc(), ElementEntity);
if (ElementInit.isInvalid()) {
hadError = true;
return;
}
Filler = ElementInit.getAs<Expr>();
}
if (hadError) {
// Do nothing
} else if (VerifyOnly) {
SkipEmptyInitChecks = true;
} else if (Init < NumInits) {
// For arrays, just set the expression used for value-initialization
// of the "holes" in the array.
if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement)
ILE->setArrayFiller(Filler);
else
ILE->setInit(Init, Filler);
} else {
// For arrays, just set the expression used for value-initialization
// of the rest of elements and exit.
if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement) {
ILE->setArrayFiller(Filler);
return;
}
if (!isa<ImplicitValueInitExpr>(Filler) && !isa<NoInitExpr>(Filler)) {
// Empty initialization requires a constructor call, so
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
// through the initializer list.
ILE->updateInit(SemaRef.Context, Init, Filler);
RequiresSecondPass = true;
}
}
} else if (InitListExpr *InnerILE
= dyn_cast_or_null<InitListExpr>(InitExpr)) {
FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass,
ILE, Init, FillWithNoInit);
} else if (DesignatedInitUpdateExpr *InnerDIUE =
dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr)) {
FillInEmptyInitializations(ElementEntity, InnerDIUE->getUpdater(),
RequiresSecondPass, ILE, Init,
/*FillWithNoInit =*/true);
}
}
}
static bool hasAnyDesignatedInits(const InitListExpr *IL) {
for (const Stmt *Init : *IL)
if (Init && isa<DesignatedInitExpr>(Init))
return true;
return false;
}
InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
InitListExpr *IL, QualType &T, bool VerifyOnly,
bool TreatUnavailableAsInvalid,
bool InOverloadResolution)
: SemaRef(S), VerifyOnly(VerifyOnly),
TreatUnavailableAsInvalid(TreatUnavailableAsInvalid),
InOverloadResolution(InOverloadResolution) {
if (!VerifyOnly || hasAnyDesignatedInits(IL)) {
FullyStructuredList =
createInitListExpr(T, IL->getSourceRange(), IL->getNumInits());
// FIXME: Check that IL isn't already the semantic form of some other
// InitListExpr. If it is, we'd create a broken AST.
if (!VerifyOnly)
FullyStructuredList->setSyntacticForm(IL);
}
CheckExplicitInitList(Entity, IL, T, FullyStructuredList,
/*TopLevelObject=*/true);
if (!hadError && FullyStructuredList) {
bool RequiresSecondPass = false;
FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass,
/*OuterILE=*/nullptr, /*OuterIndex=*/0);
if (RequiresSecondPass && !hadError)
FillInEmptyInitializations(Entity, FullyStructuredList,
RequiresSecondPass, nullptr, 0);
}
if (hadError && FullyStructuredList)
FullyStructuredList->markError();
}
int InitListChecker::numArrayElements(QualType DeclType) {
// FIXME: use a proper constant
int maxElements = 0x7FFFFFFF;
if (const ConstantArrayType *CAT =
SemaRef.Context.getAsConstantArrayType(DeclType)) {
maxElements = static_cast<int>(CAT->getSize().getZExtValue());
}
return maxElements;
}
int InitListChecker::numStructUnionElements(QualType DeclType) {
RecordDecl *structDecl = DeclType->castAs<RecordType>()->getDecl();
int InitializableMembers = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(structDecl))
InitializableMembers += CXXRD->getNumBases();
for (const auto *Field : structDecl->fields())
if (!Field->isUnnamedBitfield())
++InitializableMembers;
if (structDecl->isUnion())
return std::min(InitializableMembers, 1);
return InitializableMembers - structDecl->hasFlexibleArrayMember();
}
/// Determine whether Entity is an entity for which it is idiomatic to elide
/// the braces in aggregate initialization.
static bool isIdiomaticBraceElisionEntity(const InitializedEntity &Entity) {
// Recursive initialization of the one and only field within an aggregate
// class is considered idiomatic. This case arises in particular for
// initialization of std::array, where the C++ standard suggests the idiom of
//
// std::array<T, N> arr = {1, 2, 3};
//
// (where std::array is an aggregate struct containing a single array field.
if (!Entity.getParent())
return false;
// Allows elide brace initialization for aggregates with empty base.
if (Entity.getKind() == InitializedEntity::EK_Base) {
auto *ParentRD =
Entity.getParent()->getType()->castAs<RecordType>()->getDecl();
CXXRecordDecl *CXXRD = cast<CXXRecordDecl>(ParentRD);
return CXXRD->getNumBases() == 1 && CXXRD->field_empty();
}
// Allow brace elision if the only subobject is a field.
if (Entity.getKind() == InitializedEntity::EK_Member) {
auto *ParentRD =
Entity.getParent()->getType()->castAs<RecordType>()->getDecl();
if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD)) {
if (CXXRD->getNumBases()) {
return false;
}
}
auto FieldIt = ParentRD->field_begin();
assert(FieldIt != ParentRD->field_end() &&
"no fields but have initializer for member?");
return ++FieldIt == ParentRD->field_end();
}
return false;
}
/// Check whether the range of the initializer \p ParentIList from element
/// \p Index onwards can be used to initialize an object of type \p T. Update
/// \p Index to indicate how many elements of the list were consumed.
///
/// This also fills in \p StructuredList, from element \p StructuredIndex
/// onwards, with the fully-braced, desugared form of the initialization.
void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
InitListExpr *ParentIList,
QualType T, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
int maxElements = 0;
if (T->isArrayType())
maxElements = numArrayElements(T);
else if (T->isRecordType())
maxElements = numStructUnionElements(T);
else if (T->isVectorType())
maxElements = T->castAs<VectorType>()->getNumElements();
else
llvm_unreachable("CheckImplicitInitList(): Illegal type");
if (maxElements == 0) {
if (!VerifyOnly)
SemaRef.Diag(ParentIList->getInit(Index)->getBeginLoc(),
diag::err_implicit_empty_initializer);
++Index;
hadError = true;
return;
}
// Build a structured initializer list corresponding to this subobject.
InitListExpr *StructuredSubobjectInitList = getStructuredSubobjectInit(
ParentIList, Index, T, StructuredList, StructuredIndex,
SourceRange(ParentIList->getInit(Index)->getBeginLoc(),
ParentIList->getSourceRange().getEnd()));
unsigned StructuredSubobjectInitIndex = 0;
// Check the element types and build the structural subobject.
unsigned StartIndex = Index;
CheckListElementTypes(Entity, ParentIList, T,
/*SubobjectIsDesignatorContext=*/false, Index,
StructuredSubobjectInitList,
StructuredSubobjectInitIndex);
if (StructuredSubobjectInitList) {
StructuredSubobjectInitList->setType(T);
unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
// Update the structured sub-object initializer so that it's ending
// range corresponds with the end of the last initializer it used.
if (EndIndex < ParentIList->getNumInits() &&
ParentIList->getInit(EndIndex)) {
SourceLocation EndLoc
= ParentIList->getInit(EndIndex)->getSourceRange().getEnd();
StructuredSubobjectInitList->setRBraceLoc(EndLoc);
}
// Complain about missing braces.
if (!VerifyOnly && (T->isArrayType() || T->isRecordType()) &&
!ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
!isIdiomaticBraceElisionEntity(Entity)) {
SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(),
diag::warn_missing_braces)
<< StructuredSubobjectInitList->getSourceRange()
<< FixItHint::CreateInsertion(
StructuredSubobjectInitList->getBeginLoc(), "{")
<< FixItHint::CreateInsertion(
SemaRef.getLocForEndOfToken(
StructuredSubobjectInitList->getEndLoc()),
"}");
}
// Warn if this type won't be an aggregate in future versions of C++.
auto *CXXRD = T->getAsCXXRecordDecl();
if (!VerifyOnly && CXXRD && CXXRD->hasUserDeclaredConstructor()) {
SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(),
diag::warn_cxx20_compat_aggregate_init_with_ctors)
<< StructuredSubobjectInitList->getSourceRange() << T;
}
}
}
/// Warn that \p Entity was of scalar type and was initialized by a
/// single-element braced initializer list.
static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity,
SourceRange Braces) {
// Don't warn during template instantiation. If the initialization was
// non-dependent, we warned during the initial parse; otherwise, the
// type might not be scalar in some uses of the template.
if (S.inTemplateInstantiation())
return;
unsigned DiagID = 0;
switch (Entity.getKind()) {
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Parameter_CF_Audited:
case InitializedEntity::EK_TemplateParameter:
case InitializedEntity::EK_Result:
// Extra braces here are suspicious.
DiagID = diag::warn_braces_around_init;
break;
case InitializedEntity::EK_Member:
// Warn on aggregate initialization but not on ctor init list or
// default member initializer.
if (Entity.getParent())
DiagID = diag::warn_braces_around_init;
break;
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_LambdaCapture:
// No warning, might be direct-list-initialization.
// FIXME: Should we warn for copy-list-initialization in these cases?
break;
case InitializedEntity::EK_New:
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_CompoundLiteralInit:
// No warning, braces are part of the syntax of the underlying construct.
break;
case InitializedEntity::EK_RelatedResult:
// No warning, we already warned when initializing the result.
break;
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_Binding:
case InitializedEntity::EK_StmtExprResult:
llvm_unreachable("unexpected braced scalar init");
}
if (DiagID) {
S.Diag(Braces.getBegin(), DiagID)
<< Entity.getType()->isSizelessBuiltinType() << Braces
<< FixItHint::CreateRemoval(Braces.getBegin())
<< FixItHint::CreateRemoval(Braces.getEnd());
}
}
/// Check whether the initializer \p IList (that was written with explicit
/// braces) can be used to initialize an object of type \p T.
///
/// This also fills in \p StructuredList with the fully-braced, desugared
/// form of the initialization.
void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
InitListExpr *IList, QualType &T,
InitListExpr *StructuredList,
bool TopLevelObject) {
unsigned Index = 0, StructuredIndex = 0;
CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true,
Index, StructuredList, StructuredIndex, TopLevelObject);
if (StructuredList) {
QualType ExprTy = T;
if (!ExprTy->isArrayType())
ExprTy = ExprTy.getNonLValueExprType(SemaRef.Context);
if (!VerifyOnly)
IList->setType(ExprTy);
StructuredList->setType(ExprTy);
}
if (hadError)
return;
// Don't complain for incomplete types, since we'll get an error elsewhere.
if (Index < IList->getNumInits() && !T->isIncompleteType()) {
// We have leftover initializers
bool ExtraInitsIsError = SemaRef.getLangOpts().CPlusPlus ||
(SemaRef.getLangOpts().OpenCL && T->isVectorType());
hadError = ExtraInitsIsError;
if (VerifyOnly) {
return;
} else if (StructuredIndex == 1 &&
IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) ==
SIF_None) {
unsigned DK =
ExtraInitsIsError
? diag::err_excess_initializers_in_char_array_initializer
: diag::ext_excess_initializers_in_char_array_initializer;
SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
<< IList->getInit(Index)->getSourceRange();
} else if (T->isSizelessBuiltinType()) {
unsigned DK = ExtraInitsIsError
? diag::err_excess_initializers_for_sizeless_type
: diag::ext_excess_initializers_for_sizeless_type;
SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
<< T << IList->getInit(Index)->getSourceRange();
} else {
int initKind = T->isArrayType() ? 0 :
T->isVectorType() ? 1 :
T->isScalarType() ? 2 :
T->isUnionType() ? 3 :
4;
unsigned DK = ExtraInitsIsError ? diag::err_excess_initializers
: diag::ext_excess_initializers;
SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
<< initKind << IList->getInit(Index)->getSourceRange();
}
}
if (!VerifyOnly) {
if (T->isScalarType() && IList->getNumInits() == 1 &&
!isa<InitListExpr>(IList->getInit(0)))
warnBracedScalarInit(SemaRef, Entity, IList->getSourceRange());
// Warn if this is a class type that won't be an aggregate in future
// versions of C++.
auto *CXXRD = T->getAsCXXRecordDecl();
if (CXXRD && CXXRD->hasUserDeclaredConstructor()) {
// Don't warn if there's an equivalent default constructor that would be
// used instead.
bool HasEquivCtor = false;
if (IList->getNumInits() == 0) {
auto *CD = SemaRef.LookupDefaultConstructor(CXXRD);
HasEquivCtor = CD && !CD->isDeleted();
}
if (!HasEquivCtor) {
SemaRef.Diag(IList->getBeginLoc(),
diag::warn_cxx20_compat_aggregate_init_with_ctors)
<< IList->getSourceRange() << T;
}
}
}
}
void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
InitListExpr *IList,
QualType &DeclType,
bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject) {
if (DeclType->isAnyComplexType() && SubobjectIsDesignatorContext) {
// Explicitly braced initializer for complex type can be real+imaginary
// parts.
CheckComplexType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
} else if (DeclType->isScalarType()) {
CheckScalarType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
} else if (DeclType->isVectorType()) {
CheckVectorType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
} else if (DeclType->isRecordType()) {
assert(DeclType->isAggregateType() &&
"non-aggregate records should be handed in CheckSubElementType");
RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
auto Bases =
CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(),
CXXRecordDecl::base_class_iterator());
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
Bases = CXXRD->bases();
CheckStructUnionTypes(Entity, IList, DeclType, Bases, RD->field_begin(),
SubobjectIsDesignatorContext, Index, StructuredList,
StructuredIndex, TopLevelObject);
} else if (DeclType->isArrayType()) {
llvm::APSInt Zero(
SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()),
false);
CheckArrayType(Entity, IList, DeclType, Zero,
SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex);
} else if (DeclType->isVoidType() || DeclType->isFunctionType()) {
// This type is invalid, issue a diagnostic.
++Index;
if (!VerifyOnly)
SemaRef.Diag(IList->getBeginLoc(), diag::err_illegal_initializer_type)
<< DeclType;
hadError = true;
} else if (DeclType->isReferenceType()) {
CheckReferenceType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
} else if (DeclType->isObjCObjectType()) {
if (!VerifyOnly)
SemaRef.Diag(IList->getBeginLoc(), diag::err_init_objc_class) << DeclType;
hadError = true;
} else if (DeclType->isOCLIntelSubgroupAVCType() ||
DeclType->isSizelessBuiltinType()) {
// Checks for scalar type are sufficient for these types too.
CheckScalarType(Entity, IList, DeclType, Index, StructuredList,
StructuredIndex);
} else {
if (!VerifyOnly)
SemaRef.Diag(IList->getBeginLoc(), diag::err_illegal_initializer_type)
<< DeclType;
hadError = true;
}
}
void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
InitListExpr *IList,
QualType ElemType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool DirectlyDesignated) {
Expr *expr = IList->getInit(Index);
if (ElemType->isReferenceType())
return CheckReferenceType(Entity, IList, ElemType, Index,
StructuredList, StructuredIndex);
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
if (SubInitList->getNumInits() == 1 &&
IsStringInit(SubInitList->getInit(0), ElemType, SemaRef.Context) ==
SIF_None) {
// FIXME: It would be more faithful and no less correct to include an
// InitListExpr in the semantic form of the initializer list in this case.
expr = SubInitList->getInit(0);
}
// Nested aggregate initialization and C++ initialization are handled later.
} else if (isa<ImplicitValueInitExpr>(expr)) {
// This happens during template instantiation when we see an InitListExpr
// that we've already checked once.
assert(SemaRef.Context.hasSameType(expr->getType(), ElemType) &&
"found implicit initialization for the wrong type");
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
return;
}
if (SemaRef.getLangOpts().CPlusPlus || isa<InitListExpr>(expr)) {
// C++ [dcl.init.aggr]p2:
// Each member is copy-initialized from the corresponding
// initializer-clause.
// FIXME: Better EqualLoc?
InitializationKind Kind =
InitializationKind::CreateCopy(expr->getBeginLoc(), SourceLocation());
// Vector elements can be initialized from other vectors in which case
// we need initialization entity with a type of a vector (and not a vector
// element!) initializing multiple vector elements.
auto TmpEntity =
(ElemType->isExtVectorType() && !Entity.getType()->isExtVectorType())
? InitializedEntity::InitializeTemporary(ElemType)
: Entity;
InitializationSequence Seq(SemaRef, TmpEntity, Kind, expr,
/*TopLevelOfInitList*/ true);
// C++14 [dcl.init.aggr]p13:
// If the assignment-expression can initialize a member, the member is
// initialized. Otherwise [...] brace elision is assumed
//
// Brace elision is never performed if the element is not an
// assignment-expression.
if (Seq || isa<InitListExpr>(expr)) {
if (!VerifyOnly) {
ExprResult Result = Seq.Perform(SemaRef, TmpEntity, Kind, expr);
if (Result.isInvalid())
hadError = true;
UpdateStructuredListElement(StructuredList, StructuredIndex,
Result.getAs<Expr>());
} else if (!Seq) {
hadError = true;
} else if (StructuredList) {
UpdateStructuredListElement(StructuredList, StructuredIndex,
getDummyInit());
}
++Index;
return;
}
// Fall through for subaggregate initialization
} else if (ElemType->isScalarType() || ElemType->isAtomicType()) {
// FIXME: Need to handle atomic aggregate types with implicit init lists.
return CheckScalarType(Entity, IList, ElemType, Index,
StructuredList, StructuredIndex);
} else if (const ArrayType *arrayType =
SemaRef.Context.getAsArrayType(ElemType)) {
// arrayType can be incomplete if we're initializing a flexible
// array member. There's nothing we can do with the completed
// type here, though.
if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) {
// FIXME: Should we do this checking in verify-only mode?
if (!VerifyOnly)
CheckStringInit(expr, ElemType, arrayType, SemaRef);
if (StructuredList)
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
return;
}
// Fall through for subaggregate initialization.
} else {
assert((ElemType->isRecordType() || ElemType->isVectorType() ||
ElemType->isOpenCLSpecificType()) && "Unexpected type");
// C99 6.7.8p13:
//
// The initializer for a structure or union object that has
// automatic storage duration shall be either an initializer
// list as described below, or a single expression that has
// compatible structure or union type. In the latter case, the
// initial value of the object, including unnamed members, is
// that of the expression.
ExprResult ExprRes = expr;
if (SemaRef.CheckSingleAssignmentConstraints(
ElemType, ExprRes, !VerifyOnly) != Sema::Incompatible) {
if (ExprRes.isInvalid())
hadError = true;
else {
ExprRes = SemaRef.DefaultFunctionArrayLvalueConversion(ExprRes.get());
if (ExprRes.isInvalid())
hadError = true;
}
UpdateStructuredListElement(StructuredList, StructuredIndex,
ExprRes.getAs<Expr>());
++Index;
return;
}
ExprRes.get();
// Fall through for subaggregate initialization
}
// C++ [dcl.init.aggr]p12:
//
// [...] Otherwise, if the member is itself a non-empty
// subaggregate, brace elision is assumed and the initializer is
// considered for the initialization of the first member of
// the subaggregate.
// OpenCL vector initializer is handled elsewhere.
if ((!SemaRef.getLangOpts().OpenCL && ElemType->isVectorType()) ||
ElemType->isAggregateType()) {
CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList,
StructuredIndex);
++StructuredIndex;
// In C++20, brace elision is not permitted for a designated initializer.
if (DirectlyDesignated && SemaRef.getLangOpts().CPlusPlus && !hadError) {
if (InOverloadResolution)
hadError = true;
if (!VerifyOnly) {
SemaRef.Diag(expr->getBeginLoc(),
diag::ext_designated_init_brace_elision)
<< expr->getSourceRange()
<< FixItHint::CreateInsertion(expr->getBeginLoc(), "{")
<< FixItHint::CreateInsertion(
SemaRef.getLocForEndOfToken(expr->getEndLoc()), "}");
}
}
} else {
if (!VerifyOnly) {
// We cannot initialize this element, so let PerformCopyInitialization
// produce the appropriate diagnostic. We already checked that this
// initialization will fail.
ExprResult Copy =
SemaRef.PerformCopyInitialization(Entity, SourceLocation(), expr,
/*TopLevelOfInitList=*/true);
(void)Copy;
assert(Copy.isInvalid() &&
"expected non-aggregate initialization to fail");
}
hadError = true;
++Index;
++StructuredIndex;
}
}
void InitListChecker::CheckComplexType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
assert(Index == 0 && "Index in explicit init list must be zero");
// As an extension, clang supports complex initializers, which initialize
// a complex number component-wise. When an explicit initializer list for
// a complex number contains two two initializers, this extension kicks in:
// it exepcts the initializer list to contain two elements convertible to
// the element type of the complex type. The first element initializes
// the real part, and the second element intitializes the imaginary part.
if (IList->getNumInits() != 2)
return CheckScalarType(Entity, IList, DeclType, Index, StructuredList,
StructuredIndex);
// This is an extension in C. (The builtin _Complex type does not exist
// in the C++ standard.)
if (!SemaRef.getLangOpts().CPlusPlus && !VerifyOnly)
SemaRef.Diag(IList->getBeginLoc(), diag::ext_complex_component_init)
<< IList->getSourceRange();
// Initialize the complex number.
QualType elementType = DeclType->castAs<ComplexType>()->getElementType();
InitializedEntity ElementEntity =
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
for (unsigned i = 0; i < 2; ++i) {
ElementEntity.setElementIndex(Index);
CheckSubElementType(ElementEntity, IList, elementType, Index,
StructuredList, StructuredIndex);
}
}
void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
if (Index >= IList->getNumInits()) {
if (!VerifyOnly) {
if (DeclType->isSizelessBuiltinType())
SemaRef.Diag(IList->getBeginLoc(),
SemaRef.getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_empty_sizeless_initializer
: diag::err_empty_sizeless_initializer)
<< DeclType << IList->getSourceRange();
else
SemaRef.Diag(IList->getBeginLoc(),
SemaRef.getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_empty_scalar_initializer
: diag::err_empty_scalar_initializer)
<< IList->getSourceRange();
}
hadError = !SemaRef.getLangOpts().CPlusPlus11;
++Index;
++StructuredIndex;
return;
}
Expr *expr = IList->getInit(Index);
if (InitListExpr *SubIList = dyn_cast<InitListExpr>(expr)) {
// FIXME: This is invalid, and accepting it causes overload resolution
// to pick the wrong overload in some corner cases.
if (!VerifyOnly)
SemaRef.Diag(SubIList->getBeginLoc(), diag::ext_many_braces_around_init)
<< DeclType->isSizelessBuiltinType() << SubIList->getSourceRange();
CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList,
StructuredIndex);
return;
} else if (isa<DesignatedInitExpr>(expr)) {
if (!VerifyOnly)
SemaRef.Diag(expr->getBeginLoc(),
diag::err_designator_for_scalar_or_sizeless_init)
<< DeclType->isSizelessBuiltinType() << DeclType
<< expr->getSourceRange();
hadError = true;
++Index;
++StructuredIndex;
return;
}
ExprResult Result;
if (VerifyOnly) {
if (SemaRef.CanPerformCopyInitialization(Entity, expr))
Result = getDummyInit();
else
Result = ExprError();
} else {
Result =
SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
/*TopLevelOfInitList=*/true);
}
Expr *ResultExpr = nullptr;
if (Result.isInvalid())
hadError = true; // types weren't compatible.
else {
ResultExpr = Result.getAs<Expr>();
if (ResultExpr != expr && !VerifyOnly) {
// The type was promoted, update initializer list.
// FIXME: Why are we updating the syntactic init list?
IList->setInit(Index, ResultExpr);
}
}
UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr);
++Index;
}
void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
if (Index >= IList->getNumInits()) {
// FIXME: It would be wonderful if we could point at the actual member. In
// general, it would be useful to pass location information down the stack,
// so that we know the location (or decl) of the "current object" being
// initialized.
if (!VerifyOnly)
SemaRef.Diag(IList->getBeginLoc(),
diag::err_init_reference_member_uninitialized)
<< DeclType << IList->getSourceRange();
hadError = true;
++Index;
++StructuredIndex;
return;
}
Expr *expr = IList->getInit(Index);
if (isa<InitListExpr>(expr) && !SemaRef.getLangOpts().CPlusPlus11) {
if (!VerifyOnly)
SemaRef.Diag(IList->getBeginLoc(), diag::err_init_non_aggr_init_list)
<< DeclType << IList->getSourceRange();
hadError = true;
++Index;
++StructuredIndex;
return;
}
ExprResult Result;
if (VerifyOnly) {
if (SemaRef.CanPerformCopyInitialization(Entity,expr))
Result = getDummyInit();
else
Result = ExprError();
} else {
Result =
SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
/*TopLevelOfInitList=*/true);
}
if (Result.isInvalid())
hadError = true;
expr = Result.getAs<Expr>();
// FIXME: Why are we updating the syntactic init list?
if (!VerifyOnly && expr)
IList->setInit(Index, expr);
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
}
void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
const VectorType *VT = DeclType->castAs<VectorType>();
unsigned maxElements = VT->getNumElements();
unsigned numEltsInit = 0;
QualType elementType = VT->getElementType();
if (Index >= IList->getNumInits()) {
// Make sure the element type can be value-initialized.
CheckEmptyInitializable(
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity),
IList->getEndLoc());
return;
}
if (!SemaRef.getLangOpts().OpenCL && !SemaRef.getLangOpts().HLSL ) {
// If the initializing element is a vector, try to copy-initialize
// instead of breaking it apart (which is doomed to failure anyway).
Expr *Init = IList->getInit(Index);
if (!isa<InitListExpr>(Init) && Init->getType()->isVectorType()) {
ExprResult Result;
if (VerifyOnly) {
if (SemaRef.CanPerformCopyInitialization(Entity, Init))
Result = getDummyInit();
else
Result = ExprError();
} else {
Result =
SemaRef.PerformCopyInitialization(Entity, Init->getBeginLoc(), Init,
/*TopLevelOfInitList=*/true);
}
Expr *ResultExpr = nullptr;
if (Result.isInvalid())
hadError = true; // types weren't compatible.
else {
ResultExpr = Result.getAs<Expr>();
if (ResultExpr != Init && !VerifyOnly) {
// The type was promoted, update initializer list.
// FIXME: Why are we updating the syntactic init list?
IList->setInit(Index, ResultExpr);
}
}
UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr);
++Index;
return;
}
InitializedEntity ElementEntity =
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) {
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits()) {
CheckEmptyInitializable(ElementEntity, IList->getEndLoc());
break;
}
ElementEntity.setElementIndex(Index);
CheckSubElementType(ElementEntity, IList, elementType, Index,
StructuredList, StructuredIndex);
}
if (VerifyOnly)
return;
bool isBigEndian = SemaRef.Context.getTargetInfo().isBigEndian();
const VectorType *T = Entity.getType()->castAs<VectorType>();
if (isBigEndian && (T->getVectorKind() == VectorType::NeonVector ||
T->getVectorKind() == VectorType::NeonPolyVector)) {
// The ability to use vector initializer lists is a GNU vector extension
// and is unrelated to the NEON intrinsics in arm_neon.h. On little
// endian machines it works fine, however on big endian machines it
// exhibits surprising behaviour:
//
// uint32x2_t x = {42, 64};
// return vget_lane_u32(x, 0); // Will return 64.
//
// Because of this, explicitly call out that it is non-portable.
//
SemaRef.Diag(IList->getBeginLoc(),
diag::warn_neon_vector_initializer_non_portable);
const char *typeCode;
unsigned typeSize = SemaRef.Context.getTypeSize(elementType);
if (elementType->isFloatingType())
typeCode = "f";
else if (elementType->isSignedIntegerType())
typeCode = "s";
else if (elementType->isUnsignedIntegerType())
typeCode = "u";
else
llvm_unreachable("Invalid element type!");
SemaRef.Diag(IList->getBeginLoc(),
SemaRef.Context.getTypeSize(VT) > 64
? diag::note_neon_vector_initializer_non_portable_q
: diag::note_neon_vector_initializer_non_portable)
<< typeCode << typeSize;
}
return;
}
InitializedEntity ElementEntity =
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
// OpenCL and HLSL initializers allow vectors to be constructed from vectors.
for (unsigned i = 0; i < maxElements; ++i) {
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits())
break;
ElementEntity.setElementIndex(Index);
QualType IType = IList->getInit(Index)->getType();
if (!IType->isVectorType()) {
CheckSubElementType(ElementEntity, IList, elementType, Index,
StructuredList, StructuredIndex);
++numEltsInit;
} else {
QualType VecType;
const VectorType *IVT = IType->castAs<VectorType>();
unsigned numIElts = IVT->getNumElements();
if (IType->isExtVectorType())
VecType = SemaRef.Context.getExtVectorType(elementType, numIElts);
else
VecType = SemaRef.Context.getVectorType(elementType, numIElts,
IVT->getVectorKind());
CheckSubElementType(ElementEntity, IList, VecType, Index,
StructuredList, StructuredIndex);
numEltsInit += numIElts;
}
}
// OpenCL and HLSL require all elements to be initialized.
if (numEltsInit != maxElements) {
if (!VerifyOnly)
SemaRef.Diag(IList->getBeginLoc(),
diag::err_vector_incorrect_num_initializers)
<< (numEltsInit < maxElements) << maxElements << numEltsInit;
hadError = true;
}
}
/// Check if the type of a class element has an accessible destructor, and marks
/// it referenced. Returns true if we shouldn't form a reference to the
/// destructor.
///
/// Aggregate initialization requires a class element's destructor be
/// accessible per 11.6.1 [dcl.init.aggr]:
///
/// The destructor for each element of class type is potentially invoked
/// (15.4 [class.dtor]) from the context where the aggregate initialization
/// occurs.
static bool checkDestructorReference(QualType ElementType, SourceLocation Loc,
Sema &SemaRef) {
auto *CXXRD = ElementType->getAsCXXRecordDecl();
if (!CXXRD)
return false;
CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD);
SemaRef.CheckDestructorAccess(Loc, Destructor,
SemaRef.PDiag(diag::err_access_dtor_temp)
<< ElementType);
SemaRef.MarkFunctionReferenced(Loc, Destructor);
return SemaRef.DiagnoseUseOfDecl(Destructor, Loc);
}
void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
const ArrayType *arrayType = SemaRef.Context.getAsArrayType(DeclType);
if (!VerifyOnly) {
if (checkDestructorReference(arrayType->getElementType(),
IList->getEndLoc(), SemaRef)) {
hadError = true;
return;
}
}
// Check for the special-case of initializing an array with a string.
if (Index < IList->getNumInits()) {
if (IsStringInit(IList->getInit(Index), arrayType, SemaRef.Context) ==
SIF_None) {
// We place the string literal directly into the resulting
// initializer list. This is the only place where the structure
// of the structured initializer list doesn't match exactly,
// because doing so would involve allocating one character
// constant for each string.
// FIXME: Should we do these checks in verify-only mode too?
if (!VerifyOnly)
CheckStringInit(IList->getInit(Index), DeclType, arrayType, SemaRef);
if (StructuredList) {
UpdateStructuredListElement(StructuredList, StructuredIndex,
IList->getInit(Index));
StructuredList->resizeInits(SemaRef.Context, StructuredIndex);
}
++Index;
return;
}
}
if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(arrayType)) {
// Check for VLAs; in standard C it would be possible to check this
// earlier, but I don't know where clang accepts VLAs (gcc accepts
// them in all sorts of strange places).
if (!VerifyOnly)
SemaRef.Diag(VAT->getSizeExpr()->getBeginLoc(),
diag::err_variable_object_no_init)
<< VAT->getSizeExpr()->getSourceRange();
hadError = true;
++Index;
++StructuredIndex;
return;
}
// We might know the maximum number of elements in advance.
llvm::APSInt maxElements(elementIndex.getBitWidth(),
elementIndex.isUnsigned());
bool maxElementsKnown = false;
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(arrayType)) {
maxElements = CAT->getSize();
elementIndex = elementIndex.extOrTrunc(maxElements.getBitWidth());
elementIndex.setIsUnsigned(maxElements.isUnsigned());
maxElementsKnown = true;
}
QualType elementType = arrayType->getElementType();
while (Index < IList->getNumInits()) {
Expr *Init = IList->getInit(Index);
if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
// If we're not the subobject that matches up with the '{' for
// the designator, we shouldn't be handling the
// designator. Return immediately.
if (!SubobjectIsDesignatorContext)
return;
// Handle this designated initializer. elementIndex will be
// updated to be the next array element we'll initialize.
if (CheckDesignatedInitializer(Entity, IList, DIE, 0,
DeclType, nullptr, &elementIndex, Index,
StructuredList, StructuredIndex, true,
false)) {
hadError = true;
continue;
}
if (elementIndex.getBitWidth() > maxElements.getBitWidth())
maxElements = maxElements.extend(elementIndex.getBitWidth());
else if (elementIndex.getBitWidth() < maxElements.getBitWidth())
elementIndex = elementIndex.extend(maxElements.getBitWidth());
elementIndex.setIsUnsigned(maxElements.isUnsigned());
// If the array is of incomplete type, keep track of the number of
// elements in the initializer.
if (!maxElementsKnown && elementIndex > maxElements)
maxElements = elementIndex;
continue;
}
// If we know the maximum number of elements, and we've already
// hit it, stop consuming elements in the initializer list.
if (maxElementsKnown && elementIndex == maxElements)
break;
InitializedEntity ElementEntity =
InitializedEntity::InitializeElement(SemaRef.Context, StructuredIndex,
Entity);
// Check this element.
CheckSubElementType(ElementEntity, IList, elementType, Index,
StructuredList, StructuredIndex);
++elementIndex;
// If the array is of incomplete type, keep track of the number of
// elements in the initializer.
if (!maxElementsKnown && elementIndex > maxElements)
maxElements = elementIndex;
}
if (!hadError && DeclType->isIncompleteArrayType() && !VerifyOnly) {
// If this is an incomplete array type, the actual type needs to
// be calculated here.
llvm::APSInt Zero(maxElements.getBitWidth(), maxElements.isUnsigned());
if (maxElements == Zero && !Entity.isVariableLengthArrayNew()) {
// Sizing an array implicitly to zero is not allowed by ISO C,
// but is supported by GNU.
SemaRef.Diag(IList->getBeginLoc(), diag::ext_typecheck_zero_array_size);
}
DeclType = SemaRef.Context.getConstantArrayType(
elementType, maxElements, nullptr, ArrayType::Normal, 0);
}
if (!hadError) {
// If there are any members of the array that get value-initialized, check
// that is possible. That happens if we know the bound and don't have
// enough elements, or if we're performing an array new with an unknown
// bound.
if ((maxElementsKnown && elementIndex < maxElements) ||
Entity.isVariableLengthArrayNew())
CheckEmptyInitializable(
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity),
IList->getEndLoc());
}
}
bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity,
Expr *InitExpr,
FieldDecl *Field,
bool TopLevelObject) {
// Handle GNU flexible array initializers.
unsigned FlexArrayDiag;
if (isa<InitListExpr>(InitExpr) &&
cast<InitListExpr>(InitExpr)->getNumInits() == 0) {
// Empty flexible array init always allowed as an extension
FlexArrayDiag = diag::ext_flexible_array_init;
} else if (!TopLevelObject) {
// Disallow flexible array init on non-top-level object
FlexArrayDiag = diag::err_flexible_array_init;
} else if (Entity.getKind() != InitializedEntity::EK_Variable) {
// Disallow flexible array init on anything which is not a variable.
FlexArrayDiag = diag::err_flexible_array_init;
} else if (cast<VarDecl>(Entity.getDecl())->hasLocalStorage()) {
// Disallow flexible array init on local variables.
FlexArrayDiag = diag::err_flexible_array_init;
} else {
// Allow other cases.
FlexArrayDiag = diag::ext_flexible_array_init;
}
if (!VerifyOnly) {
SemaRef.Diag(InitExpr->getBeginLoc(), FlexArrayDiag)
<< InitExpr->getBeginLoc();
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
<< Field;
}
return FlexArrayDiag != diag::ext_flexible_array_init;
}
void InitListChecker::CheckStructUnionTypes(
const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType,
CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList, unsigned &StructuredIndex,
bool TopLevelObject) {
RecordDecl *structDecl = DeclType->castAs<RecordType>()->getDecl();
// If the record is invalid, some of it's members are invalid. To avoid
// confusion, we forgo checking the initializer for the entire record.
if (structDecl->isInvalidDecl()) {
// Assume it was supposed to consume a single initializer.
++Index;
hadError = true;
return;
}
if (DeclType->isUnionType() && IList->getNumInits() == 0) {
RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
if (!VerifyOnly)
for (FieldDecl *FD : RD->fields()) {
QualType ET = SemaRef.Context.getBaseElementType(FD->getType());
if (checkDestructorReference(ET, IList->getEndLoc(), SemaRef)) {
hadError = true;
return;
}
}
// If there's a default initializer, use it.
if (isa<CXXRecordDecl>(RD) &&
cast<CXXRecordDecl>(RD)->hasInClassInitializer()) {
if (!StructuredList)
return;
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
if (Field->hasInClassInitializer()) {
StructuredList->setInitializedFieldInUnion(*Field);
// FIXME: Actually build a CXXDefaultInitExpr?
return;
}
}
}
// Value-initialize the first member of the union that isn't an unnamed
// bitfield.
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
if (!Field->isUnnamedBitfield()) {
CheckEmptyInitializable(
InitializedEntity::InitializeMember(*Field, &Entity),
IList->getEndLoc());
if (StructuredList)
StructuredList->setInitializedFieldInUnion(*Field);
break;
}
}
return;
}
bool InitializedSomething = false;
// If we have any base classes, they are initialized prior to the fields.
for (auto &Base : Bases) {
Expr *Init = Index < IList->getNumInits() ? IList->getInit(Index) : nullptr;
// Designated inits always initialize fields, so if we see one, all
// remaining base classes have no explicit initializer.
if (Init && isa<DesignatedInitExpr>(Init))
Init = nullptr;
SourceLocation InitLoc = Init ? Init->getBeginLoc() : IList->getEndLoc();
InitializedEntity BaseEntity = InitializedEntity::InitializeBase(
SemaRef.Context, &Base, false, &Entity);
if (Init) {
CheckSubElementType(BaseEntity, IList, Base.getType(), Index,
StructuredList, StructuredIndex);
InitializedSomething = true;
} else {
CheckEmptyInitializable(BaseEntity, InitLoc);
}
if (!VerifyOnly)
if (checkDestructorReference(Base.getType(), InitLoc, SemaRef)) {
hadError = true;
return;
}
}
// If structDecl is a forward declaration, this loop won't do
// anything except look at designated initializers; That's okay,
// because an error should get printed out elsewhere. It might be
// worthwhile to skip over the rest of the initializer, though.
RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
RecordDecl::field_iterator FieldEnd = RD->field_end();
size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) {
return isa<FieldDecl>(D) || isa<RecordDecl>(D);
});
bool CheckForMissingFields =
!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
bool HasDesignatedInit = false;
while (Index < IList->getNumInits()) {
Expr *Init = IList->getInit(Index);
SourceLocation InitLoc = Init->getBeginLoc();
if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
// If we're not the subobject that matches up with the '{' for
// the designator, we shouldn't be handling the
// designator. Return immediately.
if (!SubobjectIsDesignatorContext)
return;
HasDesignatedInit = true;
// Handle this designated initializer. Field will be updated to
// the next field that we'll be initializing.
if (CheckDesignatedInitializer(Entity, IList, DIE, 0,
DeclType, &Field, nullptr, Index,
StructuredList, StructuredIndex,
true, TopLevelObject))
hadError = true;
else if (!VerifyOnly) {
// Find the field named by the designated initializer.
RecordDecl::field_iterator F = RD->field_begin();
while (std::next(F) != Field)
++F;
QualType ET = SemaRef.Context.getBaseElementType(F->getType());
if (checkDestructorReference(ET, InitLoc, SemaRef)) {
hadError = true;
return;
}
}
InitializedSomething = true;
// Disable check for missing fields when designators are used.
// This matches gcc behaviour.
CheckForMissingFields = false;
continue;
}
// Check if this is an initializer of forms:
//
// struct foo f = {};
// struct foo g = {0};
//
// These are okay for randomized structures. [C99 6.7.8p19]
//
// Also, if there is only one element in the structure, we allow something
// like this, because it's really not randomized in the tranditional sense.
//
// struct foo h = {bar};
auto IsZeroInitializer = [&](const Expr *I) {
if (IList->getNumInits() == 1) {
if (NumRecordDecls == 1)
return true;
if (const auto *IL = dyn_cast<IntegerLiteral>(I))
return IL->getValue().isZero();
}
return false;
};
// Don't allow non-designated initializers on randomized structures.
if (RD->isRandomized() && !IsZeroInitializer(Init)) {
if (!VerifyOnly)
SemaRef.Diag(InitLoc, diag::err_non_designated_init_used);
hadError = true;
break;
}
if (Field == FieldEnd) {
// We've run out of fields. We're done.
break;
}
// We've already initialized a member of a union. We're done.
if (InitializedSomething && DeclType->isUnionType())
break;
// If we've hit the flexible array member at the end, we're done.
if (Field->getType()->isIncompleteArrayType())
break;
if (Field->isUnnamedBitfield()) {
// Don't initialize unnamed bitfields, e.g. "int : 20;"
++Field;
continue;
}
// Make sure we can use this declaration.
bool InvalidUse;
if (VerifyOnly)
InvalidUse = !SemaRef.CanUseDecl(*Field, TreatUnavailableAsInvalid);
else
InvalidUse = SemaRef.DiagnoseUseOfDecl(
*Field, IList->getInit(Index)->getBeginLoc());
if (InvalidUse) {
++Index;
++Field;
hadError = true;
continue;
}
if (!VerifyOnly) {
QualType ET = SemaRef.Context.getBaseElementType(Field->getType());
if (checkDestructorReference(ET, InitLoc, SemaRef)) {
hadError = true;
return;
}
}
InitializedEntity MemberEntity =
InitializedEntity::InitializeMember(*Field, &Entity);
CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
StructuredList, StructuredIndex);
InitializedSomething = true;
if (DeclType->isUnionType() && StructuredList) {
// Initialize the first field within the union.
StructuredList->setInitializedFieldInUnion(*Field);
}
++Field;
}
// Emit warnings for missing struct field initializers.
if (!VerifyOnly && InitializedSomething && CheckForMissingFields &&
Field != FieldEnd && !Field->getType()->isIncompleteArrayType() &&
!DeclType->isUnionType()) {
// It is possible we have one or more unnamed bitfields remaining.
// Find first (if any) named field and emit warning.
for (RecordDecl::field_iterator it = Field, end = RD->field_end();
it != end; ++it) {
if (!it->isUnnamedBitfield() && !it->hasInClassInitializer()) {
SemaRef.Diag(IList->getSourceRange().getEnd(),
diag::warn_missing_field_initializers) << *it;
break;
}
}
}
// Check that any remaining fields can be value-initialized if we're not
// building a structured list. (If we are, we'll check this later.)
if (!StructuredList && Field != FieldEnd && !DeclType->isUnionType() &&
!Field->getType()->isIncompleteArrayType()) {
for (; Field != FieldEnd && !hadError; ++Field) {
if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer())
CheckEmptyInitializable(
InitializedEntity::InitializeMember(*Field, &Entity),
IList->getEndLoc());
}
}
// Check that the types of the remaining fields have accessible destructors.
if (!VerifyOnly) {
// If the initializer expression has a designated initializer, check the
// elements for which a designated initializer is not provided too.
RecordDecl::field_iterator I = HasDesignatedInit ? RD->field_begin()
: Field;
for (RecordDecl::field_iterator E = RD->field_end(); I != E; ++I) {
QualType ET = SemaRef.Context.getBaseElementType(I->getType());
if (checkDestructorReference(ET, IList->getEndLoc(), SemaRef)) {
hadError = true;
return;
}
}
}
if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() ||
Index >= IList->getNumInits())
return;
if (CheckFlexibleArrayInit(Entity, IList->getInit(Index), *Field,
TopLevelObject)) {
hadError = true;
++Index;
return;
}
InitializedEntity MemberEntity =
InitializedEntity::InitializeMember(*Field, &Entity);
if (isa<InitListExpr>(IList->getInit(Index)))
CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
StructuredList, StructuredIndex);
else
CheckImplicitInitList(MemberEntity, IList, Field->getType(), Index,
StructuredList, StructuredIndex);
}
/// Expand a field designator that refers to a member of an
/// anonymous struct or union into a series of field designators that
/// refers to the field within the appropriate subobject.
///
static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
DesignatedInitExpr *DIE,
unsigned DesigIdx,
IndirectFieldDecl *IndirectField) {
typedef DesignatedInitExpr::Designator Designator;
// Build the replacement designators.
SmallVector<Designator, 4> Replacements;
for (IndirectFieldDecl::chain_iterator PI = IndirectField->chain_begin(),
PE = IndirectField->chain_end(); PI != PE; ++PI) {
if (PI + 1 == PE)
Replacements.push_back(Designator((IdentifierInfo *)nullptr,
DIE->getDesignator(DesigIdx)->getDotLoc(),
DIE->getDesignator(DesigIdx)->getFieldLoc()));
else
Replacements.push_back(Designator((IdentifierInfo *)nullptr,
SourceLocation(), SourceLocation()));
assert(isa<FieldDecl>(*PI));
Replacements.back().setField(cast<FieldDecl>(*PI));
}
// Expand the current designator into the set of replacement
// designators, so we have a full subobject path down to where the
// member of the anonymous struct/union is actually stored.
DIE->ExpandDesignator(SemaRef.Context, DesigIdx, &Replacements[0],
&Replacements[0] + Replacements.size());
}
static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef,
DesignatedInitExpr *DIE) {
unsigned NumIndexExprs = DIE->getNumSubExprs() - 1;
SmallVector<Expr*, 4> IndexExprs(NumIndexExprs);
for (unsigned I = 0; I < NumIndexExprs; ++I)
IndexExprs[I] = DIE->getSubExpr(I + 1);
return DesignatedInitExpr::Create(SemaRef.Context, DIE->designators(),
IndexExprs,
DIE->getEqualOrColonLoc(),
DIE->usesGNUSyntax(), DIE->getInit());
}
namespace {
// Callback to only accept typo corrections that are for field members of
// the given struct or union.
class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
public:
explicit FieldInitializerValidatorCCC(RecordDecl *RD)
: Record(RD) {}
bool ValidateCandidate(const TypoCorrection &candidate) override {
FieldDecl *FD = candidate.getCorrectionDeclAs<FieldDecl>();
return FD && FD->getDeclContext()->getRedeclContext()->Equals(Record);
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
return std::make_unique<FieldInitializerValidatorCCC>(*this);
}
private:
RecordDecl *Record;
};
} // end anonymous namespace
/// Check the well-formedness of a C99 designated initializer.
///
/// Determines whether the designated initializer @p DIE, which
/// resides at the given @p Index within the initializer list @p
/// IList, is well-formed for a current object of type @p DeclType
/// (C99 6.7.8). The actual subobject that this designator refers to
/// within the current subobject is returned in either
/// @p NextField or @p NextElementIndex (whichever is appropriate).
///
/// @param IList The initializer list in which this designated
/// initializer occurs.
///
/// @param DIE The designated initializer expression.
///
/// @param DesigIdx The index of the current designator.
///
/// @param CurrentObjectType The type of the "current object" (C99 6.7.8p17),
/// into which the designation in @p DIE should refer.
///
/// @param NextField If non-NULL and the first designator in @p DIE is
/// a field, this will be set to the field declaration corresponding
/// to the field named by the designator. On input, this is expected to be
/// the next field that would be initialized in the absence of designation,
/// if the complete object being initialized is a struct.
///
/// @param NextElementIndex If non-NULL and the first designator in @p
/// DIE is an array designator or GNU array-range designator, this
/// will be set to the last index initialized by this designator.
///
/// @param Index Index into @p IList where the designated initializer
/// @p DIE occurs.
///
/// @param StructuredList The initializer list expression that
/// describes all of the subobject initializers in the order they'll
/// actually be initialized.
///
/// @returns true if there was an error, false otherwise.
bool
InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
InitListExpr *IList,
DesignatedInitExpr *DIE,
unsigned DesigIdx,
QualType &CurrentObjectType,
RecordDecl::field_iterator *NextField,
llvm::APSInt *NextElementIndex,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool FinishSubobjectInit,
bool TopLevelObject) {
if (DesigIdx == DIE->size()) {
// C++20 designated initialization can result in direct-list-initialization
// of the designated subobject. This is the only way that we can end up
// performing direct initialization as part of aggregate initialization, so
// it needs special handling.
if (DIE->isDirectInit()) {
Expr *Init = DIE->getInit();
assert(isa<InitListExpr>(Init) &&
"designator result in direct non-list initialization?");
InitializationKind Kind = InitializationKind::CreateDirectList(
DIE->getBeginLoc(), Init->getBeginLoc(), Init->getEndLoc());
InitializationSequence Seq(SemaRef, Entity, Kind, Init,
/*TopLevelOfInitList*/ true);
if (StructuredList) {
ExprResult Result = VerifyOnly
? getDummyInit()
: Seq.Perform(SemaRef, Entity, Kind, Init);
UpdateStructuredListElement(StructuredList, StructuredIndex,
Result.get());
}
++Index;
return !Seq;
}
// Check the actual initialization for the designated object type.
bool prevHadError = hadError;
// Temporarily remove the designator expression from the
// initializer list that the child calls see, so that we don't try
// to re-process the designator.
unsigned OldIndex = Index;
IList->setInit(OldIndex, DIE->getInit());
CheckSubElementType(Entity, IList, CurrentObjectType, Index, StructuredList,
StructuredIndex, /*DirectlyDesignated=*/true);
// Restore the designated initializer expression in the syntactic
// form of the initializer list.
if (IList->getInit(OldIndex) != DIE->getInit())
DIE->setInit(IList->getInit(OldIndex));
IList->setInit(OldIndex, DIE);
return hadError && !prevHadError;
}
DesignatedInitExpr::Designator *D = DIE->getDesignator(DesigIdx);
bool IsFirstDesignator = (DesigIdx == 0);
if (IsFirstDesignator ? FullyStructuredList : StructuredList) {
// Determine the structural initializer list that corresponds to the
// current subobject.
if (IsFirstDesignator)
StructuredList = FullyStructuredList;
else {
Expr *ExistingInit = StructuredIndex < StructuredList->getNumInits() ?
StructuredList->getInit(StructuredIndex) : nullptr;
if (!ExistingInit && StructuredList->hasArrayFiller())
ExistingInit = StructuredList->getArrayFiller();
if (!ExistingInit)
StructuredList = getStructuredSubobjectInit(
IList, Index, CurrentObjectType, StructuredList, StructuredIndex,
SourceRange(D->getBeginLoc(), DIE->getEndLoc()));
else if (InitListExpr *Result = dyn_cast<InitListExpr>(ExistingInit))
StructuredList = Result;
else {
// We are creating an initializer list that initializes the
// subobjects of the current object, but there was already an
// initialization that completely initialized the current
// subobject, e.g., by a compound literal:
//
// struct X { int a, b; };
// struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
//
// Here, xs[0].a == 1 and xs[0].b == 3, since the second,
// designated initializer re-initializes only its current object
// subobject [0].b.
diagnoseInitOverride(ExistingInit,
SourceRange(D->getBeginLoc(), DIE->getEndLoc()),
/*FullyOverwritten=*/false);
if (!VerifyOnly) {
if (DesignatedInitUpdateExpr *E =
dyn_cast<DesignatedInitUpdateExpr>(ExistingInit))
StructuredList = E->getUpdater();
else {
DesignatedInitUpdateExpr *DIUE = new (SemaRef.Context)
DesignatedInitUpdateExpr(SemaRef.Context, D->getBeginLoc(),
ExistingInit, DIE->getEndLoc());
StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE);
StructuredList = DIUE->getUpdater();
}
} else {
// We don't need to track the structured representation of a
// designated init update of an already-fully-initialized object in
// verify-only mode. The only reason we would need the structure is
// to determine where the uninitialized "holes" are, and in this
// case, we know there aren't any and we can't introduce any.
StructuredList = nullptr;
}
}
}
}
if (D->isFieldDesignator()) {
// C99 6.7.8p7:
//
// If a designator has the form
//
// . identifier
//
// then the current object (defined below) shall have
// structure or union type and the identifier shall be the
// name of a member of that type.
const RecordType *RT = CurrentObjectType->getAs<RecordType>();
if (!RT) {
SourceLocation Loc = D->getDotLoc();
if (Loc.isInvalid())
Loc = D->getFieldLoc();
if (!VerifyOnly)
SemaRef.Diag(Loc, diag::err_field_designator_non_aggr)
<< SemaRef.getLangOpts().CPlusPlus << CurrentObjectType;
++Index;
return true;
}
FieldDecl *KnownField = D->getField();
if (!KnownField) {
IdentifierInfo *FieldName = D->getFieldName();
DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
for (NamedDecl *ND : Lookup) {
if (auto *FD = dyn_cast<FieldDecl>(ND)) {
KnownField = FD;
break;
}
if (auto *IFD = dyn_cast<IndirectFieldDecl>(ND)) {
// In verify mode, don't modify the original.
if (VerifyOnly)
DIE = CloneDesignatedInitExpr(SemaRef, DIE);
ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, IFD);
D = DIE->getDesignator(DesigIdx);
KnownField = cast<FieldDecl>(*IFD->chain_begin());
break;
}
}
if (!KnownField) {
if (VerifyOnly) {
++Index;
return true; // No typo correction when just trying this out.
}
// Name lookup found something, but it wasn't a field.
if (!Lookup.empty()) {
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
<< FieldName;
SemaRef.Diag(Lookup.front()->getLocation(),
diag::note_field_designator_found);
++Index;
return true;
}
// Name lookup didn't find anything.
// Determine whether this was a typo for another field name.
FieldInitializerValidatorCCC CCC(RT->getDecl());
if (TypoCorrection Corrected = SemaRef.CorrectTypo(
DeclarationNameInfo(FieldName, D->getFieldLoc()),
Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr, CCC,
Sema::CTK_ErrorRecovery, RT->getDecl())) {
SemaRef.diagnoseTypo(
Corrected,
SemaRef.PDiag(diag::err_field_designator_unknown_suggest)
<< FieldName << CurrentObjectType);
KnownField = Corrected.getCorrectionDeclAs<FieldDecl>();
hadError = true;
} else {
// Typo correction didn't find anything.
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
++Index;
return true;
}
}
}
unsigned NumBases = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
NumBases = CXXRD->getNumBases();
unsigned FieldIndex = NumBases;
for (auto *FI : RT->getDecl()->fields()) {
if (FI->isUnnamedBitfield())
continue;
if (declaresSameEntity(KnownField, FI)) {
KnownField = FI;
break;
}
++FieldIndex;
}
RecordDecl::field_iterator Field =
RecordDecl::field_iterator(DeclContext::decl_iterator(KnownField));
// All of the fields of a union are located at the same place in
// the initializer list.
if (RT->getDecl()->isUnion()) {
FieldIndex = 0;
if (StructuredList) {
FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion();
if (CurrentField && !declaresSameEntity(CurrentField, *Field)) {
assert(StructuredList->getNumInits() == 1
&& "A union should never have more than one initializer!");
Expr *ExistingInit = StructuredList->getInit(0);
if (ExistingInit) {
// We're about to throw away an initializer, emit warning.
diagnoseInitOverride(
ExistingInit, SourceRange(D->getBeginLoc(), DIE->getEndLoc()));
}
// remove existing initializer
StructuredList->resizeInits(SemaRef.Context, 0);
StructuredList->setInitializedFieldInUnion(nullptr);
}
StructuredList->setInitializedFieldInUnion(*Field);
}
}
// Make sure we can use this declaration.
bool InvalidUse;
if (VerifyOnly)
InvalidUse = !SemaRef.CanUseDecl(*Field, TreatUnavailableAsInvalid);
else
InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc());
if (InvalidUse) {
++Index;
return true;
}
// C++20 [dcl.init.list]p3:
// The ordered identifiers in the designators of the designated-
// initializer-list shall form a subsequence of the ordered identifiers
// in the direct non-static data members of T.
//
// Note that this is not a condition on forming the aggregate
// initialization, only on actually performing initialization,
// so it is not checked in VerifyOnly mode.
//
// FIXME: This is the only reordering diagnostic we produce, and it only
// catches cases where we have a top-level field designator that jumps
// backwards. This is the only such case that is reachable in an
// otherwise-valid C++20 program, so is the only case that's required for
// conformance, but for consistency, we should diagnose all the other
// cases where a designator takes us backwards too.
if (IsFirstDesignator && !VerifyOnly && SemaRef.getLangOpts().CPlusPlus &&
NextField &&
(*NextField == RT->getDecl()->field_end() ||
(*NextField)->getFieldIndex() > Field->getFieldIndex() + 1)) {
// Find the field that we just initialized.
FieldDecl *PrevField = nullptr;
for (auto FI = RT->getDecl()->field_begin();
FI != RT->getDecl()->field_end(); ++FI) {
if (FI->isUnnamedBitfield())
continue;
if (*NextField != RT->getDecl()->field_end() &&
declaresSameEntity(*FI, **NextField))
break;
PrevField = *FI;
}
if (PrevField &&
PrevField->getFieldIndex() > KnownField->getFieldIndex()) {
SemaRef.Diag(DIE->getBeginLoc(), diag::ext_designated_init_reordered)
<< KnownField << PrevField << DIE->getSourceRange();
unsigned OldIndex = NumBases + PrevField->getFieldIndex();
if (StructuredList && OldIndex <= StructuredList->getNumInits()) {
if (Expr *PrevInit = StructuredList->getInit(OldIndex)) {
SemaRef.Diag(PrevInit->getBeginLoc(),
diag::note_previous_field_init)
<< PrevField << PrevInit->getSourceRange();
}
}
}
}
// Update the designator with the field declaration.
if (!VerifyOnly)
D->setField(*Field);
// Make sure that our non-designated initializer list has space
// for a subobject corresponding to this field.
if (StructuredList && FieldIndex >= StructuredList->getNumInits())
StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1);
// This designator names a flexible array member.
if (Field->getType()->isIncompleteArrayType()) {
bool Invalid = false;
if ((DesigIdx + 1) != DIE->size()) {
// We can't designate an object within the flexible array
// member (because GCC doesn't allow it).
if (!VerifyOnly) {
DesignatedInitExpr::Designator *NextD
= DIE->getDesignator(DesigIdx + 1);
SemaRef.Diag(NextD->getBeginLoc(),
diag::err_designator_into_flexible_array_member)
<< SourceRange(NextD->getBeginLoc(), DIE->getEndLoc());
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
<< *Field;
}
Invalid = true;
}
if (!hadError && !isa<InitListExpr>(DIE->getInit()) &&
!isa<StringLiteral>(DIE->getInit())) {
// The initializer is not an initializer list.
if (!VerifyOnly) {
SemaRef.Diag(DIE->getInit()->getBeginLoc(),
diag::err_flexible_array_init_needs_braces)
<< DIE->getInit()->getSourceRange();
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
<< *Field;
}
Invalid = true;
}
// Check GNU flexible array initializer.
if (!Invalid && CheckFlexibleArrayInit(Entity, DIE->getInit(), *Field,
TopLevelObject))
Invalid = true;
if (Invalid) {
++Index;
return true;
}
// Initialize the array.
bool prevHadError = hadError;
unsigned newStructuredIndex = FieldIndex;
unsigned OldIndex = Index;
IList->setInit(Index, DIE->getInit());
InitializedEntity MemberEntity =
InitializedEntity::InitializeMember(*Field, &Entity);
CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
StructuredList, newStructuredIndex);
IList->setInit(OldIndex, DIE);
if (hadError && !prevHadError) {
++Field;
++FieldIndex;
if (NextField)
*NextField = Field;
StructuredIndex = FieldIndex;
return true;
}
} else {
// Recurse to check later designated subobjects.
QualType FieldType = Field->getType();
unsigned newStructuredIndex = FieldIndex;
InitializedEntity MemberEntity =
InitializedEntity::InitializeMember(*Field, &Entity);
if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1,
FieldType, nullptr, nullptr, Index,
StructuredList, newStructuredIndex,
FinishSubobjectInit, false))
return true;
}
// Find the position of the next field to be initialized in this
// subobject.
++Field;
++FieldIndex;
// If this the first designator, our caller will continue checking
// the rest of this struct/class/union subobject.
if (IsFirstDesignator) {
if (NextField)
*NextField = Field;
StructuredIndex = FieldIndex;
return false;
}
if (!FinishSubobjectInit)
return false;
// We've already initialized something in the union; we're done.
if (RT->getDecl()->isUnion())
return hadError;
// Check the remaining fields within this class/struct/union subobject.
bool prevHadError = hadError;
auto NoBases =
CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(),
CXXRecordDecl::base_class_iterator());
CheckStructUnionTypes(Entity, IList, CurrentObjectType, NoBases, Field,
false, Index, StructuredList, FieldIndex);
return hadError && !prevHadError;
}
// C99 6.7.8p6:
//
// If a designator has the form
//
// [ constant-expression ]
//
// then the current object (defined below) shall have array
// type and the expression shall be an integer constant
// expression. If the array is of unknown size, any
// nonnegative value is valid.
//
// Additionally, cope with the GNU extension that permits
// designators of the form
//
// [ constant-expression ... constant-expression ]
const ArrayType *AT = SemaRef.Context.getAsArrayType(CurrentObjectType);
if (!AT) {
if (!VerifyOnly)
SemaRef.Diag(D->getLBracketLoc(), diag::err_array_designator_non_array)
<< CurrentObjectType;
++Index;
return true;
}
Expr *IndexExpr = nullptr;
llvm::APSInt DesignatedStartIndex, DesignatedEndIndex;
if (D->isArrayDesignator()) {
IndexExpr = DIE->getArrayIndex(*D);
DesignatedStartIndex = IndexExpr->EvaluateKnownConstInt(SemaRef.Context);
DesignatedEndIndex = DesignatedStartIndex;
} else {
assert(D->isArrayRangeDesignator() && "Need array-range designator");
DesignatedStartIndex =
DIE->getArrayRangeStart(*D)->EvaluateKnownConstInt(SemaRef.Context);
DesignatedEndIndex =
DIE->getArrayRangeEnd(*D)->EvaluateKnownConstInt(SemaRef.Context);
IndexExpr = DIE->getArrayRangeEnd(*D);
// Codegen can't handle evaluating array range designators that have side
// effects, because we replicate the AST value for each initialized element.
// As such, set the sawArrayRangeDesignator() bit if we initialize multiple
// elements with something that has a side effect, so codegen can emit an
// "error unsupported" error instead of miscompiling the app.
if (DesignatedStartIndex.getZExtValue()!=DesignatedEndIndex.getZExtValue()&&
DIE->getInit()->HasSideEffects(SemaRef.Context) && !VerifyOnly)
FullyStructuredList->sawArrayRangeDesignator();
}
if (isa<ConstantArrayType>(AT)) {
llvm::APSInt MaxElements(cast<ConstantArrayType>(AT)->getSize(), false);
DesignatedStartIndex
= DesignatedStartIndex.extOrTrunc(MaxElements.getBitWidth());
DesignatedStartIndex.setIsUnsigned(MaxElements.isUnsigned());
DesignatedEndIndex
= DesignatedEndIndex.extOrTrunc(MaxElements.getBitWidth());
DesignatedEndIndex.setIsUnsigned(MaxElements.isUnsigned());
if (DesignatedEndIndex >= MaxElements) {
if (!VerifyOnly)
SemaRef.Diag(IndexExpr->getBeginLoc(),
diag::err_array_designator_too_large)
<< toString(DesignatedEndIndex, 10) << toString(MaxElements, 10)
<< IndexExpr->getSourceRange();
++Index;
return true;
}
} else {
unsigned DesignatedIndexBitWidth =
ConstantArrayType::getMaxSizeBits(SemaRef.Context);
DesignatedStartIndex =
DesignatedStartIndex.extOrTrunc(DesignatedIndexBitWidth);
DesignatedEndIndex =
DesignatedEndIndex.extOrTrunc(DesignatedIndexBitWidth);
DesignatedStartIndex.setIsUnsigned(true);
DesignatedEndIndex.setIsUnsigned(true);
}
bool IsStringLiteralInitUpdate =
StructuredList && StructuredList->isStringLiteralInit();
if (IsStringLiteralInitUpdate && VerifyOnly) {
// We're just verifying an update to a string literal init. We don't need
// to split the string up into individual characters to do that.
StructuredList = nullptr;
} else if (IsStringLiteralInitUpdate) {
// We're modifying a string literal init; we have to decompose the string
// so we can modify the individual characters.
ASTContext &Context = SemaRef.Context;
Expr *SubExpr = StructuredList->getInit(0)->IgnoreParenImpCasts();
// Compute the character type
QualType CharTy = AT->getElementType();
// Compute the type of the integer literals.
QualType PromotedCharTy = CharTy;
if (CharTy->isPromotableIntegerType())
PromotedCharTy = Context.getPromotedIntegerType(CharTy);
unsigned PromotedCharTyWidth = Context.getTypeSize(PromotedCharTy);
if (StringLiteral *SL = dyn_cast<StringLiteral>(SubExpr)) {
// Get the length of the string.
uint64_t StrLen = SL->getLength();
if (cast<ConstantArrayType>(AT)->getSize().ult(StrLen))
StrLen = cast<ConstantArrayType>(AT)->getSize().getZExtValue();
StructuredList->resizeInits(Context, StrLen);
// Build a literal for each character in the string, and put them into
// the init list.
for (unsigned i = 0, e = StrLen; i != e; ++i) {
llvm::APInt CodeUnit(PromotedCharTyWidth, SL->getCodeUnit(i));
Expr *Init = new (Context) IntegerLiteral(
Context, CodeUnit, PromotedCharTy, SubExpr->getExprLoc());
if (CharTy != PromotedCharTy)
Init = ImplicitCastExpr::Create(Context, CharTy, CK_IntegralCast,
Init, nullptr, VK_PRValue,
FPOptionsOverride());
StructuredList->updateInit(Context, i, Init);
}
} else {
ObjCEncodeExpr *E = cast<ObjCEncodeExpr>(SubExpr);
std::string Str;
Context.getObjCEncodingForType(E->getEncodedType(), Str);
// Get the length of the string.
uint64_t StrLen = Str.size();
if (cast<ConstantArrayType>(AT)->getSize().ult(StrLen))
StrLen = cast<ConstantArrayType>(AT)->getSize().getZExtValue();
StructuredList->resizeInits(Context, StrLen);
// Build a literal for each character in the string, and put them into
// the init list.
for (unsigned i = 0, e = StrLen; i != e; ++i) {
llvm::APInt CodeUnit(PromotedCharTyWidth, Str[i]);
Expr *Init = new (Context) IntegerLiteral(
Context, CodeUnit, PromotedCharTy, SubExpr->getExprLoc());
if (CharTy != PromotedCharTy)
Init = ImplicitCastExpr::Create(Context, CharTy, CK_IntegralCast,
Init, nullptr, VK_PRValue,
FPOptionsOverride());
StructuredList->updateInit(Context, i, Init);
}
}
}
// Make sure that our non-designated initializer list has space
// for a subobject corresponding to this array element.
if (StructuredList &&
DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits())
StructuredList->resizeInits(SemaRef.Context,
DesignatedEndIndex.getZExtValue() + 1);
// Repeatedly perform subobject initializations in the range
// [DesignatedStartIndex, DesignatedEndIndex].
// Move to the next designator
unsigned ElementIndex = DesignatedStartIndex.getZExtValue();
unsigned OldIndex = Index;
InitializedEntity ElementEntity =
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
while (DesignatedStartIndex <= DesignatedEndIndex) {
// Recurse to check later designated subobjects.
QualType ElementType = AT->getElementType();
Index = OldIndex;
ElementEntity.setElementIndex(ElementIndex);
if (CheckDesignatedInitializer(
ElementEntity, IList, DIE, DesigIdx + 1, ElementType, nullptr,
nullptr, Index, StructuredList, ElementIndex,
FinishSubobjectInit && (DesignatedStartIndex == DesignatedEndIndex),
false))
return true;
// Move to the next index in the array that we'll be initializing.
++DesignatedStartIndex;
ElementIndex = DesignatedStartIndex.getZExtValue();
}
// If this the first designator, our caller will continue checking
// the rest of this array subobject.
if (IsFirstDesignator) {
if (NextElementIndex)
*NextElementIndex = DesignatedStartIndex;
StructuredIndex = ElementIndex;
return false;
}
if (!FinishSubobjectInit)
return false;
// Check the remaining elements within this array subobject.
bool prevHadError = hadError;
CheckArrayType(Entity, IList, CurrentObjectType, DesignatedStartIndex,
/*SubobjectIsDesignatorContext=*/false, Index,
StructuredList, ElementIndex);
return hadError && !prevHadError;
}
// Get the structured initializer list for a subobject of type
// @p CurrentObjectType.
InitListExpr *
InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
QualType CurrentObjectType,
InitListExpr *StructuredList,
unsigned StructuredIndex,
SourceRange InitRange,
bool IsFullyOverwritten) {
if (!StructuredList)
return nullptr;
Expr *ExistingInit = nullptr;
if (StructuredIndex < StructuredList->getNumInits())
ExistingInit = StructuredList->getInit(StructuredIndex);
if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
// There might have already been initializers for subobjects of the current
// object, but a subsequent initializer list will overwrite the entirety
// of the current object. (See DR 253 and C99 6.7.8p21). e.g.,
//
// struct P { char x[6]; };
// struct P l = { .x[2] = 'x', .x = { [0] = 'f' } };
//
// The first designated initializer is ignored, and l.x is just "f".
if (!IsFullyOverwritten)
return Result;
if (ExistingInit) {
// We are creating an initializer list that initializes the
// subobjects of the current object, but there was already an
// initialization that completely initialized the current
// subobject:
//
// struct X { int a, b; };
// struct X xs[] = { [0] = { 1, 2 }, [0].b = 3 };
//
// Here, xs[0].a == 1 and xs[0].b == 3, since the second,
// designated initializer overwrites the [0].b initializer
// from the prior initialization.
//
// When the existing initializer is an expression rather than an
// initializer list, we cannot decompose and update it in this way.
// For example:
//
// struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
//
// This case is handled by CheckDesignatedInitializer.
diagnoseInitOverride(ExistingInit, InitRange);
}
unsigned ExpectedNumInits = 0;
if (Index < IList->getNumInits()) {
if (auto *Init = dyn_cast_or_null<InitListExpr>(IList->getInit(Index)))
ExpectedNumInits = Init->getNumInits();
else
ExpectedNumInits = IList->getNumInits() - Index;
}
InitListExpr *Result =
createInitListExpr(CurrentObjectType, InitRange, ExpectedNumInits);
// Link this new initializer list into the structured initializer
// lists.
StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result);
return Result;
}
InitListExpr *
InitListChecker::createInitListExpr(QualType CurrentObjectType,
SourceRange InitRange,
unsigned ExpectedNumInits) {
InitListExpr *Result
= new (SemaRef.Context) InitListExpr(SemaRef.Context,
InitRange.getBegin(), None,
InitRange.getEnd());
QualType ResultType = CurrentObjectType;
if (!ResultType->isArrayType())
ResultType = ResultType.getNonLValueExprType(SemaRef.Context);
Result->setType(ResultType);
// Pre-allocate storage for the structured initializer list.
unsigned NumElements = 0;
if (const ArrayType *AType
= SemaRef.Context.getAsArrayType(CurrentObjectType)) {
if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType)) {
NumElements = CAType->getSize().getZExtValue();
// Simple heuristic so that we don't allocate a very large
// initializer with many empty entries at the end.
if (NumElements > ExpectedNumInits)
NumElements = 0;
}
} else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>()) {
NumElements = VType->getNumElements();
} else if (CurrentObjectType->isRecordType()) {
NumElements = numStructUnionElements(CurrentObjectType);
}
Result->reserveInits(SemaRef.Context, NumElements);
return Result;
}
/// Update the initializer at index @p StructuredIndex within the
/// structured initializer list to the value @p expr.
void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
unsigned &StructuredIndex,
Expr *expr) {
// No structured initializer list to update
if (!StructuredList)
return;
if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context,
StructuredIndex, expr)) {
// This initializer overwrites a previous initializer.
// No need to diagnose when `expr` is nullptr because a more relevant
// diagnostic has already been issued and this diagnostic is potentially
// noise.
if (expr)
diagnoseInitOverride(PrevInit, expr->getSourceRange());
}
++StructuredIndex;
}
/// Determine whether we can perform aggregate initialization for the purposes
/// of overload resolution.
bool Sema::CanPerformAggregateInitializationForOverloadResolution(
const InitializedEntity &Entity, InitListExpr *From) {
QualType Type = Entity.getType();
InitListChecker Check(*this, Entity, From, Type, /*VerifyOnly=*/true,
/*TreatUnavailableAsInvalid=*/false,
/*InOverloadResolution=*/true);
return !Check.HadError();
}
/// Check that the given Index expression is a valid array designator
/// value. This is essentially just a wrapper around
/// VerifyIntegerConstantExpression that also checks for negative values
/// and produces a reasonable diagnostic if there is a
/// failure. Returns the index expression, possibly with an implicit cast
/// added, on success. If everything went okay, Value will receive the
/// value of the constant expression.
static ExprResult
CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) {
SourceLocation Loc = Index->getBeginLoc();
// Make sure this is an integer constant expression.
ExprResult Result =
S.VerifyIntegerConstantExpression(Index, &Value, Sema::AllowFold);
if (Result.isInvalid())
return Result;
if (Value.isSigned() && Value.isNegative())
return S.Diag(Loc, diag::err_array_designator_negative)
<< toString(Value, 10) << Index->getSourceRange();
Value.setIsUnsigned(true);
return Result;
}
ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
SourceLocation EqualOrColonLoc,
bool GNUSyntax,
ExprResult Init) {
typedef DesignatedInitExpr::Designator ASTDesignator;
bool Invalid = false;
SmallVector<ASTDesignator, 32> Designators;
SmallVector<Expr *, 32> InitExpressions;
// Build designators and check array designator expressions.
for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) {
const Designator &D = Desig.getDesignator(Idx);
switch (D.getKind()) {
case Designator::FieldDesignator:
Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(),
D.getFieldLoc()));
break;
case Designator::ArrayDesignator: {
Expr *Index = static_cast<Expr *>(D.getArrayIndex());
llvm::APSInt IndexValue;
if (!Index->isTypeDependent() && !Index->isValueDependent())
Index = CheckArrayDesignatorExpr(*this, Index, IndexValue).get();
if (!Index)
Invalid = true;
else {
Designators.push_back(ASTDesignator(InitExpressions.size(),
D.getLBracketLoc(),
D.getRBracketLoc()));
InitExpressions.push_back(Index);
}
break;
}
case Designator::ArrayRangeDesignator: {
Expr *StartIndex = static_cast<Expr *>(D.getArrayRangeStart());
Expr *EndIndex = static_cast<Expr *>(D.getArrayRangeEnd());
llvm::APSInt StartValue;
llvm::APSInt EndValue;
bool StartDependent = StartIndex->isTypeDependent() ||
StartIndex->isValueDependent();
bool EndDependent = EndIndex->isTypeDependent() ||
EndIndex->isValueDependent();
if (!StartDependent)
StartIndex =
CheckArrayDesignatorExpr(*this, StartIndex, StartValue).get();
if (!EndDependent)
EndIndex = CheckArrayDesignatorExpr(*this, EndIndex, EndValue).get();
if (!StartIndex || !EndIndex)
Invalid = true;
else {
// Make sure we're comparing values with the same bit width.
if (StartDependent || EndDependent) {
// Nothing to compute.
} else if (StartValue.getBitWidth() > EndValue.getBitWidth())
EndValue = EndValue.extend(StartValue.getBitWidth());
else if (StartValue.getBitWidth() < EndValue.getBitWidth())
StartValue = StartValue.extend(EndValue.getBitWidth());
if (!StartDependent && !EndDependent && EndValue < StartValue) {
Diag(D.getEllipsisLoc(), diag::err_array_designator_empty_range)
<< toString(StartValue, 10) << toString(EndValue, 10)
<< StartIndex->getSourceRange() << EndIndex->getSourceRange();
Invalid = true;
} else {
Designators.push_back(ASTDesignator(InitExpressions.size(),
D.getLBracketLoc(),
D.getEllipsisLoc(),
D.getRBracketLoc()));
InitExpressions.push_back(StartIndex);
InitExpressions.push_back(EndIndex);
}
}
break;
}
}
}
if (Invalid || Init.isInvalid())
return ExprError();
// Clear out the expressions within the designation.
Desig.ClearExprs(*this);
return DesignatedInitExpr::Create(Context, Designators, InitExpressions,
EqualOrColonLoc, GNUSyntax,
Init.getAs<Expr>());
}
//===----------------------------------------------------------------------===//
// Initialization entity
//===----------------------------------------------------------------------===//
InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index,
const InitializedEntity &Parent)
: Parent(&Parent), Index(Index)
{
if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) {
Kind = EK_ArrayElement;
Type = AT->getElementType();
} else if (const VectorType *VT = Parent.getType()->getAs<VectorType>()) {
Kind = EK_VectorElement;
Type = VT->getElementType();
} else {
const ComplexType *CT = Parent.getType()->getAs<ComplexType>();
assert(CT && "Unexpected type");
Kind = EK_ComplexElement;
Type = CT->getElementType();
}
}
InitializedEntity
InitializedEntity::InitializeBase(ASTContext &Context,
const CXXBaseSpecifier *Base,
bool IsInheritedVirtualBase,
const InitializedEntity *Parent) {
InitializedEntity Result;
Result.Kind = EK_Base;
Result.Parent = Parent;
Result.Base = {Base, IsInheritedVirtualBase};
Result.Type = Base->getType();
return Result;
}
DeclarationName InitializedEntity::getName() const {
switch (getKind()) {
case EK_Parameter:
case EK_Parameter_CF_Audited: {
ParmVarDecl *D = Parameter.getPointer();
return (D ? D->getDeclName() : DeclarationName());
}
case EK_Variable:
case EK_Member:
case EK_Binding:
case EK_TemplateParameter:
return Variable.VariableOrMember->getDeclName();
case EK_LambdaCapture:
return DeclarationName(Capture.VarID);
case EK_Result:
case EK_StmtExprResult:
case EK_Exception:
case EK_New:
case EK_Temporary:
case EK_Base:
case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
case EK_ComplexElement:
case EK_BlockElement:
case EK_LambdaToBlockConversionBlockElement:
case EK_CompoundLiteralInit:
case EK_RelatedResult:
return DeclarationName();
}
llvm_unreachable("Invalid EntityKind!");
}
ValueDecl *InitializedEntity::getDecl() const {
switch (getKind()) {
case EK_Variable:
case EK_Member:
case EK_Binding:
case EK_TemplateParameter:
return Variable.VariableOrMember;
case EK_Parameter:
case EK_Parameter_CF_Audited:
return Parameter.getPointer();
case EK_Result:
case EK_StmtExprResult:
case EK_Exception:
case EK_New:
case EK_Temporary:
case EK_Base:
case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
case EK_ComplexElement:
case EK_BlockElement:
case EK_LambdaToBlockConversionBlockElement:
case EK_LambdaCapture:
case EK_CompoundLiteralInit:
case EK_RelatedResult:
return nullptr;
}
llvm_unreachable("Invalid EntityKind!");
}
bool InitializedEntity::allowsNRVO() const {
switch (getKind()) {
case EK_Result:
case EK_Exception:
return LocAndNRVO.NRVO;
case EK_StmtExprResult:
case EK_Variable:
case EK_Parameter:
case EK_Parameter_CF_Audited:
case EK_TemplateParameter:
case EK_Member:
case EK_Binding:
case EK_New:
case EK_Temporary:
case EK_CompoundLiteralInit:
case EK_Base:
case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
case EK_ComplexElement:
case EK_BlockElement:
case EK_LambdaToBlockConversionBlockElement:
case EK_LambdaCapture:
case EK_RelatedResult:
break;
}
return false;
}
unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
assert(getParent() != this);
unsigned Depth = getParent() ? getParent()->dumpImpl(OS) : 0;
for (unsigned I = 0; I != Depth; ++I)
OS << "`-";
switch (getKind()) {
case EK_Variable: OS << "Variable"; break;
case EK_Parameter: OS << "Parameter"; break;
case EK_Parameter_CF_Audited: OS << "CF audited function Parameter";
break;
case EK_TemplateParameter: OS << "TemplateParameter"; break;
case EK_Result: OS << "Result"; break;
case EK_StmtExprResult: OS << "StmtExprResult"; break;
case EK_Exception: OS << "Exception"; break;
case EK_Member: OS << "Member"; break;
case EK_Binding: OS << "Binding"; break;
case EK_New: OS << "New"; break;
case EK_Temporary: OS << "Temporary"; break;
case EK_CompoundLiteralInit: OS << "CompoundLiteral";break;
case EK_RelatedResult: OS << "RelatedResult"; break;
case EK_Base: OS << "Base"; break;
case EK_Delegating: OS << "Delegating"; break;
case EK_ArrayElement: OS << "ArrayElement " << Index; break;
case EK_VectorElement: OS << "VectorElement " << Index; break;
case EK_ComplexElement: OS << "ComplexElement " << Index; break;
case EK_BlockElement: OS << "Block"; break;
case EK_LambdaToBlockConversionBlockElement:
OS << "Block (lambda)";
break;
case EK_LambdaCapture:
OS << "LambdaCapture ";
OS << DeclarationName(Capture.VarID);
break;
}
if (auto *D = getDecl()) {
OS << " ";
D->printQualifiedName(OS);
}
OS << " '" << getType() << "'\n";
return Depth + 1;
}
LLVM_DUMP_METHOD void InitializedEntity::dump() const {
dumpImpl(llvm::errs());
}
//===----------------------------------------------------------------------===//
// Initialization sequence
//===----------------------------------------------------------------------===//
void InitializationSequence::Step::Destroy() {
switch (Kind) {
case SK_ResolveAddressOfOverloadedFunction:
case SK_CastDerivedToBasePRValue:
case SK_CastDerivedToBaseXValue:
case SK_CastDerivedToBaseLValue:
case SK_BindReference:
case SK_BindReferenceToTemporary:
case SK_FinalCopy:
case SK_ExtraneousCopyToTemporary:
case SK_UserConversion:
case SK_QualificationConversionPRValue:
case SK_QualificationConversionXValue:
case SK_QualificationConversionLValue:
case SK_FunctionReferenceConversion:
case SK_AtomicConversion:
case SK_ListInitialization:
case SK_UnwrapInitList:
case SK_RewrapInitList:
case SK_ConstructorInitialization:
case SK_ConstructorInitializationFromList:
case SK_ZeroInitialization:
case SK_CAssignment:
case SK_StringInit:
case SK_ObjCObjectConversion:
case SK_ArrayLoopIndex:
case SK_ArrayLoopInit:
case SK_ArrayInit:
case SK_GNUArrayInit:
case SK_ParenthesizedArrayInit:
case SK_PassByIndirectCopyRestore:
case SK_PassByIndirectRestore:
case SK_ProduceObjCObject:
case SK_StdInitializerList:
case SK_StdInitializerListConstructorCall:
case SK_OCLSamplerInit:
case SK_OCLZeroOpaqueType:
break;
case SK_ConversionSequence:
case SK_ConversionSequenceNoNarrowing:
delete ICS;
}
}
bool InitializationSequence::isDirectReferenceBinding() const {
// There can be some lvalue adjustments after the SK_BindReference step.
for (const Step &S : llvm::reverse(Steps)) {
if (S.Kind == SK_BindReference)
return true;
if (S.Kind == SK_BindReferenceToTemporary)
return false;
}
return false;
}
bool InitializationSequence::isAmbiguous() const {
if (!Failed())
return false;
switch (getFailureKind()) {
case FK_TooManyInitsForReference:
case FK_ParenthesizedListInitForReference:
case FK_ArrayNeedsInitList:
case FK_ArrayNeedsInitListOrStringLiteral:
case FK_ArrayNeedsInitListOrWideStringLiteral:
case FK_NarrowStringIntoWideCharArray:
case FK_WideStringIntoCharArray:
case FK_IncompatWideStringIntoWideChar:
case FK_PlainStringIntoUTF8Char:
case FK_UTF8StringIntoPlainChar:
case FK_AddressOfOverloadFailed: // FIXME: Could do better
case FK_NonConstLValueReferenceBindingToTemporary:
case FK_NonConstLValueReferenceBindingToBitfield:
case FK_NonConstLValueReferenceBindingToVectorElement:
case FK_NonConstLValueReferenceBindingToMatrixElement:
case FK_NonConstLValueReferenceBindingToUnrelated:
case FK_RValueReferenceBindingToLValue:
case FK_ReferenceAddrspaceMismatchTemporary:
case FK_ReferenceInitDropsQualifiers:
case FK_ReferenceInitFailed:
case FK_ConversionFailed:
case FK_ConversionFromPropertyFailed:
case FK_TooManyInitsForScalar:
case FK_ParenthesizedListInitForScalar:
case FK_ReferenceBindingToInitList:
case FK_InitListBadDestinationType:
case FK_DefaultInitOfConst:
case FK_Incomplete:
case FK_ArrayTypeMismatch:
case FK_NonConstantArrayInit:
case FK_ListInitializationFailed:
case FK_VariableLengthArrayHasInitializer:
case FK_PlaceholderType:
case FK_ExplicitConstructor:
case FK_AddressOfUnaddressableFunction:
return false;
case FK_ReferenceInitOverloadFailed:
case FK_UserConversionOverloadFailed:
case FK_ConstructorOverloadFailed:
case FK_ListConstructorOverloadFailed:
return FailedOverloadResult == OR_Ambiguous;
}
llvm_unreachable("Invalid EntityKind!");
}
bool InitializationSequence::isConstructorInitialization() const {
return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization;
}
void
InitializationSequence
::AddAddressOverloadResolutionStep(FunctionDecl *Function,
DeclAccessPair Found,
bool HadMultipleCandidates) {
Step S;
S.Kind = SK_ResolveAddressOfOverloadedFunction;
S.Type = Function->getType();
S.Function.HadMultipleCandidates = HadMultipleCandidates;
S.Function.Function = Function;
S.Function.FoundDecl = Found;
Steps.push_back(S);
}
void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType,
ExprValueKind VK) {
Step S;
switch (VK) {
case VK_PRValue:
S.Kind = SK_CastDerivedToBasePRValue;
break;
case VK_XValue: S.Kind = SK_CastDerivedToBaseXValue; break;
case VK_LValue: S.Kind = SK_CastDerivedToBaseLValue; break;
}
S.Type = BaseType;
Steps.push_back(S);
}
void InitializationSequence::AddReferenceBindingStep(QualType T,
bool BindingTemporary) {
Step S;
S.Kind = BindingTemporary? SK_BindReferenceToTemporary : SK_BindReference;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddFinalCopy(QualType T) {
Step S;
S.Kind = SK_FinalCopy;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddExtraneousCopyToTemporary(QualType T) {
Step S;
S.Kind = SK_ExtraneousCopyToTemporary;
S.Type = T;
Steps.push_back(S);
}
void
InitializationSequence::AddUserConversionStep(FunctionDecl *Function,
DeclAccessPair FoundDecl,
QualType T,
bool HadMultipleCandidates) {
Step S;
S.Kind = SK_UserConversion;
S.Type = T;
S.Function.HadMultipleCandidates = HadMultipleCandidates;
S.Function.Function = Function;
S.Function.FoundDecl = FoundDecl;
Steps.push_back(S);
}
void InitializationSequence::AddQualificationConversionStep(QualType Ty,
ExprValueKind VK) {
Step S;
S.Kind = SK_QualificationConversionPRValue; // work around a gcc warning
switch (VK) {
case VK_PRValue:
S.Kind = SK_QualificationConversionPRValue;
break;
case VK_XValue:
S.Kind = SK_QualificationConversionXValue;
break;
case VK_LValue:
S.Kind = SK_QualificationConversionLValue;
break;
}
S.Type = Ty;
Steps.push_back(S);
}
void InitializationSequence::AddFunctionReferenceConversionStep(QualType Ty) {
Step S;
S.Kind = SK_FunctionReferenceConversion;
S.Type = Ty;
Steps.push_back(S);
}
void InitializationSequence::AddAtomicConversionStep(QualType Ty) {
Step S;
S.Kind = SK_AtomicConversion;
S.Type = Ty;
Steps.push_back(S);
}
void InitializationSequence::AddConversionSequenceStep(
const ImplicitConversionSequence &ICS, QualType T,
bool TopLevelOfInitList) {
Step S;
S.Kind = TopLevelOfInitList ? SK_ConversionSequenceNoNarrowing
: SK_ConversionSequence;
S.Type = T;
S.ICS = new ImplicitConversionSequence(ICS);
Steps.push_back(S);
}
void InitializationSequence::AddListInitializationStep(QualType T) {
Step S;
S.Kind = SK_ListInitialization;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddConstructorInitializationStep(
DeclAccessPair FoundDecl, CXXConstructorDecl *Constructor, QualType T,
bool HadMultipleCandidates, bool FromInitList, bool AsInitList) {
Step S;
S.Kind = FromInitList ? AsInitList ? SK_StdInitializerListConstructorCall
: SK_ConstructorInitializationFromList
: SK_ConstructorInitialization;
S.Type = T;
S.Function.HadMultipleCandidates = HadMultipleCandidates;
S.Function.Function = Constructor;
S.Function.FoundDecl = FoundDecl;
Steps.push_back(S);
}
void InitializationSequence::AddZeroInitializationStep(QualType T) {
Step S;
S.Kind = SK_ZeroInitialization;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddCAssignmentStep(QualType T) {
Step S;
S.Kind = SK_CAssignment;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddStringInitStep(QualType T) {
Step S;
S.Kind = SK_StringInit;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddObjCObjectConversionStep(QualType T) {
Step S;
S.Kind = SK_ObjCObjectConversion;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddArrayInitStep(QualType T, bool IsGNUExtension) {
Step S;
S.Kind = IsGNUExtension ? SK_GNUArrayInit : SK_ArrayInit;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddArrayInitLoopStep(QualType T, QualType EltT) {
Step S;
S.Kind = SK_ArrayLoopIndex;
S.Type = EltT;
Steps.insert(Steps.begin(), S);
S.Kind = SK_ArrayLoopInit;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddParenthesizedArrayInitStep(QualType T) {
Step S;
S.Kind = SK_ParenthesizedArrayInit;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddPassByIndirectCopyRestoreStep(QualType type,
bool shouldCopy) {
Step s;
s.Kind = (shouldCopy ? SK_PassByIndirectCopyRestore
: SK_PassByIndirectRestore);
s.Type = type;
Steps.push_back(s);
}
void InitializationSequence::AddProduceObjCObjectStep(QualType T) {
Step S;
S.Kind = SK_ProduceObjCObject;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddStdInitializerListConstructionStep(QualType T) {
Step S;
S.Kind = SK_StdInitializerList;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddOCLSamplerInitStep(QualType T) {
Step S;
S.Kind = SK_OCLSamplerInit;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::AddOCLZeroOpaqueTypeStep(QualType T) {
Step S;
S.Kind = SK_OCLZeroOpaqueType;
S.Type = T;
Steps.push_back(S);
}
void InitializationSequence::RewrapReferenceInitList(QualType T,
InitListExpr *Syntactic) {
assert(Syntactic->getNumInits() == 1 &&
"Can only rewrap trivial init lists.");
Step S;
S.Kind = SK_UnwrapInitList;
S.Type = Syntactic->getInit(0)->getType();
Steps.insert(Steps.begin(), S);
S.Kind = SK_RewrapInitList;
S.Type = T;
S.WrappingSyntacticList = Syntactic;
Steps.push_back(S);
}
void InitializationSequence::SetOverloadFailure(FailureKind Failure,
OverloadingResult Result) {
setSequenceKind(FailedSequence);
this->Failure = Failure;
this->FailedOverloadResult = Result;
}
//===----------------------------------------------------------------------===//
// Attempt initialization
//===----------------------------------------------------------------------===//
/// Tries to add a zero initializer. Returns true if that worked.
static bool
maybeRecoverWithZeroInitialization(Sema &S, InitializationSequence &Sequence,
const InitializedEntity &Entity) {
if (Entity.getKind() != InitializedEntity::EK_Variable)
return false;
VarDecl *VD = cast<VarDecl>(Entity.getDecl());
if (VD->getInit() || VD->getEndLoc().isMacroID())
return false;
QualType VariableTy = VD->getType().getCanonicalType();
SourceLocation Loc = S.getLocForEndOfToken(VD->getEndLoc());
std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc);
if (!Init.empty()) {
Sequence.AddZeroInitializationStep(Entity.getType());
Sequence.SetZeroInitializationFixit(Init, Loc);
return true;
}
return false;
}
static void MaybeProduceObjCObject(Sema &S,
InitializationSequence &Sequence,
const InitializedEntity &Entity) {
if (!S.getLangOpts().ObjCAutoRefCount) return;
/// When initializing a parameter, produce the value if it's marked
/// __attribute__((ns_consumed)).
if (Entity.isParameterKind()) {
if (!Entity.isParameterConsumed())
return;
assert(Entity.getType()->isObjCRetainableType() &&
"consuming an object of unretainable type?");
Sequence.AddProduceObjCObjectStep(Entity.getType());
/// When initializing a return value, if the return type is a
/// retainable type, then returns need to immediately retain the
/// object. If an autorelease is required, it will be done at the
/// last instant.
} else if (Entity.getKind() == InitializedEntity::EK_Result ||
Entity.getKind() == InitializedEntity::EK_StmtExprResult) {
if (!Entity.getType()->isObjCRetainableType())
return;
Sequence.AddProduceObjCObjectStep(Entity.getType());
}
}
static void TryListInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
InitListExpr *InitList,
InitializationSequence &Sequence,
bool TreatUnavailableAsInvalid);
/// When initializing from init list via constructor, handle
/// initialization of an object of type std::initializer_list<T>.
///
/// \return true if we have handled initialization of an object of type
/// std::initializer_list<T>, false otherwise.
static bool TryInitializerListConstruction(Sema &S,
InitListExpr *List,
QualType DestType,
InitializationSequence &Sequence,
bool TreatUnavailableAsInvalid) {
QualType E;
if (!S.isStdInitializerList(DestType, &E))
return false;
if (!S.isCompleteType(List->getExprLoc(), E)) {
Sequence.setIncompleteTypeFailure(E);
return true;
}
// Try initializing a temporary array from the init list.
QualType ArrayType = S.Context.getConstantArrayType(
E.withConst(),
llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
List->getNumInits()),
nullptr, clang::ArrayType::Normal, 0);
InitializedEntity HiddenArray =
InitializedEntity::InitializeTemporary(ArrayType);
InitializationKind Kind = InitializationKind::CreateDirectList(
List->getExprLoc(), List->getBeginLoc(), List->getEndLoc());
TryListInitialization(S, HiddenArray, Kind, List, Sequence,
TreatUnavailableAsInvalid);
if (Sequence)
Sequence.AddStdInitializerListConstructionStep(DestType);
return true;
}
/// Determine if the constructor has the signature of a copy or move
/// constructor for the type T of the class in which it was found. That is,
/// determine if its first parameter is of type T or reference to (possibly
/// cv-qualified) T.
static bool hasCopyOrMoveCtorParam(ASTContext &Ctx,
const ConstructorInfo &Info) {
if (Info.Constructor->getNumParams() == 0)
return false;
QualType ParmT =
Info.Constructor->getParamDecl(0)->getType().getNonReferenceType();
QualType ClassT =
Ctx.getRecordType(cast<CXXRecordDecl>(Info.FoundDecl->getDeclContext()));
return Ctx.hasSameUnqualifiedType(ParmT, ClassT);
}
static OverloadingResult
ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
MultiExprArg Args,
OverloadCandidateSet &CandidateSet,
QualType DestType,
DeclContext::lookup_result Ctors,
OverloadCandidateSet::iterator &Best,
bool CopyInitializing, bool AllowExplicit,
bool OnlyListConstructors, bool IsListInit,
bool SecondStepOfCopyInit = false) {
CandidateSet.clear(OverloadCandidateSet::CSK_InitByConstructor);
CandidateSet.setDestAS(DestType.getQualifiers().getAddressSpace());
for (NamedDecl *D : Ctors) {
auto Info = getConstructorInfo(D);
if (!Info.Constructor || Info.Constructor->isInvalidDecl())
continue;
if (OnlyListConstructors && !S.isInitListConstructor(Info.Constructor))
continue;
// C++11 [over.best.ics]p4:
// ... and the constructor or user-defined conversion function is a
// candidate by
// - 13.3.1.3, when the argument is the temporary in the second step
// of a class copy-initialization, or
// - 13.3.1.4, 13.3.1.5, or 13.3.1.6 (in all cases), [not handled here]
// - the second phase of 13.3.1.7 when the initializer list has exactly
// one element that is itself an initializer list, and the target is
// the first parameter of a constructor of class X, and the conversion
// is to X or reference to (possibly cv-qualified X),
// user-defined conversion sequences are not considered.
bool SuppressUserConversions =
SecondStepOfCopyInit ||
(IsListInit && Args.size() == 1 && isa<InitListExpr>(Args[0]) &&
hasCopyOrMoveCtorParam(S.Context, Info));
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr, Args, CandidateSet, SuppressUserConversions,
/*PartialOverloading=*/false, AllowExplicit);
else {
// C++ [over.match.copy]p1:
// - When initializing a temporary to be bound to the first parameter
// of a constructor [for type T] that takes a reference to possibly
// cv-qualified T as its first argument, called with a single
// argument in the context of direct-initialization, explicit
// conversion functions are also considered.
// FIXME: What if a constructor template instantiates to such a signature?
bool AllowExplicitConv = AllowExplicit && !CopyInitializing &&
Args.size() == 1 &&
hasCopyOrMoveCtorParam(S.Context, Info);
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args,
CandidateSet, SuppressUserConversions,
/*PartialOverloading=*/false, AllowExplicit,
AllowExplicitConv);
}
}
// FIXME: Work around a bug in C++17 guaranteed copy elision.
//
// When initializing an object of class type T by constructor
// ([over.match.ctor]) or by list-initialization ([over.match.list])
// from a single expression of class type U, conversion functions of
// U that convert to the non-reference type cv T are candidates.
// Explicit conversion functions are only candidates during
// direct-initialization.
//
// Note: SecondStepOfCopyInit is only ever true in this case when
// evaluating whether to produce a C++98 compatibility warning.
if (S.getLangOpts().CPlusPlus17 && Args.size() == 1 &&
!SecondStepOfCopyInit) {
Expr *Initializer = Args[0];
auto *SourceRD = Initializer->getType()->getAsCXXRecordDecl();
if (SourceRD && S.isCompleteType(DeclLoc, Initializer->getType())) {
const auto &Conversions = SourceRD->getVisibleConversionFunctions();
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
D = D->getUnderlyingDecl();
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
CXXConversionDecl *Conv;
if (ConvTemplate)
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
Conv = cast<CXXConversionDecl>(D);
if (ConvTemplate)
S.AddTemplateConversionCandidate(
ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
CandidateSet, AllowExplicit, AllowExplicit,
/*AllowResultConversion*/ false);
else
S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
DestType, CandidateSet, AllowExplicit,
AllowExplicit,
/*AllowResultConversion*/ false);
}
}
}
// Perform overload resolution and return the result.
return CandidateSet.BestViableFunction(S, DeclLoc, Best);
}
/// Attempt initialization by constructor (C++ [dcl.init]), which
/// enumerates the constructors of the initialized entity and performs overload
/// resolution to select the best.
/// \param DestType The destination class type.
/// \param DestArrayType The destination type, which is either DestType or
/// a (possibly multidimensional) array of DestType.
/// \param IsListInit Is this list-initialization?
/// \param IsInitListCopy Is this non-list-initialization resulting from a
/// list-initialization from {x} where x is the same
/// type as the entity?
static void TryConstructorInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
MultiExprArg Args, QualType DestType,
QualType DestArrayType,
InitializationSequence &Sequence,
bool IsListInit = false,
bool IsInitListCopy = false) {
assert(((!IsListInit && !IsInitListCopy) ||
(Args.size() == 1 && isa<InitListExpr>(Args[0]))) &&
"IsListInit/IsInitListCopy must come with a single initializer list "
"argument.");
InitListExpr *ILE =
(IsListInit || IsInitListCopy) ? cast<InitListExpr>(Args[0]) : nullptr;
MultiExprArg UnwrappedArgs =
ILE ? MultiExprArg(ILE->getInits(), ILE->getNumInits()) : Args;
// The type we're constructing needs to be complete.
if (!S.isCompleteType(Kind.getLocation(), DestType)) {
Sequence.setIncompleteTypeFailure(DestType);
return;
}
// C++17 [dcl.init]p17:
// - If the initializer expression is a prvalue and the cv-unqualified
// version of the source type is the same class as the class of the
// destination, the initializer expression is used to initialize the
// destination object.
// Per DR (no number yet), this does not apply when initializing a base
// class or delegating to another constructor from a mem-initializer.
// ObjC++: Lambda captured by the block in the lambda to block conversion
// should avoid copy elision.
if (S.getLangOpts().CPlusPlus17 &&
Entity.getKind() != InitializedEntity::EK_Base &&
Entity.getKind() != InitializedEntity::EK_Delegating &&
Entity.getKind() !=
InitializedEntity::EK_LambdaToBlockConversionBlockElement &&
UnwrappedArgs.size() == 1 && UnwrappedArgs[0]->isPRValue() &&
S.Context.hasSameUnqualifiedType(UnwrappedArgs[0]->getType(), DestType)) {
// Convert qualifications if necessary.
Sequence.AddQualificationConversionStep(DestType, VK_PRValue);
if (ILE)
Sequence.RewrapReferenceInitList(DestType, ILE);
return;
}
const RecordType *DestRecordType = DestType->getAs<RecordType>();
assert(DestRecordType && "Constructor initialization requires record type");
CXXRecordDecl *DestRecordDecl
= cast<CXXRecordDecl>(DestRecordType->getDecl());
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
bool AllowExplicit = Kind.AllowExplicit() || IsListInit;
bool CopyInitialization = Kind.getKind() == InitializationKind::IK_Copy;
// - Otherwise, if T is a class type, constructors are considered. The
// applicable constructors are enumerated, and the best one is chosen
// through overload resolution.
DeclContext::lookup_result Ctors = S.LookupConstructors(DestRecordDecl);
OverloadingResult Result = OR_No_Viable_Function;
OverloadCandidateSet::iterator Best;
bool AsInitializerList = false;
// C++11 [over.match.list]p1, per DR1467:
// When objects of non-aggregate type T are list-initialized, such that
// 8.5.4 [dcl.init.list] specifies that overload resolution is performed
// according to the rules in this section, overload resolution selects
// the constructor in two phases:
//
// - Initially, the candidate functions are the initializer-list
// constructors of the class T and the argument list consists of the
// initializer list as a single argument.
if (IsListInit) {
AsInitializerList = true;
// If the initializer list has no elements and T has a default constructor,
// the first phase is omitted.
if (!(UnwrappedArgs.empty() && S.LookupDefaultConstructor(DestRecordDecl)))
Result = ResolveConstructorOverload(S, Kind.getLocation(), Args,
CandidateSet, DestType, Ctors, Best,
CopyInitialization, AllowExplicit,
/*OnlyListConstructors=*/true,
IsListInit);
}
// C++11 [over.match.list]p1:
// - If no viable initializer-list constructor is found, overload resolution
// is performed again, where the candidate functions are all the
// constructors of the class T and the argument list consists of the
// elements of the initializer list.
if (Result == OR_No_Viable_Function) {
AsInitializerList = false;
Result = ResolveConstructorOverload(S, Kind.getLocation(), UnwrappedArgs,
CandidateSet, DestType, Ctors, Best,
CopyInitialization, AllowExplicit,
/*OnlyListConstructors=*/false,
IsListInit);
}
if (Result) {
Sequence.SetOverloadFailure(
IsListInit ? InitializationSequence::FK_ListConstructorOverloadFailed
: InitializationSequence::FK_ConstructorOverloadFailed,
Result);
if (Result != OR_Deleted)
return;
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
// In C++17, ResolveConstructorOverload can select a conversion function
// instead of a constructor.
if (auto *CD = dyn_cast<CXXConversionDecl>(Best->Function)) {
// Add the user-defined conversion step that calls the conversion function.
QualType ConvType = CD->getConversionType();
assert(S.Context.hasSameUnqualifiedType(ConvType, DestType) &&
"should not have selected this conversion function");
Sequence.AddUserConversionStep(CD, Best->FoundDecl, ConvType,
HadMultipleCandidates);
if (!S.Context.hasSameType(ConvType, DestType))
Sequence.AddQualificationConversionStep(DestType, VK_PRValue);
if (IsListInit)
Sequence.RewrapReferenceInitList(Entity.getType(), ILE);
return;
}
CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
if (Result != OR_Deleted) {
// C++11 [dcl.init]p6:
// If a program calls for the default initialization of an object
// of a const-qualified type T, T shall be a class type with a
// user-provided default constructor.
// C++ core issue 253 proposal:
// If the implicit default constructor initializes all subobjects, no
// initializer should be required.
// The 253 proposal is for example needed to process libstdc++ headers
// in 5.x.
if (Kind.getKind() == InitializationKind::IK_Default &&
Entity.getType().isConstQualified()) {
if (!CtorDecl->getParent()->allowConstDefaultInit()) {
if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity))
Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
return;
}
}
// C++11 [over.match.list]p1:
// In copy-list-initialization, if an explicit constructor is chosen, the
// initializer is ill-formed.
if (IsListInit && !Kind.AllowExplicit() && CtorDecl->isExplicit()) {
Sequence.SetFailed(InitializationSequence::FK_ExplicitConstructor);
return;
}
}
// [class.copy.elision]p3:
// In some copy-initialization contexts, a two-stage overload resolution
// is performed.
// If the first overload resolution selects a deleted function, we also
// need the initialization sequence to decide whether to perform the second
// overload resolution.
// For deleted functions in other contexts, there is no need to get the
// initialization sequence.
if (Result == OR_Deleted && Kind.getKind() != InitializationKind::IK_Copy)
return;
// Add the constructor initialization step. Any cv-qualification conversion is
// subsumed by the initialization.
Sequence.AddConstructorInitializationStep(
Best->FoundDecl, CtorDecl, DestArrayType, HadMultipleCandidates,
IsListInit | IsInitListCopy, AsInitializerList);
}
static bool
ResolveOverloadedFunctionForReferenceBinding(Sema &S,
Expr *Initializer,
QualType &SourceType,
QualType &UnqualifiedSourceType,
QualType UnqualifiedTargetType,
InitializationSequence &Sequence) {
if (S.Context.getCanonicalType(UnqualifiedSourceType) ==
S.Context.OverloadTy) {
DeclAccessPair Found;
bool HadMultipleCandidates = false;
if (FunctionDecl *Fn
= S.ResolveAddressOfOverloadedFunction(Initializer,
UnqualifiedTargetType,
false, Found,
&HadMultipleCandidates)) {
Sequence.AddAddressOverloadResolutionStep(Fn, Found,
HadMultipleCandidates);
SourceType = Fn->getType();
UnqualifiedSourceType = SourceType.getUnqualifiedType();
} else if (!UnqualifiedTargetType->isRecordType()) {
Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
return true;
}
}
return false;
}
static void TryReferenceInitializationCore(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Expr *Initializer,
QualType cv1T1, QualType T1,
Qualifiers T1Quals,
QualType cv2T2, QualType T2,
Qualifiers T2Quals,
InitializationSequence &Sequence);
static void TryValueInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
InitializationSequence &Sequence,
InitListExpr *InitList = nullptr);
/// Attempt list initialization of a reference.
static void TryReferenceListInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
InitListExpr *InitList,
InitializationSequence &Sequence,
bool TreatUnavailableAsInvalid) {
// First, catch C++03 where this isn't possible.
if (!S.getLangOpts().CPlusPlus11) {
Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
return;
}
// Can't reference initialize a compound literal.
if (Entity.getKind() == InitializedEntity::EK_CompoundLiteralInit) {
Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
return;
}
QualType DestType = Entity.getType();
QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
// Reference initialization via an initializer list works thus:
// If the initializer list consists of a single element that is
// reference-related to the referenced type, bind directly to that element
// (possibly creating temporaries).
// Otherwise, initialize a temporary with the initializer list and
// bind to that.
if (InitList->getNumInits() == 1) {
Expr *Initializer = InitList->getInit(0);
QualType cv2T2 = S.getCompletedType(Initializer);
Qualifiers T2Quals;
QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals);
// If this fails, creating a temporary wouldn't work either.
if (ResolveOverloadedFunctionForReferenceBinding(S, Initializer, cv2T2, T2,
T1, Sequence))
return;
SourceLocation DeclLoc = Initializer->getBeginLoc();
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2);
if (RefRelationship >= Sema::Ref_Related) {
// Try to bind the reference here.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
T1Quals, cv2T2, T2, T2Quals, Sequence);
if (Sequence)
Sequence.RewrapReferenceInitList(cv1T1, InitList);
return;
}
// Update the initializer if we've resolved an overloaded function.
if (Sequence.step_begin() != Sequence.step_end())
Sequence.RewrapReferenceInitList(cv1T1, InitList);
}
// Perform address space compatibility check.
QualType cv1T1IgnoreAS = cv1T1;
if (T1Quals.hasAddressSpace()) {
Qualifiers T2Quals;
(void)S.Context.getUnqualifiedArrayType(InitList->getType(), T2Quals);
if (!T1Quals.isAddressSpaceSupersetOf(T2Quals)) {
Sequence.SetFailed(
InitializationSequence::FK_ReferenceInitDropsQualifiers);
return;
}
// Ignore address space of reference type at this point and perform address
// space conversion after the reference binding step.
cv1T1IgnoreAS =
S.Context.getQualifiedType(T1, T1Quals.withoutAddressSpace());
}
// Not reference-related. Create a temporary and bind to that.
InitializedEntity TempEntity =
InitializedEntity::InitializeTemporary(cv1T1IgnoreAS);
TryListInitialization(S, TempEntity, Kind, InitList, Sequence,
TreatUnavailableAsInvalid);
if (Sequence) {
if (DestType->isRValueReferenceType() ||
(T1Quals.hasConst() && !T1Quals.hasVolatile())) {
Sequence.AddReferenceBindingStep(cv1T1IgnoreAS,
/*BindingTemporary=*/true);
if (T1Quals.hasAddressSpace())
Sequence.AddQualificationConversionStep(
cv1T1, DestType->isRValueReferenceType() ? VK_XValue : VK_LValue);
} else
Sequence.SetFailed(
InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
}
}
/// Attempt list initialization (C++0x [dcl.init.list])
static void TryListInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
InitListExpr *InitList,
InitializationSequence &Sequence,
bool TreatUnavailableAsInvalid) {
QualType DestType = Entity.getType();
// C++ doesn't allow scalar initialization with more than one argument.
// But C99 complex numbers are scalars and it makes sense there.
if (S.getLangOpts().CPlusPlus && DestType->isScalarType() &&
!DestType->isAnyComplexType() && InitList->getNumInits() > 1) {
Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar);
return;
}
if (DestType->isReferenceType()) {
TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence,
TreatUnavailableAsInvalid);
return;
}
if (DestType->isRecordType() &&
!S.isCompleteType(InitList->getBeginLoc(), DestType)) {
Sequence.setIncompleteTypeFailure(DestType);
return;
}
// C++11 [dcl.init.list]p3, per DR1467:
// - If T is a class type and the initializer list has a single element of
// type cv U, where U is T or a class derived from T, the object is
// initialized from that element (by copy-initialization for
// copy-list-initialization, or by direct-initialization for
// direct-list-initialization).
// - Otherwise, if T is a character array and the initializer list has a
// single element that is an appropriately-typed string literal
// (8.5.2 [dcl.init.string]), initialization is performed as described
// in that section.
// - Otherwise, if T is an aggregate, [...] (continue below).
if (S.getLangOpts().CPlusPlus11 && InitList->getNumInits() == 1) {
if (DestType->isRecordType()) {
QualType InitType = InitList->getInit(0)->getType();
if (S.Context.hasSameUnqualifiedType(InitType, DestType) ||
S.IsDerivedFrom(InitList->getBeginLoc(), InitType, DestType)) {
Expr *InitListAsExpr = InitList;
TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType,
DestType, Sequence,
/*InitListSyntax*/false,
/*IsInitListCopy*/true);
return;
}
}
if (const ArrayType *DestAT = S.Context.getAsArrayType(DestType)) {
Expr *SubInit[1] = {InitList->getInit(0)};
if (!isa<VariableArrayType>(DestAT) &&
IsStringInit(SubInit[0], DestAT, S.Context) == SIF_None) {
InitializationKind SubKind =
Kind.getKind() == InitializationKind::IK_DirectList
? InitializationKind::CreateDirect(Kind.getLocation(),
InitList->getLBraceLoc(),
InitList->getRBraceLoc())
: Kind;
Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
/*TopLevelOfInitList*/ true,
TreatUnavailableAsInvalid);
// TryStringLiteralInitialization() (in InitializeFrom()) will fail if
// the element is not an appropriately-typed string literal, in which
// case we should proceed as in C++11 (below).
if (Sequence) {
Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
return;
}
}
}
}
// C++11 [dcl.init.list]p3:
// - If T is an aggregate, aggregate initialization is performed.
if ((DestType->isRecordType() && !DestType->isAggregateType()) ||
(S.getLangOpts().CPlusPlus11 &&
S.isStdInitializerList(DestType, nullptr))) {
if (S.getLangOpts().CPlusPlus11) {
// - Otherwise, if the initializer list has no elements and T is a
// class type with a default constructor, the object is
// value-initialized.
if (InitList->getNumInits() == 0) {
CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();
if (S.LookupDefaultConstructor(RD)) {
TryValueInitialization(S, Entity, Kind, Sequence, InitList);
return;
}
}
// - Otherwise, if T is a specialization of std::initializer_list<E>,
// an initializer_list object constructed [...]
if (TryInitializerListConstruction(S, InitList, DestType, Sequence,
TreatUnavailableAsInvalid))
return;
// - Otherwise, if T is a class type, constructors are considered.
Expr *InitListAsExpr = InitList;
TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType,
DestType, Sequence, /*InitListSyntax*/true);
} else
Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType);
return;
}
if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() &&
InitList->getNumInits() == 1) {
Expr *E = InitList->getInit(0);
// - Otherwise, if T is an enumeration with a fixed underlying type,
// the initializer-list has a single element v, and the initialization
// is direct-list-initialization, the object is initialized with the
// value T(v); if a narrowing conversion is required to convert v to
// the underlying type of T, the program is ill-formed.
auto *ET = DestType->getAs<EnumType>();
if (S.getLangOpts().CPlusPlus17 &&
Kind.getKind() == InitializationKind::IK_DirectList &&
ET && ET->getDecl()->isFixed() &&
!S.Context.hasSameUnqualifiedType(E->getType(), DestType) &&
(E->getType()->isIntegralOrUnscopedEnumerationType() ||
E->getType()->isFloatingType())) {
// There are two ways that T(v) can work when T is an enumeration type.
// If there is either an implicit conversion sequence from v to T or
// a conversion function that can convert from v to T, then we use that.
// Otherwise, if v is of integral, unscoped enumeration, or floating-point
// type, it is converted to the enumeration type via its underlying type.
// There is no overlap possible between these two cases (except when the
// source value is already of the destination type), and the first
// case is handled by the general case for single-element lists below.
ImplicitConversionSequence ICS;
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
if (!E->isPRValue())
ICS.Standard.First = ICK_Lvalue_To_Rvalue;
// If E is of a floating-point type, then the conversion is ill-formed
// due to narrowing, but go through the motions in order to produce the
// right diagnostic.
ICS.Standard.Second = E->getType()->isFloatingType()
? ICK_Floating_Integral
: ICK_Integral_Conversion;
ICS.Standard.setFromType(E->getType());
ICS.Standard.setToType(0, E->getType());
ICS.Standard.setToType(1, DestType);
ICS.Standard.setToType(2, DestType);
Sequence.AddConversionSequenceStep(ICS, ICS.Standard.getToType(2),
/*TopLevelOfInitList*/true);
Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
return;
}
// - Otherwise, if the initializer list has a single element of type E
// [...references are handled above...], the object or reference is
// initialized from that element (by copy-initialization for
// copy-list-initialization, or by direct-initialization for
// direct-list-initialization); if a narrowing conversion is required
// to convert the element to T, the program is ill-formed.
//
// Per core-24034, this is direct-initialization if we were performing
// direct-list-initialization and copy-initialization otherwise.
// We can't use InitListChecker for this, because it always performs
// copy-initialization. This only matters if we might use an 'explicit'
// conversion operator, or for the special case conversion of nullptr_t to
// bool, so we only need to handle those cases.
//
// FIXME: Why not do this in all cases?
Expr *Init = InitList->getInit(0);
if (Init->getType()->isRecordType() ||
(Init->getType()->isNullPtrType() && DestType->isBooleanType())) {
InitializationKind SubKind =
Kind.getKind() == InitializationKind::IK_DirectList
? InitializationKind::CreateDirect(Kind.getLocation(),
InitList->getLBraceLoc(),
InitList->getRBraceLoc())
: Kind;
Expr *SubInit[1] = { Init };
Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
/*TopLevelOfInitList*/true,
TreatUnavailableAsInvalid);
if (Sequence)
Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
return;
}
}
InitListChecker CheckInitList(S, Entity, InitList,
DestType, /*VerifyOnly=*/true, TreatUnavailableAsInvalid);
if (CheckInitList.HadError()) {
Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed);
return;
}
// Add the list initialization step with the built init list.
Sequence.AddListInitializationStep(DestType);
}
/// Try a reference initialization that involves calling a conversion
/// function.
static OverloadingResult TryRefInitWithConversionFunction(
Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
Expr *Initializer, bool AllowRValues, bool IsLValueRef,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
QualType T1 = cv1T1.getUnqualifiedType();
QualType cv2T2 = Initializer->getType();
QualType T2 = cv2T2.getUnqualifiedType();
assert(!S.CompareReferenceRelationship(Initializer->getBeginLoc(), T1, T2) &&
"Must have incompatible references when binding via conversion");
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
// Determine whether we are allowed to call explicit conversion operators.
// Note that none of [over.match.copy], [over.match.conv], nor
// [over.match.ref] permit an explicit constructor to be chosen when
// initializing a reference, not even for direct-initialization.
bool AllowExplicitCtors = false;
bool AllowExplicitConvs = Kind.allowExplicitConversionFunctionsInRefBinding();
const RecordType *T1RecordType = nullptr;
if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) &&
S.isCompleteType(Kind.getLocation(), T1)) {
// The type we're converting to is a class type. Enumerate its constructors
// to see if there is a suitable conversion.
CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl());
for (NamedDecl *D : S.LookupConstructors(T1RecordDecl)) {
auto Info = getConstructorInfo(D);
if (!Info.Constructor)
continue;
if (!Info.Constructor->isInvalidDecl() &&
Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr, Initializer, CandidateSet,
/*SuppressUserConversions=*/true,
/*PartialOverloading*/ false, AllowExplicitCtors);
else
S.AddOverloadCandidate(
Info.Constructor, Info.FoundDecl, Initializer, CandidateSet,
/*SuppressUserConversions=*/true,
/*PartialOverloading*/ false, AllowExplicitCtors);
}
}
}
if (T1RecordType && T1RecordType->getDecl()->isInvalidDecl())
return OR_No_Viable_Function;
const RecordType *T2RecordType = nullptr;
if ((T2RecordType = T2->getAs<RecordType>()) &&
S.isCompleteType(Kind.getLocation(), T2)) {
// The type we're converting from is a class type, enumerate its conversion
// functions.
CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl());
const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions();
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
CXXConversionDecl *Conv;
if (ConvTemplate)
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
Conv = cast<CXXConversionDecl>(D);
// If the conversion function doesn't return a reference type,
// it can't be considered for this conversion unless we're allowed to
// consider rvalues.
// FIXME: Do we need to make sure that we only consider conversion
// candidates with reference-compatible results? That might be needed to
// break recursion.
if ((AllowRValues ||
Conv->getConversionType()->isLValueReferenceType())) {
if (ConvTemplate)
S.AddTemplateConversionCandidate(
ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
CandidateSet,
/*AllowObjCConversionOnExplicit=*/false, AllowExplicitConvs);
else
S.AddConversionCandidate(
Conv, I.getPair(), ActingDC, Initializer, DestType, CandidateSet,
/*AllowObjCConversionOnExplicit=*/false, AllowExplicitConvs);
}
}
}
if (T2RecordType && T2RecordType->getDecl()->isInvalidDecl())
return OR_No_Viable_Function;
SourceLocation DeclLoc = Initializer->getBeginLoc();
// Perform overload resolution. If it fails, return the failed result.
OverloadCandidateSet::iterator Best;
if (OverloadingResult Result
= CandidateSet.BestViableFunction(S, DeclLoc, Best))
return Result;
FunctionDecl *Function = Best->Function;
// This is the overload that will be used for this initialization step if we
// use this initialization. Mark it as referenced.
Function->setReferenced();
// Compute the returned type and value kind of the conversion.
QualType cv3T3;
if (isa<CXXConversionDecl>(Function))
cv3T3 = Function->getReturnType();
else
cv3T3 = T1;
ExprValueKind VK = VK_PRValue;
if (cv3T3->isLValueReferenceType())
VK = VK_LValue;
else if (const auto *RRef = cv3T3->getAs<RValueReferenceType>())
VK = RRef->getPointeeType()->isFunctionType() ? VK_LValue : VK_XValue;
cv3T3 = cv3T3.getNonLValueExprType(S.Context);
// Add the user-defined conversion step.
bool HadMultipleCandidates = (CandidateSet.size() > 1);
Sequence.AddUserConversionStep(Function, Best->FoundDecl, cv3T3,
HadMultipleCandidates);
// Determine whether we'll need to perform derived-to-base adjustments or
// other conversions.
Sema::ReferenceConversions RefConv;
Sema::ReferenceCompareResult NewRefRelationship =
S.CompareReferenceRelationship(DeclLoc, T1, cv3T3, &RefConv);
// Add the final conversion sequence, if necessary.
if (NewRefRelationship == Sema::Ref_Incompatible) {
assert(!isa<CXXConstructorDecl>(Function) &&
"should not have conversion after constructor");
ImplicitConversionSequence ICS;
ICS.setStandard();
ICS.Standard = Best->FinalConversion;
Sequence.AddConversionSequenceStep(ICS, ICS.Standard.getToType(2));
// Every implicit conversion results in a prvalue, except for a glvalue
// derived-to-base conversion, which we handle below.
cv3T3 = ICS.Standard.getToType(2);
VK = VK_PRValue;
}
// If the converted initializer is a prvalue, its type T4 is adjusted to
// type "cv1 T4" and the temporary materialization conversion is applied.
//
// We adjust the cv-qualifications to match the reference regardless of
// whether we have a prvalue so that the AST records the change. In this
// case, T4 is "cv3 T3".
QualType cv1T4 = S.Context.getQualifiedType(cv3T3, cv1T1.getQualifiers());
if (cv1T4.getQualifiers() != cv3T3.getQualifiers())
Sequence.AddQualificationConversionStep(cv1T4, VK);
Sequence.AddReferenceBindingStep(cv1T4, VK == VK_PRValue);
VK = IsLValueRef ? VK_LValue : VK_XValue;
if (RefConv & Sema::ReferenceConversions::DerivedToBase)
Sequence.AddDerivedToBaseCastStep(cv1T1, VK);
else if (RefConv & Sema::ReferenceConversions::ObjC)
Sequence.AddObjCObjectConversionStep(cv1T1);
else if (RefConv & Sema::ReferenceConversions::Function)
Sequence.AddFunctionReferenceConversionStep(cv1T1);
else if (RefConv & Sema::ReferenceConversions::Qualification) {
if (!S.Context.hasSameType(cv1T4, cv1T1))
Sequence.AddQualificationConversionStep(cv1T1, VK);
}
return OR_Success;
}
static void CheckCXX98CompatAccessibleCopy(Sema &S,
const InitializedEntity &Entity,
Expr *CurInitExpr);
/// Attempt reference initialization (C++0x [dcl.init.ref])
static void TryReferenceInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
QualType cv2T2 = S.getCompletedType(Initializer);
Qualifiers T2Quals;
QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals);
// If the initializer is the address of an overloaded function, try
// to resolve the overloaded function. If all goes well, T2 is the
// type of the resulting function.
if (ResolveOverloadedFunctionForReferenceBinding(S, Initializer, cv2T2, T2,
T1, Sequence))
return;
// Delegate everything else to a subfunction.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
T1Quals, cv2T2, T2, T2Quals, Sequence);
}
/// Determine whether an expression is a non-referenceable glvalue (one to
/// which a reference can never bind). Attempting to bind a reference to
/// such a glvalue will always create a temporary.
static bool isNonReferenceableGLValue(Expr *E) {
return E->refersToBitField() || E->refersToVectorElement() ||
E->refersToMatrixElement();
}
/// Reference initialization without resolving overloaded functions.
///
/// We also can get here in C if we call a builtin which is declared as
/// a function with a parameter of reference type (such as __builtin_va_end()).
static void TryReferenceInitializationCore(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Expr *Initializer,
QualType cv1T1, QualType T1,
Qualifiers T1Quals,
QualType cv2T2, QualType T2,
Qualifiers T2Quals,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
SourceLocation DeclLoc = Initializer->getBeginLoc();
// Compute some basic properties of the types and the initializer.
bool isLValueRef = DestType->isLValueReferenceType();
bool isRValueRef = !isLValueRef;
Expr::Classification InitCategory = Initializer->Classify(S.Context);
Sema::ReferenceConversions RefConv;
Sema::ReferenceCompareResult RefRelationship =
S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, &RefConv);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression of type
// "cv2 T2" as follows:
//
// - If the reference is an lvalue reference and the initializer
// expression
// Note the analogous bullet points for rvalue refs to functions. Because
// there are no function rvalues in C++, rvalue refs to functions are treated
// like lvalue refs.
OverloadingResult ConvOvlResult = OR_Success;
bool T1Function = T1->isFunctionType();
if (isLValueRef || T1Function) {
if (InitCategory.isLValue() && !isNonReferenceableGLValue(Initializer) &&
(RefRelationship == Sema::Ref_Compatible ||
(Kind.isCStyleOrFunctionalCast() &&
RefRelationship == Sema::Ref_Related))) {
// - is an lvalue (but is not a bit-field), and "cv1 T1" is
// reference-compatible with "cv2 T2," or
if (RefConv & (Sema::ReferenceConversions::DerivedToBase |
Sema::ReferenceConversions::ObjC)) {
// If we're converting the pointee, add any qualifiers first;
// these qualifiers must all be top-level, so just convert to "cv1 T2".
if (RefConv & (Sema::ReferenceConversions::Qualification))
Sequence.AddQualificationConversionStep(
S.Context.getQualifiedType(T2, T1Quals),
Initializer->getValueKind());
if (RefConv & Sema::ReferenceConversions::DerivedToBase)
Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
else
Sequence.AddObjCObjectConversionStep(cv1T1);
} else if (RefConv & Sema::ReferenceConversions::Qualification) {
// Perform a (possibly multi-level) qualification conversion.
Sequence.AddQualificationConversionStep(cv1T1,
Initializer->getValueKind());
} else if (RefConv & Sema::ReferenceConversions::Function) {
Sequence.AddFunctionReferenceConversionStep(cv1T1);
}
// We only create a temporary here when binding a reference to a
// bit-field or vector element. Those cases are't supposed to be
// handled by this bullet, but the outcome is the same either way.
Sequence.AddReferenceBindingStep(cv1T1, false);
return;
}
// - has a class type (i.e., T2 is a class type), where T1 is not
// reference-related to T2, and can be implicitly converted to an
// lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible
// with "cv3 T3" (this conversion is selected by enumerating the
// applicable conversion functions (13.3.1.6) and choosing the best
// one through overload resolution (13.3)),
// If we have an rvalue ref to function type here, the rhs must be
// an rvalue. DR1287 removed the "implicitly" here.
if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType() &&
(isLValueRef || InitCategory.isRValue())) {
if (S.getLangOpts().CPlusPlus) {
// Try conversion functions only for C++.
ConvOvlResult = TryRefInitWithConversionFunction(
S, Entity, Kind, Initializer, /*AllowRValues*/ isRValueRef,
/*IsLValueRef*/ isLValueRef, Sequence);
if (ConvOvlResult == OR_Success)
return;
if (ConvOvlResult != OR_No_Viable_Function)
Sequence.SetOverloadFailure(
InitializationSequence::FK_ReferenceInitOverloadFailed,
ConvOvlResult);
} else {
ConvOvlResult = OR_No_Viable_Function;
}
}
}
// - Otherwise, the reference shall be an lvalue reference to a
// non-volatile const type (i.e., cv1 shall be const), or the reference
// shall be an rvalue reference.
// For address spaces, we interpret this to mean that an addr space
// of a reference "cv1 T1" is a superset of addr space of "cv2 T2".
if (isLValueRef && !(T1Quals.hasConst() && !T1Quals.hasVolatile() &&
T1Quals.isAddressSpaceSupersetOf(T2Quals))) {
if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy)
Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
else if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
Sequence.SetOverloadFailure(
InitializationSequence::FK_ReferenceInitOverloadFailed,
ConvOvlResult);
else if (!InitCategory.isLValue())
Sequence.SetFailed(
T1Quals.isAddressSpaceSupersetOf(T2Quals)
? InitializationSequence::
FK_NonConstLValueReferenceBindingToTemporary
: InitializationSequence::FK_ReferenceInitDropsQualifiers);
else {
InitializationSequence::FailureKind FK;
switch (RefRelationship) {
case Sema::Ref_Compatible:
if (Initializer->refersToBitField())
FK = InitializationSequence::
FK_NonConstLValueReferenceBindingToBitfield;
else if (Initializer->refersToVectorElement())
FK = InitializationSequence::
FK_NonConstLValueReferenceBindingToVectorElement;
else if (Initializer->refersToMatrixElement())
FK = InitializationSequence::
FK_NonConstLValueReferenceBindingToMatrixElement;
else
llvm_unreachable("unexpected kind of compatible initializer");
break;
case Sema::Ref_Related:
FK = InitializationSequence::FK_ReferenceInitDropsQualifiers;
break;
case Sema::Ref_Incompatible:
FK = InitializationSequence::
FK_NonConstLValueReferenceBindingToUnrelated;
break;
}
Sequence.SetFailed(FK);
}
return;
}
// - If the initializer expression
// - is an
// [<=14] xvalue (but not a bit-field), class prvalue, array prvalue, or
// [1z] rvalue (but not a bit-field) or
// function lvalue and "cv1 T1" is reference-compatible with "cv2 T2"
//
// Note: functions are handled above and below rather than here...
if (!T1Function &&
(RefRelationship == Sema::Ref_Compatible ||
(Kind.isCStyleOrFunctionalCast() &&
RefRelationship == Sema::Ref_Related)) &&
((InitCategory.isXValue() && !isNonReferenceableGLValue(Initializer)) ||
(InitCategory.isPRValue() &&
(S.getLangOpts().CPlusPlus17 || T2->isRecordType() ||
T2->isArrayType())))) {
ExprValueKind ValueKind = InitCategory.isXValue() ? VK_XValue : VK_PRValue;
if (InitCategory.isPRValue() && T2->isRecordType()) {
// The corresponding bullet in C++03 [dcl.init.ref]p5 gives the
// compiler the freedom to perform a copy here or bind to the
// object, while C++0x requires that we bind directly to the
// object. Hence, we always bind to the object without making an
// extra copy. However, in C++03 requires that we check for the
// presence of a suitable copy constructor:
//
// The constructor that would be used to make the copy shall
// be callable whether or not the copy is actually done.
if (!S.getLangOpts().CPlusPlus11 && !S.getLangOpts().MicrosoftExt)
Sequence.AddExtraneousCopyToTemporary(cv2T2);
else if (S.getLangOpts().CPlusPlus11)
CheckCXX98CompatAccessibleCopy(S, Entity, Initializer);
}
// C++1z [dcl.init.ref]/5.2.1.2:
// If the converted initializer is a prvalue, its type T4 is adjusted
// to type "cv1 T4" and the temporary materialization conversion is
// applied.
// Postpone address space conversions to after the temporary materialization
// conversion to allow creating temporaries in the alloca address space.
auto T1QualsIgnoreAS = T1Quals;
auto T2QualsIgnoreAS = T2Quals;
if (T1Quals.getAddressSpace() != T2Quals.getAddressSpace()) {
T1QualsIgnoreAS.removeAddressSpace();
T2QualsIgnoreAS.removeAddressSpace();
}
QualType cv1T4 = S.Context.getQualifiedType(cv2T2, T1QualsIgnoreAS);
if (T1QualsIgnoreAS != T2QualsIgnoreAS)
Sequence.AddQualificationConversionStep(cv1T4, ValueKind);
Sequence.AddReferenceBindingStep(cv1T4, ValueKind == VK_PRValue);
ValueKind = isLValueRef ? VK_LValue : VK_XValue;
// Add addr space conversion if required.
if (T1Quals.getAddressSpace() != T2Quals.getAddressSpace()) {
auto T4Quals = cv1T4.getQualifiers();
T4Quals.addAddressSpace(T1Quals.getAddressSpace());
QualType cv1T4WithAS = S.Context.getQualifiedType(T2, T4Quals);
Sequence.AddQualificationConversionStep(cv1T4WithAS, ValueKind);
cv1T4 = cv1T4WithAS;
}
// In any case, the reference is bound to the resulting glvalue (or to
// an appropriate base class subobject).
if (RefConv & Sema::ReferenceConversions::DerivedToBase)
Sequence.AddDerivedToBaseCastStep(cv1T1, ValueKind);
else if (RefConv & Sema::ReferenceConversions::ObjC)
Sequence.AddObjCObjectConversionStep(cv1T1);
else if (RefConv & Sema::ReferenceConversions::Qualification) {
if (!S.Context.hasSameType(cv1T4, cv1T1))
Sequence.AddQualificationConversionStep(cv1T1, ValueKind);
}
return;
}
// - has a class type (i.e., T2 is a class type), where T1 is not
// reference-related to T2, and can be implicitly converted to an
// xvalue, class prvalue, or function lvalue of type "cv3 T3",
// where "cv1 T1" is reference-compatible with "cv3 T3",
//
// DR1287 removes the "implicitly" here.
if (T2->isRecordType()) {
if (RefRelationship == Sema::Ref_Incompatible) {
ConvOvlResult = TryRefInitWithConversionFunction(
S, Entity, Kind, Initializer, /*AllowRValues*/ true,
/*IsLValueRef*/ isLValueRef, Sequence);
if (ConvOvlResult)
Sequence.SetOverloadFailure(
InitializationSequence::FK_ReferenceInitOverloadFailed,
ConvOvlResult);
return;
}
if (RefRelationship == Sema::Ref_Compatible &&
isRValueRef && InitCategory.isLValue()) {
Sequence.SetFailed(
InitializationSequence::FK_RValueReferenceBindingToLValue);
return;
}
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers);
return;
}
// - Otherwise, a temporary of type "cv1 T1" is created and initialized
// from the initializer expression using the rules for a non-reference
// copy-initialization (8.5). The reference is then bound to the
// temporary. [...]
// Ignore address space of reference type at this point and perform address
// space conversion after the reference binding step.
QualType cv1T1IgnoreAS =
T1Quals.hasAddressSpace()
? S.Context.getQualifiedType(T1, T1Quals.withoutAddressSpace())
: cv1T1;
InitializedEntity TempEntity =
InitializedEntity::InitializeTemporary(cv1T1IgnoreAS);
// FIXME: Why do we use an implicit conversion here rather than trying
// copy-initialization?
ImplicitConversionSequence ICS
= S.TryImplicitConversion(Initializer, TempEntity.getType(),
/*SuppressUserConversions=*/false,
Sema::AllowedExplicit::None,
/*FIXME:InOverloadResolution=*/false,
/*CStyle=*/Kind.isCStyleOrFunctionalCast(),
/*AllowObjCWritebackConversion=*/false);
if (ICS.isBad()) {
// FIXME: Use the conversion function set stored in ICS to turn
// this into an overloading ambiguity diagnostic. However, we need
// to keep that set as an OverloadCandidateSet rather than as some
// other kind of set.
if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
Sequence.SetOverloadFailure(
InitializationSequence::FK_ReferenceInitOverloadFailed,
ConvOvlResult);
else if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy)
Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
else
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
return;
} else {
Sequence.AddConversionSequenceStep(ICS, TempEntity.getType());
}
// [...] If T1 is reference-related to T2, cv1 must be the
// same cv-qualification as, or greater cv-qualification
// than, cv2; otherwise, the program is ill-formed.
unsigned T1CVRQuals = T1Quals.getCVRQualifiers();
unsigned T2CVRQuals = T2Quals.getCVRQualifiers();
if (RefRelationship == Sema::Ref_Related &&
((T1CVRQuals | T2CVRQuals) != T1CVRQuals ||
!T1Quals.isAddressSpaceSupersetOf(T2Quals))) {
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers);
return;
}
// [...] If T1 is reference-related to T2 and the reference is an rvalue
// reference, the initializer expression shall not be an lvalue.
if (RefRelationship >= Sema::Ref_Related && !isLValueRef &&
InitCategory.isLValue()) {
Sequence.SetFailed(
InitializationSequence::FK_RValueReferenceBindingToLValue);
return;
}
Sequence.AddReferenceBindingStep(cv1T1IgnoreAS, /*BindingTemporary=*/true);
if (T1Quals.hasAddressSpace()) {
if (!Qualifiers::isAddressSpaceSupersetOf(T1Quals.getAddressSpace(),
LangAS::Default)) {
Sequence.SetFailed(
InitializationSequence::FK_ReferenceAddrspaceMismatchTemporary);
return;
}
Sequence.AddQualificationConversionStep(cv1T1, isLValueRef ? VK_LValue
: VK_XValue);
}
}
/// Attempt character array initialization from a string literal
/// (C++ [dcl.init.string], C99 6.7.8).
static void TryStringLiteralInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence) {
Sequence.AddStringInitStep(Entity.getType());
}
/// Attempt value initialization (C++ [dcl.init]p7).
static void TryValueInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
InitializationSequence &Sequence,
InitListExpr *InitList) {
assert((!InitList || InitList->getNumInits() == 0) &&
"Shouldn't use value-init for non-empty init lists");
// C++98 [dcl.init]p5, C++11 [dcl.init]p7:
//
// To value-initialize an object of type T means:
QualType T = Entity.getType();
// -- if T is an array type, then each element is value-initialized;
T = S.Context.getBaseElementType(T);
if (const RecordType *RT = T->getAs<RecordType>()) {
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
bool NeedZeroInitialization = true;
// C++98:
// -- if T is a class type (clause 9) with a user-declared constructor
// (12.1), then the default constructor for T is called (and the
// initialization is ill-formed if T has no accessible default
// constructor);
// C++11:
// -- if T is a class type (clause 9) with either no default constructor
// (12.1 [class.ctor]) or a default constructor that is user-provided
// or deleted, then the object is default-initialized;
//
// Note that the C++11 rule is the same as the C++98 rule if there are no
// defaulted or deleted constructors, so we just use it unconditionally.
CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl);
if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted())
NeedZeroInitialization = false;
// -- if T is a (possibly cv-qualified) non-union class type without a
// user-provided or deleted default constructor, then the object is
// zero-initialized and, if T has a non-trivial default constructor,
// default-initialized;
// The 'non-union' here was removed by DR1502. The 'non-trivial default
// constructor' part was removed by DR1507.
if (NeedZeroInitialization)
Sequence.AddZeroInitializationStep(Entity.getType());
// C++03:
// -- if T is a non-union class type without a user-declared constructor,
// then every non-static data member and base class component of T is
// value-initialized;
// [...] A program that calls for [...] value-initialization of an
// entity of reference type is ill-formed.
//
// C++11 doesn't need this handling, because value-initialization does not
// occur recursively there, and the implicit default constructor is
// defined as deleted in the problematic cases.
if (!S.getLangOpts().CPlusPlus11 &&
ClassDecl->hasUninitializedReferenceMember()) {
Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForReference);
return;
}
// If this is list-value-initialization, pass the empty init list on when
// building the constructor call. This affects the semantics of a few
// things (such as whether an explicit default constructor can be called).
Expr *InitListAsExpr = InitList;
MultiExprArg Args(&InitListAsExpr, InitList ? 1 : 0);
bool InitListSyntax = InitList;
// FIXME: Instead of creating a CXXConstructExpr of array type here,
// wrap a class-typed CXXConstructExpr in an ArrayInitLoopExpr.
return TryConstructorInitialization(
S, Entity, Kind, Args, T, Entity.getType(), Sequence, InitListSyntax);
}
}
Sequence.AddZeroInitializationStep(Entity.getType());
}
/// Attempt default initialization (C++ [dcl.init]p6).
static void TryDefaultInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
InitializationSequence &Sequence) {
assert(Kind.getKind() == InitializationKind::IK_Default);
// C++ [dcl.init]p6:
// To default-initialize an object of type T means:
// - if T is an array type, each element is default-initialized;
QualType DestType = S.Context.getBaseElementType(Entity.getType());
// - if T is a (possibly cv-qualified) class type (Clause 9), the default
// constructor for T is called (and the initialization is ill-formed if
// T has no accessible default constructor);
if (DestType->isRecordType() && S.getLangOpts().CPlusPlus) {
TryConstructorInitialization(S, Entity, Kind, None, DestType,
Entity.getType(), Sequence);
return;
}
// - otherwise, no initialization is performed.
// If a program calls for the default initialization of an object of
// a const-qualified type T, T shall be a class type with a user-provided
// default constructor.
if (DestType.isConstQualified() && S.getLangOpts().CPlusPlus) {
if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity))
Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
return;
}
// If the destination type has a lifetime property, zero-initialize it.
if (DestType.getQualifiers().hasObjCLifetime()) {
Sequence.AddZeroInitializationStep(Entity.getType());
return;
}
}
/// Attempt a user-defined conversion between two types (C++ [dcl.init]),
/// which enumerates all conversion functions and performs overload resolution
/// to select the best.
static void TryUserDefinedConversion(Sema &S,
QualType DestType,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence,
bool TopLevelOfInitList) {
assert(!DestType->isReferenceType() && "References are handled elsewhere");
QualType SourceType = Initializer->getType();
assert((DestType->isRecordType() || SourceType->isRecordType()) &&
"Must have a class type to perform a user-defined conversion");
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
CandidateSet.setDestAS(DestType.getQualifiers().getAddressSpace());
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
bool AllowExplicit = Kind.AllowExplicit();
if (const RecordType *DestRecordType = DestType->getAs<RecordType>()) {
// The type we're converting to is a class type. Enumerate its constructors
// to see if there is a suitable conversion.
CXXRecordDecl *DestRecordDecl
= cast<CXXRecordDecl>(DestRecordType->getDecl());
// Try to complete the type we're converting to.
if (S.isCompleteType(Kind.getLocation(), DestType)) {
for (NamedDecl *D : S.LookupConstructors(DestRecordDecl)) {
auto Info = getConstructorInfo(D);
if (!Info.Constructor)
continue;
if (!Info.Constructor->isInvalidDecl() &&
Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr, Initializer, CandidateSet,
/*SuppressUserConversions=*/true,
/*PartialOverloading*/ false, AllowExplicit);
else
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
Initializer, CandidateSet,
/*SuppressUserConversions=*/true,
/*PartialOverloading*/ false, AllowExplicit);
}
}
}
}
SourceLocation DeclLoc = Initializer->getBeginLoc();
if (const RecordType *SourceRecordType = SourceType->getAs<RecordType>()) {
// The type we're converting from is a class type, enumerate its conversion
// functions.
// We can only enumerate the conversion functions for a complete type; if
// the type isn't complete, simply skip this step.
if (S.isCompleteType(DeclLoc, SourceType)) {
CXXRecordDecl *SourceRecordDecl
= cast<CXXRecordDecl>(SourceRecordType->getDecl());
const auto &Conversions =
SourceRecordDecl->getVisibleConversionFunctions();
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
CXXConversionDecl *Conv;
if (ConvTemplate)
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
Conv = cast<CXXConversionDecl>(D);
if (ConvTemplate)
S.AddTemplateConversionCandidate(
ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
CandidateSet, AllowExplicit, AllowExplicit);
else
S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
DestType, CandidateSet, AllowExplicit,
AllowExplicit);
}
}
}
// Perform overload resolution. If it fails, return the failed result.
OverloadCandidateSet::iterator Best;
if (OverloadingResult Result
= CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
Sequence.SetOverloadFailure(
InitializationSequence::FK_UserConversionOverloadFailed, Result);
// [class.copy.elision]p3:
// In some copy-initialization contexts, a two-stage overload resolution
// is performed.
// If the first overload resolution selects a deleted function, we also
// need the initialization sequence to decide whether to perform the second
// overload resolution.
if (!(Result == OR_Deleted &&
Kind.getKind() == InitializationKind::IK_Copy))
return;
}
FunctionDecl *Function = Best->Function;
Function->setReferenced();
bool HadMultipleCandidates = (CandidateSet.size() > 1);
if (isa<CXXConstructorDecl>(Function)) {
// Add the user-defined conversion step. Any cv-qualification conversion is
// subsumed by the initialization. Per DR5, the created temporary is of the
// cv-unqualified type of the destination.
Sequence.AddUserConversionStep(Function, Best->FoundDecl,
DestType.getUnqualifiedType(),
HadMultipleCandidates);
// C++14 and before:
// - if the function is a constructor, the call initializes a temporary
// of the cv-unqualified version of the destination type. The [...]
// temporary [...] is then used to direct-initialize, according to the
// rules above, the object that is the destination of the
// copy-initialization.
// Note that this just performs a simple object copy from the temporary.
//
// C++17:
// - if the function is a constructor, the call is a prvalue of the
// cv-unqualified version of the destination type whose return object
// is initialized by the constructor. The call is used to
// direct-initialize, according to the rules above, the object that
// is the destination of the copy-initialization.
// Therefore we need to do nothing further.
//
// FIXME: Mark this copy as extraneous.
if (!S.getLangOpts().CPlusPlus17)
Sequence.AddFinalCopy(DestType);
else if (DestType.hasQualifiers())
Sequence.AddQualificationConversionStep(DestType, VK_PRValue);
return;
}
// Add the user-defined conversion step that calls the conversion function.
QualType ConvType = Function->getCallResultType();
Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType,
HadMultipleCandidates);
if (ConvType->getAs<RecordType>()) {
// The call is used to direct-initialize [...] the object that is the
// destination of the copy-initialization.
//
// In C++17, this does not call a constructor if we enter /17.6.1:
// - If the initializer expression is a prvalue and the cv-unqualified
// version of the source type is the same as the class of the
// destination [... do not make an extra copy]
//
// FIXME: Mark this copy as extraneous.
if (!S.getLangOpts().CPlusPlus17 ||
Function->getReturnType()->isReferenceType() ||
!S.Context.hasSameUnqualifiedType(ConvType, DestType))
Sequence.AddFinalCopy(DestType);
else if (!S.Context.hasSameType(ConvType, DestType))
Sequence.AddQualificationConversionStep(DestType, VK_PRValue);
return;
}
// If the conversion following the call to the conversion function
// is interesting, add it as a separate step.
if (Best->FinalConversion.First || Best->FinalConversion.Second ||
Best->FinalConversion.Third) {
ImplicitConversionSequence ICS;
ICS.setStandard();
ICS.Standard = Best->FinalConversion;
Sequence.AddConversionSequenceStep(ICS, DestType, TopLevelOfInitList);
}
}
/// An egregious hack for compatibility with libstdc++-4.2: in <tr1/hashtable>,
/// a function with a pointer return type contains a 'return false;' statement.
/// In C++11, 'false' is not a null pointer, so this breaks the build of any
/// code using that header.
///
/// Work around this by treating 'return false;' as zero-initializing the result
/// if it's used in a pointer-returning function in a system header.
static bool isLibstdcxxPointerReturnFalseHack(Sema &S,
const InitializedEntity &Entity,
const Expr *Init) {
return S.getLangOpts().CPlusPlus11 &&
Entity.getKind() == InitializedEntity::EK_Result &&
Entity.getType()->isPointerType() &&
isa<CXXBoolLiteralExpr>(Init) &&
!cast<CXXBoolLiteralExpr>(Init)->getValue() &&
S.getSourceManager().isInSystemHeader(Init->getExprLoc());
}
/// The non-zero enum values here are indexes into diagnostic alternatives.
enum InvalidICRKind { IIK_okay, IIK_nonlocal, IIK_nonscalar };
/// Determines whether this expression is an acceptable ICR source.
static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
bool isAddressOf, bool &isWeakAccess) {
// Skip parens.
e = e->IgnoreParens();
// Skip address-of nodes.
if (UnaryOperator *op = dyn_cast<UnaryOperator>(e)) {
if (op->getOpcode() == UO_AddrOf)
return isInvalidICRSource(C, op->getSubExpr(), /*addressof*/ true,
isWeakAccess);
// Skip certain casts.
} else if (CastExpr *ce = dyn_cast<CastExpr>(e)) {
switch (ce->getCastKind()) {
case CK_Dependent:
case CK_BitCast:
case CK_LValueBitCast:
case CK_NoOp:
return isInvalidICRSource(C, ce->getSubExpr(), isAddressOf, isWeakAccess);
case CK_ArrayToPointerDecay:
return IIK_nonscalar;
case CK_NullToPointer:
return IIK_okay;
default:
break;
}
// If we have a declaration reference, it had better be a local variable.
} else if (isa<DeclRefExpr>(e)) {
// set isWeakAccess to true, to mean that there will be an implicit
// load which requires a cleanup.
if (e->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
isWeakAccess = true;
if (!isAddressOf) return IIK_nonlocal;
VarDecl *var = dyn_cast<VarDecl>(cast<DeclRefExpr>(e)->getDecl());
if (!var) return IIK_nonlocal;
return (var->hasLocalStorage() ? IIK_okay : IIK_nonlocal);
// If we have a conditional operator, check both sides.
} else if (ConditionalOperator *cond = dyn_cast<ConditionalOperator>(e)) {
if (InvalidICRKind iik = isInvalidICRSource(C, cond->getLHS(), isAddressOf,
isWeakAccess))
return iik;
return isInvalidICRSource(C, cond->getRHS(), isAddressOf, isWeakAccess);
// These are never scalar.
} else if (isa<ArraySubscriptExpr>(e)) {
return IIK_nonscalar;
// Otherwise, it needs to be a null pointer constant.
} else {
return (e->isNullPointerConstant(C, Expr::NPC_ValueDependentIsNull)
? IIK_okay : IIK_nonlocal);
}
return IIK_nonlocal;
}
/// Check whether the given expression is a valid operand for an
/// indirect copy/restore.
static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) {
assert(src->isPRValue());
bool isWeakAccess = false;
InvalidICRKind iik = isInvalidICRSource(S.Context, src, false, isWeakAccess);
// If isWeakAccess to true, there will be an implicit
// load which requires a cleanup.
if (S.getLangOpts().ObjCAutoRefCount && isWeakAccess)
S.Cleanup.setExprNeedsCleanups(true);
if (iik == IIK_okay) return;
S.Diag(src->getExprLoc(), diag::err_arc_nonlocal_writeback)
<< ((unsigned) iik - 1) // shift index into diagnostic explanations
<< src->getSourceRange();
}
/// Determine whether we have compatible array types for the
/// purposes of GNU by-copy array initialization.
static bool hasCompatibleArrayTypes(ASTContext &Context, const ArrayType *Dest,
const ArrayType *Source) {
// If the source and destination array types are equivalent, we're
// done.
if (Context.hasSameType(QualType(Dest, 0), QualType(Source, 0)))
return true;
// Make sure that the element types are the same.
if (!Context.hasSameType(Dest->getElementType(), Source->getElementType()))
return false;
// The only mismatch we allow is when the destination is an
// incomplete array type and the source is a constant array type.
return Source->isConstantArrayType() && Dest->isIncompleteArrayType();
}
static bool tryObjCWritebackConversion(Sema &S,
InitializationSequence &Sequence,
const InitializedEntity &Entity,
Expr *Initializer) {
bool ArrayDecay = false;
QualType ArgType = Initializer->getType();
QualType ArgPointee;
if (const ArrayType *ArgArrayType = S.Context.getAsArrayType(ArgType)) {
ArrayDecay = true;
ArgPointee = ArgArrayType->getElementType();
ArgType = S.Context.getPointerType(ArgPointee);
}
// Handle write-back conversion.
QualType ConvertedArgType;
if (!S.isObjCWritebackConversion(ArgType, Entity.getType(),
ConvertedArgType))
return false;
// We should copy unless we're passing to an argument explicitly
// marked 'out'.
bool ShouldCopy = true;
if (ParmVarDecl *param = cast_or_null<ParmVarDecl>(Entity.getDecl()))
ShouldCopy = (param->getObjCDeclQualifier() != ParmVarDecl::OBJC_TQ_Out);
// Do we need an lvalue conversion?
if (ArrayDecay || Initializer->isGLValue()) {
ImplicitConversionSequence ICS;
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
QualType ResultType;
if (ArrayDecay) {
ICS.Standard.First = ICK_Array_To_Pointer;
ResultType = S.Context.getPointerType(ArgPointee);
} else {
ICS.Standard.First = ICK_Lvalue_To_Rvalue;
ResultType = Initializer->getType().getNonLValueExprType(S.Context);
}
Sequence.AddConversionSequenceStep(ICS, ResultType);
}
Sequence.AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
return true;
}
static bool TryOCLSamplerInitialization(Sema &S,
InitializationSequence &Sequence,
QualType DestType,
Expr *Initializer) {
if (!S.getLangOpts().OpenCL || !DestType->isSamplerT() ||
(!Initializer->isIntegerConstantExpr(S.Context) &&
!Initializer->getType()->isSamplerT()))
return false;
Sequence.AddOCLSamplerInitStep(DestType);
return true;
}
static bool IsZeroInitializer(Expr *Initializer, Sema &S) {
return Initializer->isIntegerConstantExpr(S.getASTContext()) &&
(Initializer->EvaluateKnownConstInt(S.getASTContext()) == 0);
}
static bool TryOCLZeroOpaqueTypeInitialization(Sema &S,
InitializationSequence &Sequence,
QualType DestType,
Expr *Initializer) {
if (!S.getLangOpts().OpenCL)
return false;
//
// OpenCL 1.2 spec, s6.12.10
//
// The event argument can also be used to associate the
// async_work_group_copy with a previous async copy allowing
// an event to be shared by multiple async copies; otherwise
// event should be zero.
//
if (DestType->isEventT() || DestType->isQueueT()) {
if (!IsZeroInitializer(Initializer, S))
return false;
Sequence.AddOCLZeroOpaqueTypeStep(DestType);
return true;
}
// We should allow zero initialization for all types defined in the
// cl_intel_device_side_avc_motion_estimation extension, except
// intel_sub_group_avc_mce_payload_t and intel_sub_group_avc_mce_result_t.
if (S.getOpenCLOptions().isAvailableOption(
"cl_intel_device_side_avc_motion_estimation", S.getLangOpts()) &&
DestType->isOCLIntelSubgroupAVCType()) {
if (DestType->isOCLIntelSubgroupAVCMcePayloadType() ||
DestType->isOCLIntelSubgroupAVCMceResultType())
return false;
if (!IsZeroInitializer(Initializer, S))
return false;
Sequence.AddOCLZeroOpaqueTypeStep(DestType);
return true;
}
return false;
}
InitializationSequence::InitializationSequence(
Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
MultiExprArg Args, bool TopLevelOfInitList, bool TreatUnavailableAsInvalid)
: FailedOverloadResult(OR_Success),
FailedCandidateSet(Kind.getLocation(), OverloadCandidateSet::CSK_Normal) {
InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList,
TreatUnavailableAsInvalid);
}
/// Tries to get a FunctionDecl out of `E`. If it succeeds and we can take the
/// address of that function, this returns true. Otherwise, it returns false.
static bool isExprAnUnaddressableFunction(Sema &S, const Expr *E) {
auto *DRE = dyn_cast<DeclRefExpr>(E);
if (!DRE || !isa<FunctionDecl>(DRE->getDecl()))
return false;
return !S.checkAddressOfFunctionIsAvailable(
cast<FunctionDecl>(DRE->getDecl()));
}
/// Determine whether we can perform an elementwise array copy for this kind
/// of entity.
static bool canPerformArrayCopy(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
case InitializedEntity::EK_LambdaCapture:
// C++ [expr.prim.lambda]p24:
// For array members, the array elements are direct-initialized in
// increasing subscript order.
return true;
case InitializedEntity::EK_Variable:
// C++ [dcl.decomp]p1:
// [...] each element is copy-initialized or direct-initialized from the
// corresponding element of the assignment-expression [...]
return isa<DecompositionDecl>(Entity.getDecl());
case InitializedEntity::EK_Member:
// C++ [class.copy.ctor]p14:
// - if the member is an array, each element is direct-initialized with
// the corresponding subobject of x
return Entity.isImplicitMemberInitializer();
case InitializedEntity::EK_ArrayElement:
// All the above cases are intended to apply recursively, even though none
// of them actually say that.
if (auto *E = Entity.getParent())
return canPerformArrayCopy(*E);
break;
default:
break;
}
return false;
}
void InitializationSequence::InitializeFrom(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
MultiExprArg Args,
bool TopLevelOfInitList,
bool TreatUnavailableAsInvalid) {
ASTContext &Context = S.Context;
// Eliminate non-overload placeholder types in the arguments. We
// need to do this before checking whether types are dependent
// because lowering a pseudo-object expression might well give us
// something of dependent type.
for (unsigned I = 0, E = Args.size(); I != E; ++I)
if (Args[I]->getType()->isNonOverloadPlaceholderType()) {
// FIXME: should we be doing this here?
ExprResult result = S.CheckPlaceholderExpr(Args[I]);
if (result.isInvalid()) {
SetFailed(FK_PlaceholderType);
return;
}
Args[I] = result.get();
}
// C++0x [dcl.init]p16:
// The semantics of initializers are as follows. The destination type is
// the type of the object or reference being initialized and the source
// type is the type of the initializer expression. The source type is not
// defined when the initializer is a braced-init-list or when it is a
// parenthesized list of expressions.
QualType DestType = Entity.getType();
if (DestType->isDependentType() ||
Expr::hasAnyTypeDependentArguments(Args)) {
SequenceKind = DependentSequence;
return;
}
// Almost everything is a normal sequence.
setSequenceKind(NormalSequence);
QualType SourceType;
Expr *Initializer = nullptr;
if (Args.size() == 1) {
Initializer = Args[0];
if (S.getLangOpts().ObjC) {
if (S.CheckObjCBridgeRelatedConversions(Initializer->getBeginLoc(),
DestType, Initializer->getType(),
Initializer) ||
S.CheckConversionToObjCLiteral(DestType, Initializer))
Args[0] = Initializer;
}
if (!isa<InitListExpr>(Initializer))
SourceType = Initializer->getType();
}
// - If the initializer is a (non-parenthesized) braced-init-list, the
// object is list-initialized (8.5.4).
if (Kind.getKind() != InitializationKind::IK_Direct) {
if (InitListExpr *InitList = dyn_cast_or_null<InitListExpr>(Initializer)) {
TryListInitialization(S, Entity, Kind, InitList, *this,
TreatUnavailableAsInvalid);
return;
}
}
// - If the destination type is a reference type, see 8.5.3.
if (DestType->isReferenceType()) {
// C++0x [dcl.init.ref]p1:
// A variable declared to be a T& or T&&, that is, "reference to type T"
// (8.3.2), shall be initialized by an object, or function, of type T or
// by an object that can be converted into a T.
// (Therefore, multiple arguments are not permitted.)
if (Args.size() != 1)
SetFailed(FK_TooManyInitsForReference);
// C++17 [dcl.init.ref]p5:
// A reference [...] is initialized by an expression [...] as follows:
// If the initializer is not an expression, presumably we should reject,
// but the standard fails to actually say so.
else if (isa<InitListExpr>(Args[0]))
SetFailed(FK_ParenthesizedListInitForReference);
else
TryReferenceInitialization(S, Entity, Kind, Args[0], *this);
return;
}
// - If the initializer is (), the object is value-initialized.
if (Kind.getKind() == InitializationKind::IK_Value ||
(Kind.getKind() == InitializationKind::IK_Direct && Args.empty())) {
TryValueInitialization(S, Entity, Kind, *this);
return;
}
// Handle default initialization.
if (Kind.getKind() == InitializationKind::IK_Default) {
TryDefaultInitialization(S, Entity, Kind, *this);
return;
}
// - If the destination type is an array of characters, an array of
// char16_t, an array of char32_t, or an array of wchar_t, and the
// initializer is a string literal, see 8.5.2.
// - Otherwise, if the destination type is an array, the program is
// ill-formed.
if (const ArrayType *DestAT = Context.getAsArrayType(DestType)) {
if (Initializer && isa<VariableArrayType>(DestAT)) {
SetFailed(FK_VariableLengthArrayHasInitializer);
return;
}
if (Initializer) {
switch (IsStringInit(Initializer, DestAT, Context)) {
case SIF_None:
TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this);
return;
case SIF_NarrowStringIntoWideChar:
SetFailed(FK_NarrowStringIntoWideCharArray);
return;
case SIF_WideStringIntoChar:
SetFailed(FK_WideStringIntoCharArray);
return;
case SIF_IncompatWideStringIntoWideChar:
SetFailed(FK_IncompatWideStringIntoWideChar);
return;
case SIF_PlainStringIntoUTF8Char:
SetFailed(FK_PlainStringIntoUTF8Char);
return;
case SIF_UTF8StringIntoPlainChar:
SetFailed(FK_UTF8StringIntoPlainChar);
return;
case SIF_Other:
break;
}
}
// Some kinds of initialization permit an array to be initialized from
// another array of the same type, and perform elementwise initialization.
if (Initializer && isa<ConstantArrayType>(DestAT) &&
S.Context.hasSameUnqualifiedType(Initializer->getType(),
Entity.getType()) &&
canPerformArrayCopy(Entity)) {
// If source is a prvalue, use it directly.
if (Initializer->isPRValue()) {
AddArrayInitStep(DestType, /*IsGNUExtension*/false);
return;
}
// Emit element-at-a-time copy loop.
InitializedEntity Element =
InitializedEntity::InitializeElement(S.Context, 0, Entity);
QualType InitEltT =
Context.getAsArrayType(Initializer->getType())->getElementType();
OpaqueValueExpr OVE(Initializer->getExprLoc(), InitEltT,
Initializer->getValueKind(),
Initializer->getObjectKind());
Expr *OVEAsExpr = &OVE;
InitializeFrom(S, Element, Kind, OVEAsExpr, TopLevelOfInitList,
TreatUnavailableAsInvalid);
if (!Failed())
AddArrayInitLoopStep(Entity.getType(), InitEltT);
return;
}
// Note: as an GNU C extension, we allow initialization of an
// array from a compound literal that creates an array of the same
// type, so long as the initializer has no side effects.
if (!S.getLangOpts().CPlusPlus && Initializer &&
isa<CompoundLiteralExpr>(Initializer->IgnoreParens()) &&
Initializer->getType()->isArrayType()) {
const ArrayType *SourceAT
= Context.getAsArrayType(Initializer->getType());
if (!hasCompatibleArrayTypes(S.Context, DestAT, SourceAT))
SetFailed(FK_ArrayTypeMismatch);
else if (Initializer->HasSideEffects(S.Context))
SetFailed(FK_NonConstantArrayInit);
else {
AddArrayInitStep(DestType, /*IsGNUExtension*/true);
}
}
// Note: as a GNU C++ extension, we allow list-initialization of a
// class member of array type from a parenthesized initializer list.
else if (S.getLangOpts().CPlusPlus &&
Entity.getKind() == InitializedEntity::EK_Member &&
Initializer && isa<InitListExpr>(Initializer)) {
TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer),
*this, TreatUnavailableAsInvalid);
AddParenthesizedArrayInitStep(DestType);
} else if (DestAT->getElementType()->isCharType())
SetFailed(FK_ArrayNeedsInitListOrStringLiteral);
else if (IsWideCharCompatible(DestAT->getElementType(), Context))
SetFailed(FK_ArrayNeedsInitListOrWideStringLiteral);
else
SetFailed(FK_ArrayNeedsInitList);
return;
}
// Determine whether we should consider writeback conversions for
// Objective-C ARC.
bool allowObjCWritebackConversion = S.getLangOpts().ObjCAutoRefCount &&
Entity.isParameterKind();
if (TryOCLSamplerInitialization(S, *this, DestType, Initializer))
return;
// We're at the end of the line for C: it's either a write-back conversion
// or it's a C assignment. There's no need to check anything else.
if (!S.getLangOpts().CPlusPlus) {
// If allowed, check whether this is an Objective-C writeback conversion.
if (allowObjCWritebackConversion &&
tryObjCWritebackConversion(S, *this, Entity, Initializer)) {
return;
}
if (TryOCLZeroOpaqueTypeInitialization(S, *this, DestType, Initializer))
return;
// Handle initialization in C
AddCAssignmentStep(DestType);
MaybeProduceObjCObject(S, *this, Entity);
return;
}
assert(S.getLangOpts().CPlusPlus);
// - If the destination type is a (possibly cv-qualified) class type:
if (DestType->isRecordType()) {
// - If the initialization is direct-initialization, or if it is
// copy-initialization where the cv-unqualified version of the
// source type is the same class as, or a derived class of, the
// class of the destination, constructors are considered. [...]
if (Kind.getKind() == InitializationKind::IK_Direct ||
(Kind.getKind() == InitializationKind::IK_Copy &&
(Context.hasSameUnqualifiedType(SourceType, DestType) ||
S.IsDerivedFrom(Initializer->getBeginLoc(), SourceType, DestType))))
TryConstructorInitialization(S, Entity, Kind, Args,
DestType, DestType, *this);
// - Otherwise (i.e., for the remaining copy-initialization cases),
// user-defined conversion sequences that can convert from the source
// type to the destination type or (when a conversion function is
// used) to a derived class thereof are enumerated as described in
// 13.3.1.4, and the best one is chosen through overload resolution
// (13.3).
else
TryUserDefinedConversion(S, DestType, Kind, Initializer, *this,
TopLevelOfInitList);
return;
}
assert(Args.size() >= 1 && "Zero-argument case handled above");
// For HLSL ext vector types we allow list initialization behavior for C++
// constructor syntax. This is accomplished by converting initialization
// arguments an InitListExpr late.
if (S.getLangOpts().HLSL && DestType->isExtVectorType() &&
(SourceType.isNull() ||
!Context.hasSameUnqualifiedType(SourceType, DestType))) {
llvm::SmallVector<Expr *> InitArgs;
for (auto Arg : Args) {
if (Arg->getType()->isExtVectorType()) {
const auto *VTy = Arg->getType()->castAs<ExtVectorType>();
unsigned Elm = VTy->getNumElements();
for (unsigned Idx = 0; Idx < Elm; ++Idx) {
InitArgs.emplace_back(new (Context) ArraySubscriptExpr(
Arg,
IntegerLiteral::Create(
Context, llvm::APInt(Context.getIntWidth(Context.IntTy), Idx),
Context.IntTy, SourceLocation()),
VTy->getElementType(), Arg->getValueKind(), Arg->getObjectKind(),
SourceLocation()));
}
} else
InitArgs.emplace_back(Arg);
}
InitListExpr *ILE = new (Context) InitListExpr(
S.getASTContext(), SourceLocation(), InitArgs, SourceLocation());
Args[0] = ILE;
AddListInitializationStep(DestType);
return;
}
// The remaining cases all need a source type.
if (Args.size() > 1) {
SetFailed(FK_TooManyInitsForScalar);
return;
} else if (isa<InitListExpr>(Args[0])) {
SetFailed(FK_ParenthesizedListInitForScalar);
return;
}
// - Otherwise, if the source type is a (possibly cv-qualified) class
// type, conversion functions are considered.
if (!SourceType.isNull() && SourceType->isRecordType()) {
// For a conversion to _Atomic(T) from either T or a class type derived
// from T, initialize the T object then convert to _Atomic type.
bool NeedAtomicConversion = false;
if (const AtomicType *Atomic = DestType->getAs<AtomicType>()) {
if (Context.hasSameUnqualifiedType(SourceType, Atomic->getValueType()) ||
S.IsDerivedFrom(Initializer->getBeginLoc(), SourceType,
Atomic->getValueType())) {
DestType = Atomic->getValueType();
NeedAtomicConversion = true;
}
}
TryUserDefinedConversion(S, DestType, Kind, Initializer, *this,
TopLevelOfInitList);
MaybeProduceObjCObject(S, *this, Entity);
if (!Failed() && NeedAtomicConversion)
AddAtomicConversionStep(Entity.getType());
return;
}
// - Otherwise, if the initialization is direct-initialization, the source
// type is std::nullptr_t, and the destination type is bool, the initial
// value of the object being initialized is false.
if (!SourceType.isNull() && SourceType->isNullPtrType() &&
DestType->isBooleanType() &&
Kind.getKind() == InitializationKind::IK_Direct) {
AddConversionSequenceStep(
ImplicitConversionSequence::getNullptrToBool(SourceType, DestType,
Initializer->isGLValue()),
DestType);
return;
}
// - Otherwise, the initial value of the object being initialized is the
// (possibly converted) value of the initializer expression. Standard
// conversions (Clause 4) will be used, if necessary, to convert the
// initializer expression to the cv-unqualified version of the
// destination type; no user-defined conversions are considered.
ImplicitConversionSequence ICS
= S.TryImplicitConversion(Initializer, DestType,
/*SuppressUserConversions*/true,
Sema::AllowedExplicit::None,
/*InOverloadResolution*/ false,
/*CStyle=*/Kind.isCStyleOrFunctionalCast(),
allowObjCWritebackConversion);
if (ICS.isStandard() &&
ICS.Standard.Second == ICK_Writeback_Conversion) {
// Objective-C ARC writeback conversion.
// We should copy unless we're passing to an argument explicitly
// marked 'out'.
bool ShouldCopy = true;
if (ParmVarDecl *Param = cast_or_null<ParmVarDecl>(Entity.getDecl()))
ShouldCopy = (Param->getObjCDeclQualifier() != ParmVarDecl::OBJC_TQ_Out);
// If there was an lvalue adjustment, add it as a separate conversion.
if (ICS.Standard.First == ICK_Array_To_Pointer ||
ICS.Standard.First == ICK_Lvalue_To_Rvalue) {
ImplicitConversionSequence LvalueICS;
LvalueICS.setStandard();
LvalueICS.Standard.setAsIdentityConversion();
LvalueICS.Standard.setAllToTypes(ICS.Standard.getToType(0));
LvalueICS.Standard.First = ICS.Standard.First;
AddConversionSequenceStep(LvalueICS, ICS.Standard.getToType(0));
}
AddPassByIndirectCopyRestoreStep(DestType, ShouldCopy);
} else if (ICS.isBad()) {
DeclAccessPair dap;
if (isLibstdcxxPointerReturnFalseHack(S, Entity, Initializer)) {
AddZeroInitializationStep(Entity.getType());
} else if (Initializer->getType() == Context.OverloadTy &&
!S.ResolveAddressOfOverloadedFunction(Initializer, DestType,
false, dap))
SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
else if (Initializer->getType()->isFunctionType() &&
isExprAnUnaddressableFunction(S, Initializer))
SetFailed(InitializationSequence::FK_AddressOfUnaddressableFunction);
else
SetFailed(InitializationSequence::FK_ConversionFailed);
} else {
AddConversionSequenceStep(ICS, DestType, TopLevelOfInitList);
MaybeProduceObjCObject(S, *this, Entity);
}
}
InitializationSequence::~InitializationSequence() {
for (auto &S : Steps)
S.Destroy();
}
//===----------------------------------------------------------------------===//
// Perform initialization
//===----------------------------------------------------------------------===//
static Sema::AssignmentAction
getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) {
switch(Entity.getKind()) {
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
return Sema::AA_Initializing;
case InitializedEntity::EK_Parameter:
if (Entity.getDecl() &&
isa<ObjCMethodDecl>(Entity.getDecl()->getDeclContext()))
return Sema::AA_Sending;
return Sema::AA_Passing;
case InitializedEntity::EK_Parameter_CF_Audited:
if (Entity.getDecl() &&
isa<ObjCMethodDecl>(Entity.getDecl()->getDeclContext()))
return Sema::AA_Sending;
return !Diagnose ? Sema::AA_Passing : Sema::AA_Passing_CFAudited;
case InitializedEntity::EK_Result:
case InitializedEntity::EK_StmtExprResult: // FIXME: Not quite right.
return Sema::AA_Returning;
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_RelatedResult:
// FIXME: Can we tell apart casting vs. converting?
return Sema::AA_Casting;
case InitializedEntity::EK_TemplateParameter:
// This is really initialization, but refer to it as conversion for
// consistency with CheckConvertedConstantExpression.
return Sema::AA_Converting;
case InitializedEntity::EK_Member:
case InitializedEntity::EK_Binding:
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_LambdaCapture:
case InitializedEntity::EK_CompoundLiteralInit:
return Sema::AA_Initializing;
}
llvm_unreachable("Invalid EntityKind!");
}
/// Whether we should bind a created object as a temporary when
/// initializing the given entity.
static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_Member:
case InitializedEntity::EK_Result:
case InitializedEntity::EK_StmtExprResult:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_LambdaCapture:
case InitializedEntity::EK_CompoundLiteralInit:
case InitializedEntity::EK_TemplateParameter:
return false;
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Parameter_CF_Audited:
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_RelatedResult:
case InitializedEntity::EK_Binding:
return true;
}
llvm_unreachable("missed an InitializedEntity kind?");
}
/// Whether the given entity, when initialized with an object
/// created for that initialization, requires destruction.
static bool shouldDestroyEntity(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
case InitializedEntity::EK_Result:
case InitializedEntity::EK_StmtExprResult:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_LambdaCapture:
return false;
case InitializedEntity::EK_Member:
case InitializedEntity::EK_Binding:
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Parameter_CF_Audited:
case InitializedEntity::EK_TemplateParameter:
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_CompoundLiteralInit:
case InitializedEntity::EK_RelatedResult:
return true;
}
llvm_unreachable("missed an InitializedEntity kind?");
}
/// Get the location at which initialization diagnostics should appear.
static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
Expr *Initializer) {
switch (Entity.getKind()) {
case InitializedEntity::EK_Result:
case InitializedEntity::EK_StmtExprResult:
return Entity.getReturnLoc();
case InitializedEntity::EK_Exception:
return Entity.getThrowLoc();
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Binding:
return Entity.getDecl()->getLocation();
case InitializedEntity::EK_LambdaCapture:
return Entity.getCaptureLoc();
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_Member:
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Parameter_CF_Audited:
case InitializedEntity::EK_TemplateParameter:
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_CompoundLiteralInit:
case InitializedEntity::EK_RelatedResult:
return Initializer->getBeginLoc();
}
llvm_unreachable("missed an InitializedEntity kind?");
}
/// Make a (potentially elidable) temporary copy of the object
/// provided by the given initializer by calling the appropriate copy
/// constructor.
///
/// \param S The Sema object used for type-checking.
///
/// \param T The type of the temporary object, which must either be
/// the type of the initializer expression or a superclass thereof.
///
/// \param Entity The entity being initialized.
///
/// \param CurInit The initializer expression.
///
/// \param IsExtraneousCopy Whether this is an "extraneous" copy that
/// is permitted in C++03 (but not C++0x) when binding a reference to
/// an rvalue.
///
/// \returns An expression that copies the initializer expression into
/// a temporary object, or an error expression if a copy could not be
/// created.
static ExprResult CopyObject(Sema &S,
QualType T,
const InitializedEntity &Entity,
ExprResult CurInit,
bool IsExtraneousCopy) {
if (CurInit.isInvalid())
return CurInit;
// Determine which class type we're copying to.
Expr *CurInitExpr = (Expr *)CurInit.get();
CXXRecordDecl *Class = nullptr;
if (const RecordType *Record = T->getAs<RecordType>())
Class = cast<CXXRecordDecl>(Record->getDecl());
if (!Class)
return CurInit;
SourceLocation Loc = getInitializationLoc(Entity, CurInit.get());
// Make sure that the type we are copying is complete.
if (S.RequireCompleteType(Loc, T, diag::err_temp_copy_incomplete))
return CurInit;
// Perform overload resolution using the class's constructors. Per
// C++11 [dcl.init]p16, second bullet for class types, this initialization
// is direct-initialization.
OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
DeclContext::lookup_result Ctors = S.LookupConstructors(Class);
OverloadCandidateSet::iterator Best;
switch (ResolveConstructorOverload(
S, Loc, CurInitExpr, CandidateSet, T, Ctors, Best,
/*CopyInitializing=*/false, /*AllowExplicit=*/true,
/*OnlyListConstructors=*/false, /*IsListInit=*/false,
/*SecondStepOfCopyInit=*/true)) {
case OR_Success:
break;
case OR_No_Viable_Function:
CandidateSet.NoteCandidates(
PartialDiagnosticAt(
Loc, S.PDiag(IsExtraneousCopy && !S.isSFINAEContext()
? diag::ext_rvalue_to_reference_temp_copy_no_viable
: diag::err_temp_copy_no_viable)
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange()),
S, OCD_AllCandidates, CurInitExpr);
if (!IsExtraneousCopy || S.isSFINAEContext())
return ExprError();
return CurInit;
case OR_Ambiguous:
CandidateSet.NoteCandidates(
PartialDiagnosticAt(Loc, S.PDiag(diag::err_temp_copy_ambiguous)
<< (int)Entity.getKind()
<< CurInitExpr->getType()
<< CurInitExpr->getSourceRange()),
S, OCD_AmbiguousCandidates, CurInitExpr);
return ExprError();
case OR_Deleted:
S.Diag(Loc, diag::err_temp_copy_deleted)
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
S.NoteDeletedFunction(Best->Function);
return ExprError();
}
bool HadMultipleCandidates = CandidateSet.size() > 1;
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
SmallVector<Expr*, 8> ConstructorArgs;
CurInit.get(); // Ownership transferred into MultiExprArg, below.
S.CheckConstructorAccess(Loc, Constructor, Best->FoundDecl, Entity,
IsExtraneousCopy);
if (IsExtraneousCopy) {
// If this is a totally extraneous copy for C++03 reference
// binding purposes, just return the original initialization
// expression. We don't generate an (elided) copy operation here
// because doing so would require us to pass down a flag to avoid
// infinite recursion, where each step adds another extraneous,
// elidable copy.
// Instantiate the default arguments of any extra parameters in
// the selected copy constructor, as if we were going to create a
// proper call to the copy constructor.
for (unsigned I = 1, N = Constructor->getNumParams(); I != N; ++I) {
ParmVarDecl *Parm = Constructor->getParamDecl(I);
if (S.RequireCompleteType(Loc, Parm->getType(),
diag::err_call_incomplete_argument))
break;
// Build the default argument expression; we don't actually care
// if this succeeds or not, because this routine will complain
// if there was a problem.
S.BuildCXXDefaultArgExpr(Loc, Constructor, Parm);
}
return CurInitExpr;
}
// Determine the arguments required to actually perform the
// constructor call (we might have derived-to-base conversions, or
// the copy constructor may have default arguments).
if (S.CompleteConstructorCall(Constructor, T, CurInitExpr, Loc,
ConstructorArgs))
return ExprError();
// C++0x [class.copy]p32:
// When certain criteria are met, an implementation is allowed to
// omit the copy/move construction of a class object, even if the
// copy/move constructor and/or destructor for the object have
// side effects. [...]
// - when a temporary class object that has not been bound to a
// reference (12.2) would be copied/moved to a class object
// with the same cv-unqualified type, the copy/move operation
// can be omitted by constructing the temporary object
// directly into the target of the omitted copy/move
//
// Note that the other three bullets are handled elsewhere. Copy
// elision for return statements and throw expressions are handled as part
// of constructor initialization, while copy elision for exception handlers
// is handled by the run-time.
//
// FIXME: If the function parameter is not the same type as the temporary, we
// should still be able to elide the copy, but we don't have a way to
// represent in the AST how much should be elided in this case.
bool Elidable =
CurInitExpr->isTemporaryObject(S.Context, Class) &&
S.Context.hasSameUnqualifiedType(
Best->Function->getParamDecl(0)->getType().getNonReferenceType(),
CurInitExpr->getType());
// Actually perform the constructor call.
CurInit = S.BuildCXXConstructExpr(Loc, T, Best->FoundDecl, Constructor,
Elidable,
ConstructorArgs,
HadMultipleCandidates,
/*ListInit*/ false,
/*StdInitListInit*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
// If we're supposed to bind temporaries, do so.
if (!CurInit.isInvalid() && shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.getAs<Expr>());
return CurInit;
}
/// Check whether elidable copy construction for binding a reference to
/// a temporary would have succeeded if we were building in C++98 mode, for
/// -Wc++98-compat.
static void CheckCXX98CompatAccessibleCopy(Sema &S,
const InitializedEntity &Entity,
Expr *CurInitExpr) {
assert(S.getLangOpts().CPlusPlus11);
const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>();
if (!Record)
return;
SourceLocation Loc = getInitializationLoc(Entity, CurInitExpr);
if (S.Diags.isIgnored(diag::warn_cxx98_compat_temp_copy, Loc))
return;
// Find constructors which would have been considered.
OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
DeclContext::lookup_result Ctors =
S.LookupConstructors(cast<CXXRecordDecl>(Record->getDecl()));
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
OverloadingResult OR = ResolveConstructorOverload(
S, Loc, CurInitExpr, CandidateSet, CurInitExpr->getType(), Ctors, Best,
/*CopyInitializing=*/false, /*AllowExplicit=*/true,
/*OnlyListConstructors=*/false, /*IsListInit=*/false,
/*SecondStepOfCopyInit=*/true);
PartialDiagnostic Diag = S.PDiag(diag::warn_cxx98_compat_temp_copy)
<< OR << (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
switch (OR) {
case OR_Success:
S.CheckConstructorAccess(Loc, cast<CXXConstructorDecl>(Best->Function),
Best->FoundDecl, Entity, Diag);
// FIXME: Check default arguments as far as that's possible.
break;
case OR_No_Viable_Function:
CandidateSet.NoteCandidates(PartialDiagnosticAt(Loc, Diag), S,
OCD_AllCandidates, CurInitExpr);
break;
case OR_Ambiguous:
CandidateSet.NoteCandidates(PartialDiagnosticAt(Loc, Diag), S,
OCD_AmbiguousCandidates, CurInitExpr);
break;
case OR_Deleted:
S.Diag(Loc, Diag);
S.NoteDeletedFunction(Best->Function);
break;
}
}
void InitializationSequence::PrintInitLocationNote(Sema &S,
const InitializedEntity &Entity) {
if (Entity.isParamOrTemplateParamKind() && Entity.getDecl()) {
if (Entity.getDecl()->getLocation().isInvalid())
return;
if (Entity.getDecl()->getDeclName())
S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_named_here)
<< Entity.getDecl()->getDeclName();
else
S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here);
}
else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
Entity.getMethodDecl())
S.Diag(Entity.getMethodDecl()->getLocation(),
diag::note_method_return_type_change)
<< Entity.getMethodDecl()->getDeclName();
}
/// Returns true if the parameters describe a constructor initialization of
/// an explicit temporary object, e.g. "Point(x, y)".
static bool isExplicitTemporary(const InitializedEntity &Entity,
const InitializationKind &Kind,
unsigned NumArgs) {
switch (Entity.getKind()) {
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_CompoundLiteralInit:
case InitializedEntity::EK_RelatedResult:
break;
default:
return false;
}
switch (Kind.getKind()) {
case InitializationKind::IK_DirectList:
return true;
// FIXME: Hack to work around cast weirdness.
case InitializationKind::IK_Direct:
case InitializationKind::IK_Value:
return NumArgs != 1;
default:
return false;
}
}
static ExprResult
PerformConstructorInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
MultiExprArg Args,
const InitializationSequence::Step& Step,
bool &ConstructorInitRequiresZeroInit,
bool IsListInitialization,
bool IsStdInitListInitialization,
SourceLocation LBraceLoc,
SourceLocation RBraceLoc) {
unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(Step.Function.Function);
bool HadMultipleCandidates = Step.Function.HadMultipleCandidates;
// Build a call to the selected constructor.
SmallVector<Expr*, 8> ConstructorArgs;
SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid())
? Kind.getEqualLoc()
: Kind.getLocation();
if (Kind.getKind() == InitializationKind::IK_Default) {
// Force even a trivial, implicit default constructor to be
// semantically checked. We do this explicitly because we don't build
// the definition for completely trivial constructors.
assert(Constructor->getParent() && "No parent class for constructor.");
if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
Constructor->isTrivial() && !Constructor->isUsed(false)) {
S.runWithSufficientStackSpace(Loc, [&] {
S.DefineImplicitDefaultConstructor(Loc, Constructor);
});
}
}
ExprResult CurInit((Expr *)nullptr);
// C++ [over.match.copy]p1:
// - When initializing a temporary to be bound to the first parameter
// of a constructor that takes a reference to possibly cv-qualified
// T as its first argument, called with a single argument in the
// context of direct-initialization, explicit conversion functions
// are also considered.
bool AllowExplicitConv =
Kind.AllowExplicit() && !Kind.isCopyInit() && Args.size() == 1 &&
hasCopyOrMoveCtorParam(S.Context,
getConstructorInfo(Step.Function.FoundDecl));
// Determine the arguments required to actually perform the constructor
// call.
if (S.CompleteConstructorCall(Constructor, Step.Type, Args, Loc,
ConstructorArgs, AllowExplicitConv,
IsListInitialization))
return ExprError();
if (isExplicitTemporary(Entity, Kind, NumArgs)) {
// An explicitly-constructed temporary, e.g., X(1, 2).
if (S.DiagnoseUseOfDecl(Constructor, Loc))
return ExprError();
TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
if (!TSInfo)
TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc);
SourceRange ParenOrBraceRange =
(Kind.getKind() == InitializationKind::IK_DirectList)
? SourceRange(LBraceLoc, RBraceLoc)
: Kind.getParenOrBraceRange();
CXXConstructorDecl *CalleeDecl = Constructor;
if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(
Step.Function.FoundDecl.getDecl())) {
CalleeDecl = S.findInheritingConstructor(Loc, Constructor, Shadow);
if (S.DiagnoseUseOfDecl(CalleeDecl, Loc))
return ExprError();
}
S.MarkFunctionReferenced(Loc, CalleeDecl);
CurInit = S.CheckForImmediateInvocation(
CXXTemporaryObjectExpr::Create(
S.Context, CalleeDecl,
Entity.getType().getNonLValueExprType(S.Context), TSInfo,
ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates,
IsListInitialization, IsStdInitListInitialization,
ConstructorInitRequiresZeroInit),
CalleeDecl);
} else {
CXXConstructExpr::ConstructionKind ConstructKind =
CXXConstructExpr::CK_Complete;
if (Entity.getKind() == InitializedEntity::EK_Base) {
ConstructKind = Entity.getBaseSpecifier()->isVirtual() ?
CXXConstructExpr::CK_VirtualBase :
CXXConstructExpr::CK_NonVirtualBase;
} else if (Entity.getKind() == InitializedEntity::EK_Delegating) {
ConstructKind = CXXConstructExpr::CK_Delegating;
}
// Only get the parenthesis or brace range if it is a list initialization or
// direct construction.
SourceRange ParenOrBraceRange;
if (IsListInitialization)
ParenOrBraceRange = SourceRange(LBraceLoc, RBraceLoc);
else if (Kind.getKind() == InitializationKind::IK_Direct)
ParenOrBraceRange = Kind.getParenOrBraceRange();
// If the entity allows NRVO, mark the construction as elidable
// unconditionally.
if (Entity.allowsNRVO())
CurInit = S.BuildCXXConstructExpr(Loc, Step.Type,
Step.Function.FoundDecl,
Constructor, /*Elidable=*/true,
ConstructorArgs,
HadMultipleCandidates,
IsListInitialization,
IsStdInitListInitialization,
ConstructorInitRequiresZeroInit,
ConstructKind,
ParenOrBraceRange);
else
CurInit = S.BuildCXXConstructExpr(Loc, Step.Type,
Step.Function.FoundDecl,
Constructor,
ConstructorArgs,
HadMultipleCandidates,
IsListInitialization,
IsStdInitListInitialization,
ConstructorInitRequiresZeroInit,
ConstructKind,
ParenOrBraceRange);
}
if (CurInit.isInvalid())
return ExprError();
// Only check access if all of that succeeded.
S.CheckConstructorAccess(Loc, Constructor, Step.Function.FoundDecl, Entity);
if (S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc))
return ExprError();
if (const ArrayType *AT = S.Context.getAsArrayType(Entity.getType()))
if (checkDestructorReference(S.Context.getBaseElementType(AT), Loc, S))
return ExprError();
if (shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.get());
return CurInit;
}
namespace {
enum LifetimeKind {
/// The lifetime of a temporary bound to this entity ends at the end of the
/// full-expression, and that's (probably) fine.
LK_FullExpression,
/// The lifetime of a temporary bound to this entity is extended to the
/// lifeitme of the entity itself.
LK_Extended,
/// The lifetime of a temporary bound to this entity probably ends too soon,
/// because the entity is allocated in a new-expression.
LK_New,
/// The lifetime of a temporary bound to this entity ends too soon, because
/// the entity is a return object.
LK_Return,
/// The lifetime of a temporary bound to this entity ends too soon, because
/// the entity is the result of a statement expression.
LK_StmtExprResult,
/// This is a mem-initializer: if it would extend a temporary (other than via
/// a default member initializer), the program is ill-formed.
LK_MemInitializer,
};
using LifetimeResult =
llvm::PointerIntPair<const InitializedEntity *, 3, LifetimeKind>;
}
/// Determine the declaration which an initialized entity ultimately refers to,
/// for the purpose of lifetime-extending a temporary bound to a reference in
/// the initialization of \p Entity.
static LifetimeResult getEntityLifetime(
const InitializedEntity *Entity,
const InitializedEntity *InitField = nullptr) {
// C++11 [class.temporary]p5:
switch (Entity->getKind()) {
case InitializedEntity::EK_Variable:
// The temporary [...] persists for the lifetime of the reference
return {Entity, LK_Extended};
case InitializedEntity::EK_Member:
// For subobjects, we look at the complete object.
if (Entity->getParent())
return getEntityLifetime(Entity->getParent(), Entity);
// except:
// C++17 [class.base.init]p8:
// A temporary expression bound to a reference member in a
// mem-initializer is ill-formed.
// C++17 [class.base.init]p11:
// A temporary expression bound to a reference member from a
// default member initializer is ill-formed.
//
// The context of p11 and its example suggest that it's only the use of a
// default member initializer from a constructor that makes the program
// ill-formed, not its mere existence, and that it can even be used by
// aggregate initialization.
return {Entity, Entity->isDefaultMemberInitializer() ? LK_Extended
: LK_MemInitializer};
case InitializedEntity::EK_Binding:
// Per [dcl.decomp]p3, the binding is treated as a variable of reference
// type.
return {Entity, LK_Extended};
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Parameter_CF_Audited:
// -- A temporary bound to a reference parameter in a function call
// persists until the completion of the full-expression containing
// the call.
return {nullptr, LK_FullExpression};
case InitializedEntity::EK_TemplateParameter:
// FIXME: This will always be ill-formed; should we eagerly diagnose it here?
return {nullptr, LK_FullExpression};
case InitializedEntity::EK_Result:
// -- The lifetime of a temporary bound to the returned value in a
// function return statement is not extended; the temporary is
// destroyed at the end of the full-expression in the return statement.
return {nullptr, LK_Return};
case InitializedEntity::EK_StmtExprResult:
// FIXME: Should we lifetime-extend through the result of a statement
// expression?
return {nullptr, LK_StmtExprResult};
case InitializedEntity::EK_New:
// -- A temporary bound to a reference in a new-initializer persists
// until the completion of the full-expression containing the
// new-initializer.
return {nullptr, LK_New};
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_CompoundLiteralInit:
case InitializedEntity::EK_RelatedResult:
// We don't yet know the storage duration of the surrounding temporary.
// Assume it's got full-expression duration for now, it will patch up our
// storage duration if that's not correct.
return {nullptr, LK_FullExpression};
case InitializedEntity::EK_ArrayElement:
// For subobjects, we look at the complete object.
return getEntityLifetime(Entity->getParent(), InitField);
case InitializedEntity::EK_Base:
// For subobjects, we look at the complete object.
if (Entity->getParent())
return getEntityLifetime(Entity->getParent(), InitField);
return {InitField, LK_MemInitializer};
case InitializedEntity::EK_Delegating:
// We can reach this case for aggregate initialization in a constructor:
// struct A { int &&r; };
// struct B : A { B() : A{0} {} };
// In this case, use the outermost field decl as the context.
return {InitField, LK_MemInitializer};
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_LambdaCapture:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
return {nullptr, LK_FullExpression};
case InitializedEntity::EK_Exception:
// FIXME: Can we diagnose lifetime problems with exceptions?
return {nullptr, LK_FullExpression};
}
llvm_unreachable("unknown entity kind");
}
namespace {
enum ReferenceKind {
/// Lifetime would be extended by a reference binding to a temporary.
RK_ReferenceBinding,
/// Lifetime would be extended by a std::initializer_list object binding to
/// its backing array.
RK_StdInitializerList,
};
/// A temporary or local variable. This will be one of:
/// * A MaterializeTemporaryExpr.
/// * A DeclRefExpr whose declaration is a local.
/// * An AddrLabelExpr.
/// * A BlockExpr for a block with captures.
using Local = Expr*;
/// Expressions we stepped over when looking for the local state. Any steps
/// that would inhibit lifetime extension or take us out of subexpressions of
/// the initializer are included.
struct IndirectLocalPathEntry {
enum EntryKind {
DefaultInit,
AddressOf,
VarInit,
LValToRVal,
LifetimeBoundCall,
TemporaryCopy,
LambdaCaptureInit,
GslReferenceInit,
GslPointerInit
} Kind;
Expr *E;
union {
const Decl *D = nullptr;
const LambdaCapture *Capture;
};
IndirectLocalPathEntry() {}
IndirectLocalPathEntry(EntryKind K, Expr *E) : Kind(K), E(E) {}
IndirectLocalPathEntry(EntryKind K, Expr *E, const Decl *D)
: Kind(K), E(E), D(D) {}
IndirectLocalPathEntry(EntryKind K, Expr *E, const LambdaCapture *Capture)
: Kind(K), E(E), Capture(Capture) {}
};
using IndirectLocalPath = llvm::SmallVectorImpl<IndirectLocalPathEntry>;
struct RevertToOldSizeRAII {
IndirectLocalPath &Path;
unsigned OldSize = Path.size();
RevertToOldSizeRAII(IndirectLocalPath &Path) : Path(Path) {}
~RevertToOldSizeRAII() { Path.resize(OldSize); }
};
using LocalVisitor = llvm::function_ref<bool(IndirectLocalPath &Path, Local L,
ReferenceKind RK)>;
}
static bool isVarOnPath(IndirectLocalPath &Path, VarDecl *VD) {
for (auto E : Path)
if (E.Kind == IndirectLocalPathEntry::VarInit && E.D == VD)
return true;
return false;
}
static bool pathContainsInit(IndirectLocalPath &Path) {
return llvm::any_of(Path, [=](IndirectLocalPathEntry E) {
return E.Kind == IndirectLocalPathEntry::DefaultInit ||
E.Kind == IndirectLocalPathEntry::VarInit;
});
}
static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *Init, LocalVisitor Visit,
bool RevisitSubinits,
bool EnableLifetimeWarnings);
static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
LocalVisitor Visit,
bool EnableLifetimeWarnings);
template <typename T> static bool isRecordWithAttr(QualType Type) {
if (auto *RD = Type->getAsCXXRecordDecl())
return RD->hasAttr<T>();
return false;
}
// Decl::isInStdNamespace will return false for iterators in some STL
// implementations due to them being defined in a namespace outside of the std
// namespace.
static bool isInStlNamespace(const Decl *D) {
const DeclContext *DC = D->getDeclContext();
if (!DC)
return false;
if (const auto *ND = dyn_cast<NamespaceDecl>(DC))
if (const IdentifierInfo *II = ND->getIdentifier()) {
StringRef Name = II->getName();
if (Name.size() >= 2 && Name.front() == '_' &&
(Name[1] == '_' || isUppercase(Name[1])))
return true;
}
return DC->isStdNamespace();
}
static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()))
return true;
if (!isInStlNamespace(Callee->getParent()))
return false;
if (!isRecordWithAttr<PointerAttr>(Callee->getThisObjectType()) &&
!isRecordWithAttr<OwnerAttr>(Callee->getThisObjectType()))
return false;
if (Callee->getReturnType()->isPointerType() ||
isRecordWithAttr<PointerAttr>(Callee->getReturnType())) {
if (!Callee->getIdentifier())
return false;
return llvm::StringSwitch<bool>(Callee->getName())
.Cases("begin", "rbegin", "cbegin", "crbegin", true)
.Cases("end", "rend", "cend", "crend", true)
.Cases("c_str", "data", "get", true)
// Map and set types.
.Cases("find", "equal_range", "lower_bound", "upper_bound", true)
.Default(false);
} else if (Callee->getReturnType()->isReferenceType()) {
if (!Callee->getIdentifier()) {
auto OO = Callee->getOverloadedOperator();
return OO == OverloadedOperatorKind::OO_Subscript ||
OO == OverloadedOperatorKind::OO_Star;
}
return llvm::StringSwitch<bool>(Callee->getName())
.Cases("front", "back", "at", "top", "value", true)
.Default(false);
}
return false;
}
static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
if (!FD->getIdentifier() || FD->getNumParams() != 1)
return false;
const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl();
if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace())
return false;
if (!isRecordWithAttr<PointerAttr>(QualType(RD->getTypeForDecl(), 0)) &&
!isRecordWithAttr<OwnerAttr>(QualType(RD->getTypeForDecl(), 0)))
return false;
if (FD->getReturnType()->isPointerType() ||
isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
return llvm::StringSwitch<bool>(FD->getName())
.Cases("begin", "rbegin", "cbegin", "crbegin", true)
.Cases("end", "rend", "cend", "crend", true)
.Case("data", true)
.Default(false);
} else if (FD->getReturnType()->isReferenceType()) {
return llvm::StringSwitch<bool>(FD->getName())
.Cases("get", "any_cast", true)
.Default(false);
}
return false;
}
static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
LocalVisitor Visit) {
auto VisitPointerArg = [&](const Decl *D, Expr *Arg, bool Value) {
// We are not interested in the temporary base objects of gsl Pointers:
// Temp().ptr; // Here ptr might not dangle.
if (isa<MemberExpr>(Arg->IgnoreImpCasts()))
return;
// Once we initialized a value with a reference, it can no longer dangle.
if (!Value) {
for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) {
if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit)
continue;
if (PE.Kind == IndirectLocalPathEntry::GslPointerInit)
return;
break;
}
}
Path.push_back({Value ? IndirectLocalPathEntry::GslPointerInit
: IndirectLocalPathEntry::GslReferenceInit,
Arg, D});
if (Arg->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
Visit,
/*EnableLifetimeWarnings=*/true);
else
visitLocalsRetainedByInitializer(Path, Arg, Visit, true,
/*EnableLifetimeWarnings=*/true);
Path.pop_back();
};
if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
const auto *MD = cast_or_null<CXXMethodDecl>(MCE->getDirectCallee());
if (MD && shouldTrackImplicitObjectArg(MD))
VisitPointerArg(MD, MCE->getImplicitObjectArgument(),
!MD->getReturnType()->isReferenceType());
return;
} else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(Call)) {
FunctionDecl *Callee = OCE->getDirectCallee();
if (Callee && Callee->isCXXInstanceMember() &&
shouldTrackImplicitObjectArg(cast<CXXMethodDecl>(Callee)))
VisitPointerArg(Callee, OCE->getArg(0),
!Callee->getReturnType()->isReferenceType());
return;
} else if (auto *CE = dyn_cast<CallExpr>(Call)) {
FunctionDecl *Callee = CE->getDirectCallee();
if (Callee && shouldTrackFirstArgument(Callee))
VisitPointerArg(Callee, CE->getArg(0),
!Callee->getReturnType()->isReferenceType());
return;
}
if (auto *CCE = dyn_cast<CXXConstructExpr>(Call)) {
const auto *Ctor = CCE->getConstructor();
const CXXRecordDecl *RD = Ctor->getParent();
if (CCE->getNumArgs() > 0 && RD->hasAttr<PointerAttr>())
VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0], true);
}
}
static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
if (!TSI)
return false;
// Don't declare this variable in the second operand of the for-statement;
// GCC miscompiles that by ending its lifetime before evaluating the
// third operand. See gcc.gnu.org/PR86769.
AttributedTypeLoc ATL;
for (TypeLoc TL = TSI->getTypeLoc();
(ATL = TL.getAsAdjusted<AttributedTypeLoc>());
TL = ATL.getModifiedLoc()) {
if (ATL.getAttrAs<LifetimeBoundAttr>())
return true;
}
// Assume that all assignment operators with a "normal" return type return
// *this, that is, an lvalue reference that is the same type as the implicit
// object parameter (or the LHS for a non-member operator$=).
OverloadedOperatorKind OO = FD->getDeclName().getCXXOverloadedOperator();
if (OO == OO_Equal || isCompoundAssignmentOperator(OO)) {
QualType RetT = FD->getReturnType();
if (RetT->isLValueReferenceType()) {
ASTContext &Ctx = FD->getASTContext();
QualType LHST;
auto *MD = dyn_cast<CXXMethodDecl>(FD);
if (MD && MD->isCXXInstanceMember())
LHST = Ctx.getLValueReferenceType(MD->getThisObjectType());
else
LHST = MD->getParamDecl(0)->getType();
if (Ctx.hasSameType(RetT, LHST))
return true;
}
}
return false;
}
static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
LocalVisitor Visit) {
const FunctionDecl *Callee;
ArrayRef<Expr*> Args;
if (auto *CE = dyn_cast<CallExpr>(Call)) {
Callee = CE->getDirectCallee();
Args = llvm::makeArrayRef(CE->getArgs(), CE->getNumArgs());
} else {
auto *CCE = cast<CXXConstructExpr>(Call);
Callee = CCE->getConstructor();
Args = llvm::makeArrayRef(CCE->getArgs(), CCE->getNumArgs());
}
if (!Callee)
return;
Expr *ObjectArg = nullptr;
if (isa<CXXOperatorCallExpr>(Call) && Callee->isCXXInstanceMember()) {
ObjectArg = Args[0];
Args = Args.slice(1);
} else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
ObjectArg = MCE->getImplicitObjectArgument();
}
auto VisitLifetimeBoundArg = [&](const Decl *D, Expr *Arg) {
Path.push_back({IndirectLocalPathEntry::LifetimeBoundCall, Arg, D});
if (Arg->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
Visit,
/*EnableLifetimeWarnings=*/false);
else
visitLocalsRetainedByInitializer(Path, Arg, Visit, true,
/*EnableLifetimeWarnings=*/false);
Path.pop_back();
};
if (ObjectArg && implicitObjectParamIsLifetimeBound(Callee))
VisitLifetimeBoundArg(Callee, ObjectArg);
for (unsigned I = 0,
N = std::min<unsigned>(Callee->getNumParams(), Args.size());
I != N; ++I) {
if (Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]);
}
}
/// Visit the locals that would be reachable through a reference bound to the
/// glvalue expression \c Init.
static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
LocalVisitor Visit,
bool EnableLifetimeWarnings) {
RevertToOldSizeRAII RAII(Path);
// Walk past any constructs which we can lifetime-extend across.
Expr *Old;
do {
Old = Init;
if (auto *FE = dyn_cast<FullExpr>(Init))
Init = FE->getSubExpr();
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
// If this is just redundant braces around an initializer, step over it.
if (ILE->isTransparent())
Init = ILE->getInit(0);
}
// Step over any subobject adjustments; we may have a materialized
// temporary inside them.
Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
// Per current approach for DR1376, look through casts to reference type
// when performing lifetime extension.
if (CastExpr *CE = dyn_cast<CastExpr>(Init))
if (CE->getSubExpr()->isGLValue())
Init = CE->getSubExpr();
// Per the current approach for DR1299, look through array element access
// on array glvalues when performing lifetime extension.
if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Init)) {
Init = ASE->getBase();
auto *ICE = dyn_cast<ImplicitCastExpr>(Init);
if (ICE && ICE->getCastKind() == CK_ArrayToPointerDecay)
Init = ICE->getSubExpr();
else
// We can't lifetime extend through this but we might still find some
// retained temporaries.
return visitLocalsRetainedByInitializer(Path, Init, Visit, true,
EnableLifetimeWarnings);
}
// Step into CXXDefaultInitExprs so we can diagnose cases where a
// constructor inherits one as an implicit mem-initializer.
if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {
Path.push_back(
{IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()});
Init = DIE->getExpr();
}
} while (Init != Old);
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) {
if (Visit(Path, Local(MTE), RK))
visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit, true,
EnableLifetimeWarnings);
}
if (isa<CallExpr>(Init)) {
if (EnableLifetimeWarnings)
handleGslAnnotatedTypes(Path, Init, Visit);
return visitLifetimeBoundArguments(Path, Init, Visit);
}
switch (Init->getStmtClass()) {
case Stmt::DeclRefExprClass: {
// If we find the name of a local non-reference parameter, we could have a
// lifetime problem.
auto *DRE = cast<DeclRefExpr>(Init);
auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
if (VD && VD->hasLocalStorage() &&
!DRE->refersToEnclosingVariableOrCapture()) {
if (!VD->getType()->isReferenceType()) {
Visit(Path, Local(DRE), RK);
} else if (isa<ParmVarDecl>(DRE->getDecl())) {
// The lifetime of a reference parameter is unknown; assume it's OK
// for now.
break;
} else if (VD->getInit() && !isVarOnPath(Path, VD)) {
Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});
visitLocalsRetainedByReferenceBinding(Path, VD->getInit(),
RK_ReferenceBinding, Visit,
EnableLifetimeWarnings);
}
}
break;
}
case Stmt::UnaryOperatorClass: {
// The only unary operator that make sense to handle here
// is Deref. All others don't resolve to a "name." This includes
// handling all sorts of rvalues passed to a unary operator.
const UnaryOperator *U = cast<UnaryOperator>(Init);
if (U->getOpcode() == UO_Deref)
visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true,
EnableLifetimeWarnings);
break;
}
case Stmt::OMPArraySectionExprClass: {
visitLocalsRetainedByInitializer(Path,
cast<OMPArraySectionExpr>(Init)->getBase(),
Visit, true, EnableLifetimeWarnings);
break;
}
case Stmt::ConditionalOperatorClass:
case Stmt::BinaryConditionalOperatorClass: {
auto *C = cast<AbstractConditionalOperator>(Init);
if (!C->getTrueExpr()->getType()->isVoidType())
visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit,
EnableLifetimeWarnings);
if (!C->getFalseExpr()->getType()->isVoidType())
visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit,
EnableLifetimeWarnings);
break;
}
// FIXME: Visit the left-hand side of an -> or ->*.
default:
break;
}
}
/// Visit the locals that would be reachable through an object initialized by
/// the prvalue expression \c Init.
static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *Init, LocalVisitor Visit,
bool RevisitSubinits,
bool EnableLifetimeWarnings) {
RevertToOldSizeRAII RAII(Path);
Expr *Old;
do {
Old = Init;
// Step into CXXDefaultInitExprs so we can diagnose cases where a
// constructor inherits one as an implicit mem-initializer.
if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {
Path.push_back({IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()});
Init = DIE->getExpr();
}
if (auto *FE = dyn_cast<FullExpr>(Init))
Init = FE->getSubExpr();
// Dig out the expression which constructs the extended temporary.
Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))
Init = BTE->getSubExpr();
Init = Init->IgnoreParens();
// Step over value-preserving rvalue casts.
if (auto *CE = dyn_cast<CastExpr>(Init)) {
switch (CE->getCastKind()) {
case CK_LValueToRValue:
// If we can match the lvalue to a const object, we can look at its
// initializer.
Path.push_back({IndirectLocalPathEntry::LValToRVal, CE});
return visitLocalsRetainedByReferenceBinding(
Path, Init, RK_ReferenceBinding,
[&](IndirectLocalPath &Path, Local L, ReferenceKind RK) -> bool {
if (auto *DRE = dyn_cast<DeclRefExpr>(L)) {
auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
if (VD && VD->getType().isConstQualified() && VD->getInit() &&
!isVarOnPath(Path, VD)) {
Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});
visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true,
EnableLifetimeWarnings);
}
} else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) {
if (MTE->getType().isConstQualified())
visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit,
true, EnableLifetimeWarnings);
}
return false;
}, EnableLifetimeWarnings);
// We assume that objects can be retained by pointers cast to integers,
// but not if the integer is cast to floating-point type or to _Complex.
// We assume that casts to 'bool' do not preserve enough information to
// retain a local object.
case CK_NoOp:
case CK_BitCast:
case CK_BaseToDerived:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
case CK_Dynamic:
case CK_ToUnion:
case CK_UserDefinedConversion:
case CK_ConstructorConversion:
case CK_IntegralToPointer:
case CK_PointerToIntegral:
case CK_VectorSplat:
case CK_IntegralCast:
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_AddressSpaceConversion:
break;
case CK_ArrayToPointerDecay:
// Model array-to-pointer decay as taking the address of the array
// lvalue.
Path.push_back({IndirectLocalPathEntry::AddressOf, CE});
return visitLocalsRetainedByReferenceBinding(Path, CE->getSubExpr(),
RK_ReferenceBinding, Visit,
EnableLifetimeWarnings);
default:
return;
}
Init = CE->getSubExpr();
}
} while (Old != Init);
// C++17 [dcl.init.list]p6:
// initializing an initializer_list object from the array extends the
// lifetime of the array exactly like binding a reference to a temporary.
if (auto *ILE = dyn_cast<CXXStdInitializerListExpr>(Init))
return visitLocalsRetainedByReferenceBinding(Path, ILE->getSubExpr(),
RK_StdInitializerList, Visit,
EnableLifetimeWarnings);
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
// We already visited the elements of this initializer list while
// performing the initialization. Don't visit them again unless we've
// changed the lifetime of the initialized entity.
if (!RevisitSubinits)
return;
if (ILE->isTransparent())
return visitLocalsRetainedByInitializer(Path, ILE->getInit(0), Visit,
RevisitSubinits,
EnableLifetimeWarnings);
if (ILE->getType()->isArrayType()) {
for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)
visitLocalsRetainedByInitializer(Path, ILE->getInit(I), Visit,
RevisitSubinits,
EnableLifetimeWarnings);
return;
}
if (CXXRecordDecl *RD = ILE->getType()->getAsCXXRecordDecl()) {
assert(RD->isAggregate() && "aggregate init on non-aggregate");
// If we lifetime-extend a braced initializer which is initializing an
// aggregate, and that aggregate contains reference members which are
// bound to temporaries, those temporaries are also lifetime-extended.
if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&
ILE->getInitializedFieldInUnion()->getType()->isReferenceType())
visitLocalsRetainedByReferenceBinding(Path, ILE->getInit(0),
RK_ReferenceBinding, Visit,
EnableLifetimeWarnings);
else {
unsigned Index = 0;
for (; Index < RD->getNumBases() && Index < ILE->getNumInits(); ++Index)
visitLocalsRetainedByInitializer(Path, ILE->getInit(Index), Visit,
RevisitSubinits,
EnableLifetimeWarnings);
for (const auto *I : RD->fields()) {
if (Index >= ILE->getNumInits())
break;
if (I->isUnnamedBitfield())
continue;
Expr *SubInit = ILE->getInit(Index);
if (I->getType()->isReferenceType())
visitLocalsRetainedByReferenceBinding(Path, SubInit,
RK_ReferenceBinding, Visit,
EnableLifetimeWarnings);
else
// This might be either aggregate-initialization of a member or
// initialization of a std::initializer_list object. Regardless,
// we should recursively lifetime-extend that initializer.
visitLocalsRetainedByInitializer(Path, SubInit, Visit,
RevisitSubinits,
EnableLifetimeWarnings);
++Index;
}
}
}
return;
}
// The lifetime of an init-capture is that of the closure object constructed
// by a lambda-expression.
if (auto *LE = dyn_cast<LambdaExpr>(Init)) {
LambdaExpr::capture_iterator CapI = LE->capture_begin();
for (Expr *E : LE->capture_inits()) {
assert(CapI != LE->capture_end());
const LambdaCapture &Cap = *CapI++;
if (!E)
continue;
if (Cap.capturesVariable())
Path.push_back({IndirectLocalPathEntry::LambdaCaptureInit, E, &Cap});
if (E->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, E, RK_ReferenceBinding,
Visit, EnableLifetimeWarnings);
else
visitLocalsRetainedByInitializer(Path, E, Visit, true,
EnableLifetimeWarnings);
if (Cap.capturesVariable())
Path.pop_back();
}
}
// Assume that a copy or move from a temporary references the same objects
// that the temporary does.
if (auto *CCE = dyn_cast<CXXConstructExpr>(Init)) {
if (CCE->getConstructor()->isCopyOrMoveConstructor()) {
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(CCE->getArg(0))) {
Expr *Arg = MTE->getSubExpr();
Path.push_back({IndirectLocalPathEntry::TemporaryCopy, Arg,
CCE->getConstructor()});
visitLocalsRetainedByInitializer(Path, Arg, Visit, true,
/*EnableLifetimeWarnings*/false);
Path.pop_back();
}
}
}
if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init)) {
if (EnableLifetimeWarnings)
handleGslAnnotatedTypes(Path, Init, Visit);
return visitLifetimeBoundArguments(Path, Init, Visit);
}
switch (Init->getStmtClass()) {
case Stmt::UnaryOperatorClass: {
auto *UO = cast<UnaryOperator>(Init);
// If the initializer is the address of a local, we could have a lifetime
// problem.
if (UO->getOpcode() == UO_AddrOf) {
// If this is &rvalue, then it's ill-formed and we have already diagnosed
// it. Don't produce a redundant warning about the lifetime of the
// temporary.
if (isa<MaterializeTemporaryExpr>(UO->getSubExpr()))
return;
Path.push_back({IndirectLocalPathEntry::AddressOf, UO});
visitLocalsRetainedByReferenceBinding(Path, UO->getSubExpr(),
RK_ReferenceBinding, Visit,
EnableLifetimeWarnings);
}
break;
}
case Stmt::BinaryOperatorClass: {
// Handle pointer arithmetic.
auto *BO = cast<BinaryOperator>(Init);
BinaryOperatorKind BOK = BO->getOpcode();
if (!BO->getType()->isPointerType() || (BOK != BO_Add && BOK != BO_Sub))
break;
if (BO->getLHS()->getType()->isPointerType())
visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true,
EnableLifetimeWarnings);
else if (BO->getRHS()->getType()->isPointerType())
visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true,
EnableLifetimeWarnings);
break;
}
case Stmt::ConditionalOperatorClass:
case Stmt::BinaryConditionalOperatorClass: {
auto *C = cast<AbstractConditionalOperator>(Init);
// In C++, we can have a throw-expression operand, which has 'void' type
// and isn't interesting from a lifetime perspective.
if (!C->getTrueExpr()->getType()->isVoidType())
visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true,
EnableLifetimeWarnings);
if (!C->getFalseExpr()->getType()->isVoidType())
visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true,
EnableLifetimeWarnings);
break;
}
case Stmt::BlockExprClass:
if (cast<BlockExpr>(Init)->getBlockDecl()->hasCaptures()) {
// This is a local block, whose lifetime is that of the function.
Visit(Path, Local(cast<BlockExpr>(Init)), RK_ReferenceBinding);
}
break;
case Stmt::AddrLabelExprClass:
// We want to warn if the address of a label would escape the function.
Visit(Path, Local(cast<AddrLabelExpr>(Init)), RK_ReferenceBinding);
break;
default:
break;
}
}
/// Whether a path to an object supports lifetime extension.
enum PathLifetimeKind {
/// Lifetime-extend along this path.
Extend,
/// We should lifetime-extend, but we don't because (due to technical
/// limitations) we can't. This happens for default member initializers,
/// which we don't clone for every use, so we don't have a unique
/// MaterializeTemporaryExpr to update.
ShouldExtend,
/// Do not lifetime extend along this path.
NoExtend
};
/// Determine whether this is an indirect path to a temporary that we are
/// supposed to lifetime-extend along.
static PathLifetimeKind
shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) {
PathLifetimeKind Kind = PathLifetimeKind::Extend;
for (auto Elem : Path) {
if (Elem.Kind == IndirectLocalPathEntry::DefaultInit)
Kind = PathLifetimeKind::ShouldExtend;
else if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit)
return PathLifetimeKind::NoExtend;
}
return Kind;
}
/// Find the range for the first interesting entry in the path at or after I.
static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
Expr *E) {
for (unsigned N = Path.size(); I != N; ++I) {
switch (Path[I].Kind) {
case IndirectLocalPathEntry::AddressOf:
case IndirectLocalPathEntry::LValToRVal:
case IndirectLocalPathEntry::LifetimeBoundCall:
case IndirectLocalPathEntry::TemporaryCopy:
case IndirectLocalPathEntry::GslReferenceInit:
case IndirectLocalPathEntry::GslPointerInit:
// These exist primarily to mark the path as not permitting or
// supporting lifetime extension.
break;
case IndirectLocalPathEntry::VarInit:
if (cast<VarDecl>(Path[I].D)->isImplicit())
return SourceRange();
LLVM_FALLTHROUGH;
case IndirectLocalPathEntry::DefaultInit:
return Path[I].E->getSourceRange();
case IndirectLocalPathEntry::LambdaCaptureInit:
if (!Path[I].Capture->capturesVariable())
continue;
return Path[I].E->getSourceRange();
}
}
return E->getSourceRange();
}
static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) {
for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) {
if (It->Kind == IndirectLocalPathEntry::VarInit)
continue;
if (It->Kind == IndirectLocalPathEntry::AddressOf)
continue;
if (It->Kind == IndirectLocalPathEntry::LifetimeBoundCall)
continue;
return It->Kind == IndirectLocalPathEntry::GslPointerInit ||
It->Kind == IndirectLocalPathEntry::GslReferenceInit;
}
return false;
}
void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
Expr *Init) {
LifetimeResult LR = getEntityLifetime(&Entity);
LifetimeKind LK = LR.getInt();
const InitializedEntity *ExtendingEntity = LR.getPointer();
// If this entity doesn't have an interesting lifetime, don't bother looking
// for temporaries within its initializer.
if (LK == LK_FullExpression)
return;
auto TemporaryVisitor = [&](IndirectLocalPath &Path, Local L,
ReferenceKind RK) -> bool {
SourceRange DiagRange = nextPathEntryRange(Path, 0, L);
SourceLocation DiagLoc = DiagRange.getBegin();
auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
bool IsGslPtrInitWithGslTempOwner = false;
bool IsLocalGslOwner = false;
if (pathOnlyInitializesGslPointer(Path)) {
if (isa<DeclRefExpr>(L)) {
// We do not want to follow the references when returning a pointer originating
// from a local owner to avoid the following false positive:
// int &p = *localUniquePtr;
// someContainer.add(std::move(localUniquePtr));
// return p;
IsLocalGslOwner = isRecordWithAttr<OwnerAttr>(L->getType());
if (pathContainsInit(Path) || !IsLocalGslOwner)
return false;
} else {
IsGslPtrInitWithGslTempOwner = MTE && !MTE->getExtendingDecl() &&
isRecordWithAttr<OwnerAttr>(MTE->getType());
// Skipping a chain of initializing gsl::Pointer annotated objects.
// We are looking only for the final source to find out if it was
// a local or temporary owner or the address of a local variable/param.
if (!IsGslPtrInitWithGslTempOwner)
return true;
}
}
switch (LK) {
case LK_FullExpression:
llvm_unreachable("already handled this");
case LK_Extended: {
if (!MTE) {
// The initialized entity has lifetime beyond the full-expression,
// and the local entity does too, so don't warn.
//
// FIXME: We should consider warning if a static / thread storage
// duration variable retains an automatic storage duration local.
return false;
}
if (IsGslPtrInitWithGslTempOwner && DiagLoc.isValid()) {
Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange;
return false;
}
switch (shouldLifetimeExtendThroughPath(Path)) {
case PathLifetimeKind::Extend:
// Update the storage duration of the materialized temporary.
// FIXME: Rebuild the expression instead of mutating it.
MTE->setExtendingDecl(ExtendingEntity->getDecl(),
ExtendingEntity->allocateManglingNumber());
// Also visit the temporaries lifetime-extended by this initializer.
return true;
case PathLifetimeKind::ShouldExtend:
// We're supposed to lifetime-extend the temporary along this path (per
// the resolution of DR1815), but we don't support that yet.
//
// FIXME: Properly handle this situation. Perhaps the easiest approach
// would be to clone the initializer expression on each use that would
// lifetime extend its temporaries.
Diag(DiagLoc, diag::warn_unsupported_lifetime_extension)
<< RK << DiagRange;
break;
case PathLifetimeKind::NoExtend:
// If the path goes through the initialization of a variable or field,
// it can't possibly reach a temporary created in this full-expression.
// We will have already diagnosed any problems with the initializer.
if (pathContainsInit(Path))
return false;
Diag(DiagLoc, diag::warn_dangling_variable)
<< RK << !Entity.getParent()
<< ExtendingEntity->getDecl()->isImplicit()
<< ExtendingEntity->getDecl() << Init->isGLValue() << DiagRange;
break;
}
break;
}
case LK_MemInitializer: {
if (isa<MaterializeTemporaryExpr>(L)) {
// Under C++ DR1696, if a mem-initializer (or a default member
// initializer used by the absence of one) would lifetime-extend a
// temporary, the program is ill-formed.
if (auto *ExtendingDecl =
ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {
if (IsGslPtrInitWithGslTempOwner) {
Diag(DiagLoc, diag::warn_dangling_lifetime_pointer_member)
<< ExtendingDecl << DiagRange;
Diag(ExtendingDecl->getLocation(),
diag::note_ref_or_ptr_member_declared_here)
<< true;
return false;
}
bool IsSubobjectMember = ExtendingEntity != &Entity;
Diag(DiagLoc, shouldLifetimeExtendThroughPath(Path) !=
PathLifetimeKind::NoExtend
? diag::err_dangling_member
: diag::warn_dangling_member)
<< ExtendingDecl << IsSubobjectMember << RK << DiagRange;
// Don't bother adding a note pointing to the field if we're inside
// its default member initializer; our primary diagnostic points to
// the same place in that case.
if (Path.empty() ||
Path.back().Kind != IndirectLocalPathEntry::DefaultInit) {
Diag(ExtendingDecl->getLocation(),
diag::note_lifetime_extending_member_declared_here)
<< RK << IsSubobjectMember;
}
} else {
// We have a mem-initializer but no particular field within it; this
// is either a base class or a delegating initializer directly
// initializing the base-class from something that doesn't live long
// enough.
//
// FIXME: Warn on this.
return false;
}
} else {
// Paths via a default initializer can only occur during error recovery
// (there's no other way that a default initializer can refer to a
// local). Don't produce a bogus warning on those cases.
if (pathContainsInit(Path))
return false;
// Suppress false positives for code like the one below:
// Ctor(unique_ptr<T> up) : member(*up), member2(move(up)) {}
if (IsLocalGslOwner && pathOnlyInitializesGslPointer(Path))
return false;
auto *DRE = dyn_cast<DeclRefExpr>(L);
auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr;
if (!VD) {
// A member was initialized to a local block.
// FIXME: Warn on this.
return false;
}
if (auto *Member =
ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {
bool IsPointer = !Member->getType()->isReferenceType();
Diag(DiagLoc, IsPointer ? diag::warn_init_ptr_member_to_parameter_addr
: diag::warn_bind_ref_member_to_parameter)
<< Member << VD << isa<ParmVarDecl>(VD) << DiagRange;
Diag(Member->getLocation(),
diag::note_ref_or_ptr_member_declared_here)
<< (unsigned)IsPointer;
}
}
break;
}
case LK_New:
if (isa<MaterializeTemporaryExpr>(L)) {
if (IsGslPtrInitWithGslTempOwner)
Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange;
else
Diag(DiagLoc, RK == RK_ReferenceBinding
? diag::warn_new_dangling_reference
: diag::warn_new_dangling_initializer_list)
<< !Entity.getParent() << DiagRange;
} else {
// We can't determine if the allocation outlives the local declaration.
return false;
}
break;
case LK_Return:
case LK_StmtExprResult:
if (auto *DRE = dyn_cast<DeclRefExpr>(L)) {
// We can't determine if the local variable outlives the statement
// expression.
if (LK == LK_StmtExprResult)
return false;
Diag(DiagLoc, diag::warn_ret_stack_addr_ref)
<< Entity.getType()->isReferenceType() << DRE->getDecl()
<< isa<ParmVarDecl>(DRE->getDecl()) << DiagRange;
} else if (isa<BlockExpr>(L)) {
Diag(DiagLoc, diag::err_ret_local_block) << DiagRange;
} else if (isa<AddrLabelExpr>(L)) {
// Don't warn when returning a label from a statement expression.
// Leaving the scope doesn't end its lifetime.
if (LK == LK_StmtExprResult)
return false;
Diag(DiagLoc, diag::warn_ret_addr_label) << DiagRange;
} else {
Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref)
<< Entity.getType()->isReferenceType() << DiagRange;
}
break;
}
for (unsigned I = 0; I != Path.size(); ++I) {
auto Elem = Path[I];
switch (Elem.Kind) {
case IndirectLocalPathEntry::AddressOf:
case IndirectLocalPathEntry::LValToRVal:
// These exist primarily to mark the path as not permitting or
// supporting lifetime extension.
break;
case IndirectLocalPathEntry::LifetimeBoundCall:
case IndirectLocalPathEntry::TemporaryCopy:
case IndirectLocalPathEntry::GslPointerInit:
case IndirectLocalPathEntry::GslReferenceInit:
// FIXME: Consider adding a note for these.
break;
case IndirectLocalPathEntry::DefaultInit: {
auto *FD = cast<FieldDecl>(Elem.D);
Diag(FD->getLocation(), diag::note_init_with_default_member_initalizer)
<< FD << nextPathEntryRange(Path, I + 1, L);
break;
}
case IndirectLocalPathEntry::VarInit: {
const VarDecl *VD = cast<VarDecl>(Elem.D);
Diag(VD->getLocation(), diag::note_local_var_initializer)
<< VD->getType()->isReferenceType()
<< VD->isImplicit() << VD->getDeclName()
<< nextPathEntryRange(Path, I + 1, L);
break;
}
case IndirectLocalPathEntry::LambdaCaptureInit:
if (!Elem.Capture->capturesVariable())
break;
// FIXME: We can't easily tell apart an init-capture from a nested
// capture of an init-capture.
const VarDecl *VD = Elem.Capture->getCapturedVar();
Diag(Elem.Capture->getLocation(), diag::note_lambda_capture_initializer)
<< VD << VD->isInitCapture() << Elem.Capture->isExplicit()
<< (Elem.Capture->getCaptureKind() == LCK_ByRef) << VD
<< nextPathEntryRange(Path, I + 1, L);
break;
}
}
// We didn't lifetime-extend, so don't go any further; we don't need more
// warnings or errors on inner temporaries within this one's initializer.
return false;
};
bool EnableLifetimeWarnings = !getDiagnostics().isIgnored(
diag::warn_dangling_lifetime_pointer, SourceLocation());
llvm::SmallVector<IndirectLocalPathEntry, 8> Path;
if (Init->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding,
TemporaryVisitor,
EnableLifetimeWarnings);
else
visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false,
EnableLifetimeWarnings);
}
static void DiagnoseNarrowingInInitList(Sema &S,
const ImplicitConversionSequence &ICS,
QualType PreNarrowingType,
QualType EntityType,
const Expr *PostInit);
/// Provide warnings when std::move is used on construction.
static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr,
bool IsReturnStmt) {
if (!InitExpr)
return;
if (S.inTemplateInstantiation())
return;
QualType DestType = InitExpr->getType();
if (!DestType->isRecordType())
return;
unsigned DiagID = 0;
if (IsReturnStmt) {
const CXXConstructExpr *CCE =
dyn_cast<CXXConstructExpr>(InitExpr->IgnoreParens());
if (!CCE || CCE->getNumArgs() != 1)
return;
if (!CCE->getConstructor()->isCopyOrMoveConstructor())
return;
InitExpr = CCE->getArg(0)->IgnoreImpCasts();
}
// Find the std::move call and get the argument.
const CallExpr *CE = dyn_cast<CallExpr>(InitExpr->IgnoreParens());
if (!CE || !CE->isCallToStdMove())
return;
const Expr *Arg = CE->getArg(0)->IgnoreImplicit();
if (IsReturnStmt) {
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenImpCasts());
if (!DRE || DRE->refersToEnclosingVariableOrCapture())
return;
const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
if (!VD || !VD->hasLocalStorage())
return;
// __block variables are not moved implicitly.
if (VD->hasAttr<BlocksAttr>())
return;
QualType SourceType = VD->getType();
if (!SourceType->isRecordType())
return;
if (!S.Context.hasSameUnqualifiedType(DestType, SourceType)) {
return;
}
// If we're returning a function parameter, copy elision
// is not possible.
if (isa<ParmVarDecl>(VD))
DiagID = diag::warn_redundant_move_on_return;
else
DiagID = diag::warn_pessimizing_move_on_return;
} else {
DiagID = diag::warn_pessimizing_move_on_initialization;
const Expr *ArgStripped = Arg->IgnoreImplicit()->IgnoreParens();
if (!ArgStripped->isPRValue() || !ArgStripped->getType()->isRecordType())
return;
}
S.Diag(CE->getBeginLoc(), DiagID);
// Get all the locations for a fix-it. Don't emit the fix-it if any location
// is within a macro.
SourceLocation CallBegin = CE->getCallee()->getBeginLoc();
if (CallBegin.isMacroID())
return;
SourceLocation RParen = CE->getRParenLoc();
if (RParen.isMacroID())
return;
SourceLocation LParen;
SourceLocation ArgLoc = Arg->getBeginLoc();
// Special testing for the argument location. Since the fix-it needs the
// location right before the argument, the argument location can be in a
// macro only if it is at the beginning of the macro.
while (ArgLoc.isMacroID() &&
S.getSourceManager().isAtStartOfImmediateMacroExpansion(ArgLoc)) {
ArgLoc = S.getSourceManager().getImmediateExpansionRange(ArgLoc).getBegin();
}
if (LParen.isMacroID())
return;
LParen = ArgLoc.getLocWithOffset(-1);
S.Diag(CE->getBeginLoc(), diag::note_remove_move)
<< FixItHint::CreateRemoval(SourceRange(CallBegin, LParen))
<< FixItHint::CreateRemoval(SourceRange(RParen, RParen));
}
static void CheckForNullPointerDereference(Sema &S, const Expr *E) {
// Check to see if we are dereferencing a null pointer. If so, this is
// undefined behavior, so warn about it. This only handles the pattern
// "*null", which is a very syntactic check.
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts()))
if (UO->getOpcode() == UO_Deref &&
UO->getSubExpr()->IgnoreParenCasts()->
isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) {
S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
S.PDiag(diag::warn_binding_null_to_reference)
<< UO->getSubExpr()->getSourceRange());
}
}
MaterializeTemporaryExpr *
Sema::CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary,
bool BoundToLvalueReference) {
auto MTE = new (Context)
MaterializeTemporaryExpr(T, Temporary, BoundToLvalueReference);
// Order an ExprWithCleanups for lifetime marks.
//
// TODO: It'll be good to have a single place to check the access of the
// destructor and generate ExprWithCleanups for various uses. Currently these
// are done in both CreateMaterializeTemporaryExpr and MaybeBindToTemporary,
// but there may be a chance to merge them.
Cleanup.setExprNeedsCleanups(false);
return MTE;
}
ExprResult Sema::TemporaryMaterializationConversion(Expr *E) {
// In C++98, we don't want to implicitly create an xvalue.
// FIXME: This means that AST consumers need to deal with "prvalues" that
// denote materialized temporaries. Maybe we should add another ValueKind
// for "xvalue pretending to be a prvalue" for C++98 support.
if (!E->isPRValue() || !getLangOpts().CPlusPlus11)
return E;
// C++1z [conv.rval]/1: T shall be a complete type.
// FIXME: Does this ever matter (can we form a prvalue of incomplete type)?
// If so, we should check for a non-abstract class type here too.
QualType T = E->getType();
if (RequireCompleteType(E->getExprLoc(), T, diag::err_incomplete_type))
return ExprError();
return CreateMaterializeTemporaryExpr(E->getType(), E, false);
}
ExprResult Sema::PerformQualificationConversion(Expr *E, QualType Ty,
ExprValueKind VK,
CheckedConversionKind CCK) {
CastKind CK = CK_NoOp;
if (VK == VK_PRValue) {
auto PointeeTy = Ty->getPointeeType();
auto ExprPointeeTy = E->getType()->getPointeeType();
if (!PointeeTy.isNull() &&
PointeeTy.getAddressSpace() != ExprPointeeTy.getAddressSpace())
CK = CK_AddressSpaceConversion;
} else if (Ty.getAddressSpace() != E->getType().getAddressSpace()) {
CK = CK_AddressSpaceConversion;
}
return ImpCastExprToType(E, Ty, CK, VK, /*BasePath=*/nullptr, CCK);
}
ExprResult InitializationSequence::Perform(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
MultiExprArg Args,
QualType *ResultType) {
if (Failed()) {
Diagnose(S, Entity, Kind, Args);
return ExprError();
}
if (!ZeroInitializationFixit.empty()) {
unsigned DiagID = diag::err_default_init_const;
if (Decl *D = Entity.getDecl())
if (S.getLangOpts().MSVCCompat && D->hasAttr<SelectAnyAttr>())
DiagID = diag::ext_default_init_const;
// The initialization would have succeeded with this fixit. Since the fixit
// is on the error, we need to build a valid AST in this case, so this isn't
// handled in the Failed() branch above.
QualType DestType = Entity.getType();
S.Diag(Kind.getLocation(), DiagID)
<< DestType << (bool)DestType->getAs<RecordType>()
<< FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
ZeroInitializationFixit);
}
if (getKind() == DependentSequence) {
// If the declaration is a non-dependent, incomplete array type
// that has an initializer, then its type will be completed once
// the initializer is instantiated.
if (ResultType && !Entity.getType()->isDependentType() &&
Args.size() == 1) {
QualType DeclType = Entity.getType();
if (const IncompleteArrayType *ArrayT
= S.Context.getAsIncompleteArrayType(DeclType)) {
// FIXME: We don't currently have the ability to accurately
// compute the length of an initializer list without
// performing full type-checking of the initializer list
// (since we have to determine where braces are implicitly
// introduced and such). So, we fall back to making the array
// type a dependently-sized array type with no specified
// bound.
if (isa<InitListExpr>((Expr *)Args[0])) {
SourceRange Brackets;
// Scavange the location of the brackets from the entity, if we can.
if (auto *DD = dyn_cast_or_null<DeclaratorDecl>(Entity.getDecl())) {
if (TypeSourceInfo *TInfo = DD->getTypeSourceInfo()) {
TypeLoc TL = TInfo->getTypeLoc();
if (IncompleteArrayTypeLoc ArrayLoc =
TL.getAs<IncompleteArrayTypeLoc>())
Brackets = ArrayLoc.getBracketsRange();
}
}
*ResultType
= S.Context.getDependentSizedArrayType(ArrayT->getElementType(),
/*NumElts=*/nullptr,
ArrayT->getSizeModifier(),
ArrayT->getIndexTypeCVRQualifiers(),
Brackets);
}
}
}
if (Kind.getKind() == InitializationKind::IK_Direct &&
!Kind.isExplicitCast()) {
// Rebuild the ParenListExpr.
SourceRange ParenRange = Kind.getParenOrBraceRange();
return S.ActOnParenListExpr(ParenRange.getBegin(), ParenRange.getEnd(),
Args);
}
assert(Kind.getKind() == InitializationKind::IK_Copy ||
Kind.isExplicitCast() ||
Kind.getKind() == InitializationKind::IK_DirectList);
return ExprResult(Args[0]);
}
// No steps means no initialization.
if (Steps.empty())
return ExprResult((Expr *)nullptr);
if (S.getLangOpts().CPlusPlus11 && Entity.getType()->isReferenceType() &&
Args.size() == 1 && isa<InitListExpr>(Args[0]) &&
!Entity.isParamOrTemplateParamKind()) {
// Produce a C++98 compatibility warning if we are initializing a reference
// from an initializer list. For parameters, we produce a better warning
// elsewhere.
Expr *Init = Args[0];
S.Diag(Init->getBeginLoc(), diag::warn_cxx98_compat_reference_list_init)
<< Init->getSourceRange();
}
// OpenCL v2.0 s6.13.11.1. atomic variables can be initialized in global scope
QualType ETy = Entity.getType();
bool HasGlobalAS = ETy.hasAddressSpace() &&
ETy.getAddressSpace() == LangAS::opencl_global;
if (S.getLangOpts().OpenCLVersion >= 200 &&
ETy->isAtomicType() && !HasGlobalAS &&
Entity.getKind() == InitializedEntity::EK_Variable && Args.size() > 0) {
S.Diag(Args[0]->getBeginLoc(), diag::err_opencl_atomic_init)
<< 1
<< SourceRange(Entity.getDecl()->getBeginLoc(), Args[0]->getEndLoc());
return ExprError();
}
QualType DestType = Entity.getType().getNonReferenceType();
// FIXME: Ugly hack around the fact that Entity.getType() is not
// the same as Entity.getDecl()->getType() in cases involving type merging,
// and we want latter when it makes sense.
if (ResultType)
*ResultType = Entity.getDecl() ? Entity.getDecl()->getType() :
Entity.getType();
ExprResult CurInit((Expr *)nullptr);
SmallVector<Expr*, 4> ArrayLoopCommonExprs;
// HLSL allows vector initialization to function like list initialization, but
// use the syntax of a C++-like constructor.
bool IsHLSLVectorInit = S.getLangOpts().HLSL && DestType->isExtVectorType() &&
isa<InitListExpr>(Args[0]);
(void)IsHLSLVectorInit;
// For initialization steps that start with a single initializer,
// grab the only argument out the Args and place it into the "current"
// initializer.
switch (Steps.front().Kind) {
case SK_ResolveAddressOfOverloadedFunction:
case SK_CastDerivedToBasePRValue:
case SK_CastDerivedToBaseXValue:
case SK_CastDerivedToBaseLValue:
case SK_BindReference:
case SK_BindReferenceToTemporary:
case SK_FinalCopy:
case SK_ExtraneousCopyToTemporary:
case SK_UserConversion:
case SK_QualificationConversionLValue:
case SK_QualificationConversionXValue:
case SK_QualificationConversionPRValue:
case SK_FunctionReferenceConversion:
case SK_AtomicConversion:
case SK_ConversionSequence:
case SK_ConversionSequenceNoNarrowing:
case SK_ListInitialization:
case SK_UnwrapInitList:
case SK_RewrapInitList:
case SK_CAssignment:
case SK_StringInit:
case SK_ObjCObjectConversion:
case SK_ArrayLoopIndex:
case SK_ArrayLoopInit:
case SK_ArrayInit:
case SK_GNUArrayInit:
case SK_ParenthesizedArrayInit:
case SK_PassByIndirectCopyRestore:
case SK_PassByIndirectRestore:
case SK_ProduceObjCObject:
case SK_StdInitializerList:
case SK_OCLSamplerInit:
case SK_OCLZeroOpaqueType: {
assert(Args.size() == 1 || IsHLSLVectorInit);
CurInit = Args[0];
if (!CurInit.get()) return ExprError();
break;
}
case SK_ConstructorInitialization:
case SK_ConstructorInitializationFromList:
case SK_StdInitializerListConstructorCall:
case SK_ZeroInitialization:
break;
}
// Promote from an unevaluated context to an unevaluated list context in
// C++11 list-initialization; we need to instantiate entities usable in
// constant expressions here in order to perform narrowing checks =(
EnterExpressionEvaluationContext Evaluated(
S, EnterExpressionEvaluationContext::InitList,
CurInit.get() && isa<InitListExpr>(CurInit.get()));
// C++ [class.abstract]p2:
// no objects of an abstract class can be created except as subobjects
// of a class derived from it
auto checkAbstractType = [&](QualType T) -> bool {
if (Entity.getKind() == InitializedEntity::EK_Base ||
Entity.getKind() == InitializedEntity::EK_Delegating)
return false;
return S.RequireNonAbstractType(Kind.getLocation(), T,
diag::err_allocation_of_abstract_type);
};
// Walk through the computed steps for the initialization sequence,
// performing the specified conversions along the way.
bool ConstructorInitRequiresZeroInit = false;
for (step_iterator Step = step_begin(), StepEnd = step_end();
Step != StepEnd; ++Step) {
if (CurInit.isInvalid())
return ExprError();
QualType SourceType = CurInit.get() ? CurInit.get()->getType() : QualType();
switch (Step->Kind) {
case SK_ResolveAddressOfOverloadedFunction:
// Overload resolution determined which function invoke; update the
// initializer to reflect that choice.
S.CheckAddressOfMemberAccess(CurInit.get(), Step->Function.FoundDecl);
if (S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation()))
return ExprError();
CurInit = S.FixOverloadedFunctionReference(CurInit,
Step->Function.FoundDecl,
Step->Function.Function);
// We might get back another placeholder expression if we resolved to a
// builtin.
if (!CurInit.isInvalid())
CurInit = S.CheckPlaceholderExpr(CurInit.get());
break;
case SK_CastDerivedToBasePRValue:
case SK_CastDerivedToBaseXValue:
case SK_CastDerivedToBaseLValue: {
// We have a derived-to-base cast that produces either an rvalue or an
// lvalue. Perform that cast.
CXXCastPath BasePath;
// Casts to inaccessible base classes are allowed with C-style casts.
bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast();
if (S.CheckDerivedToBaseConversion(
SourceType, Step->Type, CurInit.get()->getBeginLoc(),
CurInit.get()->getSourceRange(), &BasePath, IgnoreBaseAccess))
return ExprError();
ExprValueKind VK =
Step->Kind == SK_CastDerivedToBaseLValue
? VK_LValue
: (Step->Kind == SK_CastDerivedToBaseXValue ? VK_XValue
: VK_PRValue);
CurInit = ImplicitCastExpr::Create(S.Context, Step->Type,
CK_DerivedToBase, CurInit.get(),
&BasePath, VK, FPOptionsOverride());
break;
}
case SK_BindReference:
// Reference binding does not have any corresponding ASTs.
// Check exception specifications
if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
// We don't check for e.g. function pointers here, since address
// availability checks should only occur when the function first decays
// into a pointer or reference.
if (CurInit.get()->getType()->isFunctionProtoType()) {
if (auto *DRE = dyn_cast<DeclRefExpr>(CurInit.get()->IgnoreParens())) {
if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
if (!S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
DRE->getBeginLoc()))
return ExprError();
}
}
}
CheckForNullPointerDereference(S, CurInit.get());
break;
case SK_BindReferenceToTemporary: {
// Make sure the "temporary" is actually an rvalue.
assert(CurInit.get()->isPRValue() && "not a temporary");
// Check exception specifications
if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
QualType MTETy = Step->Type;
// When this is an incomplete array type (such as when this is
// initializing an array of unknown bounds from an init list), use THAT
// type instead so that we propagate the array bounds.
if (MTETy->isIncompleteArrayType() &&
!CurInit.get()->getType()->isIncompleteArrayType() &&
S.Context.hasSameType(
MTETy->getPointeeOrArrayElementType(),
CurInit.get()->getType()->getPointeeOrArrayElementType()))
MTETy = CurInit.get()->getType();
// Materialize the temporary into memory.
MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr(
MTETy, CurInit.get(), Entity.getType()->isLValueReferenceType());
CurInit = MTE;
// If we're extending this temporary to automatic storage duration -- we
// need to register its cleanup during the full-expression's cleanups.
if (MTE->getStorageDuration() == SD_Automatic &&
MTE->getType().isDestructedType())
S.Cleanup.setExprNeedsCleanups(true);
break;
}
case SK_FinalCopy:
if (checkAbstractType(Step->Type))
return ExprError();
// If the overall initialization is initializing a temporary, we already
// bound our argument if it was necessary to do so. If not (if we're
// ultimately initializing a non-temporary), our argument needs to be
// bound since it's initializing a function parameter.
// FIXME: This is a mess. Rationalize temporary destruction.
if (!shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.get());
CurInit = CopyObject(S, Step->Type, Entity, CurInit,
/*IsExtraneousCopy=*/false);
break;
case SK_ExtraneousCopyToTemporary:
CurInit = CopyObject(S, Step->Type, Entity, CurInit,
/*IsExtraneousCopy=*/true);
break;
case SK_UserConversion: {
// We have a user-defined conversion that invokes either a constructor
// or a conversion function.
CastKind CastKind;
FunctionDecl *Fn = Step->Function.Function;
DeclAccessPair FoundFn = Step->Function.FoundDecl;
bool HadMultipleCandidates = Step->Function.HadMultipleCandidates;
bool CreatedObject = false;
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor.
SmallVector<Expr*, 8> ConstructorArgs;
SourceLocation Loc = CurInit.get()->getBeginLoc();
// Determine the arguments required to actually perform the constructor
// call.
Expr *Arg = CurInit.get();
if (S.CompleteConstructorCall(Constructor, Step->Type,
MultiExprArg(&Arg, 1), Loc,
ConstructorArgs))
return ExprError();
// Build an expression that constructs a temporary.
CurInit = S.BuildCXXConstructExpr(Loc, Step->Type,
FoundFn, Constructor,
ConstructorArgs,
HadMultipleCandidates,
/*ListInit*/ false,
/*StdInitListInit*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
if (CurInit.isInvalid())
return ExprError();
S.CheckConstructorAccess(Kind.getLocation(), Constructor, FoundFn,
Entity);
if (S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()))
return ExprError();
CastKind = CK_ConstructorConversion;
CreatedObject = true;
} else {
// Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
S.CheckMemberOperatorAccess(Kind.getLocation(), CurInit.get(), nullptr,
FoundFn);
if (S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()))
return ExprError();
CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion,
HadMultipleCandidates);
if (CurInit.isInvalid())
return ExprError();
CastKind = CK_UserDefinedConversion;
CreatedObject = Conversion->getReturnType()->isRecordType();
}
if (CreatedObject && checkAbstractType(CurInit.get()->getType()))
return ExprError();
CurInit = ImplicitCastExpr::Create(
S.Context, CurInit.get()->getType(), CastKind, CurInit.get(), nullptr,
CurInit.get()->getValueKind(), S.CurFPFeatureOverrides());
if (shouldBindAsTemporary(Entity))
// The overall entity is temporary, so this expression should be
// destroyed at the end of its full-expression.
CurInit = S.MaybeBindToTemporary(CurInit.getAs<Expr>());
else if (CreatedObject && shouldDestroyEntity(Entity)) {
// The object outlasts the full-expression, but we need to prepare for
// a destructor being run on it.
// FIXME: It makes no sense to do this here. This should happen
// regardless of how we initialized the entity.
QualType T = CurInit.get()->getType();
if (const RecordType *Record = T->getAs<RecordType>()) {
CXXDestructorDecl *Destructor
= S.LookupDestructor(cast<CXXRecordDecl>(Record->getDecl()));
S.CheckDestructorAccess(CurInit.get()->getBeginLoc(), Destructor,
S.PDiag(diag::err_access_dtor_temp) << T);
S.MarkFunctionReferenced(CurInit.get()->getBeginLoc(), Destructor);
if (S.DiagnoseUseOfDecl(Destructor, CurInit.get()->getBeginLoc()))
return ExprError();
}
}
break;
}
case SK_QualificationConversionLValue:
case SK_QualificationConversionXValue:
case SK_QualificationConversionPRValue: {
// Perform a qualification conversion; these can never go wrong.
ExprValueKind VK =
Step->Kind == SK_QualificationConversionLValue
? VK_LValue
: (Step->Kind == SK_QualificationConversionXValue ? VK_XValue
: VK_PRValue);
CurInit = S.PerformQualificationConversion(CurInit.get(), Step->Type, VK);
break;
}
case SK_FunctionReferenceConversion:
assert(CurInit.get()->isLValue() &&
"function reference should be lvalue");
CurInit =
S.ImpCastExprToType(CurInit.get(), Step->Type, CK_NoOp, VK_LValue);
break;
case SK_AtomicConversion: {
assert(CurInit.get()->isPRValue() && "cannot convert glvalue to atomic");
CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type,
CK_NonAtomicToAtomic, VK_PRValue);
break;
}
case SK_ConversionSequence:
case SK_ConversionSequenceNoNarrowing: {
if (const auto *FromPtrType =
CurInit.get()->getType()->getAs<PointerType>()) {
if (const auto *ToPtrType = Step->Type->getAs<PointerType>()) {
if (FromPtrType->getPointeeType()->hasAttr(attr::NoDeref) &&
!ToPtrType->getPointeeType()->hasAttr(attr::NoDeref)) {
// Do not check static casts here because they are checked earlier
// in Sema::ActOnCXXNamedCast()
if (!Kind.isStaticCast()) {
S.Diag(CurInit.get()->getExprLoc(),
diag::warn_noderef_to_dereferenceable_pointer)
<< CurInit.get()->getSourceRange();
}
}
}
}
Sema::CheckedConversionKind CCK
= Kind.isCStyleCast()? Sema::CCK_CStyleCast
: Kind.isFunctionalCast()? Sema::CCK_FunctionalCast
: Kind.isExplicitCast()? Sema::CCK_OtherCast
: Sema::CCK_ImplicitConversion;
ExprResult CurInitExprRes =
S.PerformImplicitConversion(CurInit.get(), Step->Type, *Step->ICS,
getAssignmentAction(Entity), CCK);
if (CurInitExprRes.isInvalid())
return ExprError();
S.DiscardMisalignedMemberAddress(Step->Type.getTypePtr(), CurInit.get());
CurInit = CurInitExprRes;
if (Step->Kind == SK_ConversionSequenceNoNarrowing &&
S.getLangOpts().CPlusPlus)
DiagnoseNarrowingInInitList(S, *Step->ICS, SourceType, Entity.getType(),
CurInit.get());
break;
}
case SK_ListInitialization: {
if (checkAbstractType(Step->Type))
return ExprError();
InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
// If we're not initializing the top-level entity, we need to create an
// InitializeTemporary entity for our target type.
QualType Ty = Step->Type;
bool IsTemporary = !S.Context.hasSameType(Entity.getType(), Ty);
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty);
InitializedEntity InitEntity = IsTemporary ? TempEntity : Entity;
InitListChecker PerformInitList(S, InitEntity,
InitList, Ty, /*VerifyOnly=*/false,
/*TreatUnavailableAsInvalid=*/false);
if (PerformInitList.HadError())
return ExprError();
// Hack: We must update *ResultType if available in order to set the
// bounds of arrays, e.g. in 'int ar[] = {1, 2, 3};'.
// Worst case: 'const int (&arref)[] = {1, 2, 3};'.
if (ResultType &&
ResultType->getNonReferenceType()->isIncompleteArrayType()) {
if ((*ResultType)->isRValueReferenceType())
Ty = S.Context.getRValueReferenceType(Ty);
else if ((*ResultType)->isLValueReferenceType())
Ty = S.Context.getLValueReferenceType(Ty,
(*ResultType)->castAs<LValueReferenceType>()->isSpelledAsLValue());
*ResultType = Ty;
}
InitListExpr *StructuredInitList =
PerformInitList.getFullyStructuredList();
CurInit.get();
CurInit = shouldBindAsTemporary(InitEntity)
? S.MaybeBindToTemporary(StructuredInitList)
: StructuredInitList;
break;
}
case SK_ConstructorInitializationFromList: {
if (checkAbstractType(Step->Type))
return ExprError();
// When an initializer list is passed for a parameter of type "reference
// to object", we don't get an EK_Temporary entity, but instead an
// EK_Parameter entity with reference type.
// FIXME: This is a hack. What we really should do is create a user
// conversion step for this case, but this makes it considerably more
// complicated. For now, this will do.
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(
Entity.getType().getNonReferenceType());
bool UseTemporary = Entity.getType()->isReferenceType();
assert(Args.size() == 1 && "expected a single argument for list init");
InitListExpr *InitList = cast<InitListExpr>(Args[0]);
S.Diag(InitList->getExprLoc(), diag::warn_cxx98_compat_ctor_list_init)
<< InitList->getSourceRange();
MultiExprArg Arg(InitList->getInits(), InitList->getNumInits());
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity :
Entity,
Kind, Arg, *Step,
ConstructorInitRequiresZeroInit,
/*IsListInitialization*/true,
/*IsStdInitListInit*/false,
InitList->getLBraceLoc(),
InitList->getRBraceLoc());
break;
}
case SK_UnwrapInitList:
CurInit = cast<InitListExpr>(CurInit.get())->getInit(0);
break;
case SK_RewrapInitList: {
Expr *E = CurInit.get();
InitListExpr *Syntactic = Step->WrappingSyntacticList;
InitListExpr *ILE = new (S.Context) InitListExpr(S.Context,
Syntactic->getLBraceLoc(), E, Syntactic->getRBraceLoc());
ILE->setSyntacticForm(Syntactic);
ILE->setType(E->getType());
ILE->setValueKind(E->getValueKind());
CurInit = ILE;
break;
}
case SK_ConstructorInitialization:
case SK_StdInitializerListConstructorCall: {
if (checkAbstractType(Step->Type))
return ExprError();
// When an initializer list is passed for a parameter of type "reference
// to object", we don't get an EK_Temporary entity, but instead an
// EK_Parameter entity with reference type.
// FIXME: This is a hack. What we really should do is create a user
// conversion step for this case, but this makes it considerably more
// complicated. For now, this will do.
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(
Entity.getType().getNonReferenceType());
bool UseTemporary = Entity.getType()->isReferenceType();
bool IsStdInitListInit =
Step->Kind == SK_StdInitializerListConstructorCall;
Expr *Source = CurInit.get();
SourceRange Range = Kind.hasParenOrBraceRange()
? Kind.getParenOrBraceRange()
: SourceRange();
CurInit = PerformConstructorInitialization(
S, UseTemporary ? TempEntity : Entity, Kind,
Source ? MultiExprArg(Source) : Args, *Step,
ConstructorInitRequiresZeroInit,
/*IsListInitialization*/ IsStdInitListInit,
/*IsStdInitListInitialization*/ IsStdInitListInit,
/*LBraceLoc*/ Range.getBegin(),
/*RBraceLoc*/ Range.getEnd());
break;
}
case SK_ZeroInitialization: {
step_iterator NextStep = Step;
++NextStep;
if (NextStep != StepEnd &&
(NextStep->Kind == SK_ConstructorInitialization ||
NextStep->Kind == SK_ConstructorInitializationFromList)) {
// The need for zero-initialization is recorded directly into
// the call to the object's constructor within the next step.
ConstructorInitRequiresZeroInit = true;
} else if (Kind.getKind() == InitializationKind::IK_Value &&
S.getLangOpts().CPlusPlus &&
!Kind.isImplicitValueInit()) {
TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
if (!TSInfo)
TSInfo = S.Context.getTrivialTypeSourceInfo(Step->Type,
Kind.getRange().getBegin());
CurInit = new (S.Context) CXXScalarValueInitExpr(
Entity.getType().getNonLValueExprType(S.Context), TSInfo,
Kind.getRange().getEnd());
} else {
CurInit = new (S.Context) ImplicitValueInitExpr(Step->Type);
}
break;
}
case SK_CAssignment: {
QualType SourceType = CurInit.get()->getType();
// Save off the initial CurInit in case we need to emit a diagnostic
ExprResult InitialCurInit = CurInit;
ExprResult Result = CurInit;
Sema::AssignConvertType ConvTy =
S.CheckSingleAssignmentConstraints(Step->Type, Result, true,
Entity.getKind() == InitializedEntity::EK_Parameter_CF_Audited);
if (Result.isInvalid())
return ExprError();
CurInit = Result;
// If this is a call, allow conversion to a transparent union.
ExprResult CurInitExprRes = CurInit;
if (ConvTy != Sema::Compatible &&
Entity.isParameterKind() &&
S.CheckTransparentUnionArgumentConstraints(Step->Type, CurInitExprRes)
== Sema::Compatible)
ConvTy = Sema::Compatible;
if (CurInitExprRes.isInvalid())
return ExprError();
CurInit = CurInitExprRes;
bool Complained;
if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(),
Step->Type, SourceType,
InitialCurInit.get(),
getAssignmentAction(Entity, true),
&Complained)) {
PrintInitLocationNote(S, Entity);
return ExprError();
} else if (Complained)
PrintInitLocationNote(S, Entity);
break;
}
case SK_StringInit: {
QualType Ty = Step->Type;
bool UpdateType = ResultType && Entity.getType()->isIncompleteArrayType();
CheckStringInit(CurInit.get(), UpdateType ? *ResultType : Ty,
S.Context.getAsArrayType(Ty), S);
break;
}
case SK_ObjCObjectConversion:
CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type,
CK_ObjCObjectLValueCast,
CurInit.get()->getValueKind());
break;
case SK_ArrayLoopIndex: {
Expr *Cur = CurInit.get();
Expr *BaseExpr = new (S.Context)
OpaqueValueExpr(Cur->getExprLoc(), Cur->getType(),
Cur->getValueKind(), Cur->getObjectKind(), Cur);
Expr *IndexExpr =
new (S.Context) ArrayInitIndexExpr(S.Context.getSizeType());
CurInit = S.CreateBuiltinArraySubscriptExpr(
BaseExpr, Kind.getLocation(), IndexExpr, Kind.getLocation());
ArrayLoopCommonExprs.push_back(BaseExpr);
break;
}
case SK_ArrayLoopInit: {
assert(!ArrayLoopCommonExprs.empty() &&
"mismatched SK_ArrayLoopIndex and SK_ArrayLoopInit");
Expr *Common = ArrayLoopCommonExprs.pop_back_val();
CurInit = new (S.Context) ArrayInitLoopExpr(Step->Type, Common,
CurInit.get());
break;
}
case SK_GNUArrayInit:
// Okay: we checked everything before creating this step. Note that
// this is a GNU extension.
S.Diag(Kind.getLocation(), diag::ext_array_init_copy)
<< Step->Type << CurInit.get()->getType()
<< CurInit.get()->getSourceRange();
updateGNUCompoundLiteralRValue(CurInit.get());
LLVM_FALLTHROUGH;
case SK_ArrayInit:
// If the destination type is an incomplete array type, update the
// type accordingly.
if (ResultType) {
if (const IncompleteArrayType *IncompleteDest
= S.Context.getAsIncompleteArrayType(Step->Type)) {
if (const ConstantArrayType *ConstantSource
= S.Context.getAsConstantArrayType(CurInit.get()->getType())) {
*ResultType = S.Context.getConstantArrayType(
IncompleteDest->getElementType(),
ConstantSource->getSize(),
ConstantSource->getSizeExpr(),
ArrayType::Normal, 0);
}
}
}
break;
case SK_ParenthesizedArrayInit:
// Okay: we checked everything before creating this step. Note that
// this is a GNU extension.
S.Diag(Kind.getLocation(), diag::ext_array_init_parens)
<< CurInit.get()->getSourceRange();
break;
case SK_PassByIndirectCopyRestore:
case SK_PassByIndirectRestore:
checkIndirectCopyRestoreSource(S, CurInit.get());
CurInit = new (S.Context) ObjCIndirectCopyRestoreExpr(
CurInit.get(), Step->Type,
Step->Kind == SK_PassByIndirectCopyRestore);
break;
case SK_ProduceObjCObject:
CurInit = ImplicitCastExpr::Create(
S.Context, Step->Type, CK_ARCProduceObject, CurInit.get(), nullptr,
VK_PRValue, FPOptionsOverride());
break;
case SK_StdInitializerList: {
S.Diag(CurInit.get()->getExprLoc(),
diag::warn_cxx98_compat_initializer_list_init)
<< CurInit.get()->getSourceRange();
// Materialize the temporary into memory.
MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr(
CurInit.get()->getType(), CurInit.get(),
/*BoundToLvalueReference=*/false);
// Wrap it in a construction of a std::initializer_list<T>.
CurInit = new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE);
// Bind the result, in case the library has given initializer_list a
// non-trivial destructor.
if (shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.get());
break;
}
case SK_OCLSamplerInit: {
// Sampler initialization have 5 cases:
// 1. function argument passing
// 1a. argument is a file-scope variable
// 1b. argument is a function-scope variable
// 1c. argument is one of caller function's parameters
// 2. variable initialization
// 2a. initializing a file-scope variable
// 2b. initializing a function-scope variable
//
// For file-scope variables, since they cannot be initialized by function
// call of __translate_sampler_initializer in LLVM IR, their references
// need to be replaced by a cast from their literal initializers to
// sampler type. Since sampler variables can only be used in function
// calls as arguments, we only need to replace them when handling the
// argument passing.
assert(Step->Type->isSamplerT() &&
"Sampler initialization on non-sampler type.");
Expr *Init = CurInit.get()->IgnoreParens();
QualType SourceType = Init->getType();
// Case 1
if (Entity.isParameterKind()) {
if (!SourceType->isSamplerT() && !SourceType->isIntegerType()) {
S.Diag(Kind.getLocation(), diag::err_sampler_argument_required)
<< SourceType;
break;
} else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Init)) {
auto Var = cast<VarDecl>(DRE->getDecl());
// Case 1b and 1c
// No cast from integer to sampler is needed.
if (!Var->hasGlobalStorage()) {
CurInit = ImplicitCastExpr::Create(
S.Context, Step->Type, CK_LValueToRValue, Init,
/*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride());
break;
}
// Case 1a
// For function call with a file-scope sampler variable as argument,
// get the integer literal.
// Do not diagnose if the file-scope variable does not have initializer
// since this has already been diagnosed when parsing the variable
// declaration.
if (!Var->getInit() || !isa<ImplicitCastExpr>(Var->getInit()))
break;
Init = cast<ImplicitCastExpr>(const_cast<Expr*>(
Var->getInit()))->getSubExpr();
SourceType = Init->getType();
}
} else {
// Case 2
// Check initializer is 32 bit integer constant.
// If the initializer is taken from global variable, do not diagnose since
// this has already been done when parsing the variable declaration.
if (!Init->isConstantInitializer(S.Context, false))
break;
if (!SourceType->isIntegerType() ||
32 != S.Context.getIntWidth(SourceType)) {
S.Diag(Kind.getLocation(), diag::err_sampler_initializer_not_integer)
<< SourceType;
break;
}
Expr::EvalResult EVResult;
Init->EvaluateAsInt(EVResult, S.Context);
llvm::APSInt Result = EVResult.Val.getInt();
const uint64_t SamplerValue = Result.getLimitedValue();
// 32-bit value of sampler's initializer is interpreted as
// bit-field with the following structure:
// |unspecified|Filter|Addressing Mode| Normalized Coords|
// |31 6|5 4|3 1| 0|
// This structure corresponds to enum values of sampler properties
// defined in SPIR spec v1.2 and also opencl-c.h
unsigned AddressingMode = (0x0E & SamplerValue) >> 1;
unsigned FilterMode = (0x30 & SamplerValue) >> 4;
if (FilterMode != 1 && FilterMode != 2 &&
!S.getOpenCLOptions().isAvailableOption(
"cl_intel_device_side_avc_motion_estimation", S.getLangOpts()))
S.Diag(Kind.getLocation(),
diag::warn_sampler_initializer_invalid_bits)
<< "Filter Mode";
if (AddressingMode > 4)
S.Diag(Kind.getLocation(),
diag::warn_sampler_initializer_invalid_bits)
<< "Addressing Mode";
}
// Cases 1a, 2a and 2b
// Insert cast from integer to sampler.
CurInit = S.ImpCastExprToType(Init, S.Context.OCLSamplerTy,
CK_IntToOCLSampler);
break;
}
case SK_OCLZeroOpaqueType: {
assert((Step->Type->isEventT() || Step->Type->isQueueT() ||
Step->Type->isOCLIntelSubgroupAVCType()) &&
"Wrong type for initialization of OpenCL opaque type.");
CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type,
CK_ZeroToOCLOpaqueType,
CurInit.get()->getValueKind());
break;
}
}
}
// Check whether the initializer has a shorter lifetime than the initialized
// entity, and if not, either lifetime-extend or warn as appropriate.
if (auto *Init = CurInit.get())
S.checkInitializerLifetime(Entity, Init);
// Diagnose non-fatal problems with the completed initialization.
if (Entity.getKind() == InitializedEntity::EK_Member &&
cast<FieldDecl>(Entity.getDecl())->isBitField())
S.CheckBitFieldInitialization(Kind.getLocation(),
cast<FieldDecl>(Entity.getDecl()),
CurInit.get());
// Check for std::move on construction.
if (const Expr *E = CurInit.get()) {
CheckMoveOnConstruction(S, E,
Entity.getKind() == InitializedEntity::EK_Result);
}
return CurInit;
}
/// Somewhere within T there is an uninitialized reference subobject.
/// Dig it out and diagnose it.
static bool DiagnoseUninitializedReference(Sema &S, SourceLocation Loc,
QualType T) {
if (T->isReferenceType()) {
S.Diag(Loc, diag::err_reference_without_init)
<< T.getNonReferenceType();
return true;
}
CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
if (!RD || !RD->hasUninitializedReferenceMember())
return false;
for (const auto *FI : RD->fields()) {
if (FI->isUnnamedBitfield())
continue;
if (DiagnoseUninitializedReference(S, FI->getLocation(), FI->getType())) {
S.Diag(Loc, diag::note_value_initialization_here) << RD;
return true;
}
}
for (const auto &BI : RD->bases()) {
if (DiagnoseUninitializedReference(S, BI.getBeginLoc(), BI.getType())) {
S.Diag(Loc, diag::note_value_initialization_here) << RD;
return true;
}
}
return false;
}
//===----------------------------------------------------------------------===//
// Diagnose initialization failures
//===----------------------------------------------------------------------===//
/// Emit notes associated with an initialization that failed due to a
/// "simple" conversion failure.
static void emitBadConversionNotes(Sema &S, const InitializedEntity &entity,
Expr *op) {
QualType destType = entity.getType();
if (destType.getNonReferenceType()->isObjCObjectPointerType() &&
op->getType()->isObjCObjectPointerType()) {
// Emit a possible note about the conversion failing because the
// operand is a message send with a related result type.
S.EmitRelatedResultTypeNote(op);
// Emit a possible note about a return failing because we're
// expecting a related result type.
if (entity.getKind() == InitializedEntity::EK_Result)
S.EmitRelatedResultTypeNoteForReturn(destType);
}
QualType fromType = op->getType();
QualType fromPointeeType = fromType.getCanonicalType()->getPointeeType();
QualType destPointeeType = destType.getCanonicalType()->getPointeeType();
auto *fromDecl = fromType->getPointeeCXXRecordDecl();
auto *destDecl = destType->getPointeeCXXRecordDecl();
if (fromDecl && destDecl && fromDecl->getDeclKind() == Decl::CXXRecord &&
destDecl->getDeclKind() == Decl::CXXRecord &&
!fromDecl->isInvalidDecl() && !destDecl->isInvalidDecl() &&
!fromDecl->hasDefinition() &&
destPointeeType.getQualifiers().compatiblyIncludes(
fromPointeeType.getQualifiers()))
S.Diag(fromDecl->getLocation(), diag::note_forward_class_conversion)
<< S.getASTContext().getTagDeclType(fromDecl)
<< S.getASTContext().getTagDeclType(destDecl);
}
static void diagnoseListInit(Sema &S, const InitializedEntity &Entity,
InitListExpr *InitList) {
QualType DestType = Entity.getType();
QualType E;
if (S.getLangOpts().CPlusPlus11 && S.isStdInitializerList(DestType, &E)) {
QualType ArrayType = S.Context.getConstantArrayType(
E.withConst(),
llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
InitList->getNumInits()),
nullptr, clang::ArrayType::Normal, 0);
InitializedEntity HiddenArray =
InitializedEntity::InitializeTemporary(ArrayType);
return diagnoseListInit(S, HiddenArray, InitList);
}
if (DestType->isReferenceType()) {
// A list-initialization failure for a reference means that we tried to
// create a temporary of the inner type (per [dcl.init.list]p3.6) and the
// inner initialization failed.
QualType T = DestType->castAs<ReferenceType>()->getPointeeType();
diagnoseListInit(S, InitializedEntity::InitializeTemporary(T), InitList);
SourceLocation Loc = InitList->getBeginLoc();
if (auto *D = Entity.getDecl())
Loc = D->getLocation();
S.Diag(Loc, diag::note_in_reference_temporary_list_initializer) << T;
return;
}
InitListChecker DiagnoseInitList(S, Entity, InitList, DestType,
/*VerifyOnly=*/false,
/*TreatUnavailableAsInvalid=*/false);
assert(DiagnoseInitList.HadError() &&
"Inconsistent init list check result.");
}
bool InitializationSequence::Diagnose(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
ArrayRef<Expr *> Args) {
if (!Failed())
return false;
// When we want to diagnose only one element of a braced-init-list,
// we need to factor it out.
Expr *OnlyArg;
if (Args.size() == 1) {
auto *List = dyn_cast<InitListExpr>(Args[0]);
if (List && List->getNumInits() == 1)
OnlyArg = List->getInit(0);
else
OnlyArg = Args[0];
}
else
OnlyArg = nullptr;
QualType DestType = Entity.getType();
switch (Failure) {
case FK_TooManyInitsForReference:
// FIXME: Customize for the initialized entity?
if (Args.empty()) {
// Dig out the reference subobject which is uninitialized and diagnose it.
// If this is value-initialization, this could be nested some way within
// the target type.
assert(Kind.getKind() == InitializationKind::IK_Value ||
DestType->isReferenceType());
bool Diagnosed =
DiagnoseUninitializedReference(S, Kind.getLocation(), DestType);
assert(Diagnosed && "couldn't find uninitialized reference to diagnose");
(void)Diagnosed;
} else // FIXME: diagnostic below could be better!
S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
<< SourceRange(Args.front()->getBeginLoc(), Args.back()->getEndLoc());
break;
case FK_ParenthesizedListInitForReference:
S.Diag(Kind.getLocation(), diag::err_list_init_in_parens)
<< 1 << Entity.getType() << Args[0]->getSourceRange();
break;
case FK_ArrayNeedsInitList:
S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 0;
break;
case FK_ArrayNeedsInitListOrStringLiteral:
S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 1;
break;
case FK_ArrayNeedsInitListOrWideStringLiteral:
S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 2;
break;
case FK_NarrowStringIntoWideCharArray:
S.Diag(Kind.getLocation(), diag::err_array_init_narrow_string_into_wchar);
break;
case FK_WideStringIntoCharArray:
S.Diag(Kind.getLocation(), diag::err_array_init_wide_string_into_char);
break;
case FK_IncompatWideStringIntoWideChar:
S.Diag(Kind.getLocation(),
diag::err_array_init_incompat_wide_string_into_wchar);
break;
case FK_PlainStringIntoUTF8Char:
S.Diag(Kind.getLocation(),
diag::err_array_init_plain_string_into_char8_t);
S.Diag(Args.front()->getBeginLoc(),
diag::note_array_init_plain_string_into_char8_t)
<< FixItHint::CreateInsertion(Args.front()->getBeginLoc(), "u8");
break;
case FK_UTF8StringIntoPlainChar:
S.Diag(Kind.getLocation(),
diag::err_array_init_utf8_string_into_char)
<< S.getLangOpts().CPlusPlus20;
break;
case FK_ArrayTypeMismatch:
case FK_NonConstantArrayInit:
S.Diag(Kind.getLocation(),
(Failure == FK_ArrayTypeMismatch
? diag::err_array_init_different_type
: diag::err_array_init_non_constant_array))
<< DestType.getNonReferenceType()
<< OnlyArg->getType()
<< Args[0]->getSourceRange();
break;
case FK_VariableLengthArrayHasInitializer:
S.Diag(Kind.getLocation(), diag::err_variable_object_no_init)
<< Args[0]->getSourceRange();
break;
case FK_AddressOfOverloadFailed: {
DeclAccessPair Found;
S.ResolveAddressOfOverloadedFunction(OnlyArg,
DestType.getNonReferenceType(),
true,
Found);
break;
}
case FK_AddressOfUnaddressableFunction: {
auto *FD = cast<FunctionDecl>(cast<DeclRefExpr>(OnlyArg)->getDecl());
S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
OnlyArg->getBeginLoc());
break;
}
case FK_ReferenceInitOverloadFailed:
case FK_UserConversionOverloadFailed:
switch (FailedOverloadResult) {
case OR_Ambiguous:
FailedCandidateSet.NoteCandidates(
PartialDiagnosticAt(
Kind.getLocation(),
Failure == FK_UserConversionOverloadFailed
? (S.PDiag(diag::err_typecheck_ambiguous_condition)
<< OnlyArg->getType() << DestType
<< Args[0]->getSourceRange())
: (S.PDiag(diag::err_ref_init_ambiguous)
<< DestType << OnlyArg->getType()
<< Args[0]->getSourceRange())),
S, OCD_AmbiguousCandidates, Args);
break;
case OR_No_Viable_Function: {
auto Cands = FailedCandidateSet.CompleteCandidates(S, OCD_AllCandidates, Args);
if (!S.RequireCompleteType(Kind.getLocation(),
DestType.getNonReferenceType(),
diag::err_typecheck_nonviable_condition_incomplete,
OnlyArg->getType(), Args[0]->getSourceRange()))
S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition)
<< (Entity.getKind() == InitializedEntity::EK_Result)
<< OnlyArg->getType() << Args[0]->getSourceRange()
<< DestType.getNonReferenceType();
FailedCandidateSet.NoteCandidates(S, Args, Cands);
break;
}
case OR_Deleted: {
S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function)
<< OnlyArg->getType() << DestType.getNonReferenceType()
<< Args[0]->getSourceRange();
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
if (Ovl == OR_Deleted) {
S.NoteDeletedFunction(Best->Function);
} else {
llvm_unreachable("Inconsistent overload resolution?");
}
break;
}
case OR_Success:
llvm_unreachable("Conversion did not fail!");
}
break;
case FK_NonConstLValueReferenceBindingToTemporary:
if (isa<InitListExpr>(Args[0])) {
S.Diag(Kind.getLocation(),
diag::err_lvalue_reference_bind_to_initlist)
<< DestType.getNonReferenceType().isVolatileQualified()
<< DestType.getNonReferenceType()
<< Args[0]->getSourceRange();
break;
}
LLVM_FALLTHROUGH;
case FK_NonConstLValueReferenceBindingToUnrelated:
S.Diag(Kind.getLocation(),
Failure == FK_NonConstLValueReferenceBindingToTemporary
? diag::err_lvalue_reference_bind_to_temporary
: diag::err_lvalue_reference_bind_to_unrelated)
<< DestType.getNonReferenceType().isVolatileQualified()
<< DestType.getNonReferenceType()
<< OnlyArg->getType()
<< Args[0]->getSourceRange();
break;
case FK_NonConstLValueReferenceBindingToBitfield: {
// We don't necessarily have an unambiguous source bit-field.
FieldDecl *BitField = Args[0]->getSourceBitField();
S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield)
<< DestType.isVolatileQualified()
<< (BitField ? BitField->getDeclName() : DeclarationName())
<< (BitField != nullptr)
<< Args[0]->getSourceRange();
if (BitField)
S.Diag(BitField->getLocation(), diag::note_bitfield_decl);
break;
}
case FK_NonConstLValueReferenceBindingToVectorElement:
S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element)
<< DestType.isVolatileQualified()
<< Args[0]->getSourceRange();
break;
case FK_NonConstLValueReferenceBindingToMatrixElement:
S.Diag(Kind.getLocation(), diag::err_reference_bind_to_matrix_element)
<< DestType.isVolatileQualified() << Args[0]->getSourceRange();
break;
case FK_RValueReferenceBindingToLValue:
S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref)
<< DestType.getNonReferenceType() << OnlyArg->getType()
<< Args[0]->getSourceRange();
break;
case FK_ReferenceAddrspaceMismatchTemporary:
S.Diag(Kind.getLocation(), diag::err_reference_bind_temporary_addrspace)
<< DestType << Args[0]->getSourceRange();
break;
case FK_ReferenceInitDropsQualifiers: {
QualType SourceType = OnlyArg->getType();
QualType NonRefType = DestType.getNonReferenceType();
Qualifiers DroppedQualifiers =
SourceType.getQualifiers() - NonRefType.getQualifiers();
if (!NonRefType.getQualifiers().isAddressSpaceSupersetOf(
SourceType.getQualifiers()))
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
<< NonRefType << SourceType << 1 /*addr space*/
<< Args[0]->getSourceRange();
else if (DroppedQualifiers.hasQualifiers())
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
<< NonRefType << SourceType << 0 /*cv quals*/
<< Qualifiers::fromCVRMask(DroppedQualifiers.getCVRQualifiers())
<< DroppedQualifiers.getCVRQualifiers() << Args[0]->getSourceRange();
else
// FIXME: Consider decomposing the type and explaining which qualifiers
// were dropped where, or on which level a 'const' is missing, etc.
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
<< NonRefType << SourceType << 2 /*incompatible quals*/
<< Args[0]->getSourceRange();
break;
}
case FK_ReferenceInitFailed:
S.Diag(Kind.getLocation(), diag::err_reference_bind_failed)
<< DestType.getNonReferenceType()
<< DestType.getNonReferenceType()->isIncompleteType()
<< OnlyArg->isLValue()
<< OnlyArg->getType()
<< Args[0]->getSourceRange();
emitBadConversionNotes(S, Entity, Args[0]);
break;
case FK_ConversionFailed: {
QualType FromType = OnlyArg->getType();
PartialDiagnostic PDiag = S.PDiag(diag::err_init_conversion_failed)
<< (int)Entity.getKind()
<< DestType
<< OnlyArg->isLValue()
<< FromType
<< Args[0]->getSourceRange();
S.HandleFunctionTypeMismatch(PDiag, FromType, DestType);
S.Diag(Kind.getLocation(), PDiag);
emitBadConversionNotes(S, Entity, Args[0]);
break;
}
case FK_ConversionFromPropertyFailed:
// No-op. This error has already been reported.
break;
case FK_TooManyInitsForScalar: {
SourceRange R;
auto *InitList = dyn_cast<InitListExpr>(Args[0]);
if (InitList && InitList->getNumInits() >= 1) {
R = SourceRange(InitList->getInit(0)->getEndLoc(), InitList->getEndLoc());
} else {
assert(Args.size() > 1 && "Expected multiple initializers!");
R = SourceRange(Args.front()->getEndLoc(), Args.back()->getEndLoc());
}
R.setBegin(S.getLocForEndOfToken(R.getBegin()));
if (Kind.isCStyleOrFunctionalCast())
S.Diag(Kind.getLocation(), diag::err_builtin_func_cast_more_than_one_arg)
<< R;
else
S.Diag(Kind.getLocation(), diag::err_excess_initializers)
<< /*scalar=*/2 << R;
break;
}
case FK_ParenthesizedListInitForScalar:
S.Diag(Kind.getLocation(), diag::err_list_init_in_parens)
<< 0 << Entity.getType() << Args[0]->getSourceRange();
break;
case FK_ReferenceBindingToInitList:
S.Diag(Kind.getLocation(), diag::err_reference_bind_init_list)
<< DestType.getNonReferenceType() << Args[0]->getSourceRange();
break;
case FK_InitListBadDestinationType:
S.Diag(Kind.getLocation(), diag::err_init_list_bad_dest_type)
<< (DestType->isRecordType()) << DestType << Args[0]->getSourceRange();
break;
case FK_ListConstructorOverloadFailed:
case FK_ConstructorOverloadFailed: {
SourceRange ArgsRange;
if (Args.size())
ArgsRange =
SourceRange(Args.front()->getBeginLoc(), Args.back()->getEndLoc());
if (Failure == FK_ListConstructorOverloadFailed) {
assert(Args.size() == 1 &&
"List construction from other than 1 argument.");
InitListExpr *InitList = cast<InitListExpr>(Args[0]);
Args = MultiExprArg(InitList->getInits(), InitList->getNumInits());
}
// FIXME: Using "DestType" for the entity we're printing is probably
// bad.
switch (FailedOverloadResult) {
case OR_Ambiguous:
FailedCandidateSet.NoteCandidates(
PartialDiagnosticAt(Kind.getLocation(),
S.PDiag(diag::err_ovl_ambiguous_init)
<< DestType << ArgsRange),
S, OCD_AmbiguousCandidates, Args);
break;
case OR_No_Viable_Function:
if (Kind.getKind() == InitializationKind::IK_Default &&
(Entity.getKind() == InitializedEntity::EK_Base ||
Entity.getKind() == InitializedEntity::EK_Member) &&
isa<CXXConstructorDecl>(S.CurContext)) {
// This is implicit default initialization of a member or
// base within a constructor. If no viable function was
// found, notify the user that they need to explicitly
// initialize this base/member.
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(S.CurContext);
const CXXRecordDecl *InheritedFrom = nullptr;
if (auto Inherited = Constructor->getInheritedConstructor())
InheritedFrom = Inherited.getShadowDecl()->getNominatedBaseClass();
if (Entity.getKind() == InitializedEntity::EK_Base) {
S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
<< (InheritedFrom ? 2 : Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*base=*/0
<< Entity.getType()
<< InheritedFrom;
RecordDecl *BaseDecl
= Entity.getBaseSpecifier()->getType()->castAs<RecordType>()
->getDecl();
S.Diag(BaseDecl->getLocation(), diag::note_previous_decl)
<< S.Context.getTagDeclType(BaseDecl);
} else {
S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
<< (InheritedFrom ? 2 : Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*member=*/1
<< Entity.getName()
<< InheritedFrom;
S.Diag(Entity.getDecl()->getLocation(),
diag::note_member_declared_at);
if (const RecordType *Record
= Entity.getType()->getAs<RecordType>())
S.Diag(Record->getDecl()->getLocation(),
diag::note_previous_decl)
<< S.Context.getTagDeclType(Record->getDecl());
}
break;
}
FailedCandidateSet.NoteCandidates(
PartialDiagnosticAt(
Kind.getLocation(),
S.PDiag(diag::err_ovl_no_viable_function_in_init)
<< DestType << ArgsRange),
S, OCD_AllCandidates, Args);
break;
case OR_Deleted: {
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
if (Ovl != OR_Deleted) {
S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
<< DestType << ArgsRange;
llvm_unreachable("Inconsistent overload resolution?");
break;
}
// If this is a defaulted or implicitly-declared function, then
// it was implicitly deleted. Make it clear that the deletion was
// implicit.
if (S.isImplicitlyDeleted(Best->Function))
S.Diag(Kind.getLocation(), diag::err_ovl_deleted_special_init)
<< S.getSpecialMember(cast<CXXMethodDecl>(Best->Function))
<< DestType << ArgsRange;
else
S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
<< DestType << ArgsRange;
S.NoteDeletedFunction(Best->Function);
break;
}
case OR_Success:
llvm_unreachable("Conversion did not fail!");
}
}
break;
case FK_DefaultInitOfConst:
if (Entity.getKind() == InitializedEntity::EK_Member &&
isa<CXXConstructorDecl>(S.CurContext)) {
// This is implicit default-initialization of a const member in
// a constructor. Complain that it needs to be explicitly
// initialized.
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(S.CurContext);
S.Diag(Kind.getLocation(), diag::err_uninitialized_member_in_ctor)
<< (Constructor->getInheritedConstructor() ? 2 :
Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*const=*/1
<< Entity.getName();
S.Diag(Entity.getDecl()->getLocation(), diag::note_previous_decl)
<< Entity.getName();
} else {
S.Diag(Kind.getLocation(), diag::err_default_init_const)
<< DestType << (bool)DestType->getAs<RecordType>();
}
break;
case FK_Incomplete:
S.RequireCompleteType(Kind.getLocation(), FailedIncompleteType,
diag::err_init_incomplete_type);
break;
case FK_ListInitializationFailed: {
// Run the init list checker again to emit diagnostics.
InitListExpr *InitList = cast<InitListExpr>(Args[0]);
diagnoseListInit(S, Entity, InitList);
break;
}
case FK_PlaceholderType: {
// FIXME: Already diagnosed!
break;
}
case FK_ExplicitConstructor: {
S.Diag(Kind.getLocation(), diag::err_selected_explicit_constructor)
<< Args[0]->getSourceRange();
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
(void)Ovl;
assert(Ovl == OR_Success && "Inconsistent overload resolution");
CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
S.Diag(CtorDecl->getLocation(),
diag::note_explicit_ctor_deduction_guide_here) << false;
break;
}
}
PrintInitLocationNote(S, Entity);
return true;
}
void InitializationSequence::dump(raw_ostream &OS) const {
switch (SequenceKind) {
case FailedSequence: {
OS << "Failed sequence: ";
switch (Failure) {
case FK_TooManyInitsForReference:
OS << "too many initializers for reference";
break;
case FK_ParenthesizedListInitForReference:
OS << "parenthesized list init for reference";
break;
case FK_ArrayNeedsInitList:
OS << "array requires initializer list";
break;
case FK_AddressOfUnaddressableFunction:
OS << "address of unaddressable function was taken";
break;
case FK_ArrayNeedsInitListOrStringLiteral:
OS << "array requires initializer list or string literal";
break;
case FK_ArrayNeedsInitListOrWideStringLiteral:
OS << "array requires initializer list or wide string literal";
break;
case FK_NarrowStringIntoWideCharArray:
OS << "narrow string into wide char array";
break;
case FK_WideStringIntoCharArray:
OS << "wide string into char array";
break;
case FK_IncompatWideStringIntoWideChar:
OS << "incompatible wide string into wide char array";
break;
case FK_PlainStringIntoUTF8Char:
OS << "plain string literal into char8_t array";
break;
case FK_UTF8StringIntoPlainChar:
OS << "u8 string literal into char array";
break;
case FK_ArrayTypeMismatch:
OS << "array type mismatch";
break;
case FK_NonConstantArrayInit:
OS << "non-constant array initializer";
break;
case FK_AddressOfOverloadFailed:
OS << "address of overloaded function failed";
break;
case FK_ReferenceInitOverloadFailed:
OS << "overload resolution for reference initialization failed";
break;
case FK_NonConstLValueReferenceBindingToTemporary:
OS << "non-const lvalue reference bound to temporary";
break;
case FK_NonConstLValueReferenceBindingToBitfield:
OS << "non-const lvalue reference bound to bit-field";
break;
case FK_NonConstLValueReferenceBindingToVectorElement:
OS << "non-const lvalue reference bound to vector element";
break;
case FK_NonConstLValueReferenceBindingToMatrixElement:
OS << "non-const lvalue reference bound to matrix element";
break;
case FK_NonConstLValueReferenceBindingToUnrelated:
OS << "non-const lvalue reference bound to unrelated type";
break;
case FK_RValueReferenceBindingToLValue:
OS << "rvalue reference bound to an lvalue";
break;
case FK_ReferenceInitDropsQualifiers:
OS << "reference initialization drops qualifiers";
break;
case FK_ReferenceAddrspaceMismatchTemporary:
OS << "reference with mismatching address space bound to temporary";
break;
case FK_ReferenceInitFailed:
OS << "reference initialization failed";
break;
case FK_ConversionFailed:
OS << "conversion failed";
break;
case FK_ConversionFromPropertyFailed:
OS << "conversion from property failed";
break;
case FK_TooManyInitsForScalar:
OS << "too many initializers for scalar";
break;
case FK_ParenthesizedListInitForScalar:
OS << "parenthesized list init for reference";
break;
case FK_ReferenceBindingToInitList:
OS << "referencing binding to initializer list";
break;
case FK_InitListBadDestinationType:
OS << "initializer list for non-aggregate, non-scalar type";
break;
case FK_UserConversionOverloadFailed:
OS << "overloading failed for user-defined conversion";
break;
case FK_ConstructorOverloadFailed:
OS << "constructor overloading failed";
break;
case FK_DefaultInitOfConst:
OS << "default initialization of a const variable";
break;
case FK_Incomplete:
OS << "initialization of incomplete type";
break;
case FK_ListInitializationFailed:
OS << "list initialization checker failure";
break;
case FK_VariableLengthArrayHasInitializer:
OS << "variable length array has an initializer";
break;
case FK_PlaceholderType:
OS << "initializer expression isn't contextually valid";
break;
case FK_ListConstructorOverloadFailed:
OS << "list constructor overloading failed";
break;
case FK_ExplicitConstructor:
OS << "list copy initialization chose explicit constructor";
break;
}
OS << '\n';
return;
}
case DependentSequence:
OS << "Dependent sequence\n";
return;
case NormalSequence:
OS << "Normal sequence: ";
break;
}
for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) {
if (S != step_begin()) {
OS << " -> ";
}
switch (S->Kind) {
case SK_ResolveAddressOfOverloadedFunction:
OS << "resolve address of overloaded function";
break;
case SK_CastDerivedToBasePRValue:
OS << "derived-to-base (prvalue)";
break;
case SK_CastDerivedToBaseXValue:
OS << "derived-to-base (xvalue)";
break;
case SK_CastDerivedToBaseLValue:
OS << "derived-to-base (lvalue)";
break;
case SK_BindReference:
OS << "bind reference to lvalue";
break;
case SK_BindReferenceToTemporary:
OS << "bind reference to a temporary";
break;
case SK_FinalCopy:
OS << "final copy in class direct-initialization";
break;
case SK_ExtraneousCopyToTemporary:
OS << "extraneous C++03 copy to temporary";
break;
case SK_UserConversion:
OS << "user-defined conversion via " << *S->Function.Function;
break;
case SK_QualificationConversionPRValue:
OS << "qualification conversion (prvalue)";
break;
case SK_QualificationConversionXValue:
OS << "qualification conversion (xvalue)";
break;
case SK_QualificationConversionLValue:
OS << "qualification conversion (lvalue)";
break;
case SK_FunctionReferenceConversion:
OS << "function reference conversion";
break;
case SK_AtomicConversion:
OS << "non-atomic-to-atomic conversion";
break;
case SK_ConversionSequence:
OS << "implicit conversion sequence (";
S->ICS->dump(); // FIXME: use OS
OS << ")";
break;
case SK_ConversionSequenceNoNarrowing:
OS << "implicit conversion sequence with narrowing prohibited (";
S->ICS->dump(); // FIXME: use OS
OS << ")";
break;
case SK_ListInitialization:
OS << "list aggregate initialization";
break;
case SK_UnwrapInitList:
OS << "unwrap reference initializer list";
break;
case SK_RewrapInitList:
OS << "rewrap reference initializer list";
break;
case SK_ConstructorInitialization:
OS << "constructor initialization";
break;
case SK_ConstructorInitializationFromList:
OS << "list initialization via constructor";
break;
case SK_ZeroInitialization:
OS << "zero initialization";
break;
case SK_CAssignment:
OS << "C assignment";
break;
case SK_StringInit:
OS << "string initialization";
break;
case SK_ObjCObjectConversion:
OS << "Objective-C object conversion";
break;
case SK_ArrayLoopIndex:
OS << "indexing for array initialization loop";
break;
case SK_ArrayLoopInit:
OS << "array initialization loop";
break;
case SK_ArrayInit:
OS << "array initialization";
break;
case SK_GNUArrayInit:
OS << "array initialization (GNU extension)";
break;
case SK_ParenthesizedArrayInit:
OS << "parenthesized array initialization";
break;
case SK_PassByIndirectCopyRestore:
OS << "pass by indirect copy and restore";
break;
case SK_PassByIndirectRestore:
OS << "pass by indirect restore";
break;
case SK_ProduceObjCObject:
OS << "Objective-C object retension";
break;
case SK_StdInitializerList:
OS << "std::initializer_list from initializer list";
break;
case SK_StdInitializerListConstructorCall:
OS << "list initialization from std::initializer_list";
break;
case SK_OCLSamplerInit:
OS << "OpenCL sampler_t from integer constant";
break;
case SK_OCLZeroOpaqueType:
OS << "OpenCL opaque type from zero";
break;
}
OS << " [" << S->Type << ']';
}
OS << '\n';
}
void InitializationSequence::dump() const {
dump(llvm::errs());
}
static bool NarrowingErrs(const LangOptions &L) {
return L.CPlusPlus11 &&
(!L.MicrosoftExt || L.isCompatibleWithMSVC(LangOptions::MSVC2015));
}
static void DiagnoseNarrowingInInitList(Sema &S,
const ImplicitConversionSequence &ICS,
QualType PreNarrowingType,
QualType EntityType,
const Expr *PostInit) {
const StandardConversionSequence *SCS = nullptr;
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
SCS = &ICS.Standard;
break;
case ImplicitConversionSequence::UserDefinedConversion:
SCS = &ICS.UserDefined.After;
break;
case ImplicitConversionSequence::AmbiguousConversion:
case ImplicitConversionSequence::EllipsisConversion:
case ImplicitConversionSequence::BadConversion:
return;
}
// C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion.
APValue ConstantValue;
QualType ConstantType;
switch (SCS->getNarrowingKind(S.Context, PostInit, ConstantValue,
ConstantType)) {
case NK_Not_Narrowing:
case NK_Dependent_Narrowing:
// No narrowing occurred.
return;
case NK_Type_Narrowing:
// This was a floating-to-integer conversion, which is always considered a
// narrowing conversion even if the value is a constant and can be
// represented exactly as an integer.
S.Diag(PostInit->getBeginLoc(), NarrowingErrs(S.getLangOpts())
? diag::ext_init_list_type_narrowing
: diag::warn_init_list_type_narrowing)
<< PostInit->getSourceRange()
<< PreNarrowingType.getLocalUnqualifiedType()
<< EntityType.getLocalUnqualifiedType();
break;
case NK_Constant_Narrowing:
// A constant value was narrowed.
S.Diag(PostInit->getBeginLoc(),
NarrowingErrs(S.getLangOpts())
? diag::ext_init_list_constant_narrowing
: diag::warn_init_list_constant_narrowing)
<< PostInit->getSourceRange()
<< ConstantValue.getAsString(S.getASTContext(), ConstantType)
<< EntityType.getLocalUnqualifiedType();
break;
case NK_Variable_Narrowing:
// A variable's value may have been narrowed.
S.Diag(PostInit->getBeginLoc(),
NarrowingErrs(S.getLangOpts())
? diag::ext_init_list_variable_narrowing
: diag::warn_init_list_variable_narrowing)
<< PostInit->getSourceRange()
<< PreNarrowingType.getLocalUnqualifiedType()
<< EntityType.getLocalUnqualifiedType();
break;
}
SmallString<128> StaticCast;
llvm::raw_svector_ostream OS(StaticCast);
OS << "static_cast<";
if (const TypedefType *TT = EntityType->getAs<TypedefType>()) {
// It's important to use the typedef's name if there is one so that the
// fixit doesn't break code using types like int64_t.
//
// FIXME: This will break if the typedef requires qualification. But
// getQualifiedNameAsString() includes non-machine-parsable components.
OS << *TT->getDecl();
} else if (const BuiltinType *BT = EntityType->getAs<BuiltinType>())
OS << BT->getName(S.getLangOpts());
else {
// Oops, we didn't find the actual type of the variable. Don't emit a fixit
// with a broken cast.
return;
}
OS << ">(";
S.Diag(PostInit->getBeginLoc(), diag::note_init_list_narrowing_silence)
<< PostInit->getSourceRange()
<< FixItHint::CreateInsertion(PostInit->getBeginLoc(), OS.str())
<< FixItHint::CreateInsertion(
S.getLocForEndOfToken(PostInit->getEndLoc()), ")");
}
//===----------------------------------------------------------------------===//
// Initialization helper functions
//===----------------------------------------------------------------------===//
bool
Sema::CanPerformCopyInitialization(const InitializedEntity &Entity,
ExprResult Init) {
if (Init.isInvalid())
return false;
Expr *InitE = Init.get();
assert(InitE && "No initialization expression");
InitializationKind Kind =
InitializationKind::CreateCopy(InitE->getBeginLoc(), SourceLocation());
InitializationSequence Seq(*this, Entity, Kind, InitE);
return !Seq.Failed();
}
ExprResult
Sema::PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
ExprResult Init,
bool TopLevelOfInitList,
bool AllowExplicit) {
if (Init.isInvalid())
return ExprError();
Expr *InitE = Init.get();
assert(InitE && "No initialization expression?");
if (EqualLoc.isInvalid())
EqualLoc = InitE->getBeginLoc();
InitializationKind Kind = InitializationKind::CreateCopy(
InitE->getBeginLoc(), EqualLoc, AllowExplicit);
InitializationSequence Seq(*this, Entity, Kind, InitE, TopLevelOfInitList);
// Prevent infinite recursion when performing parameter copy-initialization.
const bool ShouldTrackCopy =
Entity.isParameterKind() && Seq.isConstructorInitialization();
if (ShouldTrackCopy) {
if (llvm::is_contained(CurrentParameterCopyTypes, Entity.getType())) {
Seq.SetOverloadFailure(
InitializationSequence::FK_ConstructorOverloadFailed,
OR_No_Viable_Function);
// Try to give a meaningful diagnostic note for the problematic
// constructor.
const auto LastStep = Seq.step_end() - 1;
assert(LastStep->Kind ==
InitializationSequence::SK_ConstructorInitialization);
const FunctionDecl *Function = LastStep->Function.Function;
auto Candidate =
llvm::find_if(Seq.getFailedCandidateSet(),
[Function](const OverloadCandidate &Candidate) -> bool {
return Candidate.Viable &&
Candidate.Function == Function &&
Candidate.Conversions.size() > 0;
});
if (Candidate != Seq.getFailedCandidateSet().end() &&
Function->getNumParams() > 0) {
Candidate->Viable = false;
Candidate->FailureKind = ovl_fail_bad_conversion;
Candidate->Conversions[0].setBad(BadConversionSequence::no_conversion,
InitE,
Function->getParamDecl(0)->getType());
}
}
CurrentParameterCopyTypes.push_back(Entity.getType());
}
ExprResult Result = Seq.Perform(*this, Entity, Kind, InitE);
if (ShouldTrackCopy)
CurrentParameterCopyTypes.pop_back();
return Result;
}
/// Determine whether RD is, or is derived from, a specialization of CTD.
static bool isOrIsDerivedFromSpecializationOf(CXXRecordDecl *RD,
ClassTemplateDecl *CTD) {
auto NotSpecialization = [&] (const CXXRecordDecl *Candidate) {
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Candidate);
return !CTSD || !declaresSameEntity(CTSD->getSpecializedTemplate(), CTD);
};
return !(NotSpecialization(RD) && RD->forallBases(NotSpecialization));
}
QualType Sema::DeduceTemplateSpecializationFromInitializer(
TypeSourceInfo *TSInfo, const InitializedEntity &Entity,
const InitializationKind &Kind, MultiExprArg Inits) {
auto *DeducedTST = dyn_cast<DeducedTemplateSpecializationType>(
TSInfo->getType()->getContainedDeducedType());
assert(DeducedTST && "not a deduced template specialization type");
auto TemplateName = DeducedTST->getTemplateName();
if (TemplateName.isDependent())
return SubstAutoTypeDependent(TSInfo->getType());
// We can only perform deduction for class templates.
auto *Template =
dyn_cast_or_null<ClassTemplateDecl>(TemplateName.getAsTemplateDecl());
if (!Template) {
Diag(Kind.getLocation(),
diag::err_deduced_non_class_template_specialization_type)
<< (int)getTemplateNameKindForDiagnostics(TemplateName) << TemplateName;
if (auto *TD = TemplateName.getAsTemplateDecl())
Diag(TD->getLocation(), diag::note_template_decl_here);
return QualType();
}
// Can't deduce from dependent arguments.
if (Expr::hasAnyTypeDependentArguments(Inits)) {
Diag(TSInfo->getTypeLoc().getBeginLoc(),
diag::warn_cxx14_compat_class_template_argument_deduction)
<< TSInfo->getTypeLoc().getSourceRange() << 0;
return SubstAutoTypeDependent(TSInfo->getType());
}
// FIXME: Perform "exact type" matching first, per CWG discussion?
// Or implement this via an implied 'T(T) -> T' deduction guide?
// FIXME: Do we need/want a std::initializer_list<T> special case?
// Look up deduction guides, including those synthesized from constructors.
//
// C++1z [over.match.class.deduct]p1:
// A set of functions and function templates is formed comprising:
// - For each constructor of the class template designated by the
// template-name, a function template [...]
// - For each deduction-guide, a function or function template [...]
DeclarationNameInfo NameInfo(
Context.DeclarationNames.getCXXDeductionGuideName(Template),
TSInfo->getTypeLoc().getEndLoc());
LookupResult Guides(*this, NameInfo, LookupOrdinaryName);
LookupQualifiedName(Guides, Template->getDeclContext());
// FIXME: Do not diagnose inaccessible deduction guides. The standard isn't
// clear on this, but they're not found by name so access does not apply.
Guides.suppressDiagnostics();
// Figure out if this is list-initialization.
InitListExpr *ListInit =
(Inits.size() == 1 && Kind.getKind() != InitializationKind::IK_Direct)
? dyn_cast<InitListExpr>(Inits[0])
: nullptr;
// C++1z [over.match.class.deduct]p1:
// Initialization and overload resolution are performed as described in
// [dcl.init] and [over.match.ctor], [over.match.copy], or [over.match.list]
// (as appropriate for the type of initialization performed) for an object
// of a hypothetical class type, where the selected functions and function
// templates are considered to be the constructors of that class type
//
// Since we know we're initializing a class type of a type unrelated to that
// of the initializer, this reduces to something fairly reasonable.
OverloadCandidateSet Candidates(Kind.getLocation(),
OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
bool HasAnyDeductionGuide = false;
bool AllowExplicit = !Kind.isCopyInit() || ListInit;
auto tryToResolveOverload =
[&](bool OnlyListConstructors) -> OverloadingResult {
Candidates.clear(OverloadCandidateSet::CSK_Normal);
HasAnyDeductionGuide = false;
for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
if (D->isInvalidDecl())
continue;
auto *TD = dyn_cast<FunctionTemplateDecl>(D);
auto *GD = dyn_cast_or_null<CXXDeductionGuideDecl>(
TD ? TD->getTemplatedDecl() : dyn_cast<FunctionDecl>(D));
if (!GD)
continue;
if (!GD->isImplicit())
HasAnyDeductionGuide = true;
// C++ [over.match.ctor]p1: (non-list copy-initialization from non-class)
// For copy-initialization, the candidate functions are all the
// converting constructors (12.3.1) of that class.
// C++ [over.match.copy]p1: (non-list copy-initialization from class)
// The converting constructors of T are candidate functions.
if (!AllowExplicit) {
// Overload resolution checks whether the deduction guide is declared
// explicit for us.
// When looking for a converting constructor, deduction guides that
// could never be called with one argument are not interesting to
// check or note.
if (GD->getMinRequiredArguments() > 1 ||
(GD->getNumParams() == 0 && !GD->isVariadic()))
continue;
}
// C++ [over.match.list]p1.1: (first phase list initialization)
// Initially, the candidate functions are the initializer-list
// constructors of the class T
if (OnlyListConstructors && !isInitListConstructor(GD))
continue;
// C++ [over.match.list]p1.2: (second phase list initialization)
// the candidate functions are all the constructors of the class T
// C++ [over.match.ctor]p1: (all other cases)
// the candidate functions are all the constructors of the class of
// the object being initialized
// C++ [over.best.ics]p4:
// When [...] the constructor [...] is a candidate by
// - [over.match.copy] (in all cases)
// FIXME: The "second phase of [over.match.list] case can also
// theoretically happen here, but it's not clear whether we can
// ever have a parameter of the right type.
bool SuppressUserConversions = Kind.isCopyInit();
if (TD)
AddTemplateOverloadCandidate(TD, I.getPair(), /*ExplicitArgs*/ nullptr,
Inits, Candidates, SuppressUserConversions,
/*PartialOverloading*/ false,
AllowExplicit);
else
AddOverloadCandidate(GD, I.getPair(), Inits, Candidates,
SuppressUserConversions,
/*PartialOverloading*/ false, AllowExplicit);
}
return Candidates.BestViableFunction(*this, Kind.getLocation(), Best);
};
OverloadingResult Result = OR_No_Viable_Function;
// C++11 [over.match.list]p1, per DR1467: for list-initialization, first
// try initializer-list constructors.
if (ListInit) {
bool TryListConstructors = true;
// Try list constructors unless the list is empty and the class has one or
// more default constructors, in which case those constructors win.
if (!ListInit->getNumInits()) {
for (NamedDecl *D : Guides) {
auto *FD = dyn_cast<FunctionDecl>(D->getUnderlyingDecl());
if (FD && FD->getMinRequiredArguments() == 0) {
TryListConstructors = false;
break;
}
}
} else if (ListInit->getNumInits() == 1) {
// C++ [over.match.class.deduct]:
// As an exception, the first phase in [over.match.list] (considering
// initializer-list constructors) is omitted if the initializer list
// consists of a single expression of type cv U, where U is a
// specialization of C or a class derived from a specialization of C.
Expr *E = ListInit->getInit(0);
auto *RD = E->getType()->getAsCXXRecordDecl();
if (!isa<InitListExpr>(E) && RD &&
isCompleteType(Kind.getLocation(), E->getType()) &&
isOrIsDerivedFromSpecializationOf(RD, Template))
TryListConstructors = false;
}
if (TryListConstructors)
Result = tryToResolveOverload(/*OnlyListConstructor*/true);
// Then unwrap the initializer list and try again considering all
// constructors.
Inits = MultiExprArg(ListInit->getInits(), ListInit->getNumInits());
}
// If list-initialization fails, or if we're doing any other kind of
// initialization, we (eventually) consider constructors.
if (Result == OR_No_Viable_Function)
Result = tryToResolveOverload(/*OnlyListConstructor*/false);
switch (Result) {
case OR_Ambiguous:
// FIXME: For list-initialization candidates, it'd usually be better to
// list why they were not viable when given the initializer list itself as
// an argument.
Candidates.NoteCandidates(
PartialDiagnosticAt(
Kind.getLocation(),
PDiag(diag::err_deduced_class_template_ctor_ambiguous)
<< TemplateName),
*this, OCD_AmbiguousCandidates, Inits);
return QualType();
case OR_No_Viable_Function: {
CXXRecordDecl *Primary =
cast<ClassTemplateDecl>(Template)->getTemplatedDecl();
bool Complete =
isCompleteType(Kind.getLocation(), Context.getTypeDeclType(Primary));
Candidates.NoteCandidates(
PartialDiagnosticAt(
Kind.getLocation(),
PDiag(Complete ? diag::err_deduced_class_template_ctor_no_viable
: diag::err_deduced_class_template_incomplete)
<< TemplateName << !Guides.empty()),
*this, OCD_AllCandidates, Inits);
return QualType();
}
case OR_Deleted: {
Diag(Kind.getLocation(), diag::err_deduced_class_template_deleted)
<< TemplateName;
NoteDeletedFunction(Best->Function);
return QualType();
}
case OR_Success:
// C++ [over.match.list]p1:
// In copy-list-initialization, if an explicit constructor is chosen, the
// initialization is ill-formed.
if (Kind.isCopyInit() && ListInit &&
cast<CXXDeductionGuideDecl>(Best->Function)->isExplicit()) {
bool IsDeductionGuide = !Best->Function->isImplicit();
Diag(Kind.getLocation(), diag::err_deduced_class_template_explicit)
<< TemplateName << IsDeductionGuide;
Diag(Best->Function->getLocation(),
diag::note_explicit_ctor_deduction_guide_here)
<< IsDeductionGuide;
return QualType();
}
// Make sure we didn't select an unusable deduction guide, and mark it
// as referenced.
DiagnoseUseOfDecl(Best->Function, Kind.getLocation());
MarkFunctionReferenced(Kind.getLocation(), Best->Function);
break;
}
// C++ [dcl.type.class.deduct]p1:
// The placeholder is replaced by the return type of the function selected
// by overload resolution for class template deduction.
QualType DeducedType =
SubstAutoType(TSInfo->getType(), Best->Function->getReturnType());
Diag(TSInfo->getTypeLoc().getBeginLoc(),
diag::warn_cxx14_compat_class_template_argument_deduction)
<< TSInfo->getTypeLoc().getSourceRange() << 1 << DeducedType;
// Warn if CTAD was used on a type that does not have any user-defined
// deduction guides.
if (!HasAnyDeductionGuide) {
Diag(TSInfo->getTypeLoc().getBeginLoc(),
diag::warn_ctad_maybe_unsupported)
<< TemplateName;
Diag(Template->getLocation(), diag::note_suppress_ctad_maybe_unsupported);
}
return DeducedType;
}
diff --git a/contrib/llvm-project/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/contrib/llvm-project/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
index 0143b5f8df6b..655be20572b6 100644
--- a/contrib/llvm-project/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
+++ b/contrib/llvm-project/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -1,550 +1,550 @@
//===- InterpolatingCompilationDatabase.cpp ---------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// InterpolatingCompilationDatabase wraps another CompilationDatabase and
// attempts to heuristically determine appropriate compile commands for files
// that are not included, such as headers or newly created files.
//
// Motivating cases include:
// Header files that live next to their implementation files. These typically
// share a base filename. (libclang/CXString.h, libclang/CXString.cpp).
// Some projects separate headers from includes. Filenames still typically
// match, maybe other path segments too. (include/llvm/IR/Use.h, lib/IR/Use.cc).
// Matches are sometimes only approximate (Sema.h, SemaDecl.cpp). This goes
// for directories too (Support/Unix/Process.inc, lib/Support/Process.cpp).
// Even if we can't find a "right" compile command, even a random one from
// the project will tend to get important flags like -I and -x right.
//
// We "borrow" the compile command for the closest available file:
// - points are awarded if the filename matches (ignoring extension)
// - points are awarded if the directory structure matches
// - ties are broken by length of path prefix match
//
// The compile command is adjusted, replacing the filename and removing output
// file arguments. The -x and -std flags may be affected too.
//
// Source language is a tricky issue: is it OK to use a .c file's command
// for building a .cc file? What language is a .h file in?
// - We only consider compile commands for c-family languages as candidates.
// - For files whose language is implied by the filename (e.g. .m, .hpp)
// we prefer candidates from the same language.
// If we must cross languages, we drop any -x and -std flags.
// - For .h files, candidates from any c-family language are acceptable.
// We use the candidate's language, inserting e.g. -x c++-header.
//
// This class is only useful when wrapping databases that can enumerate all
// their compile commands. If getAllFilenames() is empty, no inference occurs.
//
//===----------------------------------------------------------------------===//
#include "clang/Basic/LangStandard.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Types.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
namespace clang {
namespace tooling {
namespace {
using namespace llvm;
namespace types = clang::driver::types;
namespace path = llvm::sys::path;
// The length of the prefix these two strings have in common.
size_t matchingPrefix(StringRef L, StringRef R) {
size_t Limit = std::min(L.size(), R.size());
for (size_t I = 0; I < Limit; ++I)
if (L[I] != R[I])
return I;
return Limit;
}
// A comparator for searching SubstringWithIndexes with std::equal_range etc.
// Optionaly prefix semantics: compares equal if the key is a prefix.
template <bool Prefix> struct Less {
bool operator()(StringRef Key, std::pair<StringRef, size_t> Value) const {
StringRef V = Prefix ? Value.first.substr(0, Key.size()) : Value.first;
return Key < V;
}
bool operator()(std::pair<StringRef, size_t> Value, StringRef Key) const {
StringRef V = Prefix ? Value.first.substr(0, Key.size()) : Value.first;
return V < Key;
}
};
// Infer type from filename. If we might have gotten it wrong, set *Certain.
// *.h will be inferred as a C header, but not certain.
types::ID guessType(StringRef Filename, bool *Certain = nullptr) {
// path::extension is ".cpp", lookupTypeForExtension wants "cpp".
auto Lang =
types::lookupTypeForExtension(path::extension(Filename).substr(1));
if (Certain)
*Certain = Lang != types::TY_CHeader && Lang != types::TY_INVALID;
return Lang;
}
// Return Lang as one of the canonical supported types.
// e.g. c-header --> c; fortran --> TY_INVALID
static types::ID foldType(types::ID Lang) {
switch (Lang) {
case types::TY_C:
case types::TY_CHeader:
return types::TY_C;
case types::TY_ObjC:
case types::TY_ObjCHeader:
return types::TY_ObjC;
case types::TY_CXX:
case types::TY_CXXHeader:
return types::TY_CXX;
case types::TY_ObjCXX:
case types::TY_ObjCXXHeader:
return types::TY_ObjCXX;
case types::TY_CUDA:
case types::TY_CUDA_DEVICE:
return types::TY_CUDA;
default:
return types::TY_INVALID;
}
}
// A CompileCommand that can be applied to another file.
struct TransferableCommand {
// Flags that should not apply to all files are stripped from CommandLine.
CompileCommand Cmd;
// Language detected from -x or the filename. Never TY_INVALID.
Optional<types::ID> Type;
// Standard specified by -std.
LangStandard::Kind Std = LangStandard::lang_unspecified;
// Whether the command line is for the cl-compatible driver.
bool ClangCLMode;
TransferableCommand(CompileCommand C)
: Cmd(std::move(C)), Type(guessType(Cmd.Filename)) {
std::vector<std::string> OldArgs = std::move(Cmd.CommandLine);
Cmd.CommandLine.clear();
// Wrap the old arguments in an InputArgList.
llvm::opt::InputArgList ArgList;
{
SmallVector<const char *, 16> TmpArgv;
for (const std::string &S : OldArgs)
TmpArgv.push_back(S.c_str());
ClangCLMode = !TmpArgv.empty() &&
driver::IsClangCL(driver::getDriverMode(
TmpArgv.front(), llvm::makeArrayRef(TmpArgv).slice(1)));
ArgList = {TmpArgv.begin(), TmpArgv.end()};
}
// Parse the old args in order to strip out and record unwanted flags.
// We parse each argument individually so that we can retain the exact
// spelling of each argument; re-rendering is lossy for aliased flags.
// E.g. in CL mode, /W4 maps to -Wall.
auto &OptTable = clang::driver::getDriverOptTable();
if (!OldArgs.empty())
Cmd.CommandLine.emplace_back(OldArgs.front());
for (unsigned Pos = 1; Pos < OldArgs.size();) {
using namespace driver::options;
const unsigned OldPos = Pos;
std::unique_ptr<llvm::opt::Arg> Arg(OptTable.ParseOneArg(
ArgList, Pos,
- /* Include */ ClangCLMode ? CoreOption | CLOption : 0,
- /* Exclude */ ClangCLMode ? 0 : CLOption));
+ /* Include */ ClangCLMode ? CoreOption | CLOption | CLDXCOption : 0,
+ /* Exclude */ ClangCLMode ? 0 : CLOption | CLDXCOption));
if (!Arg)
continue;
const llvm::opt::Option &Opt = Arg->getOption();
// Strip input and output files.
if (Opt.matches(OPT_INPUT) || Opt.matches(OPT_o) ||
(ClangCLMode && (Opt.matches(OPT__SLASH_Fa) ||
Opt.matches(OPT__SLASH_Fe) ||
Opt.matches(OPT__SLASH_Fi) ||
Opt.matches(OPT__SLASH_Fo))))
continue;
// ...including when the inputs are passed after --.
if (Opt.matches(OPT__DASH_DASH))
break;
// Strip -x, but record the overridden language.
if (const auto GivenType = tryParseTypeArg(*Arg)) {
Type = *GivenType;
continue;
}
// Strip -std, but record the value.
if (const auto GivenStd = tryParseStdArg(*Arg)) {
if (*GivenStd != LangStandard::lang_unspecified)
Std = *GivenStd;
continue;
}
Cmd.CommandLine.insert(Cmd.CommandLine.end(),
OldArgs.data() + OldPos, OldArgs.data() + Pos);
}
// Make use of -std iff -x was missing.
if (Type == types::TY_INVALID && Std != LangStandard::lang_unspecified)
Type = toType(LangStandard::getLangStandardForKind(Std).getLanguage());
Type = foldType(*Type);
// The contract is to store None instead of TY_INVALID.
if (Type == types::TY_INVALID)
Type = llvm::None;
}
// Produce a CompileCommand for \p filename, based on this one.
// (This consumes the TransferableCommand just to avoid copying Cmd).
CompileCommand transferTo(StringRef Filename) && {
CompileCommand Result = std::move(Cmd);
Result.Heuristic = "inferred from " + Result.Filename;
Result.Filename = std::string(Filename);
bool TypeCertain;
auto TargetType = guessType(Filename, &TypeCertain);
// If the filename doesn't determine the language (.h), transfer with -x.
if ((!TargetType || !TypeCertain) && Type) {
// Use *Type, or its header variant if the file is a header.
// Treat no/invalid extension as header (e.g. C++ standard library).
TargetType =
(!TargetType || types::onlyPrecompileType(TargetType)) // header?
? types::lookupHeaderTypeForSourceType(*Type)
: *Type;
if (ClangCLMode) {
const StringRef Flag = toCLFlag(TargetType);
if (!Flag.empty())
Result.CommandLine.push_back(std::string(Flag));
} else {
Result.CommandLine.push_back("-x");
Result.CommandLine.push_back(types::getTypeName(TargetType));
}
}
// --std flag may only be transferred if the language is the same.
// We may consider "translating" these, e.g. c++11 -> c11.
if (Std != LangStandard::lang_unspecified && foldType(TargetType) == Type) {
Result.CommandLine.emplace_back((
llvm::Twine(ClangCLMode ? "/std:" : "-std=") +
LangStandard::getLangStandardForKind(Std).getName()).str());
}
Result.CommandLine.push_back("--");
Result.CommandLine.push_back(std::string(Filename));
return Result;
}
private:
// Map the language from the --std flag to that of the -x flag.
static types::ID toType(Language Lang) {
switch (Lang) {
case Language::C:
return types::TY_C;
case Language::CXX:
return types::TY_CXX;
case Language::ObjC:
return types::TY_ObjC;
case Language::ObjCXX:
return types::TY_ObjCXX;
default:
return types::TY_INVALID;
}
}
// Convert a file type to the matching CL-style type flag.
static StringRef toCLFlag(types::ID Type) {
switch (Type) {
case types::TY_C:
case types::TY_CHeader:
return "/TC";
case types::TY_CXX:
case types::TY_CXXHeader:
return "/TP";
default:
return StringRef();
}
}
// Try to interpret the argument as a type specifier, e.g. '-x'.
Optional<types::ID> tryParseTypeArg(const llvm::opt::Arg &Arg) {
const llvm::opt::Option &Opt = Arg.getOption();
using namespace driver::options;
if (ClangCLMode) {
if (Opt.matches(OPT__SLASH_TC) || Opt.matches(OPT__SLASH_Tc))
return types::TY_C;
if (Opt.matches(OPT__SLASH_TP) || Opt.matches(OPT__SLASH_Tp))
return types::TY_CXX;
} else {
if (Opt.matches(driver::options::OPT_x))
return types::lookupTypeForTypeSpecifier(Arg.getValue());
}
return None;
}
// Try to interpret the argument as '-std='.
Optional<LangStandard::Kind> tryParseStdArg(const llvm::opt::Arg &Arg) {
using namespace driver::options;
if (Arg.getOption().matches(ClangCLMode ? OPT__SLASH_std : OPT_std_EQ))
return LangStandard::getLangKind(Arg.getValue());
return None;
}
};
// Given a filename, FileIndex picks the best matching file from the underlying
// DB. This is the proxy file whose CompileCommand will be reused. The
// heuristics incorporate file name, extension, and directory structure.
// Strategy:
// - Build indexes of each of the substrings we want to look up by.
// These indexes are just sorted lists of the substrings.
// - Each criterion corresponds to a range lookup into the index, so we only
// need O(log N) string comparisons to determine scores.
//
// Apart from path proximity signals, also takes file extensions into account
// when scoring the candidates.
class FileIndex {
public:
FileIndex(std::vector<std::string> Files)
: OriginalPaths(std::move(Files)), Strings(Arena) {
// Sort commands by filename for determinism (index is a tiebreaker later).
llvm::sort(OriginalPaths);
Paths.reserve(OriginalPaths.size());
Types.reserve(OriginalPaths.size());
Stems.reserve(OriginalPaths.size());
for (size_t I = 0; I < OriginalPaths.size(); ++I) {
StringRef Path = Strings.save(StringRef(OriginalPaths[I]).lower());
Paths.emplace_back(Path, I);
Types.push_back(foldType(guessType(OriginalPaths[I])));
Stems.emplace_back(sys::path::stem(Path), I);
auto Dir = ++sys::path::rbegin(Path), DirEnd = sys::path::rend(Path);
for (int J = 0; J < DirectorySegmentsIndexed && Dir != DirEnd; ++J, ++Dir)
if (Dir->size() > ShortDirectorySegment) // not trivial ones
Components.emplace_back(*Dir, I);
}
llvm::sort(Paths);
llvm::sort(Stems);
llvm::sort(Components);
}
bool empty() const { return Paths.empty(); }
// Returns the path for the file that best fits OriginalFilename.
// Candidates with extensions matching PreferLanguage will be chosen over
// others (unless it's TY_INVALID, or all candidates are bad).
StringRef chooseProxy(StringRef OriginalFilename,
types::ID PreferLanguage) const {
assert(!empty() && "need at least one candidate!");
std::string Filename = OriginalFilename.lower();
auto Candidates = scoreCandidates(Filename);
std::pair<size_t, int> Best =
pickWinner(Candidates, Filename, PreferLanguage);
DEBUG_WITH_TYPE(
"interpolate",
llvm::dbgs() << "interpolate: chose " << OriginalPaths[Best.first]
<< " as proxy for " << OriginalFilename << " preferring "
<< (PreferLanguage == types::TY_INVALID
? "none"
: types::getTypeName(PreferLanguage))
<< " score=" << Best.second << "\n");
return OriginalPaths[Best.first];
}
private:
using SubstringAndIndex = std::pair<StringRef, size_t>;
// Directory matching parameters: we look at the last two segments of the
// parent directory (usually the semantically significant ones in practice).
// We search only the last four of each candidate (for efficiency).
constexpr static int DirectorySegmentsIndexed = 4;
constexpr static int DirectorySegmentsQueried = 2;
constexpr static int ShortDirectorySegment = 1; // Only look at longer names.
// Award points to candidate entries that should be considered for the file.
// Returned keys are indexes into paths, and the values are (nonzero) scores.
DenseMap<size_t, int> scoreCandidates(StringRef Filename) const {
// Decompose Filename into the parts we care about.
// /some/path/complicated/project/Interesting.h
// [-prefix--][---dir---] [-dir-] [--stem---]
StringRef Stem = sys::path::stem(Filename);
llvm::SmallVector<StringRef, DirectorySegmentsQueried> Dirs;
llvm::StringRef Prefix;
auto Dir = ++sys::path::rbegin(Filename),
DirEnd = sys::path::rend(Filename);
for (int I = 0; I < DirectorySegmentsQueried && Dir != DirEnd; ++I, ++Dir) {
if (Dir->size() > ShortDirectorySegment)
Dirs.push_back(*Dir);
Prefix = Filename.substr(0, Dir - DirEnd);
}
// Now award points based on lookups into our various indexes.
DenseMap<size_t, int> Candidates; // Index -> score.
auto Award = [&](int Points, ArrayRef<SubstringAndIndex> Range) {
for (const auto &Entry : Range)
Candidates[Entry.second] += Points;
};
// Award one point if the file's basename is a prefix of the candidate,
// and another if it's an exact match (so exact matches get two points).
Award(1, indexLookup</*Prefix=*/true>(Stem, Stems));
Award(1, indexLookup</*Prefix=*/false>(Stem, Stems));
// For each of the last few directories in the Filename, award a point
// if it's present in the candidate.
for (StringRef Dir : Dirs)
Award(1, indexLookup</*Prefix=*/false>(Dir, Components));
// Award one more point if the whole rest of the path matches.
if (sys::path::root_directory(Prefix) != Prefix)
Award(1, indexLookup</*Prefix=*/true>(Prefix, Paths));
return Candidates;
}
// Pick a single winner from the set of scored candidates.
// Returns (index, score).
std::pair<size_t, int> pickWinner(const DenseMap<size_t, int> &Candidates,
StringRef Filename,
types::ID PreferredLanguage) const {
struct ScoredCandidate {
size_t Index;
bool Preferred;
int Points;
size_t PrefixLength;
};
// Choose the best candidate by (preferred, points, prefix length, alpha).
ScoredCandidate Best = {size_t(-1), false, 0, 0};
for (const auto &Candidate : Candidates) {
ScoredCandidate S;
S.Index = Candidate.first;
S.Preferred = PreferredLanguage == types::TY_INVALID ||
PreferredLanguage == Types[S.Index];
S.Points = Candidate.second;
if (!S.Preferred && Best.Preferred)
continue;
if (S.Preferred == Best.Preferred) {
if (S.Points < Best.Points)
continue;
if (S.Points == Best.Points) {
S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
if (S.PrefixLength < Best.PrefixLength)
continue;
// hidden heuristics should at least be deterministic!
if (S.PrefixLength == Best.PrefixLength)
if (S.Index > Best.Index)
continue;
}
}
// PrefixLength was only set above if actually needed for a tiebreak.
// But it definitely needs to be set to break ties in the future.
S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
Best = S;
}
// Edge case: no candidate got any points.
// We ignore PreferredLanguage at this point (not ideal).
if (Best.Index == size_t(-1))
return {longestMatch(Filename, Paths).second, 0};
return {Best.Index, Best.Points};
}
// Returns the range within a sorted index that compares equal to Key.
// If Prefix is true, it's instead the range starting with Key.
template <bool Prefix>
ArrayRef<SubstringAndIndex>
indexLookup(StringRef Key, ArrayRef<SubstringAndIndex> Idx) const {
// Use pointers as iteratiors to ease conversion of result to ArrayRef.
auto Range = std::equal_range(Idx.data(), Idx.data() + Idx.size(), Key,
Less<Prefix>());
return {Range.first, Range.second};
}
// Performs a point lookup into a nonempty index, returning a longest match.
SubstringAndIndex longestMatch(StringRef Key,
ArrayRef<SubstringAndIndex> Idx) const {
assert(!Idx.empty());
// Longest substring match will be adjacent to a direct lookup.
auto It = llvm::lower_bound(Idx, SubstringAndIndex{Key, 0});
if (It == Idx.begin())
return *It;
if (It == Idx.end())
return *--It;
// Have to choose between It and It-1
size_t Prefix = matchingPrefix(Key, It->first);
size_t PrevPrefix = matchingPrefix(Key, (It - 1)->first);
return Prefix > PrevPrefix ? *It : *--It;
}
// Original paths, everything else is in lowercase.
std::vector<std::string> OriginalPaths;
BumpPtrAllocator Arena;
StringSaver Strings;
// Indexes of candidates by certain substrings.
// String is lowercase and sorted, index points into OriginalPaths.
std::vector<SubstringAndIndex> Paths; // Full path.
// Lang types obtained by guessing on the corresponding path. I-th element is
// a type for the I-th path.
std::vector<types::ID> Types;
std::vector<SubstringAndIndex> Stems; // Basename, without extension.
std::vector<SubstringAndIndex> Components; // Last path components.
};
// The actual CompilationDatabase wrapper delegates to its inner database.
// If no match, looks up a proxy file in FileIndex and transfers its
// command to the requested file.
class InterpolatingCompilationDatabase : public CompilationDatabase {
public:
InterpolatingCompilationDatabase(std::unique_ptr<CompilationDatabase> Inner)
: Inner(std::move(Inner)), Index(this->Inner->getAllFiles()) {}
std::vector<CompileCommand>
getCompileCommands(StringRef Filename) const override {
auto Known = Inner->getCompileCommands(Filename);
if (Index.empty() || !Known.empty())
return Known;
bool TypeCertain;
auto Lang = guessType(Filename, &TypeCertain);
if (!TypeCertain)
Lang = types::TY_INVALID;
auto ProxyCommands =
Inner->getCompileCommands(Index.chooseProxy(Filename, foldType(Lang)));
if (ProxyCommands.empty())
return {};
return {transferCompileCommand(std::move(ProxyCommands.front()), Filename)};
}
std::vector<std::string> getAllFiles() const override {
return Inner->getAllFiles();
}
std::vector<CompileCommand> getAllCompileCommands() const override {
return Inner->getAllCompileCommands();
}
private:
std::unique_ptr<CompilationDatabase> Inner;
FileIndex Index;
};
} // namespace
std::unique_ptr<CompilationDatabase>
inferMissingCompileCommands(std::unique_ptr<CompilationDatabase> Inner) {
return std::make_unique<InterpolatingCompilationDatabase>(std::move(Inner));
}
tooling::CompileCommand transferCompileCommand(CompileCommand Cmd,
StringRef Filename) {
return TransferableCommand(std::move(Cmd)).transferTo(Filename);
}
} // namespace tooling
} // namespace clang
diff --git a/contrib/llvm-project/clang/lib/Tooling/Syntax/Tokens.cpp b/contrib/llvm-project/clang/lib/Tooling/Syntax/Tokens.cpp
index e2014f965c90..1fa73c667b7f 100644
--- a/contrib/llvm-project/clang/lib/Tooling/Syntax/Tokens.cpp
+++ b/contrib/llvm-project/clang/lib/Tooling/Syntax/Tokens.cpp
@@ -1,931 +1,1025 @@
//===- Tokens.cpp - collect tokens from preprocessing ---------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Syntax/Tokens.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <string>
#include <utility>
#include <vector>
using namespace clang;
using namespace clang::syntax;
namespace {
// Finds the smallest consecutive subsuquence of Toks that covers R.
llvm::ArrayRef<syntax::Token>
getTokensCovering(llvm::ArrayRef<syntax::Token> Toks, SourceRange R,
const SourceManager &SM) {
if (R.isInvalid())
return {};
const syntax::Token *Begin =
llvm::partition_point(Toks, [&](const syntax::Token &T) {
return SM.isBeforeInTranslationUnit(T.location(), R.getBegin());
});
const syntax::Token *End =
llvm::partition_point(Toks, [&](const syntax::Token &T) {
return !SM.isBeforeInTranslationUnit(R.getEnd(), T.location());
});
if (Begin > End)
return {};
return {Begin, End};
}
-// Finds the smallest expansion range that contains expanded tokens First and
-// Last, e.g.:
+// Finds the range within FID corresponding to expanded tokens [First, Last].
+// Prev precedes First and Next follows Last, these must *not* be included.
+// If no range satisfies the criteria, returns an invalid range.
+//
// #define ID(x) x
// ID(ID(ID(a1) a2))
// ~~ -> a1
// ~~ -> a2
// ~~~~~~~~~ -> a1 a2
-SourceRange findCommonRangeForMacroArgs(const syntax::Token &First,
- const syntax::Token &Last,
- const SourceManager &SM) {
- SourceRange Res;
- auto FirstLoc = First.location(), LastLoc = Last.location();
- // Keep traversing up the spelling chain as longs as tokens are part of the
- // same expansion.
- while (!FirstLoc.isFileID() && !LastLoc.isFileID()) {
- auto ExpInfoFirst = SM.getSLocEntry(SM.getFileID(FirstLoc)).getExpansion();
- auto ExpInfoLast = SM.getSLocEntry(SM.getFileID(LastLoc)).getExpansion();
- // Stop if expansions have diverged.
- if (ExpInfoFirst.getExpansionLocStart() !=
- ExpInfoLast.getExpansionLocStart())
+SourceRange spelledForExpandedSlow(SourceLocation First, SourceLocation Last,
+ SourceLocation Prev, SourceLocation Next,
+ FileID TargetFile,
+ const SourceManager &SM) {
+ // There are two main parts to this algorithm:
+ // - identifying which spelled range covers the expanded tokens
+ // - validating that this range doesn't cover any extra tokens (First/Last)
+ //
+ // We do these in order. However as we transform the expanded range into the
+ // spelled one, we adjust First/Last so the validation remains simple.
+
+ assert(SM.getSLocEntry(TargetFile).isFile());
+ // In most cases, to select First and Last we must return their expansion
+ // range, i.e. the whole of any macros they are included in.
+ //
+ // When First and Last are part of the *same macro arg* of a macro written
+ // in TargetFile, we that slice of the arg, i.e. their spelling range.
+ //
+ // Unwrap such macro calls. If the target file has A(B(C)), the
+ // SourceLocation stack of a token inside C shows us the expansion of A first,
+ // then B, then any macros inside C's body, then C itself.
+ // (This is the reverse of the order the PP applies the expansions in).
+ while (First.isMacroID() && Last.isMacroID()) {
+ auto DecFirst = SM.getDecomposedLoc(First);
+ auto DecLast = SM.getDecomposedLoc(Last);
+ auto &ExpFirst = SM.getSLocEntry(DecFirst.first).getExpansion();
+ auto &ExpLast = SM.getSLocEntry(DecLast.first).getExpansion();
+
+ if (!ExpFirst.isMacroArgExpansion() || !ExpLast.isMacroArgExpansion())
+ break;
+ // Locations are in the same macro arg if they expand to the same place.
+ // (They may still have different FileIDs - an arg can have >1 chunks!)
+ if (ExpFirst.getExpansionLocStart() != ExpLast.getExpansionLocStart())
break;
- // Do not continue into macro bodies.
- if (!ExpInfoFirst.isMacroArgExpansion() ||
- !ExpInfoLast.isMacroArgExpansion())
+ // Careful, given:
+ // #define HIDE ID(ID(a))
+ // ID(ID(HIDE))
+ // The token `a` is wrapped in 4 arg-expansions, we only want to unwrap 2.
+ // We distinguish them by whether the macro expands into the target file.
+ // Fortunately, the target file ones will always appear first.
+ auto &ExpMacro =
+ SM.getSLocEntry(SM.getFileID(ExpFirst.getExpansionLocStart()))
+ .getExpansion();
+ if (ExpMacro.getExpansionLocStart().isMacroID())
break;
- FirstLoc = SM.getImmediateSpellingLoc(FirstLoc);
- LastLoc = SM.getImmediateSpellingLoc(LastLoc);
- // Update the result afterwards, as we want the tokens that triggered the
- // expansion.
- Res = {FirstLoc, LastLoc};
+ // Replace each endpoint with its spelling inside the macro arg.
+ // (This is getImmediateSpellingLoc without repeating lookups).
+ First = ExpFirst.getSpellingLoc().getLocWithOffset(DecFirst.second);
+ Last = ExpLast.getSpellingLoc().getLocWithOffset(DecLast.second);
+
+ // Now: how do we adjust the previous/next bounds? Three cases:
+ // A) If they are also part of the same macro arg, we translate them too.
+ // This will ensure that we don't select any macros nested within the
+ // macro arg that cover extra tokens. Critical case:
+ // #define ID(X) X
+ // ID(prev target) // selecting 'target' succeeds
+ // #define LARGE ID(prev target)
+ // LARGE // selecting 'target' fails.
+ // B) They are not in the macro at all, then their expansion range is a
+ // sibling to it, and we can safely substitute that.
+ // #define PREV prev
+ // #define ID(X) X
+ // PREV ID(target) // selecting 'target' succeeds.
+ // #define LARGE PREV ID(target)
+ // LARGE // selecting 'target' fails.
+ // C) They are in a different arg of this macro, or the macro body.
+ // Now selecting the whole macro arg is fine, but the whole macro is not.
+ // Model this by setting using the edge of the macro call as the bound.
+ // #define ID2(X, Y) X Y
+ // ID2(prev, target) // selecting 'target' succeeds
+ // #define LARGE ID2(prev, target)
+ // LARGE // selecting 'target' fails
+ auto AdjustBound = [&](SourceLocation &Bound) {
+ if (Bound.isInvalid() || !Bound.isMacroID()) // Non-macro must be case B.
+ return;
+ auto DecBound = SM.getDecomposedLoc(Bound);
+ auto &ExpBound = SM.getSLocEntry(DecBound.first).getExpansion();
+ if (ExpBound.isMacroArgExpansion() &&
+ ExpBound.getExpansionLocStart() == ExpFirst.getExpansionLocStart()) {
+ // Case A: translate to (spelling) loc within the macro arg.
+ Bound = ExpBound.getSpellingLoc().getLocWithOffset(DecBound.second);
+ return;
+ }
+ while (Bound.isMacroID()) {
+ SourceRange Exp = SM.getImmediateExpansionRange(Bound).getAsRange();
+ if (Exp.getBegin() == ExpMacro.getExpansionLocStart()) {
+ // Case B: bounds become the macro call itself.
+ Bound = (&Bound == &Prev) ? Exp.getBegin() : Exp.getEnd();
+ return;
+ }
+ // Either case C, or expansion location will later find case B.
+ // We choose the upper bound for Prev and the lower one for Next:
+ // ID(prev) target ID(next)
+ // ^ ^
+ // new-prev new-next
+ Bound = (&Bound == &Prev) ? Exp.getEnd() : Exp.getBegin();
+ }
+ };
+ AdjustBound(Prev);
+ AdjustBound(Next);
}
- // Normally mapping back to expansion location here only changes FileID, as
- // we've already found some tokens expanded from the same macro argument, and
- // they should map to a consecutive subset of spelled tokens. Unfortunately
- // SourceManager::isBeforeInTranslationUnit discriminates sourcelocations
- // based on their FileID in addition to offsets. So even though we are
- // referring to same tokens, SourceManager might tell us that one is before
- // the other if they've got different FileIDs.
- return SM.getExpansionRange(CharSourceRange(Res, true)).getAsRange();
+
+ // In all remaining cases we need the full containing macros.
+ // If this overlaps Prev or Next, then no range is possible.
+ SourceRange Candidate =
+ SM.getExpansionRange(SourceRange(First, Last)).getAsRange();
+ auto DecFirst = SM.getDecomposedExpansionLoc(Candidate.getBegin());
+ auto DecLast = SM.getDecomposedLoc(Candidate.getEnd());
+ // Can end up in the wrong file due to bad input or token-pasting shenanigans.
+ if (Candidate.isInvalid() || DecFirst.first != TargetFile || DecLast.first != TargetFile)
+ return SourceRange();
+ // Check bounds, which may still be inside macros.
+ if (Prev.isValid()) {
+ auto Dec = SM.getDecomposedLoc(SM.getExpansionRange(Prev).getBegin());
+ if (Dec.first != DecFirst.first || Dec.second >= DecFirst.second)
+ return SourceRange();
+ }
+ if (Next.isValid()) {
+ auto Dec = SM.getDecomposedLoc(SM.getExpansionRange(Next).getEnd());
+ if (Dec.first != DecLast.first || Dec.second <= DecLast.second)
+ return SourceRange();
+ }
+ // Now we know that Candidate is a file range that covers [First, Last]
+ // without encroaching on {Prev, Next}. Ship it!
+ return Candidate;
}
} // namespace
syntax::Token::Token(SourceLocation Location, unsigned Length,
tok::TokenKind Kind)
: Location(Location), Length(Length), Kind(Kind) {
assert(Location.isValid());
}
syntax::Token::Token(const clang::Token &T)
: Token(T.getLocation(), T.getLength(), T.getKind()) {
assert(!T.isAnnotation());
}
llvm::StringRef syntax::Token::text(const SourceManager &SM) const {
bool Invalid = false;
const char *Start = SM.getCharacterData(location(), &Invalid);
assert(!Invalid);
return llvm::StringRef(Start, length());
}
FileRange syntax::Token::range(const SourceManager &SM) const {
assert(location().isFileID() && "must be a spelled token");
FileID File;
unsigned StartOffset;
std::tie(File, StartOffset) = SM.getDecomposedLoc(location());
return FileRange(File, StartOffset, StartOffset + length());
}
FileRange syntax::Token::range(const SourceManager &SM,
const syntax::Token &First,
const syntax::Token &Last) {
auto F = First.range(SM);
auto L = Last.range(SM);
assert(F.file() == L.file() && "tokens from different files");
assert((F == L || F.endOffset() <= L.beginOffset()) &&
"wrong order of tokens");
return FileRange(F.file(), F.beginOffset(), L.endOffset());
}
llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, const Token &T) {
return OS << T.str();
}
FileRange::FileRange(FileID File, unsigned BeginOffset, unsigned EndOffset)
: File(File), Begin(BeginOffset), End(EndOffset) {
assert(File.isValid());
assert(BeginOffset <= EndOffset);
}
FileRange::FileRange(const SourceManager &SM, SourceLocation BeginLoc,
unsigned Length) {
assert(BeginLoc.isValid());
assert(BeginLoc.isFileID());
std::tie(File, Begin) = SM.getDecomposedLoc(BeginLoc);
End = Begin + Length;
}
FileRange::FileRange(const SourceManager &SM, SourceLocation BeginLoc,
SourceLocation EndLoc) {
assert(BeginLoc.isValid());
assert(BeginLoc.isFileID());
assert(EndLoc.isValid());
assert(EndLoc.isFileID());
assert(SM.getFileID(BeginLoc) == SM.getFileID(EndLoc));
assert(SM.getFileOffset(BeginLoc) <= SM.getFileOffset(EndLoc));
std::tie(File, Begin) = SM.getDecomposedLoc(BeginLoc);
End = SM.getFileOffset(EndLoc);
}
llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS,
const FileRange &R) {
return OS << llvm::formatv("FileRange(file = {0}, offsets = {1}-{2})",
R.file().getHashValue(), R.beginOffset(),
R.endOffset());
}
llvm::StringRef FileRange::text(const SourceManager &SM) const {
bool Invalid = false;
StringRef Text = SM.getBufferData(File, &Invalid);
if (Invalid)
return "";
assert(Begin <= Text.size());
assert(End <= Text.size());
return Text.substr(Begin, length());
}
void TokenBuffer::indexExpandedTokens() {
// No-op if the index is already created.
if (!ExpandedTokIndex.empty())
return;
ExpandedTokIndex.reserve(ExpandedTokens.size());
// Index ExpandedTokens for faster lookups by SourceLocation.
for (size_t I = 0, E = ExpandedTokens.size(); I != E; ++I) {
SourceLocation Loc = ExpandedTokens[I].location();
if (Loc.isValid())
ExpandedTokIndex[Loc] = I;
}
}
llvm::ArrayRef<syntax::Token> TokenBuffer::expandedTokens(SourceRange R) const {
if (R.isInvalid())
return {};
if (!ExpandedTokIndex.empty()) {
// Quick lookup if `R` is a token range.
// This is a huge win since majority of the users use ranges provided by an
// AST. Ranges in AST are token ranges from expanded token stream.
const auto B = ExpandedTokIndex.find(R.getBegin());
const auto E = ExpandedTokIndex.find(R.getEnd());
if (B != ExpandedTokIndex.end() && E != ExpandedTokIndex.end()) {
const Token *L = ExpandedTokens.data() + B->getSecond();
// Add 1 to End to make a half-open range.
const Token *R = ExpandedTokens.data() + E->getSecond() + 1;
if (L > R)
return {};
return {L, R};
}
}
// Slow case. Use `isBeforeInTranslationUnit` to binary search for the
// required range.
return getTokensCovering(expandedTokens(), R, *SourceMgr);
}
CharSourceRange FileRange::toCharRange(const SourceManager &SM) const {
return CharSourceRange(
SourceRange(SM.getComposedLoc(File, Begin), SM.getComposedLoc(File, End)),
/*IsTokenRange=*/false);
}
std::pair<const syntax::Token *, const TokenBuffer::Mapping *>
TokenBuffer::spelledForExpandedToken(const syntax::Token *Expanded) const {
assert(Expanded);
assert(ExpandedTokens.data() <= Expanded &&
Expanded < ExpandedTokens.data() + ExpandedTokens.size());
auto FileIt = Files.find(
SourceMgr->getFileID(SourceMgr->getExpansionLoc(Expanded->location())));
assert(FileIt != Files.end() && "no file for an expanded token");
const MarkedFile &File = FileIt->second;
unsigned ExpandedIndex = Expanded - ExpandedTokens.data();
// Find the first mapping that produced tokens after \p Expanded.
auto It = llvm::partition_point(File.Mappings, [&](const Mapping &M) {
return M.BeginExpanded <= ExpandedIndex;
});
// Our token could only be produced by the previous mapping.
if (It == File.Mappings.begin()) {
// No previous mapping, no need to modify offsets.
return {&File.SpelledTokens[ExpandedIndex - File.BeginExpanded],
/*Mapping=*/nullptr};
}
--It; // 'It' now points to last mapping that started before our token.
// Check if the token is part of the mapping.
if (ExpandedIndex < It->EndExpanded)
return {&File.SpelledTokens[It->BeginSpelled], /*Mapping=*/&*It};
// Not part of the mapping, use the index from previous mapping to compute the
// corresponding spelled token.
return {
&File.SpelledTokens[It->EndSpelled + (ExpandedIndex - It->EndExpanded)],
/*Mapping=*/nullptr};
}
const TokenBuffer::Mapping *
TokenBuffer::mappingStartingBeforeSpelled(const MarkedFile &F,
const syntax::Token *Spelled) {
assert(F.SpelledTokens.data() <= Spelled);
unsigned SpelledI = Spelled - F.SpelledTokens.data();
assert(SpelledI < F.SpelledTokens.size());
auto It = llvm::partition_point(F.Mappings, [SpelledI](const Mapping &M) {
return M.BeginSpelled <= SpelledI;
});
if (It == F.Mappings.begin())
return nullptr;
--It;
return &*It;
}
llvm::SmallVector<llvm::ArrayRef<syntax::Token>, 1>
TokenBuffer::expandedForSpelled(llvm::ArrayRef<syntax::Token> Spelled) const {
if (Spelled.empty())
return {};
const auto &File = fileForSpelled(Spelled);
auto *FrontMapping = mappingStartingBeforeSpelled(File, &Spelled.front());
unsigned SpelledFrontI = &Spelled.front() - File.SpelledTokens.data();
assert(SpelledFrontI < File.SpelledTokens.size());
unsigned ExpandedBegin;
if (!FrontMapping) {
// No mapping that starts before the first token of Spelled, we don't have
// to modify offsets.
ExpandedBegin = File.BeginExpanded + SpelledFrontI;
} else if (SpelledFrontI < FrontMapping->EndSpelled) {
// This mapping applies to Spelled tokens.
if (SpelledFrontI != FrontMapping->BeginSpelled) {
// Spelled tokens don't cover the entire mapping, returning empty result.
return {}; // FIXME: support macro arguments.
}
// Spelled tokens start at the beginning of this mapping.
ExpandedBegin = FrontMapping->BeginExpanded;
} else {
// Spelled tokens start after the mapping ends (they start in the hole
// between 2 mappings, or between a mapping and end of the file).
ExpandedBegin =
FrontMapping->EndExpanded + (SpelledFrontI - FrontMapping->EndSpelled);
}
auto *BackMapping = mappingStartingBeforeSpelled(File, &Spelled.back());
unsigned SpelledBackI = &Spelled.back() - File.SpelledTokens.data();
unsigned ExpandedEnd;
if (!BackMapping) {
// No mapping that starts before the last token of Spelled, we don't have to
// modify offsets.
ExpandedEnd = File.BeginExpanded + SpelledBackI + 1;
} else if (SpelledBackI < BackMapping->EndSpelled) {
// This mapping applies to Spelled tokens.
if (SpelledBackI + 1 != BackMapping->EndSpelled) {
// Spelled tokens don't cover the entire mapping, returning empty result.
return {}; // FIXME: support macro arguments.
}
ExpandedEnd = BackMapping->EndExpanded;
} else {
// Spelled tokens end after the mapping ends.
ExpandedEnd =
BackMapping->EndExpanded + (SpelledBackI - BackMapping->EndSpelled) + 1;
}
assert(ExpandedBegin < ExpandedTokens.size());
assert(ExpandedEnd < ExpandedTokens.size());
// Avoid returning empty ranges.
if (ExpandedBegin == ExpandedEnd)
return {};
return {llvm::makeArrayRef(ExpandedTokens.data() + ExpandedBegin,
ExpandedTokens.data() + ExpandedEnd)};
}
llvm::ArrayRef<syntax::Token> TokenBuffer::spelledTokens(FileID FID) const {
auto It = Files.find(FID);
assert(It != Files.end());
return It->second.SpelledTokens;
}
const syntax::Token *TokenBuffer::spelledTokenAt(SourceLocation Loc) const {
assert(Loc.isFileID());
const auto *Tok = llvm::partition_point(
spelledTokens(SourceMgr->getFileID(Loc)),
[&](const syntax::Token &Tok) { return Tok.location() < Loc; });
if (!Tok || Tok->location() != Loc)
return nullptr;
return Tok;
}
std::string TokenBuffer::Mapping::str() const {
return std::string(
llvm::formatv("spelled tokens: [{0},{1}), expanded tokens: [{2},{3})",
BeginSpelled, EndSpelled, BeginExpanded, EndExpanded));
}
llvm::Optional<llvm::ArrayRef<syntax::Token>>
TokenBuffer::spelledForExpanded(llvm::ArrayRef<syntax::Token> Expanded) const {
// Mapping an empty range is ambiguous in case of empty mappings at either end
// of the range, bail out in that case.
if (Expanded.empty())
return llvm::None;
-
- const syntax::Token *BeginSpelled;
- const Mapping *BeginMapping;
- std::tie(BeginSpelled, BeginMapping) =
- spelledForExpandedToken(&Expanded.front());
-
- const syntax::Token *LastSpelled;
- const Mapping *LastMapping;
- std::tie(LastSpelled, LastMapping) =
- spelledForExpandedToken(&Expanded.back());
-
- FileID FID = SourceMgr->getFileID(BeginSpelled->location());
+ const syntax::Token *First = &Expanded.front();
+ const syntax::Token *Last = &Expanded.back();
+ const syntax::Token *FirstSpelled, *LastSpelled;
+ const TokenBuffer::Mapping *FirstMapping, *LastMapping;
+ std::tie(FirstSpelled, FirstMapping) = spelledForExpandedToken(First);
+ std::tie(LastSpelled, LastMapping) = spelledForExpandedToken(Last);
+
+ FileID FID = SourceMgr->getFileID(FirstSpelled->location());
// FIXME: Handle multi-file changes by trying to map onto a common root.
if (FID != SourceMgr->getFileID(LastSpelled->location()))
return llvm::None;
const MarkedFile &File = Files.find(FID)->second;
- // If both tokens are coming from a macro argument expansion, try and map to
- // smallest part of the macro argument. BeginMapping && LastMapping check is
- // only for performance, they are a prerequisite for Expanded.front() and
- // Expanded.back() being part of a macro arg expansion.
- if (BeginMapping && LastMapping &&
- SourceMgr->isMacroArgExpansion(Expanded.front().location()) &&
- SourceMgr->isMacroArgExpansion(Expanded.back().location())) {
- auto CommonRange = findCommonRangeForMacroArgs(Expanded.front(),
- Expanded.back(), *SourceMgr);
- // It might be the case that tokens are arguments of different macro calls,
- // in that case we should continue with the logic below instead of returning
- // an empty range.
- if (CommonRange.isValid())
- return getTokensCovering(File.SpelledTokens, CommonRange, *SourceMgr);
+ // If the range is within one macro argument, the result may be only part of a
+ // Mapping. We must use the general (SourceManager-based) algorithm.
+ if (FirstMapping && FirstMapping == LastMapping &&
+ SourceMgr->isMacroArgExpansion(First->location()) &&
+ SourceMgr->isMacroArgExpansion(Last->location())) {
+ // We use excluded Prev/Next token for bounds checking.
+ SourceLocation Prev = (First == &ExpandedTokens.front())
+ ? SourceLocation()
+ : (First - 1)->location();
+ SourceLocation Next = (Last == &ExpandedTokens.back())
+ ? SourceLocation()
+ : (Last + 1)->location();
+ SourceRange Range = spelledForExpandedSlow(
+ First->location(), Last->location(), Prev, Next, FID, *SourceMgr);
+ if (Range.isInvalid())
+ return llvm::None;
+ return getTokensCovering(File.SpelledTokens, Range, *SourceMgr);
}
+ // Otherwise, use the fast version based on Mappings.
// Do not allow changes that doesn't cover full expansion.
- unsigned BeginExpanded = Expanded.begin() - ExpandedTokens.data();
- unsigned EndExpanded = Expanded.end() - ExpandedTokens.data();
- if (BeginMapping && BeginExpanded != BeginMapping->BeginExpanded)
+ unsigned FirstExpanded = Expanded.begin() - ExpandedTokens.data();
+ unsigned LastExpanded = Expanded.end() - ExpandedTokens.data();
+ if (FirstMapping && FirstExpanded != FirstMapping->BeginExpanded)
return llvm::None;
- if (LastMapping && LastMapping->EndExpanded != EndExpanded)
+ if (LastMapping && LastMapping->EndExpanded != LastExpanded)
return llvm::None;
- // All is good, return the result.
return llvm::makeArrayRef(
- BeginMapping ? File.SpelledTokens.data() + BeginMapping->BeginSpelled
- : BeginSpelled,
+ FirstMapping ? File.SpelledTokens.data() + FirstMapping->BeginSpelled
+ : FirstSpelled,
LastMapping ? File.SpelledTokens.data() + LastMapping->EndSpelled
: LastSpelled + 1);
}
TokenBuffer::Expansion TokenBuffer::makeExpansion(const MarkedFile &F,
const Mapping &M) const {
Expansion E;
E.Spelled = llvm::makeArrayRef(F.SpelledTokens.data() + M.BeginSpelled,
F.SpelledTokens.data() + M.EndSpelled);
E.Expanded = llvm::makeArrayRef(ExpandedTokens.data() + M.BeginExpanded,
ExpandedTokens.data() + M.EndExpanded);
return E;
}
const TokenBuffer::MarkedFile &
TokenBuffer::fileForSpelled(llvm::ArrayRef<syntax::Token> Spelled) const {
assert(!Spelled.empty());
assert(Spelled.front().location().isFileID() && "not a spelled token");
auto FileIt = Files.find(SourceMgr->getFileID(Spelled.front().location()));
assert(FileIt != Files.end() && "file not tracked by token buffer");
const auto &File = FileIt->second;
assert(File.SpelledTokens.data() <= Spelled.data() &&
Spelled.end() <=
(File.SpelledTokens.data() + File.SpelledTokens.size()) &&
"Tokens not in spelled range");
#ifndef NDEBUG
auto T1 = Spelled.back().location();
auto T2 = File.SpelledTokens.back().location();
assert(T1 == T2 || sourceManager().isBeforeInTranslationUnit(T1, T2));
#endif
return File;
}
llvm::Optional<TokenBuffer::Expansion>
TokenBuffer::expansionStartingAt(const syntax::Token *Spelled) const {
assert(Spelled);
const auto &File = fileForSpelled(*Spelled);
unsigned SpelledIndex = Spelled - File.SpelledTokens.data();
auto M = llvm::partition_point(File.Mappings, [&](const Mapping &M) {
return M.BeginSpelled < SpelledIndex;
});
if (M == File.Mappings.end() || M->BeginSpelled != SpelledIndex)
return llvm::None;
return makeExpansion(File, *M);
}
std::vector<TokenBuffer::Expansion> TokenBuffer::expansionsOverlapping(
llvm::ArrayRef<syntax::Token> Spelled) const {
if (Spelled.empty())
return {};
const auto &File = fileForSpelled(Spelled);
// Find the first overlapping range, and then copy until we stop overlapping.
unsigned SpelledBeginIndex = Spelled.begin() - File.SpelledTokens.data();
unsigned SpelledEndIndex = Spelled.end() - File.SpelledTokens.data();
auto M = llvm::partition_point(File.Mappings, [&](const Mapping &M) {
return M.EndSpelled <= SpelledBeginIndex;
});
std::vector<TokenBuffer::Expansion> Expansions;
for (; M != File.Mappings.end() && M->BeginSpelled < SpelledEndIndex; ++M)
Expansions.push_back(makeExpansion(File, *M));
return Expansions;
}
llvm::ArrayRef<syntax::Token>
syntax::spelledTokensTouching(SourceLocation Loc,
llvm::ArrayRef<syntax::Token> Tokens) {
assert(Loc.isFileID());
auto *Right = llvm::partition_point(
Tokens, [&](const syntax::Token &Tok) { return Tok.location() < Loc; });
bool AcceptRight = Right != Tokens.end() && Right->location() <= Loc;
bool AcceptLeft =
Right != Tokens.begin() && (Right - 1)->endLocation() >= Loc;
return llvm::makeArrayRef(Right - (AcceptLeft ? 1 : 0),
Right + (AcceptRight ? 1 : 0));
}
llvm::ArrayRef<syntax::Token>
syntax::spelledTokensTouching(SourceLocation Loc,
const syntax::TokenBuffer &Tokens) {
return spelledTokensTouching(
Loc, Tokens.spelledTokens(Tokens.sourceManager().getFileID(Loc)));
}
const syntax::Token *
syntax::spelledIdentifierTouching(SourceLocation Loc,
llvm::ArrayRef<syntax::Token> Tokens) {
for (const syntax::Token &Tok : spelledTokensTouching(Loc, Tokens)) {
if (Tok.kind() == tok::identifier)
return &Tok;
}
return nullptr;
}
const syntax::Token *
syntax::spelledIdentifierTouching(SourceLocation Loc,
const syntax::TokenBuffer &Tokens) {
return spelledIdentifierTouching(
Loc, Tokens.spelledTokens(Tokens.sourceManager().getFileID(Loc)));
}
std::vector<const syntax::Token *>
TokenBuffer::macroExpansions(FileID FID) const {
auto FileIt = Files.find(FID);
assert(FileIt != Files.end() && "file not tracked by token buffer");
auto &File = FileIt->second;
std::vector<const syntax::Token *> Expansions;
auto &Spelled = File.SpelledTokens;
for (auto Mapping : File.Mappings) {
const syntax::Token *Token = &Spelled[Mapping.BeginSpelled];
if (Token->kind() == tok::TokenKind::identifier)
Expansions.push_back(Token);
}
return Expansions;
}
std::vector<syntax::Token> syntax::tokenize(const FileRange &FR,
const SourceManager &SM,
const LangOptions &LO) {
std::vector<syntax::Token> Tokens;
IdentifierTable Identifiers(LO);
auto AddToken = [&](clang::Token T) {
// Fill the proper token kind for keywords, etc.
if (T.getKind() == tok::raw_identifier && !T.needsCleaning() &&
!T.hasUCN()) { // FIXME: support needsCleaning and hasUCN cases.
clang::IdentifierInfo &II = Identifiers.get(T.getRawIdentifier());
T.setIdentifierInfo(&II);
T.setKind(II.getTokenID());
}
Tokens.push_back(syntax::Token(T));
};
auto SrcBuffer = SM.getBufferData(FR.file());
Lexer L(SM.getLocForStartOfFile(FR.file()), LO, SrcBuffer.data(),
SrcBuffer.data() + FR.beginOffset(),
// We can't make BufEnd point to FR.endOffset, as Lexer requires a
// null terminated buffer.
SrcBuffer.data() + SrcBuffer.size());
clang::Token T;
while (!L.LexFromRawLexer(T) && L.getCurrentBufferOffset() < FR.endOffset())
AddToken(T);
// LexFromRawLexer returns true when it parses the last token of the file, add
// it iff it starts within the range we are interested in.
if (SM.getFileOffset(T.getLocation()) < FR.endOffset())
AddToken(T);
return Tokens;
}
std::vector<syntax::Token> syntax::tokenize(FileID FID, const SourceManager &SM,
const LangOptions &LO) {
return tokenize(syntax::FileRange(FID, 0, SM.getFileIDSize(FID)), SM, LO);
}
/// Records information reqired to construct mappings for the token buffer that
/// we are collecting.
class TokenCollector::CollectPPExpansions : public PPCallbacks {
public:
CollectPPExpansions(TokenCollector &C) : Collector(&C) {}
/// Disabled instance will stop reporting anything to TokenCollector.
/// This ensures that uses of the preprocessor after TokenCollector::consume()
/// is called do not access the (possibly invalid) collector instance.
void disable() { Collector = nullptr; }
void MacroExpands(const clang::Token &MacroNameTok, const MacroDefinition &MD,
SourceRange Range, const MacroArgs *Args) override {
if (!Collector)
return;
const auto &SM = Collector->PP.getSourceManager();
// Only record top-level expansions that directly produce expanded tokens.
// This excludes those where:
// - the macro use is inside a macro body,
// - the macro appears in an argument to another macro.
// However macro expansion isn't really a tree, it's token rewrite rules,
// so there are other cases, e.g.
// #define B(X) X
// #define A 1 + B
// A(2)
// Both A and B produce expanded tokens, though the macro name 'B' comes
// from an expansion. The best we can do is merge the mappings for both.
// The *last* token of any top-level macro expansion must be in a file.
// (In the example above, see the closing paren of the expansion of B).
if (!Range.getEnd().isFileID())
return;
// If there's a current expansion that encloses this one, this one can't be
// top-level.
if (LastExpansionEnd.isValid() &&
!SM.isBeforeInTranslationUnit(LastExpansionEnd, Range.getEnd()))
return;
// If the macro invocation (B) starts in a macro (A) but ends in a file,
// we'll create a merged mapping for A + B by overwriting the endpoint for
// A's startpoint.
if (!Range.getBegin().isFileID()) {
Range.setBegin(SM.getExpansionLoc(Range.getBegin()));
assert(Collector->Expansions.count(Range.getBegin()) &&
"Overlapping macros should have same expansion location");
}
Collector->Expansions[Range.getBegin()] = Range.getEnd();
LastExpansionEnd = Range.getEnd();
}
// FIXME: handle directives like #pragma, #include, etc.
private:
TokenCollector *Collector;
/// Used to detect recursive macro expansions.
SourceLocation LastExpansionEnd;
};
/// Fills in the TokenBuffer by tracing the run of a preprocessor. The
/// implementation tracks the tokens, macro expansions and directives coming
/// from the preprocessor and:
/// - for each token, figures out if it is a part of an expanded token stream,
/// spelled token stream or both. Stores the tokens appropriately.
/// - records mappings from the spelled to expanded token ranges, e.g. for macro
/// expansions.
/// FIXME: also properly record:
/// - #include directives,
/// - #pragma, #line and other PP directives,
/// - skipped pp regions,
/// - ...
TokenCollector::TokenCollector(Preprocessor &PP) : PP(PP) {
// Collect the expanded token stream during preprocessing.
PP.setTokenWatcher([this](const clang::Token &T) {
if (T.isAnnotation())
return;
DEBUG_WITH_TYPE("collect-tokens", llvm::dbgs()
<< "Token: "
<< syntax::Token(T).dumpForTests(
this->PP.getSourceManager())
<< "\n"
);
Expanded.push_back(syntax::Token(T));
});
// And locations of macro calls, to properly recover boundaries of those in
// case of empty expansions.
auto CB = std::make_unique<CollectPPExpansions>(*this);
this->Collector = CB.get();
PP.addPPCallbacks(std::move(CB));
}
/// Builds mappings and spelled tokens in the TokenBuffer based on the expanded
/// token stream.
class TokenCollector::Builder {
public:
Builder(std::vector<syntax::Token> Expanded, PPExpansions CollectedExpansions,
const SourceManager &SM, const LangOptions &LangOpts)
: Result(SM), CollectedExpansions(std::move(CollectedExpansions)), SM(SM),
LangOpts(LangOpts) {
Result.ExpandedTokens = std::move(Expanded);
}
TokenBuffer build() && {
assert(!Result.ExpandedTokens.empty());
assert(Result.ExpandedTokens.back().kind() == tok::eof);
// Tokenize every file that contributed tokens to the expanded stream.
buildSpelledTokens();
// The expanded token stream consists of runs of tokens that came from
// the same source (a macro expansion, part of a file etc).
// Between these runs are the logical positions of spelled tokens that
// didn't expand to anything.
while (NextExpanded < Result.ExpandedTokens.size() - 1 /* eof */) {
// Create empty mappings for spelled tokens that expanded to nothing here.
// May advance NextSpelled, but NextExpanded is unchanged.
discard();
// Create mapping for a contiguous run of expanded tokens.
// Advances NextExpanded past the run, and NextSpelled accordingly.
unsigned OldPosition = NextExpanded;
advance();
if (NextExpanded == OldPosition)
diagnoseAdvanceFailure();
}
// If any tokens remain in any of the files, they didn't expand to anything.
// Create empty mappings up until the end of the file.
for (const auto &File : Result.Files)
discard(File.first);
#ifndef NDEBUG
for (auto &pair : Result.Files) {
auto &mappings = pair.second.Mappings;
assert(llvm::is_sorted(mappings, [](const TokenBuffer::Mapping &M1,
const TokenBuffer::Mapping &M2) {
return M1.BeginSpelled < M2.BeginSpelled &&
M1.EndSpelled < M2.EndSpelled &&
M1.BeginExpanded < M2.BeginExpanded &&
M1.EndExpanded < M2.EndExpanded;
}));
}
#endif
return std::move(Result);
}
private:
// Consume a sequence of spelled tokens that didn't expand to anything.
// In the simplest case, skips spelled tokens until finding one that produced
// the NextExpanded token, and creates an empty mapping for them.
// If Drain is provided, skips remaining tokens from that file instead.
void discard(llvm::Optional<FileID> Drain = llvm::None) {
SourceLocation Target =
Drain ? SM.getLocForEndOfFile(*Drain)
: SM.getExpansionLoc(
Result.ExpandedTokens[NextExpanded].location());
FileID File = SM.getFileID(Target);
const auto &SpelledTokens = Result.Files[File].SpelledTokens;
auto &NextSpelled = this->NextSpelled[File];
TokenBuffer::Mapping Mapping;
Mapping.BeginSpelled = NextSpelled;
// When dropping trailing tokens from a file, the empty mapping should
// be positioned within the file's expanded-token range (at the end).
Mapping.BeginExpanded = Mapping.EndExpanded =
Drain ? Result.Files[*Drain].EndExpanded : NextExpanded;
// We may want to split into several adjacent empty mappings.
// FlushMapping() emits the current mapping and starts a new one.
auto FlushMapping = [&, this] {
Mapping.EndSpelled = NextSpelled;
if (Mapping.BeginSpelled != Mapping.EndSpelled)
Result.Files[File].Mappings.push_back(Mapping);
Mapping.BeginSpelled = NextSpelled;
};
while (NextSpelled < SpelledTokens.size() &&
SpelledTokens[NextSpelled].location() < Target) {
// If we know mapping bounds at [NextSpelled, KnownEnd] (macro expansion)
// then we want to partition our (empty) mapping.
// [Start, NextSpelled) [NextSpelled, KnownEnd] (KnownEnd, Target)
SourceLocation KnownEnd =
CollectedExpansions.lookup(SpelledTokens[NextSpelled].location());
if (KnownEnd.isValid()) {
FlushMapping(); // Emits [Start, NextSpelled)
while (NextSpelled < SpelledTokens.size() &&
SpelledTokens[NextSpelled].location() <= KnownEnd)
++NextSpelled;
FlushMapping(); // Emits [NextSpelled, KnownEnd]
// Now the loop contitues and will emit (KnownEnd, Target).
} else {
++NextSpelled;
}
}
FlushMapping();
}
// Consumes the NextExpanded token and others that are part of the same run.
// Increases NextExpanded and NextSpelled by at least one, and adds a mapping
// (unless this is a run of file tokens, which we represent with no mapping).
void advance() {
const syntax::Token &Tok = Result.ExpandedTokens[NextExpanded];
SourceLocation Expansion = SM.getExpansionLoc(Tok.location());
FileID File = SM.getFileID(Expansion);
const auto &SpelledTokens = Result.Files[File].SpelledTokens;
auto &NextSpelled = this->NextSpelled[File];
if (Tok.location().isFileID()) {
// A run of file tokens continues while the expanded/spelled tokens match.
while (NextSpelled < SpelledTokens.size() &&
NextExpanded < Result.ExpandedTokens.size() &&
SpelledTokens[NextSpelled].location() ==
Result.ExpandedTokens[NextExpanded].location()) {
++NextSpelled;
++NextExpanded;
}
// We need no mapping for file tokens copied to the expanded stream.
} else {
// We found a new macro expansion. We should have its spelling bounds.
auto End = CollectedExpansions.lookup(Expansion);
assert(End.isValid() && "Macro expansion wasn't captured?");
// Mapping starts here...
TokenBuffer::Mapping Mapping;
Mapping.BeginExpanded = NextExpanded;
Mapping.BeginSpelled = NextSpelled;
// ... consumes spelled tokens within bounds we captured ...
while (NextSpelled < SpelledTokens.size() &&
SpelledTokens[NextSpelled].location() <= End)
++NextSpelled;
// ... consumes expanded tokens rooted at the same expansion ...
while (NextExpanded < Result.ExpandedTokens.size() &&
SM.getExpansionLoc(
Result.ExpandedTokens[NextExpanded].location()) == Expansion)
++NextExpanded;
// ... and ends here.
Mapping.EndExpanded = NextExpanded;
Mapping.EndSpelled = NextSpelled;
Result.Files[File].Mappings.push_back(Mapping);
}
}
// advance() is supposed to consume at least one token - if not, we crash.
void diagnoseAdvanceFailure() {
#ifndef NDEBUG
// Show the failed-to-map token in context.
for (unsigned I = (NextExpanded < 10) ? 0 : NextExpanded - 10;
I < NextExpanded + 5 && I < Result.ExpandedTokens.size(); ++I) {
const char *L =
(I == NextExpanded) ? "!! " : (I < NextExpanded) ? "ok " : " ";
llvm::errs() << L << Result.ExpandedTokens[I].dumpForTests(SM) << "\n";
}
#endif
llvm_unreachable("Couldn't map expanded token to spelled tokens!");
}
/// Initializes TokenBuffer::Files and fills spelled tokens and expanded
/// ranges for each of the files.
void buildSpelledTokens() {
for (unsigned I = 0; I < Result.ExpandedTokens.size(); ++I) {
const auto &Tok = Result.ExpandedTokens[I];
auto FID = SM.getFileID(SM.getExpansionLoc(Tok.location()));
auto It = Result.Files.try_emplace(FID);
TokenBuffer::MarkedFile &File = It.first->second;
// The eof token should not be considered part of the main-file's range.
File.EndExpanded = Tok.kind() == tok::eof ? I : I + 1;
if (!It.second)
continue; // we have seen this file before.
// This is the first time we see this file.
File.BeginExpanded = I;
File.SpelledTokens = tokenize(FID, SM, LangOpts);
}
}
TokenBuffer Result;
unsigned NextExpanded = 0; // cursor in ExpandedTokens
llvm::DenseMap<FileID, unsigned> NextSpelled; // cursor in SpelledTokens
PPExpansions CollectedExpansions;
const SourceManager &SM;
const LangOptions &LangOpts;
};
TokenBuffer TokenCollector::consume() && {
PP.setTokenWatcher(nullptr);
Collector->disable();
return Builder(std::move(Expanded), std::move(Expansions),
PP.getSourceManager(), PP.getLangOpts())
.build();
}
std::string syntax::Token::str() const {
return std::string(llvm::formatv("Token({0}, length = {1})",
tok::getTokenName(kind()), length()));
}
std::string syntax::Token::dumpForTests(const SourceManager &SM) const {
return std::string(llvm::formatv("Token(`{0}`, {1}, length = {2})", text(SM),
tok::getTokenName(kind()), length()));
}
std::string TokenBuffer::dumpForTests() const {
auto PrintToken = [this](const syntax::Token &T) -> std::string {
if (T.kind() == tok::eof)
return "<eof>";
return std::string(T.text(*SourceMgr));
};
auto DumpTokens = [this, &PrintToken](llvm::raw_ostream &OS,
llvm::ArrayRef<syntax::Token> Tokens) {
if (Tokens.empty()) {
OS << "<empty>";
return;
}
OS << Tokens[0].text(*SourceMgr);
for (unsigned I = 1; I < Tokens.size(); ++I) {
if (Tokens[I].kind() == tok::eof)
continue;
OS << " " << PrintToken(Tokens[I]);
}
};
std::string Dump;
llvm::raw_string_ostream OS(Dump);
OS << "expanded tokens:\n"
<< " ";
// (!) we do not show '<eof>'.
DumpTokens(OS, llvm::makeArrayRef(ExpandedTokens).drop_back());
OS << "\n";
std::vector<FileID> Keys;
for (auto F : Files)
Keys.push_back(F.first);
llvm::sort(Keys);
for (FileID ID : Keys) {
const MarkedFile &File = Files.find(ID)->second;
auto *Entry = SourceMgr->getFileEntryForID(ID);
if (!Entry)
continue; // Skip builtin files.
OS << llvm::formatv("file '{0}'\n", Entry->getName())
<< " spelled tokens:\n"
<< " ";
DumpTokens(OS, File.SpelledTokens);
OS << "\n";
if (File.Mappings.empty()) {
OS << " no mappings.\n";
continue;
}
OS << " mappings:\n";
for (auto &M : File.Mappings) {
OS << llvm::formatv(
" ['{0}'_{1}, '{2}'_{3}) => ['{4}'_{5}, '{6}'_{7})\n",
PrintToken(File.SpelledTokens[M.BeginSpelled]), M.BeginSpelled,
M.EndSpelled == File.SpelledTokens.size()
? "<eof>"
: PrintToken(File.SpelledTokens[M.EndSpelled]),
M.EndSpelled, PrintToken(ExpandedTokens[M.BeginExpanded]),
M.BeginExpanded, PrintToken(ExpandedTokens[M.EndExpanded]),
M.EndExpanded);
}
}
return Dump;
}
diff --git a/contrib/llvm-project/libcxx/include/__config b/contrib/llvm-project/libcxx/include/__config
index 8c2f7614af53..589b5c3b2241 100644
--- a/contrib/llvm-project/libcxx/include/__config
+++ b/contrib/llvm-project/libcxx/include/__config
@@ -1,1224 +1,1231 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP___CONFIG
#define _LIBCPP___CONFIG
#include <__config_site>
#if defined(_MSC_VER) && !defined(__clang__)
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# define _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
# endif
#endif
#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
# pragma GCC system_header
#endif
+#if defined(__apple_build_version__)
+# define _LIBCPP_COMPILER_CLANG_BASED
+# define _LIBCPP_APPLE_CLANG_VER (__apple_build_version__ / 10000)
+#elif defined(__clang__)
+# define _LIBCPP_COMPILER_CLANG_BASED
+# define _LIBCPP_CLANG_VER (__clang_major__ * 100 + __clang_minor__)
+#elif defined(__GNUC__)
+# define _LIBCPP_COMPILER_GCC
+#elif defined(_MSC_VER)
+# define _LIBCPP_COMPILER_MSVC
+#endif
+
#ifdef __cplusplus
-# define _LIBCPP_VERSION 15000
+# define _LIBCPP_VERSION 15003
# define _LIBCPP_CONCAT_IMPL(_X, _Y) _X##_Y
# define _LIBCPP_CONCAT(_X, _Y) _LIBCPP_CONCAT_IMPL(_X, _Y)
// Valid C++ identifier that revs with every libc++ version. This can be used to
// generate identifiers that must be unique for every released libc++ version.
# define _LIBCPP_VERSIONED_IDENTIFIER _LIBCPP_CONCAT(v, _LIBCPP_VERSION)
# if __STDC_HOSTED__ == 0
# define _LIBCPP_FREESTANDING
# endif
# ifndef _LIBCPP_STD_VER
# if __cplusplus <= 201103L
# define _LIBCPP_STD_VER 11
# elif __cplusplus <= 201402L
# define _LIBCPP_STD_VER 14
# elif __cplusplus <= 201703L
# define _LIBCPP_STD_VER 17
# elif __cplusplus <= 202002L
# define _LIBCPP_STD_VER 20
# else
# define _LIBCPP_STD_VER 22 // current year, or date of c++2b ratification
# endif
# endif // _LIBCPP_STD_VER
# if defined(__ELF__)
# define _LIBCPP_OBJECT_FORMAT_ELF 1
# elif defined(__MACH__)
# define _LIBCPP_OBJECT_FORMAT_MACHO 1
# elif defined(_WIN32)
# define _LIBCPP_OBJECT_FORMAT_COFF 1
# elif defined(__wasm__)
# define _LIBCPP_OBJECT_FORMAT_WASM 1
# elif defined(_AIX)
# define _LIBCPP_OBJECT_FORMAT_XCOFF 1
# else
// ... add new file formats here ...
# endif
# if _LIBCPP_ABI_VERSION >= 2
// Change short string representation so that string data starts at offset 0,
// improving its alignment in some cases.
# define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
// Fix deque iterator type in order to support incomplete types.
# define _LIBCPP_ABI_INCOMPLETE_TYPES_IN_DEQUE
// Fix undefined behavior in how std::list stores its linked nodes.
# define _LIBCPP_ABI_LIST_REMOVE_NODE_POINTER_UB
// Fix undefined behavior in how __tree stores its end and parent nodes.
# define _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB
// Fix undefined behavior in how __hash_table stores its pointer types.
# define _LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB
# define _LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB
# define _LIBCPP_ABI_FIX_UNORDERED_CONTAINER_SIZE_TYPE
// Define a key function for `bad_function_call` in the library, to centralize
// its vtable and typeinfo to libc++ rather than having all other libraries
// using that class define their own copies.
# define _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION
// Override the default return value of exception::what() for
// bad_function_call::what() with a string that is specific to
// bad_function_call (see http://wg21.link/LWG2233). This is an ABI break
// because it changes the vtable layout of bad_function_call.
# define _LIBCPP_ABI_BAD_FUNCTION_CALL_GOOD_WHAT_MESSAGE
// Enable optimized version of __do_get_(un)signed which avoids redundant copies.
# define _LIBCPP_ABI_OPTIMIZED_LOCALE_NUM_GET
// Give reverse_iterator<T> one data member of type T, not two.
// Also, in C++17 and later, don't derive iterator types from std::iterator.
# define _LIBCPP_ABI_NO_ITERATOR_BASES
// Use the smallest possible integer type to represent the index of the variant.
// Previously libc++ used "unsigned int" exclusively.
# define _LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION
// Unstable attempt to provide a more optimized std::function
# define _LIBCPP_ABI_OPTIMIZED_FUNCTION
// All the regex constants must be distinct and nonzero.
# define _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO
// Re-worked external template instantiations for std::string with a focus on
// performance and fast-path inlining.
# define _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION
// Enable clang::trivial_abi on std::unique_ptr.
# define _LIBCPP_ABI_ENABLE_UNIQUE_PTR_TRIVIAL_ABI
// Enable clang::trivial_abi on std::shared_ptr and std::weak_ptr
# define _LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI
// std::random_device holds some state when it uses an implementation that gets
// entropy from a file (see _LIBCPP_USING_DEV_RANDOM). When switching from this
// implementation to another one on a platform that has already shipped
// std::random_device, one needs to retain the same object layout to remain ABI
// compatible. This switch removes these workarounds for platforms that don't care
// about ABI compatibility.
# define _LIBCPP_ABI_NO_RANDOM_DEVICE_COMPATIBILITY_LAYOUT
// Don't export the legacy __basic_string_common class and its methods from the built library.
# define _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON
// Don't export the legacy __vector_base_common class and its methods from the built library.
# define _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON
// According to the Standard, `bitset::operator[] const` returns bool
# define _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL
// Remove the base 10 implementation of std::to_chars from the dylib.
// The implementation moved to the header, but we still export the symbols from
// the dylib for backwards compatibility.
# define _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10
# elif _LIBCPP_ABI_VERSION == 1
# if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
// Enable compiling copies of now inline methods into the dylib to support
// applications compiled against older libraries. This is unnecessary with
// COFF dllexport semantics, since dllexport forces a non-inline definition
// of inline functions to be emitted anyway. Our own non-inline copy would
// conflict with the dllexport-emitted copy, so we disable it. For XCOFF,
// the linker will take issue with the symbols in the shared object if the
// weak inline methods get visibility (such as from -fvisibility-inlines-hidden),
// so disable it.
# define _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
# endif
// Feature macros for disabling pre ABI v1 features. All of these options
// are deprecated.
# if defined(__FreeBSD__)
# define _LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR
# endif
# endif
# if defined(_LIBCPP_BUILDING_LIBRARY) || _LIBCPP_ABI_VERSION >= 2
// Enable additional explicit instantiations of iostreams components. This
// reduces the number of weak definitions generated in programs that use
// iostreams by providing a single strong definition in the shared library.
# define _LIBCPP_ABI_ENABLE_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1
// Define a key function for `bad_function_call` in the library, to centralize
// its vtable and typeinfo to libc++ rather than having all other libraries
// using that class define their own copies.
# define _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION
# endif
# define _LIBCPP_TOSTRING2(x) # x
# define _LIBCPP_TOSTRING(x) _LIBCPP_TOSTRING2(x)
# if __cplusplus < 201103L
# define _LIBCPP_CXX03_LANG
# endif
# ifndef __has_attribute
# define __has_attribute(__x) 0
# endif
# ifndef __has_builtin
# define __has_builtin(__x) 0
# endif
# ifndef __has_extension
# define __has_extension(__x) 0
# endif
# ifndef __has_feature
# define __has_feature(__x) 0
# endif
# ifndef __has_cpp_attribute
# define __has_cpp_attribute(__x) 0
# endif
// '__is_identifier' returns '0' if '__x' is a reserved identifier provided by
// the compiler and '1' otherwise.
# ifndef __is_identifier
# define __is_identifier(__x) 1
# endif
# ifndef __has_declspec_attribute
# define __has_declspec_attribute(__x) 0
# endif
# define __has_keyword(__x) !(__is_identifier(__x))
# ifndef __has_include
# define __has_include(...) 0
# endif
-# if defined(__apple_build_version__)
-# define _LIBCPP_COMPILER_CLANG_BASED
-# define _LIBCPP_APPLE_CLANG_VER (__apple_build_version__ / 10000)
-# elif defined(__clang__)
-# define _LIBCPP_COMPILER_CLANG_BASED
-# define _LIBCPP_CLANG_VER (__clang_major__ * 100 + __clang_minor__)
-# elif defined(__GNUC__)
-# define _LIBCPP_COMPILER_GCC
-# elif defined(_MSC_VER)
-# define _LIBCPP_COMPILER_MSVC
-# endif
-
# if !defined(_LIBCPP_COMPILER_CLANG_BASED) && __cplusplus < 201103L
# error "libc++ only supports C++03 with Clang-based compilers. Please enable C++11"
# endif
# ifdef _LIBCPP_COMPILER_MSVC
# error If you successfully use libc++ with MSVC please tell the libc++ developers and consider upstreaming your \
changes. We are not aware of anybody using this configuration and know that at least some code is currently broken. \
If there are users of this configuration we are happy to provide support.
# endif
// FIXME: ABI detection should be done via compiler builtin macros. This
// is just a placeholder until Clang implements such macros. For now assume
// that Windows compilers pretending to be MSVC++ target the Microsoft ABI,
// and allow the user to explicitly specify the ABI to handle cases where this
// heuristic falls short.
# if defined(_LIBCPP_ABI_FORCE_ITANIUM) && defined(_LIBCPP_ABI_FORCE_MICROSOFT)
# error "Only one of _LIBCPP_ABI_FORCE_ITANIUM and _LIBCPP_ABI_FORCE_MICROSOFT can be defined"
# elif defined(_LIBCPP_ABI_FORCE_ITANIUM)
# define _LIBCPP_ABI_ITANIUM
# elif defined(_LIBCPP_ABI_FORCE_MICROSOFT)
# define _LIBCPP_ABI_MICROSOFT
# else
# if defined(_WIN32) && defined(_MSC_VER)
# define _LIBCPP_ABI_MICROSOFT
# else
# define _LIBCPP_ABI_ITANIUM
# endif
# endif
# if defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_NO_VCRUNTIME)
# define _LIBCPP_ABI_VCRUNTIME
# endif
# if __has_feature(experimental_library)
# ifndef _LIBCPP_ENABLE_EXPERIMENTAL
# define _LIBCPP_ENABLE_EXPERIMENTAL
# endif
# endif
// Incomplete features get their own specific disabling flags. This makes it
// easier to grep for target specific flags once the feature is complete.
# if !defined(_LIBCPP_ENABLE_EXPERIMENTAL) && !defined(_LIBCPP_BUILDING_LIBRARY)
# define _LIBCPP_HAS_NO_INCOMPLETE_FORMAT
# define _LIBCPP_HAS_NO_INCOMPLETE_RANGES
# endif
// Need to detect which libc we're using if we're on Linux.
# if defined(__linux__)
# include <features.h>
# if defined(__GLIBC_PREREQ)
# define _LIBCPP_GLIBC_PREREQ(a, b) __GLIBC_PREREQ(a, b)
# else
# define _LIBCPP_GLIBC_PREREQ(a, b) 0
# endif // defined(__GLIBC_PREREQ)
# endif // defined(__linux__)
# if defined(__MVS__)
# include <features.h> // for __NATIVE_ASCII_F
# endif
# ifdef __LITTLE_ENDIAN__
# if __LITTLE_ENDIAN__
# define _LIBCPP_LITTLE_ENDIAN
# endif // __LITTLE_ENDIAN__
# endif // __LITTLE_ENDIAN__
# ifdef __BIG_ENDIAN__
# if __BIG_ENDIAN__
# define _LIBCPP_BIG_ENDIAN
# endif // __BIG_ENDIAN__
# endif // __BIG_ENDIAN__
# ifdef __BYTE_ORDER__
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define _LIBCPP_LITTLE_ENDIAN
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define _LIBCPP_BIG_ENDIAN
# endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# endif // __BYTE_ORDER__
# ifdef __FreeBSD__
# include <sys/endian.h>
# include <osreldate.h>
# if _BYTE_ORDER == _LITTLE_ENDIAN
# define _LIBCPP_LITTLE_ENDIAN
# else // _BYTE_ORDER == _LITTLE_ENDIAN
# define _LIBCPP_BIG_ENDIAN
# endif // _BYTE_ORDER == _LITTLE_ENDIAN
# endif // __FreeBSD__
# if defined(__NetBSD__) || defined(__OpenBSD__)
# include <sys/endian.h>
# if _BYTE_ORDER == _LITTLE_ENDIAN
# define _LIBCPP_LITTLE_ENDIAN
# else // _BYTE_ORDER == _LITTLE_ENDIAN
# define _LIBCPP_BIG_ENDIAN
# endif // _BYTE_ORDER == _LITTLE_ENDIAN
# endif // defined(__NetBSD__) || defined(__OpenBSD__)
# if defined(_WIN32)
# define _LIBCPP_WIN32API
# define _LIBCPP_LITTLE_ENDIAN
# define _LIBCPP_SHORT_WCHAR 1
// Both MinGW and native MSVC provide a "MSVC"-like environment
# define _LIBCPP_MSVCRT_LIKE
// If mingw not explicitly detected, assume using MS C runtime only if
// a MS compatibility version is specified.
# if defined(_MSC_VER) && !defined(__MINGW32__)
# define _LIBCPP_MSVCRT // Using Microsoft's C Runtime library
# endif
# if (defined(_M_AMD64) || defined(__x86_64__)) || (defined(_M_ARM) || defined(__arm__))
# define _LIBCPP_HAS_BITSCAN64
# endif
# define _LIBCPP_HAS_OPEN_WITH_WCHAR
# endif // defined(_WIN32)
# ifdef __sun__
# include <sys/isa_defs.h>
# ifdef _LITTLE_ENDIAN
# define _LIBCPP_LITTLE_ENDIAN
# else
# define _LIBCPP_BIG_ENDIAN
# endif
# endif // __sun__
# if defined(_AIX) && !defined(__64BIT__)
// The size of wchar is 2 byte on 32-bit mode on AIX.
# define _LIBCPP_SHORT_WCHAR 1
# endif
// Libc++ supports various implementations of std::random_device.
//
// _LIBCPP_USING_DEV_RANDOM
// Read entropy from the given file, by default `/dev/urandom`.
// If a token is provided, it is assumed to be the path to a file
// to read entropy from. This is the default behavior if nothing
// else is specified. This implementation requires storing state
// inside `std::random_device`.
//
// _LIBCPP_USING_ARC4_RANDOM
// Use arc4random(). This allows obtaining random data even when
// using sandboxing mechanisms. On some platforms like Apple, this
// is the recommended source of entropy for user-space programs.
// When this option is used, the token passed to `std::random_device`'s
// constructor *must* be "/dev/urandom" -- anything else is an error.
//
// _LIBCPP_USING_GETENTROPY
// Use getentropy().
// When this option is used, the token passed to `std::random_device`'s
// constructor *must* be "/dev/urandom" -- anything else is an error.
//
// _LIBCPP_USING_FUCHSIA_CPRNG
// Use Fuchsia's zx_cprng_draw() system call, which is specified to
// deliver high-quality entropy and cannot fail.
// When this option is used, the token passed to `std::random_device`'s
// constructor *must* be "/dev/urandom" -- anything else is an error.
//
// _LIBCPP_USING_NACL_RANDOM
// NaCl's sandbox (which PNaCl also runs in) doesn't allow filesystem access,
// including accesses to the special files under `/dev`. This implementation
// uses the NaCL syscall `nacl_secure_random_init()` to get entropy.
// When this option is used, the token passed to `std::random_device`'s
// constructor *must* be "/dev/urandom" -- anything else is an error.
//
// _LIBCPP_USING_WIN32_RANDOM
// Use rand_s(), for use on Windows.
// When this option is used, the token passed to `std::random_device`'s
// constructor *must* be "/dev/urandom" -- anything else is an error.
# if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__DragonFly__) || defined(__sun__)
# define _LIBCPP_USING_ARC4_RANDOM
# elif defined(__wasi__) || defined(__EMSCRIPTEN__)
# define _LIBCPP_USING_GETENTROPY
# elif defined(__Fuchsia__)
# define _LIBCPP_USING_FUCHSIA_CPRNG
# elif defined(__native_client__)
# define _LIBCPP_USING_NACL_RANDOM
# elif defined(_LIBCPP_WIN32API)
# define _LIBCPP_USING_WIN32_RANDOM
# else
# define _LIBCPP_USING_DEV_RANDOM
# endif
# if !defined(_LIBCPP_LITTLE_ENDIAN) && !defined(_LIBCPP_BIG_ENDIAN)
# include <endian.h>
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define _LIBCPP_LITTLE_ENDIAN
# elif __BYTE_ORDER == __BIG_ENDIAN
# define _LIBCPP_BIG_ENDIAN
# else // __BYTE_ORDER == __BIG_ENDIAN
# error unable to determine endian
# endif
# endif // !defined(_LIBCPP_LITTLE_ENDIAN) && !defined(_LIBCPP_BIG_ENDIAN)
# if __has_attribute(__no_sanitize__) && !defined(_LIBCPP_COMPILER_GCC)
# define _LIBCPP_NO_CFI __attribute__((__no_sanitize__("cfi")))
# else
# define _LIBCPP_NO_CFI
# endif
# ifndef _LIBCPP_CXX03_LANG
# define _LIBCPP_ALIGNOF(_Tp) alignof(_Tp)
# define _ALIGNAS_TYPE(x) alignas(x)
# define _ALIGNAS(x) alignas(x)
# define _LIBCPP_NORETURN [[noreturn]]
# define _NOEXCEPT noexcept
# define _NOEXCEPT_(x) noexcept(x)
# else
# define _LIBCPP_ALIGNOF(_Tp) _Alignof(_Tp)
# define _ALIGNAS_TYPE(x) __attribute__((__aligned__(_LIBCPP_ALIGNOF(x))))
# define _ALIGNAS(x) __attribute__((__aligned__(x)))
# define _LIBCPP_NORETURN __attribute__((noreturn))
# define _LIBCPP_HAS_NO_NOEXCEPT
# define nullptr __nullptr
# define _NOEXCEPT throw()
# define _NOEXCEPT_(x)
typedef __char16_t char16_t;
typedef __char32_t char32_t;
# endif
# if !defined(__cpp_exceptions) || __cpp_exceptions < 199711L
# define _LIBCPP_NO_EXCEPTIONS
# endif
# define _LIBCPP_PREFERRED_ALIGNOF(_Tp) __alignof(_Tp)
# if defined(_LIBCPP_COMPILER_CLANG_BASED)
# if defined(__APPLE__) && !defined(__i386__) && !defined(__x86_64__) && (!defined(__arm__) || __ARM_ARCH_7K__ >= 2)
# define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
# endif
// Objective-C++ features (opt-in)
# if __has_feature(objc_arc)
# define _LIBCPP_HAS_OBJC_ARC
# endif
# if __has_feature(objc_arc_weak)
# define _LIBCPP_HAS_OBJC_ARC_WEAK
# endif
# if __has_extension(blocks)
# define _LIBCPP_HAS_EXTENSION_BLOCKS
# endif
# if defined(_LIBCPP_HAS_EXTENSION_BLOCKS) && defined(__APPLE__)
# define _LIBCPP_HAS_BLOCKS_RUNTIME
# endif
# if !__has_feature(address_sanitizer)
# define _LIBCPP_HAS_NO_ASAN
# endif
// Allow for build-time disabling of unsigned integer sanitization
# if __has_attribute(no_sanitize)
# define _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK __attribute__((__no_sanitize__("unsigned-integer-overflow")))
# endif
# define _LIBCPP_ALWAYS_INLINE __attribute__((__always_inline__))
# define _LIBCPP_DISABLE_EXTENSION_WARNING __extension__
# elif defined(_LIBCPP_COMPILER_GCC)
# if !defined(__SANITIZE_ADDRESS__)
# define _LIBCPP_HAS_NO_ASAN
# endif
# define _LIBCPP_ALWAYS_INLINE __attribute__((__always_inline__))
# define _LIBCPP_DISABLE_EXTENSION_WARNING __extension__
# elif defined(_LIBCPP_COMPILER_MSVC)
# define _LIBCPP_WARNING(x) __pragma(message(__FILE__ "(" _LIBCPP_TOSTRING(__LINE__) ") : warning note: " x))
# if _MSC_VER < 1900
# error "MSVC versions prior to Visual Studio 2015 are not supported"
# endif
# define _LIBCPP_NORETURN __declspec(noreturn)
# define _LIBCPP_WEAK
# define _LIBCPP_HAS_NO_ASAN
# define _LIBCPP_ALWAYS_INLINE __forceinline
# define _LIBCPP_HAS_NO_VECTOR_EXTENSION
# define _LIBCPP_DISABLE_EXTENSION_WARNING
# endif // _LIBCPP_COMPILER_[CLANG|GCC|MSVC]
# if defined(_LIBCPP_OBJECT_FORMAT_COFF)
# ifdef _DLL
# define _LIBCPP_CRT_FUNC __declspec(dllimport)
# else
# define _LIBCPP_CRT_FUNC
# endif
# if defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) || (defined(__MINGW32__) && !defined(_LIBCPP_BUILDING_LIBRARY))
# define _LIBCPP_DLL_VIS
# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
# define _LIBCPP_OVERRIDABLE_FUNC_VIS
# define _LIBCPP_EXPORTED_FROM_ABI
# elif defined(_LIBCPP_BUILDING_LIBRARY)
# define _LIBCPP_DLL_VIS __declspec(dllexport)
# if defined(__MINGW32__)
# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_DLL_VIS
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
# else
# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS _LIBCPP_DLL_VIS
# endif
# define _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_DLL_VIS
# define _LIBCPP_EXPORTED_FROM_ABI __declspec(dllexport)
# else
# define _LIBCPP_DLL_VIS __declspec(dllimport)
# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_DLL_VIS
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
# define _LIBCPP_OVERRIDABLE_FUNC_VIS
# define _LIBCPP_EXPORTED_FROM_ABI __declspec(dllimport)
# endif
# define _LIBCPP_TYPE_VIS _LIBCPP_DLL_VIS
# define _LIBCPP_FUNC_VIS _LIBCPP_DLL_VIS
# define _LIBCPP_EXCEPTION_ABI _LIBCPP_DLL_VIS
# define _LIBCPP_HIDDEN
# define _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
# define _LIBCPP_TEMPLATE_VIS
# define _LIBCPP_TEMPLATE_DATA_VIS
# define _LIBCPP_ENUM_VIS
# else
# if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
# define _LIBCPP_VISIBILITY(vis) __attribute__((__visibility__(vis)))
# else
# define _LIBCPP_VISIBILITY(vis)
# endif
# define _LIBCPP_HIDDEN _LIBCPP_VISIBILITY("hidden")
# define _LIBCPP_FUNC_VIS _LIBCPP_VISIBILITY("default")
# define _LIBCPP_TYPE_VIS _LIBCPP_VISIBILITY("default")
# define _LIBCPP_TEMPLATE_DATA_VIS _LIBCPP_VISIBILITY("default")
# define _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_VISIBILITY("default")
# define _LIBCPP_EXCEPTION_ABI _LIBCPP_VISIBILITY("default")
# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_VISIBILITY("default")
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
// TODO: Make this a proper customization point or remove the option to override it.
# ifndef _LIBCPP_OVERRIDABLE_FUNC_VIS
# define _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_VISIBILITY("default")
# endif
# if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
// The inline should be removed once PR32114 is resolved
# define _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS inline _LIBCPP_HIDDEN
# else
# define _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
# endif
# if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
# if __has_attribute(__type_visibility__)
# define _LIBCPP_TEMPLATE_VIS __attribute__((__type_visibility__("default")))
# else
# define _LIBCPP_TEMPLATE_VIS __attribute__((__visibility__("default")))
# endif
# else
# define _LIBCPP_TEMPLATE_VIS
# endif
# if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) && __has_attribute(__type_visibility__)
# define _LIBCPP_ENUM_VIS __attribute__((__type_visibility__("default")))
# else
# define _LIBCPP_ENUM_VIS
# endif
# endif // defined(_LIBCPP_OBJECT_FORMAT_COFF)
# if __has_attribute(exclude_from_explicit_instantiation)
# define _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((__exclude_from_explicit_instantiation__))
# else
// Try to approximate the effect of exclude_from_explicit_instantiation
// (which is that entities are not assumed to be provided by explicit
// template instantiations in the dylib) by always inlining those entities.
# define _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION _LIBCPP_ALWAYS_INLINE
# endif
// This macro marks a symbol as being hidden from libc++'s ABI. This is achieved
// on two levels:
// 1. The symbol is given hidden visibility, which ensures that users won't start exporting
// symbols from their dynamic library by means of using the libc++ headers. This ensures
// that those symbols stay private to the dynamic library in which it is defined.
//
// 2. The symbol is given an ABI tag that changes with each version of libc++. This ensures
// that no ODR violation can arise from mixing two TUs compiled with different versions
// of libc++ where we would have changed the definition of a symbol. If the symbols shared
// the same name, the ODR would require that their definitions be token-by-token equivalent,
// which basically prevents us from being able to make any change to any function in our
// headers. Using this ABI tag ensures that the symbol name is "bumped" artificially at
// each release, which lets us change the definition of these symbols at our leisure.
// Note that historically, this has been achieved in various ways, including force-inlining
// all functions or giving internal linkage to all functions. Both these (previous) solutions
// suffer from drawbacks that lead notably to code bloat.
//
// Note that we use _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION to ensure that we don't depend
// on _LIBCPP_HIDE_FROM_ABI methods of classes explicitly instantiated in the dynamic library.
//
// TODO: We provide a escape hatch with _LIBCPP_NO_ABI_TAG for folks who want to avoid increasing
// the length of symbols with an ABI tag. In practice, we should remove the escape hatch and
// use compression mangling instead, see https://github.com/itanium-cxx-abi/cxx-abi/issues/70.
# ifndef _LIBCPP_NO_ABI_TAG
# define _LIBCPP_HIDE_FROM_ABI \
_LIBCPP_HIDDEN _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION \
__attribute__((__abi_tag__(_LIBCPP_TOSTRING(_LIBCPP_VERSIONED_IDENTIFIER))))
# else
# define _LIBCPP_HIDE_FROM_ABI _LIBCPP_HIDDEN _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION
# endif
# ifdef _LIBCPP_BUILDING_LIBRARY
# if _LIBCPP_ABI_VERSION > 1
# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_HIDE_FROM_ABI
# else
# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1
# endif
# else
# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_HIDE_FROM_ABI
# endif
// Just so we can migrate to the new macros gradually.
# define _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
// Inline namespaces are available in Clang/GCC/MSVC regardless of C++ dialect.
// clang-format off
# define _LIBCPP_BEGIN_NAMESPACE_STD namespace std { inline namespace _LIBCPP_ABI_NAMESPACE {
# define _LIBCPP_END_NAMESPACE_STD }}
# define _VSTD std
_LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD
# if _LIBCPP_STD_VER > 14
# define _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM \
_LIBCPP_BEGIN_NAMESPACE_STD inline namespace __fs { namespace filesystem {
# else
# define _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM \
_LIBCPP_BEGIN_NAMESPACE_STD namespace __fs { namespace filesystem {
# endif
# define _LIBCPP_END_NAMESPACE_FILESYSTEM _LIBCPP_END_NAMESPACE_STD }}
// clang-format on
# define _VSTD_FS std::__fs::filesystem
# if __has_attribute(__enable_if__)
# define _LIBCPP_PREFERRED_OVERLOAD __attribute__((__enable_if__(true, "")))
# endif
# ifndef __SIZEOF_INT128__
# define _LIBCPP_HAS_NO_INT128
# endif
# ifdef _LIBCPP_CXX03_LANG
# define static_assert(...) _Static_assert(__VA_ARGS__)
# define decltype(...) __decltype(__VA_ARGS__)
# endif // _LIBCPP_CXX03_LANG
# ifdef _LIBCPP_CXX03_LANG
# define _LIBCPP_CONSTEXPR
# else
# define _LIBCPP_CONSTEXPR constexpr
# endif
# ifndef __cpp_consteval
# define _LIBCPP_CONSTEVAL _LIBCPP_CONSTEXPR
# else
# define _LIBCPP_CONSTEVAL consteval
# endif
# ifdef __GNUC__
# define _LIBCPP_NOALIAS __attribute__((__malloc__))
# else
# define _LIBCPP_NOALIAS
# endif
# if __has_attribute(using_if_exists)
# define _LIBCPP_USING_IF_EXISTS __attribute__((using_if_exists))
# else
# define _LIBCPP_USING_IF_EXISTS
# endif
# ifdef _LIBCPP_CXX03_LANG
# define _LIBCPP_DECLARE_STRONG_ENUM(x) \
struct _LIBCPP_TYPE_VIS x { \
enum __lx
// clang-format off
# define _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(x) \
__lx __v_; \
_LIBCPP_INLINE_VISIBILITY x(__lx __v) : __v_(__v) {} \
_LIBCPP_INLINE_VISIBILITY explicit x(int __v) : __v_(static_cast<__lx>(__v)) {} \
_LIBCPP_INLINE_VISIBILITY operator int() const { return __v_; } \
};
// clang-format on
# else // _LIBCPP_CXX03_LANG
# define _LIBCPP_DECLARE_STRONG_ENUM(x) enum class _LIBCPP_ENUM_VIS x
# define _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(x)
# endif // _LIBCPP_CXX03_LANG
# if defined(__APPLE__) || defined(__FreeBSD__) || defined(_LIBCPP_MSVCRT_LIKE) || defined(__sun__) || \
defined(__NetBSD__)
# define _LIBCPP_LOCALE__L_EXTENSIONS 1
# endif
# ifdef __FreeBSD__
# define _DECLARE_C99_LDBL_MATH 1
# endif
// If we are getting operator new from the MSVC CRT, then allocation overloads
// for align_val_t were added in 19.12, aka VS 2017 version 15.3.
# if defined(_LIBCPP_MSVCRT) && defined(_MSC_VER) && _MSC_VER < 1912
# define _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
# elif defined(_LIBCPP_ABI_VCRUNTIME) && !defined(__cpp_aligned_new)
// We're deferring to Microsoft's STL to provide aligned new et al. We don't
// have it unless the language feature test macro is defined.
# define _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
# elif defined(__MVS__)
# define _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
# endif
# if defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) || (!defined(__cpp_aligned_new) || __cpp_aligned_new < 201606)
# define _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
# endif
# if defined(__APPLE__) || defined(__FreeBSD__)
# define _LIBCPP_HAS_DEFAULTRUNELOCALE
# endif
# if defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun__)
# define _LIBCPP_WCTYPE_IS_MASK
# endif
# if _LIBCPP_STD_VER <= 17 || !defined(__cpp_char8_t)
# define _LIBCPP_HAS_NO_CHAR8_T
# endif
// Deprecation macros.
//
// Deprecations warnings are always enabled, except when users explicitly opt-out
// by defining _LIBCPP_DISABLE_DEPRECATION_WARNINGS.
# if !defined(_LIBCPP_DISABLE_DEPRECATION_WARNINGS)
# if __has_attribute(deprecated)
# define _LIBCPP_DEPRECATED __attribute__((deprecated))
# define _LIBCPP_DEPRECATED_(m) __attribute__((deprected(m)))
# elif _LIBCPP_STD_VER > 11
# define _LIBCPP_DEPRECATED [[deprecated]]
# define _LIBCPP_DEPRECATED_(m) [[deprecated(m)]]
# else
# define _LIBCPP_DEPRECATED
# define _LIBCPP_DEPRECATED_(m)
# endif
# else
# define _LIBCPP_DEPRECATED
# define _LIBCPP_DEPRECATED_(m)
# endif
# if !defined(_LIBCPP_CXX03_LANG)
# define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
# else
# define _LIBCPP_DEPRECATED_IN_CXX11
# endif
# if _LIBCPP_STD_VER > 11
# define _LIBCPP_DEPRECATED_IN_CXX14 _LIBCPP_DEPRECATED
# else
# define _LIBCPP_DEPRECATED_IN_CXX14
# endif
# if _LIBCPP_STD_VER > 14
# define _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_DEPRECATED
# else
# define _LIBCPP_DEPRECATED_IN_CXX17
# endif
# if _LIBCPP_STD_VER > 17
# define _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_DEPRECATED
# else
# define _LIBCPP_DEPRECATED_IN_CXX20
# endif
# if !defined(_LIBCPP_HAS_NO_CHAR8_T)
# define _LIBCPP_DEPRECATED_WITH_CHAR8_T _LIBCPP_DEPRECATED
# else
# define _LIBCPP_DEPRECATED_WITH_CHAR8_T
# endif
// Macros to enter and leave a state where deprecation warnings are suppressed.
# if defined(_LIBCPP_COMPILER_CLANG_BASED) || defined(_LIBCPP_COMPILER_GCC)
# define _LIBCPP_SUPPRESS_DEPRECATED_PUSH \
_Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wdeprecated\"") \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
# define _LIBCPP_SUPPRESS_DEPRECATED_POP _Pragma("GCC diagnostic pop")
# else
# define _LIBCPP_SUPPRESS_DEPRECATED_PUSH
# define _LIBCPP_SUPPRESS_DEPRECATED_POP
# endif
# if _LIBCPP_STD_VER <= 11
# define _LIBCPP_EXPLICIT_AFTER_CXX11
# else
# define _LIBCPP_EXPLICIT_AFTER_CXX11 explicit
# endif
# if _LIBCPP_STD_VER > 11
# define _LIBCPP_CONSTEXPR_AFTER_CXX11 constexpr
# else
# define _LIBCPP_CONSTEXPR_AFTER_CXX11
# endif
# if _LIBCPP_STD_VER > 14
# define _LIBCPP_CONSTEXPR_AFTER_CXX14 constexpr
# else
# define _LIBCPP_CONSTEXPR_AFTER_CXX14
# endif
# if _LIBCPP_STD_VER > 17
# define _LIBCPP_CONSTEXPR_AFTER_CXX17 constexpr
# else
# define _LIBCPP_CONSTEXPR_AFTER_CXX17
# endif
# if __has_cpp_attribute(nodiscard) || defined(_LIBCPP_COMPILER_MSVC)
# define _LIBCPP_NODISCARD [[nodiscard]]
# elif defined(_LIBCPP_COMPILER_CLANG_BASED) && !defined(_LIBCPP_CXX03_LANG)
# define _LIBCPP_NODISCARD [[clang::warn_unused_result]]
# else
// We can't use GCC's [[gnu::warn_unused_result]] and
// __attribute__((warn_unused_result)), because GCC does not silence them via
// (void) cast.
# define _LIBCPP_NODISCARD
# endif
// _LIBCPP_NODISCARD_EXT may be used to apply [[nodiscard]] to entities not
// specified as such as an extension.
# if defined(_LIBCPP_ENABLE_NODISCARD) && !defined(_LIBCPP_DISABLE_NODISCARD_EXT)
# define _LIBCPP_NODISCARD_EXT _LIBCPP_NODISCARD
# else
# define _LIBCPP_NODISCARD_EXT
# endif
# if !defined(_LIBCPP_DISABLE_NODISCARD_AFTER_CXX17) && (_LIBCPP_STD_VER > 17 || defined(_LIBCPP_ENABLE_NODISCARD))
# define _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_NODISCARD
# else
# define _LIBCPP_NODISCARD_AFTER_CXX17
# endif
# if __has_attribute(no_destroy)
# define _LIBCPP_NO_DESTROY __attribute__((__no_destroy__))
# else
# define _LIBCPP_NO_DESTROY
# endif
# ifndef _LIBCPP_HAS_NO_ASAN
extern "C" _LIBCPP_FUNC_VIS void
__sanitizer_annotate_contiguous_container(const void*, const void*, const void*, const void*);
# endif
// Try to find out if RTTI is disabled.
# if !defined(__cpp_rtti) || __cpp_rtti < 199711L
# define _LIBCPP_NO_RTTI
# endif
# ifndef _LIBCPP_WEAK
# define _LIBCPP_WEAK __attribute__((__weak__))
# endif
// Thread API
// clang-format off
# if !defined(_LIBCPP_HAS_NO_THREADS) && \
!defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && \
!defined(_LIBCPP_HAS_THREAD_API_WIN32) && \
!defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
# if defined(__FreeBSD__) || \
defined(__wasi__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__) || \
defined(__NuttX__) || \
defined(__linux__) || \
defined(__GNU__) || \
defined(__APPLE__) || \
defined(__sun__) || \
defined(__MVS__) || \
defined(_AIX) || \
defined(__EMSCRIPTEN__)
// clang-format on
# define _LIBCPP_HAS_THREAD_API_PTHREAD
# elif defined(__Fuchsia__)
// TODO(44575): Switch to C11 thread API when possible.
# define _LIBCPP_HAS_THREAD_API_PTHREAD
# elif defined(_LIBCPP_WIN32API)
# define _LIBCPP_HAS_THREAD_API_WIN32
# else
# error "No thread API"
# endif // _LIBCPP_HAS_THREAD_API
# endif // _LIBCPP_HAS_NO_THREADS
# if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
# if defined(__ANDROID__) && __ANDROID_API__ >= 30
# define _LIBCPP_HAS_COND_CLOCKWAIT
# elif defined(_LIBCPP_GLIBC_PREREQ)
# if _LIBCPP_GLIBC_PREREQ(2, 30)
# define _LIBCPP_HAS_COND_CLOCKWAIT
# endif
# endif
# endif
# if defined(_LIBCPP_HAS_NO_THREADS) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
# error _LIBCPP_HAS_THREAD_API_PTHREAD may only be defined when \
_LIBCPP_HAS_NO_THREADS is not defined.
# endif
# if defined(_LIBCPP_HAS_NO_THREADS) && defined(_LIBCPP_HAS_THREAD_API_EXTERNAL)
# error _LIBCPP_HAS_THREAD_API_EXTERNAL may not be defined when \
_LIBCPP_HAS_NO_THREADS is defined.
# endif
# if defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK) && !defined(_LIBCPP_HAS_NO_THREADS)
# error _LIBCPP_HAS_NO_MONOTONIC_CLOCK may only be defined when \
_LIBCPP_HAS_NO_THREADS is defined.
# endif
# if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(__STDCPP_THREADS__)
# define __STDCPP_THREADS__ 1
# endif
// The glibc and Bionic implementation of pthreads implements
// pthread_mutex_destroy as nop for regular mutexes. Additionally, Win32
// mutexes have no destroy mechanism.
//
// This optimization can't be performed on Apple platforms, where
// pthread_mutex_destroy can allow the kernel to release resources.
// See https://llvm.org/D64298 for details.
//
// TODO(EricWF): Enable this optimization on Bionic after speaking to their
// respective stakeholders.
// clang-format off
# if (defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && defined(__GLIBC__)) || \
(defined(_LIBCPP_HAS_THREAD_API_C11) && defined(__Fuchsia__)) || \
defined(_LIBCPP_HAS_THREAD_API_WIN32)
// clang-format on
# define _LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION
# endif
// Destroying a condvar is a nop on Windows.
//
// This optimization can't be performed on Apple platforms, where
// pthread_cond_destroy can allow the kernel to release resources.
// See https://llvm.org/D64298 for details.
//
// TODO(EricWF): This is potentially true for some pthread implementations
// as well.
# if (defined(_LIBCPP_HAS_THREAD_API_C11) && defined(__Fuchsia__)) || defined(_LIBCPP_HAS_THREAD_API_WIN32)
# define _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
# endif
// Some systems do not provide gets() in their C library, for security reasons.
# if defined(_LIBCPP_MSVCRT) || (defined(__FreeBSD_version) && __FreeBSD_version >= 1300043) || defined(__OpenBSD__)
# define _LIBCPP_C_HAS_NO_GETS
# endif
# if defined(__BIONIC__) || defined(__NuttX__) || defined(__Fuchsia__) || defined(__wasi__) || \
defined(_LIBCPP_HAS_MUSL_LIBC) || defined(__OpenBSD__)
# define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE
# endif
# if __has_feature(cxx_atomic) || __has_extension(c_atomic) || __has_keyword(_Atomic)
# define _LIBCPP_HAS_C_ATOMIC_IMP
# elif defined(_LIBCPP_COMPILER_GCC)
# define _LIBCPP_HAS_GCC_ATOMIC_IMP
# endif
# if !defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_GCC_ATOMIC_IMP) && \
!defined(_LIBCPP_HAS_EXTERNAL_ATOMIC_IMP)
# define _LIBCPP_HAS_NO_ATOMIC_HEADER
# else
# ifndef _LIBCPP_ATOMIC_FLAG_TYPE
# define _LIBCPP_ATOMIC_FLAG_TYPE bool
# endif
# ifdef _LIBCPP_FREESTANDING
# define _LIBCPP_ATOMIC_ONLY_USE_BUILTINS
# endif
# endif
# ifndef _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
# define _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
# endif
# if defined(_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS)
# if defined(__clang__) && __has_attribute(acquire_capability)
// Work around the attribute handling in clang. When both __declspec and
// __attribute__ are present, the processing goes awry preventing the definition
// of the types. In MinGW mode, __declspec evaluates to __attribute__, and thus
// combining the two does work.
# if !defined(_MSC_VER)
# define _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS
# endif
# endif
# endif
# ifdef _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS
# define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) __attribute__((x))
# else
# define _LIBCPP_THREAD_SAFETY_ANNOTATION(x)
# endif
# if _LIBCPP_STD_VER > 17
# define _LIBCPP_CONSTINIT constinit
# elif __has_attribute(require_constant_initialization)
# define _LIBCPP_CONSTINIT __attribute__((__require_constant_initialization__))
# else
# define _LIBCPP_CONSTINIT
# endif
# if __has_attribute(diagnose_if) && !defined(_LIBCPP_DISABLE_ADDITIONAL_DIAGNOSTICS)
# define _LIBCPP_DIAGNOSE_WARNING(...) __attribute__((diagnose_if(__VA_ARGS__, "warning")))
# define _LIBCPP_DIAGNOSE_ERROR(...) __attribute__((diagnose_if(__VA_ARGS__, "error")))
# else
# define _LIBCPP_DIAGNOSE_WARNING(...)
# define _LIBCPP_DIAGNOSE_ERROR(...)
# endif
// Use a function like macro to imply that it must be followed by a semicolon
# if __has_cpp_attribute(fallthrough)
# define _LIBCPP_FALLTHROUGH() [[fallthrough]]
# elif __has_attribute(__fallthrough__)
# define _LIBCPP_FALLTHROUGH() __attribute__((__fallthrough__))
# else
# define _LIBCPP_FALLTHROUGH() ((void)0)
# endif
# if __has_attribute(__nodebug__)
# define _LIBCPP_NODEBUG __attribute__((__nodebug__))
# else
# define _LIBCPP_NODEBUG
# endif
# if __has_attribute(__standalone_debug__)
# define _LIBCPP_STANDALONE_DEBUG __attribute__((__standalone_debug__))
# else
# define _LIBCPP_STANDALONE_DEBUG
# endif
# if __has_attribute(__preferred_name__)
# define _LIBCPP_PREFERRED_NAME(x) __attribute__((__preferred_name__(x)))
# else
# define _LIBCPP_PREFERRED_NAME(x)
# endif
// We often repeat things just for handling wide characters in the library.
// When wide characters are disabled, it can be useful to have a quick way of
// disabling it without having to resort to #if-#endif, which has a larger
// impact on readability.
# if defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
# define _LIBCPP_IF_WIDE_CHARACTERS(...)
# else
# define _LIBCPP_IF_WIDE_CHARACTERS(...) __VA_ARGS__
# endif
# if defined(_LIBCPP_ABI_MICROSOFT) && (defined(_LIBCPP_COMPILER_MSVC) || __has_declspec_attribute(empty_bases))
# define _LIBCPP_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
# else
# define _LIBCPP_DECLSPEC_EMPTY_BASES
# endif
# if defined(_LIBCPP_ENABLE_CXX17_REMOVED_FEATURES)
# define _LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR
# define _LIBCPP_ENABLE_CXX17_REMOVED_BINDERS
# define _LIBCPP_ENABLE_CXX17_REMOVED_RANDOM_SHUFFLE
# define _LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS
# define _LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION
# endif // _LIBCPP_ENABLE_CXX17_REMOVED_FEATURES
+// Leave the deprecation notices in by default, but don't remove unary_function and
+// binary_function entirely just yet. That way, folks will have one release to act
+// on the deprecation warnings.
+# ifndef _LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION
+# define _LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION
+# endif
+
# if defined(_LIBCPP_ENABLE_CXX20_REMOVED_FEATURES)
# define _LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS
# define _LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_VOID_SPECIALIZATION
# define _LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS
# define _LIBCPP_ENABLE_CXX20_REMOVED_NEGATORS
# define _LIBCPP_ENABLE_CXX20_REMOVED_RAW_STORAGE_ITERATOR
# define _LIBCPP_ENABLE_CXX20_REMOVED_TYPE_TRAITS
# endif // _LIBCPP_ENABLE_CXX20_REMOVED_FEATURES
# if !defined(__cpp_impl_coroutine) || __cpp_impl_coroutine < 201902L
# define _LIBCPP_HAS_NO_CXX20_COROUTINES
# endif
# define _LIBCPP_PUSH_MACROS _Pragma("push_macro(\"min\")") _Pragma("push_macro(\"max\")")
# define _LIBCPP_POP_MACROS _Pragma("pop_macro(\"min\")") _Pragma("pop_macro(\"max\")")
# ifndef _LIBCPP_NO_AUTO_LINK
# if defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_BUILDING_LIBRARY)
# if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
# pragma comment(lib, "c++.lib")
# else
# pragma comment(lib, "libc++.lib")
# endif
# endif // defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_BUILDING_LIBRARY)
# endif // _LIBCPP_NO_AUTO_LINK
// Configures the fopen close-on-exec mode character, if any. This string will
// be appended to any mode string used by fstream for fopen/fdopen.
//
// Not all platforms support this, but it helps avoid fd-leaks on platforms that
// do.
# if defined(__BIONIC__)
# define _LIBCPP_FOPEN_CLOEXEC_MODE "e"
# else
# define _LIBCPP_FOPEN_CLOEXEC_MODE
# endif
// Support for _FILE_OFFSET_BITS=64 landed gradually in Android, so the full set
// of functions used in cstdio may not be available for low API levels when
// using 64-bit file offsets on LP32.
# if defined(__BIONIC__) && defined(__USE_FILE_OFFSET64) && __ANDROID_API__ < 24
# define _LIBCPP_HAS_NO_FGETPOS_FSETPOS
# endif
# if __has_attribute(init_priority)
// TODO: Remove this once we drop support for building libc++ with old Clangs
# if (defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER < 1200) || \
(defined(__apple_build_version__) && __apple_build_version__ < 13000000)
# define _LIBCPP_INIT_PRIORITY_MAX __attribute__((init_priority(101)))
# else
# define _LIBCPP_INIT_PRIORITY_MAX __attribute__((init_priority(100)))
# endif
# else
# define _LIBCPP_INIT_PRIORITY_MAX
# endif
# if defined(__GNUC__) || defined(__clang__)
// The attribute uses 1-based indices for ordinary and static member functions.
// The attribute uses 2-based indices for non-static member functions.
# define _LIBCPP_ATTRIBUTE_FORMAT(archetype, format_string_index, first_format_arg_index) \
__attribute__((__format__(archetype, format_string_index, first_format_arg_index)))
# else
# define _LIBCPP_ATTRIBUTE_FORMAT(archetype, format_string_index, first_format_arg_index) /* nothing */
# endif
# if __has_cpp_attribute(msvc::no_unique_address)
// MSVC implements [[no_unique_address]] as a silent no-op currently.
// (If/when MSVC breaks its C++ ABI, it will be changed to work as intended.)
// However, MSVC implements [[msvc::no_unique_address]] which does what
// [[no_unique_address]] is supposed to do, in general.
// Clang-cl does not yet (14.0) implement either [[no_unique_address]] or
// [[msvc::no_unique_address]] though. If/when it does implement
// [[msvc::no_unique_address]], this should be preferred though.
# define _LIBCPP_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
# elif __has_cpp_attribute(no_unique_address)
# define _LIBCPP_NO_UNIQUE_ADDRESS [[no_unique_address]]
# else
# define _LIBCPP_NO_UNIQUE_ADDRESS /* nothing */
// Note that this can be replaced by #error as soon as clang-cl
// implements msvc::no_unique_address, since there should be no C++20
// compiler that doesn't support one of the two attributes at that point.
// We generally don't want to use this macro outside of C++20-only code,
// because using it conditionally in one language version only would make
// the ABI inconsistent.
# endif
# ifdef _LIBCPP_COMPILER_CLANG_BASED
# define _LIBCPP_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push")
# define _LIBCPP_DIAGNOSTIC_POP _Pragma("clang diagnostic pop")
# define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED(str) _Pragma(_LIBCPP_TOSTRING(clang diagnostic ignored str))
# define _LIBCPP_GCC_DIAGNOSTIC_IGNORED(str)
# elif defined(_LIBCPP_COMPILER_GCC)
# define _LIBCPP_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
# define _LIBCPP_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
# define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED(str)
# define _LIBCPP_GCC_DIAGNOSTIC_IGNORED(str) _Pragma(_LIBCPP_TOSTRING(GCC diagnostic ignored str))
# else
# define _LIBCPP_DIAGNOSTIC_PUSH
# define _LIBCPP_DIAGNOSTIC_POP
# define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED(str)
# define _LIBCPP_GCC_DIAGNOSTIC_IGNORED(str)
# endif
# if defined(_AIX) && !defined(_LIBCPP_COMPILER_GCC)
# define _LIBCPP_PACKED_BYTE_FOR_AIX _Pragma("pack(1)")
# define _LIBCPP_PACKED_BYTE_FOR_AIX_END _Pragma("pack(pop)")
# else
# define _LIBCPP_PACKED_BYTE_FOR_AIX /* empty */
# define _LIBCPP_PACKED_BYTE_FOR_AIX_END /* empty */
# endif
# if __has_attribute(__packed__)
# define _LIBCPP_PACKED __attribute__((__packed__))
# else
# define _LIBCPP_PACKED
# endif
#endif // __cplusplus
#endif // _LIBCPP___CONFIG
diff --git a/contrib/llvm-project/libcxx/include/atomic b/contrib/llvm-project/libcxx/include/atomic
index 6cdc839c1715..28c86ce5daa2 100644
--- a/contrib/llvm-project/libcxx/include/atomic
+++ b/contrib/llvm-project/libcxx/include/atomic
@@ -1,2706 +1,2678 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_ATOMIC
#define _LIBCPP_ATOMIC
/*
atomic synopsis
namespace std
{
// feature test macro [version.syn]
#define __cpp_lib_atomic_is_always_lock_free
#define __cpp_lib_atomic_flag_test
#define __cpp_lib_atomic_lock_free_type_aliases
#define __cpp_lib_atomic_wait
// order and consistency
enum memory_order: unspecified // enum class in C++20
{
relaxed,
consume, // load-consume
acquire, // load-acquire
release, // store-release
acq_rel, // store-release load-acquire
seq_cst // store-release load-acquire
};
inline constexpr auto memory_order_relaxed = memory_order::relaxed;
inline constexpr auto memory_order_consume = memory_order::consume;
inline constexpr auto memory_order_acquire = memory_order::acquire;
inline constexpr auto memory_order_release = memory_order::release;
inline constexpr auto memory_order_acq_rel = memory_order::acq_rel;
inline constexpr auto memory_order_seq_cst = memory_order::seq_cst;
template <class T> T kill_dependency(T y) noexcept;
// lock-free property
#define ATOMIC_BOOL_LOCK_FREE unspecified
#define ATOMIC_CHAR_LOCK_FREE unspecified
#define ATOMIC_CHAR8_T_LOCK_FREE unspecified // C++20
#define ATOMIC_CHAR16_T_LOCK_FREE unspecified
#define ATOMIC_CHAR32_T_LOCK_FREE unspecified
#define ATOMIC_WCHAR_T_LOCK_FREE unspecified
#define ATOMIC_SHORT_LOCK_FREE unspecified
#define ATOMIC_INT_LOCK_FREE unspecified
#define ATOMIC_LONG_LOCK_FREE unspecified
#define ATOMIC_LLONG_LOCK_FREE unspecified
#define ATOMIC_POINTER_LOCK_FREE unspecified
template <class T>
struct atomic
{
using value_type = T;
static constexpr bool is_always_lock_free;
bool is_lock_free() const volatile noexcept;
bool is_lock_free() const noexcept;
atomic() noexcept = default; // until C++20
constexpr atomic() noexcept(is_nothrow_default_constructible_v<T>); // since C++20
constexpr atomic(T desr) noexcept;
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
T load(memory_order m = memory_order_seq_cst) const volatile noexcept;
T load(memory_order m = memory_order_seq_cst) const noexcept;
operator T() const volatile noexcept;
operator T() const noexcept;
void store(T desr, memory_order m = memory_order_seq_cst) volatile noexcept;
void store(T desr, memory_order m = memory_order_seq_cst) noexcept;
T operator=(T) volatile noexcept;
T operator=(T) noexcept;
T exchange(T desr, memory_order m = memory_order_seq_cst) volatile noexcept;
T exchange(T desr, memory_order m = memory_order_seq_cst) noexcept;
bool compare_exchange_weak(T& expc, T desr,
memory_order s, memory_order f) volatile noexcept;
bool compare_exchange_weak(T& expc, T desr, memory_order s, memory_order f) noexcept;
bool compare_exchange_strong(T& expc, T desr,
memory_order s, memory_order f) volatile noexcept;
bool compare_exchange_strong(T& expc, T desr,
memory_order s, memory_order f) noexcept;
bool compare_exchange_weak(T& expc, T desr,
memory_order m = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_weak(T& expc, T desr,
memory_order m = memory_order_seq_cst) noexcept;
bool compare_exchange_strong(T& expc, T desr,
memory_order m = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_strong(T& expc, T desr,
memory_order m = memory_order_seq_cst) noexcept;
void wait(T, memory_order = memory_order::seq_cst) const volatile noexcept;
void wait(T, memory_order = memory_order::seq_cst) const noexcept;
void notify_one() volatile noexcept;
void notify_one() noexcept;
void notify_all() volatile noexcept;
void notify_all() noexcept;
};
template <>
struct atomic<integral>
{
using value_type = integral;
using difference_type = value_type;
static constexpr bool is_always_lock_free;
bool is_lock_free() const volatile noexcept;
bool is_lock_free() const noexcept;
atomic() noexcept = default;
constexpr atomic(integral desr) noexcept;
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
integral load(memory_order m = memory_order_seq_cst) const volatile noexcept;
integral load(memory_order m = memory_order_seq_cst) const noexcept;
operator integral() const volatile noexcept;
operator integral() const noexcept;
void store(integral desr, memory_order m = memory_order_seq_cst) volatile noexcept;
void store(integral desr, memory_order m = memory_order_seq_cst) noexcept;
integral operator=(integral desr) volatile noexcept;
integral operator=(integral desr) noexcept;
integral exchange(integral desr,
memory_order m = memory_order_seq_cst) volatile noexcept;
integral exchange(integral desr, memory_order m = memory_order_seq_cst) noexcept;
bool compare_exchange_weak(integral& expc, integral desr,
memory_order s, memory_order f) volatile noexcept;
bool compare_exchange_weak(integral& expc, integral desr,
memory_order s, memory_order f) noexcept;
bool compare_exchange_strong(integral& expc, integral desr,
memory_order s, memory_order f) volatile noexcept;
bool compare_exchange_strong(integral& expc, integral desr,
memory_order s, memory_order f) noexcept;
bool compare_exchange_weak(integral& expc, integral desr,
memory_order m = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_weak(integral& expc, integral desr,
memory_order m = memory_order_seq_cst) noexcept;
bool compare_exchange_strong(integral& expc, integral desr,
memory_order m = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_strong(integral& expc, integral desr,
memory_order m = memory_order_seq_cst) noexcept;
integral fetch_add(integral op, memory_order m = memory_order_seq_cst) volatile noexcept;
integral fetch_add(integral op, memory_order m = memory_order_seq_cst) noexcept;
integral fetch_sub(integral op, memory_order m = memory_order_seq_cst) volatile noexcept;
integral fetch_sub(integral op, memory_order m = memory_order_seq_cst) noexcept;
integral fetch_and(integral op, memory_order m = memory_order_seq_cst) volatile noexcept;
integral fetch_and(integral op, memory_order m = memory_order_seq_cst) noexcept;
integral fetch_or(integral op, memory_order m = memory_order_seq_cst) volatile noexcept;
integral fetch_or(integral op, memory_order m = memory_order_seq_cst) noexcept;
integral fetch_xor(integral op, memory_order m = memory_order_seq_cst) volatile noexcept;
integral fetch_xor(integral op, memory_order m = memory_order_seq_cst) noexcept;
integral operator++(int) volatile noexcept;
integral operator++(int) noexcept;
integral operator--(int) volatile noexcept;
integral operator--(int) noexcept;
integral operator++() volatile noexcept;
integral operator++() noexcept;
integral operator--() volatile noexcept;
integral operator--() noexcept;
integral operator+=(integral op) volatile noexcept;
integral operator+=(integral op) noexcept;
integral operator-=(integral op) volatile noexcept;
integral operator-=(integral op) noexcept;
integral operator&=(integral op) volatile noexcept;
integral operator&=(integral op) noexcept;
integral operator|=(integral op) volatile noexcept;
integral operator|=(integral op) noexcept;
integral operator^=(integral op) volatile noexcept;
integral operator^=(integral op) noexcept;
void wait(integral, memory_order = memory_order::seq_cst) const volatile noexcept;
void wait(integral, memory_order = memory_order::seq_cst) const noexcept;
void notify_one() volatile noexcept;
void notify_one() noexcept;
void notify_all() volatile noexcept;
void notify_all() noexcept;
};
template <class T>
struct atomic<T*>
{
using value_type = T*;
using difference_type = ptrdiff_t;
static constexpr bool is_always_lock_free;
bool is_lock_free() const volatile noexcept;
bool is_lock_free() const noexcept;
atomic() noexcept = default; // until C++20
constexpr atomic() noexcept; // since C++20
constexpr atomic(T* desr) noexcept;
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
T* load(memory_order m = memory_order_seq_cst) const volatile noexcept;
T* load(memory_order m = memory_order_seq_cst) const noexcept;
operator T*() const volatile noexcept;
operator T*() const noexcept;
void store(T* desr, memory_order m = memory_order_seq_cst) volatile noexcept;
void store(T* desr, memory_order m = memory_order_seq_cst) noexcept;
T* operator=(T*) volatile noexcept;
T* operator=(T*) noexcept;
T* exchange(T* desr, memory_order m = memory_order_seq_cst) volatile noexcept;
T* exchange(T* desr, memory_order m = memory_order_seq_cst) noexcept;
bool compare_exchange_weak(T*& expc, T* desr,
memory_order s, memory_order f) volatile noexcept;
bool compare_exchange_weak(T*& expc, T* desr,
memory_order s, memory_order f) noexcept;
bool compare_exchange_strong(T*& expc, T* desr,
memory_order s, memory_order f) volatile noexcept;
bool compare_exchange_strong(T*& expc, T* desr,
memory_order s, memory_order f) noexcept;
bool compare_exchange_weak(T*& expc, T* desr,
memory_order m = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_weak(T*& expc, T* desr,
memory_order m = memory_order_seq_cst) noexcept;
bool compare_exchange_strong(T*& expc, T* desr,
memory_order m = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_strong(T*& expc, T* desr,
memory_order m = memory_order_seq_cst) noexcept;
T* fetch_add(ptrdiff_t op, memory_order m = memory_order_seq_cst) volatile noexcept;
T* fetch_add(ptrdiff_t op, memory_order m = memory_order_seq_cst) noexcept;
T* fetch_sub(ptrdiff_t op, memory_order m = memory_order_seq_cst) volatile noexcept;
T* fetch_sub(ptrdiff_t op, memory_order m = memory_order_seq_cst) noexcept;
T* operator++(int) volatile noexcept;
T* operator++(int) noexcept;
T* operator--(int) volatile noexcept;
T* operator--(int) noexcept;
T* operator++() volatile noexcept;
T* operator++() noexcept;
T* operator--() volatile noexcept;
T* operator--() noexcept;
T* operator+=(ptrdiff_t op) volatile noexcept;
T* operator+=(ptrdiff_t op) noexcept;
T* operator-=(ptrdiff_t op) volatile noexcept;
T* operator-=(ptrdiff_t op) noexcept;
void wait(T*, memory_order = memory_order::seq_cst) const volatile noexcept;
void wait(T*, memory_order = memory_order::seq_cst) const noexcept;
void notify_one() volatile noexcept;
void notify_one() noexcept;
void notify_all() volatile noexcept;
void notify_all() noexcept;
};
// [atomics.nonmembers], non-member functions
template<class T>
bool atomic_is_lock_free(const volatile atomic<T>*) noexcept;
template<class T>
bool atomic_is_lock_free(const atomic<T>*) noexcept;
template<class T>
void atomic_store(volatile atomic<T>*, atomic<T>::value_type) noexcept;
template<class T>
void atomic_store(atomic<T>*, atomic<T>::value_type) noexcept;
template<class T>
void atomic_store_explicit(volatile atomic<T>*, atomic<T>::value_type,
memory_order) noexcept;
template<class T>
void atomic_store_explicit(atomic<T>*, atomic<T>::value_type,
memory_order) noexcept;
template<class T>
T atomic_load(const volatile atomic<T>*) noexcept;
template<class T>
T atomic_load(const atomic<T>*) noexcept;
template<class T>
T atomic_load_explicit(const volatile atomic<T>*, memory_order) noexcept;
template<class T>
T atomic_load_explicit(const atomic<T>*, memory_order) noexcept;
template<class T>
T atomic_exchange(volatile atomic<T>*, atomic<T>::value_type) noexcept;
template<class T>
T atomic_exchange(atomic<T>*, atomic<T>::value_type) noexcept;
template<class T>
T atomic_exchange_explicit(volatile atomic<T>*, atomic<T>::value_type,
memory_order) noexcept;
template<class T>
T atomic_exchange_explicit(atomic<T>*, atomic<T>::value_type,
memory_order) noexcept;
template<class T>
bool atomic_compare_exchange_weak(volatile atomic<T>*, atomic<T>::value_type*,
atomic<T>::value_type) noexcept;
template<class T>
bool atomic_compare_exchange_weak(atomic<T>*, atomic<T>::value_type*,
atomic<T>::value_type) noexcept;
template<class T>
bool atomic_compare_exchange_strong(volatile atomic<T>*, atomic<T>::value_type*,
atomic<T>::value_type) noexcept;
template<class T>
bool atomic_compare_exchange_strong(atomic<T>*, atomic<T>::value_type*,
atomic<T>::value_type) noexcept;
template<class T>
bool atomic_compare_exchange_weak_explicit(volatile atomic<T>*, atomic<T>::value_type*,
atomic<T>::value_type,
memory_order, memory_order) noexcept;
template<class T>
bool atomic_compare_exchange_weak_explicit(atomic<T>*, atomic<T>::value_type*,
atomic<T>::value_type,
memory_order, memory_order) noexcept;
template<class T>
bool atomic_compare_exchange_strong_explicit(volatile atomic<T>*, atomic<T>::value_type*,
atomic<T>::value_type,
memory_order, memory_order) noexcept;
template<class T>
bool atomic_compare_exchange_strong_explicit(atomic<T>*, atomic<T>::value_type*,
atomic<T>::value_type,
memory_order, memory_order) noexcept;
template<class T>
T atomic_fetch_add(volatile atomic<T>*, atomic<T>::difference_type) noexcept;
template<class T>
T atomic_fetch_add(atomic<T>*, atomic<T>::difference_type) noexcept;
template<class T>
T atomic_fetch_add_explicit(volatile atomic<T>*, atomic<T>::difference_type,
memory_order) noexcept;
template<class T>
T atomic_fetch_add_explicit(atomic<T>*, atomic<T>::difference_type,
memory_order) noexcept;
template<class T>
T atomic_fetch_sub(volatile atomic<T>*, atomic<T>::difference_type) noexcept;
template<class T>
T atomic_fetch_sub(atomic<T>*, atomic<T>::difference_type) noexcept;
template<class T>
T atomic_fetch_sub_explicit(volatile atomic<T>*, atomic<T>::difference_type,
memory_order) noexcept;
template<class T>
T atomic_fetch_sub_explicit(atomic<T>*, atomic<T>::difference_type,
memory_order) noexcept;
template<class T>
T atomic_fetch_and(volatile atomic<T>*, atomic<T>::value_type) noexcept;
template<class T>
T atomic_fetch_and(atomic<T>*, atomic<T>::value_type) noexcept;
template<class T>
T atomic_fetch_and_explicit(volatile atomic<T>*, atomic<T>::value_type,
memory_order) noexcept;
template<class T>
T atomic_fetch_and_explicit(atomic<T>*, atomic<T>::value_type,
memory_order) noexcept;
template<class T>
T atomic_fetch_or(volatile atomic<T>*, atomic<T>::value_type) noexcept;
template<class T>
T atomic_fetch_or(atomic<T>*, atomic<T>::value_type) noexcept;
template<class T>
T atomic_fetch_or_explicit(volatile atomic<T>*, atomic<T>::value_type,
memory_order) noexcept;
template<class T>
T atomic_fetch_or_explicit(atomic<T>*, atomic<T>::value_type,
memory_order) noexcept;
template<class T>
T atomic_fetch_xor(volatile atomic<T>*, atomic<T>::value_type) noexcept;
template<class T>
T atomic_fetch_xor(atomic<T>*, atomic<T>::value_type) noexcept;
template<class T>
T atomic_fetch_xor_explicit(volatile atomic<T>*, atomic<T>::value_type,
memory_order) noexcept;
template<class T>
T atomic_fetch_xor_explicit(atomic<T>*, atomic<T>::value_type,
memory_order) noexcept;
template<class T>
void atomic_wait(const volatile atomic<T>*, atomic<T>::value_type);
template<class T>
void atomic_wait(const atomic<T>*, atomic<T>::value_type);
template<class T>
void atomic_wait_explicit(const volatile atomic<T>*, atomic<T>::value_type,
memory_order);
template<class T>
void atomic_wait_explicit(const atomic<T>*, atomic<T>::value_type,
memory_order);
template<class T>
void atomic_notify_one(volatile atomic<T>*);
template<class T>
void atomic_notify_one(atomic<T>*);
template<class T>
void atomic_notify_all(volatile atomic<T>*);
template<class T>
void atomic_notify_all(atomic<T>*);
// Atomics for standard typedef types
typedef atomic<bool> atomic_bool;
typedef atomic<char> atomic_char;
typedef atomic<signed char> atomic_schar;
typedef atomic<unsigned char> atomic_uchar;
typedef atomic<short> atomic_short;
typedef atomic<unsigned short> atomic_ushort;
typedef atomic<int> atomic_int;
typedef atomic<unsigned int> atomic_uint;
typedef atomic<long> atomic_long;
typedef atomic<unsigned long> atomic_ulong;
typedef atomic<long long> atomic_llong;
typedef atomic<unsigned long long> atomic_ullong;
typedef atomic<char8_t> atomic_char8_t; // C++20
typedef atomic<char16_t> atomic_char16_t;
typedef atomic<char32_t> atomic_char32_t;
typedef atomic<wchar_t> atomic_wchar_t;
typedef atomic<int_least8_t> atomic_int_least8_t;
typedef atomic<uint_least8_t> atomic_uint_least8_t;
typedef atomic<int_least16_t> atomic_int_least16_t;
typedef atomic<uint_least16_t> atomic_uint_least16_t;
typedef atomic<int_least32_t> atomic_int_least32_t;
typedef atomic<uint_least32_t> atomic_uint_least32_t;
typedef atomic<int_least64_t> atomic_int_least64_t;
typedef atomic<uint_least64_t> atomic_uint_least64_t;
typedef atomic<int_fast8_t> atomic_int_fast8_t;
typedef atomic<uint_fast8_t> atomic_uint_fast8_t;
typedef atomic<int_fast16_t> atomic_int_fast16_t;
typedef atomic<uint_fast16_t> atomic_uint_fast16_t;
typedef atomic<int_fast32_t> atomic_int_fast32_t;
typedef atomic<uint_fast32_t> atomic_uint_fast32_t;
typedef atomic<int_fast64_t> atomic_int_fast64_t;
typedef atomic<uint_fast64_t> atomic_uint_fast64_t;
typedef atomic<int8_t> atomic_int8_t;
typedef atomic<uint8_t> atomic_uint8_t;
typedef atomic<int16_t> atomic_int16_t;
typedef atomic<uint16_t> atomic_uint16_t;
typedef atomic<int32_t> atomic_int32_t;
typedef atomic<uint32_t> atomic_uint32_t;
typedef atomic<int64_t> atomic_int64_t;
typedef atomic<uint64_t> atomic_uint64_t;
typedef atomic<intptr_t> atomic_intptr_t;
typedef atomic<uintptr_t> atomic_uintptr_t;
typedef atomic<size_t> atomic_size_t;
typedef atomic<ptrdiff_t> atomic_ptrdiff_t;
typedef atomic<intmax_t> atomic_intmax_t;
typedef atomic<uintmax_t> atomic_uintmax_t;
// flag type and operations
typedef struct atomic_flag
{
atomic_flag() noexcept = default; // until C++20
constexpr atomic_flag() noexcept; // since C++20
atomic_flag(const atomic_flag&) = delete;
atomic_flag& operator=(const atomic_flag&) = delete;
atomic_flag& operator=(const atomic_flag&) volatile = delete;
bool test(memory_order m = memory_order_seq_cst) volatile noexcept;
bool test(memory_order m = memory_order_seq_cst) noexcept;
bool test_and_set(memory_order m = memory_order_seq_cst) volatile noexcept;
bool test_and_set(memory_order m = memory_order_seq_cst) noexcept;
void clear(memory_order m = memory_order_seq_cst) volatile noexcept;
void clear(memory_order m = memory_order_seq_cst) noexcept;
void wait(bool, memory_order = memory_order::seq_cst) const volatile noexcept;
void wait(bool, memory_order = memory_order::seq_cst) const noexcept;
void notify_one() volatile noexcept;
void notify_one() noexcept;
void notify_all() volatile noexcept;
void notify_all() noexcept;
} atomic_flag;
bool atomic_flag_test(volatile atomic_flag* obj) noexcept;
bool atomic_flag_test(atomic_flag* obj) noexcept;
bool atomic_flag_test_explicit(volatile atomic_flag* obj,
memory_order m) noexcept;
bool atomic_flag_test_explicit(atomic_flag* obj, memory_order m) noexcept;
bool atomic_flag_test_and_set(volatile atomic_flag* obj) noexcept;
bool atomic_flag_test_and_set(atomic_flag* obj) noexcept;
bool atomic_flag_test_and_set_explicit(volatile atomic_flag* obj,
memory_order m) noexcept;
bool atomic_flag_test_and_set_explicit(atomic_flag* obj, memory_order m) noexcept;
void atomic_flag_clear(volatile atomic_flag* obj) noexcept;
void atomic_flag_clear(atomic_flag* obj) noexcept;
void atomic_flag_clear_explicit(volatile atomic_flag* obj, memory_order m) noexcept;
void atomic_flag_clear_explicit(atomic_flag* obj, memory_order m) noexcept;
void atomic_wait(const volatile atomic_flag* obj, T old) noexcept;
void atomic_wait(const atomic_flag* obj, T old) noexcept;
void atomic_wait_explicit(const volatile atomic_flag* obj, T old, memory_order m) noexcept;
void atomic_wait_explicit(const atomic_flag* obj, T old, memory_order m) noexcept;
void atomic_one(volatile atomic_flag* obj) noexcept;
void atomic_one(atomic_flag* obj) noexcept;
void atomic_all(volatile atomic_flag* obj) noexcept;
void atomic_all(atomic_flag* obj) noexcept;
// fences
void atomic_thread_fence(memory_order m) noexcept;
void atomic_signal_fence(memory_order m) noexcept;
// deprecated
template <class T>
void atomic_init(volatile atomic<T>* obj, atomic<T>::value_type desr) noexcept;
template <class T>
void atomic_init(atomic<T>* obj, atomic<T>::value_type desr) noexcept;
#define ATOMIC_VAR_INIT(value) see below
#define ATOMIC_FLAG_INIT see below
} // std
*/
#include <__assert> // all public C++ headers provide the assertion handler
#include <__availability>
#include <__chrono/duration.h>
#include <__config>
#include <__thread/poll_with_backoff.h>
#include <__thread/timed_backoff_policy.h>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <type_traits>
#include <version>
#ifndef _LIBCPP_HAS_NO_THREADS
# include <__threading_support>
#endif
#ifndef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES
# include <chrono>
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
#ifdef _LIBCPP_HAS_NO_ATOMIC_HEADER
# error <atomic> is not implemented
#endif
#ifdef kill_dependency
# error <atomic> is incompatible with <stdatomic.h> before C++23. Please compile with -std=c++23.
#endif
#define _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) \
_LIBCPP_DIAGNOSE_WARNING(__m == memory_order_consume || \
__m == memory_order_acquire || \
__m == memory_order_acq_rel, \
"memory order argument to atomic operation is invalid")
#define _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) \
_LIBCPP_DIAGNOSE_WARNING(__m == memory_order_release || \
__m == memory_order_acq_rel, \
"memory order argument to atomic operation is invalid")
#define _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__m, __f) \
_LIBCPP_DIAGNOSE_WARNING(__f == memory_order_release || \
__f == memory_order_acq_rel, \
"memory order argument to atomic operation is invalid")
_LIBCPP_BEGIN_NAMESPACE_STD
// Figure out what the underlying type for `memory_order` would be if it were
// declared as an unscoped enum (accounting for -fshort-enums). Use this result
// to pin the underlying type in C++20.
enum __legacy_memory_order {
__mo_relaxed,
__mo_consume,
__mo_acquire,
__mo_release,
__mo_acq_rel,
__mo_seq_cst
};
typedef underlying_type<__legacy_memory_order>::type __memory_order_underlying_t;
#if _LIBCPP_STD_VER > 17
enum class memory_order : __memory_order_underlying_t {
relaxed = __mo_relaxed,
consume = __mo_consume,
acquire = __mo_acquire,
release = __mo_release,
acq_rel = __mo_acq_rel,
seq_cst = __mo_seq_cst
};
inline constexpr auto memory_order_relaxed = memory_order::relaxed;
inline constexpr auto memory_order_consume = memory_order::consume;
inline constexpr auto memory_order_acquire = memory_order::acquire;
inline constexpr auto memory_order_release = memory_order::release;
inline constexpr auto memory_order_acq_rel = memory_order::acq_rel;
inline constexpr auto memory_order_seq_cst = memory_order::seq_cst;
#else
typedef enum memory_order {
memory_order_relaxed = __mo_relaxed,
memory_order_consume = __mo_consume,
memory_order_acquire = __mo_acquire,
memory_order_release = __mo_release,
memory_order_acq_rel = __mo_acq_rel,
memory_order_seq_cst = __mo_seq_cst,
} memory_order;
#endif // _LIBCPP_STD_VER > 17
template <typename _Tp> _LIBCPP_INLINE_VISIBILITY
bool __cxx_nonatomic_compare_equal(_Tp const& __lhs, _Tp const& __rhs) {
return _VSTD::memcmp(&__lhs, &__rhs, sizeof(_Tp)) == 0;
}
static_assert((is_same<underlying_type<memory_order>::type, __memory_order_underlying_t>::value),
"unexpected underlying type for std::memory_order");
#if defined(_LIBCPP_HAS_GCC_ATOMIC_IMP) || \
defined(_LIBCPP_ATOMIC_ONLY_USE_BUILTINS)
// [atomics.types.generic]p1 guarantees _Tp is trivially copyable. Because
// the default operator= in an object is not volatile, a byte-by-byte copy
// is required.
template <typename _Tp, typename _Tv> _LIBCPP_INLINE_VISIBILITY
typename enable_if<is_assignable<_Tp&, _Tv>::value>::type
__cxx_atomic_assign_volatile(_Tp& __a_value, _Tv const& __val) {
__a_value = __val;
}
template <typename _Tp, typename _Tv> _LIBCPP_INLINE_VISIBILITY
typename enable_if<is_assignable<_Tp&, _Tv>::value>::type
__cxx_atomic_assign_volatile(_Tp volatile& __a_value, _Tv volatile const& __val) {
volatile char* __to = reinterpret_cast<volatile char*>(&__a_value);
volatile char* __end = __to + sizeof(_Tp);
volatile const char* __from = reinterpret_cast<volatile const char*>(&__val);
while (__to != __end)
*__to++ = *__from++;
}
#endif
#if defined(_LIBCPP_HAS_GCC_ATOMIC_IMP)
template <typename _Tp>
struct __cxx_atomic_base_impl {
_LIBCPP_INLINE_VISIBILITY
#ifndef _LIBCPP_CXX03_LANG
__cxx_atomic_base_impl() _NOEXCEPT = default;
#else
__cxx_atomic_base_impl() _NOEXCEPT : __a_value() {}
#endif // _LIBCPP_CXX03_LANG
_LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp value) _NOEXCEPT
: __a_value(value) {}
_Tp __a_value;
};
_LIBCPP_INLINE_VISIBILITY inline _LIBCPP_CONSTEXPR int __to_gcc_order(memory_order __order) {
// Avoid switch statement to make this a constexpr.
return __order == memory_order_relaxed ? __ATOMIC_RELAXED:
(__order == memory_order_acquire ? __ATOMIC_ACQUIRE:
(__order == memory_order_release ? __ATOMIC_RELEASE:
(__order == memory_order_seq_cst ? __ATOMIC_SEQ_CST:
(__order == memory_order_acq_rel ? __ATOMIC_ACQ_REL:
__ATOMIC_CONSUME))));
}
_LIBCPP_INLINE_VISIBILITY inline _LIBCPP_CONSTEXPR int __to_gcc_failure_order(memory_order __order) {
// Avoid switch statement to make this a constexpr.
return __order == memory_order_relaxed ? __ATOMIC_RELAXED:
(__order == memory_order_acquire ? __ATOMIC_ACQUIRE:
(__order == memory_order_release ? __ATOMIC_RELAXED:
(__order == memory_order_seq_cst ? __ATOMIC_SEQ_CST:
(__order == memory_order_acq_rel ? __ATOMIC_ACQUIRE:
__ATOMIC_CONSUME))));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
void __cxx_atomic_init(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val) {
__cxx_atomic_assign_volatile(__a->__a_value, __val);
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val) {
__a->__a_value = __val;
}
_LIBCPP_INLINE_VISIBILITY inline
void __cxx_atomic_thread_fence(memory_order __order) {
__atomic_thread_fence(__to_gcc_order(__order));
}
_LIBCPP_INLINE_VISIBILITY inline
void __cxx_atomic_signal_fence(memory_order __order) {
__atomic_signal_fence(__to_gcc_order(__order));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
void __cxx_atomic_store(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val,
memory_order __order) {
__atomic_store(&__a->__a_value, &__val,
__to_gcc_order(__order));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
void __cxx_atomic_store(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val,
memory_order __order) {
__atomic_store(&__a->__a_value, &__val,
__to_gcc_order(__order));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_load(const volatile __cxx_atomic_base_impl<_Tp>* __a,
memory_order __order) {
_Tp __ret;
__atomic_load(&__a->__a_value, &__ret,
__to_gcc_order(__order));
return __ret;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_load(const __cxx_atomic_base_impl<_Tp>* __a, memory_order __order) {
_Tp __ret;
__atomic_load(&__a->__a_value, &__ret,
__to_gcc_order(__order));
return __ret;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_exchange(volatile __cxx_atomic_base_impl<_Tp>* __a,
_Tp __value, memory_order __order) {
_Tp __ret;
__atomic_exchange(&__a->__a_value, &__value, &__ret,
__to_gcc_order(__order));
return __ret;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a, _Tp __value,
memory_order __order) {
_Tp __ret;
__atomic_exchange(&__a->__a_value, &__value, &__ret,
__to_gcc_order(__order));
return __ret;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_strong(
volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value,
memory_order __success, memory_order __failure) {
return __atomic_compare_exchange(&__a->__a_value, __expected, &__value,
false,
__to_gcc_order(__success),
__to_gcc_failure_order(__failure));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_strong(
__cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success,
memory_order __failure) {
return __atomic_compare_exchange(&__a->__a_value, __expected, &__value,
false,
__to_gcc_order(__success),
__to_gcc_failure_order(__failure));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_weak(
volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value,
memory_order __success, memory_order __failure) {
return __atomic_compare_exchange(&__a->__a_value, __expected, &__value,
true,
__to_gcc_order(__success),
__to_gcc_failure_order(__failure));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_weak(
__cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success,
memory_order __failure) {
return __atomic_compare_exchange(&__a->__a_value, __expected, &__value,
true,
__to_gcc_order(__success),
__to_gcc_failure_order(__failure));
}
template <typename _Tp>
struct __skip_amt { enum {value = 1}; };
template <typename _Tp>
struct __skip_amt<_Tp*> { enum {value = sizeof(_Tp)}; };
// FIXME: Haven't figured out what the spec says about using arrays with
// atomic_fetch_add. Force a failure rather than creating bad behavior.
template <typename _Tp>
struct __skip_amt<_Tp[]> { };
template <typename _Tp, int n>
struct __skip_amt<_Tp[n]> { };
template <typename _Tp, typename _Td>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_add(volatile __cxx_atomic_base_impl<_Tp>* __a,
_Td __delta, memory_order __order) {
return __atomic_fetch_add(&__a->__a_value, __delta * __skip_amt<_Tp>::value,
__to_gcc_order(__order));
}
template <typename _Tp, typename _Td>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp>* __a, _Td __delta,
memory_order __order) {
return __atomic_fetch_add(&__a->__a_value, __delta * __skip_amt<_Tp>::value,
__to_gcc_order(__order));
}
template <typename _Tp, typename _Td>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_sub(volatile __cxx_atomic_base_impl<_Tp>* __a,
_Td __delta, memory_order __order) {
return __atomic_fetch_sub(&__a->__a_value, __delta * __skip_amt<_Tp>::value,
__to_gcc_order(__order));
}
template <typename _Tp, typename _Td>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp>* __a, _Td __delta,
memory_order __order) {
return __atomic_fetch_sub(&__a->__a_value, __delta * __skip_amt<_Tp>::value,
__to_gcc_order(__order));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_and(volatile __cxx_atomic_base_impl<_Tp>* __a,
_Tp __pattern, memory_order __order) {
return __atomic_fetch_and(&__a->__a_value, __pattern,
__to_gcc_order(__order));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp>* __a,
_Tp __pattern, memory_order __order) {
return __atomic_fetch_and(&__a->__a_value, __pattern,
__to_gcc_order(__order));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_or(volatile __cxx_atomic_base_impl<_Tp>* __a,
_Tp __pattern, memory_order __order) {
return __atomic_fetch_or(&__a->__a_value, __pattern,
__to_gcc_order(__order));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern,
memory_order __order) {
return __atomic_fetch_or(&__a->__a_value, __pattern,
__to_gcc_order(__order));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_xor(volatile __cxx_atomic_base_impl<_Tp>* __a,
_Tp __pattern, memory_order __order) {
return __atomic_fetch_xor(&__a->__a_value, __pattern,
__to_gcc_order(__order));
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern,
memory_order __order) {
return __atomic_fetch_xor(&__a->__a_value, __pattern,
__to_gcc_order(__order));
}
#define __cxx_atomic_is_lock_free(__s) __atomic_is_lock_free(__s, 0)
#elif defined(_LIBCPP_HAS_C_ATOMIC_IMP)
template <typename _Tp>
struct __cxx_atomic_base_impl {
_LIBCPP_INLINE_VISIBILITY
#ifndef _LIBCPP_CXX03_LANG
__cxx_atomic_base_impl() _NOEXCEPT = default;
#else
__cxx_atomic_base_impl() _NOEXCEPT : __a_value() {}
#endif // _LIBCPP_CXX03_LANG
_LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT
: __a_value(__value) {}
_LIBCPP_DISABLE_EXTENSION_WARNING _Atomic(_Tp) __a_value;
};
#define __cxx_atomic_is_lock_free(__s) __c11_atomic_is_lock_free(__s)
_LIBCPP_INLINE_VISIBILITY inline
void __cxx_atomic_thread_fence(memory_order __order) _NOEXCEPT {
__c11_atomic_thread_fence(static_cast<__memory_order_underlying_t>(__order));
}
_LIBCPP_INLINE_VISIBILITY inline
void __cxx_atomic_signal_fence(memory_order __order) _NOEXCEPT {
__c11_atomic_signal_fence(static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __val) _NOEXCEPT {
__c11_atomic_init(&__a->__a_value, __val);
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp> * __a, _Tp __val) _NOEXCEPT {
__c11_atomic_init(&__a->__a_value, __val);
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
void __cxx_atomic_store(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __val, memory_order __order) _NOEXCEPT {
__c11_atomic_store(&__a->__a_value, __val, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
void __cxx_atomic_store(__cxx_atomic_base_impl<_Tp> * __a, _Tp __val, memory_order __order) _NOEXCEPT {
__c11_atomic_store(&__a->__a_value, __val, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_load(__cxx_atomic_base_impl<_Tp> const volatile* __a, memory_order __order) _NOEXCEPT {
using __ptr_type = typename remove_const<decltype(__a->__a_value)>::type*;
return __c11_atomic_load(const_cast<__ptr_type>(&__a->__a_value), static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_load(__cxx_atomic_base_impl<_Tp> const* __a, memory_order __order) _NOEXCEPT {
using __ptr_type = typename remove_const<decltype(__a->__a_value)>::type*;
return __c11_atomic_load(const_cast<__ptr_type>(&__a->__a_value), static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __value, memory_order __order) _NOEXCEPT {
return __c11_atomic_exchange(&__a->__a_value, __value, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp> * __a, _Tp __value, memory_order __order) _NOEXCEPT {
return __c11_atomic_exchange(&__a->__a_value, __value, static_cast<__memory_order_underlying_t>(__order));
}
_LIBCPP_INLINE_VISIBILITY inline _LIBCPP_CONSTEXPR memory_order __to_failure_order(memory_order __order) {
// Avoid switch statement to make this a constexpr.
return __order == memory_order_release ? memory_order_relaxed:
(__order == memory_order_acq_rel ? memory_order_acquire:
__order);
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_strong(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) _NOEXCEPT {
return __c11_atomic_compare_exchange_strong(&__a->__a_value, __expected, __value, static_cast<__memory_order_underlying_t>(__success), static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_strong(__cxx_atomic_base_impl<_Tp> * __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) _NOEXCEPT {
return __c11_atomic_compare_exchange_strong(&__a->__a_value, __expected, __value, static_cast<__memory_order_underlying_t>(__success), static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_weak(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) _NOEXCEPT {
return __c11_atomic_compare_exchange_weak(&__a->__a_value, __expected, __value, static_cast<__memory_order_underlying_t>(__success), static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_weak(__cxx_atomic_base_impl<_Tp> * __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) _NOEXCEPT {
return __c11_atomic_compare_exchange_weak(&__a->__a_value, __expected, __value, static_cast<__memory_order_underlying_t>(__success), static_cast<__memory_order_underlying_t>(__to_failure_order(__failure)));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __delta, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_add(&__a->__a_value, __delta, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp> * __a, _Tp __delta, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_add(&__a->__a_value, __delta, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp* __cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp*> volatile* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_add(&__a->__a_value, __delta, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp* __cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp*> * __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_add(&__a->__a_value, __delta, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __delta, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_sub(&__a->__a_value, __delta, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp> * __a, _Tp __delta, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_sub(&__a->__a_value, __delta, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp* __cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp*> volatile* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_sub(&__a->__a_value, __delta, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp* __cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp*> * __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_sub(&__a->__a_value, __delta, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __pattern, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_and(&__a->__a_value, __pattern, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp> * __a, _Tp __pattern, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_and(&__a->__a_value, __pattern, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __pattern, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_or(&__a->__a_value, __pattern, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp> * __a, _Tp __pattern, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_or(&__a->__a_value, __pattern, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __pattern, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_xor(&__a->__a_value, __pattern, static_cast<__memory_order_underlying_t>(__order));
}
template<class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp> * __a, _Tp __pattern, memory_order __order) _NOEXCEPT {
return __c11_atomic_fetch_xor(&__a->__a_value, __pattern, static_cast<__memory_order_underlying_t>(__order));
}
#endif // _LIBCPP_HAS_GCC_ATOMIC_IMP, _LIBCPP_HAS_C_ATOMIC_IMP
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp kill_dependency(_Tp __y) _NOEXCEPT
{
return __y;
}
#if defined(__CLANG_ATOMIC_BOOL_LOCK_FREE)
# define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE
# define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE
#ifndef _LIBCPP_HAS_NO_CHAR8_T
# define ATOMIC_CHAR8_T_LOCK_FREE __CLANG_ATOMIC_CHAR8_T_LOCK_FREE
#endif
# define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE
# define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE
# define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE
# define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE
# define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE
# define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE
# define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE
# define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE
#elif defined(__GCC_ATOMIC_BOOL_LOCK_FREE)
# define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
# define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
#ifndef _LIBCPP_HAS_NO_CHAR8_T
# define ATOMIC_CHAR8_T_LOCK_FREE __GCC_ATOMIC_CHAR8_T_LOCK_FREE
#endif
# define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
# define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
# define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
# define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
# define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
# define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
# define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
# define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
#endif
+template <class _Tp>
+struct __libcpp_is_always_lock_free {
+ // __atomic_always_lock_free is available in all Standard modes
+ static const bool __value = __atomic_always_lock_free(sizeof(_Tp), 0);
+};
+
#ifdef _LIBCPP_ATOMIC_ONLY_USE_BUILTINS
template<typename _Tp>
struct __cxx_atomic_lock_impl {
_LIBCPP_INLINE_VISIBILITY
__cxx_atomic_lock_impl() _NOEXCEPT
: __a_value(), __a_lock(0) {}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR explicit
__cxx_atomic_lock_impl(_Tp value) _NOEXCEPT
: __a_value(value), __a_lock(0) {}
_Tp __a_value;
mutable __cxx_atomic_base_impl<_LIBCPP_ATOMIC_FLAG_TYPE> __a_lock;
_LIBCPP_INLINE_VISIBILITY void __lock() const volatile {
while(1 == __cxx_atomic_exchange(&__a_lock, _LIBCPP_ATOMIC_FLAG_TYPE(true), memory_order_acquire))
/*spin*/;
}
_LIBCPP_INLINE_VISIBILITY void __lock() const {
while(1 == __cxx_atomic_exchange(&__a_lock, _LIBCPP_ATOMIC_FLAG_TYPE(true), memory_order_acquire))
/*spin*/;
}
_LIBCPP_INLINE_VISIBILITY void __unlock() const volatile {
__cxx_atomic_store(&__a_lock, _LIBCPP_ATOMIC_FLAG_TYPE(false), memory_order_release);
}
_LIBCPP_INLINE_VISIBILITY void __unlock() const {
__cxx_atomic_store(&__a_lock, _LIBCPP_ATOMIC_FLAG_TYPE(false), memory_order_release);
}
_LIBCPP_INLINE_VISIBILITY _Tp __read() const volatile {
__lock();
_Tp __old;
__cxx_atomic_assign_volatile(__old, __a_value);
__unlock();
return __old;
}
_LIBCPP_INLINE_VISIBILITY _Tp __read() const {
__lock();
_Tp __old = __a_value;
__unlock();
return __old;
}
};
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
void __cxx_atomic_init(volatile __cxx_atomic_lock_impl<_Tp>* __a, _Tp __val) {
__cxx_atomic_assign_volatile(__a->__a_value, __val);
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
void __cxx_atomic_init(__cxx_atomic_lock_impl<_Tp>* __a, _Tp __val) {
__a->__a_value = __val;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
void __cxx_atomic_store(volatile __cxx_atomic_lock_impl<_Tp>* __a, _Tp __val, memory_order) {
__a->__lock();
__cxx_atomic_assign_volatile(__a->__a_value, __val);
__a->__unlock();
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
void __cxx_atomic_store(__cxx_atomic_lock_impl<_Tp>* __a, _Tp __val, memory_order) {
__a->__lock();
__a->__a_value = __val;
__a->__unlock();
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_load(const volatile __cxx_atomic_lock_impl<_Tp>* __a, memory_order) {
return __a->__read();
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_load(const __cxx_atomic_lock_impl<_Tp>* __a, memory_order) {
return __a->__read();
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_exchange(volatile __cxx_atomic_lock_impl<_Tp>* __a, _Tp __value, memory_order) {
__a->__lock();
_Tp __old;
__cxx_atomic_assign_volatile(__old, __a->__a_value);
__cxx_atomic_assign_volatile(__a->__a_value, __value);
__a->__unlock();
return __old;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_exchange(__cxx_atomic_lock_impl<_Tp>* __a, _Tp __value, memory_order) {
__a->__lock();
_Tp __old = __a->__a_value;
__a->__a_value = __value;
__a->__unlock();
return __old;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_strong(volatile __cxx_atomic_lock_impl<_Tp>* __a,
_Tp* __expected, _Tp __value, memory_order, memory_order) {
_Tp __temp;
__a->__lock();
__cxx_atomic_assign_volatile(__temp, __a->__a_value);
bool __ret = (_VSTD::memcmp(&__temp, __expected, sizeof(_Tp)) == 0);
if(__ret)
__cxx_atomic_assign_volatile(__a->__a_value, __value);
else
__cxx_atomic_assign_volatile(*__expected, __a->__a_value);
__a->__unlock();
return __ret;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_strong(__cxx_atomic_lock_impl<_Tp>* __a,
_Tp* __expected, _Tp __value, memory_order, memory_order) {
__a->__lock();
bool __ret = (_VSTD::memcmp(&__a->__a_value, __expected, sizeof(_Tp)) == 0);
if(__ret)
_VSTD::memcpy(&__a->__a_value, &__value, sizeof(_Tp));
else
_VSTD::memcpy(__expected, &__a->__a_value, sizeof(_Tp));
__a->__unlock();
return __ret;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_weak(volatile __cxx_atomic_lock_impl<_Tp>* __a,
_Tp* __expected, _Tp __value, memory_order, memory_order) {
_Tp __temp;
__a->__lock();
__cxx_atomic_assign_volatile(__temp, __a->__a_value);
bool __ret = (_VSTD::memcmp(&__temp, __expected, sizeof(_Tp)) == 0);
if(__ret)
__cxx_atomic_assign_volatile(__a->__a_value, __value);
else
__cxx_atomic_assign_volatile(*__expected, __a->__a_value);
__a->__unlock();
return __ret;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
bool __cxx_atomic_compare_exchange_weak(__cxx_atomic_lock_impl<_Tp>* __a,
_Tp* __expected, _Tp __value, memory_order, memory_order) {
__a->__lock();
bool __ret = (_VSTD::memcmp(&__a->__a_value, __expected, sizeof(_Tp)) == 0);
if(__ret)
_VSTD::memcpy(&__a->__a_value, &__value, sizeof(_Tp));
else
_VSTD::memcpy(__expected, &__a->__a_value, sizeof(_Tp));
__a->__unlock();
return __ret;
}
template <typename _Tp, typename _Td>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_add(volatile __cxx_atomic_lock_impl<_Tp>* __a,
_Td __delta, memory_order) {
__a->__lock();
_Tp __old;
__cxx_atomic_assign_volatile(__old, __a->__a_value);
__cxx_atomic_assign_volatile(__a->__a_value, _Tp(__old + __delta));
__a->__unlock();
return __old;
}
template <typename _Tp, typename _Td>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_add(__cxx_atomic_lock_impl<_Tp>* __a,
_Td __delta, memory_order) {
__a->__lock();
_Tp __old = __a->__a_value;
__a->__a_value += __delta;
__a->__unlock();
return __old;
}
template <typename _Tp, typename _Td>
_LIBCPP_INLINE_VISIBILITY
_Tp* __cxx_atomic_fetch_add(volatile __cxx_atomic_lock_impl<_Tp*>* __a,
ptrdiff_t __delta, memory_order) {
__a->__lock();
_Tp* __old;
__cxx_atomic_assign_volatile(__old, __a->__a_value);
__cxx_atomic_assign_volatile(__a->__a_value, __old + __delta);
__a->__unlock();
return __old;
}
template <typename _Tp, typename _Td>
_LIBCPP_INLINE_VISIBILITY
_Tp* __cxx_atomic_fetch_add(__cxx_atomic_lock_impl<_Tp*>* __a,
ptrdiff_t __delta, memory_order) {
__a->__lock();
_Tp* __old = __a->__a_value;
__a->__a_value += __delta;
__a->__unlock();
return __old;
}
template <typename _Tp, typename _Td>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_sub(volatile __cxx_atomic_lock_impl<_Tp>* __a,
_Td __delta, memory_order) {
__a->__lock();
_Tp __old;
__cxx_atomic_assign_volatile(__old, __a->__a_value);
__cxx_atomic_assign_volatile(__a->__a_value, _Tp(__old - __delta));
__a->__unlock();
return __old;
}
template <typename _Tp, typename _Td>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_sub(__cxx_atomic_lock_impl<_Tp>* __a,
_Td __delta, memory_order) {
__a->__lock();
_Tp __old = __a->__a_value;
__a->__a_value -= __delta;
__a->__unlock();
return __old;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_and(volatile __cxx_atomic_lock_impl<_Tp>* __a,
_Tp __pattern, memory_order) {
__a->__lock();
_Tp __old;
__cxx_atomic_assign_volatile(__old, __a->__a_value);
__cxx_atomic_assign_volatile(__a->__a_value, _Tp(__old & __pattern));
__a->__unlock();
return __old;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_and(__cxx_atomic_lock_impl<_Tp>* __a,
_Tp __pattern, memory_order) {
__a->__lock();
_Tp __old = __a->__a_value;
__a->__a_value &= __pattern;
__a->__unlock();
return __old;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_or(volatile __cxx_atomic_lock_impl<_Tp>* __a,
_Tp __pattern, memory_order) {
__a->__lock();
_Tp __old;
__cxx_atomic_assign_volatile(__old, __a->__a_value);
__cxx_atomic_assign_volatile(__a->__a_value, _Tp(__old | __pattern));
__a->__unlock();
return __old;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_or(__cxx_atomic_lock_impl<_Tp>* __a,
_Tp __pattern, memory_order) {
__a->__lock();
_Tp __old = __a->__a_value;
__a->__a_value |= __pattern;
__a->__unlock();
return __old;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_xor(volatile __cxx_atomic_lock_impl<_Tp>* __a,
_Tp __pattern, memory_order) {
__a->__lock();
_Tp __old;
__cxx_atomic_assign_volatile(__old, __a->__a_value);
__cxx_atomic_assign_volatile(__a->__a_value, _Tp(__old ^ __pattern));
__a->__unlock();
return __old;
}
template <typename _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp __cxx_atomic_fetch_xor(__cxx_atomic_lock_impl<_Tp>* __a,
_Tp __pattern, memory_order) {
__a->__lock();
_Tp __old = __a->__a_value;
__a->__a_value ^= __pattern;
__a->__unlock();
return __old;
}
-#ifdef __cpp_lib_atomic_is_always_lock_free
-
-template<typename _Tp> struct __cxx_is_always_lock_free {
- enum { __value = __atomic_always_lock_free(sizeof(_Tp), 0) }; };
-
-#else
-
-template<typename _Tp> struct __cxx_is_always_lock_free { enum { __value = false }; };
-// Implementations must match the C ATOMIC_*_LOCK_FREE macro values.
-template<> struct __cxx_is_always_lock_free<bool> { enum { __value = 2 == ATOMIC_BOOL_LOCK_FREE }; };
-template<> struct __cxx_is_always_lock_free<char> { enum { __value = 2 == ATOMIC_CHAR_LOCK_FREE }; };
-template<> struct __cxx_is_always_lock_free<signed char> { enum { __value = 2 == ATOMIC_CHAR_LOCK_FREE }; };
-template<> struct __cxx_is_always_lock_free<unsigned char> { enum { __value = 2 == ATOMIC_CHAR_LOCK_FREE }; };
-#ifndef _LIBCPP_HAS_NO_CHAR8_T
-template<> struct __cxx_is_always_lock_free<char8_t> { enum { __value = 2 == ATOMIC_CHAR8_T_LOCK_FREE }; };
-#endif
-template<> struct __cxx_is_always_lock_free<char16_t> { enum { __value = 2 == ATOMIC_CHAR16_T_LOCK_FREE }; };
-template<> struct __cxx_is_always_lock_free<char32_t> { enum { __value = 2 == ATOMIC_CHAR32_T_LOCK_FREE }; };
-#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
-template<> struct __cxx_is_always_lock_free<wchar_t> { enum { __value = 2 == ATOMIC_WCHAR_T_LOCK_FREE }; };
-#endif
-template<> struct __cxx_is_always_lock_free<short> { enum { __value = 2 == ATOMIC_SHORT_LOCK_FREE }; };
-template<> struct __cxx_is_always_lock_free<unsigned short> { enum { __value = 2 == ATOMIC_SHORT_LOCK_FREE }; };
-template<> struct __cxx_is_always_lock_free<int> { enum { __value = 2 == ATOMIC_INT_LOCK_FREE }; };
-template<> struct __cxx_is_always_lock_free<unsigned int> { enum { __value = 2 == ATOMIC_INT_LOCK_FREE }; };
-template<> struct __cxx_is_always_lock_free<long> { enum { __value = 2 == ATOMIC_LONG_LOCK_FREE }; };
-template<> struct __cxx_is_always_lock_free<unsigned long> { enum { __value = 2 == ATOMIC_LONG_LOCK_FREE }; };
-template<> struct __cxx_is_always_lock_free<long long> { enum { __value = 2 == ATOMIC_LLONG_LOCK_FREE }; };
-template<> struct __cxx_is_always_lock_free<unsigned long long> { enum { __value = 2 == ATOMIC_LLONG_LOCK_FREE }; };
-template<typename _Tp> struct __cxx_is_always_lock_free<_Tp*> { enum { __value = 2 == ATOMIC_POINTER_LOCK_FREE }; };
-template<> struct __cxx_is_always_lock_free<std::nullptr_t> { enum { __value = 2 == ATOMIC_POINTER_LOCK_FREE }; };
-
-#endif //__cpp_lib_atomic_is_always_lock_free
-
template <typename _Tp,
- typename _Base = typename conditional<__cxx_is_always_lock_free<_Tp>::__value,
+ typename _Base = typename conditional<__libcpp_is_always_lock_free<_Tp>::__value,
__cxx_atomic_base_impl<_Tp>,
__cxx_atomic_lock_impl<_Tp> >::type>
#else
template <typename _Tp,
typename _Base = __cxx_atomic_base_impl<_Tp> >
#endif //_LIBCPP_ATOMIC_ONLY_USE_BUILTINS
struct __cxx_atomic_impl : public _Base {
static_assert(is_trivially_copyable<_Tp>::value,
"std::atomic<T> requires that 'T' be a trivially copyable type");
_LIBCPP_INLINE_VISIBILITY __cxx_atomic_impl() _NOEXCEPT = default;
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR explicit __cxx_atomic_impl(_Tp __value) _NOEXCEPT
: _Base(__value) {}
};
#if defined(__linux__) || (defined(_AIX) && !defined(__64BIT__)) || \
(defined(__FreeBSD__) && defined(__mips__))
using __cxx_contention_t = int32_t;
#else
using __cxx_contention_t = int64_t;
#endif // __linux__ || (_AIX && !__64BIT__) || (__FreeBSD__ && __mips__)
using __cxx_atomic_contention_t = __cxx_atomic_impl<__cxx_contention_t>;
#if defined(_LIBCPP_HAS_NO_THREADS)
# define _LIBCPP_HAS_NO_PLATFORM_WAIT
#endif
// TODO:
// _LIBCPP_HAS_NO_PLATFORM_WAIT is currently a "dead" macro, in the sense that
// it is not tied anywhere into the build system or even documented. We should
// clean it up because it is technically never defined except when threads are
// disabled. We should clean it up in its own changeset in case we break "bad"
// users.
#ifndef _LIBCPP_HAS_NO_PLATFORM_WAIT
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*);
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(void const volatile*);
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __libcpp_atomic_monitor(void const volatile*);
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __libcpp_atomic_wait(void const volatile*, __cxx_contention_t);
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(__cxx_atomic_contention_t const volatile*);
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(__cxx_atomic_contention_t const volatile*);
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*);
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t);
template <class _Atp, class _Fn>
struct __libcpp_atomic_wait_backoff_impl {
_Atp* __a;
_Fn __test_fn;
_LIBCPP_AVAILABILITY_SYNC
_LIBCPP_INLINE_VISIBILITY bool operator()(chrono::nanoseconds __elapsed) const
{
if(__elapsed > chrono::microseconds(64))
{
auto const __monitor = __libcpp_atomic_monitor(__a);
if(__test_fn())
return true;
__libcpp_atomic_wait(__a, __monitor);
}
else if(__elapsed > chrono::microseconds(4))
__libcpp_thread_yield();
else
{} // poll
return false;
}
};
template <class _Atp, class _Fn>
_LIBCPP_AVAILABILITY_SYNC
_LIBCPP_INLINE_VISIBILITY bool __cxx_atomic_wait(_Atp* __a, _Fn && __test_fn)
{
__libcpp_atomic_wait_backoff_impl<_Atp, typename decay<_Fn>::type> __backoff_fn = {__a, __test_fn};
return __libcpp_thread_poll_with_backoff(__test_fn, __backoff_fn);
}
#else // _LIBCPP_HAS_NO_PLATFORM_WAIT
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY void __cxx_atomic_notify_all(__cxx_atomic_impl<_Tp> const volatile*) { }
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY void __cxx_atomic_notify_one(__cxx_atomic_impl<_Tp> const volatile*) { }
template <class _Atp, class _Fn>
_LIBCPP_INLINE_VISIBILITY bool __cxx_atomic_wait(_Atp*, _Fn && __test_fn)
{
#if defined(_LIBCPP_HAS_NO_THREADS)
using _Policy = __spinning_backoff_policy;
#else
using _Policy = __libcpp_timed_backoff_policy;
#endif
return __libcpp_thread_poll_with_backoff(__test_fn, _Policy());
}
#endif // _LIBCPP_HAS_NO_PLATFORM_WAIT
template <class _Atp, class _Tp>
struct __cxx_atomic_wait_test_fn_impl {
_Atp* __a;
_Tp __val;
memory_order __order;
_LIBCPP_INLINE_VISIBILITY bool operator()() const
{
return !__cxx_nonatomic_compare_equal(__cxx_atomic_load(__a, __order), __val);
}
};
template <class _Atp, class _Tp>
_LIBCPP_AVAILABILITY_SYNC
_LIBCPP_INLINE_VISIBILITY bool __cxx_atomic_wait(_Atp* __a, _Tp const __val, memory_order __order)
{
__cxx_atomic_wait_test_fn_impl<_Atp, _Tp> __test_fn = {__a, __val, __order};
return __cxx_atomic_wait(__a, __test_fn);
}
// general atomic<T>
template <class _Tp, bool = is_integral<_Tp>::value && !is_same<_Tp, bool>::value>
struct __atomic_base // false
{
mutable __cxx_atomic_impl<_Tp> __a_;
#if defined(__cpp_lib_atomic_is_always_lock_free)
- static _LIBCPP_CONSTEXPR bool is_always_lock_free = __atomic_always_lock_free(sizeof(__a_), 0);
+ static _LIBCPP_CONSTEXPR bool is_always_lock_free = __libcpp_is_always_lock_free<__cxx_atomic_impl<_Tp> >::__value;
#endif
_LIBCPP_INLINE_VISIBILITY
bool is_lock_free() const volatile _NOEXCEPT
{return __cxx_atomic_is_lock_free(sizeof(_Tp));}
_LIBCPP_INLINE_VISIBILITY
bool is_lock_free() const _NOEXCEPT
{return static_cast<__atomic_base const volatile*>(this)->is_lock_free();}
_LIBCPP_INLINE_VISIBILITY
void store(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
_LIBCPP_CHECK_STORE_MEMORY_ORDER(__m)
{__cxx_atomic_store(&__a_, __d, __m);}
_LIBCPP_INLINE_VISIBILITY
void store(_Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT
_LIBCPP_CHECK_STORE_MEMORY_ORDER(__m)
{__cxx_atomic_store(&__a_, __d, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp load(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT
_LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m)
{return __cxx_atomic_load(&__a_, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp load(memory_order __m = memory_order_seq_cst) const _NOEXCEPT
_LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m)
{return __cxx_atomic_load(&__a_, __m);}
_LIBCPP_INLINE_VISIBILITY
operator _Tp() const volatile _NOEXCEPT {return load();}
_LIBCPP_INLINE_VISIBILITY
operator _Tp() const _NOEXCEPT {return load();}
_LIBCPP_INLINE_VISIBILITY
_Tp exchange(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
{return __cxx_atomic_exchange(&__a_, __d, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp exchange(_Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT
{return __cxx_atomic_exchange(&__a_, __d, __m);}
_LIBCPP_INLINE_VISIBILITY
bool compare_exchange_weak(_Tp& __e, _Tp __d,
memory_order __s, memory_order __f) volatile _NOEXCEPT
_LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f)
{return __cxx_atomic_compare_exchange_weak(&__a_, &__e, __d, __s, __f);}
_LIBCPP_INLINE_VISIBILITY
bool compare_exchange_weak(_Tp& __e, _Tp __d,
memory_order __s, memory_order __f) _NOEXCEPT
_LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f)
{return __cxx_atomic_compare_exchange_weak(&__a_, &__e, __d, __s, __f);}
_LIBCPP_INLINE_VISIBILITY
bool compare_exchange_strong(_Tp& __e, _Tp __d,
memory_order __s, memory_order __f) volatile _NOEXCEPT
_LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f)
{return __cxx_atomic_compare_exchange_strong(&__a_, &__e, __d, __s, __f);}
_LIBCPP_INLINE_VISIBILITY
bool compare_exchange_strong(_Tp& __e, _Tp __d,
memory_order __s, memory_order __f) _NOEXCEPT
_LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f)
{return __cxx_atomic_compare_exchange_strong(&__a_, &__e, __d, __s, __f);}
_LIBCPP_INLINE_VISIBILITY
bool compare_exchange_weak(_Tp& __e, _Tp __d,
memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
{return __cxx_atomic_compare_exchange_weak(&__a_, &__e, __d, __m, __m);}
_LIBCPP_INLINE_VISIBILITY
bool compare_exchange_weak(_Tp& __e, _Tp __d,
memory_order __m = memory_order_seq_cst) _NOEXCEPT
{return __cxx_atomic_compare_exchange_weak(&__a_, &__e, __d, __m, __m);}
_LIBCPP_INLINE_VISIBILITY
bool compare_exchange_strong(_Tp& __e, _Tp __d,
memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
{return __cxx_atomic_compare_exchange_strong(&__a_, &__e, __d, __m, __m);}
_LIBCPP_INLINE_VISIBILITY
bool compare_exchange_strong(_Tp& __e, _Tp __d,
memory_order __m = memory_order_seq_cst) _NOEXCEPT
{return __cxx_atomic_compare_exchange_strong(&__a_, &__e, __d, __m, __m);}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT
{__cxx_atomic_wait(&__a_, __v, __m);}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT
{__cxx_atomic_wait(&__a_, __v, __m);}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY void notify_one() volatile _NOEXCEPT
{__cxx_atomic_notify_one(&__a_);}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY void notify_one() _NOEXCEPT
{__cxx_atomic_notify_one(&__a_);}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY void notify_all() volatile _NOEXCEPT
{__cxx_atomic_notify_all(&__a_);}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY void notify_all() _NOEXCEPT
{__cxx_atomic_notify_all(&__a_);}
#if _LIBCPP_STD_VER > 17
_LIBCPP_INLINE_VISIBILITY constexpr
__atomic_base() noexcept(is_nothrow_default_constructible_v<_Tp>) : __a_(_Tp()) {}
#else
_LIBCPP_INLINE_VISIBILITY
__atomic_base() _NOEXCEPT = default;
#endif
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
__atomic_base(_Tp __d) _NOEXCEPT : __a_(__d) {}
__atomic_base(const __atomic_base&) = delete;
};
#if defined(__cpp_lib_atomic_is_always_lock_free)
template <class _Tp, bool __b>
_LIBCPP_CONSTEXPR bool __atomic_base<_Tp, __b>::is_always_lock_free;
#endif
// atomic<Integral>
template <class _Tp>
struct __atomic_base<_Tp, true>
: public __atomic_base<_Tp, false>
{
typedef __atomic_base<_Tp, false> __base;
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
__atomic_base() _NOEXCEPT = default;
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __base(__d) {}
_LIBCPP_INLINE_VISIBILITY
_Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
{return __cxx_atomic_fetch_add(&this->__a_, __op, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT
{return __cxx_atomic_fetch_add(&this->__a_, __op, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
{return __cxx_atomic_fetch_sub(&this->__a_, __op, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT
{return __cxx_atomic_fetch_sub(&this->__a_, __op, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp fetch_and(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
{return __cxx_atomic_fetch_and(&this->__a_, __op, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp fetch_and(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT
{return __cxx_atomic_fetch_and(&this->__a_, __op, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp fetch_or(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
{return __cxx_atomic_fetch_or(&this->__a_, __op, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp fetch_or(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT
{return __cxx_atomic_fetch_or(&this->__a_, __op, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp fetch_xor(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
{return __cxx_atomic_fetch_xor(&this->__a_, __op, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp fetch_xor(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT
{return __cxx_atomic_fetch_xor(&this->__a_, __op, __m);}
_LIBCPP_INLINE_VISIBILITY
_Tp operator++(int) volatile _NOEXCEPT {return fetch_add(_Tp(1));}
_LIBCPP_INLINE_VISIBILITY
_Tp operator++(int) _NOEXCEPT {return fetch_add(_Tp(1));}
_LIBCPP_INLINE_VISIBILITY
_Tp operator--(int) volatile _NOEXCEPT {return fetch_sub(_Tp(1));}
_LIBCPP_INLINE_VISIBILITY
_Tp operator--(int) _NOEXCEPT {return fetch_sub(_Tp(1));}
_LIBCPP_INLINE_VISIBILITY
_Tp operator++() volatile _NOEXCEPT {return fetch_add(_Tp(1)) + _Tp(1);}
_LIBCPP_INLINE_VISIBILITY
_Tp operator++() _NOEXCEPT {return fetch_add(_Tp(1)) + _Tp(1);}
_LIBCPP_INLINE_VISIBILITY
_Tp operator--() volatile _NOEXCEPT {return fetch_sub(_Tp(1)) - _Tp(1);}
_LIBCPP_INLINE_VISIBILITY
_Tp operator--() _NOEXCEPT {return fetch_sub(_Tp(1)) - _Tp(1);}
_LIBCPP_INLINE_VISIBILITY
_Tp operator+=(_Tp __op) volatile _NOEXCEPT {return fetch_add(__op) + __op;}
_LIBCPP_INLINE_VISIBILITY
_Tp operator+=(_Tp __op) _NOEXCEPT {return fetch_add(__op) + __op;}
_LIBCPP_INLINE_VISIBILITY
_Tp operator-=(_Tp __op) volatile _NOEXCEPT {return fetch_sub(__op) - __op;}
_LIBCPP_INLINE_VISIBILITY
_Tp operator-=(_Tp __op) _NOEXCEPT {return fetch_sub(__op) - __op;}
_LIBCPP_INLINE_VISIBILITY
_Tp operator&=(_Tp __op) volatile _NOEXCEPT {return fetch_and(__op) & __op;}
_LIBCPP_INLINE_VISIBILITY
_Tp operator&=(_Tp __op) _NOEXCEPT {return fetch_and(__op) & __op;}
_LIBCPP_INLINE_VISIBILITY
_Tp operator|=(_Tp __op) volatile _NOEXCEPT {return fetch_or(__op) | __op;}
_LIBCPP_INLINE_VISIBILITY
_Tp operator|=(_Tp __op) _NOEXCEPT {return fetch_or(__op) | __op;}
_LIBCPP_INLINE_VISIBILITY
_Tp operator^=(_Tp __op) volatile _NOEXCEPT {return fetch_xor(__op) ^ __op;}
_LIBCPP_INLINE_VISIBILITY
_Tp operator^=(_Tp __op) _NOEXCEPT {return fetch_xor(__op) ^ __op;}
};
// atomic<T>
template <class _Tp>
struct atomic
: public __atomic_base<_Tp>
{
typedef __atomic_base<_Tp> __base;
typedef _Tp value_type;
typedef value_type difference_type;
#if _LIBCPP_STD_VER > 17
_LIBCPP_INLINE_VISIBILITY
atomic() = default;
#else
_LIBCPP_INLINE_VISIBILITY
atomic() _NOEXCEPT = default;
#endif
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR atomic(_Tp __d) _NOEXCEPT : __base(__d) {}
_LIBCPP_INLINE_VISIBILITY
_Tp operator=(_Tp __d) volatile _NOEXCEPT
{__base::store(__d); return __d;}
_LIBCPP_INLINE_VISIBILITY
_Tp operator=(_Tp __d) _NOEXCEPT
{__base::store(__d); return __d;}
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
};
// atomic<T*>
template <class _Tp>
struct atomic<_Tp*>
: public __atomic_base<_Tp*>
{
typedef __atomic_base<_Tp*> __base;
typedef _Tp* value_type;
typedef ptrdiff_t difference_type;
_LIBCPP_INLINE_VISIBILITY
atomic() _NOEXCEPT = default;
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR atomic(_Tp* __d) _NOEXCEPT : __base(__d) {}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator=(_Tp* __d) volatile _NOEXCEPT
{__base::store(__d); return __d;}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator=(_Tp* __d) _NOEXCEPT
{__base::store(__d); return __d;}
_LIBCPP_INLINE_VISIBILITY
_Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
// __atomic_fetch_add accepts function pointers, guard against them.
static_assert(!is_function<typename remove_pointer<_Tp>::type>::value, "Pointer to function isn't allowed");
return __cxx_atomic_fetch_add(&this->__a_, __op, __m);
}
_LIBCPP_INLINE_VISIBILITY
_Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
// __atomic_fetch_add accepts function pointers, guard against them.
static_assert(!is_function<typename remove_pointer<_Tp>::type>::value, "Pointer to function isn't allowed");
return __cxx_atomic_fetch_add(&this->__a_, __op, __m);
}
_LIBCPP_INLINE_VISIBILITY
_Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
// __atomic_fetch_add accepts function pointers, guard against them.
static_assert(!is_function<typename remove_pointer<_Tp>::type>::value, "Pointer to function isn't allowed");
return __cxx_atomic_fetch_sub(&this->__a_, __op, __m);
}
_LIBCPP_INLINE_VISIBILITY
_Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
// __atomic_fetch_add accepts function pointers, guard against them.
static_assert(!is_function<typename remove_pointer<_Tp>::type>::value, "Pointer to function isn't allowed");
return __cxx_atomic_fetch_sub(&this->__a_, __op, __m);
}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator++(int) volatile _NOEXCEPT {return fetch_add(1);}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator++(int) _NOEXCEPT {return fetch_add(1);}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator--(int) volatile _NOEXCEPT {return fetch_sub(1);}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator--(int) _NOEXCEPT {return fetch_sub(1);}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator++() volatile _NOEXCEPT {return fetch_add(1) + 1;}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator++() _NOEXCEPT {return fetch_add(1) + 1;}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator--() volatile _NOEXCEPT {return fetch_sub(1) - 1;}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator--() _NOEXCEPT {return fetch_sub(1) - 1;}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator+=(ptrdiff_t __op) volatile _NOEXCEPT {return fetch_add(__op) + __op;}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator+=(ptrdiff_t __op) _NOEXCEPT {return fetch_add(__op) + __op;}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator-=(ptrdiff_t __op) volatile _NOEXCEPT {return fetch_sub(__op) - __op;}
_LIBCPP_INLINE_VISIBILITY
_Tp* operator-=(ptrdiff_t __op) _NOEXCEPT {return fetch_sub(__op) - __op;}
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
};
// atomic_is_lock_free
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool
atomic_is_lock_free(const volatile atomic<_Tp>* __o) _NOEXCEPT
{
return __o->is_lock_free();
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool
atomic_is_lock_free(const atomic<_Tp>* __o) _NOEXCEPT
{
return __o->is_lock_free();
}
// atomic_init
template <class _Tp>
_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_INLINE_VISIBILITY
void
atomic_init(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT
{
__cxx_atomic_init(&__o->__a_, __d);
}
template <class _Tp>
_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_INLINE_VISIBILITY
void
atomic_init(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT
{
__cxx_atomic_init(&__o->__a_, __d);
}
// atomic_store
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
void
atomic_store(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT
{
__o->store(__d);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
void
atomic_store(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT
{
__o->store(__d);
}
// atomic_store_explicit
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
void
atomic_store_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, memory_order __m) _NOEXCEPT
_LIBCPP_CHECK_STORE_MEMORY_ORDER(__m)
{
__o->store(__d, __m);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
void
atomic_store_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, memory_order __m) _NOEXCEPT
_LIBCPP_CHECK_STORE_MEMORY_ORDER(__m)
{
__o->store(__d, __m);
}
// atomic_load
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp
atomic_load(const volatile atomic<_Tp>* __o) _NOEXCEPT
{
return __o->load();
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp
atomic_load(const atomic<_Tp>* __o) _NOEXCEPT
{
return __o->load();
}
// atomic_load_explicit
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp
atomic_load_explicit(const volatile atomic<_Tp>* __o, memory_order __m) _NOEXCEPT
_LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m)
{
return __o->load(__m);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp
atomic_load_explicit(const atomic<_Tp>* __o, memory_order __m) _NOEXCEPT
_LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m)
{
return __o->load(__m);
}
// atomic_exchange
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp
atomic_exchange(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT
{
return __o->exchange(__d);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp
atomic_exchange(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT
{
return __o->exchange(__d);
}
// atomic_exchange_explicit
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp
atomic_exchange_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, memory_order __m) _NOEXCEPT
{
return __o->exchange(__d, __m);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp
atomic_exchange_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, memory_order __m) _NOEXCEPT
{
return __o->exchange(__d, __m);
}
// atomic_compare_exchange_weak
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool
atomic_compare_exchange_weak(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d) _NOEXCEPT
{
return __o->compare_exchange_weak(*__e, __d);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool
atomic_compare_exchange_weak(atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d) _NOEXCEPT
{
return __o->compare_exchange_weak(*__e, __d);
}
// atomic_compare_exchange_strong
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool
atomic_compare_exchange_strong(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d) _NOEXCEPT
{
return __o->compare_exchange_strong(*__e, __d);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool
atomic_compare_exchange_strong(atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d) _NOEXCEPT
{
return __o->compare_exchange_strong(*__e, __d);
}
// atomic_compare_exchange_weak_explicit
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool
atomic_compare_exchange_weak_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e,
typename atomic<_Tp>::value_type __d,
memory_order __s, memory_order __f) _NOEXCEPT
_LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f)
{
return __o->compare_exchange_weak(*__e, __d, __s, __f);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool
atomic_compare_exchange_weak_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d,
memory_order __s, memory_order __f) _NOEXCEPT
_LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f)
{
return __o->compare_exchange_weak(*__e, __d, __s, __f);
}
// atomic_compare_exchange_strong_explicit
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool
atomic_compare_exchange_strong_explicit(volatile atomic<_Tp>* __o,
typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d,
memory_order __s, memory_order __f) _NOEXCEPT
_LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f)
{
return __o->compare_exchange_strong(*__e, __d, __s, __f);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
bool
atomic_compare_exchange_strong_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e,
typename atomic<_Tp>::value_type __d,
memory_order __s, memory_order __f) _NOEXCEPT
_LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f)
{
return __o->compare_exchange_strong(*__e, __d, __s, __f);
}
// atomic_wait
template <class _Tp>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void atomic_wait(const volatile atomic<_Tp>* __o,
typename atomic<_Tp>::value_type __v) _NOEXCEPT
{
return __o->wait(__v);
}
template <class _Tp>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void atomic_wait(const atomic<_Tp>* __o,
typename atomic<_Tp>::value_type __v) _NOEXCEPT
{
return __o->wait(__v);
}
// atomic_wait_explicit
template <class _Tp>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void atomic_wait_explicit(const volatile atomic<_Tp>* __o,
typename atomic<_Tp>::value_type __v,
memory_order __m) _NOEXCEPT
_LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m)
{
return __o->wait(__v, __m);
}
template <class _Tp>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void atomic_wait_explicit(const atomic<_Tp>* __o,
typename atomic<_Tp>::value_type __v,
memory_order __m) _NOEXCEPT
_LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m)
{
return __o->wait(__v, __m);
}
// atomic_notify_one
template <class _Tp>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void atomic_notify_one(volatile atomic<_Tp>* __o) _NOEXCEPT
{
__o->notify_one();
}
template <class _Tp>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void atomic_notify_one(atomic<_Tp>* __o) _NOEXCEPT
{
__o->notify_one();
}
// atomic_notify_one
template <class _Tp>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void atomic_notify_all(volatile atomic<_Tp>* __o) _NOEXCEPT
{
__o->notify_all();
}
template <class _Tp>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void atomic_notify_all(atomic<_Tp>* __o) _NOEXCEPT
{
__o->notify_all();
}
// atomic_fetch_add
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp
atomic_fetch_add(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT
{
return __o->fetch_add(__op);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp
atomic_fetch_add(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT
{
return __o->fetch_add(__op);
}
// atomic_fetch_add_explicit
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp atomic_fetch_add_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT
{
return __o->fetch_add(__op, __m);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp atomic_fetch_add_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT
{
return __o->fetch_add(__op, __m);
}
// atomic_fetch_sub
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp atomic_fetch_sub(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT
{
return __o->fetch_sub(__op);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp atomic_fetch_sub(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT
{
return __o->fetch_sub(__op);
}
// atomic_fetch_sub_explicit
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp atomic_fetch_sub_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT
{
return __o->fetch_sub(__op, __m);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
_Tp atomic_fetch_sub_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT
{
return __o->fetch_sub(__op, __m);
}
// atomic_fetch_and
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value && !is_same<_Tp, bool>::value,
_Tp
>::type
atomic_fetch_and(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT
{
return __o->fetch_and(__op);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value && !is_same<_Tp, bool>::value,
_Tp
>::type
atomic_fetch_and(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT
{
return __o->fetch_and(__op);
}
// atomic_fetch_and_explicit
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value && !is_same<_Tp, bool>::value,
_Tp
>::type
atomic_fetch_and_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT
{
return __o->fetch_and(__op, __m);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value && !is_same<_Tp, bool>::value,
_Tp
>::type
atomic_fetch_and_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT
{
return __o->fetch_and(__op, __m);
}
// atomic_fetch_or
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value && !is_same<_Tp, bool>::value,
_Tp
>::type
atomic_fetch_or(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT
{
return __o->fetch_or(__op);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value && !is_same<_Tp, bool>::value,
_Tp
>::type
atomic_fetch_or(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT
{
return __o->fetch_or(__op);
}
// atomic_fetch_or_explicit
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value && !is_same<_Tp, bool>::value,
_Tp
>::type
atomic_fetch_or_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT
{
return __o->fetch_or(__op, __m);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value && !is_same<_Tp, bool>::value,
_Tp
>::type
atomic_fetch_or_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT
{
return __o->fetch_or(__op, __m);
}
// atomic_fetch_xor
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value && !is_same<_Tp, bool>::value,
_Tp
>::type
atomic_fetch_xor(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT
{
return __o->fetch_xor(__op);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value && !is_same<_Tp, bool>::value,
_Tp
>::type
atomic_fetch_xor(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT
{
return __o->fetch_xor(__op);
}
// atomic_fetch_xor_explicit
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value && !is_same<_Tp, bool>::value,
_Tp
>::type
atomic_fetch_xor_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT
{
return __o->fetch_xor(__op, __m);
}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value && !is_same<_Tp, bool>::value,
_Tp
>::type
atomic_fetch_xor_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT
{
return __o->fetch_xor(__op, __m);
}
// flag type and operations
typedef struct atomic_flag
{
__cxx_atomic_impl<_LIBCPP_ATOMIC_FLAG_TYPE> __a_;
_LIBCPP_INLINE_VISIBILITY
bool test(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT
{return _LIBCPP_ATOMIC_FLAG_TYPE(true) == __cxx_atomic_load(&__a_, __m);}
_LIBCPP_INLINE_VISIBILITY
bool test(memory_order __m = memory_order_seq_cst) const _NOEXCEPT
{return _LIBCPP_ATOMIC_FLAG_TYPE(true) == __cxx_atomic_load(&__a_, __m);}
_LIBCPP_INLINE_VISIBILITY
bool test_and_set(memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
{return __cxx_atomic_exchange(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(true), __m);}
_LIBCPP_INLINE_VISIBILITY
bool test_and_set(memory_order __m = memory_order_seq_cst) _NOEXCEPT
{return __cxx_atomic_exchange(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(true), __m);}
_LIBCPP_INLINE_VISIBILITY
void clear(memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
{__cxx_atomic_store(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(false), __m);}
_LIBCPP_INLINE_VISIBILITY
void clear(memory_order __m = memory_order_seq_cst) _NOEXCEPT
{__cxx_atomic_store(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(false), __m);}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void wait(bool __v, memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT
{__cxx_atomic_wait(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m);}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void wait(bool __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT
{__cxx_atomic_wait(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m);}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void notify_one() volatile _NOEXCEPT
{__cxx_atomic_notify_one(&__a_);}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void notify_one() _NOEXCEPT
{__cxx_atomic_notify_one(&__a_);}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void notify_all() volatile _NOEXCEPT
{__cxx_atomic_notify_all(&__a_);}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
void notify_all() _NOEXCEPT
{__cxx_atomic_notify_all(&__a_);}
#if _LIBCPP_STD_VER > 17
_LIBCPP_INLINE_VISIBILITY constexpr
atomic_flag() _NOEXCEPT : __a_(false) {}
#else
_LIBCPP_INLINE_VISIBILITY
atomic_flag() _NOEXCEPT = default;
#endif
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
atomic_flag(bool __b) _NOEXCEPT : __a_(__b) {} // EXTENSION
atomic_flag(const atomic_flag&) = delete;
atomic_flag& operator=(const atomic_flag&) = delete;
atomic_flag& operator=(const atomic_flag&) volatile = delete;
} atomic_flag;
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test(const volatile atomic_flag* __o) _NOEXCEPT
{
return __o->test();
}
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test(const atomic_flag* __o) _NOEXCEPT
{
return __o->test();
}
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test_explicit(const volatile atomic_flag* __o, memory_order __m) _NOEXCEPT
{
return __o->test(__m);
}
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test_explicit(const atomic_flag* __o, memory_order __m) _NOEXCEPT
{
return __o->test(__m);
}
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test_and_set(volatile atomic_flag* __o) _NOEXCEPT
{
return __o->test_and_set();
}
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test_and_set(atomic_flag* __o) _NOEXCEPT
{
return __o->test_and_set();
}
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test_and_set_explicit(volatile atomic_flag* __o, memory_order __m) _NOEXCEPT
{
return __o->test_and_set(__m);
}
inline _LIBCPP_INLINE_VISIBILITY
bool
atomic_flag_test_and_set_explicit(atomic_flag* __o, memory_order __m) _NOEXCEPT
{
return __o->test_and_set(__m);
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_flag_clear(volatile atomic_flag* __o) _NOEXCEPT
{
__o->clear();
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_flag_clear(atomic_flag* __o) _NOEXCEPT
{
__o->clear();
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_flag_clear_explicit(volatile atomic_flag* __o, memory_order __m) _NOEXCEPT
{
__o->clear(__m);
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_flag_clear_explicit(atomic_flag* __o, memory_order __m) _NOEXCEPT
{
__o->clear(__m);
}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_SYNC
void
atomic_flag_wait(const volatile atomic_flag* __o, bool __v) _NOEXCEPT
{
__o->wait(__v);
}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_SYNC
void
atomic_flag_wait(const atomic_flag* __o, bool __v) _NOEXCEPT
{
__o->wait(__v);
}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_SYNC
void
atomic_flag_wait_explicit(const volatile atomic_flag* __o,
bool __v, memory_order __m) _NOEXCEPT
{
__o->wait(__v, __m);
}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_SYNC
void
atomic_flag_wait_explicit(const atomic_flag* __o,
bool __v, memory_order __m) _NOEXCEPT
{
__o->wait(__v, __m);
}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_SYNC
void
atomic_flag_notify_one(volatile atomic_flag* __o) _NOEXCEPT
{
__o->notify_one();
}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_SYNC
void
atomic_flag_notify_one(atomic_flag* __o) _NOEXCEPT
{
__o->notify_one();
}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_SYNC
void
atomic_flag_notify_all(volatile atomic_flag* __o) _NOEXCEPT
{
__o->notify_all();
}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_SYNC
void
atomic_flag_notify_all(atomic_flag* __o) _NOEXCEPT
{
__o->notify_all();
}
// fences
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_thread_fence(memory_order __m) _NOEXCEPT
{
__cxx_atomic_thread_fence(__m);
}
inline _LIBCPP_INLINE_VISIBILITY
void
atomic_signal_fence(memory_order __m) _NOEXCEPT
{
__cxx_atomic_signal_fence(__m);
}
// Atomics for standard typedef types
typedef atomic<bool> atomic_bool;
typedef atomic<char> atomic_char;
typedef atomic<signed char> atomic_schar;
typedef atomic<unsigned char> atomic_uchar;
typedef atomic<short> atomic_short;
typedef atomic<unsigned short> atomic_ushort;
typedef atomic<int> atomic_int;
typedef atomic<unsigned int> atomic_uint;
typedef atomic<long> atomic_long;
typedef atomic<unsigned long> atomic_ulong;
typedef atomic<long long> atomic_llong;
typedef atomic<unsigned long long> atomic_ullong;
#ifndef _LIBCPP_HAS_NO_CHAR8_T
typedef atomic<char8_t> atomic_char8_t;
#endif
typedef atomic<char16_t> atomic_char16_t;
typedef atomic<char32_t> atomic_char32_t;
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
typedef atomic<wchar_t> atomic_wchar_t;
#endif
typedef atomic<int_least8_t> atomic_int_least8_t;
typedef atomic<uint_least8_t> atomic_uint_least8_t;
typedef atomic<int_least16_t> atomic_int_least16_t;
typedef atomic<uint_least16_t> atomic_uint_least16_t;
typedef atomic<int_least32_t> atomic_int_least32_t;
typedef atomic<uint_least32_t> atomic_uint_least32_t;
typedef atomic<int_least64_t> atomic_int_least64_t;
typedef atomic<uint_least64_t> atomic_uint_least64_t;
typedef atomic<int_fast8_t> atomic_int_fast8_t;
typedef atomic<uint_fast8_t> atomic_uint_fast8_t;
typedef atomic<int_fast16_t> atomic_int_fast16_t;
typedef atomic<uint_fast16_t> atomic_uint_fast16_t;
typedef atomic<int_fast32_t> atomic_int_fast32_t;
typedef atomic<uint_fast32_t> atomic_uint_fast32_t;
typedef atomic<int_fast64_t> atomic_int_fast64_t;
typedef atomic<uint_fast64_t> atomic_uint_fast64_t;
typedef atomic< int8_t> atomic_int8_t;
typedef atomic<uint8_t> atomic_uint8_t;
typedef atomic< int16_t> atomic_int16_t;
typedef atomic<uint16_t> atomic_uint16_t;
typedef atomic< int32_t> atomic_int32_t;
typedef atomic<uint32_t> atomic_uint32_t;
typedef atomic< int64_t> atomic_int64_t;
typedef atomic<uint64_t> atomic_uint64_t;
typedef atomic<intptr_t> atomic_intptr_t;
typedef atomic<uintptr_t> atomic_uintptr_t;
typedef atomic<size_t> atomic_size_t;
typedef atomic<ptrdiff_t> atomic_ptrdiff_t;
typedef atomic<intmax_t> atomic_intmax_t;
typedef atomic<uintmax_t> atomic_uintmax_t;
// atomic_*_lock_free : prefer the contention type most highly, then the largest lock-free type
#ifdef __cpp_lib_atomic_is_always_lock_free
-# define _LIBCPP_CONTENTION_LOCK_FREE __atomic_always_lock_free(sizeof(__cxx_contention_t), 0)
+# define _LIBCPP_CONTENTION_LOCK_FREE ::std::__libcpp_is_always_lock_free<__cxx_contention_t>::__value
#else
# define _LIBCPP_CONTENTION_LOCK_FREE false
#endif
#if ATOMIC_LLONG_LOCK_FREE == 2
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, long long>::type __libcpp_signed_lock_free;
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, unsigned long long>::type __libcpp_unsigned_lock_free;
#elif ATOMIC_INT_LOCK_FREE == 2
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, int>::type __libcpp_signed_lock_free;
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, unsigned int>::type __libcpp_unsigned_lock_free;
#elif ATOMIC_SHORT_LOCK_FREE == 2
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, short>::type __libcpp_signed_lock_free;
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, unsigned short>::type __libcpp_unsigned_lock_free;
#elif ATOMIC_CHAR_LOCK_FREE == 2
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, char>::type __libcpp_signed_lock_free;
typedef conditional<_LIBCPP_CONTENTION_LOCK_FREE, __cxx_contention_t, unsigned char>::type __libcpp_unsigned_lock_free;
#else
// No signed/unsigned lock-free types
#define _LIBCPP_NO_LOCK_FREE_TYPES
#endif
#if !defined(_LIBCPP_NO_LOCK_FREE_TYPES)
typedef atomic<__libcpp_signed_lock_free> atomic_signed_lock_free;
typedef atomic<__libcpp_unsigned_lock_free> atomic_unsigned_lock_free;
#endif
#define ATOMIC_FLAG_INIT {false}
#define ATOMIC_VAR_INIT(__v) {__v}
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_DISABLE_DEPRECATION_WARNINGS)
# if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 1400
# pragma clang deprecated(ATOMIC_VAR_INIT)
# endif
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_DISABLE_DEPRECATION_WARNINGS)
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_ATOMIC
diff --git a/contrib/llvm-project/libcxx/include/stdatomic.h b/contrib/llvm-project/libcxx/include/stdatomic.h
index d9550c44061c..ff2a5682f5bb 100644
--- a/contrib/llvm-project/libcxx/include/stdatomic.h
+++ b/contrib/llvm-project/libcxx/include/stdatomic.h
@@ -1,235 +1,235 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_STDATOMIC_H
#define _LIBCPP_STDATOMIC_H
/*
stdatomic.h synopsis
template<class T>
using std-atomic = std::atomic<T>; // exposition only
#define _Atomic(T) std-atomic<T>
#define ATOMIC_BOOL_LOCK_FREE see below
#define ATOMIC_CHAR_LOCK_FREE see below
#define ATOMIC_CHAR16_T_LOCK_FREE see below
#define ATOMIC_CHAR32_T_LOCK_FREE see below
#define ATOMIC_WCHAR_T_LOCK_FREE see below
#define ATOMIC_SHORT_LOCK_FREE see below
#define ATOMIC_INT_LOCK_FREE see below
#define ATOMIC_LONG_LOCK_FREE see below
#define ATOMIC_LLONG_LOCK_FREE see below
#define ATOMIC_POINTER_LOCK_FREE see below
using std::memory_order // see below
using std::memory_order_relaxed // see below
using std::memory_order_consume // see below
using std::memory_order_acquire // see below
using std::memory_order_release // see below
using std::memory_order_acq_rel // see below
using std::memory_order_seq_cst // see below
using std::atomic_flag // see below
using std::atomic_bool // see below
using std::atomic_char // see below
using std::atomic_schar // see below
using std::atomic_uchar // see below
using std::atomic_short // see below
using std::atomic_ushort // see below
using std::atomic_int // see below
using std::atomic_uint // see below
using std::atomic_long // see below
using std::atomic_ulong // see below
using std::atomic_llong // see below
using std::atomic_ullong // see below
using std::atomic_char8_t // see below
using std::atomic_char16_t // see below
using std::atomic_char32_t // see below
using std::atomic_wchar_t // see below
using std::atomic_int8_t // see below
using std::atomic_uint8_t // see below
using std::atomic_int16_t // see below
using std::atomic_uint16_t // see below
using std::atomic_int32_t // see below
using std::atomic_uint32_t // see below
using std::atomic_int64_t // see below
using std::atomic_uint64_t // see below
using std::atomic_int_least8_t // see below
using std::atomic_uint_least8_t // see below
using std::atomic_int_least16_t // see below
using std::atomic_uint_least16_t // see below
using std::atomic_int_least32_t // see below
using std::atomic_uint_least32_t // see below
using std::atomic_int_least64_t // see below
using std::atomic_uint_least64_t // see below
using std::atomic_int_fast8_t // see below
using std::atomic_uint_fast8_t // see below
using std::atomic_int_fast16_t // see below
using std::atomic_uint_fast16_t // see below
using std::atomic_int_fast32_t // see below
using std::atomic_uint_fast32_t // see below
using std::atomic_int_fast64_t // see below
using std::atomic_uint_fast64_t // see below
using std::atomic_intptr_t // see below
using std::atomic_uintptr_t // see below
using std::atomic_size_t // see below
using std::atomic_ptrdiff_t // see below
using std::atomic_intmax_t // see below
using std::atomic_uintmax_t // see below
using std::atomic_is_lock_free // see below
using std::atomic_load // see below
using std::atomic_load_explicit // see below
using std::atomic_store // see below
using std::atomic_store_explicit // see below
using std::atomic_exchange // see below
using std::atomic_exchange_explicit // see below
using std::atomic_compare_exchange_strong // see below
using std::atomic_compare_exchange_strong_explicit // see below
using std::atomic_compare_exchange_weak // see below
using std::atomic_compare_exchange_weak_explicit // see below
using std::atomic_fetch_add // see below
using std::atomic_fetch_add_explicit // see below
using std::atomic_fetch_sub // see below
using std::atomic_fetch_sub_explicit // see below
using std::atomic_fetch_or // see below
using std::atomic_fetch_or_explicit // see below
using std::atomic_fetch_and // see below
using std::atomic_fetch_and_explicit // see below
using std::atomic_flag_test_and_set // see below
using std::atomic_flag_test_and_set_explicit // see below
using std::atomic_flag_clear // see below
using std::atomic_flag_clear_explicit // see below
using std::atomic_thread_fence // see below
using std::atomic_signal_fence // see below
*/
#include <__config>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
-#if _LIBCPP_STD_VER > 20
+#if defined(__cplusplus) && _LIBCPP_STD_VER > 20
#include <atomic>
#include <version>
#ifdef _Atomic
# undef _Atomic
#endif
#define _Atomic(_Tp) ::std::atomic<_Tp>
using std::memory_order _LIBCPP_USING_IF_EXISTS;
using std::memory_order_relaxed _LIBCPP_USING_IF_EXISTS;
using std::memory_order_consume _LIBCPP_USING_IF_EXISTS;
using std::memory_order_acquire _LIBCPP_USING_IF_EXISTS;
using std::memory_order_release _LIBCPP_USING_IF_EXISTS;
using std::memory_order_acq_rel _LIBCPP_USING_IF_EXISTS;
using std::memory_order_seq_cst _LIBCPP_USING_IF_EXISTS;
using std::atomic_flag _LIBCPP_USING_IF_EXISTS;
using std::atomic_bool _LIBCPP_USING_IF_EXISTS;
using std::atomic_char _LIBCPP_USING_IF_EXISTS;
using std::atomic_schar _LIBCPP_USING_IF_EXISTS;
using std::atomic_uchar _LIBCPP_USING_IF_EXISTS;
using std::atomic_short _LIBCPP_USING_IF_EXISTS;
using std::atomic_ushort _LIBCPP_USING_IF_EXISTS;
using std::atomic_int _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint _LIBCPP_USING_IF_EXISTS;
using std::atomic_long _LIBCPP_USING_IF_EXISTS;
using std::atomic_ulong _LIBCPP_USING_IF_EXISTS;
using std::atomic_llong _LIBCPP_USING_IF_EXISTS;
using std::atomic_ullong _LIBCPP_USING_IF_EXISTS;
using std::atomic_char8_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_char16_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_char32_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_wchar_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_int8_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint8_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_int16_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint16_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_int32_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint32_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_int64_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint64_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_int_least8_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint_least8_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_int_least16_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint_least16_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_int_least32_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint_least32_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_int_least64_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint_least64_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_int_fast8_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint_fast8_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_int_fast16_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint_fast16_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_int_fast32_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint_fast32_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_int_fast64_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uint_fast64_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_intptr_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uintptr_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_size_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_ptrdiff_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_intmax_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_uintmax_t _LIBCPP_USING_IF_EXISTS;
using std::atomic_compare_exchange_strong _LIBCPP_USING_IF_EXISTS;
using std::atomic_compare_exchange_strong_explicit _LIBCPP_USING_IF_EXISTS;
using std::atomic_compare_exchange_weak _LIBCPP_USING_IF_EXISTS;
using std::atomic_compare_exchange_weak_explicit _LIBCPP_USING_IF_EXISTS;
using std::atomic_exchange _LIBCPP_USING_IF_EXISTS;
using std::atomic_exchange_explicit _LIBCPP_USING_IF_EXISTS;
using std::atomic_fetch_add _LIBCPP_USING_IF_EXISTS;
using std::atomic_fetch_add_explicit _LIBCPP_USING_IF_EXISTS;
using std::atomic_fetch_and _LIBCPP_USING_IF_EXISTS;
using std::atomic_fetch_and_explicit _LIBCPP_USING_IF_EXISTS;
using std::atomic_fetch_or _LIBCPP_USING_IF_EXISTS;
using std::atomic_fetch_or_explicit _LIBCPP_USING_IF_EXISTS;
using std::atomic_fetch_sub _LIBCPP_USING_IF_EXISTS;
using std::atomic_fetch_sub_explicit _LIBCPP_USING_IF_EXISTS;
using std::atomic_flag_clear _LIBCPP_USING_IF_EXISTS;
using std::atomic_flag_clear_explicit _LIBCPP_USING_IF_EXISTS;
using std::atomic_flag_test_and_set _LIBCPP_USING_IF_EXISTS;
using std::atomic_flag_test_and_set_explicit _LIBCPP_USING_IF_EXISTS;
using std::atomic_is_lock_free _LIBCPP_USING_IF_EXISTS;
using std::atomic_load _LIBCPP_USING_IF_EXISTS;
using std::atomic_load_explicit _LIBCPP_USING_IF_EXISTS;
using std::atomic_store _LIBCPP_USING_IF_EXISTS;
using std::atomic_store_explicit _LIBCPP_USING_IF_EXISTS;
using std::atomic_signal_fence _LIBCPP_USING_IF_EXISTS;
using std::atomic_thread_fence _LIBCPP_USING_IF_EXISTS;
#elif defined(_LIBCPP_COMPILER_CLANG_BASED)
// Before C++23, we include the next <stdatomic.h> on the path to avoid hijacking
// the header. We do this because Clang has historically shipped a <stdatomic.h>
// header that would be available in all Standard modes, and we don't want to
// break that use case.
# if __has_include_next(<stdatomic.h>)
# include_next <stdatomic.h>
# endif
-#endif // _LIBCPP_STD_VER > 20
+#endif // defined(__cplusplus) && _LIBCPP_STD_VER > 20
#endif // _LIBCPP_STDATOMIC_H
diff --git a/contrib/llvm-project/libcxx/include/version b/contrib/llvm-project/libcxx/include/version
index 8ffb1747eb27..d0c6fe466e70 100644
--- a/contrib/llvm-project/libcxx/include/version
+++ b/contrib/llvm-project/libcxx/include/version
@@ -1,413 +1,413 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_VERSIONH
#define _LIBCPP_VERSIONH
/*
version synopsis
Macro name Value Headers
__cpp_lib_adaptor_iterator_pair_constructor 202106L <queue> <stack>
__cpp_lib_addressof_constexpr 201603L <memory>
__cpp_lib_allocate_at_least 202106L <memory>
__cpp_lib_allocator_traits_is_always_equal 201411L <deque> <forward_list> <list>
<map> <memory> <scoped_allocator>
<set> <string> <unordered_map>
<unordered_set> <vector>
__cpp_lib_any 201606L <any>
__cpp_lib_apply 201603L <tuple>
__cpp_lib_array_constexpr 201811L <array> <iterator>
201603L // C++17
__cpp_lib_as_const 201510L <utility>
__cpp_lib_associative_heterogeneous_erasure 202110L <map> <set> <unordered_map>
<unordered_set>
__cpp_lib_assume_aligned 201811L <memory>
__cpp_lib_atomic_flag_test 201907L <atomic>
__cpp_lib_atomic_float 201711L <atomic>
__cpp_lib_atomic_is_always_lock_free 201603L <atomic>
__cpp_lib_atomic_lock_free_type_aliases 201907L <atomic>
__cpp_lib_atomic_ref 201806L <atomic>
__cpp_lib_atomic_shared_ptr 201711L <atomic>
__cpp_lib_atomic_value_initialization 201911L <atomic> <memory>
__cpp_lib_atomic_wait 201907L <atomic>
__cpp_lib_barrier 201907L <barrier>
__cpp_lib_bind_back 202202L <functional>
__cpp_lib_bind_front 201907L <functional>
__cpp_lib_bit_cast 201806L <bit>
__cpp_lib_bitops 201907L <bit>
__cpp_lib_bool_constant 201505L <type_traits>
__cpp_lib_bounded_array_traits 201902L <type_traits>
__cpp_lib_boyer_moore_searcher 201603L <functional>
__cpp_lib_byte 201603L <cstddef>
__cpp_lib_byteswap 202110L <bit>
__cpp_lib_char8_t 201907L <atomic> <filesystem> <istream>
<limits> <locale> <ostream>
<string> <string_view>
__cpp_lib_chrono 201611L <chrono>
__cpp_lib_chrono_udls 201304L <chrono>
__cpp_lib_clamp 201603L <algorithm>
__cpp_lib_complex_udls 201309L <complex>
__cpp_lib_concepts 202002L <concepts>
__cpp_lib_constexpr_algorithms 201806L <algorithm>
__cpp_lib_constexpr_cmath 202202L <cmath> <cstdlib>
__cpp_lib_constexpr_complex 201711L <complex>
__cpp_lib_constexpr_dynamic_alloc 201907L <memory>
__cpp_lib_constexpr_functional 201907L <functional>
__cpp_lib_constexpr_iterator 201811L <iterator>
__cpp_lib_constexpr_memory 201811L <memory>
__cpp_lib_constexpr_numeric 201911L <numeric>
__cpp_lib_constexpr_string 201907L <string>
__cpp_lib_constexpr_string_view 201811L <string_view>
__cpp_lib_constexpr_tuple 201811L <tuple>
__cpp_lib_constexpr_typeinfo 202106L <typeinfo>
__cpp_lib_constexpr_utility 201811L <utility>
__cpp_lib_constexpr_vector 201907L <vector>
__cpp_lib_coroutine 201902L <coroutine>
__cpp_lib_destroying_delete 201806L <new>
__cpp_lib_enable_shared_from_this 201603L <memory>
__cpp_lib_endian 201907L <bit>
__cpp_lib_erase_if 202002L <deque> <forward_list> <list>
<map> <set> <string>
<unordered_map> <unordered_set> <vector>
__cpp_lib_exchange_function 201304L <utility>
__cpp_lib_execution 201902L <execution>
201603L // C++17
__cpp_lib_filesystem 201703L <filesystem>
__cpp_lib_format 202106L <format>
__cpp_lib_gcd_lcm 201606L <numeric>
__cpp_lib_generic_associative_lookup 201304L <map> <set>
__cpp_lib_generic_unordered_lookup 201811L <unordered_map> <unordered_set>
__cpp_lib_hardware_interference_size 201703L <new>
__cpp_lib_has_unique_object_representations 201606L <type_traits>
__cpp_lib_hypot 201603L <cmath>
__cpp_lib_incomplete_container_elements 201505L <forward_list> <list> <vector>
__cpp_lib_int_pow2 202002L <bit>
__cpp_lib_integer_comparison_functions 202002L <utility>
__cpp_lib_integer_sequence 201304L <utility>
__cpp_lib_integral_constant_callable 201304L <type_traits>
__cpp_lib_interpolate 201902L <cmath> <numeric>
__cpp_lib_invoke 201411L <functional>
__cpp_lib_invoke_r 202106L <functional>
__cpp_lib_is_aggregate 201703L <type_traits>
__cpp_lib_is_constant_evaluated 201811L <type_traits>
__cpp_lib_is_final 201402L <type_traits>
__cpp_lib_is_invocable 201703L <type_traits>
__cpp_lib_is_layout_compatible 201907L <type_traits>
__cpp_lib_is_nothrow_convertible 201806L <type_traits>
__cpp_lib_is_null_pointer 201309L <type_traits>
__cpp_lib_is_pointer_interconvertible 201907L <type_traits>
__cpp_lib_is_scoped_enum 202011L <type_traits>
__cpp_lib_is_swappable 201603L <type_traits>
__cpp_lib_jthread 201911L <stop_token> <thread>
__cpp_lib_latch 201907L <latch>
__cpp_lib_launder 201606L <new>
__cpp_lib_list_remove_return_type 201806L <forward_list> <list>
__cpp_lib_logical_traits 201510L <type_traits>
__cpp_lib_make_from_tuple 201606L <tuple>
__cpp_lib_make_reverse_iterator 201402L <iterator>
__cpp_lib_make_unique 201304L <memory>
__cpp_lib_map_try_emplace 201411L <map>
__cpp_lib_math_constants 201907L <numbers>
__cpp_lib_math_special_functions 201603L <cmath>
__cpp_lib_memory_resource 201603L <memory_resource>
__cpp_lib_move_only_function 202110L <functional>
__cpp_lib_node_extract 201606L <map> <set> <unordered_map>
<unordered_set>
__cpp_lib_nonmember_container_access 201411L <array> <deque> <forward_list>
<iterator> <list> <map>
<regex> <set> <string>
<unordered_map> <unordered_set> <vector>
__cpp_lib_not_fn 201603L <functional>
__cpp_lib_null_iterators 201304L <iterator>
__cpp_lib_optional 202110L <optional>
201606L // C++17
__cpp_lib_out_ptr 202106L <memory>
__cpp_lib_parallel_algorithm 201603L <algorithm> <numeric>
__cpp_lib_polymorphic_allocator 201902L <memory_resource>
__cpp_lib_quoted_string_io 201304L <iomanip>
__cpp_lib_ranges 201811L <algorithm> <functional> <iterator>
<memory> <ranges>
__cpp_lib_ranges_chunk 202202L <ranges>
__cpp_lib_ranges_chunk_by 202202L <ranges>
__cpp_lib_ranges_iota 202202L <numeric>
__cpp_lib_ranges_join_with 202202L <ranges>
__cpp_lib_ranges_slide 202202L <ranges>
__cpp_lib_ranges_starts_ends_with 202106L <algorithm>
__cpp_lib_ranges_to_container 202202L <deque> <forward_list> <list>
<map> <priority_queue> <queue>
<set> <stack> <string>
<unordered_map> <unordered_set> <vector>
__cpp_lib_ranges_zip 202110L <ranges> <tuple> <utility>
__cpp_lib_raw_memory_algorithms 201606L <memory>
__cpp_lib_reference_from_temporary 202202L <type_traits>
__cpp_lib_remove_cvref 201711L <type_traits>
__cpp_lib_result_of_sfinae 201210L <functional> <type_traits>
__cpp_lib_robust_nonmodifying_seq_ops 201304L <algorithm>
__cpp_lib_sample 201603L <algorithm>
__cpp_lib_scoped_lock 201703L <mutex>
__cpp_lib_semaphore 201907L <semaphore>
__cpp_lib_shared_mutex 201505L <shared_mutex>
__cpp_lib_shared_ptr_arrays 201707L <memory>
201611L // C++17
__cpp_lib_shared_ptr_weak_type 201606L <memory>
__cpp_lib_shared_timed_mutex 201402L <shared_mutex>
__cpp_lib_shift 201806L <algorithm>
__cpp_lib_smart_ptr_for_overwrite 202002L <memory>
__cpp_lib_source_location 201907L <source_location>
__cpp_lib_span 202002L <span>
__cpp_lib_spanstream 202106L <spanstream>
__cpp_lib_ssize 201902L <iterator>
__cpp_lib_stacktrace 202011L <stacktrace>
__cpp_lib_starts_ends_with 201711L <string> <string_view>
__cpp_lib_stdatomic_h 202011L <stdatomic.h>
__cpp_lib_string_contains 202011L <string> <string_view>
__cpp_lib_string_resize_and_overwrite 202110L <string>
__cpp_lib_string_udls 201304L <string>
__cpp_lib_string_view 201803L <string> <string_view>
201606L // C++17
__cpp_lib_syncbuf 201803L <syncstream>
__cpp_lib_three_way_comparison 201907L <compare>
__cpp_lib_to_address 201711L <memory>
__cpp_lib_to_array 201907L <array>
__cpp_lib_to_chars 201611L <charconv>
__cpp_lib_to_underlying 202102L <utility>
__cpp_lib_transformation_trait_aliases 201304L <type_traits>
__cpp_lib_transparent_operators 201510L <functional> <memory>
201210L // C++14
__cpp_lib_tuple_element_t 201402L <tuple>
__cpp_lib_tuples_by_type 201304L <tuple> <utility>
__cpp_lib_type_identity 201806L <type_traits>
__cpp_lib_type_trait_variable_templates 201510L <type_traits>
__cpp_lib_uncaught_exceptions 201411L <exception>
__cpp_lib_unordered_map_try_emplace 201411L <unordered_map>
__cpp_lib_unreachable 202202L <utility>
__cpp_lib_unwrap_ref 201811L <functional>
__cpp_lib_variant 202102L <variant>
__cpp_lib_void_t 201411L <type_traits>
*/
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
// clang-format off
#if _LIBCPP_STD_VER > 11
# define __cpp_lib_chrono_udls 201304L
# define __cpp_lib_complex_udls 201309L
# define __cpp_lib_exchange_function 201304L
# define __cpp_lib_generic_associative_lookup 201304L
# define __cpp_lib_integer_sequence 201304L
# define __cpp_lib_integral_constant_callable 201304L
# define __cpp_lib_is_final 201402L
# define __cpp_lib_is_null_pointer 201309L
# define __cpp_lib_make_reverse_iterator 201402L
# define __cpp_lib_make_unique 201304L
# define __cpp_lib_null_iterators 201304L
# define __cpp_lib_quoted_string_io 201304L
# define __cpp_lib_result_of_sfinae 201210L
# define __cpp_lib_robust_nonmodifying_seq_ops 201304L
# if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_timed_mutex)
# define __cpp_lib_shared_timed_mutex 201402L
# endif
# define __cpp_lib_string_udls 201304L
# define __cpp_lib_transformation_trait_aliases 201304L
# define __cpp_lib_transparent_operators 201210L
# define __cpp_lib_tuple_element_t 201402L
# define __cpp_lib_tuples_by_type 201304L
#endif
#if _LIBCPP_STD_VER > 14
# define __cpp_lib_addressof_constexpr 201603L
# define __cpp_lib_allocator_traits_is_always_equal 201411L
# define __cpp_lib_any 201606L
# define __cpp_lib_apply 201603L
# define __cpp_lib_array_constexpr 201603L
# define __cpp_lib_as_const 201510L
# define __cpp_lib_atomic_is_always_lock_free 201603L
# define __cpp_lib_bool_constant 201505L
# define __cpp_lib_boyer_moore_searcher 201603L
# define __cpp_lib_byte 201603L
# define __cpp_lib_chrono 201611L
# define __cpp_lib_clamp 201603L
# define __cpp_lib_enable_shared_from_this 201603L
// # define __cpp_lib_execution 201603L
# if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem)
# define __cpp_lib_filesystem 201703L
# endif
# define __cpp_lib_gcd_lcm 201606L
# if defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE)
# define __cpp_lib_hardware_interference_size 201703L
# endif
# define __cpp_lib_has_unique_object_representations 201606L
# define __cpp_lib_hypot 201603L
# define __cpp_lib_incomplete_container_elements 201505L
# define __cpp_lib_invoke 201411L
# define __cpp_lib_is_aggregate 201703L
# define __cpp_lib_is_invocable 201703L
# define __cpp_lib_is_swappable 201603L
# define __cpp_lib_launder 201606L
# define __cpp_lib_logical_traits 201510L
# define __cpp_lib_make_from_tuple 201606L
# define __cpp_lib_map_try_emplace 201411L
// # define __cpp_lib_math_special_functions 201603L
// # define __cpp_lib_memory_resource 201603L
# define __cpp_lib_node_extract 201606L
# define __cpp_lib_nonmember_container_access 201411L
# define __cpp_lib_not_fn 201603L
# define __cpp_lib_optional 201606L
// # define __cpp_lib_parallel_algorithm 201603L
# define __cpp_lib_raw_memory_algorithms 201606L
# define __cpp_lib_sample 201603L
# define __cpp_lib_scoped_lock 201703L
# if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_shared_mutex)
# define __cpp_lib_shared_mutex 201505L
# endif
# define __cpp_lib_shared_ptr_arrays 201611L
# define __cpp_lib_shared_ptr_weak_type 201606L
# define __cpp_lib_string_view 201606L
// # define __cpp_lib_to_chars 201611L
# undef __cpp_lib_transparent_operators
# define __cpp_lib_transparent_operators 201510L
# define __cpp_lib_type_trait_variable_templates 201510L
# define __cpp_lib_uncaught_exceptions 201411L
# define __cpp_lib_unordered_map_try_emplace 201411L
# define __cpp_lib_variant 202102L
# define __cpp_lib_void_t 201411L
#endif
#if _LIBCPP_STD_VER > 17
# undef __cpp_lib_array_constexpr
# define __cpp_lib_array_constexpr 201811L
# define __cpp_lib_assume_aligned 201811L
# define __cpp_lib_atomic_flag_test 201907L
// # define __cpp_lib_atomic_float 201711L
# define __cpp_lib_atomic_lock_free_type_aliases 201907L
// # define __cpp_lib_atomic_ref 201806L
// # define __cpp_lib_atomic_shared_ptr 201711L
# define __cpp_lib_atomic_value_initialization 201911L
# if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_atomic_wait)
# define __cpp_lib_atomic_wait 201907L
# endif
# if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_barrier)
# define __cpp_lib_barrier 201907L
# endif
# define __cpp_lib_bind_front 201907L
# define __cpp_lib_bit_cast 201806L
// # define __cpp_lib_bitops 201907L
# define __cpp_lib_bounded_array_traits 201902L
# if !defined(_LIBCPP_HAS_NO_CHAR8_T)
# define __cpp_lib_char8_t 201907L
# endif
# define __cpp_lib_concepts 202002L
# define __cpp_lib_constexpr_algorithms 201806L
// # define __cpp_lib_constexpr_complex 201711L
# define __cpp_lib_constexpr_dynamic_alloc 201907L
# define __cpp_lib_constexpr_functional 201907L
# define __cpp_lib_constexpr_iterator 201811L
# define __cpp_lib_constexpr_memory 201811L
# define __cpp_lib_constexpr_numeric 201911L
# define __cpp_lib_constexpr_string 201907L
# define __cpp_lib_constexpr_string_view 201811L
# define __cpp_lib_constexpr_tuple 201811L
# define __cpp_lib_constexpr_utility 201811L
// # define __cpp_lib_constexpr_vector 201907L
# define __cpp_lib_coroutine 201902L
# if _LIBCPP_STD_VER > 17 && defined(__cpp_impl_destroying_delete) && __cpp_impl_destroying_delete >= 201806L
# define __cpp_lib_destroying_delete 201806L
# endif
# define __cpp_lib_endian 201907L
# define __cpp_lib_erase_if 202002L
# undef __cpp_lib_execution
// # define __cpp_lib_execution 201902L
# if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
-# define __cpp_lib_format 202106L
+// # define __cpp_lib_format 202106L
# endif
# define __cpp_lib_generic_unordered_lookup 201811L
# define __cpp_lib_int_pow2 202002L
# define __cpp_lib_integer_comparison_functions 202002L
# define __cpp_lib_interpolate 201902L
# define __cpp_lib_is_constant_evaluated 201811L
// # define __cpp_lib_is_layout_compatible 201907L
# define __cpp_lib_is_nothrow_convertible 201806L
// # define __cpp_lib_is_pointer_interconvertible 201907L
# if !defined(_LIBCPP_HAS_NO_THREADS)
// # define __cpp_lib_jthread 201911L
# endif
# if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_latch)
# define __cpp_lib_latch 201907L
# endif
# define __cpp_lib_list_remove_return_type 201806L
# define __cpp_lib_math_constants 201907L
// # define __cpp_lib_polymorphic_allocator 201902L
# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
# define __cpp_lib_ranges 201811L
# endif
# define __cpp_lib_remove_cvref 201711L
# if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_semaphore)
# define __cpp_lib_semaphore 201907L
# endif
# undef __cpp_lib_shared_ptr_arrays
# define __cpp_lib_shared_ptr_arrays 201707L
# define __cpp_lib_shift 201806L
// # define __cpp_lib_smart_ptr_for_overwrite 202002L
// # define __cpp_lib_source_location 201907L
# define __cpp_lib_span 202002L
# define __cpp_lib_ssize 201902L
# define __cpp_lib_starts_ends_with 201711L
# undef __cpp_lib_string_view
# define __cpp_lib_string_view 201803L
// # define __cpp_lib_syncbuf 201803L
// # define __cpp_lib_three_way_comparison 201907L
# define __cpp_lib_to_address 201711L
# define __cpp_lib_to_array 201907L
# define __cpp_lib_type_identity 201806L
# define __cpp_lib_unwrap_ref 201811L
#endif
#if _LIBCPP_STD_VER > 20
# define __cpp_lib_adaptor_iterator_pair_constructor 202106L
# define __cpp_lib_allocate_at_least 202106L
// # define __cpp_lib_associative_heterogeneous_erasure 202110L
// # define __cpp_lib_bind_back 202202L
# define __cpp_lib_byteswap 202110L
// # define __cpp_lib_constexpr_cmath 202202L
// # define __cpp_lib_constexpr_typeinfo 202106L
// # define __cpp_lib_invoke_r 202106L
# define __cpp_lib_is_scoped_enum 202011L
// # define __cpp_lib_move_only_function 202110L
# undef __cpp_lib_optional
# define __cpp_lib_optional 202110L
// # define __cpp_lib_out_ptr 202106L
// # define __cpp_lib_ranges_chunk 202202L
// # define __cpp_lib_ranges_chunk_by 202202L
// # define __cpp_lib_ranges_iota 202202L
// # define __cpp_lib_ranges_join_with 202202L
// # define __cpp_lib_ranges_slide 202202L
// # define __cpp_lib_ranges_starts_ends_with 202106L
// # define __cpp_lib_ranges_to_container 202202L
// # define __cpp_lib_ranges_zip 202110L
// # define __cpp_lib_reference_from_temporary 202202L
// # define __cpp_lib_spanstream 202106L
// # define __cpp_lib_stacktrace 202011L
# define __cpp_lib_stdatomic_h 202011L
# define __cpp_lib_string_contains 202011L
# define __cpp_lib_string_resize_and_overwrite 202110L
# define __cpp_lib_to_underlying 202102L
# define __cpp_lib_unreachable 202202L
#endif
// clang-format on
#endif // _LIBCPP_VERSIONH
diff --git a/contrib/llvm-project/lld/COFF/Symbols.h b/contrib/llvm-project/lld/COFF/Symbols.h
index c8865d128fb8..a4c6f893f10c 100644
--- a/contrib/llvm-project/lld/COFF/Symbols.h
+++ b/contrib/llvm-project/lld/COFF/Symbols.h
@@ -1,506 +1,509 @@
//===- Symbols.h ------------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLD_COFF_SYMBOLS_H
#define LLD_COFF_SYMBOLS_H
#include "Chunks.h"
#include "Config.h"
#include "lld/Common/LLVM.h"
#include "lld/Common/Memory.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFF.h"
#include <atomic>
#include <memory>
#include <vector>
namespace lld {
std::string toString(coff::Symbol &b);
// There are two different ways to convert an Archive::Symbol to a string:
// One for Microsoft name mangling and one for Itanium name mangling.
// Call the functions toCOFFString and toELFString, not just toString.
std::string toCOFFString(const coff::Archive::Symbol &b);
namespace coff {
using llvm::object::Archive;
using llvm::object::COFFSymbolRef;
using llvm::object::coff_import_header;
using llvm::object::coff_symbol_generic;
class ArchiveFile;
class InputFile;
class ObjFile;
class SymbolTable;
// The base class for real symbol classes.
class Symbol {
public:
enum Kind {
// The order of these is significant. We start with the regular defined
// symbols as those are the most prevalent and the zero tag is the cheapest
// to set. Among the defined kinds, the lower the kind is preferred over
// the higher kind when testing whether one symbol should take precedence
// over another.
DefinedRegularKind = 0,
DefinedCommonKind,
DefinedLocalImportKind,
DefinedImportThunkKind,
DefinedImportDataKind,
DefinedAbsoluteKind,
DefinedSyntheticKind,
UndefinedKind,
LazyArchiveKind,
LazyObjectKind,
LazyDLLSymbolKind,
LastDefinedCOFFKind = DefinedCommonKind,
LastDefinedKind = DefinedSyntheticKind,
};
Kind kind() const { return static_cast<Kind>(symbolKind); }
// Returns the symbol name.
StringRef getName() {
// COFF symbol names are read lazily for a performance reason.
// Non-external symbol names are never used by the linker except for logging
// or debugging. Their internal references are resolved not by name but by
// symbol index. And because they are not external, no one can refer them by
// name. Object files contain lots of non-external symbols, and creating
// StringRefs for them (which involves lots of strlen() on the string table)
// is a waste of time.
if (nameData == nullptr)
computeName();
return StringRef(nameData, nameSize);
}
void replaceKeepingName(Symbol *other, size_t size);
// Returns the file from which this symbol was created.
InputFile *getFile();
// Indicates that this symbol will be included in the final image. Only valid
// after calling markLive.
bool isLive() const;
bool isLazy() const {
return symbolKind == LazyArchiveKind || symbolKind == LazyObjectKind ||
symbolKind == LazyDLLSymbolKind;
}
private:
void computeName();
protected:
friend SymbolTable;
explicit Symbol(Kind k, StringRef n = "")
: symbolKind(k), isExternal(true), isCOMDAT(false),
writtenToSymtab(false), pendingArchiveLoad(false), isGCRoot(false),
isRuntimePseudoReloc(false), deferUndefined(false), canInline(true),
- nameSize(n.size()), nameData(n.empty() ? nullptr : n.data()) {}
+ nameSize(n.size()), nameData(n.empty() ? nullptr : n.data()) {
+ assert((!n.empty() || k <= LastDefinedCOFFKind) &&
+ "If the name is empty, the Symbol must be a DefinedCOFF.");
+ }
const unsigned symbolKind : 8;
unsigned isExternal : 1;
public:
// This bit is used by the \c DefinedRegular subclass.
unsigned isCOMDAT : 1;
// This bit is used by Writer::createSymbolAndStringTable() to prevent
// symbols from being written to the symbol table more than once.
unsigned writtenToSymtab : 1;
// True if this symbol was referenced by a regular (non-bitcode) object.
unsigned isUsedInRegularObj : 1;
// True if we've seen both a lazy and an undefined symbol with this symbol
// name, which means that we have enqueued an archive member load and should
// not load any more archive members to resolve the same symbol.
unsigned pendingArchiveLoad : 1;
/// True if we've already added this symbol to the list of GC roots.
unsigned isGCRoot : 1;
unsigned isRuntimePseudoReloc : 1;
// True if we want to allow this symbol to be undefined in the early
// undefined check pass in SymbolTable::reportUnresolvable(), as it
// might be fixed up later.
unsigned deferUndefined : 1;
// False if LTO shouldn't inline whatever this symbol points to. If a symbol
// is overwritten after LTO, LTO shouldn't inline the symbol because it
// doesn't know the final contents of the symbol.
unsigned canInline : 1;
protected:
// Symbol name length. Assume symbol lengths fit in a 32-bit integer.
uint32_t nameSize;
const char *nameData;
};
// The base class for any defined symbols, including absolute symbols,
// etc.
class Defined : public Symbol {
public:
Defined(Kind k, StringRef n) : Symbol(k, n) {}
static bool classof(const Symbol *s) { return s->kind() <= LastDefinedKind; }
// Returns the RVA (relative virtual address) of this symbol. The
// writer sets and uses RVAs.
uint64_t getRVA();
// Returns the chunk containing this symbol. Absolute symbols and __ImageBase
// do not have chunks, so this may return null.
Chunk *getChunk();
};
// Symbols defined via a COFF object file or bitcode file. For COFF files, this
// stores a coff_symbol_generic*, and names of internal symbols are lazily
// loaded through that. For bitcode files, Sym is nullptr and the name is stored
// as a decomposed StringRef.
class DefinedCOFF : public Defined {
friend Symbol;
public:
DefinedCOFF(Kind k, InputFile *f, StringRef n, const coff_symbol_generic *s)
: Defined(k, n), file(f), sym(s) {}
static bool classof(const Symbol *s) {
return s->kind() <= LastDefinedCOFFKind;
}
InputFile *getFile() { return file; }
COFFSymbolRef getCOFFSymbol();
InputFile *file;
protected:
const coff_symbol_generic *sym;
};
// Regular defined symbols read from object file symbol tables.
class DefinedRegular : public DefinedCOFF {
public:
DefinedRegular(InputFile *f, StringRef n, bool isCOMDAT,
bool isExternal = false,
const coff_symbol_generic *s = nullptr,
SectionChunk *c = nullptr)
: DefinedCOFF(DefinedRegularKind, f, n, s), data(c ? &c->repl : nullptr) {
this->isExternal = isExternal;
this->isCOMDAT = isCOMDAT;
}
static bool classof(const Symbol *s) {
return s->kind() == DefinedRegularKind;
}
uint64_t getRVA() const { return (*data)->getRVA() + sym->Value; }
SectionChunk *getChunk() const { return *data; }
uint32_t getValue() const { return sym->Value; }
SectionChunk **data;
};
class DefinedCommon : public DefinedCOFF {
public:
DefinedCommon(InputFile *f, StringRef n, uint64_t size,
const coff_symbol_generic *s = nullptr,
CommonChunk *c = nullptr)
: DefinedCOFF(DefinedCommonKind, f, n, s), data(c), size(size) {
this->isExternal = true;
}
static bool classof(const Symbol *s) {
return s->kind() == DefinedCommonKind;
}
uint64_t getRVA() { return data->getRVA(); }
CommonChunk *getChunk() { return data; }
private:
friend SymbolTable;
uint64_t getSize() const { return size; }
CommonChunk *data;
uint64_t size;
};
// Absolute symbols.
class DefinedAbsolute : public Defined {
public:
DefinedAbsolute(StringRef n, COFFSymbolRef s)
: Defined(DefinedAbsoluteKind, n), va(s.getValue()) {
isExternal = s.isExternal();
}
DefinedAbsolute(StringRef n, uint64_t v)
: Defined(DefinedAbsoluteKind, n), va(v) {}
static bool classof(const Symbol *s) {
return s->kind() == DefinedAbsoluteKind;
}
uint64_t getRVA() { return va - config->imageBase; }
void setVA(uint64_t v) { va = v; }
uint64_t getVA() const { return va; }
// Section index relocations against absolute symbols resolve to
// this 16 bit number, and it is the largest valid section index
// plus one. This variable keeps it.
static uint16_t numOutputSections;
private:
uint64_t va;
};
// This symbol is used for linker-synthesized symbols like __ImageBase and
// __safe_se_handler_table.
class DefinedSynthetic : public Defined {
public:
explicit DefinedSynthetic(StringRef name, Chunk *c)
: Defined(DefinedSyntheticKind, name), c(c) {}
static bool classof(const Symbol *s) {
return s->kind() == DefinedSyntheticKind;
}
// A null chunk indicates that this is __ImageBase. Otherwise, this is some
// other synthesized chunk, like SEHTableChunk.
uint32_t getRVA() { return c ? c->getRVA() : 0; }
Chunk *getChunk() { return c; }
private:
Chunk *c;
};
// This class represents a symbol defined in an archive file. It is
// created from an archive file header, and it knows how to load an
// object file from an archive to replace itself with a defined
// symbol. If the resolver finds both Undefined and LazyArchive for
// the same name, it will ask the LazyArchive to load a file.
class LazyArchive : public Symbol {
public:
LazyArchive(ArchiveFile *f, const Archive::Symbol s)
: Symbol(LazyArchiveKind, s.getName()), file(f), sym(s) {}
static bool classof(const Symbol *s) { return s->kind() == LazyArchiveKind; }
MemoryBufferRef getMemberBuffer();
ArchiveFile *file;
const Archive::Symbol sym;
};
class LazyObject : public Symbol {
public:
LazyObject(InputFile *f, StringRef n) : Symbol(LazyObjectKind, n), file(f) {}
static bool classof(const Symbol *s) { return s->kind() == LazyObjectKind; }
InputFile *file;
};
// MinGW only.
class LazyDLLSymbol : public Symbol {
public:
LazyDLLSymbol(DLLFile *f, DLLFile::Symbol *s, StringRef n)
: Symbol(LazyDLLSymbolKind, n), file(f), sym(s) {}
static bool classof(const Symbol *s) {
return s->kind() == LazyDLLSymbolKind;
}
DLLFile *file;
DLLFile::Symbol *sym;
};
// Undefined symbols.
class Undefined : public Symbol {
public:
explicit Undefined(StringRef n) : Symbol(UndefinedKind, n) {}
static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; }
// An undefined symbol can have a fallback symbol which gives an
// undefined symbol a second chance if it would remain undefined.
// If it remains undefined, it'll be replaced with whatever the
// Alias pointer points to.
Symbol *weakAlias = nullptr;
// If this symbol is external weak, try to resolve it to a defined
// symbol by searching the chain of fallback symbols. Returns the symbol if
// successful, otherwise returns null.
Defined *getWeakAlias();
};
// Windows-specific classes.
// This class represents a symbol imported from a DLL. This has two
// names for internal use and external use. The former is used for
// name resolution, and the latter is used for the import descriptor
// table in an output. The former has "__imp_" prefix.
class DefinedImportData : public Defined {
public:
DefinedImportData(StringRef n, ImportFile *f)
: Defined(DefinedImportDataKind, n), file(f) {
}
static bool classof(const Symbol *s) {
return s->kind() == DefinedImportDataKind;
}
uint64_t getRVA() { return file->location->getRVA(); }
Chunk *getChunk() { return file->location; }
void setLocation(Chunk *addressTable) { file->location = addressTable; }
StringRef getDLLName() { return file->dllName; }
StringRef getExternalName() { return file->externalName; }
uint16_t getOrdinal() { return file->hdr->OrdinalHint; }
ImportFile *file;
// This is a pointer to the synthetic symbol associated with the load thunk
// for this symbol that will be called if the DLL is delay-loaded. This is
// needed for Control Flow Guard because if this DefinedImportData symbol is a
// valid call target, the corresponding load thunk must also be marked as a
// valid call target.
DefinedSynthetic *loadThunkSym = nullptr;
};
// This class represents a symbol for a jump table entry which jumps
// to a function in a DLL. Linker are supposed to create such symbols
// without "__imp_" prefix for all function symbols exported from
// DLLs, so that you can call DLL functions as regular functions with
// a regular name. A function pointer is given as a DefinedImportData.
class DefinedImportThunk : public Defined {
public:
DefinedImportThunk(StringRef name, DefinedImportData *s, uint16_t machine);
static bool classof(const Symbol *s) {
return s->kind() == DefinedImportThunkKind;
}
uint64_t getRVA() { return data->getRVA(); }
Chunk *getChunk() { return data; }
DefinedImportData *wrappedSym;
private:
Chunk *data;
};
// If you have a symbol "foo" in your object file, a symbol name
// "__imp_foo" becomes automatically available as a pointer to "foo".
// This class is for such automatically-created symbols.
// Yes, this is an odd feature. We didn't intend to implement that.
// This is here just for compatibility with MSVC.
class DefinedLocalImport : public Defined {
public:
DefinedLocalImport(StringRef n, Defined *s)
: Defined(DefinedLocalImportKind, n), data(make<LocalImportChunk>(s)) {}
static bool classof(const Symbol *s) {
return s->kind() == DefinedLocalImportKind;
}
uint64_t getRVA() { return data->getRVA(); }
Chunk *getChunk() { return data; }
private:
LocalImportChunk *data;
};
inline uint64_t Defined::getRVA() {
switch (kind()) {
case DefinedAbsoluteKind:
return cast<DefinedAbsolute>(this)->getRVA();
case DefinedSyntheticKind:
return cast<DefinedSynthetic>(this)->getRVA();
case DefinedImportDataKind:
return cast<DefinedImportData>(this)->getRVA();
case DefinedImportThunkKind:
return cast<DefinedImportThunk>(this)->getRVA();
case DefinedLocalImportKind:
return cast<DefinedLocalImport>(this)->getRVA();
case DefinedCommonKind:
return cast<DefinedCommon>(this)->getRVA();
case DefinedRegularKind:
return cast<DefinedRegular>(this)->getRVA();
case LazyArchiveKind:
case LazyObjectKind:
case LazyDLLSymbolKind:
case UndefinedKind:
llvm_unreachable("Cannot get the address for an undefined symbol.");
}
llvm_unreachable("unknown symbol kind");
}
inline Chunk *Defined::getChunk() {
switch (kind()) {
case DefinedRegularKind:
return cast<DefinedRegular>(this)->getChunk();
case DefinedAbsoluteKind:
return nullptr;
case DefinedSyntheticKind:
return cast<DefinedSynthetic>(this)->getChunk();
case DefinedImportDataKind:
return cast<DefinedImportData>(this)->getChunk();
case DefinedImportThunkKind:
return cast<DefinedImportThunk>(this)->getChunk();
case DefinedLocalImportKind:
return cast<DefinedLocalImport>(this)->getChunk();
case DefinedCommonKind:
return cast<DefinedCommon>(this)->getChunk();
case LazyArchiveKind:
case LazyObjectKind:
case LazyDLLSymbolKind:
case UndefinedKind:
llvm_unreachable("Cannot get the chunk of an undefined symbol.");
}
llvm_unreachable("unknown symbol kind");
}
// A buffer class that is large enough to hold any Symbol-derived
// object. We allocate memory using this class and instantiate a symbol
// using the placement new.
union SymbolUnion {
alignas(DefinedRegular) char a[sizeof(DefinedRegular)];
alignas(DefinedCommon) char b[sizeof(DefinedCommon)];
alignas(DefinedAbsolute) char c[sizeof(DefinedAbsolute)];
alignas(DefinedSynthetic) char d[sizeof(DefinedSynthetic)];
alignas(LazyArchive) char e[sizeof(LazyArchive)];
alignas(Undefined) char f[sizeof(Undefined)];
alignas(DefinedImportData) char g[sizeof(DefinedImportData)];
alignas(DefinedImportThunk) char h[sizeof(DefinedImportThunk)];
alignas(DefinedLocalImport) char i[sizeof(DefinedLocalImport)];
alignas(LazyObject) char j[sizeof(LazyObject)];
alignas(LazyDLLSymbol) char k[sizeof(LazyDLLSymbol)];
};
template <typename T, typename... ArgT>
void replaceSymbol(Symbol *s, ArgT &&... arg) {
static_assert(std::is_trivially_destructible<T>(),
"Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small");
static_assert(alignof(T) <= alignof(SymbolUnion),
"SymbolUnion not aligned enough");
assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
"Not a Symbol");
bool canInline = s->canInline;
new (s) T(std::forward<ArgT>(arg)...);
s->canInline = canInline;
}
} // namespace coff
} // namespace lld
#endif
diff --git a/contrib/llvm-project/lld/COFF/Writer.cpp b/contrib/llvm-project/lld/COFF/Writer.cpp
index df60c9032b2d..f39697d5d381 100644
--- a/contrib/llvm-project/lld/COFF/Writer.cpp
+++ b/contrib/llvm-project/lld/COFF/Writer.cpp
@@ -1,2104 +1,2104 @@
//===- Writer.cpp ---------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Writer.h"
#include "COFFLinkerContext.h"
#include "CallGraphSort.h"
#include "Config.h"
#include "DLL.h"
#include "InputFiles.h"
#include "LLDMapFile.h"
#include "MapFile.h"
#include "PDB.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/Timer.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Parallel.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/RandomNumberGenerator.h"
#include "llvm/Support/xxhash.h"
#include <algorithm>
#include <cstdio>
#include <map>
#include <memory>
#include <utility>
using namespace llvm;
using namespace llvm::COFF;
using namespace llvm::object;
using namespace llvm::support;
using namespace llvm::support::endian;
using namespace lld;
using namespace lld::coff;
/* To re-generate DOSProgram:
$ cat > /tmp/DOSProgram.asm
org 0
; Copy cs to ds.
push cs
pop ds
; Point ds:dx at the $-terminated string.
mov dx, str
; Int 21/AH=09h: Write string to standard output.
mov ah, 0x9
int 0x21
; Int 21/AH=4Ch: Exit with return code (in AL).
mov ax, 0x4C01
int 0x21
str:
db 'This program cannot be run in DOS mode.$'
align 8, db 0
$ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin
$ xxd -i /tmp/DOSProgram.bin
*/
static unsigned char dosProgram[] = {
0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c,
0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65,
0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00
};
static_assert(sizeof(dosProgram) % 8 == 0,
"DOSProgram size must be multiple of 8");
static const int dosStubSize = sizeof(dos_header) + sizeof(dosProgram);
static_assert(dosStubSize % 8 == 0, "DOSStub size must be multiple of 8");
static const int numberOfDataDirectory = 16;
namespace {
class DebugDirectoryChunk : public NonSectionChunk {
public:
DebugDirectoryChunk(COFFLinkerContext &c,
const std::vector<std::pair<COFF::DebugType, Chunk *>> &r,
bool writeRepro)
: records(r), writeRepro(writeRepro), ctx(c) {}
size_t getSize() const override {
return (records.size() + int(writeRepro)) * sizeof(debug_directory);
}
void writeTo(uint8_t *b) const override {
auto *d = reinterpret_cast<debug_directory *>(b);
for (const std::pair<COFF::DebugType, Chunk *>& record : records) {
Chunk *c = record.second;
OutputSection *os = ctx.getOutputSection(c);
uint64_t offs = os->getFileOff() + (c->getRVA() - os->getRVA());
fillEntry(d, record.first, c->getSize(), c->getRVA(), offs);
++d;
}
if (writeRepro) {
// FIXME: The COFF spec allows either a 0-sized entry to just say
// "the timestamp field is really a hash", or a 4-byte size field
// followed by that many bytes containing a longer hash (with the
// lowest 4 bytes usually being the timestamp in little-endian order).
// Consider storing the full 8 bytes computed by xxHash64 here.
fillEntry(d, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0);
}
}
void setTimeDateStamp(uint32_t timeDateStamp) {
for (support::ulittle32_t *tds : timeDateStamps)
*tds = timeDateStamp;
}
private:
void fillEntry(debug_directory *d, COFF::DebugType debugType, size_t size,
uint64_t rva, uint64_t offs) const {
d->Characteristics = 0;
d->TimeDateStamp = 0;
d->MajorVersion = 0;
d->MinorVersion = 0;
d->Type = debugType;
d->SizeOfData = size;
d->AddressOfRawData = rva;
d->PointerToRawData = offs;
timeDateStamps.push_back(&d->TimeDateStamp);
}
mutable std::vector<support::ulittle32_t *> timeDateStamps;
const std::vector<std::pair<COFF::DebugType, Chunk *>> &records;
bool writeRepro;
COFFLinkerContext &ctx;
};
class CVDebugRecordChunk : public NonSectionChunk {
public:
size_t getSize() const override {
return sizeof(codeview::DebugInfo) + config->pdbAltPath.size() + 1;
}
void writeTo(uint8_t *b) const override {
// Save off the DebugInfo entry to backfill the file signature (build id)
// in Writer::writeBuildId
buildId = reinterpret_cast<codeview::DebugInfo *>(b);
// variable sized field (PDB Path)
char *p = reinterpret_cast<char *>(b + sizeof(*buildId));
if (!config->pdbAltPath.empty())
memcpy(p, config->pdbAltPath.data(), config->pdbAltPath.size());
p[config->pdbAltPath.size()] = '\0';
}
mutable codeview::DebugInfo *buildId = nullptr;
};
class ExtendedDllCharacteristicsChunk : public NonSectionChunk {
public:
ExtendedDllCharacteristicsChunk(uint32_t c) : characteristics(c) {}
size_t getSize() const override { return 4; }
void writeTo(uint8_t *buf) const override { write32le(buf, characteristics); }
uint32_t characteristics = 0;
};
// PartialSection represents a group of chunks that contribute to an
// OutputSection. Collating a collection of PartialSections of same name and
// characteristics constitutes the OutputSection.
class PartialSectionKey {
public:
StringRef name;
unsigned characteristics;
bool operator<(const PartialSectionKey &other) const {
int c = name.compare(other.name);
if (c == 1)
return false;
if (c == 0)
return characteristics < other.characteristics;
return true;
}
};
// The writer writes a SymbolTable result to a file.
class Writer {
public:
Writer(COFFLinkerContext &c) : buffer(errorHandler().outputBuffer), ctx(c) {}
void run();
private:
void createSections();
void createMiscChunks();
void createImportTables();
void appendImportThunks();
void locateImportTables();
void createExportTable();
void mergeSections();
void removeUnusedSections();
void assignAddresses();
void finalizeAddresses();
void removeEmptySections();
void assignOutputSectionIndices();
void createSymbolAndStringTable();
void openFile(StringRef outputPath);
template <typename PEHeaderTy> void writeHeader();
void createSEHTable();
void createRuntimePseudoRelocs();
void insertCtorDtorSymbols();
void createGuardCFTables();
void markSymbolsForRVATable(ObjFile *file,
ArrayRef<SectionChunk *> symIdxChunks,
SymbolRVASet &tableSymbols);
void getSymbolsFromSections(ObjFile *file,
ArrayRef<SectionChunk *> symIdxChunks,
std::vector<Symbol *> &symbols);
void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
StringRef countSym, bool hasFlag=false);
void setSectionPermissions();
void writeSections();
void writeBuildId();
void sortSections();
void sortExceptionTable();
void sortCRTSectionChunks(std::vector<Chunk *> &chunks);
void addSyntheticIdata();
void fixPartialSectionChars(StringRef name, uint32_t chars);
bool fixGnuImportChunks();
void fixTlsAlignment();
PartialSection *createPartialSection(StringRef name, uint32_t outChars);
PartialSection *findPartialSection(StringRef name, uint32_t outChars);
llvm::Optional<coff_symbol16> createSymbol(Defined *d);
size_t addEntryToStringTable(StringRef str);
OutputSection *findSection(StringRef name);
void addBaserels();
void addBaserelBlocks(std::vector<Baserel> &v);
uint32_t getSizeOfInitializedData();
std::unique_ptr<FileOutputBuffer> &buffer;
std::map<PartialSectionKey, PartialSection *> partialSections;
std::vector<char> strtab;
std::vector<llvm::object::coff_symbol16> outputSymtab;
IdataContents idata;
Chunk *importTableStart = nullptr;
uint64_t importTableSize = 0;
Chunk *edataStart = nullptr;
Chunk *edataEnd = nullptr;
Chunk *iatStart = nullptr;
uint64_t iatSize = 0;
DelayLoadContents delayIdata;
EdataContents edata;
bool setNoSEHCharacteristic = false;
uint32_t tlsAlignment = 0;
DebugDirectoryChunk *debugDirectory = nullptr;
std::vector<std::pair<COFF::DebugType, Chunk *>> debugRecords;
CVDebugRecordChunk *buildId = nullptr;
ArrayRef<uint8_t> sectionTable;
uint64_t fileSize;
uint32_t pointerToSymbolTable = 0;
uint64_t sizeOfImage;
uint64_t sizeOfHeaders;
OutputSection *textSec;
OutputSection *rdataSec;
OutputSection *buildidSec;
OutputSection *dataSec;
OutputSection *pdataSec;
OutputSection *idataSec;
OutputSection *edataSec;
OutputSection *didatSec;
OutputSection *rsrcSec;
OutputSection *relocSec;
OutputSection *ctorsSec;
OutputSection *dtorsSec;
// The first and last .pdata sections in the output file.
//
// We need to keep track of the location of .pdata in whichever section it
// gets merged into so that we can sort its contents and emit a correct data
// directory entry for the exception table. This is also the case for some
// other sections (such as .edata) but because the contents of those sections
// are entirely linker-generated we can keep track of their locations using
// the chunks that the linker creates. All .pdata chunks come from input
// files, so we need to keep track of them separately.
Chunk *firstPdata = nullptr;
Chunk *lastPdata;
COFFLinkerContext &ctx;
};
} // anonymous namespace
void lld::coff::writeResult(COFFLinkerContext &ctx) { Writer(ctx).run(); }
void OutputSection::addChunk(Chunk *c) {
chunks.push_back(c);
}
void OutputSection::insertChunkAtStart(Chunk *c) {
chunks.insert(chunks.begin(), c);
}
void OutputSection::setPermissions(uint32_t c) {
header.Characteristics &= ~permMask;
header.Characteristics |= c;
}
void OutputSection::merge(OutputSection *other) {
chunks.insert(chunks.end(), other->chunks.begin(), other->chunks.end());
other->chunks.clear();
contribSections.insert(contribSections.end(), other->contribSections.begin(),
other->contribSections.end());
other->contribSections.clear();
}
// Write the section header to a given buffer.
void OutputSection::writeHeaderTo(uint8_t *buf) {
auto *hdr = reinterpret_cast<coff_section *>(buf);
*hdr = header;
if (stringTableOff) {
// If name is too long, write offset into the string table as a name.
encodeSectionName(hdr->Name, stringTableOff);
} else {
assert(!config->debug || name.size() <= COFF::NameSize ||
(hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0);
strncpy(hdr->Name, name.data(),
std::min(name.size(), (size_t)COFF::NameSize));
}
}
void OutputSection::addContributingPartialSection(PartialSection *sec) {
contribSections.push_back(sec);
}
// Check whether the target address S is in range from a relocation
// of type relType at address P.
static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) {
if (config->machine == ARMNT) {
int64_t diff = AbsoluteDifference(s, p + 4) + margin;
switch (relType) {
case IMAGE_REL_ARM_BRANCH20T:
return isInt<21>(diff);
case IMAGE_REL_ARM_BRANCH24T:
case IMAGE_REL_ARM_BLX23T:
return isInt<25>(diff);
default:
return true;
}
} else if (config->machine == ARM64) {
int64_t diff = AbsoluteDifference(s, p) + margin;
switch (relType) {
case IMAGE_REL_ARM64_BRANCH26:
return isInt<28>(diff);
case IMAGE_REL_ARM64_BRANCH19:
return isInt<21>(diff);
case IMAGE_REL_ARM64_BRANCH14:
return isInt<16>(diff);
default:
return true;
}
} else {
llvm_unreachable("Unexpected architecture");
}
}
// Return the last thunk for the given target if it is in range,
// or create a new one.
static std::pair<Defined *, bool>
getThunk(DenseMap<uint64_t, Defined *> &lastThunks, Defined *target, uint64_t p,
uint16_t type, int margin) {
Defined *&lastThunk = lastThunks[target->getRVA()];
if (lastThunk && isInRange(type, lastThunk->getRVA(), p, margin))
return {lastThunk, false};
Chunk *c;
switch (config->machine) {
case ARMNT:
c = make<RangeExtensionThunkARM>(target);
break;
case ARM64:
c = make<RangeExtensionThunkARM64>(target);
break;
default:
llvm_unreachable("Unexpected architecture");
}
- Defined *d = make<DefinedSynthetic>("", c);
+ Defined *d = make<DefinedSynthetic>("range_extension_thunk", c);
lastThunk = d;
return {d, true};
}
// This checks all relocations, and for any relocation which isn't in range
// it adds a thunk after the section chunk that contains the relocation.
// If the latest thunk for the specific target is in range, that is used
// instead of creating a new thunk. All range checks are done with the
// specified margin, to make sure that relocations that originally are in
// range, but only barely, also get thunks - in case other added thunks makes
// the target go out of range.
//
// After adding thunks, we verify that all relocations are in range (with
// no extra margin requirements). If this failed, we restart (throwing away
// the previously created thunks) and retry with a wider margin.
static bool createThunks(OutputSection *os, int margin) {
bool addressesChanged = false;
DenseMap<uint64_t, Defined *> lastThunks;
DenseMap<std::pair<ObjFile *, Defined *>, uint32_t> thunkSymtabIndices;
size_t thunksSize = 0;
// Recheck Chunks.size() each iteration, since we can insert more
// elements into it.
for (size_t i = 0; i != os->chunks.size(); ++i) {
SectionChunk *sc = dyn_cast_or_null<SectionChunk>(os->chunks[i]);
if (!sc)
continue;
size_t thunkInsertionSpot = i + 1;
// Try to get a good enough estimate of where new thunks will be placed.
// Offset this by the size of the new thunks added so far, to make the
// estimate slightly better.
size_t thunkInsertionRVA = sc->getRVA() + sc->getSize() + thunksSize;
ObjFile *file = sc->file;
std::vector<std::pair<uint32_t, uint32_t>> relocReplacements;
ArrayRef<coff_relocation> originalRelocs =
file->getCOFFObj()->getRelocations(sc->header);
for (size_t j = 0, e = originalRelocs.size(); j < e; ++j) {
const coff_relocation &rel = originalRelocs[j];
Symbol *relocTarget = file->getSymbol(rel.SymbolTableIndex);
// The estimate of the source address P should be pretty accurate,
// but we don't know whether the target Symbol address should be
// offset by thunksSize or not (or by some of thunksSize but not all of
// it), giving us some uncertainty once we have added one thunk.
uint64_t p = sc->getRVA() + rel.VirtualAddress + thunksSize;
Defined *sym = dyn_cast_or_null<Defined>(relocTarget);
if (!sym)
continue;
uint64_t s = sym->getRVA();
if (isInRange(rel.Type, s, p, margin))
continue;
// If the target isn't in range, hook it up to an existing or new
// thunk.
Defined *thunk;
bool wasNew;
std::tie(thunk, wasNew) = getThunk(lastThunks, sym, p, rel.Type, margin);
if (wasNew) {
Chunk *thunkChunk = thunk->getChunk();
thunkChunk->setRVA(
thunkInsertionRVA); // Estimate of where it will be located.
os->chunks.insert(os->chunks.begin() + thunkInsertionSpot, thunkChunk);
thunkInsertionSpot++;
thunksSize += thunkChunk->getSize();
thunkInsertionRVA += thunkChunk->getSize();
addressesChanged = true;
}
// To redirect the relocation, add a symbol to the parent object file's
// symbol table, and replace the relocation symbol table index with the
// new index.
auto insertion = thunkSymtabIndices.insert({{file, thunk}, ~0U});
uint32_t &thunkSymbolIndex = insertion.first->second;
if (insertion.second)
thunkSymbolIndex = file->addRangeThunkSymbol(thunk);
relocReplacements.push_back({j, thunkSymbolIndex});
}
// Get a writable copy of this section's relocations so they can be
// modified. If the relocations point into the object file, allocate new
// memory. Otherwise, this must be previously allocated memory that can be
// modified in place.
ArrayRef<coff_relocation> curRelocs = sc->getRelocs();
MutableArrayRef<coff_relocation> newRelocs;
if (originalRelocs.data() == curRelocs.data()) {
newRelocs = makeMutableArrayRef(
bAlloc().Allocate<coff_relocation>(originalRelocs.size()),
originalRelocs.size());
} else {
newRelocs = makeMutableArrayRef(
const_cast<coff_relocation *>(curRelocs.data()), curRelocs.size());
}
// Copy each relocation, but replace the symbol table indices which need
// thunks.
auto nextReplacement = relocReplacements.begin();
auto endReplacement = relocReplacements.end();
for (size_t i = 0, e = originalRelocs.size(); i != e; ++i) {
newRelocs[i] = originalRelocs[i];
if (nextReplacement != endReplacement && nextReplacement->first == i) {
newRelocs[i].SymbolTableIndex = nextReplacement->second;
++nextReplacement;
}
}
sc->setRelocs(newRelocs);
}
return addressesChanged;
}
// Verify that all relocations are in range, with no extra margin requirements.
static bool verifyRanges(const std::vector<Chunk *> chunks) {
for (Chunk *c : chunks) {
SectionChunk *sc = dyn_cast_or_null<SectionChunk>(c);
if (!sc)
continue;
ArrayRef<coff_relocation> relocs = sc->getRelocs();
for (size_t j = 0, e = relocs.size(); j < e; ++j) {
const coff_relocation &rel = relocs[j];
Symbol *relocTarget = sc->file->getSymbol(rel.SymbolTableIndex);
Defined *sym = dyn_cast_or_null<Defined>(relocTarget);
if (!sym)
continue;
uint64_t p = sc->getRVA() + rel.VirtualAddress;
uint64_t s = sym->getRVA();
if (!isInRange(rel.Type, s, p, 0))
return false;
}
}
return true;
}
// Assign addresses and add thunks if necessary.
void Writer::finalizeAddresses() {
assignAddresses();
if (config->machine != ARMNT && config->machine != ARM64)
return;
size_t origNumChunks = 0;
for (OutputSection *sec : ctx.outputSections) {
sec->origChunks = sec->chunks;
origNumChunks += sec->chunks.size();
}
int pass = 0;
int margin = 1024 * 100;
while (true) {
// First check whether we need thunks at all, or if the previous pass of
// adding them turned out ok.
bool rangesOk = true;
size_t numChunks = 0;
for (OutputSection *sec : ctx.outputSections) {
if (!verifyRanges(sec->chunks)) {
rangesOk = false;
break;
}
numChunks += sec->chunks.size();
}
if (rangesOk) {
if (pass > 0)
log("Added " + Twine(numChunks - origNumChunks) + " thunks with " +
"margin " + Twine(margin) + " in " + Twine(pass) + " passes");
return;
}
if (pass >= 10)
fatal("adding thunks hasn't converged after " + Twine(pass) + " passes");
if (pass > 0) {
// If the previous pass didn't work out, reset everything back to the
// original conditions before retrying with a wider margin. This should
// ideally never happen under real circumstances.
for (OutputSection *sec : ctx.outputSections)
sec->chunks = sec->origChunks;
margin *= 2;
}
// Try adding thunks everywhere where it is needed, with a margin
// to avoid things going out of range due to the added thunks.
bool addressesChanged = false;
for (OutputSection *sec : ctx.outputSections)
addressesChanged |= createThunks(sec, margin);
// If the verification above thought we needed thunks, we should have
// added some.
assert(addressesChanged);
(void)addressesChanged;
// Recalculate the layout for the whole image (and verify the ranges at
// the start of the next round).
assignAddresses();
pass++;
}
}
// The main function of the writer.
void Writer::run() {
ScopedTimer t1(ctx.codeLayoutTimer);
createImportTables();
createSections();
appendImportThunks();
// Import thunks must be added before the Control Flow Guard tables are added.
createMiscChunks();
createExportTable();
mergeSections();
removeUnusedSections();
finalizeAddresses();
removeEmptySections();
assignOutputSectionIndices();
setSectionPermissions();
createSymbolAndStringTable();
if (fileSize > UINT32_MAX)
fatal("image size (" + Twine(fileSize) + ") " +
"exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")");
openFile(config->outputFile);
if (config->is64()) {
writeHeader<pe32plus_header>();
} else {
writeHeader<pe32_header>();
}
writeSections();
sortExceptionTable();
// Fix up the alignment in the TLS Directory's characteristic field,
// if a specific alignment value is needed
if (tlsAlignment)
fixTlsAlignment();
t1.stop();
if (!config->pdbPath.empty() && config->debug) {
assert(buildId);
createPDB(ctx, sectionTable, buildId->buildId);
}
writeBuildId();
writeLLDMapFile(ctx);
writeMapFile(ctx);
if (errorCount())
return;
ScopedTimer t2(ctx.outputCommitTimer);
if (auto e = buffer->commit())
fatal("failed to write the output file: " + toString(std::move(e)));
}
static StringRef getOutputSectionName(StringRef name) {
StringRef s = name.split('$').first;
// Treat a later period as a separator for MinGW, for sections like
// ".ctors.01234".
return s.substr(0, s.find('.', 1));
}
// For /order.
static void sortBySectionOrder(std::vector<Chunk *> &chunks) {
auto getPriority = [](const Chunk *c) {
if (auto *sec = dyn_cast<SectionChunk>(c))
if (sec->sym)
return config->order.lookup(sec->sym->getName());
return 0;
};
llvm::stable_sort(chunks, [=](const Chunk *a, const Chunk *b) {
return getPriority(a) < getPriority(b);
});
}
// Change the characteristics of existing PartialSections that belong to the
// section Name to Chars.
void Writer::fixPartialSectionChars(StringRef name, uint32_t chars) {
for (auto it : partialSections) {
PartialSection *pSec = it.second;
StringRef curName = pSec->name;
if (!curName.consume_front(name) ||
(!curName.empty() && !curName.startswith("$")))
continue;
if (pSec->characteristics == chars)
continue;
PartialSection *destSec = createPartialSection(pSec->name, chars);
destSec->chunks.insert(destSec->chunks.end(), pSec->chunks.begin(),
pSec->chunks.end());
pSec->chunks.clear();
}
}
// Sort concrete section chunks from GNU import libraries.
//
// GNU binutils doesn't use short import files, but instead produces import
// libraries that consist of object files, with section chunks for the .idata$*
// sections. These are linked just as regular static libraries. Each import
// library consists of one header object, one object file for every imported
// symbol, and one trailer object. In order for the .idata tables/lists to
// be formed correctly, the section chunks within each .idata$* section need
// to be grouped by library, and sorted alphabetically within each library
// (which makes sure the header comes first and the trailer last).
bool Writer::fixGnuImportChunks() {
uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
// Make sure all .idata$* section chunks are mapped as RDATA in order to
// be sorted into the same sections as our own synthesized .idata chunks.
fixPartialSectionChars(".idata", rdata);
bool hasIdata = false;
// Sort all .idata$* chunks, grouping chunks from the same library,
// with alphabetical ordering of the object files within a library.
for (auto it : partialSections) {
PartialSection *pSec = it.second;
if (!pSec->name.startswith(".idata"))
continue;
if (!pSec->chunks.empty())
hasIdata = true;
llvm::stable_sort(pSec->chunks, [&](Chunk *s, Chunk *t) {
SectionChunk *sc1 = dyn_cast_or_null<SectionChunk>(s);
SectionChunk *sc2 = dyn_cast_or_null<SectionChunk>(t);
if (!sc1 || !sc2) {
// if SC1, order them ascending. If SC2 or both null,
// S is not less than T.
return sc1 != nullptr;
}
// Make a string with "libraryname/objectfile" for sorting, achieving
// both grouping by library and sorting of objects within a library,
// at once.
std::string key1 =
(sc1->file->parentName + "/" + sc1->file->getName()).str();
std::string key2 =
(sc2->file->parentName + "/" + sc2->file->getName()).str();
return key1 < key2;
});
}
return hasIdata;
}
// Add generated idata chunks, for imported symbols and DLLs, and a
// terminator in .idata$2.
void Writer::addSyntheticIdata() {
uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
idata.create();
// Add the .idata content in the right section groups, to allow
// chunks from other linked in object files to be grouped together.
// See Microsoft PE/COFF spec 5.4 for details.
auto add = [&](StringRef n, std::vector<Chunk *> &v) {
PartialSection *pSec = createPartialSection(n, rdata);
pSec->chunks.insert(pSec->chunks.end(), v.begin(), v.end());
};
// The loader assumes a specific order of data.
// Add each type in the correct order.
add(".idata$2", idata.dirs);
add(".idata$4", idata.lookups);
add(".idata$5", idata.addresses);
if (!idata.hints.empty())
add(".idata$6", idata.hints);
add(".idata$7", idata.dllNames);
}
// Locate the first Chunk and size of the import directory list and the
// IAT.
void Writer::locateImportTables() {
uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
if (PartialSection *importDirs = findPartialSection(".idata$2", rdata)) {
if (!importDirs->chunks.empty())
importTableStart = importDirs->chunks.front();
for (Chunk *c : importDirs->chunks)
importTableSize += c->getSize();
}
if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) {
if (!importAddresses->chunks.empty())
iatStart = importAddresses->chunks.front();
for (Chunk *c : importAddresses->chunks)
iatSize += c->getSize();
}
}
// Return whether a SectionChunk's suffix (the dollar and any trailing
// suffix) should be removed and sorted into the main suffixless
// PartialSection.
static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) {
// On MinGW, comdat groups are formed by putting the comdat group name
// after the '$' in the section name. For .eh_frame$<symbol>, that must
// still be sorted before the .eh_frame trailer from crtend.o, thus just
// strip the section name trailer. For other sections, such as
// .tls$$<symbol> (where non-comdat .tls symbols are otherwise stored in
// ".tls$"), they must be strictly sorted after .tls. And for the
// hypothetical case of comdat .CRT$XCU, we definitely need to keep the
// suffix for sorting. Thus, to play it safe, only strip the suffix for
// the standard sections.
if (!config->mingw)
return false;
if (!sc || !sc->isCOMDAT())
return false;
return name.startswith(".text$") || name.startswith(".data$") ||
name.startswith(".rdata$") || name.startswith(".pdata$") ||
name.startswith(".xdata$") || name.startswith(".eh_frame$");
}
void Writer::sortSections() {
if (!config->callGraphProfile.empty()) {
DenseMap<const SectionChunk *, int> order =
computeCallGraphProfileOrder(ctx);
for (auto it : order) {
if (DefinedRegular *sym = it.first->sym)
config->order[sym->getName()] = it.second;
}
}
if (!config->order.empty())
for (auto it : partialSections)
sortBySectionOrder(it.second->chunks);
}
// Create output section objects and add them to OutputSections.
void Writer::createSections() {
// First, create the builtin sections.
const uint32_t data = IMAGE_SCN_CNT_INITIALIZED_DATA;
const uint32_t bss = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
const uint32_t code = IMAGE_SCN_CNT_CODE;
const uint32_t discardable = IMAGE_SCN_MEM_DISCARDABLE;
const uint32_t r = IMAGE_SCN_MEM_READ;
const uint32_t w = IMAGE_SCN_MEM_WRITE;
const uint32_t x = IMAGE_SCN_MEM_EXECUTE;
SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> sections;
auto createSection = [&](StringRef name, uint32_t outChars) {
OutputSection *&sec = sections[{name, outChars}];
if (!sec) {
sec = make<OutputSection>(name, outChars);
ctx.outputSections.push_back(sec);
}
return sec;
};
// Try to match the section order used by link.exe.
textSec = createSection(".text", code | r | x);
createSection(".bss", bss | r | w);
rdataSec = createSection(".rdata", data | r);
buildidSec = createSection(".buildid", data | r);
dataSec = createSection(".data", data | r | w);
pdataSec = createSection(".pdata", data | r);
idataSec = createSection(".idata", data | r);
edataSec = createSection(".edata", data | r);
didatSec = createSection(".didat", data | r);
rsrcSec = createSection(".rsrc", data | r);
relocSec = createSection(".reloc", data | discardable | r);
ctorsSec = createSection(".ctors", data | r | w);
dtorsSec = createSection(".dtors", data | r | w);
// Then bin chunks by name and output characteristics.
for (Chunk *c : ctx.symtab.getChunks()) {
auto *sc = dyn_cast<SectionChunk>(c);
if (sc && !sc->live) {
if (config->verbose)
sc->printDiscardedMessage();
continue;
}
StringRef name = c->getSectionName();
if (shouldStripSectionSuffix(sc, name))
name = name.split('$').first;
if (name.startswith(".tls"))
tlsAlignment = std::max(tlsAlignment, c->getAlignment());
PartialSection *pSec = createPartialSection(name,
c->getOutputCharacteristics());
pSec->chunks.push_back(c);
}
fixPartialSectionChars(".rsrc", data | r);
fixPartialSectionChars(".edata", data | r);
// Even in non MinGW cases, we might need to link against GNU import
// libraries.
bool hasIdata = fixGnuImportChunks();
if (!idata.empty())
hasIdata = true;
if (hasIdata)
addSyntheticIdata();
sortSections();
if (hasIdata)
locateImportTables();
// Then create an OutputSection for each section.
// '$' and all following characters in input section names are
// discarded when determining output section. So, .text$foo
// contributes to .text, for example. See PE/COFF spec 3.2.
for (auto it : partialSections) {
PartialSection *pSec = it.second;
StringRef name = getOutputSectionName(pSec->name);
uint32_t outChars = pSec->characteristics;
if (name == ".CRT") {
// In link.exe, there is a special case for the I386 target where .CRT
// sections are treated as if they have output characteristics DATA | R if
// their characteristics are DATA | R | W. This implements the same
// special case for all architectures.
outChars = data | r;
log("Processing section " + pSec->name + " -> " + name);
sortCRTSectionChunks(pSec->chunks);
}
OutputSection *sec = createSection(name, outChars);
for (Chunk *c : pSec->chunks)
sec->addChunk(c);
sec->addContributingPartialSection(pSec);
}
// Finally, move some output sections to the end.
auto sectionOrder = [&](const OutputSection *s) {
// Move DISCARDABLE (or non-memory-mapped) sections to the end of file
// because the loader cannot handle holes. Stripping can remove other
// discardable ones than .reloc, which is first of them (created early).
if (s->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) {
// Move discardable sections named .debug_ to the end, after other
// discardable sections. Stripping only removes the sections named
// .debug_* - thus try to avoid leaving holes after stripping.
if (s->name.startswith(".debug_"))
return 3;
return 2;
}
// .rsrc should come at the end of the non-discardable sections because its
// size may change by the Win32 UpdateResources() function, causing
// subsequent sections to move (see https://crbug.com/827082).
if (s == rsrcSec)
return 1;
return 0;
};
llvm::stable_sort(ctx.outputSections,
[&](const OutputSection *s, const OutputSection *t) {
return sectionOrder(s) < sectionOrder(t);
});
}
void Writer::createMiscChunks() {
for (MergeChunk *p : ctx.mergeChunkInstances) {
if (p) {
p->finalizeContents();
rdataSec->addChunk(p);
}
}
// Create thunks for locally-dllimported symbols.
if (!ctx.symtab.localImportChunks.empty()) {
for (Chunk *c : ctx.symtab.localImportChunks)
rdataSec->addChunk(c);
}
// Create Debug Information Chunks
OutputSection *debugInfoSec = config->mingw ? buildidSec : rdataSec;
if (config->debug || config->repro || config->cetCompat) {
debugDirectory =
make<DebugDirectoryChunk>(ctx, debugRecords, config->repro);
debugDirectory->setAlignment(4);
debugInfoSec->addChunk(debugDirectory);
}
if (config->debug) {
// Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We
// output a PDB no matter what, and this chunk provides the only means of
// allowing a debugger to match a PDB and an executable. So we need it even
// if we're ultimately not going to write CodeView data to the PDB.
buildId = make<CVDebugRecordChunk>();
debugRecords.push_back({COFF::IMAGE_DEBUG_TYPE_CODEVIEW, buildId});
}
if (config->cetCompat) {
debugRecords.push_back({COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS,
make<ExtendedDllCharacteristicsChunk>(
IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT)});
}
// Align and add each chunk referenced by the debug data directory.
for (std::pair<COFF::DebugType, Chunk *> r : debugRecords) {
r.second->setAlignment(4);
debugInfoSec->addChunk(r.second);
}
// Create SEH table. x86-only.
if (config->safeSEH)
createSEHTable();
// Create /guard:cf tables if requested.
if (config->guardCF != GuardCFLevel::Off)
createGuardCFTables();
if (config->autoImport)
createRuntimePseudoRelocs();
if (config->mingw)
insertCtorDtorSymbols();
}
// Create .idata section for the DLL-imported symbol table.
// The format of this section is inherently Windows-specific.
// IdataContents class abstracted away the details for us,
// so we just let it create chunks and add them to the section.
void Writer::createImportTables() {
// Initialize DLLOrder so that import entries are ordered in
// the same order as in the command line. (That affects DLL
// initialization order, and this ordering is MSVC-compatible.)
for (ImportFile *file : ctx.importFileInstances) {
if (!file->live)
continue;
std::string dll = StringRef(file->dllName).lower();
if (config->dllOrder.count(dll) == 0)
config->dllOrder[dll] = config->dllOrder.size();
if (file->impSym && !isa<DefinedImportData>(file->impSym))
fatal(toString(*file->impSym) + " was replaced");
DefinedImportData *impSym = cast_or_null<DefinedImportData>(file->impSym);
if (config->delayLoads.count(StringRef(file->dllName).lower())) {
if (!file->thunkSym)
fatal("cannot delay-load " + toString(file) +
" due to import of data: " + toString(*impSym));
delayIdata.add(impSym);
} else {
idata.add(impSym);
}
}
}
void Writer::appendImportThunks() {
if (ctx.importFileInstances.empty())
return;
for (ImportFile *file : ctx.importFileInstances) {
if (!file->live)
continue;
if (!file->thunkSym)
continue;
if (!isa<DefinedImportThunk>(file->thunkSym))
fatal(toString(*file->thunkSym) + " was replaced");
DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym);
if (file->thunkLive)
textSec->addChunk(thunk->getChunk());
}
if (!delayIdata.empty()) {
Defined *helper = cast<Defined>(config->delayLoadHelper);
delayIdata.create(ctx, helper);
for (Chunk *c : delayIdata.getChunks())
didatSec->addChunk(c);
for (Chunk *c : delayIdata.getDataChunks())
dataSec->addChunk(c);
for (Chunk *c : delayIdata.getCodeChunks())
textSec->addChunk(c);
}
}
void Writer::createExportTable() {
if (!edataSec->chunks.empty()) {
// Allow using a custom built export table from input object files, instead
// of having the linker synthesize the tables.
if (config->hadExplicitExports)
warn("literal .edata sections override exports");
} else if (!config->exports.empty()) {
for (Chunk *c : edata.chunks)
edataSec->addChunk(c);
}
if (!edataSec->chunks.empty()) {
edataStart = edataSec->chunks.front();
edataEnd = edataSec->chunks.back();
}
// Warn on exported deleting destructor.
for (auto e : config->exports)
if (e.sym && e.sym->getName().startswith("??_G"))
warn("export of deleting dtor: " + toString(*e.sym));
}
void Writer::removeUnusedSections() {
// Remove sections that we can be sure won't get content, to avoid
// allocating space for their section headers.
auto isUnused = [this](OutputSection *s) {
if (s == relocSec)
return false; // This section is populated later.
// MergeChunks have zero size at this point, as their size is finalized
// later. Only remove sections that have no Chunks at all.
return s->chunks.empty();
};
llvm::erase_if(ctx.outputSections, isUnused);
}
// The Windows loader doesn't seem to like empty sections,
// so we remove them if any.
void Writer::removeEmptySections() {
auto isEmpty = [](OutputSection *s) { return s->getVirtualSize() == 0; };
llvm::erase_if(ctx.outputSections, isEmpty);
}
void Writer::assignOutputSectionIndices() {
// Assign final output section indices, and assign each chunk to its output
// section.
uint32_t idx = 1;
for (OutputSection *os : ctx.outputSections) {
os->sectionIndex = idx;
for (Chunk *c : os->chunks)
c->setOutputSectionIdx(idx);
++idx;
}
// Merge chunks are containers of chunks, so assign those an output section
// too.
for (MergeChunk *mc : ctx.mergeChunkInstances)
if (mc)
for (SectionChunk *sc : mc->sections)
if (sc && sc->live)
sc->setOutputSectionIdx(mc->getOutputSectionIdx());
}
size_t Writer::addEntryToStringTable(StringRef str) {
assert(str.size() > COFF::NameSize);
size_t offsetOfEntry = strtab.size() + 4; // +4 for the size field
strtab.insert(strtab.end(), str.begin(), str.end());
strtab.push_back('\0');
return offsetOfEntry;
}
Optional<coff_symbol16> Writer::createSymbol(Defined *def) {
coff_symbol16 sym;
switch (def->kind()) {
case Symbol::DefinedAbsoluteKind:
sym.Value = def->getRVA();
sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
break;
case Symbol::DefinedSyntheticKind:
// Relative symbols are unrepresentable in a COFF symbol table.
return None;
default: {
// Don't write symbols that won't be written to the output to the symbol
// table.
Chunk *c = def->getChunk();
if (!c)
return None;
OutputSection *os = ctx.getOutputSection(c);
if (!os)
return None;
sym.Value = def->getRVA() - os->getRVA();
sym.SectionNumber = os->sectionIndex;
break;
}
}
// Symbols that are runtime pseudo relocations don't point to the actual
// symbol data itself (as they are imported), but points to the IAT entry
// instead. Avoid emitting them to the symbol table, as they can confuse
// debuggers.
if (def->isRuntimePseudoReloc)
return None;
StringRef name = def->getName();
if (name.size() > COFF::NameSize) {
sym.Name.Offset.Zeroes = 0;
sym.Name.Offset.Offset = addEntryToStringTable(name);
} else {
memset(sym.Name.ShortName, 0, COFF::NameSize);
memcpy(sym.Name.ShortName, name.data(), name.size());
}
if (auto *d = dyn_cast<DefinedCOFF>(def)) {
COFFSymbolRef ref = d->getCOFFSymbol();
sym.Type = ref.getType();
sym.StorageClass = ref.getStorageClass();
} else {
sym.Type = IMAGE_SYM_TYPE_NULL;
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
}
sym.NumberOfAuxSymbols = 0;
return sym;
}
void Writer::createSymbolAndStringTable() {
// PE/COFF images are limited to 8 byte section names. Longer names can be
// supported by writing a non-standard string table, but this string table is
// not mapped at runtime and the long names will therefore be inaccessible.
// link.exe always truncates section names to 8 bytes, whereas binutils always
// preserves long section names via the string table. LLD adopts a hybrid
// solution where discardable sections have long names preserved and
// non-discardable sections have their names truncated, to ensure that any
// section which is mapped at runtime also has its name mapped at runtime.
for (OutputSection *sec : ctx.outputSections) {
if (sec->name.size() <= COFF::NameSize)
continue;
if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
continue;
if (config->warnLongSectionNames) {
warn("section name " + sec->name +
" is longer than 8 characters and will use a non-standard string "
"table");
}
sec->setStringTableOff(addEntryToStringTable(sec->name));
}
if (config->debugDwarf || config->debugSymtab) {
for (ObjFile *file : ctx.objFileInstances) {
for (Symbol *b : file->getSymbols()) {
auto *d = dyn_cast_or_null<Defined>(b);
if (!d || d->writtenToSymtab)
continue;
d->writtenToSymtab = true;
if (auto *dc = dyn_cast_or_null<DefinedCOFF>(d)) {
COFFSymbolRef symRef = dc->getCOFFSymbol();
if (symRef.isSectionDefinition() ||
symRef.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL)
continue;
}
if (Optional<coff_symbol16> sym = createSymbol(d))
outputSymtab.push_back(*sym);
}
}
}
if (outputSymtab.empty() && strtab.empty())
return;
// We position the symbol table to be adjacent to the end of the last section.
uint64_t fileOff = fileSize;
pointerToSymbolTable = fileOff;
fileOff += outputSymtab.size() * sizeof(coff_symbol16);
fileOff += 4 + strtab.size();
fileSize = alignTo(fileOff, config->fileAlign);
}
void Writer::mergeSections() {
if (!pdataSec->chunks.empty()) {
firstPdata = pdataSec->chunks.front();
lastPdata = pdataSec->chunks.back();
}
for (auto &p : config->merge) {
StringRef toName = p.second;
if (p.first == toName)
continue;
StringSet<> names;
while (true) {
if (!names.insert(toName).second)
fatal("/merge: cycle found for section '" + p.first + "'");
auto i = config->merge.find(toName);
if (i == config->merge.end())
break;
toName = i->second;
}
OutputSection *from = findSection(p.first);
OutputSection *to = findSection(toName);
if (!from)
continue;
if (!to) {
from->name = toName;
continue;
}
to->merge(from);
}
}
// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
void Writer::assignAddresses() {
sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) +
sizeof(data_directory) * numberOfDataDirectory +
sizeof(coff_section) * ctx.outputSections.size();
sizeOfHeaders +=
config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign);
fileSize = sizeOfHeaders;
// The first page is kept unmapped.
uint64_t rva = alignTo(sizeOfHeaders, config->align);
for (OutputSection *sec : ctx.outputSections) {
if (sec == relocSec)
addBaserels();
uint64_t rawSize = 0, virtualSize = 0;
sec->header.VirtualAddress = rva;
// If /FUNCTIONPADMIN is used, functions are padded in order to create a
// hotpatchable image.
const bool isCodeSection =
(sec->header.Characteristics & IMAGE_SCN_CNT_CODE) &&
(sec->header.Characteristics & IMAGE_SCN_MEM_READ) &&
(sec->header.Characteristics & IMAGE_SCN_MEM_EXECUTE);
uint32_t padding = isCodeSection ? config->functionPadMin : 0;
for (Chunk *c : sec->chunks) {
if (padding && c->isHotPatchable())
virtualSize += padding;
virtualSize = alignTo(virtualSize, c->getAlignment());
c->setRVA(rva + virtualSize);
virtualSize += c->getSize();
if (c->hasData)
rawSize = alignTo(virtualSize, config->fileAlign);
}
if (virtualSize > UINT32_MAX)
error("section larger than 4 GiB: " + sec->name);
sec->header.VirtualSize = virtualSize;
sec->header.SizeOfRawData = rawSize;
if (rawSize != 0)
sec->header.PointerToRawData = fileSize;
rva += alignTo(virtualSize, config->align);
fileSize += alignTo(rawSize, config->fileAlign);
}
sizeOfImage = alignTo(rva, config->align);
// Assign addresses to sections in MergeChunks.
for (MergeChunk *mc : ctx.mergeChunkInstances)
if (mc)
mc->assignSubsectionRVAs();
}
template <typename PEHeaderTy> void Writer::writeHeader() {
// Write DOS header. For backwards compatibility, the first part of a PE/COFF
// executable consists of an MS-DOS MZ executable. If the executable is run
// under DOS, that program gets run (usually to just print an error message).
// When run under Windows, the loader looks at AddressOfNewExeHeader and uses
// the PE header instead.
uint8_t *buf = buffer->getBufferStart();
auto *dos = reinterpret_cast<dos_header *>(buf);
buf += sizeof(dos_header);
dos->Magic[0] = 'M';
dos->Magic[1] = 'Z';
dos->UsedBytesInTheLastPage = dosStubSize % 512;
dos->FileSizeInPages = divideCeil(dosStubSize, 512);
dos->HeaderSizeInParagraphs = sizeof(dos_header) / 16;
dos->AddressOfRelocationTable = sizeof(dos_header);
dos->AddressOfNewExeHeader = dosStubSize;
// Write DOS program.
memcpy(buf, dosProgram, sizeof(dosProgram));
buf += sizeof(dosProgram);
// Write PE magic
memcpy(buf, PEMagic, sizeof(PEMagic));
buf += sizeof(PEMagic);
// Write COFF header
auto *coff = reinterpret_cast<coff_file_header *>(buf);
buf += sizeof(*coff);
coff->Machine = config->machine;
coff->NumberOfSections = ctx.outputSections.size();
coff->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
if (config->largeAddressAware)
coff->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
if (!config->is64())
coff->Characteristics |= IMAGE_FILE_32BIT_MACHINE;
if (config->dll)
coff->Characteristics |= IMAGE_FILE_DLL;
if (config->driverUponly)
coff->Characteristics |= IMAGE_FILE_UP_SYSTEM_ONLY;
if (!config->relocatable)
coff->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
if (config->swaprunCD)
coff->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP;
if (config->swaprunNet)
coff->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP;
coff->SizeOfOptionalHeader =
sizeof(PEHeaderTy) + sizeof(data_directory) * numberOfDataDirectory;
// Write PE header
auto *pe = reinterpret_cast<PEHeaderTy *>(buf);
buf += sizeof(*pe);
pe->Magic = config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32;
// If {Major,Minor}LinkerVersion is left at 0.0, then for some
// reason signing the resulting PE file with Authenticode produces a
// signature that fails to validate on Windows 7 (but is OK on 10).
// Set it to 14.0, which is what VS2015 outputs, and which avoids
// that problem.
pe->MajorLinkerVersion = 14;
pe->MinorLinkerVersion = 0;
pe->ImageBase = config->imageBase;
pe->SectionAlignment = config->align;
pe->FileAlignment = config->fileAlign;
pe->MajorImageVersion = config->majorImageVersion;
pe->MinorImageVersion = config->minorImageVersion;
pe->MajorOperatingSystemVersion = config->majorOSVersion;
pe->MinorOperatingSystemVersion = config->minorOSVersion;
pe->MajorSubsystemVersion = config->majorSubsystemVersion;
pe->MinorSubsystemVersion = config->minorSubsystemVersion;
pe->Subsystem = config->subsystem;
pe->SizeOfImage = sizeOfImage;
pe->SizeOfHeaders = sizeOfHeaders;
if (!config->noEntry) {
Defined *entry = cast<Defined>(config->entry);
pe->AddressOfEntryPoint = entry->getRVA();
// Pointer to thumb code must have the LSB set, so adjust it.
if (config->machine == ARMNT)
pe->AddressOfEntryPoint |= 1;
}
pe->SizeOfStackReserve = config->stackReserve;
pe->SizeOfStackCommit = config->stackCommit;
pe->SizeOfHeapReserve = config->heapReserve;
pe->SizeOfHeapCommit = config->heapCommit;
if (config->appContainer)
pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;
if (config->driverWdm)
pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER;
if (config->dynamicBase)
pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
if (config->highEntropyVA)
pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;
if (!config->allowBind)
pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND;
if (config->nxCompat)
pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
if (!config->allowIsolation)
pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
if (config->guardCF != GuardCFLevel::Off)
pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF;
if (config->integrityCheck)
pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY;
if (setNoSEHCharacteristic || config->noSEH)
pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH;
if (config->terminalServerAware)
pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
pe->NumberOfRvaAndSize = numberOfDataDirectory;
if (textSec->getVirtualSize()) {
pe->BaseOfCode = textSec->getRVA();
pe->SizeOfCode = textSec->getRawSize();
}
pe->SizeOfInitializedData = getSizeOfInitializedData();
// Write data directory
auto *dir = reinterpret_cast<data_directory *>(buf);
buf += sizeof(*dir) * numberOfDataDirectory;
if (edataStart) {
dir[EXPORT_TABLE].RelativeVirtualAddress = edataStart->getRVA();
dir[EXPORT_TABLE].Size =
edataEnd->getRVA() + edataEnd->getSize() - edataStart->getRVA();
}
if (importTableStart) {
dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA();
dir[IMPORT_TABLE].Size = importTableSize;
}
if (iatStart) {
dir[IAT].RelativeVirtualAddress = iatStart->getRVA();
dir[IAT].Size = iatSize;
}
if (rsrcSec->getVirtualSize()) {
dir[RESOURCE_TABLE].RelativeVirtualAddress = rsrcSec->getRVA();
dir[RESOURCE_TABLE].Size = rsrcSec->getVirtualSize();
}
if (firstPdata) {
dir[EXCEPTION_TABLE].RelativeVirtualAddress = firstPdata->getRVA();
dir[EXCEPTION_TABLE].Size =
lastPdata->getRVA() + lastPdata->getSize() - firstPdata->getRVA();
}
if (relocSec->getVirtualSize()) {
dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = relocSec->getRVA();
dir[BASE_RELOCATION_TABLE].Size = relocSec->getVirtualSize();
}
if (Symbol *sym = ctx.symtab.findUnderscore("_tls_used")) {
if (Defined *b = dyn_cast<Defined>(sym)) {
dir[TLS_TABLE].RelativeVirtualAddress = b->getRVA();
dir[TLS_TABLE].Size = config->is64()
? sizeof(object::coff_tls_directory64)
: sizeof(object::coff_tls_directory32);
}
}
if (debugDirectory) {
dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA();
dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize();
}
if (Symbol *sym = ctx.symtab.findUnderscore("_load_config_used")) {
if (auto *b = dyn_cast<DefinedRegular>(sym)) {
SectionChunk *sc = b->getChunk();
assert(b->getRVA() >= sc->getRVA());
uint64_t offsetInChunk = b->getRVA() - sc->getRVA();
if (!sc->hasData || offsetInChunk + 4 > sc->getSize())
fatal("_load_config_used is malformed");
ArrayRef<uint8_t> secContents = sc->getContents();
uint32_t loadConfigSize =
*reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]);
if (offsetInChunk + loadConfigSize > sc->getSize())
fatal("_load_config_used is too large");
dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA();
dir[LOAD_CONFIG_TABLE].Size = loadConfigSize;
}
}
if (!delayIdata.empty()) {
dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress =
delayIdata.getDirRVA();
dir[DELAY_IMPORT_DESCRIPTOR].Size = delayIdata.getDirSize();
}
// Write section table
for (OutputSection *sec : ctx.outputSections) {
sec->writeHeaderTo(buf);
buf += sizeof(coff_section);
}
sectionTable = ArrayRef<uint8_t>(
buf - ctx.outputSections.size() * sizeof(coff_section), buf);
if (outputSymtab.empty() && strtab.empty())
return;
coff->PointerToSymbolTable = pointerToSymbolTable;
uint32_t numberOfSymbols = outputSymtab.size();
coff->NumberOfSymbols = numberOfSymbols;
auto *symbolTable = reinterpret_cast<coff_symbol16 *>(
buffer->getBufferStart() + coff->PointerToSymbolTable);
for (size_t i = 0; i != numberOfSymbols; ++i)
symbolTable[i] = outputSymtab[i];
// Create the string table, it follows immediately after the symbol table.
// The first 4 bytes is length including itself.
buf = reinterpret_cast<uint8_t *>(&symbolTable[numberOfSymbols]);
write32le(buf, strtab.size() + 4);
if (!strtab.empty())
memcpy(buf + 4, strtab.data(), strtab.size());
}
void Writer::openFile(StringRef path) {
buffer = CHECK(
FileOutputBuffer::create(path, fileSize, FileOutputBuffer::F_executable),
"failed to open " + path);
}
void Writer::createSEHTable() {
SymbolRVASet handlers;
for (ObjFile *file : ctx.objFileInstances) {
if (!file->hasSafeSEH())
error("/safeseh: " + file->getName() + " is not compatible with SEH");
markSymbolsForRVATable(file, file->getSXDataChunks(), handlers);
}
// Set the "no SEH" characteristic if there really were no handlers, or if
// there is no load config object to point to the table of handlers.
setNoSEHCharacteristic =
handlers.empty() || !ctx.symtab.findUnderscore("_load_config_used");
maybeAddRVATable(std::move(handlers), "__safe_se_handler_table",
"__safe_se_handler_count");
}
// Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set
// cannot contain duplicates. Therefore, the set is uniqued by Chunk and the
// symbol's offset into that Chunk.
static void addSymbolToRVASet(SymbolRVASet &rvaSet, Defined *s) {
Chunk *c = s->getChunk();
if (auto *sc = dyn_cast<SectionChunk>(c))
c = sc->repl; // Look through ICF replacement.
uint32_t off = s->getRVA() - (c ? c->getRVA() : 0);
rvaSet.insert({c, off});
}
// Given a symbol, add it to the GFIDs table if it is a live, defined, function
// symbol in an executable section.
static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms,
Symbol *s) {
if (!s)
return;
switch (s->kind()) {
case Symbol::DefinedLocalImportKind:
case Symbol::DefinedImportDataKind:
// Defines an __imp_ pointer, so it is data, so it is ignored.
break;
case Symbol::DefinedCommonKind:
// Common is always data, so it is ignored.
break;
case Symbol::DefinedAbsoluteKind:
case Symbol::DefinedSyntheticKind:
// Absolute is never code, synthetic generally isn't and usually isn't
// determinable.
break;
case Symbol::LazyArchiveKind:
case Symbol::LazyObjectKind:
case Symbol::LazyDLLSymbolKind:
case Symbol::UndefinedKind:
// Undefined symbols resolve to zero, so they don't have an RVA. Lazy
// symbols shouldn't have relocations.
break;
case Symbol::DefinedImportThunkKind:
// Thunks are always code, include them.
addSymbolToRVASet(addressTakenSyms, cast<Defined>(s));
break;
case Symbol::DefinedRegularKind: {
// This is a regular, defined, symbol from a COFF file. Mark the symbol as
// address taken if the symbol type is function and it's in an executable
// section.
auto *d = cast<DefinedRegular>(s);
if (d->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) {
SectionChunk *sc = dyn_cast<SectionChunk>(d->getChunk());
if (sc && sc->live &&
sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)
addSymbolToRVASet(addressTakenSyms, d);
}
break;
}
}
}
// Visit all relocations from all section contributions of this object file and
// mark the relocation target as address-taken.
static void markSymbolsWithRelocations(ObjFile *file,
SymbolRVASet &usedSymbols) {
for (Chunk *c : file->getChunks()) {
// We only care about live section chunks. Common chunks and other chunks
// don't generally contain relocations.
SectionChunk *sc = dyn_cast<SectionChunk>(c);
if (!sc || !sc->live)
continue;
for (const coff_relocation &reloc : sc->getRelocs()) {
if (config->machine == I386 && reloc.Type == COFF::IMAGE_REL_I386_REL32)
// Ignore relative relocations on x86. On x86_64 they can't be ignored
// since they're also used to compute absolute addresses.
continue;
Symbol *ref = sc->file->getSymbol(reloc.SymbolTableIndex);
maybeAddAddressTakenFunction(usedSymbols, ref);
}
}
}
// Create the guard function id table. This is a table of RVAs of all
// address-taken functions. It is sorted and uniqued, just like the safe SEH
// table.
void Writer::createGuardCFTables() {
SymbolRVASet addressTakenSyms;
SymbolRVASet giatsRVASet;
std::vector<Symbol *> giatsSymbols;
SymbolRVASet longJmpTargets;
SymbolRVASet ehContTargets;
for (ObjFile *file : ctx.objFileInstances) {
// If the object was compiled with /guard:cf, the address taken symbols
// are in .gfids$y sections, the longjmp targets are in .gljmp$y sections,
// and ehcont targets are in .gehcont$y sections. If the object was not
// compiled with /guard:cf, we assume there were no setjmp and ehcont
// targets, and that all code symbols with relocations are possibly
// address-taken.
if (file->hasGuardCF()) {
markSymbolsForRVATable(file, file->getGuardFidChunks(), addressTakenSyms);
markSymbolsForRVATable(file, file->getGuardIATChunks(), giatsRVASet);
getSymbolsFromSections(file, file->getGuardIATChunks(), giatsSymbols);
markSymbolsForRVATable(file, file->getGuardLJmpChunks(), longJmpTargets);
markSymbolsForRVATable(file, file->getGuardEHContChunks(), ehContTargets);
} else {
markSymbolsWithRelocations(file, addressTakenSyms);
}
}
// Mark the image entry as address-taken.
if (config->entry)
maybeAddAddressTakenFunction(addressTakenSyms, config->entry);
// Mark exported symbols in executable sections as address-taken.
for (Export &e : config->exports)
maybeAddAddressTakenFunction(addressTakenSyms, e.sym);
// For each entry in the .giats table, check if it has a corresponding load
// thunk (e.g. because the DLL that defines it will be delay-loaded) and, if
// so, add the load thunk to the address taken (.gfids) table.
for (Symbol *s : giatsSymbols) {
if (auto *di = dyn_cast<DefinedImportData>(s)) {
if (di->loadThunkSym)
addSymbolToRVASet(addressTakenSyms, di->loadThunkSym);
}
}
// Ensure sections referenced in the gfid table are 16-byte aligned.
for (const ChunkAndOffset &c : addressTakenSyms)
if (c.inputChunk->getAlignment() < 16)
c.inputChunk->setAlignment(16);
maybeAddRVATable(std::move(addressTakenSyms), "__guard_fids_table",
"__guard_fids_count");
// Add the Guard Address Taken IAT Entry Table (.giats).
maybeAddRVATable(std::move(giatsRVASet), "__guard_iat_table",
"__guard_iat_count");
// Add the longjmp target table unless the user told us not to.
if (config->guardCF & GuardCFLevel::LongJmp)
maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table",
"__guard_longjmp_count");
// Add the ehcont target table unless the user told us not to.
if (config->guardCF & GuardCFLevel::EHCont)
maybeAddRVATable(std::move(ehContTargets), "__guard_eh_cont_table",
"__guard_eh_cont_count", true);
// Set __guard_flags, which will be used in the load config to indicate that
// /guard:cf was enabled.
uint32_t guardFlags = uint32_t(coff_guard_flags::CFInstrumented) |
uint32_t(coff_guard_flags::HasFidTable);
if (config->guardCF & GuardCFLevel::LongJmp)
guardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable);
if (config->guardCF & GuardCFLevel::EHCont)
guardFlags |= uint32_t(coff_guard_flags::HasEHContTable);
Symbol *flagSym = ctx.symtab.findUnderscore("__guard_flags");
cast<DefinedAbsolute>(flagSym)->setVA(guardFlags);
}
// Take a list of input sections containing symbol table indices and add those
// symbols to a vector. The challenge is that symbol RVAs are not known and
// depend on the table size, so we can't directly build a set of integers.
void Writer::getSymbolsFromSections(ObjFile *file,
ArrayRef<SectionChunk *> symIdxChunks,
std::vector<Symbol *> &symbols) {
for (SectionChunk *c : symIdxChunks) {
// Skip sections discarded by linker GC. This comes up when a .gfids section
// is associated with something like a vtable and the vtable is discarded.
// In this case, the associated gfids section is discarded, and we don't
// mark the virtual member functions as address-taken by the vtable.
if (!c->live)
continue;
// Validate that the contents look like symbol table indices.
ArrayRef<uint8_t> data = c->getContents();
if (data.size() % 4 != 0) {
warn("ignoring " + c->getSectionName() +
" symbol table index section in object " + toString(file));
continue;
}
// Read each symbol table index and check if that symbol was included in the
// final link. If so, add it to the vector of symbols.
ArrayRef<ulittle32_t> symIndices(
reinterpret_cast<const ulittle32_t *>(data.data()), data.size() / 4);
ArrayRef<Symbol *> objSymbols = file->getSymbols();
for (uint32_t symIndex : symIndices) {
if (symIndex >= objSymbols.size()) {
warn("ignoring invalid symbol table index in section " +
c->getSectionName() + " in object " + toString(file));
continue;
}
if (Symbol *s = objSymbols[symIndex]) {
if (s->isLive())
symbols.push_back(cast<Symbol>(s));
}
}
}
}
// Take a list of input sections containing symbol table indices and add those
// symbols to an RVA table.
void Writer::markSymbolsForRVATable(ObjFile *file,
ArrayRef<SectionChunk *> symIdxChunks,
SymbolRVASet &tableSymbols) {
std::vector<Symbol *> syms;
getSymbolsFromSections(file, symIdxChunks, syms);
for (Symbol *s : syms)
addSymbolToRVASet(tableSymbols, cast<Defined>(s));
}
// Replace the absolute table symbol with a synthetic symbol pointing to
// tableChunk so that we can emit base relocations for it and resolve section
// relative relocations.
void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
StringRef countSym, bool hasFlag) {
if (tableSymbols.empty())
return;
NonSectionChunk *tableChunk;
if (hasFlag)
tableChunk = make<RVAFlagTableChunk>(std::move(tableSymbols));
else
tableChunk = make<RVATableChunk>(std::move(tableSymbols));
rdataSec->addChunk(tableChunk);
Symbol *t = ctx.symtab.findUnderscore(tableSym);
Symbol *c = ctx.symtab.findUnderscore(countSym);
replaceSymbol<DefinedSynthetic>(t, t->getName(), tableChunk);
cast<DefinedAbsolute>(c)->setVA(tableChunk->getSize() / (hasFlag ? 5 : 4));
}
// MinGW specific. Gather all relocations that are imported from a DLL even
// though the code didn't expect it to, produce the table that the runtime
// uses for fixing them up, and provide the synthetic symbols that the
// runtime uses for finding the table.
void Writer::createRuntimePseudoRelocs() {
std::vector<RuntimePseudoReloc> rels;
for (Chunk *c : ctx.symtab.getChunks()) {
auto *sc = dyn_cast<SectionChunk>(c);
if (!sc || !sc->live)
continue;
sc->getRuntimePseudoRelocs(rels);
}
if (!config->pseudoRelocs) {
// Not writing any pseudo relocs; if some were needed, error out and
// indicate what required them.
for (const RuntimePseudoReloc &rpr : rels)
error("automatic dllimport of " + rpr.sym->getName() + " in " +
toString(rpr.target->file) + " requires pseudo relocations");
return;
}
if (!rels.empty())
log("Writing " + Twine(rels.size()) + " runtime pseudo relocations");
PseudoRelocTableChunk *table = make<PseudoRelocTableChunk>(rels);
rdataSec->addChunk(table);
EmptyChunk *endOfList = make<EmptyChunk>();
rdataSec->addChunk(endOfList);
Symbol *headSym = ctx.symtab.findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");
Symbol *endSym =
ctx.symtab.findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__");
replaceSymbol<DefinedSynthetic>(headSym, headSym->getName(), table);
replaceSymbol<DefinedSynthetic>(endSym, endSym->getName(), endOfList);
}
// MinGW specific.
// The MinGW .ctors and .dtors lists have sentinels at each end;
// a (uintptr_t)-1 at the start and a (uintptr_t)0 at the end.
// There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__
// and __DTOR_LIST__ respectively.
void Writer::insertCtorDtorSymbols() {
AbsolutePointerChunk *ctorListHead = make<AbsolutePointerChunk>(-1);
AbsolutePointerChunk *ctorListEnd = make<AbsolutePointerChunk>(0);
AbsolutePointerChunk *dtorListHead = make<AbsolutePointerChunk>(-1);
AbsolutePointerChunk *dtorListEnd = make<AbsolutePointerChunk>(0);
ctorsSec->insertChunkAtStart(ctorListHead);
ctorsSec->addChunk(ctorListEnd);
dtorsSec->insertChunkAtStart(dtorListHead);
dtorsSec->addChunk(dtorListEnd);
Symbol *ctorListSym = ctx.symtab.findUnderscore("__CTOR_LIST__");
Symbol *dtorListSym = ctx.symtab.findUnderscore("__DTOR_LIST__");
replaceSymbol<DefinedSynthetic>(ctorListSym, ctorListSym->getName(),
ctorListHead);
replaceSymbol<DefinedSynthetic>(dtorListSym, dtorListSym->getName(),
dtorListHead);
}
// Handles /section options to allow users to overwrite
// section attributes.
void Writer::setSectionPermissions() {
for (auto &p : config->section) {
StringRef name = p.first;
uint32_t perm = p.second;
for (OutputSection *sec : ctx.outputSections)
if (sec->name == name)
sec->setPermissions(perm);
}
}
// Write section contents to a mmap'ed file.
void Writer::writeSections() {
// Record the number of sections to apply section index relocations
// against absolute symbols. See applySecIdx in Chunks.cpp..
DefinedAbsolute::numOutputSections = ctx.outputSections.size();
uint8_t *buf = buffer->getBufferStart();
for (OutputSection *sec : ctx.outputSections) {
uint8_t *secBuf = buf + sec->getFileOff();
// Fill gaps between functions in .text with INT3 instructions
// instead of leaving as NUL bytes (which can be interpreted as
// ADD instructions).
if (sec->header.Characteristics & IMAGE_SCN_CNT_CODE)
memset(secBuf, 0xCC, sec->getRawSize());
parallelForEach(sec->chunks, [&](Chunk *c) {
c->writeTo(secBuf + c->getRVA() - sec->getRVA());
});
}
}
void Writer::writeBuildId() {
// There are two important parts to the build ID.
// 1) If building with debug info, the COFF debug directory contains a
// timestamp as well as a Guid and Age of the PDB.
// 2) In all cases, the PE COFF file header also contains a timestamp.
// For reproducibility, instead of a timestamp we want to use a hash of the
// PE contents.
if (config->debug) {
assert(buildId && "BuildId is not set!");
// BuildId->BuildId was filled in when the PDB was written.
}
// At this point the only fields in the COFF file which remain unset are the
// "timestamp" in the COFF file header, and the ones in the coff debug
// directory. Now we can hash the file and write that hash to the various
// timestamp fields in the file.
StringRef outputFileData(
reinterpret_cast<const char *>(buffer->getBufferStart()),
buffer->getBufferSize());
uint32_t timestamp = config->timestamp;
uint64_t hash = 0;
bool generateSyntheticBuildId =
config->mingw && config->debug && config->pdbPath.empty();
if (config->repro || generateSyntheticBuildId)
hash = xxHash64(outputFileData);
if (config->repro)
timestamp = static_cast<uint32_t>(hash);
if (generateSyntheticBuildId) {
// For MinGW builds without a PDB file, we still generate a build id
// to allow associating a crash dump to the executable.
buildId->buildId->PDB70.CVSignature = OMF::Signature::PDB70;
buildId->buildId->PDB70.Age = 1;
memcpy(buildId->buildId->PDB70.Signature, &hash, 8);
// xxhash only gives us 8 bytes, so put some fixed data in the other half.
memcpy(&buildId->buildId->PDB70.Signature[8], "LLD PDB.", 8);
}
if (debugDirectory)
debugDirectory->setTimeDateStamp(timestamp);
uint8_t *buf = buffer->getBufferStart();
buf += dosStubSize + sizeof(PEMagic);
object::coff_file_header *coffHeader =
reinterpret_cast<coff_file_header *>(buf);
coffHeader->TimeDateStamp = timestamp;
}
// Sort .pdata section contents according to PE/COFF spec 5.5.
void Writer::sortExceptionTable() {
if (!firstPdata)
return;
// We assume .pdata contains function table entries only.
auto bufAddr = [&](Chunk *c) {
OutputSection *os = ctx.getOutputSection(c);
return buffer->getBufferStart() + os->getFileOff() + c->getRVA() -
os->getRVA();
};
uint8_t *begin = bufAddr(firstPdata);
uint8_t *end = bufAddr(lastPdata) + lastPdata->getSize();
if (config->machine == AMD64) {
struct Entry { ulittle32_t begin, end, unwind; };
if ((end - begin) % sizeof(Entry) != 0) {
fatal("unexpected .pdata size: " + Twine(end - begin) +
" is not a multiple of " + Twine(sizeof(Entry)));
}
parallelSort(
MutableArrayRef<Entry>((Entry *)begin, (Entry *)end),
[](const Entry &a, const Entry &b) { return a.begin < b.begin; });
return;
}
if (config->machine == ARMNT || config->machine == ARM64) {
struct Entry { ulittle32_t begin, unwind; };
if ((end - begin) % sizeof(Entry) != 0) {
fatal("unexpected .pdata size: " + Twine(end - begin) +
" is not a multiple of " + Twine(sizeof(Entry)));
}
parallelSort(
MutableArrayRef<Entry>((Entry *)begin, (Entry *)end),
[](const Entry &a, const Entry &b) { return a.begin < b.begin; });
return;
}
lld::errs() << "warning: don't know how to handle .pdata.\n";
}
// The CRT section contains, among other things, the array of function
// pointers that initialize every global variable that is not trivially
// constructed. The CRT calls them one after the other prior to invoking
// main().
//
// As per C++ spec, 3.6.2/2.3,
// "Variables with ordered initialization defined within a single
// translation unit shall be initialized in the order of their definitions
// in the translation unit"
//
// It is therefore critical to sort the chunks containing the function
// pointers in the order that they are listed in the object file (top to
// bottom), otherwise global objects might not be initialized in the
// correct order.
void Writer::sortCRTSectionChunks(std::vector<Chunk *> &chunks) {
auto sectionChunkOrder = [](const Chunk *a, const Chunk *b) {
auto sa = dyn_cast<SectionChunk>(a);
auto sb = dyn_cast<SectionChunk>(b);
assert(sa && sb && "Non-section chunks in CRT section!");
StringRef sAObj = sa->file->mb.getBufferIdentifier();
StringRef sBObj = sb->file->mb.getBufferIdentifier();
return sAObj == sBObj && sa->getSectionNumber() < sb->getSectionNumber();
};
llvm::stable_sort(chunks, sectionChunkOrder);
if (config->verbose) {
for (auto &c : chunks) {
auto sc = dyn_cast<SectionChunk>(c);
log(" " + sc->file->mb.getBufferIdentifier().str() +
", SectionID: " + Twine(sc->getSectionNumber()));
}
}
}
OutputSection *Writer::findSection(StringRef name) {
for (OutputSection *sec : ctx.outputSections)
if (sec->name == name)
return sec;
return nullptr;
}
uint32_t Writer::getSizeOfInitializedData() {
uint32_t res = 0;
for (OutputSection *s : ctx.outputSections)
if (s->header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
res += s->getRawSize();
return res;
}
// Add base relocations to .reloc section.
void Writer::addBaserels() {
if (!config->relocatable)
return;
relocSec->chunks.clear();
std::vector<Baserel> v;
for (OutputSection *sec : ctx.outputSections) {
if (sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
continue;
// Collect all locations for base relocations.
for (Chunk *c : sec->chunks)
c->getBaserels(&v);
// Add the addresses to .reloc section.
if (!v.empty())
addBaserelBlocks(v);
v.clear();
}
}
// Add addresses to .reloc section. Note that addresses are grouped by page.
void Writer::addBaserelBlocks(std::vector<Baserel> &v) {
const uint32_t mask = ~uint32_t(pageSize - 1);
uint32_t page = v[0].rva & mask;
size_t i = 0, j = 1;
for (size_t e = v.size(); j < e; ++j) {
uint32_t p = v[j].rva & mask;
if (p == page)
continue;
relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j));
i = j;
page = p;
}
if (i == j)
return;
relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j));
}
PartialSection *Writer::createPartialSection(StringRef name,
uint32_t outChars) {
PartialSection *&pSec = partialSections[{name, outChars}];
if (pSec)
return pSec;
pSec = make<PartialSection>(name, outChars);
return pSec;
}
PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) {
auto it = partialSections.find({name, outChars});
if (it != partialSections.end())
return it->second;
return nullptr;
}
void Writer::fixTlsAlignment() {
Defined *tlsSym =
dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore("_tls_used"));
if (!tlsSym)
return;
OutputSection *sec = ctx.getOutputSection(tlsSym->getChunk());
assert(sec && tlsSym->getRVA() >= sec->getRVA() &&
"no output section for _tls_used");
uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();
uint64_t tlsOffset = tlsSym->getRVA() - sec->getRVA();
uint64_t directorySize = config->is64()
? sizeof(object::coff_tls_directory64)
: sizeof(object::coff_tls_directory32);
if (tlsOffset + directorySize > sec->getRawSize())
fatal("_tls_used sym is malformed");
if (config->is64()) {
object::coff_tls_directory64 *tlsDir =
reinterpret_cast<object::coff_tls_directory64 *>(&secBuf[tlsOffset]);
tlsDir->setAlignment(tlsAlignment);
} else {
object::coff_tls_directory32 *tlsDir =
reinterpret_cast<object::coff_tls_directory32 *>(&secBuf[tlsOffset]);
tlsDir->setAlignment(tlsAlignment);
}
}
diff --git a/contrib/llvm-project/lld/ELF/Arch/RISCV.cpp b/contrib/llvm-project/lld/ELF/Arch/RISCV.cpp
index 8fca1a686a79..56a516f9cdc1 100644
--- a/contrib/llvm-project/lld/ELF/Arch/RISCV.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/RISCV.cpp
@@ -1,818 +1,819 @@
//===- RISCV.cpp ----------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "InputFiles.h"
#include "OutputSections.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "llvm/Support/TimeProfiler.h"
using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
namespace {
class RISCV final : public TargetInfo {
public:
RISCV();
uint32_t calcEFlags() const override;
int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
void writeGotHeader(uint8_t *buf) const override;
void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
void writeIgotPlt(uint8_t *buf, const Symbol &s) const override;
void writePltHeader(uint8_t *buf) const override;
void writePlt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) const override;
RelType getDynRel(RelType type) const override;
RelExpr getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const override;
void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;
bool relaxOnce(int pass) const override;
};
} // end anonymous namespace
const uint64_t dtpOffset = 0x800;
enum Op {
ADDI = 0x13,
AUIPC = 0x17,
JALR = 0x67,
LD = 0x3003,
LW = 0x2003,
SRLI = 0x5013,
SUB = 0x40000033,
};
enum Reg {
X_RA = 1,
X_TP = 4,
X_T0 = 5,
X_T1 = 6,
X_T2 = 7,
X_T3 = 28,
};
static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; }
static uint32_t lo12(uint32_t val) { return val & 4095; }
static uint32_t itype(uint32_t op, uint32_t rd, uint32_t rs1, uint32_t imm) {
return op | (rd << 7) | (rs1 << 15) | (imm << 20);
}
static uint32_t rtype(uint32_t op, uint32_t rd, uint32_t rs1, uint32_t rs2) {
return op | (rd << 7) | (rs1 << 15) | (rs2 << 20);
}
static uint32_t utype(uint32_t op, uint32_t rd, uint32_t imm) {
return op | (rd << 7) | (imm << 12);
}
// Extract bits v[begin:end], where range is inclusive, and begin must be < 63.
static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) {
return (v & ((1ULL << (begin + 1)) - 1)) >> end;
}
static uint32_t setLO12_I(uint32_t insn, uint32_t imm) {
return (insn & 0xfffff) | (imm << 20);
}
static uint32_t setLO12_S(uint32_t insn, uint32_t imm) {
return (insn & 0x1fff07f) | (extractBits(imm, 11, 5) << 25) |
(extractBits(imm, 4, 0) << 7);
}
RISCV::RISCV() {
copyRel = R_RISCV_COPY;
pltRel = R_RISCV_JUMP_SLOT;
relativeRel = R_RISCV_RELATIVE;
iRelativeRel = R_RISCV_IRELATIVE;
if (config->is64) {
symbolicRel = R_RISCV_64;
tlsModuleIndexRel = R_RISCV_TLS_DTPMOD64;
tlsOffsetRel = R_RISCV_TLS_DTPREL64;
tlsGotRel = R_RISCV_TLS_TPREL64;
} else {
symbolicRel = R_RISCV_32;
tlsModuleIndexRel = R_RISCV_TLS_DTPMOD32;
tlsOffsetRel = R_RISCV_TLS_DTPREL32;
tlsGotRel = R_RISCV_TLS_TPREL32;
}
gotRel = symbolicRel;
// .got[0] = _DYNAMIC
gotHeaderEntriesNum = 1;
// .got.plt[0] = _dl_runtime_resolve, .got.plt[1] = link_map
gotPltHeaderEntriesNum = 2;
pltHeaderSize = 32;
pltEntrySize = 16;
ipltEntrySize = 16;
}
static uint32_t getEFlags(InputFile *f) {
if (config->is64)
return cast<ObjFile<ELF64LE>>(f)->getObj().getHeader().e_flags;
return cast<ObjFile<ELF32LE>>(f)->getObj().getHeader().e_flags;
}
uint32_t RISCV::calcEFlags() const {
// If there are only binary input files (from -b binary), use a
// value of 0 for the ELF header flags.
if (ctx->objectFiles.empty())
return 0;
uint32_t target = getEFlags(ctx->objectFiles.front());
for (InputFile *f : ctx->objectFiles) {
uint32_t eflags = getEFlags(f);
if (eflags & EF_RISCV_RVC)
target |= EF_RISCV_RVC;
if ((eflags & EF_RISCV_FLOAT_ABI) != (target & EF_RISCV_FLOAT_ABI))
error(toString(f) +
": cannot link object files with different floating-point ABI");
if ((eflags & EF_RISCV_RVE) != (target & EF_RISCV_RVE))
error(toString(f) +
": cannot link object files with different EF_RISCV_RVE");
}
return target;
}
int64_t RISCV::getImplicitAddend(const uint8_t *buf, RelType type) const {
switch (type) {
default:
internalLinkerError(getErrorLocation(buf),
"cannot read addend for relocation " + toString(type));
return 0;
case R_RISCV_32:
case R_RISCV_TLS_DTPMOD32:
case R_RISCV_TLS_DTPREL32:
return SignExtend64<32>(read32le(buf));
case R_RISCV_64:
return read64le(buf);
case R_RISCV_RELATIVE:
case R_RISCV_IRELATIVE:
return config->is64 ? read64le(buf) : read32le(buf);
case R_RISCV_NONE:
case R_RISCV_JUMP_SLOT:
// These relocations are defined as not having an implicit addend.
return 0;
}
}
void RISCV::writeGotHeader(uint8_t *buf) const {
if (config->is64)
write64le(buf, mainPart->dynamic->getVA());
else
write32le(buf, mainPart->dynamic->getVA());
}
void RISCV::writeGotPlt(uint8_t *buf, const Symbol &s) const {
if (config->is64)
write64le(buf, in.plt->getVA());
else
write32le(buf, in.plt->getVA());
}
void RISCV::writeIgotPlt(uint8_t *buf, const Symbol &s) const {
if (config->writeAddends) {
if (config->is64)
write64le(buf, s.getVA());
else
write32le(buf, s.getVA());
}
}
void RISCV::writePltHeader(uint8_t *buf) const {
// 1: auipc t2, %pcrel_hi(.got.plt)
// sub t1, t1, t3
// l[wd] t3, %pcrel_lo(1b)(t2); t3 = _dl_runtime_resolve
// addi t1, t1, -pltHeaderSize-12; t1 = &.plt[i] - &.plt[0]
// addi t0, t2, %pcrel_lo(1b)
// srli t1, t1, (rv64?1:2); t1 = &.got.plt[i] - &.got.plt[0]
// l[wd] t0, Wordsize(t0); t0 = link_map
// jr t3
uint32_t offset = in.gotPlt->getVA() - in.plt->getVA();
uint32_t load = config->is64 ? LD : LW;
write32le(buf + 0, utype(AUIPC, X_T2, hi20(offset)));
write32le(buf + 4, rtype(SUB, X_T1, X_T1, X_T3));
write32le(buf + 8, itype(load, X_T3, X_T2, lo12(offset)));
write32le(buf + 12, itype(ADDI, X_T1, X_T1, -target->pltHeaderSize - 12));
write32le(buf + 16, itype(ADDI, X_T0, X_T2, lo12(offset)));
write32le(buf + 20, itype(SRLI, X_T1, X_T1, config->is64 ? 1 : 2));
write32le(buf + 24, itype(load, X_T0, X_T0, config->wordsize));
write32le(buf + 28, itype(JALR, 0, X_T3, 0));
}
void RISCV::writePlt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) const {
// 1: auipc t3, %pcrel_hi(f@.got.plt)
// l[wd] t3, %pcrel_lo(1b)(t3)
// jalr t1, t3
// nop
uint32_t offset = sym.getGotPltVA() - pltEntryAddr;
write32le(buf + 0, utype(AUIPC, X_T3, hi20(offset)));
write32le(buf + 4, itype(config->is64 ? LD : LW, X_T3, X_T3, lo12(offset)));
write32le(buf + 8, itype(JALR, X_T1, X_T3, 0));
write32le(buf + 12, itype(ADDI, 0, 0, 0));
}
RelType RISCV::getDynRel(RelType type) const {
return type == target->symbolicRel ? type
: static_cast<RelType>(R_RISCV_NONE);
}
RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
const uint8_t *loc) const {
switch (type) {
case R_RISCV_NONE:
return R_NONE;
case R_RISCV_32:
case R_RISCV_64:
case R_RISCV_HI20:
case R_RISCV_LO12_I:
case R_RISCV_LO12_S:
case R_RISCV_RVC_LUI:
return R_ABS;
case R_RISCV_ADD8:
case R_RISCV_ADD16:
case R_RISCV_ADD32:
case R_RISCV_ADD64:
case R_RISCV_SET6:
case R_RISCV_SET8:
case R_RISCV_SET16:
case R_RISCV_SET32:
case R_RISCV_SUB6:
case R_RISCV_SUB8:
case R_RISCV_SUB16:
case R_RISCV_SUB32:
case R_RISCV_SUB64:
return R_RISCV_ADD;
case R_RISCV_JAL:
case R_RISCV_BRANCH:
case R_RISCV_PCREL_HI20:
case R_RISCV_RVC_BRANCH:
case R_RISCV_RVC_JUMP:
case R_RISCV_32_PCREL:
return R_PC;
case R_RISCV_CALL:
case R_RISCV_CALL_PLT:
return R_PLT_PC;
case R_RISCV_GOT_HI20:
return R_GOT_PC;
case R_RISCV_PCREL_LO12_I:
case R_RISCV_PCREL_LO12_S:
return R_RISCV_PC_INDIRECT;
case R_RISCV_TLS_GD_HI20:
return R_TLSGD_PC;
case R_RISCV_TLS_GOT_HI20:
config->hasTlsIe = true;
return R_GOT_PC;
case R_RISCV_TPREL_HI20:
case R_RISCV_TPREL_LO12_I:
case R_RISCV_TPREL_LO12_S:
return R_TPREL;
case R_RISCV_ALIGN:
return R_RELAX_HINT;
case R_RISCV_TPREL_ADD:
case R_RISCV_RELAX:
return config->relax ? R_RELAX_HINT : R_NONE;
default:
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
") against symbol " + toString(s));
return R_NONE;
}
}
void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
const unsigned bits = config->wordsize * 8;
switch (rel.type) {
case R_RISCV_32:
write32le(loc, val);
return;
case R_RISCV_64:
write64le(loc, val);
return;
case R_RISCV_RVC_BRANCH: {
checkInt(loc, val, 9, rel);
checkAlignment(loc, val, 2, rel);
uint16_t insn = read16le(loc) & 0xE383;
uint16_t imm8 = extractBits(val, 8, 8) << 12;
uint16_t imm4_3 = extractBits(val, 4, 3) << 10;
uint16_t imm7_6 = extractBits(val, 7, 6) << 5;
uint16_t imm2_1 = extractBits(val, 2, 1) << 3;
uint16_t imm5 = extractBits(val, 5, 5) << 2;
insn |= imm8 | imm4_3 | imm7_6 | imm2_1 | imm5;
write16le(loc, insn);
return;
}
case R_RISCV_RVC_JUMP: {
checkInt(loc, val, 12, rel);
checkAlignment(loc, val, 2, rel);
uint16_t insn = read16le(loc) & 0xE003;
uint16_t imm11 = extractBits(val, 11, 11) << 12;
uint16_t imm4 = extractBits(val, 4, 4) << 11;
uint16_t imm9_8 = extractBits(val, 9, 8) << 9;
uint16_t imm10 = extractBits(val, 10, 10) << 8;
uint16_t imm6 = extractBits(val, 6, 6) << 7;
uint16_t imm7 = extractBits(val, 7, 7) << 6;
uint16_t imm3_1 = extractBits(val, 3, 1) << 3;
uint16_t imm5 = extractBits(val, 5, 5) << 2;
insn |= imm11 | imm4 | imm9_8 | imm10 | imm6 | imm7 | imm3_1 | imm5;
write16le(loc, insn);
return;
}
case R_RISCV_RVC_LUI: {
int64_t imm = SignExtend64(val + 0x800, bits) >> 12;
checkInt(loc, imm, 6, rel);
if (imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0`
write16le(loc, (read16le(loc) & 0x0F83) | 0x4000);
} else {
uint16_t imm17 = extractBits(val + 0x800, 17, 17) << 12;
uint16_t imm16_12 = extractBits(val + 0x800, 16, 12) << 2;
write16le(loc, (read16le(loc) & 0xEF83) | imm17 | imm16_12);
}
return;
}
case R_RISCV_JAL: {
checkInt(loc, val, 21, rel);
checkAlignment(loc, val, 2, rel);
uint32_t insn = read32le(loc) & 0xFFF;
uint32_t imm20 = extractBits(val, 20, 20) << 31;
uint32_t imm10_1 = extractBits(val, 10, 1) << 21;
uint32_t imm11 = extractBits(val, 11, 11) << 20;
uint32_t imm19_12 = extractBits(val, 19, 12) << 12;
insn |= imm20 | imm10_1 | imm11 | imm19_12;
write32le(loc, insn);
return;
}
case R_RISCV_BRANCH: {
checkInt(loc, val, 13, rel);
checkAlignment(loc, val, 2, rel);
uint32_t insn = read32le(loc) & 0x1FFF07F;
uint32_t imm12 = extractBits(val, 12, 12) << 31;
uint32_t imm10_5 = extractBits(val, 10, 5) << 25;
uint32_t imm4_1 = extractBits(val, 4, 1) << 8;
uint32_t imm11 = extractBits(val, 11, 11) << 7;
insn |= imm12 | imm10_5 | imm4_1 | imm11;
write32le(loc, insn);
return;
}
// auipc + jalr pair
case R_RISCV_CALL:
case R_RISCV_CALL_PLT: {
int64_t hi = SignExtend64(val + 0x800, bits) >> 12;
checkInt(loc, hi, 20, rel);
if (isInt<20>(hi)) {
relocateNoSym(loc, R_RISCV_PCREL_HI20, val);
relocateNoSym(loc + 4, R_RISCV_PCREL_LO12_I, val);
}
return;
}
case R_RISCV_GOT_HI20:
case R_RISCV_PCREL_HI20:
case R_RISCV_TLS_GD_HI20:
case R_RISCV_TLS_GOT_HI20:
case R_RISCV_TPREL_HI20:
case R_RISCV_HI20: {
uint64_t hi = val + 0x800;
checkInt(loc, SignExtend64(hi, bits) >> 12, 20, rel);
write32le(loc, (read32le(loc) & 0xFFF) | (hi & 0xFFFFF000));
return;
}
case R_RISCV_PCREL_LO12_I:
case R_RISCV_TPREL_LO12_I:
case R_RISCV_LO12_I: {
uint64_t hi = (val + 0x800) >> 12;
uint64_t lo = val - (hi << 12);
write32le(loc, setLO12_I(read32le(loc), lo & 0xfff));
return;
}
case R_RISCV_PCREL_LO12_S:
case R_RISCV_TPREL_LO12_S:
case R_RISCV_LO12_S: {
uint64_t hi = (val + 0x800) >> 12;
uint64_t lo = val - (hi << 12);
write32le(loc, setLO12_S(read32le(loc), lo));
return;
}
case R_RISCV_ADD8:
*loc += val;
return;
case R_RISCV_ADD16:
write16le(loc, read16le(loc) + val);
return;
case R_RISCV_ADD32:
write32le(loc, read32le(loc) + val);
return;
case R_RISCV_ADD64:
write64le(loc, read64le(loc) + val);
return;
case R_RISCV_SUB6:
*loc = (*loc & 0xc0) | (((*loc & 0x3f) - val) & 0x3f);
return;
case R_RISCV_SUB8:
*loc -= val;
return;
case R_RISCV_SUB16:
write16le(loc, read16le(loc) - val);
return;
case R_RISCV_SUB32:
write32le(loc, read32le(loc) - val);
return;
case R_RISCV_SUB64:
write64le(loc, read64le(loc) - val);
return;
case R_RISCV_SET6:
*loc = (*loc & 0xc0) | (val & 0x3f);
return;
case R_RISCV_SET8:
*loc = val;
return;
case R_RISCV_SET16:
write16le(loc, val);
return;
case R_RISCV_SET32:
case R_RISCV_32_PCREL:
write32le(loc, val);
return;
case R_RISCV_TLS_DTPREL32:
write32le(loc, val - dtpOffset);
break;
case R_RISCV_TLS_DTPREL64:
write64le(loc, val - dtpOffset);
break;
case R_RISCV_RELAX:
return; // Ignored (for now)
default:
llvm_unreachable("unknown relocation");
}
}
namespace {
struct SymbolAnchor {
uint64_t offset;
Defined *d;
bool end; // true for the anchor of st_value+st_size
};
} // namespace
struct elf::RISCVRelaxAux {
// This records symbol start and end offsets which will be adjusted according
// to the nearest relocDeltas element.
SmallVector<SymbolAnchor, 0> anchors;
// For relocations[i], the actual offset is r_offset - (i ? relocDeltas[i-1] :
// 0).
std::unique_ptr<uint32_t[]> relocDeltas;
// For relocations[i], the actual type is relocTypes[i].
std::unique_ptr<RelType[]> relocTypes;
SmallVector<uint32_t, 0> writes;
};
static void initSymbolAnchors() {
SmallVector<InputSection *, 0> storage;
for (OutputSection *osec : outputSections) {
if (!(osec->flags & SHF_EXECINSTR))
continue;
for (InputSection *sec : getInputSections(*osec, storage)) {
sec->relaxAux = make<RISCVRelaxAux>();
if (sec->relocations.size()) {
sec->relaxAux->relocDeltas =
std::make_unique<uint32_t[]>(sec->relocations.size());
sec->relaxAux->relocTypes =
std::make_unique<RelType[]>(sec->relocations.size());
}
}
}
// Store anchors (st_value and st_value+st_size) for symbols relative to text
// sections.
for (InputFile *file : ctx->objectFiles)
for (Symbol *sym : file->getSymbols()) {
auto *d = dyn_cast<Defined>(sym);
if (!d || d->file != file)
continue;
if (auto *sec = dyn_cast_or_null<InputSection>(d->section))
if (sec->flags & SHF_EXECINSTR && sec->relaxAux) {
// If sec is discarded, relaxAux will be nullptr.
sec->relaxAux->anchors.push_back({d->value, d, false});
sec->relaxAux->anchors.push_back({d->value + d->size, d, true});
}
}
// Sort anchors by offset so that we can find the closest relocation
// efficiently. For a zero size symbol, ensure that its start anchor precedes
// its end anchor. For two symbols with anchors at the same offset, their
// order does not matter.
for (OutputSection *osec : outputSections) {
if (!(osec->flags & SHF_EXECINSTR))
continue;
for (InputSection *sec : getInputSections(*osec, storage)) {
llvm::sort(sec->relaxAux->anchors, [](auto &a, auto &b) {
return std::make_pair(a.offset, a.end) <
std::make_pair(b.offset, b.end);
});
}
}
}
// Relax R_RISCV_CALL/R_RISCV_CALL_PLT auipc+jalr to c.j, c.jal, or jal.
static void relaxCall(const InputSection &sec, size_t i, uint64_t loc,
Relocation &r, uint32_t &remove) {
const bool rvc = config->eflags & EF_RISCV_RVC;
const Symbol &sym = *r.sym;
const uint64_t insnPair = read64le(sec.rawData.data() + r.offset);
const uint32_t rd = extractBits(insnPair, 32 + 11, 32 + 7);
const uint64_t dest =
(r.expr == R_PLT_PC ? sym.getPltVA() : sym.getVA()) + r.addend;
const int64_t displace = dest - loc;
if (rvc && isInt<12>(displace) && rd == 0) {
sec.relaxAux->relocTypes[i] = R_RISCV_RVC_JUMP;
sec.relaxAux->writes.push_back(0xa001); // c.j
remove = 6;
} else if (rvc && isInt<12>(displace) && rd == X_RA &&
!config->is64) { // RV32C only
sec.relaxAux->relocTypes[i] = R_RISCV_RVC_JUMP;
sec.relaxAux->writes.push_back(0x2001); // c.jal
remove = 6;
} else if (isInt<21>(displace)) {
sec.relaxAux->relocTypes[i] = R_RISCV_JAL;
sec.relaxAux->writes.push_back(0x6f | rd << 7); // jal
remove = 4;
}
}
// Relax local-exec TLS when hi20 is zero.
static void relaxTlsLe(const InputSection &sec, size_t i, uint64_t loc,
Relocation &r, uint32_t &remove) {
uint64_t val = r.sym->getVA(r.addend);
if (hi20(val) != 0)
return;
uint32_t insn = read32le(sec.rawData.data() + r.offset);
switch (r.type) {
case R_RISCV_TPREL_HI20:
case R_RISCV_TPREL_ADD:
// Remove lui rd, %tprel_hi(x) and add rd, rd, tp, %tprel_add(x).
sec.relaxAux->relocTypes[i] = R_RISCV_RELAX;
remove = 4;
break;
case R_RISCV_TPREL_LO12_I:
// addi rd, rd, %tprel_lo(x) => addi rd, tp, st_value(x)
sec.relaxAux->relocTypes[i] = R_RISCV_32;
insn = (insn & ~(31 << 15)) | (X_TP << 15);
sec.relaxAux->writes.push_back(setLO12_I(insn, val));
break;
case R_RISCV_TPREL_LO12_S:
// sw rs, %tprel_lo(x)(rd) => sw rs, st_value(x)(rd)
sec.relaxAux->relocTypes[i] = R_RISCV_32;
insn = (insn & ~(31 << 15)) | (X_TP << 15);
sec.relaxAux->writes.push_back(setLO12_S(insn, val));
break;
}
}
static bool relax(InputSection &sec) {
const uint64_t secAddr = sec.getVA();
auto &aux = *sec.relaxAux;
bool changed = false;
// Get st_value delta for symbols relative to this section from the previous
// iteration.
DenseMap<const Defined *, uint64_t> valueDelta;
ArrayRef<SymbolAnchor> sa = makeArrayRef(aux.anchors);
uint32_t delta = 0;
for (auto it : llvm::enumerate(sec.relocations)) {
for (; sa.size() && sa[0].offset <= it.value().offset; sa = sa.slice(1))
if (!sa[0].end)
valueDelta[sa[0].d] = delta;
delta = aux.relocDeltas[it.index()];
}
for (const SymbolAnchor &sa : sa)
if (!sa.end)
valueDelta[sa.d] = delta;
sa = makeArrayRef(aux.anchors);
delta = 0;
std::fill_n(aux.relocTypes.get(), sec.relocations.size(), R_RISCV_NONE);
aux.writes.clear();
for (auto it : llvm::enumerate(sec.relocations)) {
Relocation &r = it.value();
const size_t i = it.index();
const uint64_t loc = secAddr + r.offset - delta;
uint32_t &cur = aux.relocDeltas[i], remove = 0;
switch (r.type) {
case R_RISCV_ALIGN: {
const uint64_t nextLoc = loc + r.addend;
const uint64_t align = PowerOf2Ceil(r.addend + 2);
// All bytes beyond the alignment boundary should be removed.
remove = nextLoc - ((loc + align - 1) & -align);
assert(static_cast<int32_t>(remove) >= 0 &&
"R_RISCV_ALIGN needs expanding the content");
break;
}
case R_RISCV_CALL:
case R_RISCV_CALL_PLT:
if (i + 1 != sec.relocations.size() &&
sec.relocations[i + 1].type == R_RISCV_RELAX)
relaxCall(sec, i, loc, r, remove);
break;
case R_RISCV_TPREL_HI20:
case R_RISCV_TPREL_ADD:
case R_RISCV_TPREL_LO12_I:
case R_RISCV_TPREL_LO12_S:
if (i + 1 != sec.relocations.size() &&
sec.relocations[i + 1].type == R_RISCV_RELAX)
relaxTlsLe(sec, i, loc, r, remove);
break;
}
// For all anchors whose offsets are <= r.offset, they are preceded by
// the previous relocation whose `relocDeltas` value equals `delta`.
// Decrease their st_value and update their st_size.
for (; sa.size() && sa[0].offset <= r.offset; sa = sa.slice(1)) {
if (sa[0].end)
sa[0].d->size = sa[0].offset - delta - sa[0].d->value;
else
sa[0].d->value -= delta - valueDelta.find(sa[0].d)->second;
}
delta += remove;
if (delta != cur) {
cur = delta;
changed = true;
}
}
for (const SymbolAnchor &a : sa) {
if (a.end)
a.d->size = a.offset - delta - a.d->value;
else
a.d->value -= delta - valueDelta.find(a.d)->second;
}
// Inform assignAddresses that the size has changed.
if (!isUInt<16>(delta))
fatal("section size decrease is too large");
sec.bytesDropped = delta;
return changed;
}
// When relaxing just R_RISCV_ALIGN, relocDeltas is usually changed only once in
// the absence of a linker script. For call and load/store R_RISCV_RELAX, code
// shrinkage may reduce displacement and make more relocations eligible for
// relaxation. Code shrinkage may increase displacement to a call/load/store
// target at a higher fixed address, invalidating an earlier relaxation. Any
// change in section sizes can have cascading effect and require another
// relaxation pass.
bool RISCV::relaxOnce(int pass) const {
llvm::TimeTraceScope timeScope("RISC-V relaxOnce");
if (config->relocatable)
return false;
if (pass == 0)
initSymbolAnchors();
SmallVector<InputSection *, 0> storage;
bool changed = false;
for (OutputSection *osec : outputSections) {
if (!(osec->flags & SHF_EXECINSTR))
continue;
for (InputSection *sec : getInputSections(*osec, storage))
changed |= relax(*sec);
}
return changed;
}
void elf::riscvFinalizeRelax(int passes) {
llvm::TimeTraceScope timeScope("Finalize RISC-V relaxation");
log("relaxation passes: " + Twine(passes));
SmallVector<InputSection *, 0> storage;
for (OutputSection *osec : outputSections) {
if (!(osec->flags & SHF_EXECINSTR))
continue;
for (InputSection *sec : getInputSections(*osec, storage)) {
RISCVRelaxAux &aux = *sec->relaxAux;
if (!aux.relocDeltas)
continue;
auto &rels = sec->relocations;
ArrayRef<uint8_t> old = sec->rawData;
size_t newSize =
old.size() - aux.relocDeltas[sec->relocations.size() - 1];
size_t writesIdx = 0;
uint8_t *p = context().bAlloc.Allocate<uint8_t>(newSize);
uint64_t offset = 0;
int64_t delta = 0;
sec->rawData = makeArrayRef(p, newSize);
sec->bytesDropped = 0;
// Update section content: remove NOPs for R_RISCV_ALIGN and rewrite
// instructions for relaxed relocations.
for (size_t i = 0, e = rels.size(); i != e; ++i) {
uint32_t remove = aux.relocDeltas[i] - delta;
delta = aux.relocDeltas[i];
if (remove == 0 && aux.relocTypes[i] == R_RISCV_NONE)
continue;
// Copy from last location to the current relocated location.
const Relocation &r = rels[i];
uint64_t size = r.offset - offset;
memcpy(p, old.data() + offset, size);
p += size;
// For R_RISCV_ALIGN, we will place `offset` in a location (among NOPs)
- // to satisfy the alignment requirement. If `remove` is a multiple of 4,
- // it is as if we have skipped some NOPs. Otherwise we are in the middle
- // of a 4-byte NOP, and we need to rewrite the NOP sequence.
+ // to satisfy the alignment requirement. If both `remove` and r.addend
+ // are multiples of 4, it is as if we have skipped some NOPs. Otherwise
+ // we are in the middle of a 4-byte NOP, and we need to rewrite the NOP
+ // sequence.
int64_t skip = 0;
if (r.type == R_RISCV_ALIGN) {
- if (remove % 4 != 0) {
+ if (remove % 4 || r.addend % 4) {
skip = r.addend - remove;
int64_t j = 0;
for (; j + 4 <= skip; j += 4)
write32le(p + j, 0x00000013); // nop
if (j != skip) {
assert(j + 2 == skip);
write16le(p + j, 0x0001); // c.nop
}
}
} else if (RelType newType = aux.relocTypes[i]) {
switch (newType) {
case R_RISCV_RELAX:
// Used by relaxTlsLe to indicate the relocation is ignored.
break;
case R_RISCV_RVC_JUMP:
skip = 2;
write16le(p, aux.writes[writesIdx++]);
break;
case R_RISCV_JAL:
skip = 4;
write32le(p, aux.writes[writesIdx++]);
break;
case R_RISCV_32:
// Used by relaxTlsLe to write a uint32_t then suppress the handling
// in relocateAlloc.
skip = 4;
write32le(p, aux.writes[writesIdx++]);
aux.relocTypes[i] = R_RISCV_NONE;
break;
default:
llvm_unreachable("unsupported type");
}
}
p += skip;
offset = r.offset + skip + remove;
}
memcpy(p, old.data() + offset, old.size() - offset);
// Subtract the previous relocDeltas value from the relocation offset.
// For a pair of R_RISCV_CALL/R_RISCV_RELAX with the same offset, decrease
// their r_offset by the same delta.
delta = 0;
for (size_t i = 0, e = rels.size(); i != e;) {
uint64_t cur = rels[i].offset;
do {
rels[i].offset -= delta;
if (aux.relocTypes[i] != R_RISCV_NONE)
rels[i].type = aux.relocTypes[i];
} while (++i != e && rels[i].offset == cur);
delta = aux.relocDeltas[i - 1];
}
}
}
}
TargetInfo *elf::getRISCVTargetInfo() {
static RISCV target;
return &target;
}
diff --git a/contrib/llvm-project/lld/MachO/InputFiles.cpp b/contrib/llvm-project/lld/MachO/InputFiles.cpp
index fd0e4ec8834c..87034d41e87d 100644
--- a/contrib/llvm-project/lld/MachO/InputFiles.cpp
+++ b/contrib/llvm-project/lld/MachO/InputFiles.cpp
@@ -1,2314 +1,2323 @@
//===- InputFiles.cpp -----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains functions to parse Mach-O object files. In this comment,
// we describe the Mach-O file structure and how we parse it.
//
// Mach-O is not very different from ELF or COFF. The notion of symbols,
// sections and relocations exists in Mach-O as it does in ELF and COFF.
//
// Perhaps the notion that is new to those who know ELF/COFF is "subsections".
// In ELF/COFF, sections are an atomic unit of data copied from input files to
// output files. When we merge or garbage-collect sections, we treat each
// section as an atomic unit. In Mach-O, that's not the case. Sections can
// consist of multiple subsections, and subsections are a unit of merging and
// garbage-collecting. Therefore, Mach-O's subsections are more similar to
// ELF/COFF's sections than Mach-O's sections are.
//
// A section can have multiple symbols. A symbol that does not have the
// N_ALT_ENTRY attribute indicates a beginning of a subsection. Therefore, by
// definition, a symbol is always present at the beginning of each subsection. A
// symbol with N_ALT_ENTRY attribute does not start a new subsection and can
// point to a middle of a subsection.
//
// The notion of subsections also affects how relocations are represented in
// Mach-O. All references within a section need to be explicitly represented as
// relocations if they refer to different subsections, because we obviously need
// to fix up addresses if subsections are laid out in an output file differently
// than they were in object files. To represent that, Mach-O relocations can
// refer to an unnamed location via its address. Scattered relocations (those
// with the R_SCATTERED bit set) always refer to unnamed locations.
// Non-scattered relocations refer to an unnamed location if r_extern is not set
// and r_symbolnum is zero.
//
// Without the above differences, I think you can use your knowledge about ELF
// and COFF for Mach-O.
//
//===----------------------------------------------------------------------===//
#include "InputFiles.h"
#include "Config.h"
#include "Driver.h"
#include "Dwarf.h"
#include "EhFrame.h"
#include "ExportTrie.h"
#include "InputSection.h"
#include "MachOStructs.h"
#include "ObjC.h"
#include "OutputSection.h"
#include "OutputSegment.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/DWARF.h"
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/iterator.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/TextAPI/Architecture.h"
#include "llvm/TextAPI/InterfaceFile.h"
#include <type_traits>
using namespace llvm;
using namespace llvm::MachO;
using namespace llvm::support::endian;
using namespace llvm::sys;
using namespace lld;
using namespace lld::macho;
// Returns "<internal>", "foo.a(bar.o)", or "baz.o".
std::string lld::toString(const InputFile *f) {
if (!f)
return "<internal>";
// Multiple dylibs can be defined in one .tbd file.
if (auto dylibFile = dyn_cast<DylibFile>(f))
if (f->getName().endswith(".tbd"))
return (f->getName() + "(" + dylibFile->installName + ")").str();
if (f->archiveName.empty())
return std::string(f->getName());
return (f->archiveName + "(" + path::filename(f->getName()) + ")").str();
}
std::string lld::toString(const Section &sec) {
return (toString(sec.file) + ":(" + sec.name + ")").str();
}
SetVector<InputFile *> macho::inputFiles;
std::unique_ptr<TarWriter> macho::tar;
int InputFile::idCount = 0;
static VersionTuple decodeVersion(uint32_t version) {
unsigned major = version >> 16;
unsigned minor = (version >> 8) & 0xffu;
unsigned subMinor = version & 0xffu;
return VersionTuple(major, minor, subMinor);
}
static std::vector<PlatformInfo> getPlatformInfos(const InputFile *input) {
if (!isa<ObjFile>(input) && !isa<DylibFile>(input))
return {};
const char *hdr = input->mb.getBufferStart();
// "Zippered" object files can have multiple LC_BUILD_VERSION load commands.
std::vector<PlatformInfo> platformInfos;
for (auto *cmd : findCommands<build_version_command>(hdr, LC_BUILD_VERSION)) {
PlatformInfo info;
info.target.Platform = static_cast<PlatformType>(cmd->platform);
info.minimum = decodeVersion(cmd->minos);
platformInfos.emplace_back(std::move(info));
}
for (auto *cmd : findCommands<version_min_command>(
hdr, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS,
LC_VERSION_MIN_TVOS, LC_VERSION_MIN_WATCHOS)) {
PlatformInfo info;
switch (cmd->cmd) {
case LC_VERSION_MIN_MACOSX:
info.target.Platform = PLATFORM_MACOS;
break;
case LC_VERSION_MIN_IPHONEOS:
info.target.Platform = PLATFORM_IOS;
break;
case LC_VERSION_MIN_TVOS:
info.target.Platform = PLATFORM_TVOS;
break;
case LC_VERSION_MIN_WATCHOS:
info.target.Platform = PLATFORM_WATCHOS;
break;
}
info.minimum = decodeVersion(cmd->version);
platformInfos.emplace_back(std::move(info));
}
return platformInfos;
}
static bool checkCompatibility(const InputFile *input) {
std::vector<PlatformInfo> platformInfos = getPlatformInfos(input);
if (platformInfos.empty())
return true;
auto it = find_if(platformInfos, [&](const PlatformInfo &info) {
return removeSimulator(info.target.Platform) ==
removeSimulator(config->platform());
});
if (it == platformInfos.end()) {
std::string platformNames;
raw_string_ostream os(platformNames);
interleave(
platformInfos, os,
[&](const PlatformInfo &info) {
os << getPlatformName(info.target.Platform);
},
"/");
error(toString(input) + " has platform " + platformNames +
Twine(", which is different from target platform ") +
getPlatformName(config->platform()));
return false;
}
if (it->minimum > config->platformInfo.minimum)
warn(toString(input) + " has version " + it->minimum.getAsString() +
", which is newer than target minimum of " +
config->platformInfo.minimum.getAsString());
return true;
}
// This cache mostly exists to store system libraries (and .tbds) as they're
// loaded, rather than the input archives, which are already cached at a higher
// level, and other files like the filelist that are only read once.
// Theoretically this caching could be more efficient by hoisting it, but that
// would require altering many callers to track the state.
DenseMap<CachedHashStringRef, MemoryBufferRef> macho::cachedReads;
// Open a given file path and return it as a memory-mapped file.
Optional<MemoryBufferRef> macho::readFile(StringRef path) {
CachedHashStringRef key(path);
auto entry = cachedReads.find(key);
if (entry != cachedReads.end())
return entry->second;
ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = MemoryBuffer::getFile(path);
if (std::error_code ec = mbOrErr.getError()) {
error("cannot open " + path + ": " + ec.message());
return None;
}
std::unique_ptr<MemoryBuffer> &mb = *mbOrErr;
MemoryBufferRef mbref = mb->getMemBufferRef();
make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); // take mb ownership
// If this is a regular non-fat file, return it.
const char *buf = mbref.getBufferStart();
const auto *hdr = reinterpret_cast<const fat_header *>(buf);
if (mbref.getBufferSize() < sizeof(uint32_t) ||
read32be(&hdr->magic) != FAT_MAGIC) {
if (tar)
tar->append(relativeToRoot(path), mbref.getBuffer());
return cachedReads[key] = mbref;
}
llvm::BumpPtrAllocator &bAlloc = lld::bAlloc();
// Object files and archive files may be fat files, which contain multiple
// real files for different CPU ISAs. Here, we search for a file that matches
// with the current link target and returns it as a MemoryBufferRef.
const auto *arch = reinterpret_cast<const fat_arch *>(buf + sizeof(*hdr));
for (uint32_t i = 0, n = read32be(&hdr->nfat_arch); i < n; ++i) {
if (reinterpret_cast<const char *>(arch + i + 1) >
buf + mbref.getBufferSize()) {
error(path + ": fat_arch struct extends beyond end of file");
return None;
}
if (read32be(&arch[i].cputype) != static_cast<uint32_t>(target->cpuType) ||
read32be(&arch[i].cpusubtype) != target->cpuSubtype)
continue;
uint32_t offset = read32be(&arch[i].offset);
uint32_t size = read32be(&arch[i].size);
if (offset + size > mbref.getBufferSize())
error(path + ": slice extends beyond end of file");
if (tar)
tar->append(relativeToRoot(path), mbref.getBuffer());
return cachedReads[key] = MemoryBufferRef(StringRef(buf + offset, size),
path.copy(bAlloc));
}
error("unable to find matching architecture in " + path);
return None;
}
InputFile::InputFile(Kind kind, const InterfaceFile &interface)
: id(idCount++), fileKind(kind), name(saver().save(interface.getPath())) {}
// Some sections comprise of fixed-size records, so instead of splitting them at
// symbol boundaries, we split them based on size. Records are distinct from
// literals in that they may contain references to other sections, instead of
// being leaf nodes in the InputSection graph.
//
// Note that "record" is a term I came up with. In contrast, "literal" is a term
// used by the Mach-O format.
static Optional<size_t> getRecordSize(StringRef segname, StringRef name) {
if (name == section_names::compactUnwind) {
if (segname == segment_names::ld)
return target->wordSize == 8 ? 32 : 20;
}
if (!config->dedupLiterals)
return {};
if (name == section_names::cfString && segname == segment_names::data)
return target->wordSize == 8 ? 32 : 16;
if (config->icfLevel == ICFLevel::none)
return {};
if (name == section_names::objcClassRefs && segname == segment_names::data)
return target->wordSize;
return {};
}
static Error parseCallGraph(ArrayRef<uint8_t> data,
std::vector<CallGraphEntry> &callGraph) {
TimeTraceScope timeScope("Parsing call graph section");
BinaryStreamReader reader(data, support::little);
while (!reader.empty()) {
uint32_t fromIndex, toIndex;
uint64_t count;
if (Error err = reader.readInteger(fromIndex))
return err;
if (Error err = reader.readInteger(toIndex))
return err;
if (Error err = reader.readInteger(count))
return err;
callGraph.emplace_back(fromIndex, toIndex, count);
}
return Error::success();
}
// Parse the sequence of sections within a single LC_SEGMENT(_64).
// Split each section into subsections.
template <class SectionHeader>
void ObjFile::parseSections(ArrayRef<SectionHeader> sectionHeaders) {
sections.reserve(sectionHeaders.size());
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
for (const SectionHeader &sec : sectionHeaders) {
StringRef name =
StringRef(sec.sectname, strnlen(sec.sectname, sizeof(sec.sectname)));
StringRef segname =
StringRef(sec.segname, strnlen(sec.segname, sizeof(sec.segname)));
sections.push_back(make<Section>(this, segname, name, sec.flags, sec.addr));
if (sec.align >= 32) {
error("alignment " + std::to_string(sec.align) + " of section " + name +
" is too large");
continue;
}
Section &section = *sections.back();
uint32_t align = 1 << sec.align;
ArrayRef<uint8_t> data = {isZeroFill(sec.flags) ? nullptr
: buf + sec.offset,
static_cast<size_t>(sec.size)};
auto splitRecords = [&](int recordSize) -> void {
if (data.empty())
return;
Subsections &subsections = section.subsections;
subsections.reserve(data.size() / recordSize);
for (uint64_t off = 0; off < data.size(); off += recordSize) {
auto *isec = make<ConcatInputSection>(
section, data.slice(off, recordSize), align);
subsections.push_back({off, isec});
}
section.doneSplitting = true;
};
if (sectionType(sec.flags) == S_CSTRING_LITERALS ||
(config->dedupLiterals && isWordLiteralSection(sec.flags))) {
if (sec.nreloc && config->dedupLiterals)
fatal(toString(this) + " contains relocations in " + sec.segname + "," +
sec.sectname +
", so LLD cannot deduplicate literals. Try re-running without "
"--deduplicate-literals.");
InputSection *isec;
if (sectionType(sec.flags) == S_CSTRING_LITERALS) {
isec = make<CStringInputSection>(section, data, align);
// FIXME: parallelize this?
cast<CStringInputSection>(isec)->splitIntoPieces();
} else {
isec = make<WordLiteralInputSection>(section, data, align);
}
section.subsections.push_back({0, isec});
} else if (auto recordSize = getRecordSize(segname, name)) {
splitRecords(*recordSize);
} else if (name == section_names::ehFrame &&
segname == segment_names::text) {
splitEhFrames(data, *sections.back());
} else if (segname == segment_names::llvm) {
if (config->callGraphProfileSort && name == section_names::cgProfile)
checkError(parseCallGraph(data, callGraph));
// ld64 does not appear to emit contents from sections within the __LLVM
// segment. Symbols within those sections point to bitcode metadata
// instead of actual symbols. Global symbols within those sections could
// have the same name without causing duplicate symbol errors. To avoid
// spurious duplicate symbol errors, we do not parse these sections.
// TODO: Evaluate whether the bitcode metadata is needed.
} else if (name == section_names::objCImageInfo &&
segname == segment_names::data) {
objCImageInfo = data;
} else {
if (name == section_names::addrSig)
addrSigSection = sections.back();
auto *isec = make<ConcatInputSection>(section, data, align);
if (isDebugSection(isec->getFlags()) &&
isec->getSegName() == segment_names::dwarf) {
// Instead of emitting DWARF sections, we emit STABS symbols to the
// object files that contain them. We filter them out early to avoid
// parsing their relocations unnecessarily.
debugSections.push_back(isec);
} else {
section.subsections.push_back({0, isec});
}
}
}
}
void ObjFile::splitEhFrames(ArrayRef<uint8_t> data, Section &ehFrameSection) {
EhReader reader(this, data, /*dataOff=*/0);
size_t off = 0;
while (off < reader.size()) {
uint64_t frameOff = off;
uint64_t length = reader.readLength(&off);
if (length == 0)
break;
uint64_t fullLength = length + (off - frameOff);
off += length;
// We hard-code an alignment of 1 here because we don't actually want our
// EH frames to be aligned to the section alignment. EH frame decoders don't
// expect this alignment. Moreover, each EH frame must start where the
// previous one ends, and where it ends is indicated by the length field.
// Unless we update the length field (troublesome), we should keep the
// alignment to 1.
// Note that we still want to preserve the alignment of the overall section,
// just not of the individual EH frames.
ehFrameSection.subsections.push_back(
{frameOff, make<ConcatInputSection>(ehFrameSection,
data.slice(frameOff, fullLength),
/*align=*/1)});
}
ehFrameSection.doneSplitting = true;
}
template <class T>
static Section *findContainingSection(const std::vector<Section *> &sections,
T *offset) {
static_assert(std::is_same<uint64_t, T>::value ||
std::is_same<uint32_t, T>::value,
"unexpected type for offset");
auto it = std::prev(llvm::upper_bound(
sections, *offset,
[](uint64_t value, const Section *sec) { return value < sec->addr; }));
*offset -= (*it)->addr;
return *it;
}
// Find the subsection corresponding to the greatest section offset that is <=
// that of the given offset.
//
// offset: an offset relative to the start of the original InputSection (before
// any subsection splitting has occurred). It will be updated to represent the
// same location as an offset relative to the start of the containing
// subsection.
template <class T>
static InputSection *findContainingSubsection(const Section &section,
T *offset) {
static_assert(std::is_same<uint64_t, T>::value ||
std::is_same<uint32_t, T>::value,
"unexpected type for offset");
auto it = std::prev(llvm::upper_bound(
section.subsections, *offset,
[](uint64_t value, Subsection subsec) { return value < subsec.offset; }));
*offset -= it->offset;
return it->isec;
}
// Find a symbol at offset `off` within `isec`.
static Defined *findSymbolAtOffset(const ConcatInputSection *isec,
uint64_t off) {
auto it = llvm::lower_bound(isec->symbols, off, [](Defined *d, uint64_t off) {
return d->value < off;
});
// The offset should point at the exact address of a symbol (with no addend.)
if (it == isec->symbols.end() || (*it)->value != off) {
assert(isec->wasCoalesced);
return nullptr;
}
return *it;
}
// Linker optimization hints mark a sequence of instructions used for
// synthesizing an address which that be transformed into a faster sequence. The
// transformations depend on conditions that are determined at link time, like
// the distance to the referenced symbol or its alignment.
//
// Each hint has a type and refers to 2 or 3 instructions. Each of those
// instructions must have a corresponding relocation. After addresses have been
// finalized and relocations have been performed, we check if the requirements
// hold, and perform the optimizations if they do.
//
// Similar linker relaxations exist for ELF as well, with the difference being
// that the explicit marking allows for the relaxation of non-consecutive
// relocations too.
//
// The specific types of hints are documented in Arch/ARM64.cpp
void ObjFile::parseOptimizationHints(ArrayRef<uint8_t> data) {
auto expectedArgCount = [](uint8_t type) {
switch (type) {
case LOH_ARM64_ADRP_ADRP:
case LOH_ARM64_ADRP_LDR:
case LOH_ARM64_ADRP_ADD:
case LOH_ARM64_ADRP_LDR_GOT:
return 2;
case LOH_ARM64_ADRP_ADD_LDR:
case LOH_ARM64_ADRP_ADD_STR:
case LOH_ARM64_ADRP_LDR_GOT_LDR:
case LOH_ARM64_ADRP_LDR_GOT_STR:
return 3;
}
return -1;
};
// Each hint contains at least 4 ULEB128-encoded fields, so in the worst case,
// there are data.size() / 4 LOHs. It's a huge overestimation though, as
// offsets are unlikely to fall in the 0-127 byte range, so we pre-allocate
// half as much.
optimizationHints.reserve(data.size() / 8);
for (const uint8_t *p = data.begin(); p < data.end();) {
const ptrdiff_t inputOffset = p - data.begin();
unsigned int n = 0;
uint8_t type = decodeULEB128(p, &n, data.end());
p += n;
// An entry of type 0 terminates the list.
if (type == 0)
break;
int expectedCount = expectedArgCount(type);
if (LLVM_UNLIKELY(expectedCount == -1)) {
error("Linker optimization hint at offset " + Twine(inputOffset) +
" has unknown type " + Twine(type));
return;
}
uint8_t argCount = decodeULEB128(p, &n, data.end());
p += n;
if (LLVM_UNLIKELY(argCount != expectedCount)) {
error("Linker optimization hint at offset " + Twine(inputOffset) +
" has " + Twine(argCount) + " arguments instead of the expected " +
Twine(expectedCount));
return;
}
uint64_t offset0 = decodeULEB128(p, &n, data.end());
p += n;
int16_t delta[2];
for (int i = 0; i < argCount - 1; ++i) {
uint64_t address = decodeULEB128(p, &n, data.end());
p += n;
int64_t d = address - offset0;
if (LLVM_UNLIKELY(d > std::numeric_limits<int16_t>::max() ||
d < std::numeric_limits<int16_t>::min())) {
error("Linker optimization hint at offset " + Twine(inputOffset) +
" has addresses too far apart");
return;
}
delta[i] = d;
}
optimizationHints.push_back({offset0, {delta[0], delta[1]}, type});
}
// We sort the per-object vector of optimization hints so each section only
// needs to hold an ArrayRef to a contiguous range of hints.
llvm::sort(optimizationHints,
[](const OptimizationHint &a, const OptimizationHint &b) {
return a.offset0 < b.offset0;
});
auto section = sections.begin();
auto subsection = (*section)->subsections.begin();
uint64_t subsectionBase = 0;
uint64_t subsectionEnd = 0;
auto updateAddr = [&]() {
subsectionBase = (*section)->addr + subsection->offset;
subsectionEnd = subsectionBase + subsection->isec->getSize();
};
auto advanceSubsection = [&]() {
if (section == sections.end())
return;
++subsection;
while (subsection == (*section)->subsections.end()) {
++section;
if (section == sections.end())
return;
subsection = (*section)->subsections.begin();
}
};
updateAddr();
auto hintStart = optimizationHints.begin();
for (auto hintEnd = hintStart, end = optimizationHints.end(); hintEnd != end;
++hintEnd) {
if (hintEnd->offset0 >= subsectionEnd) {
subsection->isec->optimizationHints =
ArrayRef<OptimizationHint>(&*hintStart, hintEnd - hintStart);
hintStart = hintEnd;
while (hintStart->offset0 >= subsectionEnd) {
advanceSubsection();
if (section == sections.end())
break;
updateAddr();
assert(hintStart->offset0 >= subsectionBase);
}
}
hintEnd->offset0 -= subsectionBase;
for (int i = 0, count = expectedArgCount(hintEnd->type); i < count - 1;
++i) {
if (LLVM_UNLIKELY(
hintEnd->delta[i] < -static_cast<int64_t>(hintEnd->offset0) ||
hintEnd->delta[i] >=
static_cast<int64_t>(subsectionEnd - hintEnd->offset0))) {
error("Linker optimization hint spans multiple sections");
return;
}
}
}
if (section != sections.end())
subsection->isec->optimizationHints = ArrayRef<OptimizationHint>(
&*hintStart, optimizationHints.end() - hintStart);
}
template <class SectionHeader>
static bool validateRelocationInfo(InputFile *file, const SectionHeader &sec,
relocation_info rel) {
const RelocAttrs &relocAttrs = target->getRelocAttrs(rel.r_type);
bool valid = true;
auto message = [relocAttrs, file, sec, rel, &valid](const Twine &diagnostic) {
valid = false;
return (relocAttrs.name + " relocation " + diagnostic + " at offset " +
std::to_string(rel.r_address) + " of " + sec.segname + "," +
sec.sectname + " in " + toString(file))
.str();
};
if (!relocAttrs.hasAttr(RelocAttrBits::LOCAL) && !rel.r_extern)
error(message("must be extern"));
if (relocAttrs.hasAttr(RelocAttrBits::PCREL) != rel.r_pcrel)
error(message(Twine("must ") + (rel.r_pcrel ? "not " : "") +
"be PC-relative"));
if (isThreadLocalVariables(sec.flags) &&
!relocAttrs.hasAttr(RelocAttrBits::UNSIGNED))
error(message("not allowed in thread-local section, must be UNSIGNED"));
if (rel.r_length < 2 || rel.r_length > 3 ||
!relocAttrs.hasAttr(static_cast<RelocAttrBits>(1 << rel.r_length))) {
static SmallVector<StringRef, 4> widths{"0", "4", "8", "4 or 8"};
error(message("has width " + std::to_string(1 << rel.r_length) +
" bytes, but must be " +
widths[(static_cast<int>(relocAttrs.bits) >> 2) & 3] +
" bytes"));
}
return valid;
}
template <class SectionHeader>
void ObjFile::parseRelocations(ArrayRef<SectionHeader> sectionHeaders,
const SectionHeader &sec, Section &section) {
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
ArrayRef<relocation_info> relInfos(
reinterpret_cast<const relocation_info *>(buf + sec.reloff), sec.nreloc);
Subsections &subsections = section.subsections;
auto subsecIt = subsections.rbegin();
for (size_t i = 0; i < relInfos.size(); i++) {
// Paired relocations serve as Mach-O's method for attaching a
// supplemental datum to a primary relocation record. ELF does not
// need them because the *_RELOC_RELA records contain the extra
// addend field, vs. *_RELOC_REL which omit the addend.
//
// The {X86_64,ARM64}_RELOC_SUBTRACTOR record holds the subtrahend,
// and the paired *_RELOC_UNSIGNED record holds the minuend. The
// datum for each is a symbolic address. The result is the offset
// between two addresses.
//
// The ARM64_RELOC_ADDEND record holds the addend, and the paired
// ARM64_RELOC_BRANCH26 or ARM64_RELOC_PAGE21/PAGEOFF12 holds the
// base symbolic address.
//
// Note: X86 does not use *_RELOC_ADDEND because it can embed an
// addend into the instruction stream. On X86, a relocatable address
// field always occupies an entire contiguous sequence of byte(s),
// so there is no need to merge opcode bits with address
// bits. Therefore, it's easy and convenient to store addends in the
// instruction-stream bytes that would otherwise contain zeroes. By
// contrast, RISC ISAs such as ARM64 mix opcode bits with with
// address bits so that bitwise arithmetic is necessary to extract
// and insert them. Storing addends in the instruction stream is
// possible, but inconvenient and more costly at link time.
relocation_info relInfo = relInfos[i];
bool isSubtrahend =
target->hasAttr(relInfo.r_type, RelocAttrBits::SUBTRAHEND);
int64_t pairedAddend = 0;
if (target->hasAttr(relInfo.r_type, RelocAttrBits::ADDEND)) {
pairedAddend = SignExtend64<24>(relInfo.r_symbolnum);
relInfo = relInfos[++i];
}
assert(i < relInfos.size());
if (!validateRelocationInfo(this, sec, relInfo))
continue;
if (relInfo.r_address & R_SCATTERED)
fatal("TODO: Scattered relocations not supported");
int64_t embeddedAddend = target->getEmbeddedAddend(mb, sec.offset, relInfo);
assert(!(embeddedAddend && pairedAddend));
int64_t totalAddend = pairedAddend + embeddedAddend;
Reloc r;
r.type = relInfo.r_type;
r.pcrel = relInfo.r_pcrel;
r.length = relInfo.r_length;
r.offset = relInfo.r_address;
if (relInfo.r_extern) {
r.referent = symbols[relInfo.r_symbolnum];
r.addend = isSubtrahend ? 0 : totalAddend;
} else {
assert(!isSubtrahend);
const SectionHeader &referentSecHead =
sectionHeaders[relInfo.r_symbolnum - 1];
uint64_t referentOffset;
if (relInfo.r_pcrel) {
// The implicit addend for pcrel section relocations is the pcrel offset
// in terms of the addresses in the input file. Here we adjust it so
// that it describes the offset from the start of the referent section.
// FIXME This logic was written around x86_64 behavior -- ARM64 doesn't
// have pcrel section relocations. We may want to factor this out into
// the arch-specific .cpp file.
assert(target->hasAttr(r.type, RelocAttrBits::BYTE4));
referentOffset = sec.addr + relInfo.r_address + 4 + totalAddend -
referentSecHead.addr;
} else {
// The addend for a non-pcrel relocation is its absolute address.
referentOffset = totalAddend - referentSecHead.addr;
}
r.referent = findContainingSubsection(*sections[relInfo.r_symbolnum - 1],
&referentOffset);
r.addend = referentOffset;
}
// Find the subsection that this relocation belongs to.
// Though not required by the Mach-O format, clang and gcc seem to emit
// relocations in order, so let's take advantage of it. However, ld64 emits
// unsorted relocations (in `-r` mode), so we have a fallback for that
// uncommon case.
InputSection *subsec;
while (subsecIt != subsections.rend() && subsecIt->offset > r.offset)
++subsecIt;
if (subsecIt == subsections.rend() ||
subsecIt->offset + subsecIt->isec->getSize() <= r.offset) {
subsec = findContainingSubsection(section, &r.offset);
// Now that we know the relocs are unsorted, avoid trying the 'fast path'
// for the other relocations.
subsecIt = subsections.rend();
} else {
subsec = subsecIt->isec;
r.offset -= subsecIt->offset;
}
subsec->relocs.push_back(r);
if (isSubtrahend) {
relocation_info minuendInfo = relInfos[++i];
// SUBTRACTOR relocations should always be followed by an UNSIGNED one
// attached to the same address.
assert(target->hasAttr(minuendInfo.r_type, RelocAttrBits::UNSIGNED) &&
relInfo.r_address == minuendInfo.r_address);
Reloc p;
p.type = minuendInfo.r_type;
if (minuendInfo.r_extern) {
p.referent = symbols[minuendInfo.r_symbolnum];
p.addend = totalAddend;
} else {
uint64_t referentOffset =
totalAddend - sectionHeaders[minuendInfo.r_symbolnum - 1].addr;
p.referent = findContainingSubsection(
*sections[minuendInfo.r_symbolnum - 1], &referentOffset);
p.addend = referentOffset;
}
subsec->relocs.push_back(p);
}
}
}
template <class NList>
static macho::Symbol *createDefined(const NList &sym, StringRef name,
InputSection *isec, uint64_t value,
uint64_t size, bool forceHidden) {
// Symbol scope is determined by sym.n_type & (N_EXT | N_PEXT):
// N_EXT: Global symbols. These go in the symbol table during the link,
// and also in the export table of the output so that the dynamic
// linker sees them.
// N_EXT | N_PEXT: Linkage unit (think: dylib) scoped. These go in the
// symbol table during the link so that duplicates are
// either reported (for non-weak symbols) or merged
// (for weak symbols), but they do not go in the export
// table of the output.
// N_PEXT: llvm-mc does not emit these, but `ld -r` (wherein ld64 emits
// object files) may produce them. LLD does not yet support -r.
// These are translation-unit scoped, identical to the `0` case.
// 0: Translation-unit scoped. These are not in the symbol table during
// link, and not in the export table of the output either.
bool isWeakDefCanBeHidden =
(sym.n_desc & (N_WEAK_DEF | N_WEAK_REF)) == (N_WEAK_DEF | N_WEAK_REF);
if (sym.n_type & N_EXT) {
// -load_hidden makes us treat global symbols as linkage unit scoped.
// Duplicates are reported but the symbol does not go in the export trie.
bool isPrivateExtern = sym.n_type & N_PEXT || forceHidden;
// lld's behavior for merging symbols is slightly different from ld64:
// ld64 picks the winning symbol based on several criteria (see
// pickBetweenRegularAtoms() in ld64's SymbolTable.cpp), while lld
// just merges metadata and keeps the contents of the first symbol
// with that name (see SymbolTable::addDefined). For:
// * inline function F in a TU built with -fvisibility-inlines-hidden
// * and inline function F in another TU built without that flag
// ld64 will pick the one from the file built without
// -fvisibility-inlines-hidden.
// lld will instead pick the one listed first on the link command line and
// give it visibility as if the function was built without
// -fvisibility-inlines-hidden.
// If both functions have the same contents, this will have the same
// behavior. If not, it won't, but the input had an ODR violation in
// that case.
//
// Similarly, merging a symbol
// that's isPrivateExtern and not isWeakDefCanBeHidden with one
// that's not isPrivateExtern but isWeakDefCanBeHidden technically
// should produce one
// that's not isPrivateExtern but isWeakDefCanBeHidden. That matters
// with ld64's semantics, because it means the non-private-extern
// definition will continue to take priority if more private extern
// definitions are encountered. With lld's semantics there's no observable
// difference between a symbol that's isWeakDefCanBeHidden(autohide) or one
// that's privateExtern -- neither makes it into the dynamic symbol table,
// unless the autohide symbol is explicitly exported.
// But if a symbol is both privateExtern and autohide then it can't
// be exported.
// So we nullify the autohide flag when privateExtern is present
// and promote the symbol to privateExtern when it is not already.
if (isWeakDefCanBeHidden && isPrivateExtern)
isWeakDefCanBeHidden = false;
else if (isWeakDefCanBeHidden)
isPrivateExtern = true;
return symtab->addDefined(
name, isec->getFile(), isec, value, size, sym.n_desc & N_WEAK_DEF,
isPrivateExtern, sym.n_desc & N_ARM_THUMB_DEF,
sym.n_desc & REFERENCED_DYNAMICALLY, sym.n_desc & N_NO_DEAD_STRIP,
isWeakDefCanBeHidden);
}
assert(!isWeakDefCanBeHidden &&
"weak_def_can_be_hidden on already-hidden symbol?");
bool includeInSymtab =
!name.startswith("l") && !name.startswith("L") && !isEhFrameSection(isec);
return make<Defined>(
name, isec->getFile(), isec, value, size, sym.n_desc & N_WEAK_DEF,
/*isExternal=*/false, /*isPrivateExtern=*/false, includeInSymtab,
sym.n_desc & N_ARM_THUMB_DEF, sym.n_desc & REFERENCED_DYNAMICALLY,
sym.n_desc & N_NO_DEAD_STRIP);
}
// Absolute symbols are defined symbols that do not have an associated
// InputSection. They cannot be weak.
template <class NList>
static macho::Symbol *createAbsolute(const NList &sym, InputFile *file,
StringRef name, bool forceHidden) {
if (sym.n_type & N_EXT) {
bool isPrivateExtern = sym.n_type & N_PEXT || forceHidden;
return symtab->addDefined(
name, file, nullptr, sym.n_value, /*size=*/0,
/*isWeakDef=*/false, isPrivateExtern, sym.n_desc & N_ARM_THUMB_DEF,
/*isReferencedDynamically=*/false, sym.n_desc & N_NO_DEAD_STRIP,
/*isWeakDefCanBeHidden=*/false);
}
return make<Defined>(name, file, nullptr, sym.n_value, /*size=*/0,
/*isWeakDef=*/false,
/*isExternal=*/false, /*isPrivateExtern=*/false,
/*includeInSymtab=*/true, sym.n_desc & N_ARM_THUMB_DEF,
/*isReferencedDynamically=*/false,
sym.n_desc & N_NO_DEAD_STRIP);
}
template <class NList>
macho::Symbol *ObjFile::parseNonSectionSymbol(const NList &sym,
StringRef name) {
uint8_t type = sym.n_type & N_TYPE;
bool isPrivateExtern = sym.n_type & N_PEXT || forceHidden;
switch (type) {
case N_UNDF:
return sym.n_value == 0
? symtab->addUndefined(name, this, sym.n_desc & N_WEAK_REF)
: symtab->addCommon(name, this, sym.n_value,
1 << GET_COMM_ALIGN(sym.n_desc),
isPrivateExtern);
case N_ABS:
return createAbsolute(sym, this, name, forceHidden);
case N_PBUD:
case N_INDR:
error("TODO: support symbols of type " + std::to_string(type));
return nullptr;
case N_SECT:
llvm_unreachable(
"N_SECT symbols should not be passed to parseNonSectionSymbol");
default:
llvm_unreachable("invalid symbol type");
}
}
template <class NList> static bool isUndef(const NList &sym) {
return (sym.n_type & N_TYPE) == N_UNDF && sym.n_value == 0;
}
template <class LP>
void ObjFile::parseSymbols(ArrayRef<typename LP::section> sectionHeaders,
ArrayRef<typename LP::nlist> nList,
const char *strtab, bool subsectionsViaSymbols) {
using NList = typename LP::nlist;
// Groups indices of the symbols by the sections that contain them.
std::vector<std::vector<uint32_t>> symbolsBySection(sections.size());
symbols.resize(nList.size());
SmallVector<unsigned, 32> undefineds;
for (uint32_t i = 0; i < nList.size(); ++i) {
const NList &sym = nList[i];
// Ignore debug symbols for now.
// FIXME: may need special handling.
if (sym.n_type & N_STAB)
continue;
if ((sym.n_type & N_TYPE) == N_SECT) {
Subsections &subsections = sections[sym.n_sect - 1]->subsections;
// parseSections() may have chosen not to parse this section.
if (subsections.empty())
continue;
symbolsBySection[sym.n_sect - 1].push_back(i);
} else if (isUndef(sym)) {
undefineds.push_back(i);
} else {
symbols[i] = parseNonSectionSymbol(sym, StringRef(strtab + sym.n_strx));
}
}
for (size_t i = 0; i < sections.size(); ++i) {
Subsections &subsections = sections[i]->subsections;
if (subsections.empty())
continue;
std::vector<uint32_t> &symbolIndices = symbolsBySection[i];
uint64_t sectionAddr = sectionHeaders[i].addr;
uint32_t sectionAlign = 1u << sectionHeaders[i].align;
// Some sections have already been split into subsections during
// parseSections(), so we simply need to match Symbols to the corresponding
// subsection here.
if (sections[i]->doneSplitting) {
for (size_t j = 0; j < symbolIndices.size(); ++j) {
uint32_t symIndex = symbolIndices[j];
const NList &sym = nList[symIndex];
StringRef name = strtab + sym.n_strx;
uint64_t symbolOffset = sym.n_value - sectionAddr;
InputSection *isec =
findContainingSubsection(*sections[i], &symbolOffset);
if (symbolOffset != 0) {
error(toString(*sections[i]) + ": symbol " + name +
" at misaligned offset");
continue;
}
symbols[symIndex] =
createDefined(sym, name, isec, 0, isec->getSize(), forceHidden);
}
continue;
}
sections[i]->doneSplitting = true;
// Calculate symbol sizes and create subsections by splitting the sections
// along symbol boundaries.
// We populate subsections by repeatedly splitting the last (highest
// address) subsection.
llvm::stable_sort(symbolIndices, [&](uint32_t lhs, uint32_t rhs) {
return nList[lhs].n_value < nList[rhs].n_value;
});
for (size_t j = 0; j < symbolIndices.size(); ++j) {
uint32_t symIndex = symbolIndices[j];
const NList &sym = nList[symIndex];
StringRef name = strtab + sym.n_strx;
Subsection &subsec = subsections.back();
InputSection *isec = subsec.isec;
uint64_t subsecAddr = sectionAddr + subsec.offset;
size_t symbolOffset = sym.n_value - subsecAddr;
uint64_t symbolSize =
j + 1 < symbolIndices.size()
? nList[symbolIndices[j + 1]].n_value - sym.n_value
: isec->data.size() - symbolOffset;
// There are 4 cases where we do not need to create a new subsection:
// 1. If the input file does not use subsections-via-symbols.
// 2. Multiple symbols at the same address only induce one subsection.
// (The symbolOffset == 0 check covers both this case as well as
// the first loop iteration.)
// 3. Alternative entry points do not induce new subsections.
// 4. If we have a literal section (e.g. __cstring and __literal4).
if (!subsectionsViaSymbols || symbolOffset == 0 ||
sym.n_desc & N_ALT_ENTRY || !isa<ConcatInputSection>(isec)) {
symbols[symIndex] = createDefined(sym, name, isec, symbolOffset,
symbolSize, forceHidden);
continue;
}
auto *concatIsec = cast<ConcatInputSection>(isec);
auto *nextIsec = make<ConcatInputSection>(*concatIsec);
nextIsec->wasCoalesced = false;
if (isZeroFill(isec->getFlags())) {
// Zero-fill sections have NULL data.data() non-zero data.size()
nextIsec->data = {nullptr, isec->data.size() - symbolOffset};
isec->data = {nullptr, symbolOffset};
} else {
nextIsec->data = isec->data.slice(symbolOffset);
isec->data = isec->data.slice(0, symbolOffset);
}
// By construction, the symbol will be at offset zero in the new
// subsection.
symbols[symIndex] = createDefined(sym, name, nextIsec, /*value=*/0,
symbolSize, forceHidden);
// TODO: ld64 appears to preserve the original alignment as well as each
// subsection's offset from the last aligned address. We should consider
// emulating that behavior.
nextIsec->align = MinAlign(sectionAlign, sym.n_value);
subsections.push_back({sym.n_value - sectionAddr, nextIsec});
}
}
// Undefined symbols can trigger recursive fetch from Archives due to
// LazySymbols. Process defined symbols first so that the relative order
// between a defined symbol and an undefined symbol does not change the
// symbol resolution behavior. In addition, a set of interconnected symbols
// will all be resolved to the same file, instead of being resolved to
// different files.
for (unsigned i : undefineds) {
const NList &sym = nList[i];
StringRef name = strtab + sym.n_strx;
symbols[i] = parseNonSectionSymbol(sym, name);
}
}
OpaqueFile::OpaqueFile(MemoryBufferRef mb, StringRef segName,
StringRef sectName)
: InputFile(OpaqueKind, mb) {
const auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
ArrayRef<uint8_t> data = {buf, mb.getBufferSize()};
sections.push_back(make<Section>(/*file=*/this, segName.take_front(16),
sectName.take_front(16),
/*flags=*/0, /*addr=*/0));
Section &section = *sections.back();
ConcatInputSection *isec = make<ConcatInputSection>(section, data);
isec->live = true;
section.subsections.push_back({0, isec});
}
ObjFile::ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName,
bool lazy, bool forceHidden)
: InputFile(ObjKind, mb, lazy), modTime(modTime), forceHidden(forceHidden) {
this->archiveName = std::string(archiveName);
if (lazy) {
if (target->wordSize == 8)
parseLazy<LP64>();
else
parseLazy<ILP32>();
} else {
if (target->wordSize == 8)
parse<LP64>();
else
parse<ILP32>();
}
}
template <class LP> void ObjFile::parse() {
using Header = typename LP::mach_header;
using SegmentCommand = typename LP::segment_command;
using SectionHeader = typename LP::section;
using NList = typename LP::nlist;
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
auto *hdr = reinterpret_cast<const Header *>(mb.getBufferStart());
Architecture arch = getArchitectureFromCpuType(hdr->cputype, hdr->cpusubtype);
if (arch != config->arch()) {
auto msg = config->errorForArchMismatch
? static_cast<void (*)(const Twine &)>(error)
: warn;
msg(toString(this) + " has architecture " + getArchitectureName(arch) +
" which is incompatible with target architecture " +
getArchitectureName(config->arch()));
return;
}
if (!checkCompatibility(this))
return;
for (auto *cmd : findCommands<linker_option_command>(hdr, LC_LINKER_OPTION)) {
StringRef data{reinterpret_cast<const char *>(cmd + 1),
cmd->cmdsize - sizeof(linker_option_command)};
parseLCLinkerOption(this, cmd->count, data);
}
ArrayRef<SectionHeader> sectionHeaders;
if (const load_command *cmd = findCommand(hdr, LP::segmentLCType)) {
auto *c = reinterpret_cast<const SegmentCommand *>(cmd);
sectionHeaders = ArrayRef<SectionHeader>{
reinterpret_cast<const SectionHeader *>(c + 1), c->nsects};
parseSections(sectionHeaders);
}
// TODO: Error on missing LC_SYMTAB?
if (const load_command *cmd = findCommand(hdr, LC_SYMTAB)) {
auto *c = reinterpret_cast<const symtab_command *>(cmd);
ArrayRef<NList> nList(reinterpret_cast<const NList *>(buf + c->symoff),
c->nsyms);
const char *strtab = reinterpret_cast<const char *>(buf) + c->stroff;
bool subsectionsViaSymbols = hdr->flags & MH_SUBSECTIONS_VIA_SYMBOLS;
parseSymbols<LP>(sectionHeaders, nList, strtab, subsectionsViaSymbols);
}
// The relocations may refer to the symbols, so we parse them after we have
// parsed all the symbols.
for (size_t i = 0, n = sections.size(); i < n; ++i)
if (!sections[i]->subsections.empty())
parseRelocations(sectionHeaders, sectionHeaders[i], *sections[i]);
if (!config->ignoreOptimizationHints)
if (auto *cmd = findCommand<linkedit_data_command>(
hdr, LC_LINKER_OPTIMIZATION_HINT))
parseOptimizationHints({buf + cmd->dataoff, cmd->datasize});
parseDebugInfo();
Section *ehFrameSection = nullptr;
Section *compactUnwindSection = nullptr;
for (Section *sec : sections) {
Section **s = StringSwitch<Section **>(sec->name)
.Case(section_names::compactUnwind, &compactUnwindSection)
.Case(section_names::ehFrame, &ehFrameSection)
.Default(nullptr);
if (s)
*s = sec;
}
if (compactUnwindSection)
registerCompactUnwind(*compactUnwindSection);
if (ehFrameSection)
registerEhFrames(*ehFrameSection);
}
template <class LP> void ObjFile::parseLazy() {
using Header = typename LP::mach_header;
using NList = typename LP::nlist;
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
auto *hdr = reinterpret_cast<const Header *>(mb.getBufferStart());
const load_command *cmd = findCommand(hdr, LC_SYMTAB);
if (!cmd)
return;
auto *c = reinterpret_cast<const symtab_command *>(cmd);
ArrayRef<NList> nList(reinterpret_cast<const NList *>(buf + c->symoff),
c->nsyms);
const char *strtab = reinterpret_cast<const char *>(buf) + c->stroff;
symbols.resize(nList.size());
for (auto it : llvm::enumerate(nList)) {
const NList &sym = it.value();
if ((sym.n_type & N_EXT) && !isUndef(sym)) {
// TODO: Bound checking
StringRef name = strtab + sym.n_strx;
symbols[it.index()] = symtab->addLazyObject(name, *this);
if (!lazy)
break;
}
}
}
void ObjFile::parseDebugInfo() {
std::unique_ptr<DwarfObject> dObj = DwarfObject::create(this);
if (!dObj)
return;
// We do not re-use the context from getDwarf() here as that function
// constructs an expensive DWARFCache object.
auto *ctx = make<DWARFContext>(
std::move(dObj), "",
[&](Error err) {
warn(toString(this) + ": " + toString(std::move(err)));
},
[&](Error warning) {
warn(toString(this) + ": " + toString(std::move(warning)));
});
// TODO: Since object files can contain a lot of DWARF info, we should verify
// that we are parsing just the info we need
const DWARFContext::compile_unit_range &units = ctx->compile_units();
// FIXME: There can be more than one compile unit per object file. See
// PR48637.
auto it = units.begin();
compileUnit = it != units.end() ? it->get() : nullptr;
}
ArrayRef<data_in_code_entry> ObjFile::getDataInCode() const {
const auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
const load_command *cmd = findCommand(buf, LC_DATA_IN_CODE);
if (!cmd)
return {};
const auto *c = reinterpret_cast<const linkedit_data_command *>(cmd);
return {reinterpret_cast<const data_in_code_entry *>(buf + c->dataoff),
c->datasize / sizeof(data_in_code_entry)};
}
// Create pointers from symbols to their associated compact unwind entries.
void ObjFile::registerCompactUnwind(Section &compactUnwindSection) {
for (const Subsection &subsection : compactUnwindSection.subsections) {
ConcatInputSection *isec = cast<ConcatInputSection>(subsection.isec);
// Hack!! Each compact unwind entry (CUE) has its UNSIGNED relocations embed
// their addends in its data. Thus if ICF operated naively and compared the
// entire contents of each CUE, entries with identical unwind info but e.g.
// belonging to different functions would never be considered equivalent. To
// work around this problem, we remove some parts of the data containing the
// embedded addends. In particular, we remove the function address and LSDA
// pointers. Since these locations are at the start and end of the entry,
// we can do this using a simple, efficient slice rather than performing a
// copy. We are not losing any information here because the embedded
// addends have already been parsed in the corresponding Reloc structs.
//
// Removing these pointers would not be safe if they were pointers to
// absolute symbols. In that case, there would be no corresponding
// relocation. However, (AFAIK) MC cannot emit references to absolute
// symbols for either the function address or the LSDA. However, it *can* do
// so for the personality pointer, so we are not slicing that field away.
//
// Note that we do not adjust the offsets of the corresponding relocations;
// instead, we rely on `relocateCompactUnwind()` to correctly handle these
// truncated input sections.
isec->data = isec->data.slice(target->wordSize, 8 + target->wordSize);
uint32_t encoding = read32le(isec->data.data() + sizeof(uint32_t));
// llvm-mc omits CU entries for functions that need DWARF encoding, but
// `ld -r` doesn't. We can ignore them because we will re-synthesize these
// CU entries from the DWARF info during the output phase.
if ((encoding & target->modeDwarfEncoding) == target->modeDwarfEncoding)
continue;
ConcatInputSection *referentIsec;
for (auto it = isec->relocs.begin(); it != isec->relocs.end();) {
Reloc &r = *it;
// CUE::functionAddress is at offset 0. Skip personality & LSDA relocs.
if (r.offset != 0) {
++it;
continue;
}
uint64_t add = r.addend;
if (auto *sym = cast_or_null<Defined>(r.referent.dyn_cast<Symbol *>())) {
// Check whether the symbol defined in this file is the prevailing one.
// Skip if it is e.g. a weak def that didn't prevail.
if (sym->getFile() != this) {
++it;
continue;
}
add += sym->value;
referentIsec = cast<ConcatInputSection>(sym->isec);
} else {
referentIsec =
cast<ConcatInputSection>(r.referent.dyn_cast<InputSection *>());
}
// Unwind info lives in __DATA, and finalization of __TEXT will occur
// before finalization of __DATA. Moreover, the finalization of unwind
// info depends on the exact addresses that it references. So it is safe
// for compact unwind to reference addresses in __TEXT, but not addresses
// in any other segment.
if (referentIsec->getSegName() != segment_names::text)
error(isec->getLocation(r.offset) + " references section " +
referentIsec->getName() + " which is not in segment __TEXT");
// The functionAddress relocations are typically section relocations.
// However, unwind info operates on a per-symbol basis, so we search for
// the function symbol here.
Defined *d = findSymbolAtOffset(referentIsec, add);
if (!d) {
++it;
continue;
}
d->unwindEntry = isec;
// Now that the symbol points to the unwind entry, we can remove the reloc
// that points from the unwind entry back to the symbol.
//
// First, the symbol keeps the unwind entry alive (and not vice versa), so
// this keeps dead-stripping simple.
//
// Moreover, it reduces the work that ICF needs to do to figure out if
// functions with unwind info are foldable.
//
// However, this does make it possible for ICF to fold CUEs that point to
// distinct functions (if the CUEs are otherwise identical).
// UnwindInfoSection takes care of this by re-duplicating the CUEs so that
// each one can hold a distinct functionAddress value.
//
// Given that clang emits relocations in reverse order of address, this
// relocation should be at the end of the vector for most of our input
// object files, so this erase() is typically an O(1) operation.
it = isec->relocs.erase(it);
}
}
}
struct CIE {
macho::Symbol *personalitySymbol = nullptr;
bool fdesHaveAug = false;
uint8_t lsdaPtrSize = 0; // 0 => no LSDA
uint8_t funcPtrSize = 0;
};
static uint8_t pointerEncodingToSize(uint8_t enc) {
switch (enc & 0xf) {
case dwarf::DW_EH_PE_absptr:
return target->wordSize;
case dwarf::DW_EH_PE_sdata4:
return 4;
case dwarf::DW_EH_PE_sdata8:
// ld64 doesn't actually support sdata8, but this seems simple enough...
return 8;
default:
return 0;
};
}
static CIE parseCIE(const InputSection *isec, const EhReader &reader,
size_t off) {
// Handling the full generality of possible DWARF encodings would be a major
// pain. We instead take advantage of our knowledge of how llvm-mc encodes
// DWARF and handle just that.
constexpr uint8_t expectedPersonalityEnc =
dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_sdata4;
CIE cie;
uint8_t version = reader.readByte(&off);
if (version != 1 && version != 3)
fatal("Expected CIE version of 1 or 3, got " + Twine(version));
StringRef aug = reader.readString(&off);
reader.skipLeb128(&off); // skip code alignment
reader.skipLeb128(&off); // skip data alignment
reader.skipLeb128(&off); // skip return address register
reader.skipLeb128(&off); // skip aug data length
uint64_t personalityAddrOff = 0;
for (char c : aug) {
switch (c) {
case 'z':
cie.fdesHaveAug = true;
break;
case 'P': {
uint8_t personalityEnc = reader.readByte(&off);
if (personalityEnc != expectedPersonalityEnc)
reader.failOn(off, "unexpected personality encoding 0x" +
Twine::utohexstr(personalityEnc));
personalityAddrOff = off;
off += 4;
break;
}
case 'L': {
uint8_t lsdaEnc = reader.readByte(&off);
cie.lsdaPtrSize = pointerEncodingToSize(lsdaEnc);
if (cie.lsdaPtrSize == 0)
reader.failOn(off, "unexpected LSDA encoding 0x" +
Twine::utohexstr(lsdaEnc));
break;
}
case 'R': {
uint8_t pointerEnc = reader.readByte(&off);
cie.funcPtrSize = pointerEncodingToSize(pointerEnc);
if (cie.funcPtrSize == 0 || !(pointerEnc & dwarf::DW_EH_PE_pcrel))
reader.failOn(off, "unexpected pointer encoding 0x" +
Twine::utohexstr(pointerEnc));
break;
}
default:
break;
}
}
if (personalityAddrOff != 0) {
auto personalityRelocIt =
llvm::find_if(isec->relocs, [=](const macho::Reloc &r) {
return r.offset == personalityAddrOff;
});
if (personalityRelocIt == isec->relocs.end())
reader.failOn(off, "Failed to locate relocation for personality symbol");
cie.personalitySymbol = personalityRelocIt->referent.get<macho::Symbol *>();
}
return cie;
}
// EH frame target addresses may be encoded as pcrel offsets. However, instead
// of using an actual pcrel reloc, ld64 emits subtractor relocations instead.
// This function recovers the target address from the subtractors, essentially
// performing the inverse operation of EhRelocator.
//
// Concretely, we expect our relocations to write the value of `PC -
// target_addr` to `PC`. `PC` itself is denoted by a minuend relocation that
// points to a symbol plus an addend.
//
// It is important that the minuend relocation point to a symbol within the
// same section as the fixup value, since sections may get moved around.
//
// For example, for arm64, llvm-mc emits relocations for the target function
// address like so:
//
// ltmp:
// <CIE start>
// ...
// <CIE end>
// ... multiple FDEs ...
// <FDE start>
// <target function address - (ltmp + pcrel offset)>
// ...
//
// If any of the FDEs in `multiple FDEs` get dead-stripped, then `FDE start`
// will move to an earlier address, and `ltmp + pcrel offset` will no longer
// reflect an accurate pcrel value. To avoid this problem, we "canonicalize"
// our relocation by adding an `EH_Frame` symbol at `FDE start`, and updating
// the reloc to be `target function address - (EH_Frame + new pcrel offset)`.
//
// If `Invert` is set, then we instead expect `target_addr - PC` to be written
// to `PC`.
template <bool Invert = false>
Defined *
targetSymFromCanonicalSubtractor(const InputSection *isec,
std::vector<macho::Reloc>::iterator relocIt) {
macho::Reloc &subtrahend = *relocIt;
macho::Reloc &minuend = *std::next(relocIt);
assert(target->hasAttr(subtrahend.type, RelocAttrBits::SUBTRAHEND));
assert(target->hasAttr(minuend.type, RelocAttrBits::UNSIGNED));
// Note: pcSym may *not* be exactly at the PC; there's usually a non-zero
// addend.
auto *pcSym = cast<Defined>(subtrahend.referent.get<macho::Symbol *>());
Defined *target =
cast_or_null<Defined>(minuend.referent.dyn_cast<macho::Symbol *>());
if (!pcSym) {
auto *targetIsec =
cast<ConcatInputSection>(minuend.referent.get<InputSection *>());
target = findSymbolAtOffset(targetIsec, minuend.addend);
}
if (Invert)
std::swap(pcSym, target);
if (pcSym->isec == isec) {
if (pcSym->value - (Invert ? -1 : 1) * minuend.addend != subtrahend.offset)
fatal("invalid FDE relocation in __eh_frame");
} else {
// Ensure the pcReloc points to a symbol within the current EH frame.
// HACK: we should really verify that the original relocation's semantics
// are preserved. In particular, we should have
// `oldSym->value + oldOffset == newSym + newOffset`. However, we don't
// have an easy way to access the offsets from this point in the code; some
// refactoring is needed for that.
macho::Reloc &pcReloc = Invert ? minuend : subtrahend;
pcReloc.referent = isec->symbols[0];
assert(isec->symbols[0]->value == 0);
minuend.addend = pcReloc.offset * (Invert ? 1LL : -1LL);
}
return target;
}
Defined *findSymbolAtAddress(const std::vector<Section *> &sections,
uint64_t addr) {
Section *sec = findContainingSection(sections, &addr);
auto *isec = cast<ConcatInputSection>(findContainingSubsection(*sec, &addr));
return findSymbolAtOffset(isec, addr);
}
// For symbols that don't have compact unwind info, associate them with the more
// general-purpose (and verbose) DWARF unwind info found in __eh_frame.
//
// This requires us to parse the contents of __eh_frame. See EhFrame.h for a
// description of its format.
//
// While parsing, we also look for what MC calls "abs-ified" relocations -- they
// are relocations which are implicitly encoded as offsets in the section data.
// We convert them into explicit Reloc structs so that the EH frames can be
// handled just like a regular ConcatInputSection later in our output phase.
//
// We also need to handle the case where our input object file has explicit
// relocations. This is the case when e.g. it's the output of `ld -r`. We only
// look for the "abs-ified" relocation if an explicit relocation is absent.
void ObjFile::registerEhFrames(Section &ehFrameSection) {
DenseMap<const InputSection *, CIE> cieMap;
for (const Subsection &subsec : ehFrameSection.subsections) {
auto *isec = cast<ConcatInputSection>(subsec.isec);
uint64_t isecOff = subsec.offset;
// Subtractor relocs require the subtrahend to be a symbol reloc. Ensure
// that all EH frames have an associated symbol so that we can generate
// subtractor relocs that reference them.
if (isec->symbols.size() == 0)
isec->symbols.push_back(make<Defined>(
"EH_Frame", isec->getFile(), isec, /*value=*/0, /*size=*/0,
/*isWeakDef=*/false, /*isExternal=*/false, /*isPrivateExtern=*/false,
/*includeInSymtab=*/false, /*isThumb=*/false,
/*isReferencedDynamically=*/false, /*noDeadStrip=*/false));
else if (isec->symbols[0]->value != 0)
fatal("found symbol at unexpected offset in __eh_frame");
EhReader reader(this, isec->data, subsec.offset);
size_t dataOff = 0; // Offset from the start of the EH frame.
reader.skipValidLength(&dataOff); // readLength() already validated this.
// cieOffOff is the offset from the start of the EH frame to the cieOff
// value, which is itself an offset from the current PC to a CIE.
const size_t cieOffOff = dataOff;
EhRelocator ehRelocator(isec);
auto cieOffRelocIt = llvm::find_if(
isec->relocs, [=](const Reloc &r) { return r.offset == cieOffOff; });
InputSection *cieIsec = nullptr;
if (cieOffRelocIt != isec->relocs.end()) {
// We already have an explicit relocation for the CIE offset.
cieIsec =
targetSymFromCanonicalSubtractor</*Invert=*/true>(isec, cieOffRelocIt)
->isec;
dataOff += sizeof(uint32_t);
} else {
// If we haven't found a relocation, then the CIE offset is most likely
// embedded in the section data (AKA an "abs-ified" reloc.). Parse that
// and generate a Reloc struct.
uint32_t cieMinuend = reader.readU32(&dataOff);
if (cieMinuend == 0)
cieIsec = isec;
else {
uint32_t cieOff = isecOff + dataOff - cieMinuend;
cieIsec = findContainingSubsection(ehFrameSection, &cieOff);
if (cieIsec == nullptr)
fatal("failed to find CIE");
}
if (cieIsec != isec)
ehRelocator.makeNegativePcRel(cieOffOff, cieIsec->symbols[0],
/*length=*/2);
}
if (cieIsec == isec) {
cieMap[cieIsec] = parseCIE(isec, reader, dataOff);
continue;
}
assert(cieMap.count(cieIsec));
const CIE &cie = cieMap[cieIsec];
// Offset of the function address within the EH frame.
const size_t funcAddrOff = dataOff;
uint64_t funcAddr = reader.readPointer(&dataOff, cie.funcPtrSize) +
ehFrameSection.addr + isecOff + funcAddrOff;
uint32_t funcLength = reader.readPointer(&dataOff, cie.funcPtrSize);
size_t lsdaAddrOff = 0; // Offset of the LSDA address within the EH frame.
Optional<uint64_t> lsdaAddrOpt;
if (cie.fdesHaveAug) {
reader.skipLeb128(&dataOff);
lsdaAddrOff = dataOff;
if (cie.lsdaPtrSize != 0) {
uint64_t lsdaOff = reader.readPointer(&dataOff, cie.lsdaPtrSize);
if (lsdaOff != 0) // FIXME possible to test this?
lsdaAddrOpt = ehFrameSection.addr + isecOff + lsdaAddrOff + lsdaOff;
}
}
auto funcAddrRelocIt = isec->relocs.end();
auto lsdaAddrRelocIt = isec->relocs.end();
for (auto it = isec->relocs.begin(); it != isec->relocs.end(); ++it) {
if (it->offset == funcAddrOff)
funcAddrRelocIt = it++; // Found subtrahend; skip over minuend reloc
else if (lsdaAddrOpt && it->offset == lsdaAddrOff)
lsdaAddrRelocIt = it++; // Found subtrahend; skip over minuend reloc
}
Defined *funcSym;
if (funcAddrRelocIt != isec->relocs.end()) {
funcSym = targetSymFromCanonicalSubtractor(isec, funcAddrRelocIt);
// Canonicalize the symbol. If there are multiple symbols at the same
// address, we want both `registerEhFrame` and `registerCompactUnwind`
// to register the unwind entry under same symbol.
// This is not particularly efficient, but we should run into this case
// infrequently (only when handling the output of `ld -r`).
if (funcSym->isec)
funcSym = findSymbolAtOffset(cast<ConcatInputSection>(funcSym->isec),
funcSym->value);
} else {
funcSym = findSymbolAtAddress(sections, funcAddr);
ehRelocator.makePcRel(funcAddrOff, funcSym, target->p2WordSize);
}
// The symbol has been coalesced, or already has a compact unwind entry.
if (!funcSym || funcSym->getFile() != this || funcSym->unwindEntry) {
// We must prune unused FDEs for correctness, so we cannot rely on
// -dead_strip being enabled.
isec->live = false;
continue;
}
InputSection *lsdaIsec = nullptr;
if (lsdaAddrRelocIt != isec->relocs.end()) {
lsdaIsec = targetSymFromCanonicalSubtractor(isec, lsdaAddrRelocIt)->isec;
} else if (lsdaAddrOpt) {
uint64_t lsdaAddr = *lsdaAddrOpt;
Section *sec = findContainingSection(sections, &lsdaAddr);
lsdaIsec =
cast<ConcatInputSection>(findContainingSubsection(*sec, &lsdaAddr));
ehRelocator.makePcRel(lsdaAddrOff, lsdaIsec, target->p2WordSize);
}
fdes[isec] = {funcLength, cie.personalitySymbol, lsdaIsec};
funcSym->unwindEntry = isec;
ehRelocator.commit();
}
+
+ // __eh_frame is marked as S_ATTR_LIVE_SUPPORT in input files, because FDEs
+ // are normally required to be kept alive if they reference a live symbol.
+ // However, we've explicitly created a dependency from a symbol to its FDE, so
+ // dead-stripping will just work as usual, and S_ATTR_LIVE_SUPPORT will only
+ // serve to incorrectly prevent us from dead-stripping duplicate FDEs for a
+ // live symbol (e.g. if there were multiple weak copies). Remove this flag to
+ // let dead-stripping proceed correctly.
+ ehFrameSection.flags &= ~S_ATTR_LIVE_SUPPORT;
}
std::string ObjFile::sourceFile() const {
SmallString<261> dir(compileUnit->getCompilationDir());
StringRef sep = sys::path::get_separator();
// We don't use `path::append` here because we want an empty `dir` to result
// in an absolute path. `append` would give us a relative path for that case.
if (!dir.endswith(sep))
dir += sep;
return (dir + compileUnit->getUnitDIE().getShortName()).str();
}
lld::DWARFCache *ObjFile::getDwarf() {
llvm::call_once(initDwarf, [this]() {
auto dwObj = DwarfObject::create(this);
if (!dwObj)
return;
dwarfCache = std::make_unique<DWARFCache>(std::make_unique<DWARFContext>(
std::move(dwObj), "",
[&](Error err) { warn(getName() + ": " + toString(std::move(err))); },
[&](Error warning) {
warn(getName() + ": " + toString(std::move(warning)));
}));
});
return dwarfCache.get();
}
// The path can point to either a dylib or a .tbd file.
static DylibFile *loadDylib(StringRef path, DylibFile *umbrella) {
Optional<MemoryBufferRef> mbref = readFile(path);
if (!mbref) {
error("could not read dylib file at " + path);
return nullptr;
}
return loadDylib(*mbref, umbrella);
}
// TBD files are parsed into a series of TAPI documents (InterfaceFiles), with
// the first document storing child pointers to the rest of them. When we are
// processing a given TBD file, we store that top-level document in
// currentTopLevelTapi. When processing re-exports, we search its children for
// potentially matching documents in the same TBD file. Note that the children
// themselves don't point to further documents, i.e. this is a two-level tree.
//
// Re-exports can either refer to on-disk files, or to documents within .tbd
// files.
static DylibFile *findDylib(StringRef path, DylibFile *umbrella,
const InterfaceFile *currentTopLevelTapi) {
// Search order:
// 1. Install name basename in -F / -L directories.
{
StringRef stem = path::stem(path);
SmallString<128> frameworkName;
path::append(frameworkName, path::Style::posix, stem + ".framework", stem);
bool isFramework = path.endswith(frameworkName);
if (isFramework) {
for (StringRef dir : config->frameworkSearchPaths) {
SmallString<128> candidate = dir;
path::append(candidate, frameworkName);
if (Optional<StringRef> dylibPath = resolveDylibPath(candidate.str()))
return loadDylib(*dylibPath, umbrella);
}
} else if (Optional<StringRef> dylibPath = findPathCombination(
stem, config->librarySearchPaths, {".tbd", ".dylib"}))
return loadDylib(*dylibPath, umbrella);
}
// 2. As absolute path.
if (path::is_absolute(path, path::Style::posix))
for (StringRef root : config->systemLibraryRoots)
if (Optional<StringRef> dylibPath = resolveDylibPath((root + path).str()))
return loadDylib(*dylibPath, umbrella);
// 3. As relative path.
// TODO: Handle -dylib_file
// Replace @executable_path, @loader_path, @rpath prefixes in install name.
SmallString<128> newPath;
if (config->outputType == MH_EXECUTE &&
path.consume_front("@executable_path/")) {
// ld64 allows overriding this with the undocumented flag -executable_path.
// lld doesn't currently implement that flag.
// FIXME: Consider using finalOutput instead of outputFile.
path::append(newPath, path::parent_path(config->outputFile), path);
path = newPath;
} else if (path.consume_front("@loader_path/")) {
fs::real_path(umbrella->getName(), newPath);
path::remove_filename(newPath);
path::append(newPath, path);
path = newPath;
} else if (path.startswith("@rpath/")) {
for (StringRef rpath : umbrella->rpaths) {
newPath.clear();
if (rpath.consume_front("@loader_path/")) {
fs::real_path(umbrella->getName(), newPath);
path::remove_filename(newPath);
}
path::append(newPath, rpath, path.drop_front(strlen("@rpath/")));
if (Optional<StringRef> dylibPath = resolveDylibPath(newPath.str()))
return loadDylib(*dylibPath, umbrella);
}
}
// FIXME: Should this be further up?
if (currentTopLevelTapi) {
for (InterfaceFile &child :
make_pointee_range(currentTopLevelTapi->documents())) {
assert(child.documents().empty());
if (path == child.getInstallName()) {
auto file = make<DylibFile>(child, umbrella, /*isBundleLoader=*/false,
/*explicitlyLinked=*/false);
file->parseReexports(child);
return file;
}
}
}
if (Optional<StringRef> dylibPath = resolveDylibPath(path))
return loadDylib(*dylibPath, umbrella);
return nullptr;
}
// If a re-exported dylib is public (lives in /usr/lib or
// /System/Library/Frameworks), then it is considered implicitly linked: we
// should bind to its symbols directly instead of via the re-exporting umbrella
// library.
static bool isImplicitlyLinked(StringRef path) {
if (!config->implicitDylibs)
return false;
if (path::parent_path(path) == "/usr/lib")
return true;
// Match /System/Library/Frameworks/$FOO.framework/**/$FOO
if (path.consume_front("/System/Library/Frameworks/")) {
StringRef frameworkName = path.take_until([](char c) { return c == '.'; });
return path::filename(path) == frameworkName;
}
return false;
}
static void loadReexport(StringRef path, DylibFile *umbrella,
const InterfaceFile *currentTopLevelTapi) {
DylibFile *reexport = findDylib(path, umbrella, currentTopLevelTapi);
if (!reexport)
error("unable to locate re-export with install name " + path);
}
DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
bool isBundleLoader, bool explicitlyLinked)
: InputFile(DylibKind, mb), refState(RefState::Unreferenced),
explicitlyLinked(explicitlyLinked), isBundleLoader(isBundleLoader) {
assert(!isBundleLoader || !umbrella);
if (umbrella == nullptr)
umbrella = this;
this->umbrella = umbrella;
auto *hdr = reinterpret_cast<const mach_header *>(mb.getBufferStart());
// Initialize installName.
if (const load_command *cmd = findCommand(hdr, LC_ID_DYLIB)) {
auto *c = reinterpret_cast<const dylib_command *>(cmd);
currentVersion = read32le(&c->dylib.current_version);
compatibilityVersion = read32le(&c->dylib.compatibility_version);
installName =
reinterpret_cast<const char *>(cmd) + read32le(&c->dylib.name);
} else if (!isBundleLoader) {
// macho_executable and macho_bundle don't have LC_ID_DYLIB,
// so it's OK.
error("dylib " + toString(this) + " missing LC_ID_DYLIB load command");
return;
}
if (config->printEachFile)
message(toString(this));
inputFiles.insert(this);
deadStrippable = hdr->flags & MH_DEAD_STRIPPABLE_DYLIB;
if (!checkCompatibility(this))
return;
checkAppExtensionSafety(hdr->flags & MH_APP_EXTENSION_SAFE);
for (auto *cmd : findCommands<rpath_command>(hdr, LC_RPATH)) {
StringRef rpath{reinterpret_cast<const char *>(cmd) + cmd->path};
rpaths.push_back(rpath);
}
// Initialize symbols.
exportingFile = isImplicitlyLinked(installName) ? this : this->umbrella;
const auto *dyldInfo = findCommand<dyld_info_command>(hdr, LC_DYLD_INFO_ONLY);
const auto *exportsTrie =
findCommand<linkedit_data_command>(hdr, LC_DYLD_EXPORTS_TRIE);
if (dyldInfo && exportsTrie) {
// It's unclear what should happen in this case. Maybe we should only error
// out if the two load commands refer to different data?
error("dylib " + toString(this) +
" has both LC_DYLD_INFO_ONLY and LC_DYLD_EXPORTS_TRIE");
return;
} else if (dyldInfo) {
parseExportedSymbols(dyldInfo->export_off, dyldInfo->export_size);
} else if (exportsTrie) {
parseExportedSymbols(exportsTrie->dataoff, exportsTrie->datasize);
} else {
error("No LC_DYLD_INFO_ONLY or LC_DYLD_EXPORTS_TRIE found in " +
toString(this));
return;
}
}
void DylibFile::parseExportedSymbols(uint32_t offset, uint32_t size) {
struct TrieEntry {
StringRef name;
uint64_t flags;
};
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
std::vector<TrieEntry> entries;
// Find all the $ld$* symbols to process first.
parseTrie(buf + offset, size, [&](const Twine &name, uint64_t flags) {
StringRef savedName = saver().save(name);
if (handleLDSymbol(savedName))
return;
entries.push_back({savedName, flags});
});
// Process the "normal" symbols.
for (TrieEntry &entry : entries) {
if (exportingFile->hiddenSymbols.contains(CachedHashStringRef(entry.name)))
continue;
bool isWeakDef = entry.flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
bool isTlv = entry.flags & EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL;
symbols.push_back(
symtab->addDylib(entry.name, exportingFile, isWeakDef, isTlv));
}
}
void DylibFile::parseLoadCommands(MemoryBufferRef mb) {
auto *hdr = reinterpret_cast<const mach_header *>(mb.getBufferStart());
const uint8_t *p = reinterpret_cast<const uint8_t *>(mb.getBufferStart()) +
target->headerSize;
for (uint32_t i = 0, n = hdr->ncmds; i < n; ++i) {
auto *cmd = reinterpret_cast<const load_command *>(p);
p += cmd->cmdsize;
if (!(hdr->flags & MH_NO_REEXPORTED_DYLIBS) &&
cmd->cmd == LC_REEXPORT_DYLIB) {
const auto *c = reinterpret_cast<const dylib_command *>(cmd);
StringRef reexportPath =
reinterpret_cast<const char *>(c) + read32le(&c->dylib.name);
loadReexport(reexportPath, exportingFile, nullptr);
}
// FIXME: What about LC_LOAD_UPWARD_DYLIB, LC_LAZY_LOAD_DYLIB,
// LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB (..are reexports from dylibs with
// MH_NO_REEXPORTED_DYLIBS loaded for -flat_namespace)?
if (config->namespaceKind == NamespaceKind::flat &&
cmd->cmd == LC_LOAD_DYLIB) {
const auto *c = reinterpret_cast<const dylib_command *>(cmd);
StringRef dylibPath =
reinterpret_cast<const char *>(c) + read32le(&c->dylib.name);
DylibFile *dylib = findDylib(dylibPath, umbrella, nullptr);
if (!dylib)
error(Twine("unable to locate library '") + dylibPath +
"' loaded from '" + toString(this) + "' for -flat_namespace");
}
}
}
// Some versions of Xcode ship with .tbd files that don't have the right
// platform settings.
constexpr std::array<StringRef, 3> skipPlatformChecks{
"/usr/lib/system/libsystem_kernel.dylib",
"/usr/lib/system/libsystem_platform.dylib",
"/usr/lib/system/libsystem_pthread.dylib"};
static bool skipPlatformCheckForCatalyst(const InterfaceFile &interface,
bool explicitlyLinked) {
// Catalyst outputs can link against implicitly linked macOS-only libraries.
if (config->platform() != PLATFORM_MACCATALYST || explicitlyLinked)
return false;
return is_contained(interface.targets(),
MachO::Target(config->arch(), PLATFORM_MACOS));
}
DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
bool isBundleLoader, bool explicitlyLinked)
: InputFile(DylibKind, interface), refState(RefState::Unreferenced),
explicitlyLinked(explicitlyLinked), isBundleLoader(isBundleLoader) {
// FIXME: Add test for the missing TBD code path.
if (umbrella == nullptr)
umbrella = this;
this->umbrella = umbrella;
installName = saver().save(interface.getInstallName());
compatibilityVersion = interface.getCompatibilityVersion().rawValue();
currentVersion = interface.getCurrentVersion().rawValue();
if (config->printEachFile)
message(toString(this));
inputFiles.insert(this);
if (!is_contained(skipPlatformChecks, installName) &&
!is_contained(interface.targets(), config->platformInfo.target) &&
!skipPlatformCheckForCatalyst(interface, explicitlyLinked)) {
error(toString(this) + " is incompatible with " +
std::string(config->platformInfo.target));
return;
}
checkAppExtensionSafety(interface.isApplicationExtensionSafe());
exportingFile = isImplicitlyLinked(installName) ? this : umbrella;
auto addSymbol = [&](const Twine &name) -> void {
StringRef savedName = saver().save(name);
if (exportingFile->hiddenSymbols.contains(CachedHashStringRef(savedName)))
return;
symbols.push_back(symtab->addDylib(savedName, exportingFile,
/*isWeakDef=*/false,
/*isTlv=*/false));
};
std::vector<const llvm::MachO::Symbol *> normalSymbols;
normalSymbols.reserve(interface.symbolsCount());
for (const auto *symbol : interface.symbols()) {
if (!symbol->getArchitectures().has(config->arch()))
continue;
if (handleLDSymbol(symbol->getName()))
continue;
switch (symbol->getKind()) {
case SymbolKind::GlobalSymbol: // Fallthrough
case SymbolKind::ObjectiveCClass: // Fallthrough
case SymbolKind::ObjectiveCClassEHType: // Fallthrough
case SymbolKind::ObjectiveCInstanceVariable: // Fallthrough
normalSymbols.push_back(symbol);
}
}
// TODO(compnerd) filter out symbols based on the target platform
// TODO: handle weak defs, thread locals
for (const auto *symbol : normalSymbols) {
switch (symbol->getKind()) {
case SymbolKind::GlobalSymbol:
addSymbol(symbol->getName());
break;
case SymbolKind::ObjectiveCClass:
// XXX ld64 only creates these symbols when -ObjC is passed in. We may
// want to emulate that.
addSymbol(objc::klass + symbol->getName());
addSymbol(objc::metaclass + symbol->getName());
break;
case SymbolKind::ObjectiveCClassEHType:
addSymbol(objc::ehtype + symbol->getName());
break;
case SymbolKind::ObjectiveCInstanceVariable:
addSymbol(objc::ivar + symbol->getName());
break;
}
}
}
DylibFile::DylibFile(DylibFile *umbrella)
: InputFile(DylibKind, MemoryBufferRef{}), refState(RefState::Unreferenced),
explicitlyLinked(false), isBundleLoader(false) {
if (umbrella == nullptr)
umbrella = this;
this->umbrella = umbrella;
}
void DylibFile::parseReexports(const InterfaceFile &interface) {
const InterfaceFile *topLevel =
interface.getParent() == nullptr ? &interface : interface.getParent();
for (const InterfaceFileRef &intfRef : interface.reexportedLibraries()) {
InterfaceFile::const_target_range targets = intfRef.targets();
if (is_contained(skipPlatformChecks, intfRef.getInstallName()) ||
is_contained(targets, config->platformInfo.target))
loadReexport(intfRef.getInstallName(), exportingFile, topLevel);
}
}
bool DylibFile::isExplicitlyLinked() const {
if (!explicitlyLinked)
return false;
// If this dylib was explicitly linked, but at least one of the symbols
// of the synthetic dylibs it created via $ld$previous symbols is
// referenced, then that synthetic dylib fulfils the explicit linkedness
// and we can deadstrip this dylib if it's unreferenced.
for (const auto *dylib : extraDylibs)
if (dylib->isReferenced())
return false;
return true;
}
DylibFile *DylibFile::getSyntheticDylib(StringRef installName,
uint32_t currentVersion,
uint32_t compatVersion) {
for (DylibFile *dylib : extraDylibs)
if (dylib->installName == installName) {
// FIXME: Check what to do if different $ld$previous symbols
// request the same dylib, but with different versions.
return dylib;
}
auto *dylib = make<DylibFile>(umbrella == this ? nullptr : umbrella);
dylib->installName = saver().save(installName);
dylib->currentVersion = currentVersion;
dylib->compatibilityVersion = compatVersion;
extraDylibs.push_back(dylib);
return dylib;
}
// $ld$ symbols modify the properties/behavior of the library (e.g. its install
// name, compatibility version or hide/add symbols) for specific target
// versions.
bool DylibFile::handleLDSymbol(StringRef originalName) {
if (!originalName.startswith("$ld$"))
return false;
StringRef action;
StringRef name;
std::tie(action, name) = originalName.drop_front(strlen("$ld$")).split('$');
if (action == "previous")
handleLDPreviousSymbol(name, originalName);
else if (action == "install_name")
handleLDInstallNameSymbol(name, originalName);
else if (action == "hide")
handleLDHideSymbol(name, originalName);
return true;
}
void DylibFile::handleLDPreviousSymbol(StringRef name, StringRef originalName) {
// originalName: $ld$ previous $ <installname> $ <compatversion> $
// <platformstr> $ <startversion> $ <endversion> $ <symbol-name> $
StringRef installName;
StringRef compatVersion;
StringRef platformStr;
StringRef startVersion;
StringRef endVersion;
StringRef symbolName;
StringRef rest;
std::tie(installName, name) = name.split('$');
std::tie(compatVersion, name) = name.split('$');
std::tie(platformStr, name) = name.split('$');
std::tie(startVersion, name) = name.split('$');
std::tie(endVersion, name) = name.split('$');
std::tie(symbolName, rest) = name.rsplit('$');
// FIXME: Does this do the right thing for zippered files?
unsigned platform;
if (platformStr.getAsInteger(10, platform) ||
platform != static_cast<unsigned>(config->platform()))
return;
VersionTuple start;
if (start.tryParse(startVersion)) {
warn("failed to parse start version, symbol '" + originalName +
"' ignored");
return;
}
VersionTuple end;
if (end.tryParse(endVersion)) {
warn("failed to parse end version, symbol '" + originalName + "' ignored");
return;
}
if (config->platformInfo.minimum < start ||
config->platformInfo.minimum >= end)
return;
// Initialized to compatibilityVersion for the symbolName branch below.
uint32_t newCompatibilityVersion = compatibilityVersion;
uint32_t newCurrentVersionForSymbol = currentVersion;
if (!compatVersion.empty()) {
VersionTuple cVersion;
if (cVersion.tryParse(compatVersion)) {
warn("failed to parse compatibility version, symbol '" + originalName +
"' ignored");
return;
}
newCompatibilityVersion = encodeVersion(cVersion);
newCurrentVersionForSymbol = newCompatibilityVersion;
}
if (!symbolName.empty()) {
// A $ld$previous$ symbol with symbol name adds a symbol with that name to
// a dylib with given name and version.
auto *dylib = getSyntheticDylib(installName, newCurrentVersionForSymbol,
newCompatibilityVersion);
// Just adding the symbol to the symtab works because dylibs contain their
// symbols in alphabetical order, guaranteeing $ld$ symbols to precede
// normal symbols.
dylib->symbols.push_back(symtab->addDylib(
saver().save(symbolName), dylib, /*isWeakDef=*/false, /*isTlv=*/false));
return;
}
// A $ld$previous$ symbol without symbol name modifies the dylib it's in.
this->installName = saver().save(installName);
this->compatibilityVersion = newCompatibilityVersion;
}
void DylibFile::handleLDInstallNameSymbol(StringRef name,
StringRef originalName) {
// originalName: $ld$ install_name $ os<version> $ install_name
StringRef condition, installName;
std::tie(condition, installName) = name.split('$');
VersionTuple version;
if (!condition.consume_front("os") || version.tryParse(condition))
warn("failed to parse os version, symbol '" + originalName + "' ignored");
else if (version == config->platformInfo.minimum)
this->installName = saver().save(installName);
}
void DylibFile::handleLDHideSymbol(StringRef name, StringRef originalName) {
StringRef symbolName;
bool shouldHide = true;
if (name.startswith("os")) {
// If it's hidden based on versions.
name = name.drop_front(2);
StringRef minVersion;
std::tie(minVersion, symbolName) = name.split('$');
VersionTuple versionTup;
if (versionTup.tryParse(minVersion)) {
warn("Failed to parse hidden version, symbol `" + originalName +
"` ignored.");
return;
}
shouldHide = versionTup == config->platformInfo.minimum;
} else {
symbolName = name;
}
if (shouldHide)
exportingFile->hiddenSymbols.insert(CachedHashStringRef(symbolName));
}
void DylibFile::checkAppExtensionSafety(bool dylibIsAppExtensionSafe) const {
if (config->applicationExtension && !dylibIsAppExtensionSafe)
warn("using '-application_extension' with unsafe dylib: " + toString(this));
}
ArchiveFile::ArchiveFile(std::unique_ptr<object::Archive> &&f, bool forceHidden)
: InputFile(ArchiveKind, f->getMemoryBufferRef()), file(std::move(f)),
forceHidden(forceHidden) {}
void ArchiveFile::addLazySymbols() {
for (const object::Archive::Symbol &sym : file->symbols())
symtab->addLazyArchive(sym.getName(), this, sym);
}
static Expected<InputFile *>
loadArchiveMember(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName,
uint64_t offsetInArchive, bool forceHidden) {
if (config->zeroModTime)
modTime = 0;
switch (identify_magic(mb.getBuffer())) {
case file_magic::macho_object:
return make<ObjFile>(mb, modTime, archiveName, /*lazy=*/false, forceHidden);
case file_magic::bitcode:
return make<BitcodeFile>(mb, archiveName, offsetInArchive, /*lazy=*/false,
forceHidden);
default:
return createStringError(inconvertibleErrorCode(),
mb.getBufferIdentifier() +
" has unhandled file type");
}
}
Error ArchiveFile::fetch(const object::Archive::Child &c, StringRef reason) {
if (!seen.insert(c.getChildOffset()).second)
return Error::success();
Expected<MemoryBufferRef> mb = c.getMemoryBufferRef();
if (!mb)
return mb.takeError();
// Thin archives refer to .o files, so --reproduce needs the .o files too.
if (tar && c.getParent()->isThin())
tar->append(relativeToRoot(CHECK(c.getFullName(), this)), mb->getBuffer());
Expected<TimePoint<std::chrono::seconds>> modTime = c.getLastModified();
if (!modTime)
return modTime.takeError();
Expected<InputFile *> file = loadArchiveMember(
*mb, toTimeT(*modTime), getName(), c.getChildOffset(), forceHidden);
if (!file)
return file.takeError();
inputFiles.insert(*file);
printArchiveMemberLoad(reason, *file);
return Error::success();
}
void ArchiveFile::fetch(const object::Archive::Symbol &sym) {
object::Archive::Child c =
CHECK(sym.getMember(), toString(this) +
": could not get the member defining symbol " +
toMachOString(sym));
// `sym` is owned by a LazySym, which will be replace<>()d by make<ObjFile>
// and become invalid after that call. Copy it to the stack so we can refer
// to it later.
const object::Archive::Symbol symCopy = sym;
// ld64 doesn't demangle sym here even with -demangle.
// Match that: intentionally don't call toMachOString().
if (Error e = fetch(c, symCopy.getName()))
error(toString(this) + ": could not get the member defining symbol " +
toMachOString(symCopy) + ": " + toString(std::move(e)));
}
static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym,
BitcodeFile &file) {
StringRef name = saver().save(objSym.getName());
if (objSym.isUndefined())
return symtab->addUndefined(name, &file, /*isWeakRef=*/objSym.isWeak());
// TODO: Write a test demonstrating why computing isPrivateExtern before
// LTO compilation is important.
bool isPrivateExtern = false;
switch (objSym.getVisibility()) {
case GlobalValue::HiddenVisibility:
isPrivateExtern = true;
break;
case GlobalValue::ProtectedVisibility:
error(name + " has protected visibility, which is not supported by Mach-O");
break;
case GlobalValue::DefaultVisibility:
break;
}
isPrivateExtern = isPrivateExtern || objSym.canBeOmittedFromSymbolTable() ||
file.forceHidden;
if (objSym.isCommon())
return symtab->addCommon(name, &file, objSym.getCommonSize(),
objSym.getCommonAlignment(), isPrivateExtern);
return symtab->addDefined(name, &file, /*isec=*/nullptr, /*value=*/0,
/*size=*/0, objSym.isWeak(), isPrivateExtern,
/*isThumb=*/false,
/*isReferencedDynamically=*/false,
/*noDeadStrip=*/false,
/*isWeakDefCanBeHidden=*/false);
}
BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
uint64_t offsetInArchive, bool lazy, bool forceHidden)
: InputFile(BitcodeKind, mb, lazy), forceHidden(forceHidden) {
this->archiveName = std::string(archiveName);
std::string path = mb.getBufferIdentifier().str();
// ThinLTO assumes that all MemoryBufferRefs given to it have a unique
// name. If two members with the same name are provided, this causes a
// collision and ThinLTO can't proceed.
// So, we append the archive name to disambiguate two members with the same
// name from multiple different archives, and offset within the archive to
// disambiguate two members of the same name from a single archive.
MemoryBufferRef mbref(mb.getBuffer(),
saver().save(archiveName.empty()
? path
: archiveName +
sys::path::filename(path) +
utostr(offsetInArchive)));
obj = check(lto::InputFile::create(mbref));
if (lazy)
parseLazy();
else
parse();
}
void BitcodeFile::parse() {
// Convert LTO Symbols to LLD Symbols in order to perform resolution. The
// "winning" symbol will then be marked as Prevailing at LTO compilation
// time.
symbols.clear();
for (const lto::InputFile::Symbol &objSym : obj->symbols())
symbols.push_back(createBitcodeSymbol(objSym, *this));
}
void BitcodeFile::parseLazy() {
symbols.resize(obj->symbols().size());
for (auto it : llvm::enumerate(obj->symbols())) {
const lto::InputFile::Symbol &objSym = it.value();
if (!objSym.isUndefined()) {
symbols[it.index()] =
symtab->addLazyObject(saver().save(objSym.getName()), *this);
if (!lazy)
break;
}
}
}
void macho::extract(InputFile &file, StringRef reason) {
assert(file.lazy);
file.lazy = false;
printArchiveMemberLoad(reason, &file);
if (auto *bitcode = dyn_cast<BitcodeFile>(&file)) {
bitcode->parse();
} else {
auto &f = cast<ObjFile>(file);
if (target->wordSize == 8)
f.parse<LP64>();
else
f.parse<ILP32>();
}
}
template void ObjFile::parse<LP64>();
diff --git a/contrib/llvm-project/lld/MachO/UnwindInfoSection.cpp b/contrib/llvm-project/lld/MachO/UnwindInfoSection.cpp
index c3f563d5572b..ca6cbdfbb8bb 100644
--- a/contrib/llvm-project/lld/MachO/UnwindInfoSection.cpp
+++ b/contrib/llvm-project/lld/MachO/UnwindInfoSection.cpp
@@ -1,687 +1,708 @@
//===- UnwindInfoSection.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "UnwindInfoSection.h"
#include "ConcatOutputSection.h"
#include "Config.h"
#include "InputSection.h"
#include "OutputSection.h"
#include "OutputSegment.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Parallel.h"
#include <numeric>
using namespace llvm;
using namespace llvm::MachO;
using namespace llvm::support::endian;
using namespace lld;
using namespace lld::macho;
#define COMMON_ENCODINGS_MAX 127
#define COMPACT_ENCODINGS_MAX 256
#define SECOND_LEVEL_PAGE_BYTES 4096
#define SECOND_LEVEL_PAGE_WORDS (SECOND_LEVEL_PAGE_BYTES / sizeof(uint32_t))
#define REGULAR_SECOND_LEVEL_ENTRIES_MAX \
((SECOND_LEVEL_PAGE_BYTES - \
sizeof(unwind_info_regular_second_level_page_header)) / \
sizeof(unwind_info_regular_second_level_entry))
#define COMPRESSED_SECOND_LEVEL_ENTRIES_MAX \
((SECOND_LEVEL_PAGE_BYTES - \
sizeof(unwind_info_compressed_second_level_page_header)) / \
sizeof(uint32_t))
#define COMPRESSED_ENTRY_FUNC_OFFSET_BITS 24
#define COMPRESSED_ENTRY_FUNC_OFFSET_MASK \
UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(~0)
// Compact Unwind format is a Mach-O evolution of DWARF Unwind that
// optimizes space and exception-time lookup. Most DWARF unwind
// entries can be replaced with Compact Unwind entries, but the ones
// that cannot are retained in DWARF form.
//
// This comment will address macro-level organization of the pre-link
// and post-link compact unwind tables. For micro-level organization
// pertaining to the bitfield layout of the 32-bit compact unwind
// entries, see libunwind/include/mach-o/compact_unwind_encoding.h
//
// Important clarifying factoids:
//
// * __LD,__compact_unwind is the compact unwind format for compiler
// output and linker input. It is never a final output. It could be
// an intermediate output with the `-r` option which retains relocs.
//
// * __TEXT,__unwind_info is the compact unwind format for final
// linker output. It is never an input.
//
// * __TEXT,__eh_frame is the DWARF format for both linker input and output.
//
// * __TEXT,__unwind_info entries are divided into 4 KiB pages (2nd
// level) by ascending address, and the pages are referenced by an
// index (1st level) in the section header.
//
// * Following the headers in __TEXT,__unwind_info, the bulk of the
// section contains a vector of compact unwind entries
// `{functionOffset, encoding}` sorted by ascending `functionOffset`.
// Adjacent entries with the same encoding can be folded to great
// advantage, achieving a 3-order-of-magnitude reduction in the
// number of entries.
//
// * The __TEXT,__unwind_info format can accommodate up to 127 unique
// encodings for the space-efficient compressed format. In practice,
// fewer than a dozen unique encodings are used by C++ programs of
// all sizes. Therefore, we don't even bother implementing the regular
// non-compressed format. Time will tell if anyone in the field ever
// overflows the 127-encodings limit.
//
// Refer to the definition of unwind_info_section_header in
// compact_unwind_encoding.h for an overview of the format we are encoding
// here.
// TODO(gkm): prune __eh_frame entries superseded by __unwind_info, PR50410
// TODO(gkm): how do we align the 2nd-level pages?
// The offsets of various fields in the on-disk representation of each compact
// unwind entry.
struct CompactUnwindOffsets {
uint32_t functionAddress;
uint32_t functionLength;
uint32_t encoding;
uint32_t personality;
uint32_t lsda;
CompactUnwindOffsets(size_t wordSize) {
if (wordSize == 8)
init<uint64_t>();
else {
assert(wordSize == 4);
init<uint32_t>();
}
}
private:
template <class Ptr> void init() {
functionAddress = offsetof(Layout<Ptr>, functionAddress);
functionLength = offsetof(Layout<Ptr>, functionLength);
encoding = offsetof(Layout<Ptr>, encoding);
personality = offsetof(Layout<Ptr>, personality);
lsda = offsetof(Layout<Ptr>, lsda);
}
template <class Ptr> struct Layout {
Ptr functionAddress;
uint32_t functionLength;
compact_unwind_encoding_t encoding;
Ptr personality;
Ptr lsda;
};
};
// LLD's internal representation of a compact unwind entry.
struct CompactUnwindEntry {
uint64_t functionAddress;
uint32_t functionLength;
compact_unwind_encoding_t encoding;
Symbol *personality;
InputSection *lsda;
};
using EncodingMap = DenseMap<compact_unwind_encoding_t, size_t>;
struct SecondLevelPage {
uint32_t kind;
size_t entryIndex;
size_t entryCount;
size_t byteCount;
std::vector<compact_unwind_encoding_t> localEncodings;
EncodingMap localEncodingIndexes;
};
// UnwindInfoSectionImpl allows us to avoid cluttering our header file with a
// lengthy definition of UnwindInfoSection.
class UnwindInfoSectionImpl final : public UnwindInfoSection {
public:
UnwindInfoSectionImpl() : cuOffsets(target->wordSize) {}
uint64_t getSize() const override { return unwindInfoSize; }
void prepareRelocations() override;
void finalize() override;
void writeTo(uint8_t *buf) const override;
private:
void prepareRelocations(ConcatInputSection *);
void relocateCompactUnwind(std::vector<CompactUnwindEntry> &);
void encodePersonalities();
uint64_t unwindInfoSize = 0;
std::vector<decltype(symbols)::value_type> symbolsVec;
CompactUnwindOffsets cuOffsets;
std::vector<std::pair<compact_unwind_encoding_t, size_t>> commonEncodings;
EncodingMap commonEncodingIndexes;
// The entries here will be in the same order as their originating symbols
// in symbolsVec.
std::vector<CompactUnwindEntry> cuEntries;
// Indices into the cuEntries vector.
std::vector<size_t> cuIndices;
std::vector<Symbol *> personalities;
SmallDenseMap<std::pair<InputSection *, uint64_t /* addend */>, Symbol *>
personalityTable;
// Indices into cuEntries for CUEs with a non-null LSDA.
std::vector<size_t> entriesWithLsda;
// Map of cuEntries index to an index within the LSDA array.
DenseMap<size_t, uint32_t> lsdaIndex;
std::vector<SecondLevelPage> secondLevelPages;
uint64_t level2PagesOffset = 0;
};
UnwindInfoSection::UnwindInfoSection()
: SyntheticSection(segment_names::text, section_names::unwindInfo) {
align = 4;
}
// Record function symbols that may need entries emitted in __unwind_info, which
// stores unwind data for address ranges.
//
-// Note that if several adjacent functions have the same unwind encoding, LSDA,
-// and personality function, they share one unwind entry. For this to work,
-// functions without unwind info need explicit "no unwind info" unwind entries
-// -- else the unwinder would think they have the unwind info of the closest
-// function with unwind info right before in the image. Thus, we add function
-// symbols for each unique address regardless of whether they have associated
-// unwind info.
+// Note that if several adjacent functions have the same unwind encoding and
+// personality function and no LSDA, they share one unwind entry. For this to
+// work, functions without unwind info need explicit "no unwind info" unwind
+// entries -- else the unwinder would think they have the unwind info of the
+// closest function with unwind info right before in the image. Thus, we add
+// function symbols for each unique address regardless of whether they have
+// associated unwind info.
void UnwindInfoSection::addSymbol(const Defined *d) {
if (d->unwindEntry)
allEntriesAreOmitted = false;
// We don't yet know the final output address of this symbol, but we know that
// they are uniquely determined by a combination of the isec and value, so
// we use that as the key here.
auto p = symbols.insert({{d->isec, d->value}, d});
// If we have multiple symbols at the same address, only one of them can have
// an associated unwind entry.
if (!p.second && d->unwindEntry) {
assert(!p.first->second->unwindEntry);
p.first->second = d;
}
}
void UnwindInfoSectionImpl::prepareRelocations() {
// This iteration needs to be deterministic, since prepareRelocations may add
// entries to the GOT. Hence the use of a MapVector for
// UnwindInfoSection::symbols.
for (const Defined *d : make_second_range(symbols))
if (d->unwindEntry &&
d->unwindEntry->getName() == section_names::compactUnwind)
prepareRelocations(d->unwindEntry);
}
// Compact unwind relocations have different semantics, so we handle them in a
// separate code path from regular relocations. First, we do not wish to add
// rebase opcodes for __LD,__compact_unwind, because that section doesn't
// actually end up in the final binary. Second, personality pointers always
// reside in the GOT and must be treated specially.
void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) {
assert(!isec->shouldOmitFromOutput() &&
"__compact_unwind section should not be omitted");
// FIXME: Make this skip relocations for CompactUnwindEntries that
// point to dead-stripped functions. That might save some amount of
// work. But since there are usually just few personality functions
// that are referenced from many places, at least some of them likely
// live, it wouldn't reduce number of got entries.
for (size_t i = 0; i < isec->relocs.size(); ++i) {
Reloc &r = isec->relocs[i];
assert(target->hasAttr(r.type, RelocAttrBits::UNSIGNED));
// Functions and LSDA entries always reside in the same object file as the
// compact unwind entries that references them, and thus appear as section
// relocs. There is no need to prepare them. We only prepare relocs for
// personality functions.
if (r.offset != cuOffsets.personality)
continue;
if (auto *s = r.referent.dyn_cast<Symbol *>()) {
// Personality functions are nearly always system-defined (e.g.,
// ___gxx_personality_v0 for C++) and relocated as dylib symbols. When an
// application provides its own personality function, it might be
// referenced by an extern Defined symbol reloc, or a local section reloc.
if (auto *defined = dyn_cast<Defined>(s)) {
// XXX(vyng) This is a a special case for handling duplicate personality
// symbols. Note that LD64's behavior is a bit different and it is
// inconsistent with how symbol resolution usually work
//
// So we've decided not to follow it. Instead, simply pick the symbol
// with the same name from the symbol table to replace the local one.
//
// (See discussions/alternatives already considered on D107533)
if (!defined->isExternal())
if (Symbol *sym = symtab->find(defined->getName()))
if (!sym->isLazy())
r.referent = s = sym;
}
if (auto *undefined = dyn_cast<Undefined>(s)) {
treatUndefinedSymbol(*undefined, isec, r.offset);
// treatUndefinedSymbol() can replace s with a DylibSymbol; re-check.
if (isa<Undefined>(s))
continue;
}
if (auto *defined = dyn_cast<Defined>(s)) {
// Check if we have created a synthetic symbol at the same address.
Symbol *&personality =
personalityTable[{defined->isec, defined->value}];
if (personality == nullptr) {
personality = defined;
in.got->addEntry(defined);
} else if (personality != defined) {
r.referent = personality;
}
continue;
}
assert(isa<DylibSymbol>(s));
in.got->addEntry(s);
continue;
}
if (auto *referentIsec = r.referent.dyn_cast<InputSection *>()) {
assert(!isCoalescedWeak(referentIsec));
// Personality functions can be referenced via section relocations
// if they live in the same object file. Create placeholder synthetic
// symbols for them in the GOT.
Symbol *&s = personalityTable[{referentIsec, r.addend}];
if (s == nullptr) {
// This runs after dead stripping, so the noDeadStrip argument does not
// matter.
s = make<Defined>("<internal>", /*file=*/nullptr, referentIsec,
r.addend, /*size=*/0, /*isWeakDef=*/false,
/*isExternal=*/false, /*isPrivateExtern=*/false,
/*includeInSymtab=*/true,
/*isThumb=*/false, /*isReferencedDynamically=*/false,
/*noDeadStrip=*/false);
s->used = true;
in.got->addEntry(s);
}
r.referent = s;
r.addend = 0;
}
}
}
// We need to apply the relocations to the pre-link compact unwind section
// before converting it to post-link form. There should only be absolute
// relocations here: since we are not emitting the pre-link CU section, there
// is no source address to make a relative location meaningful.
void UnwindInfoSectionImpl::relocateCompactUnwind(
std::vector<CompactUnwindEntry> &cuEntries) {
parallelFor(0, symbolsVec.size(), [&](size_t i) {
CompactUnwindEntry &cu = cuEntries[i];
const Defined *d = symbolsVec[i].second;
cu.functionAddress = d->getVA();
if (!d->unwindEntry)
return;
// If we have DWARF unwind info, create a CU entry that points to it.
if (d->unwindEntry->getName() == section_names::ehFrame) {
cu.encoding = target->modeDwarfEncoding | d->unwindEntry->outSecOff;
const FDE &fde = cast<ObjFile>(d->getFile())->fdes[d->unwindEntry];
cu.functionLength = fde.funcLength;
cu.personality = fde.personality;
cu.lsda = fde.lsda;
return;
}
assert(d->unwindEntry->getName() == section_names::compactUnwind);
auto buf = reinterpret_cast<const uint8_t *>(d->unwindEntry->data.data()) -
target->wordSize;
cu.functionLength =
support::endian::read32le(buf + cuOffsets.functionLength);
cu.encoding = support::endian::read32le(buf + cuOffsets.encoding);
for (const Reloc &r : d->unwindEntry->relocs) {
if (r.offset == cuOffsets.personality) {
cu.personality = r.referent.get<Symbol *>();
} else if (r.offset == cuOffsets.lsda) {
if (auto *referentSym = r.referent.dyn_cast<Symbol *>())
cu.lsda = cast<Defined>(referentSym)->isec;
else
cu.lsda = r.referent.get<InputSection *>();
}
}
});
}
// There should only be a handful of unique personality pointers, so we can
// encode them as 2-bit indices into a small array.
void UnwindInfoSectionImpl::encodePersonalities() {
for (size_t idx : cuIndices) {
CompactUnwindEntry &cu = cuEntries[idx];
if (cu.personality == nullptr)
continue;
// Linear search is fast enough for a small array.
auto it = find(personalities, cu.personality);
uint32_t personalityIndex; // 1-based index
if (it != personalities.end()) {
personalityIndex = std::distance(personalities.begin(), it) + 1;
} else {
personalities.push_back(cu.personality);
personalityIndex = personalities.size();
}
cu.encoding |=
personalityIndex << countTrailingZeros(
static_cast<compact_unwind_encoding_t>(UNWIND_PERSONALITY_MASK));
}
if (personalities.size() > 3)
error("too many personalities (" + Twine(personalities.size()) +
") for compact unwind to encode");
}
static bool canFoldEncoding(compact_unwind_encoding_t encoding) {
// From compact_unwind_encoding.h:
// UNWIND_X86_64_MODE_STACK_IND:
// A "frameless" (RBP not used as frame pointer) function large constant
// stack size. This case is like the previous, except the stack size is too
// large to encode in the compact unwind encoding. Instead it requires that
// the function contains "subq $nnnnnnnn,RSP" in its prolog. The compact
// encoding contains the offset to the nnnnnnnn value in the function in
// UNWIND_X86_64_FRAMELESS_STACK_SIZE.
// Since this means the unwinder has to look at the `subq` in the function
// of the unwind info's unwind address, two functions that have identical
// unwind info can't be folded if it's using this encoding since both
// entries need unique addresses.
static_assert(static_cast<uint32_t>(UNWIND_X86_64_MODE_MASK) ==
static_cast<uint32_t>(UNWIND_X86_MODE_MASK),
"");
static_assert(static_cast<uint32_t>(UNWIND_X86_64_MODE_STACK_IND) ==
static_cast<uint32_t>(UNWIND_X86_MODE_STACK_IND),
"");
if ((target->cpuType == CPU_TYPE_X86_64 || target->cpuType == CPU_TYPE_X86) &&
(encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_STACK_IND) {
// FIXME: Consider passing in the two function addresses and getting
// their two stack sizes off the `subq` and only returning false if they're
// actually different.
return false;
}
return true;
}
// Scan the __LD,__compact_unwind entries and compute the space needs of
// __TEXT,__unwind_info and __TEXT,__eh_frame.
void UnwindInfoSectionImpl::finalize() {
if (symbols.empty())
return;
// At this point, the address space for __TEXT,__text has been
// assigned, so we can relocate the __LD,__compact_unwind entries
// into a temporary buffer. Relocation is necessary in order to sort
// the CU entries by function address. Sorting is necessary so that
- // we can fold adjacent CU entries with identical
- // encoding+personality+lsda. Folding is necessary because it reduces
- // the number of CU entries by as much as 3 orders of magnitude!
+ // we can fold adjacent CU entries with identical encoding+personality
+ // and without any LSDA. Folding is necessary because it reduces the
+ // number of CU entries by as much as 3 orders of magnitude!
cuEntries.resize(symbols.size());
// The "map" part of the symbols MapVector was only needed for deduplication
// in addSymbol(). Now that we are done adding, move the contents to a plain
// std::vector for indexed access.
symbolsVec = symbols.takeVector();
relocateCompactUnwind(cuEntries);
// Rather than sort & fold the 32-byte entries directly, we create a
// vector of indices to entries and sort & fold that instead.
cuIndices.resize(cuEntries.size());
std::iota(cuIndices.begin(), cuIndices.end(), 0);
llvm::sort(cuIndices, [&](size_t a, size_t b) {
return cuEntries[a].functionAddress < cuEntries[b].functionAddress;
});
- // Fold adjacent entries with matching encoding+personality+lsda
+ // Fold adjacent entries with matching encoding+personality and without LSDA
// We use three iterators on the same cuIndices to fold in-situ:
// (1) `foldBegin` is the first of a potential sequence of matching entries
// (2) `foldEnd` is the first non-matching entry after `foldBegin`.
// The semi-open interval [ foldBegin .. foldEnd ) contains a range
// entries that can be folded into a single entry and written to ...
// (3) `foldWrite`
auto foldWrite = cuIndices.begin();
for (auto foldBegin = cuIndices.begin(); foldBegin < cuIndices.end();) {
auto foldEnd = foldBegin;
+ // Common LSDA encodings (e.g. for C++ and Objective-C) contain offsets from
+ // a base address. The base address is normally not contained directly in
+ // the LSDA, and in that case, the personality function treats the starting
+ // address of the function (which is computed by the unwinder) as the base
+ // address and interprets the LSDA accordingly. The unwinder computes the
+ // starting address of a function as the address associated with its CU
+ // entry. For this reason, we cannot fold adjacent entries if they have an
+ // LSDA, because folding would make the unwinder compute the wrong starting
+ // address for the functions with the folded entries, which in turn would
+ // cause the personality function to misinterpret the LSDA for those
+ // functions. In the very rare case where the base address is encoded
+ // directly in the LSDA, two functions at different addresses would
+ // necessarily have different LSDAs, so their CU entries would not have been
+ // folded anyway.
while (++foldEnd < cuIndices.end() &&
cuEntries[*foldBegin].encoding == cuEntries[*foldEnd].encoding &&
+ !cuEntries[*foldBegin].lsda && !cuEntries[*foldEnd].lsda &&
+ // If we've gotten to this point, we don't have an LSDA, which should
+ // also imply that we don't have a personality function, since in all
+ // likelihood a personality function needs the LSDA to do anything
+ // useful. It can be technically valid to have a personality function
+ // and no LSDA though (e.g. the C++ personality __gxx_personality_v0
+ // is just a no-op without LSDA), so we still check for personality
+ // function equivalence to handle that case.
cuEntries[*foldBegin].personality ==
cuEntries[*foldEnd].personality &&
- cuEntries[*foldBegin].lsda == cuEntries[*foldEnd].lsda &&
canFoldEncoding(cuEntries[*foldEnd].encoding))
;
*foldWrite++ = *foldBegin;
foldBegin = foldEnd;
}
cuIndices.erase(foldWrite, cuIndices.end());
encodePersonalities();
// Count frequencies of the folded encodings
EncodingMap encodingFrequencies;
for (size_t idx : cuIndices)
encodingFrequencies[cuEntries[idx].encoding]++;
// Make a vector of encodings, sorted by descending frequency
for (const auto &frequency : encodingFrequencies)
commonEncodings.emplace_back(frequency);
llvm::sort(commonEncodings,
[](const std::pair<compact_unwind_encoding_t, size_t> &a,
const std::pair<compact_unwind_encoding_t, size_t> &b) {
if (a.second == b.second)
// When frequencies match, secondarily sort on encoding
// to maintain parity with validate-unwind-info.py
return a.first > b.first;
return a.second > b.second;
});
// Truncate the vector to 127 elements.
// Common encoding indexes are limited to 0..126, while encoding
// indexes 127..255 are local to each second-level page
if (commonEncodings.size() > COMMON_ENCODINGS_MAX)
commonEncodings.resize(COMMON_ENCODINGS_MAX);
// Create a map from encoding to common-encoding-table index
for (size_t i = 0; i < commonEncodings.size(); i++)
commonEncodingIndexes[commonEncodings[i].first] = i;
// Split folded encodings into pages, where each page is limited by ...
// (a) 4 KiB capacity
// (b) 24-bit difference between first & final function address
// (c) 8-bit compact-encoding-table index,
// for which 0..126 references the global common-encodings table,
// and 127..255 references a local per-second-level-page table.
// First we try the compact format and determine how many entries fit.
// If more entries fit in the regular format, we use that.
for (size_t i = 0; i < cuIndices.size();) {
size_t idx = cuIndices[i];
secondLevelPages.emplace_back();
SecondLevelPage &page = secondLevelPages.back();
page.entryIndex = i;
uint64_t functionAddressMax =
cuEntries[idx].functionAddress + COMPRESSED_ENTRY_FUNC_OFFSET_MASK;
size_t n = commonEncodings.size();
size_t wordsRemaining =
SECOND_LEVEL_PAGE_WORDS -
sizeof(unwind_info_compressed_second_level_page_header) /
sizeof(uint32_t);
while (wordsRemaining >= 1 && i < cuIndices.size()) {
idx = cuIndices[i];
const CompactUnwindEntry *cuPtr = &cuEntries[idx];
if (cuPtr->functionAddress >= functionAddressMax) {
break;
} else if (commonEncodingIndexes.count(cuPtr->encoding) ||
page.localEncodingIndexes.count(cuPtr->encoding)) {
i++;
wordsRemaining--;
} else if (wordsRemaining >= 2 && n < COMPACT_ENCODINGS_MAX) {
page.localEncodings.emplace_back(cuPtr->encoding);
page.localEncodingIndexes[cuPtr->encoding] = n++;
i++;
wordsRemaining -= 2;
} else {
break;
}
}
page.entryCount = i - page.entryIndex;
// If this is not the final page, see if it's possible to fit more
// entries by using the regular format. This can happen when there
// are many unique encodings, and we we saturated the local
// encoding table early.
if (i < cuIndices.size() &&
page.entryCount < REGULAR_SECOND_LEVEL_ENTRIES_MAX) {
page.kind = UNWIND_SECOND_LEVEL_REGULAR;
page.entryCount = std::min(REGULAR_SECOND_LEVEL_ENTRIES_MAX,
cuIndices.size() - page.entryIndex);
i = page.entryIndex + page.entryCount;
} else {
page.kind = UNWIND_SECOND_LEVEL_COMPRESSED;
}
}
for (size_t idx : cuIndices) {
lsdaIndex[idx] = entriesWithLsda.size();
if (cuEntries[idx].lsda)
entriesWithLsda.push_back(idx);
}
// compute size of __TEXT,__unwind_info section
level2PagesOffset = sizeof(unwind_info_section_header) +
commonEncodings.size() * sizeof(uint32_t) +
personalities.size() * sizeof(uint32_t) +
// The extra second-level-page entry is for the sentinel
(secondLevelPages.size() + 1) *
sizeof(unwind_info_section_header_index_entry) +
entriesWithLsda.size() *
sizeof(unwind_info_section_header_lsda_index_entry);
unwindInfoSize =
level2PagesOffset + secondLevelPages.size() * SECOND_LEVEL_PAGE_BYTES;
}
// All inputs are relocated and output addresses are known, so write!
void UnwindInfoSectionImpl::writeTo(uint8_t *buf) const {
assert(!cuIndices.empty() && "call only if there is unwind info");
// section header
auto *uip = reinterpret_cast<unwind_info_section_header *>(buf);
uip->version = 1;
uip->commonEncodingsArraySectionOffset = sizeof(unwind_info_section_header);
uip->commonEncodingsArrayCount = commonEncodings.size();
uip->personalityArraySectionOffset =
uip->commonEncodingsArraySectionOffset +
(uip->commonEncodingsArrayCount * sizeof(uint32_t));
uip->personalityArrayCount = personalities.size();
uip->indexSectionOffset = uip->personalityArraySectionOffset +
(uip->personalityArrayCount * sizeof(uint32_t));
uip->indexCount = secondLevelPages.size() + 1;
// Common encodings
auto *i32p = reinterpret_cast<uint32_t *>(&uip[1]);
for (const auto &encoding : commonEncodings)
*i32p++ = encoding.first;
// Personalities
for (const Symbol *personality : personalities)
*i32p++ = personality->getGotVA() - in.header->addr;
// Level-1 index
uint32_t lsdaOffset =
uip->indexSectionOffset +
uip->indexCount * sizeof(unwind_info_section_header_index_entry);
uint64_t l2PagesOffset = level2PagesOffset;
auto *iep = reinterpret_cast<unwind_info_section_header_index_entry *>(i32p);
for (const SecondLevelPage &page : secondLevelPages) {
size_t idx = cuIndices[page.entryIndex];
iep->functionOffset = cuEntries[idx].functionAddress - in.header->addr;
iep->secondLevelPagesSectionOffset = l2PagesOffset;
iep->lsdaIndexArraySectionOffset =
lsdaOffset + lsdaIndex.lookup(idx) *
sizeof(unwind_info_section_header_lsda_index_entry);
iep++;
l2PagesOffset += SECOND_LEVEL_PAGE_BYTES;
}
// Level-1 sentinel
const CompactUnwindEntry &cuEnd = cuEntries[cuIndices.back()];
iep->functionOffset =
cuEnd.functionAddress - in.header->addr + cuEnd.functionLength;
iep->secondLevelPagesSectionOffset = 0;
iep->lsdaIndexArraySectionOffset =
lsdaOffset + entriesWithLsda.size() *
sizeof(unwind_info_section_header_lsda_index_entry);
iep++;
// LSDAs
auto *lep =
reinterpret_cast<unwind_info_section_header_lsda_index_entry *>(iep);
for (size_t idx : entriesWithLsda) {
const CompactUnwindEntry &cu = cuEntries[idx];
lep->lsdaOffset = cu.lsda->getVA(/*off=*/0) - in.header->addr;
lep->functionOffset = cu.functionAddress - in.header->addr;
lep++;
}
// Level-2 pages
auto *pp = reinterpret_cast<uint32_t *>(lep);
for (const SecondLevelPage &page : secondLevelPages) {
if (page.kind == UNWIND_SECOND_LEVEL_COMPRESSED) {
uintptr_t functionAddressBase =
cuEntries[cuIndices[page.entryIndex]].functionAddress;
auto *p2p =
reinterpret_cast<unwind_info_compressed_second_level_page_header *>(
pp);
p2p->kind = page.kind;
p2p->entryPageOffset =
sizeof(unwind_info_compressed_second_level_page_header);
p2p->entryCount = page.entryCount;
p2p->encodingsPageOffset =
p2p->entryPageOffset + p2p->entryCount * sizeof(uint32_t);
p2p->encodingsCount = page.localEncodings.size();
auto *ep = reinterpret_cast<uint32_t *>(&p2p[1]);
for (size_t i = 0; i < page.entryCount; i++) {
const CompactUnwindEntry &cue =
cuEntries[cuIndices[page.entryIndex + i]];
auto it = commonEncodingIndexes.find(cue.encoding);
if (it == commonEncodingIndexes.end())
it = page.localEncodingIndexes.find(cue.encoding);
*ep++ = (it->second << COMPRESSED_ENTRY_FUNC_OFFSET_BITS) |
(cue.functionAddress - functionAddressBase);
}
if (!page.localEncodings.empty())
memcpy(ep, page.localEncodings.data(),
page.localEncodings.size() * sizeof(uint32_t));
} else {
auto *p2p =
reinterpret_cast<unwind_info_regular_second_level_page_header *>(pp);
p2p->kind = page.kind;
p2p->entryPageOffset =
sizeof(unwind_info_regular_second_level_page_header);
p2p->entryCount = page.entryCount;
auto *ep = reinterpret_cast<uint32_t *>(&p2p[1]);
for (size_t i = 0; i < page.entryCount; i++) {
const CompactUnwindEntry &cue =
cuEntries[cuIndices[page.entryIndex + i]];
*ep++ = cue.functionAddress;
*ep++ = cue.encoding;
}
}
pp += SECOND_LEVEL_PAGE_WORDS;
}
}
UnwindInfoSection *macho::makeUnwindInfoSection() {
return make<UnwindInfoSectionImpl>();
}
diff --git a/contrib/llvm-project/llvm/include/llvm/ADT/GenericCycleImpl.h b/contrib/llvm-project/llvm/include/llvm/ADT/GenericCycleImpl.h
index ea2847f8c8ee..07ac1768ea27 100644
--- a/contrib/llvm-project/llvm/include/llvm/ADT/GenericCycleImpl.h
+++ b/contrib/llvm-project/llvm/include/llvm/ADT/GenericCycleImpl.h
@@ -1,464 +1,477 @@
//===- GenericCycleImpl.h -------------------------------------*- C++ -*---===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This template implementation resides in a separate file so that it
/// does not get injected into every .cpp file that includes the
/// generic header.
///
/// DO NOT INCLUDE THIS FILE WHEN MERELY USING CYCLEINFO.
///
/// This file should only be included by files that implement a
/// specialization of the relevant templates. Currently these are:
/// - CycleAnalysis.cpp
/// - MachineCycleAnalysis.cpp
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_GENERICCYCLEIMPL_H
#define LLVM_ADT_GENERICCYCLEIMPL_H
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/GenericCycleInfo.h"
#define DEBUG_TYPE "generic-cycle-impl"
namespace llvm {
template <typename ContextT>
bool GenericCycle<ContextT>::contains(const GenericCycle *C) const {
if (!C)
return false;
if (Depth > C->Depth)
return false;
while (Depth < C->Depth)
C = C->ParentCycle;
return this == C;
}
template <typename ContextT>
void GenericCycle<ContextT>::getExitBlocks(
SmallVectorImpl<BlockT *> &TmpStorage) const {
TmpStorage.clear();
size_t NumExitBlocks = 0;
for (BlockT *Block : blocks()) {
llvm::append_range(TmpStorage, successors(Block));
for (size_t Idx = NumExitBlocks, End = TmpStorage.size(); Idx < End;
++Idx) {
BlockT *Succ = TmpStorage[Idx];
if (!contains(Succ)) {
auto ExitEndIt = TmpStorage.begin() + NumExitBlocks;
if (std::find(TmpStorage.begin(), ExitEndIt, Succ) == ExitEndIt)
TmpStorage[NumExitBlocks++] = Succ;
}
}
TmpStorage.resize(NumExitBlocks);
}
}
template <typename ContextT>
auto GenericCycle<ContextT>::getCyclePreheader() const -> BlockT * {
BlockT *Predecessor = getCyclePredecessor();
if (!Predecessor)
return nullptr;
assert(isReducible() && "Cycle Predecessor must be in a reducible cycle!");
if (succ_size(Predecessor) != 1)
return nullptr;
// Make sure we are allowed to hoist instructions into the predecessor.
if (!Predecessor->isLegalToHoistInto())
return nullptr;
return Predecessor;
}
template <typename ContextT>
auto GenericCycle<ContextT>::getCyclePredecessor() const -> BlockT * {
if (!isReducible())
return nullptr;
BlockT *Out = nullptr;
// Loop over the predecessors of the header node...
BlockT *Header = getHeader();
for (const auto Pred : predecessors(Header)) {
if (!contains(Pred)) {
if (Out && Out != Pred)
return nullptr;
Out = Pred;
}
}
return Out;
}
/// \brief Helper class for computing cycle information.
template <typename ContextT> class GenericCycleInfoCompute {
using BlockT = typename ContextT::BlockT;
using CycleInfoT = GenericCycleInfo<ContextT>;
using CycleT = typename CycleInfoT::CycleT;
CycleInfoT &Info;
struct DFSInfo {
unsigned Start = 0; // DFS start; positive if block is found
unsigned End = 0; // DFS end
DFSInfo() = default;
explicit DFSInfo(unsigned Start) : Start(Start) {}
/// Whether this node is an ancestor (or equal to) the node \p Other
/// in the DFS tree.
bool isAncestorOf(const DFSInfo &Other) const {
return Start <= Other.Start && Other.End <= End;
}
};
DenseMap<BlockT *, DFSInfo> BlockDFSInfo;
SmallVector<BlockT *, 8> BlockPreorder;
GenericCycleInfoCompute(const GenericCycleInfoCompute &) = delete;
GenericCycleInfoCompute &operator=(const GenericCycleInfoCompute &) = delete;
public:
GenericCycleInfoCompute(CycleInfoT &Info) : Info(Info) {}
void run(BlockT *EntryBlock);
static void updateDepth(CycleT *SubTree);
private:
void dfs(BlockT *EntryBlock);
};
template <typename ContextT>
-auto GenericCycleInfo<ContextT>::getTopLevelParentCycle(
- const BlockT *Block) const -> CycleT * {
+auto GenericCycleInfo<ContextT>::getTopLevelParentCycle(BlockT *Block)
+ -> CycleT * {
+ auto Cycle = BlockMapTopLevel.find(Block);
+ if (Cycle != BlockMapTopLevel.end())
+ return Cycle->second;
+
auto MapIt = BlockMap.find(Block);
if (MapIt == BlockMap.end())
return nullptr;
auto *C = MapIt->second;
while (C->ParentCycle)
C = C->ParentCycle;
+ BlockMapTopLevel.try_emplace(Block, C);
return C;
}
template <typename ContextT>
-void GenericCycleInfo<ContextT>::moveToNewParent(CycleT *NewParent,
- CycleT *Child) {
+void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent,
+ CycleT *Child) {
+ assert((!Child->ParentCycle && !NewParent->ParentCycle) &&
+ "NewParent and Child must be both top level cycle!\n");
auto &CurrentContainer =
Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles;
auto Pos = llvm::find_if(CurrentContainer, [=](const auto &Ptr) -> bool {
return Child == Ptr.get();
});
assert(Pos != CurrentContainer.end());
NewParent->Children.push_back(std::move(*Pos));
*Pos = std::move(CurrentContainer.back());
CurrentContainer.pop_back();
Child->ParentCycle = NewParent;
+
+ NewParent->Blocks.insert(NewParent->Blocks.end(), Child->block_begin(),
+ Child->block_end());
+
+ for (auto &It : BlockMapTopLevel)
+ if (It.second == Child)
+ It.second = NewParent;
}
/// \brief Main function of the cycle info computations.
template <typename ContextT>
void GenericCycleInfoCompute<ContextT>::run(BlockT *EntryBlock) {
LLVM_DEBUG(errs() << "Entry block: " << Info.Context.print(EntryBlock)
<< "\n");
dfs(EntryBlock);
SmallVector<BlockT *, 8> Worklist;
for (BlockT *HeaderCandidate : llvm::reverse(BlockPreorder)) {
const DFSInfo CandidateInfo = BlockDFSInfo.lookup(HeaderCandidate);
for (BlockT *Pred : predecessors(HeaderCandidate)) {
const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred);
if (CandidateInfo.isAncestorOf(PredDFSInfo))
Worklist.push_back(Pred);
}
if (Worklist.empty()) {
continue;
}
// Found a cycle with the candidate as its header.
LLVM_DEBUG(errs() << "Found cycle for header: "
<< Info.Context.print(HeaderCandidate) << "\n");
std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>();
NewCycle->appendEntry(HeaderCandidate);
NewCycle->appendBlock(HeaderCandidate);
Info.BlockMap.try_emplace(HeaderCandidate, NewCycle.get());
// Helper function to process (non-back-edge) predecessors of a discovered
// block and either add them to the worklist or recognize that the given
// block is an additional cycle entry.
auto ProcessPredecessors = [&](BlockT *Block) {
LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": ");
bool IsEntry = false;
for (BlockT *Pred : predecessors(Block)) {
const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred);
if (CandidateInfo.isAncestorOf(PredDFSInfo)) {
Worklist.push_back(Pred);
} else {
IsEntry = true;
}
}
if (IsEntry) {
assert(!NewCycle->isEntry(Block));
LLVM_DEBUG(errs() << "append as entry\n");
NewCycle->appendEntry(Block);
} else {
LLVM_DEBUG(errs() << "append as child\n");
}
};
do {
BlockT *Block = Worklist.pop_back_val();
if (Block == HeaderCandidate)
continue;
// If the block has already been discovered by some cycle
// (possibly by ourself), then the outermost cycle containing it
// should become our child.
if (auto *BlockParent = Info.getTopLevelParentCycle(Block)) {
LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": ");
if (BlockParent != NewCycle.get()) {
LLVM_DEBUG(errs()
<< "discovered child cycle "
<< Info.Context.print(BlockParent->getHeader()) << "\n");
// Make BlockParent the child of NewCycle.
- Info.moveToNewParent(NewCycle.get(), BlockParent);
- NewCycle->Blocks.insert(NewCycle->Blocks.end(),
- BlockParent->block_begin(),
- BlockParent->block_end());
+ Info.moveTopLevelCycleToNewParent(NewCycle.get(), BlockParent);
for (auto *ChildEntry : BlockParent->entries())
ProcessPredecessors(ChildEntry);
} else {
LLVM_DEBUG(errs()
<< "known child cycle "
<< Info.Context.print(BlockParent->getHeader()) << "\n");
}
} else {
Info.BlockMap.try_emplace(Block, NewCycle.get());
assert(!is_contained(NewCycle->Blocks, Block));
NewCycle->Blocks.push_back(Block);
ProcessPredecessors(Block);
+ Info.BlockMapTopLevel.try_emplace(Block, NewCycle.get());
}
} while (!Worklist.empty());
Info.TopLevelCycles.push_back(std::move(NewCycle));
}
// Fix top-level cycle links and compute cycle depths.
for (auto *TLC : Info.toplevel_cycles()) {
LLVM_DEBUG(errs() << "top-level cycle: "
<< Info.Context.print(TLC->getHeader()) << "\n");
TLC->ParentCycle = nullptr;
updateDepth(TLC);
}
}
/// \brief Recompute depth values of \p SubTree and all descendants.
template <typename ContextT>
void GenericCycleInfoCompute<ContextT>::updateDepth(CycleT *SubTree) {
for (CycleT *Cycle : depth_first(SubTree))
Cycle->Depth = Cycle->ParentCycle ? Cycle->ParentCycle->Depth + 1 : 1;
}
/// \brief Compute a DFS of basic blocks starting at the function entry.
///
/// Fills BlockDFSInfo with start/end counters and BlockPreorder.
template <typename ContextT>
void GenericCycleInfoCompute<ContextT>::dfs(BlockT *EntryBlock) {
SmallVector<unsigned, 8> DFSTreeStack;
SmallVector<BlockT *, 8> TraverseStack;
unsigned Counter = 0;
TraverseStack.emplace_back(EntryBlock);
do {
BlockT *Block = TraverseStack.back();
LLVM_DEBUG(errs() << "DFS visiting block: " << Info.Context.print(Block)
<< "\n");
if (!BlockDFSInfo.count(Block)) {
// We're visiting the block for the first time. Open its DFSInfo, add
// successors to the traversal stack, and remember the traversal stack
// depth at which the block was opened, so that we can correctly record
// its end time.
LLVM_DEBUG(errs() << " first encountered at depth "
<< TraverseStack.size() << "\n");
DFSTreeStack.emplace_back(TraverseStack.size());
llvm::append_range(TraverseStack, successors(Block));
bool Added = BlockDFSInfo.try_emplace(Block, ++Counter).second;
(void)Added;
assert(Added);
BlockPreorder.push_back(Block);
LLVM_DEBUG(errs() << " preorder number: " << Counter << "\n");
} else {
assert(!DFSTreeStack.empty());
if (DFSTreeStack.back() == TraverseStack.size()) {
LLVM_DEBUG(errs() << " ended at " << Counter << "\n");
BlockDFSInfo.find(Block)->second.End = Counter;
DFSTreeStack.pop_back();
} else {
LLVM_DEBUG(errs() << " already done\n");
}
TraverseStack.pop_back();
}
} while (!TraverseStack.empty());
assert(DFSTreeStack.empty());
LLVM_DEBUG(
errs() << "Preorder:\n";
for (int i = 0, e = BlockPreorder.size(); i != e; ++i) {
errs() << " " << Info.Context.print(BlockPreorder[i]) << ": " << i << "\n";
}
);
}
/// \brief Reset the object to its initial state.
template <typename ContextT> void GenericCycleInfo<ContextT>::clear() {
TopLevelCycles.clear();
BlockMap.clear();
+ BlockMapTopLevel.clear();
}
/// \brief Compute the cycle info for a function.
template <typename ContextT>
void GenericCycleInfo<ContextT>::compute(FunctionT &F) {
GenericCycleInfoCompute<ContextT> Compute(*this);
Context.setFunction(F);
LLVM_DEBUG(errs() << "Computing cycles for function: " << F.getName()
<< "\n");
Compute.run(ContextT::getEntryBlock(F));
assert(validateTree());
}
/// \brief Find the innermost cycle containing a given block.
///
/// \returns the innermost cycle containing \p Block or nullptr if
/// it is not contained in any cycle.
template <typename ContextT>
auto GenericCycleInfo<ContextT>::getCycle(const BlockT *Block) const
-> CycleT * {
auto MapIt = BlockMap.find(Block);
if (MapIt != BlockMap.end())
return MapIt->second;
return nullptr;
}
/// \brief get the depth for the cycle which containing a given block.
///
/// \returns the depth for the innermost cycle containing \p Block or 0 if it is
/// not contained in any cycle.
template <typename ContextT>
unsigned GenericCycleInfo<ContextT>::getCycleDepth(const BlockT *Block) const {
CycleT *Cycle = getCycle(Block);
if (!Cycle)
return 0;
return Cycle->getDepth();
}
#ifndef NDEBUG
/// \brief Validate the internal consistency of the cycle tree.
///
/// Note that this does \em not check that cycles are really cycles in the CFG,
/// or that the right set of cycles in the CFG were found.
template <typename ContextT>
bool GenericCycleInfo<ContextT>::validateTree() const {
DenseSet<BlockT *> Blocks;
DenseSet<BlockT *> Entries;
auto reportError = [](const char *File, int Line, const char *Cond) {
errs() << File << ':' << Line
<< ": GenericCycleInfo::validateTree: " << Cond << '\n';
};
#define check(cond) \
do { \
if (!(cond)) { \
reportError(__FILE__, __LINE__, #cond); \
return false; \
} \
} while (false)
for (const auto *TLC : toplevel_cycles()) {
for (const CycleT *Cycle : depth_first(TLC)) {
if (Cycle->ParentCycle)
check(is_contained(Cycle->ParentCycle->children(), Cycle));
for (BlockT *Block : Cycle->Blocks) {
auto MapIt = BlockMap.find(Block);
check(MapIt != BlockMap.end());
check(Cycle->contains(MapIt->second));
check(Blocks.insert(Block).second); // duplicates in block list?
}
Blocks.clear();
check(!Cycle->Entries.empty());
for (BlockT *Entry : Cycle->Entries) {
check(Entries.insert(Entry).second); // duplicate entry?
check(is_contained(Cycle->Blocks, Entry));
}
Entries.clear();
unsigned ChildDepth = 0;
for (const CycleT *Child : Cycle->children()) {
check(Child->Depth > Cycle->Depth);
if (!ChildDepth) {
ChildDepth = Child->Depth;
} else {
check(ChildDepth == Child->Depth);
}
}
}
}
for (const auto &Entry : BlockMap) {
BlockT *Block = Entry.first;
for (const CycleT *Cycle = Entry.second; Cycle;
Cycle = Cycle->ParentCycle) {
check(is_contained(Cycle->Blocks, Block));
}
}
#undef check
return true;
}
#endif
/// \brief Print the cycle info.
template <typename ContextT>
void GenericCycleInfo<ContextT>::print(raw_ostream &Out) const {
for (const auto *TLC : toplevel_cycles()) {
for (const CycleT *Cycle : depth_first(TLC)) {
for (unsigned I = 0; I < Cycle->Depth; ++I)
Out << " ";
Out << Cycle->print(Context) << '\n';
}
}
}
} // namespace llvm
#undef DEBUG_TYPE
#endif // LLVM_ADT_GENERICCYCLEIMPL_H
diff --git a/contrib/llvm-project/llvm/include/llvm/ADT/GenericCycleInfo.h b/contrib/llvm-project/llvm/include/llvm/ADT/GenericCycleInfo.h
index 970664b85715..5f851b795cbc 100644
--- a/contrib/llvm-project/llvm/include/llvm/ADT/GenericCycleInfo.h
+++ b/contrib/llvm-project/llvm/include/llvm/ADT/GenericCycleInfo.h
@@ -1,352 +1,355 @@
//===- GenericCycleInfo.h - Info for Cycles in any IR ------*- C++ -*------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Find all cycles in a control-flow graph, including irreducible loops.
///
/// See docs/CycleTerminology.rst for a formal definition of cycles.
///
/// Briefly:
/// - A cycle is a generalization of a loop which can represent
/// irreducible control flow.
/// - Cycles identified in a program are implementation defined,
/// depending on the DFS traversal chosen.
/// - Cycles are well-nested, and form a forest with a parent-child
/// relationship.
/// - In any choice of DFS, every natural loop L is represented by a
/// unique cycle C which is a superset of L.
/// - In the absence of irreducible control flow, the cycles are
/// exactly the natural loops in the program.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_GENERICCYCLEINFO_H
#define LLVM_ADT_GENERICCYCLEINFO_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/GenericSSAContext.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Printable.h"
#include "llvm/Support/raw_ostream.h"
#include <vector>
namespace llvm {
template <typename ContextT> class GenericCycleInfo;
template <typename ContextT> class GenericCycleInfoCompute;
/// A possibly irreducible generalization of a \ref Loop.
template <typename ContextT> class GenericCycle {
public:
using BlockT = typename ContextT::BlockT;
using FunctionT = typename ContextT::FunctionT;
template <typename> friend class GenericCycleInfo;
template <typename> friend class GenericCycleInfoCompute;
private:
/// The parent cycle. Is null for the root "cycle". Top-level cycles point
/// at the root.
GenericCycle *ParentCycle = nullptr;
/// The entry block(s) of the cycle. The header is the only entry if
/// this is a loop. Is empty for the root "cycle", to avoid
/// unnecessary memory use.
SmallVector<BlockT *, 1> Entries;
/// Child cycles, if any.
std::vector<std::unique_ptr<GenericCycle>> Children;
/// Basic blocks that are contained in the cycle, including entry blocks,
/// and including blocks that are part of a child cycle.
std::vector<BlockT *> Blocks;
/// Depth of the cycle in the tree. The root "cycle" is at depth 0.
///
/// \note Depths are not necessarily contiguous. However, child loops always
/// have strictly greater depth than their parents, and sibling loops
/// always have the same depth.
unsigned Depth = 0;
void clear() {
Entries.clear();
Children.clear();
Blocks.clear();
Depth = 0;
ParentCycle = nullptr;
}
void appendEntry(BlockT *Block) { Entries.push_back(Block); }
void appendBlock(BlockT *Block) { Blocks.push_back(Block); }
GenericCycle(const GenericCycle &) = delete;
GenericCycle &operator=(const GenericCycle &) = delete;
GenericCycle(GenericCycle &&Rhs) = delete;
GenericCycle &operator=(GenericCycle &&Rhs) = delete;
public:
GenericCycle() = default;
/// \brief Whether the cycle is a natural loop.
bool isReducible() const { return Entries.size() == 1; }
BlockT *getHeader() const { return Entries[0]; }
const SmallVectorImpl<BlockT *> & getEntries() const {
return Entries;
}
/// \brief Return whether \p Block is an entry block of the cycle.
bool isEntry(BlockT *Block) const { return is_contained(Entries, Block); }
/// \brief Return whether \p Block is contained in the cycle.
bool contains(const BlockT *Block) const {
return is_contained(Blocks, Block);
}
/// \brief Returns true iff this cycle contains \p C.
///
/// Note: Non-strict containment check, i.e. returns true if C is the
/// same cycle.
bool contains(const GenericCycle *C) const;
const GenericCycle *getParentCycle() const { return ParentCycle; }
GenericCycle *getParentCycle() { return ParentCycle; }
unsigned getDepth() const { return Depth; }
/// Return all of the successor blocks of this cycle.
///
/// These are the blocks _outside of the current cycle_ which are
/// branched to.
void getExitBlocks(SmallVectorImpl<BlockT *> &TmpStorage) const;
/// Return the preheader block for this cycle. Pre-header is well-defined for
/// reducible cycle in docs/LoopTerminology.rst as: the only one entering
/// block and its only edge is to the entry block. Return null for irreducible
/// cycles.
BlockT *getCyclePreheader() const;
/// If the cycle has exactly one entry with exactly one predecessor, return
/// it, otherwise return nullptr.
BlockT *getCyclePredecessor() const;
/// Iteration over child cycles.
//@{
using const_child_iterator_base =
typename std::vector<std::unique_ptr<GenericCycle>>::const_iterator;
struct const_child_iterator
: iterator_adaptor_base<const_child_iterator, const_child_iterator_base> {
using Base =
iterator_adaptor_base<const_child_iterator, const_child_iterator_base>;
const_child_iterator() = default;
explicit const_child_iterator(const_child_iterator_base I) : Base(I) {}
const const_child_iterator_base &wrapped() { return Base::wrapped(); }
GenericCycle *operator*() const { return Base::I->get(); }
};
const_child_iterator child_begin() const {
return const_child_iterator{Children.begin()};
}
const_child_iterator child_end() const {
return const_child_iterator{Children.end()};
}
size_t getNumChildren() const { return Children.size(); }
iterator_range<const_child_iterator> children() const {
return llvm::make_range(const_child_iterator{Children.begin()},
const_child_iterator{Children.end()});
}
//@}
/// Iteration over blocks in the cycle (including entry blocks).
//@{
using const_block_iterator = typename std::vector<BlockT *>::const_iterator;
const_block_iterator block_begin() const {
return const_block_iterator{Blocks.begin()};
}
const_block_iterator block_end() const {
return const_block_iterator{Blocks.end()};
}
size_t getNumBlocks() const { return Blocks.size(); }
iterator_range<const_block_iterator> blocks() const {
return llvm::make_range(block_begin(), block_end());
}
//@}
/// Iteration over entry blocks.
//@{
using const_entry_iterator =
typename SmallVectorImpl<BlockT *>::const_iterator;
size_t getNumEntries() const { return Entries.size(); }
iterator_range<const_entry_iterator> entries() const {
return llvm::make_range(Entries.begin(), Entries.end());
}
//@}
Printable printEntries(const ContextT &Ctx) const {
return Printable([this, &Ctx](raw_ostream &Out) {
bool First = true;
for (auto *Entry : Entries) {
if (!First)
Out << ' ';
First = false;
Out << Ctx.print(Entry);
}
});
}
Printable print(const ContextT &Ctx) const {
return Printable([this, &Ctx](raw_ostream &Out) {
Out << "depth=" << Depth << ": entries(" << printEntries(Ctx) << ')';
for (auto *Block : Blocks) {
if (isEntry(Block))
continue;
Out << ' ' << Ctx.print(Block);
}
});
}
};
/// \brief Cycle information for a function.
template <typename ContextT> class GenericCycleInfo {
public:
using BlockT = typename ContextT::BlockT;
using CycleT = GenericCycle<ContextT>;
using FunctionT = typename ContextT::FunctionT;
template <typename> friend class GenericCycle;
template <typename> friend class GenericCycleInfoCompute;
private:
ContextT Context;
- /// Map basic blocks to their inner-most containing loop.
+ /// Map basic blocks to their inner-most containing cycle.
DenseMap<BlockT *, CycleT *> BlockMap;
+ /// Map basic blocks to their top level containing cycle.
+ DenseMap<BlockT *, CycleT *> BlockMapTopLevel;
+
/// Outermost cycles discovered by any DFS.
///
/// Note: The implementation treats the nullptr as the parent of
/// every top-level cycle. See \ref contains for an example.
std::vector<std::unique_ptr<CycleT>> TopLevelCycles;
+ /// Move \p Child to \p NewParent by manipulating Children vectors.
+ ///
+ /// Note: This is an incomplete operation that does not update the depth of
+ /// the subtree.
+ void moveTopLevelCycleToNewParent(CycleT *NewParent, CycleT *Child);
+
public:
GenericCycleInfo() = default;
GenericCycleInfo(GenericCycleInfo &&) = default;
GenericCycleInfo &operator=(GenericCycleInfo &&) = default;
void clear();
void compute(FunctionT &F);
FunctionT *getFunction() const { return Context.getFunction(); }
const ContextT &getSSAContext() const { return Context; }
CycleT *getCycle(const BlockT *Block) const;
unsigned getCycleDepth(const BlockT *Block) const;
- CycleT *getTopLevelParentCycle(const BlockT *Block) const;
-
- /// Move \p Child to \p NewParent by manipulating Children vectors.
- ///
- /// Note: This is an incomplete operation that does not update the
- /// list of blocks in the new parent or the depth of the subtree.
- void moveToNewParent(CycleT *NewParent, CycleT *Child);
+ CycleT *getTopLevelParentCycle(BlockT *Block);
/// Methods for debug and self-test.
//@{
#ifndef NDEBUG
bool validateTree() const;
#endif
void print(raw_ostream &Out) const;
void dump() const { print(dbgs()); }
//@}
/// Iteration over top-level cycles.
//@{
using const_toplevel_iterator_base =
typename std::vector<std::unique_ptr<CycleT>>::const_iterator;
struct const_toplevel_iterator
: iterator_adaptor_base<const_toplevel_iterator,
const_toplevel_iterator_base> {
using Base = iterator_adaptor_base<const_toplevel_iterator,
const_toplevel_iterator_base>;
const_toplevel_iterator() = default;
explicit const_toplevel_iterator(const_toplevel_iterator_base I)
: Base(I) {}
const const_toplevel_iterator_base &wrapped() { return Base::wrapped(); }
CycleT *operator*() const { return Base::I->get(); }
};
const_toplevel_iterator toplevel_begin() const {
return const_toplevel_iterator{TopLevelCycles.begin()};
}
const_toplevel_iterator toplevel_end() const {
return const_toplevel_iterator{TopLevelCycles.end()};
}
iterator_range<const_toplevel_iterator> toplevel_cycles() const {
return llvm::make_range(const_toplevel_iterator{TopLevelCycles.begin()},
const_toplevel_iterator{TopLevelCycles.end()});
}
//@}
};
/// \brief GraphTraits for iterating over a sub-tree of the CycleT tree.
template <typename CycleRefT, typename ChildIteratorT> struct CycleGraphTraits {
using NodeRef = CycleRefT;
using nodes_iterator = ChildIteratorT;
using ChildIteratorType = nodes_iterator;
static NodeRef getEntryNode(NodeRef Graph) { return Graph; }
static ChildIteratorType child_begin(NodeRef Ref) {
return Ref->child_begin();
}
static ChildIteratorType child_end(NodeRef Ref) { return Ref->child_end(); }
// Not implemented:
// static nodes_iterator nodes_begin(GraphType *G)
// static nodes_iterator nodes_end (GraphType *G)
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
// typedef EdgeRef - Type of Edge token in the graph, which should
// be cheap to copy.
// typedef ChildEdgeIteratorType - Type used to iterate over children edges in
// graph, dereference to a EdgeRef.
// static ChildEdgeIteratorType child_edge_begin(NodeRef)
// static ChildEdgeIteratorType child_edge_end(NodeRef)
// Return iterators that point to the beginning and ending of the
// edge list for the given callgraph node.
//
// static NodeRef edge_dest(EdgeRef)
// Return the destination node of an edge.
// static unsigned size (GraphType *G)
// Return total number of nodes in the graph
};
template <typename BlockT>
struct GraphTraits<const GenericCycle<BlockT> *>
: CycleGraphTraits<const GenericCycle<BlockT> *,
typename GenericCycle<BlockT>::const_child_iterator> {};
template <typename BlockT>
struct GraphTraits<GenericCycle<BlockT> *>
: CycleGraphTraits<GenericCycle<BlockT> *,
typename GenericCycle<BlockT>::const_child_iterator> {};
} // namespace llvm
#endif // LLVM_ADT_GENERICCYCLEINFO_H
diff --git a/contrib/llvm-project/llvm/include/llvm/Object/ELF.h b/contrib/llvm-project/llvm/include/llvm/Object/ELF.h
index 794d29fd9913..5eb43777a951 100644
--- a/contrib/llvm-project/llvm/include/llvm/Object/ELF.h
+++ b/contrib/llvm-project/llvm/include/llvm/Object/ELF.h
@@ -1,1229 +1,1229 @@
//===- ELF.h - ELF object file implementation -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file declares the ELFFile template class.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_OBJECT_ELF_H
#define LLVM_OBJECT_ELF_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/ELFTypes.h"
#include "llvm/Object/Error.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <utility>
namespace llvm {
namespace object {
struct VerdAux {
unsigned Offset;
std::string Name;
};
struct VerDef {
unsigned Offset;
unsigned Version;
unsigned Flags;
unsigned Ndx;
unsigned Cnt;
unsigned Hash;
std::string Name;
std::vector<VerdAux> AuxV;
};
struct VernAux {
unsigned Hash;
unsigned Flags;
unsigned Other;
unsigned Offset;
std::string Name;
};
struct VerNeed {
unsigned Version;
unsigned Cnt;
unsigned Offset;
std::string File;
std::vector<VernAux> AuxV;
};
struct VersionEntry {
std::string Name;
bool IsVerDef;
};
StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type);
uint32_t getELFRelativeRelocationType(uint32_t Machine);
StringRef getELFSectionTypeName(uint32_t Machine, uint32_t Type);
// Subclasses of ELFFile may need this for template instantiation
inline std::pair<unsigned char, unsigned char>
getElfArchType(StringRef Object) {
if (Object.size() < ELF::EI_NIDENT)
return std::make_pair((uint8_t)ELF::ELFCLASSNONE,
(uint8_t)ELF::ELFDATANONE);
return std::make_pair((uint8_t)Object[ELF::EI_CLASS],
(uint8_t)Object[ELF::EI_DATA]);
}
enum PPCInstrMasks : uint64_t {
PADDI_R12_NO_DISP = 0x0610000039800000,
ADDIS_R12_TO_R2_NO_DISP = 0x3D820000,
ADDI_R12_TO_R2_NO_DISP = 0x39820000,
ADDI_R12_TO_R12_NO_DISP = 0x398C0000,
PLD_R12_NO_DISP = 0x04100000E5800000,
MTCTR_R12 = 0x7D8903A6,
BCTR = 0x4E800420,
};
template <class ELFT> class ELFFile;
template <class T> struct DataRegion {
// This constructor is used when we know the start and the size of a data
// region. We assume that Arr does not go past the end of the file.
DataRegion(ArrayRef<T> Arr) : First(Arr.data()), Size(Arr.size()) {}
// Sometimes we only know the start of a data region. We still don't want to
// read past the end of the file, so we provide the end of a buffer.
DataRegion(const T *Data, const uint8_t *BufferEnd)
: First(Data), BufEnd(BufferEnd) {}
Expected<T> operator[](uint64_t N) {
assert(Size || BufEnd);
if (Size) {
if (N >= *Size)
return createError(
"the index is greater than or equal to the number of entries (" +
Twine(*Size) + ")");
} else {
const uint8_t *EntryStart = (const uint8_t *)First + N * sizeof(T);
if (EntryStart + sizeof(T) > BufEnd)
return createError("can't read past the end of the file");
}
return *(First + N);
}
const T *First;
Optional<uint64_t> Size = None;
const uint8_t *BufEnd = nullptr;
};
template <class ELFT>
std::string getSecIndexForError(const ELFFile<ELFT> &Obj,
const typename ELFT::Shdr &Sec) {
auto TableOrErr = Obj.sections();
if (TableOrErr)
return "[index " + std::to_string(&Sec - &TableOrErr->front()) + "]";
// To make this helper be more convenient for error reporting purposes we
// drop the error. But really it should never be triggered. Before this point,
// our code should have called 'sections()' and reported a proper error on
// failure.
llvm::consumeError(TableOrErr.takeError());
return "[unknown index]";
}
template <class ELFT>
static std::string describe(const ELFFile<ELFT> &Obj,
const typename ELFT::Shdr &Sec) {
unsigned SecNdx = &Sec - &cantFail(Obj.sections()).front();
return (object::getELFSectionTypeName(Obj.getHeader().e_machine,
Sec.sh_type) +
" section with index " + Twine(SecNdx))
.str();
}
template <class ELFT>
std::string getPhdrIndexForError(const ELFFile<ELFT> &Obj,
const typename ELFT::Phdr &Phdr) {
auto Headers = Obj.program_headers();
if (Headers)
return ("[index " + Twine(&Phdr - &Headers->front()) + "]").str();
// See comment in the getSecIndexForError() above.
llvm::consumeError(Headers.takeError());
return "[unknown index]";
}
static inline Error defaultWarningHandler(const Twine &Msg) {
return createError(Msg);
}
template <class ELFT>
class ELFFile {
public:
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
// This is a callback that can be passed to a number of functions.
// It can be used to ignore non-critical errors (warnings), which is
// useful for dumpers, like llvm-readobj.
// It accepts a warning message string and returns a success
// when the warning should be ignored or an error otherwise.
using WarningHandler = llvm::function_ref<Error(const Twine &Msg)>;
const uint8_t *base() const { return Buf.bytes_begin(); }
const uint8_t *end() const { return base() + getBufSize(); }
size_t getBufSize() const { return Buf.size(); }
private:
StringRef Buf;
std::vector<Elf_Shdr> FakeSections;
ELFFile(StringRef Object);
public:
const Elf_Ehdr &getHeader() const {
return *reinterpret_cast<const Elf_Ehdr *>(base());
}
template <typename T>
Expected<const T *> getEntry(uint32_t Section, uint32_t Entry) const;
template <typename T>
Expected<const T *> getEntry(const Elf_Shdr &Section, uint32_t Entry) const;
Expected<std::vector<VerDef>>
getVersionDefinitions(const Elf_Shdr &Sec) const;
Expected<std::vector<VerNeed>> getVersionDependencies(
const Elf_Shdr &Sec,
WarningHandler WarnHandler = &defaultWarningHandler) const;
Expected<StringRef>
getSymbolVersionByIndex(uint32_t SymbolVersionIndex, bool &IsDefault,
SmallVector<Optional<VersionEntry>, 0> &VersionMap,
Optional<bool> IsSymHidden) const;
Expected<StringRef>
getStringTable(const Elf_Shdr &Section,
WarningHandler WarnHandler = &defaultWarningHandler) const;
Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section) const;
Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section,
Elf_Shdr_Range Sections) const;
Expected<StringRef> getLinkAsStrtab(const typename ELFT::Shdr &Sec) const;
Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section) const;
Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section,
Elf_Shdr_Range Sections) const;
Expected<uint64_t> getDynSymtabSize() const;
StringRef getRelocationTypeName(uint32_t Type) const;
void getRelocationTypeName(uint32_t Type,
SmallVectorImpl<char> &Result) const;
uint32_t getRelativeRelocationType() const;
std::string getDynamicTagAsString(unsigned Arch, uint64_t Type) const;
std::string getDynamicTagAsString(uint64_t Type) const;
/// Get the symbol for a given relocation.
Expected<const Elf_Sym *> getRelocationSymbol(const Elf_Rel &Rel,
const Elf_Shdr *SymTab) const;
Expected<SmallVector<Optional<VersionEntry>, 0>>
loadVersionMap(const Elf_Shdr *VerNeedSec, const Elf_Shdr *VerDefSec) const;
static Expected<ELFFile> create(StringRef Object);
bool isLE() const {
return getHeader().getDataEncoding() == ELF::ELFDATA2LSB;
}
bool isMipsELF64() const {
return getHeader().e_machine == ELF::EM_MIPS &&
getHeader().getFileClass() == ELF::ELFCLASS64;
}
bool isMips64EL() const { return isMipsELF64() && isLE(); }
Expected<Elf_Shdr_Range> sections() const;
Expected<Elf_Dyn_Range> dynamicEntries() const;
Expected<const uint8_t *>
toMappedAddr(uint64_t VAddr,
WarningHandler WarnHandler = &defaultWarningHandler) const;
Expected<Elf_Sym_Range> symbols(const Elf_Shdr *Sec) const {
if (!Sec)
return makeArrayRef<Elf_Sym>(nullptr, nullptr);
return getSectionContentsAsArray<Elf_Sym>(*Sec);
}
Expected<Elf_Rela_Range> relas(const Elf_Shdr &Sec) const {
return getSectionContentsAsArray<Elf_Rela>(Sec);
}
Expected<Elf_Rel_Range> rels(const Elf_Shdr &Sec) const {
return getSectionContentsAsArray<Elf_Rel>(Sec);
}
Expected<Elf_Relr_Range> relrs(const Elf_Shdr &Sec) const {
return getSectionContentsAsArray<Elf_Relr>(Sec);
}
std::vector<Elf_Rel> decode_relrs(Elf_Relr_Range relrs) const;
Expected<std::vector<Elf_Rela>> android_relas(const Elf_Shdr &Sec) const;
/// Iterate over program header table.
Expected<Elf_Phdr_Range> program_headers() const {
if (getHeader().e_phnum && getHeader().e_phentsize != sizeof(Elf_Phdr))
return createError("invalid e_phentsize: " +
Twine(getHeader().e_phentsize));
uint64_t HeadersSize =
(uint64_t)getHeader().e_phnum * getHeader().e_phentsize;
uint64_t PhOff = getHeader().e_phoff;
if (PhOff + HeadersSize < PhOff || PhOff + HeadersSize > getBufSize())
return createError("program headers are longer than binary of size " +
Twine(getBufSize()) + ": e_phoff = 0x" +
Twine::utohexstr(getHeader().e_phoff) +
", e_phnum = " + Twine(getHeader().e_phnum) +
", e_phentsize = " + Twine(getHeader().e_phentsize));
auto *Begin = reinterpret_cast<const Elf_Phdr *>(base() + PhOff);
return makeArrayRef(Begin, Begin + getHeader().e_phnum);
}
/// Get an iterator over notes in a program header.
///
/// The program header must be of type \c PT_NOTE.
///
/// \param Phdr the program header to iterate over.
/// \param Err [out] an error to support fallible iteration, which should
/// be checked after iteration ends.
Elf_Note_Iterator notes_begin(const Elf_Phdr &Phdr, Error &Err) const {
assert(Phdr.p_type == ELF::PT_NOTE && "Phdr is not of type PT_NOTE");
ErrorAsOutParameter ErrAsOutParam(&Err);
if (Phdr.p_offset + Phdr.p_filesz > getBufSize()) {
Err =
createError("invalid offset (0x" + Twine::utohexstr(Phdr.p_offset) +
") or size (0x" + Twine::utohexstr(Phdr.p_filesz) + ")");
return Elf_Note_Iterator(Err);
}
return Elf_Note_Iterator(base() + Phdr.p_offset, Phdr.p_filesz, Err);
}
/// Get an iterator over notes in a section.
///
/// The section must be of type \c SHT_NOTE.
///
/// \param Shdr the section to iterate over.
/// \param Err [out] an error to support fallible iteration, which should
/// be checked after iteration ends.
Elf_Note_Iterator notes_begin(const Elf_Shdr &Shdr, Error &Err) const {
assert(Shdr.sh_type == ELF::SHT_NOTE && "Shdr is not of type SHT_NOTE");
ErrorAsOutParameter ErrAsOutParam(&Err);
if (Shdr.sh_offset + Shdr.sh_size > getBufSize()) {
Err =
createError("invalid offset (0x" + Twine::utohexstr(Shdr.sh_offset) +
") or size (0x" + Twine::utohexstr(Shdr.sh_size) + ")");
return Elf_Note_Iterator(Err);
}
return Elf_Note_Iterator(base() + Shdr.sh_offset, Shdr.sh_size, Err);
}
/// Get the end iterator for notes.
Elf_Note_Iterator notes_end() const {
return Elf_Note_Iterator();
}
/// Get an iterator range over notes of a program header.
///
/// The program header must be of type \c PT_NOTE.
///
/// \param Phdr the program header to iterate over.
/// \param Err [out] an error to support fallible iteration, which should
/// be checked after iteration ends.
iterator_range<Elf_Note_Iterator> notes(const Elf_Phdr &Phdr,
Error &Err) const {
return make_range(notes_begin(Phdr, Err), notes_end());
}
/// Get an iterator range over notes of a section.
///
/// The section must be of type \c SHT_NOTE.
///
/// \param Shdr the section to iterate over.
/// \param Err [out] an error to support fallible iteration, which should
/// be checked after iteration ends.
iterator_range<Elf_Note_Iterator> notes(const Elf_Shdr &Shdr,
Error &Err) const {
return make_range(notes_begin(Shdr, Err), notes_end());
}
Expected<StringRef> getSectionStringTable(
Elf_Shdr_Range Sections,
WarningHandler WarnHandler = &defaultWarningHandler) const;
Expected<uint32_t> getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms,
DataRegion<Elf_Word> ShndxTable) const;
Expected<const Elf_Shdr *> getSection(const Elf_Sym &Sym,
const Elf_Shdr *SymTab,
DataRegion<Elf_Word> ShndxTable) const;
Expected<const Elf_Shdr *> getSection(const Elf_Sym &Sym,
Elf_Sym_Range Symtab,
DataRegion<Elf_Word> ShndxTable) const;
Expected<const Elf_Shdr *> getSection(uint32_t Index) const;
Expected<const Elf_Sym *> getSymbol(const Elf_Shdr *Sec,
uint32_t Index) const;
Expected<StringRef>
getSectionName(const Elf_Shdr &Section,
WarningHandler WarnHandler = &defaultWarningHandler) const;
Expected<StringRef> getSectionName(const Elf_Shdr &Section,
StringRef DotShstrtab) const;
template <typename T>
Expected<ArrayRef<T>> getSectionContentsAsArray(const Elf_Shdr &Sec) const;
Expected<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr &Sec) const;
Expected<ArrayRef<uint8_t>> getSegmentContents(const Elf_Phdr &Phdr) const;
Expected<std::vector<BBAddrMap>> decodeBBAddrMap(const Elf_Shdr &Sec) const;
void createFakeSections();
};
using ELF32LEFile = ELFFile<ELF32LE>;
using ELF64LEFile = ELFFile<ELF64LE>;
using ELF32BEFile = ELFFile<ELF32BE>;
using ELF64BEFile = ELFFile<ELF64BE>;
template <class ELFT>
inline Expected<const typename ELFT::Shdr *>
getSection(typename ELFT::ShdrRange Sections, uint32_t Index) {
if (Index >= Sections.size())
return createError("invalid section index: " + Twine(Index));
return &Sections[Index];
}
template <class ELFT>
inline Expected<uint32_t>
getExtendedSymbolTableIndex(const typename ELFT::Sym &Sym, unsigned SymIndex,
DataRegion<typename ELFT::Word> ShndxTable) {
assert(Sym.st_shndx == ELF::SHN_XINDEX);
if (!ShndxTable.First)
return createError(
"found an extended symbol index (" + Twine(SymIndex) +
"), but unable to locate the extended symbol index table");
Expected<typename ELFT::Word> TableOrErr = ShndxTable[SymIndex];
if (!TableOrErr)
return createError("unable to read an extended symbol table at index " +
Twine(SymIndex) + ": " +
toString(TableOrErr.takeError()));
return *TableOrErr;
}
template <class ELFT>
Expected<uint32_t>
ELFFile<ELFT>::getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms,
DataRegion<Elf_Word> ShndxTable) const {
uint32_t Index = Sym.st_shndx;
if (Index == ELF::SHN_XINDEX) {
Expected<uint32_t> ErrorOrIndex =
getExtendedSymbolTableIndex<ELFT>(Sym, &Sym - Syms.begin(), ShndxTable);
if (!ErrorOrIndex)
return ErrorOrIndex.takeError();
return *ErrorOrIndex;
}
if (Index == ELF::SHN_UNDEF || Index >= ELF::SHN_LORESERVE)
return 0;
return Index;
}
template <class ELFT>
Expected<const typename ELFT::Shdr *>
ELFFile<ELFT>::getSection(const Elf_Sym &Sym, const Elf_Shdr *SymTab,
DataRegion<Elf_Word> ShndxTable) const {
auto SymsOrErr = symbols(SymTab);
if (!SymsOrErr)
return SymsOrErr.takeError();
return getSection(Sym, *SymsOrErr, ShndxTable);
}
template <class ELFT>
Expected<const typename ELFT::Shdr *>
ELFFile<ELFT>::getSection(const Elf_Sym &Sym, Elf_Sym_Range Symbols,
DataRegion<Elf_Word> ShndxTable) const {
auto IndexOrErr = getSectionIndex(Sym, Symbols, ShndxTable);
if (!IndexOrErr)
return IndexOrErr.takeError();
uint32_t Index = *IndexOrErr;
if (Index == 0)
return nullptr;
return getSection(Index);
}
template <class ELFT>
Expected<const typename ELFT::Sym *>
ELFFile<ELFT>::getSymbol(const Elf_Shdr *Sec, uint32_t Index) const {
auto SymsOrErr = symbols(Sec);
if (!SymsOrErr)
return SymsOrErr.takeError();
Elf_Sym_Range Symbols = *SymsOrErr;
if (Index >= Symbols.size())
return createError("unable to get symbol from section " +
getSecIndexForError(*this, *Sec) +
": invalid symbol index (" + Twine(Index) + ")");
return &Symbols[Index];
}
template <class ELFT>
template <typename T>
Expected<ArrayRef<T>>
ELFFile<ELFT>::getSectionContentsAsArray(const Elf_Shdr &Sec) const {
if (Sec.sh_entsize != sizeof(T) && sizeof(T) != 1)
return createError("section " + getSecIndexForError(*this, Sec) +
" has invalid sh_entsize: expected " + Twine(sizeof(T)) +
", but got " + Twine(Sec.sh_entsize));
uintX_t Offset = Sec.sh_offset;
uintX_t Size = Sec.sh_size;
if (Size % sizeof(T))
return createError("section " + getSecIndexForError(*this, Sec) +
" has an invalid sh_size (" + Twine(Size) +
") which is not a multiple of its sh_entsize (" +
Twine(Sec.sh_entsize) + ")");
if (std::numeric_limits<uintX_t>::max() - Offset < Size)
return createError("section " + getSecIndexForError(*this, Sec) +
" has a sh_offset (0x" + Twine::utohexstr(Offset) +
") + sh_size (0x" + Twine::utohexstr(Size) +
") that cannot be represented");
if (Offset + Size > Buf.size())
return createError("section " + getSecIndexForError(*this, Sec) +
" has a sh_offset (0x" + Twine::utohexstr(Offset) +
") + sh_size (0x" + Twine::utohexstr(Size) +
") that is greater than the file size (0x" +
Twine::utohexstr(Buf.size()) + ")");
if (Offset % alignof(T))
// TODO: this error is untested.
return createError("unaligned data");
const T *Start = reinterpret_cast<const T *>(base() + Offset);
return makeArrayRef(Start, Size / sizeof(T));
}
template <class ELFT>
Expected<ArrayRef<uint8_t>>
ELFFile<ELFT>::getSegmentContents(const Elf_Phdr &Phdr) const {
uintX_t Offset = Phdr.p_offset;
uintX_t Size = Phdr.p_filesz;
if (std::numeric_limits<uintX_t>::max() - Offset < Size)
return createError("program header " + getPhdrIndexForError(*this, Phdr) +
" has a p_offset (0x" + Twine::utohexstr(Offset) +
") + p_filesz (0x" + Twine::utohexstr(Size) +
") that cannot be represented");
if (Offset + Size > Buf.size())
return createError("program header " + getPhdrIndexForError(*this, Phdr) +
" has a p_offset (0x" + Twine::utohexstr(Offset) +
") + p_filesz (0x" + Twine::utohexstr(Size) +
") that is greater than the file size (0x" +
Twine::utohexstr(Buf.size()) + ")");
return makeArrayRef(base() + Offset, Size);
}
template <class ELFT>
Expected<ArrayRef<uint8_t>>
ELFFile<ELFT>::getSectionContents(const Elf_Shdr &Sec) const {
return getSectionContentsAsArray<uint8_t>(Sec);
}
template <class ELFT>
StringRef ELFFile<ELFT>::getRelocationTypeName(uint32_t Type) const {
return getELFRelocationTypeName(getHeader().e_machine, Type);
}
template <class ELFT>
void ELFFile<ELFT>::getRelocationTypeName(uint32_t Type,
SmallVectorImpl<char> &Result) const {
if (!isMipsELF64()) {
StringRef Name = getRelocationTypeName(Type);
Result.append(Name.begin(), Name.end());
} else {
// The Mips N64 ABI allows up to three operations to be specified per
// relocation record. Unfortunately there's no easy way to test for the
// presence of N64 ELFs as they have no special flag that identifies them
// as being N64. We can safely assume at the moment that all Mips
// ELFCLASS64 ELFs are N64. New Mips64 ABIs should provide enough
// information to disambiguate between old vs new ABIs.
uint8_t Type1 = (Type >> 0) & 0xFF;
uint8_t Type2 = (Type >> 8) & 0xFF;
uint8_t Type3 = (Type >> 16) & 0xFF;
// Concat all three relocation type names.
StringRef Name = getRelocationTypeName(Type1);
Result.append(Name.begin(), Name.end());
Name = getRelocationTypeName(Type2);
Result.append(1, '/');
Result.append(Name.begin(), Name.end());
Name = getRelocationTypeName(Type3);
Result.append(1, '/');
Result.append(Name.begin(), Name.end());
}
}
template <class ELFT>
uint32_t ELFFile<ELFT>::getRelativeRelocationType() const {
return getELFRelativeRelocationType(getHeader().e_machine);
}
template <class ELFT>
Expected<SmallVector<Optional<VersionEntry>, 0>>
ELFFile<ELFT>::loadVersionMap(const Elf_Shdr *VerNeedSec,
const Elf_Shdr *VerDefSec) const {
SmallVector<Optional<VersionEntry>, 0> VersionMap;
// The first two version indexes are reserved.
// Index 0 is VER_NDX_LOCAL, index 1 is VER_NDX_GLOBAL.
VersionMap.push_back(VersionEntry());
VersionMap.push_back(VersionEntry());
auto InsertEntry = [&](unsigned N, StringRef Version, bool IsVerdef) {
if (N >= VersionMap.size())
VersionMap.resize(N + 1);
VersionMap[N] = {std::string(Version), IsVerdef};
};
if (VerDefSec) {
Expected<std::vector<VerDef>> Defs = getVersionDefinitions(*VerDefSec);
if (!Defs)
return Defs.takeError();
for (const VerDef &Def : *Defs)
InsertEntry(Def.Ndx & ELF::VERSYM_VERSION, Def.Name, true);
}
if (VerNeedSec) {
Expected<std::vector<VerNeed>> Deps = getVersionDependencies(*VerNeedSec);
if (!Deps)
return Deps.takeError();
for (const VerNeed &Dep : *Deps)
for (const VernAux &Aux : Dep.AuxV)
InsertEntry(Aux.Other & ELF::VERSYM_VERSION, Aux.Name, false);
}
return VersionMap;
}
template <class ELFT>
Expected<const typename ELFT::Sym *>
ELFFile<ELFT>::getRelocationSymbol(const Elf_Rel &Rel,
const Elf_Shdr *SymTab) const {
uint32_t Index = Rel.getSymbol(isMips64EL());
if (Index == 0)
return nullptr;
return getEntry<Elf_Sym>(*SymTab, Index);
}
template <class ELFT>
Expected<StringRef>
ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections,
WarningHandler WarnHandler) const {
uint32_t Index = getHeader().e_shstrndx;
if (Index == ELF::SHN_XINDEX) {
// If the section name string table section index is greater than
// or equal to SHN_LORESERVE, then the actual index of the section name
// string table section is contained in the sh_link field of the section
// header at index 0.
if (Sections.empty())
return createError(
"e_shstrndx == SHN_XINDEX, but the section header table is empty");
Index = Sections[0].sh_link;
}
if (!Index) // no section string table.
return "";
if (Index >= Sections.size())
return createError("section header string table index " + Twine(Index) +
" does not exist");
return getStringTable(Sections[Index], WarnHandler);
}
/// This function finds the number of dynamic symbols using a GNU hash table.
///
/// @param Table The GNU hash table for .dynsym.
template <class ELFT>
static Expected<uint64_t>
getDynSymtabSizeFromGnuHash(const typename ELFT::GnuHash &Table,
const void *BufEnd) {
using Elf_Word = typename ELFT::Word;
if (Table.nbuckets == 0)
return Table.symndx + 1;
uint64_t LastSymIdx = 0;
// Find the index of the first symbol in the last chain.
for (Elf_Word Val : Table.buckets())
LastSymIdx = std::max(LastSymIdx, (uint64_t)Val);
const Elf_Word *It =
reinterpret_cast<const Elf_Word *>(Table.values(LastSymIdx).end());
// Locate the end of the chain to find the last symbol index.
while (It < BufEnd && (*It & 1) == 0) {
++LastSymIdx;
++It;
}
if (It >= BufEnd) {
return createStringError(
object_error::parse_failed,
"no terminator found for GNU hash section before buffer end");
}
return LastSymIdx + 1;
}
/// This function determines the number of dynamic symbols. It reads section
/// headers first. If section headers are not available, the number of
/// symbols will be inferred by parsing dynamic hash tables.
template <class ELFT>
Expected<uint64_t> ELFFile<ELFT>::getDynSymtabSize() const {
// Read .dynsym section header first if available.
Expected<Elf_Shdr_Range> SectionsOrError = sections();
if (!SectionsOrError)
return SectionsOrError.takeError();
for (const Elf_Shdr &Sec : *SectionsOrError) {
if (Sec.sh_type == ELF::SHT_DYNSYM) {
if (Sec.sh_size % Sec.sh_entsize != 0) {
return createStringError(object_error::parse_failed,
"SHT_DYNSYM section has sh_size (" +
Twine(Sec.sh_size) + ") % sh_entsize (" +
Twine(Sec.sh_entsize) + ") that is not 0");
}
return Sec.sh_size / Sec.sh_entsize;
}
}
if (!SectionsOrError->empty()) {
// Section headers are available but .dynsym header is not found.
// Return 0 as .dynsym does not exist.
return 0;
}
// Section headers do not exist. Falling back to infer
// upper bound of .dynsym from .gnu.hash and .hash.
Expected<Elf_Dyn_Range> DynTable = dynamicEntries();
if (!DynTable)
return DynTable.takeError();
llvm::Optional<uint64_t> ElfHash;
llvm::Optional<uint64_t> ElfGnuHash;
for (const Elf_Dyn &Entry : *DynTable) {
switch (Entry.d_tag) {
case ELF::DT_HASH:
ElfHash = Entry.d_un.d_ptr;
break;
case ELF::DT_GNU_HASH:
ElfGnuHash = Entry.d_un.d_ptr;
break;
}
}
if (ElfGnuHash) {
Expected<const uint8_t *> TablePtr = toMappedAddr(*ElfGnuHash);
if (!TablePtr)
return TablePtr.takeError();
const Elf_GnuHash *Table =
reinterpret_cast<const Elf_GnuHash *>(TablePtr.get());
return getDynSymtabSizeFromGnuHash<ELFT>(*Table, this->Buf.bytes_end());
}
// Search SYSV hash table to try to find the upper bound of dynsym.
if (ElfHash) {
Expected<const uint8_t *> TablePtr = toMappedAddr(*ElfHash);
if (!TablePtr)
return TablePtr.takeError();
const Elf_Hash *Table = reinterpret_cast<const Elf_Hash *>(TablePtr.get());
return Table->nchain;
}
return 0;
}
template <class ELFT> ELFFile<ELFT>::ELFFile(StringRef Object) : Buf(Object) {}
template <class ELFT>
Expected<ELFFile<ELFT>> ELFFile<ELFT>::create(StringRef Object) {
if (sizeof(Elf_Ehdr) > Object.size())
return createError("invalid buffer: the size (" + Twine(Object.size()) +
") is smaller than an ELF header (" +
Twine(sizeof(Elf_Ehdr)) + ")");
return ELFFile(Object);
}
/// Used by llvm-objdump -d (which needs sections for disassembly) to
/// disassemble objects without a section header table (e.g. ET_CORE objects
/// analyzed by linux perf or ET_EXEC with llvm-strip --strip-sections).
template <class ELFT> void ELFFile<ELFT>::createFakeSections() {
if (!FakeSections.empty())
return;
auto PhdrsOrErr = program_headers();
if (!PhdrsOrErr)
return;
for (auto Phdr : *PhdrsOrErr) {
if (!(Phdr.p_type & ELF::PT_LOAD) || !(Phdr.p_flags & ELF::PF_X))
continue;
Elf_Shdr FakeShdr = {};
FakeShdr.sh_type = ELF::SHT_PROGBITS;
FakeShdr.sh_flags = ELF::SHF_ALLOC | ELF::SHF_EXECINSTR;
FakeShdr.sh_addr = Phdr.p_vaddr;
FakeShdr.sh_size = Phdr.p_memsz;
FakeShdr.sh_offset = Phdr.p_offset;
FakeSections.push_back(FakeShdr);
}
}
template <class ELFT>
Expected<typename ELFT::ShdrRange> ELFFile<ELFT>::sections() const {
const uintX_t SectionTableOffset = getHeader().e_shoff;
if (SectionTableOffset == 0) {
if (!FakeSections.empty())
return makeArrayRef(FakeSections.data(), FakeSections.size());
return ArrayRef<Elf_Shdr>();
}
if (getHeader().e_shentsize != sizeof(Elf_Shdr))
return createError("invalid e_shentsize in ELF header: " +
Twine(getHeader().e_shentsize));
const uint64_t FileSize = Buf.size();
if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize ||
SectionTableOffset + (uintX_t)sizeof(Elf_Shdr) < SectionTableOffset)
return createError(
"section header table goes past the end of the file: e_shoff = 0x" +
Twine::utohexstr(SectionTableOffset));
// Invalid address alignment of section headers
if (SectionTableOffset & (alignof(Elf_Shdr) - 1))
// TODO: this error is untested.
return createError("invalid alignment of section headers");
const Elf_Shdr *First =
reinterpret_cast<const Elf_Shdr *>(base() + SectionTableOffset);
uintX_t NumSections = getHeader().e_shnum;
if (NumSections == 0)
NumSections = First->sh_size;
if (NumSections > UINT64_MAX / sizeof(Elf_Shdr))
return createError("invalid number of sections specified in the NULL "
"section's sh_size field (" +
Twine(NumSections) + ")");
const uint64_t SectionTableSize = NumSections * sizeof(Elf_Shdr);
if (SectionTableOffset + SectionTableSize < SectionTableOffset)
return createError(
"invalid section header table offset (e_shoff = 0x" +
Twine::utohexstr(SectionTableOffset) +
") or invalid number of sections specified in the first section "
"header's sh_size field (0x" +
Twine::utohexstr(NumSections) + ")");
// Section table goes past end of file!
if (SectionTableOffset + SectionTableSize > FileSize)
return createError("section table goes past the end of file");
return makeArrayRef(First, NumSections);
}
template <class ELFT>
template <typename T>
Expected<const T *> ELFFile<ELFT>::getEntry(uint32_t Section,
uint32_t Entry) const {
auto SecOrErr = getSection(Section);
if (!SecOrErr)
return SecOrErr.takeError();
return getEntry<T>(**SecOrErr, Entry);
}
template <class ELFT>
template <typename T>
Expected<const T *> ELFFile<ELFT>::getEntry(const Elf_Shdr &Section,
uint32_t Entry) const {
Expected<ArrayRef<T>> EntriesOrErr = getSectionContentsAsArray<T>(Section);
if (!EntriesOrErr)
return EntriesOrErr.takeError();
ArrayRef<T> Arr = *EntriesOrErr;
if (Entry >= Arr.size())
return createError(
"can't read an entry at 0x" +
Twine::utohexstr(Entry * static_cast<uint64_t>(sizeof(T))) +
": it goes past the end of the section (0x" +
Twine::utohexstr(Section.sh_size) + ")");
return &Arr[Entry];
}
template <typename ELFT>
Expected<StringRef> ELFFile<ELFT>::getSymbolVersionByIndex(
uint32_t SymbolVersionIndex, bool &IsDefault,
SmallVector<Optional<VersionEntry>, 0> &VersionMap,
Optional<bool> IsSymHidden) const {
size_t VersionIndex = SymbolVersionIndex & llvm::ELF::VERSYM_VERSION;
// Special markers for unversioned symbols.
if (VersionIndex == llvm::ELF::VER_NDX_LOCAL ||
VersionIndex == llvm::ELF::VER_NDX_GLOBAL) {
IsDefault = false;
return "";
}
// Lookup this symbol in the version table.
if (VersionIndex >= VersionMap.size() || !VersionMap[VersionIndex])
return createError("SHT_GNU_versym section refers to a version index " +
Twine(VersionIndex) + " which is missing");
const VersionEntry &Entry = *VersionMap[VersionIndex];
// A default version (@@) is only available for defined symbols.
if (!Entry.IsVerDef || IsSymHidden.value_or(false))
IsDefault = false;
else
IsDefault = !(SymbolVersionIndex & llvm::ELF::VERSYM_HIDDEN);
return Entry.Name.c_str();
}
template <class ELFT>
Expected<std::vector<VerDef>>
ELFFile<ELFT>::getVersionDefinitions(const Elf_Shdr &Sec) const {
Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Sec);
if (!StrTabOrErr)
return StrTabOrErr.takeError();
Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec);
if (!ContentsOrErr)
return createError("cannot read content of " + describe(*this, Sec) + ": " +
toString(ContentsOrErr.takeError()));
const uint8_t *Start = ContentsOrErr->data();
const uint8_t *End = Start + ContentsOrErr->size();
auto ExtractNextAux = [&](const uint8_t *&VerdauxBuf,
unsigned VerDefNdx) -> Expected<VerdAux> {
if (VerdauxBuf + sizeof(Elf_Verdaux) > End)
return createError("invalid " + describe(*this, Sec) +
": version definition " + Twine(VerDefNdx) +
" refers to an auxiliary entry that goes past the end "
"of the section");
auto *Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf);
VerdauxBuf += Verdaux->vda_next;
VerdAux Aux;
Aux.Offset = VerdauxBuf - Start;
if (Verdaux->vda_name <= StrTabOrErr->size())
Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name));
else
Aux.Name = ("<invalid vda_name: " + Twine(Verdaux->vda_name) + ">").str();
return Aux;
};
std::vector<VerDef> Ret;
const uint8_t *VerdefBuf = Start;
for (unsigned I = 1; I <= /*VerDefsNum=*/Sec.sh_info; ++I) {
if (VerdefBuf + sizeof(Elf_Verdef) > End)
return createError("invalid " + describe(*this, Sec) +
": version definition " + Twine(I) +
" goes past the end of the section");
if (reinterpret_cast<uintptr_t>(VerdefBuf) % sizeof(uint32_t) != 0)
return createError(
"invalid " + describe(*this, Sec) +
": found a misaligned version definition entry at offset 0x" +
Twine::utohexstr(VerdefBuf - Start));
unsigned Version = *reinterpret_cast<const Elf_Half *>(VerdefBuf);
if (Version != 1)
return createError("unable to dump " + describe(*this, Sec) +
": version " + Twine(Version) +
" is not yet supported");
const Elf_Verdef *D = reinterpret_cast<const Elf_Verdef *>(VerdefBuf);
VerDef &VD = *Ret.emplace(Ret.end());
VD.Offset = VerdefBuf - Start;
VD.Version = D->vd_version;
VD.Flags = D->vd_flags;
VD.Ndx = D->vd_ndx;
VD.Cnt = D->vd_cnt;
VD.Hash = D->vd_hash;
const uint8_t *VerdauxBuf = VerdefBuf + D->vd_aux;
for (unsigned J = 0; J < D->vd_cnt; ++J) {
if (reinterpret_cast<uintptr_t>(VerdauxBuf) % sizeof(uint32_t) != 0)
return createError("invalid " + describe(*this, Sec) +
": found a misaligned auxiliary entry at offset 0x" +
Twine::utohexstr(VerdauxBuf - Start));
Expected<VerdAux> AuxOrErr = ExtractNextAux(VerdauxBuf, I);
if (!AuxOrErr)
return AuxOrErr.takeError();
if (J == 0)
VD.Name = AuxOrErr->Name;
else
VD.AuxV.push_back(*AuxOrErr);
}
VerdefBuf += D->vd_next;
}
return Ret;
}
template <class ELFT>
Expected<std::vector<VerNeed>>
ELFFile<ELFT>::getVersionDependencies(const Elf_Shdr &Sec,
WarningHandler WarnHandler) const {
StringRef StrTab;
Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Sec);
if (!StrTabOrErr) {
if (Error E = WarnHandler(toString(StrTabOrErr.takeError())))
return std::move(E);
} else {
StrTab = *StrTabOrErr;
}
Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec);
if (!ContentsOrErr)
return createError("cannot read content of " + describe(*this, Sec) + ": " +
toString(ContentsOrErr.takeError()));
const uint8_t *Start = ContentsOrErr->data();
const uint8_t *End = Start + ContentsOrErr->size();
const uint8_t *VerneedBuf = Start;
std::vector<VerNeed> Ret;
for (unsigned I = 1; I <= /*VerneedNum=*/Sec.sh_info; ++I) {
if (VerneedBuf + sizeof(Elf_Verdef) > End)
return createError("invalid " + describe(*this, Sec) +
": version dependency " + Twine(I) +
" goes past the end of the section");
if (reinterpret_cast<uintptr_t>(VerneedBuf) % sizeof(uint32_t) != 0)
return createError(
"invalid " + describe(*this, Sec) +
": found a misaligned version dependency entry at offset 0x" +
Twine::utohexstr(VerneedBuf - Start));
unsigned Version = *reinterpret_cast<const Elf_Half *>(VerneedBuf);
if (Version != 1)
return createError("unable to dump " + describe(*this, Sec) +
": version " + Twine(Version) +
" is not yet supported");
const Elf_Verneed *Verneed =
reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
VerNeed &VN = *Ret.emplace(Ret.end());
VN.Version = Verneed->vn_version;
VN.Cnt = Verneed->vn_cnt;
VN.Offset = VerneedBuf - Start;
if (Verneed->vn_file < StrTab.size())
- VN.File = std::string(StrTab.drop_front(Verneed->vn_file));
+ VN.File = std::string(StrTab.data() + Verneed->vn_file);
else
VN.File = ("<corrupt vn_file: " + Twine(Verneed->vn_file) + ">").str();
const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
for (unsigned J = 0; J < Verneed->vn_cnt; ++J) {
if (reinterpret_cast<uintptr_t>(VernauxBuf) % sizeof(uint32_t) != 0)
return createError("invalid " + describe(*this, Sec) +
": found a misaligned auxiliary entry at offset 0x" +
Twine::utohexstr(VernauxBuf - Start));
if (VernauxBuf + sizeof(Elf_Vernaux) > End)
return createError(
"invalid " + describe(*this, Sec) + ": version dependency " +
Twine(I) +
" refers to an auxiliary entry that goes past the end "
"of the section");
const Elf_Vernaux *Vernaux =
reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
VernAux &Aux = *VN.AuxV.emplace(VN.AuxV.end());
Aux.Hash = Vernaux->vna_hash;
Aux.Flags = Vernaux->vna_flags;
Aux.Other = Vernaux->vna_other;
Aux.Offset = VernauxBuf - Start;
if (StrTab.size() <= Vernaux->vna_name)
Aux.Name = "<corrupt>";
else
Aux.Name = std::string(StrTab.drop_front(Vernaux->vna_name));
VernauxBuf += Vernaux->vna_next;
}
VerneedBuf += Verneed->vn_next;
}
return Ret;
}
template <class ELFT>
Expected<const typename ELFT::Shdr *>
ELFFile<ELFT>::getSection(uint32_t Index) const {
auto TableOrErr = sections();
if (!TableOrErr)
return TableOrErr.takeError();
return object::getSection<ELFT>(*TableOrErr, Index);
}
template <class ELFT>
Expected<StringRef>
ELFFile<ELFT>::getStringTable(const Elf_Shdr &Section,
WarningHandler WarnHandler) const {
if (Section.sh_type != ELF::SHT_STRTAB)
if (Error E = WarnHandler("invalid sh_type for string table section " +
getSecIndexForError(*this, Section) +
": expected SHT_STRTAB, but got " +
object::getELFSectionTypeName(
getHeader().e_machine, Section.sh_type)))
return std::move(E);
auto V = getSectionContentsAsArray<char>(Section);
if (!V)
return V.takeError();
ArrayRef<char> Data = *V;
if (Data.empty())
return createError("SHT_STRTAB string table section " +
getSecIndexForError(*this, Section) + " is empty");
if (Data.back() != '\0')
return createError("SHT_STRTAB string table section " +
getSecIndexForError(*this, Section) +
" is non-null terminated");
return StringRef(Data.begin(), Data.size());
}
template <class ELFT>
Expected<ArrayRef<typename ELFT::Word>>
ELFFile<ELFT>::getSHNDXTable(const Elf_Shdr &Section) const {
auto SectionsOrErr = sections();
if (!SectionsOrErr)
return SectionsOrErr.takeError();
return getSHNDXTable(Section, *SectionsOrErr);
}
template <class ELFT>
Expected<ArrayRef<typename ELFT::Word>>
ELFFile<ELFT>::getSHNDXTable(const Elf_Shdr &Section,
Elf_Shdr_Range Sections) const {
assert(Section.sh_type == ELF::SHT_SYMTAB_SHNDX);
auto VOrErr = getSectionContentsAsArray<Elf_Word>(Section);
if (!VOrErr)
return VOrErr.takeError();
ArrayRef<Elf_Word> V = *VOrErr;
auto SymTableOrErr = object::getSection<ELFT>(Sections, Section.sh_link);
if (!SymTableOrErr)
return SymTableOrErr.takeError();
const Elf_Shdr &SymTable = **SymTableOrErr;
if (SymTable.sh_type != ELF::SHT_SYMTAB &&
SymTable.sh_type != ELF::SHT_DYNSYM)
return createError(
"SHT_SYMTAB_SHNDX section is linked with " +
object::getELFSectionTypeName(getHeader().e_machine, SymTable.sh_type) +
" section (expected SHT_SYMTAB/SHT_DYNSYM)");
uint64_t Syms = SymTable.sh_size / sizeof(Elf_Sym);
if (V.size() != Syms)
return createError("SHT_SYMTAB_SHNDX has " + Twine(V.size()) +
" entries, but the symbol table associated has " +
Twine(Syms));
return V;
}
template <class ELFT>
Expected<StringRef>
ELFFile<ELFT>::getStringTableForSymtab(const Elf_Shdr &Sec) const {
auto SectionsOrErr = sections();
if (!SectionsOrErr)
return SectionsOrErr.takeError();
return getStringTableForSymtab(Sec, *SectionsOrErr);
}
template <class ELFT>
Expected<StringRef>
ELFFile<ELFT>::getStringTableForSymtab(const Elf_Shdr &Sec,
Elf_Shdr_Range Sections) const {
if (Sec.sh_type != ELF::SHT_SYMTAB && Sec.sh_type != ELF::SHT_DYNSYM)
return createError(
"invalid sh_type for symbol table, expected SHT_SYMTAB or SHT_DYNSYM");
Expected<const Elf_Shdr *> SectionOrErr =
object::getSection<ELFT>(Sections, Sec.sh_link);
if (!SectionOrErr)
return SectionOrErr.takeError();
return getStringTable(**SectionOrErr);
}
template <class ELFT>
Expected<StringRef>
ELFFile<ELFT>::getLinkAsStrtab(const typename ELFT::Shdr &Sec) const {
Expected<const typename ELFT::Shdr *> StrTabSecOrErr =
getSection(Sec.sh_link);
if (!StrTabSecOrErr)
return createError("invalid section linked to " + describe(*this, Sec) +
": " + toString(StrTabSecOrErr.takeError()));
Expected<StringRef> StrTabOrErr = getStringTable(**StrTabSecOrErr);
if (!StrTabOrErr)
return createError("invalid string table linked to " +
describe(*this, Sec) + ": " +
toString(StrTabOrErr.takeError()));
return *StrTabOrErr;
}
template <class ELFT>
Expected<StringRef>
ELFFile<ELFT>::getSectionName(const Elf_Shdr &Section,
WarningHandler WarnHandler) const {
auto SectionsOrErr = sections();
if (!SectionsOrErr)
return SectionsOrErr.takeError();
auto Table = getSectionStringTable(*SectionsOrErr, WarnHandler);
if (!Table)
return Table.takeError();
return getSectionName(Section, *Table);
}
template <class ELFT>
Expected<StringRef> ELFFile<ELFT>::getSectionName(const Elf_Shdr &Section,
StringRef DotShstrtab) const {
uint32_t Offset = Section.sh_name;
if (Offset == 0)
return StringRef();
if (Offset >= DotShstrtab.size())
return createError("a section " + getSecIndexForError(*this, Section) +
" has an invalid sh_name (0x" +
Twine::utohexstr(Offset) +
") offset which goes past the end of the "
"section name string table");
return StringRef(DotShstrtab.data() + Offset);
}
/// This function returns the hash value for a symbol in the .dynsym section
/// Name of the API remains consistent as specified in the libelf
/// REF : http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash
inline unsigned hashSysV(StringRef SymbolName) {
unsigned h = 0, g;
for (char C : SymbolName) {
h = (h << 4) + C;
g = h & 0xf0000000L;
if (g != 0)
h ^= g >> 24;
h &= ~g;
}
return h;
}
} // end namespace object
} // end namespace llvm
#endif // LLVM_OBJECT_ELF_H
diff --git a/contrib/llvm-project/llvm/lib/Analysis/ScalarEvolution.cpp b/contrib/llvm-project/llvm/lib/Analysis/ScalarEvolution.cpp
index 2958a5054afc..c784c27d36b4 100644
--- a/contrib/llvm-project/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/contrib/llvm-project/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -1,14778 +1,14783 @@
//===- ScalarEvolution.cpp - Scalar Evolution Analysis --------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains the implementation of the scalar evolution analysis
// engine, which is used primarily to analyze expressions involving induction
// variables in loops.
//
// There are several aspects to this library. First is the representation of
// scalar expressions, which are represented as subclasses of the SCEV class.
// These classes are used to represent certain types of subexpressions that we
// can handle. We only create one SCEV of a particular shape, so
// pointer-comparisons for equality are legal.
//
// One important aspect of the SCEV objects is that they are never cyclic, even
// if there is a cycle in the dataflow for an expression (ie, a PHI node). If
// the PHI node is one of the idioms that we can represent (e.g., a polynomial
// recurrence) then we represent it directly as a recurrence node, otherwise we
// represent it as a SCEVUnknown node.
//
// In addition to being able to represent expressions of various types, we also
// have folders that are used to build the *canonical* representation for a
// particular expression. These folders are capable of using a variety of
// rewrite rules to simplify the expressions.
//
// Once the folders are defined, we can implement the more interesting
// higher-level code, such as the code that recognizes PHI nodes of various
// types, computes the execution count of a loop, etc.
//
// TODO: We should use these routines and value representations to implement
// dependence analysis!
//
//===----------------------------------------------------------------------===//
//
// There are several good references for the techniques used in this analysis.
//
// Chains of recurrences -- a method to expedite the evaluation
// of closed-form functions
// Olaf Bachmann, Paul S. Wang, Eugene V. Zima
//
// On computational properties of chains of recurrences
// Eugene V. Zima
//
// Symbolic Evaluation of Chains of Recurrences for Loop Optimization
// Robert A. van Engelen
//
// Efficient Symbolic Analysis for Optimizing Compilers
// Robert A. van Engelen
//
// Using the chains of recurrences algebra for data dependence testing and
// induction variable substitution
// MS Thesis, Johnie Birch
//
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/EquivalenceClasses.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Verifier.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/KnownBits.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <climits>
#include <cstdint>
#include <cstdlib>
#include <map>
#include <memory>
#include <tuple>
#include <utility>
#include <vector>
using namespace llvm;
using namespace PatternMatch;
#define DEBUG_TYPE "scalar-evolution"
STATISTIC(NumTripCountsComputed,
"Number of loops with predictable loop counts");
STATISTIC(NumTripCountsNotComputed,
"Number of loops without predictable loop counts");
STATISTIC(NumBruteForceTripCountsComputed,
"Number of loops with trip counts computed by force");
#ifdef EXPENSIVE_CHECKS
bool llvm::VerifySCEV = true;
#else
bool llvm::VerifySCEV = false;
#endif
static cl::opt<unsigned>
MaxBruteForceIterations("scalar-evolution-max-iterations", cl::ReallyHidden,
cl::desc("Maximum number of iterations SCEV will "
"symbolically execute a constant "
"derived loop"),
cl::init(100));
static cl::opt<bool, true> VerifySCEVOpt(
"verify-scev", cl::Hidden, cl::location(VerifySCEV),
cl::desc("Verify ScalarEvolution's backedge taken counts (slow)"));
static cl::opt<bool> VerifySCEVStrict(
"verify-scev-strict", cl::Hidden,
cl::desc("Enable stricter verification with -verify-scev is passed"));
static cl::opt<bool>
VerifySCEVMap("verify-scev-maps", cl::Hidden,
cl::desc("Verify no dangling value in ScalarEvolution's "
"ExprValueMap (slow)"));
static cl::opt<bool> VerifyIR(
"scev-verify-ir", cl::Hidden,
cl::desc("Verify IR correctness when making sensitive SCEV queries (slow)"),
cl::init(false));
static cl::opt<unsigned> MulOpsInlineThreshold(
"scev-mulops-inline-threshold", cl::Hidden,
cl::desc("Threshold for inlining multiplication operands into a SCEV"),
cl::init(32));
static cl::opt<unsigned> AddOpsInlineThreshold(
"scev-addops-inline-threshold", cl::Hidden,
cl::desc("Threshold for inlining addition operands into a SCEV"),
cl::init(500));
static cl::opt<unsigned> MaxSCEVCompareDepth(
"scalar-evolution-max-scev-compare-depth", cl::Hidden,
cl::desc("Maximum depth of recursive SCEV complexity comparisons"),
cl::init(32));
static cl::opt<unsigned> MaxSCEVOperationsImplicationDepth(
"scalar-evolution-max-scev-operations-implication-depth", cl::Hidden,
cl::desc("Maximum depth of recursive SCEV operations implication analysis"),
cl::init(2));
static cl::opt<unsigned> MaxValueCompareDepth(
"scalar-evolution-max-value-compare-depth", cl::Hidden,
cl::desc("Maximum depth of recursive value complexity comparisons"),
cl::init(2));
static cl::opt<unsigned>
MaxArithDepth("scalar-evolution-max-arith-depth", cl::Hidden,
cl::desc("Maximum depth of recursive arithmetics"),
cl::init(32));
static cl::opt<unsigned> MaxConstantEvolvingDepth(
"scalar-evolution-max-constant-evolving-depth", cl::Hidden,
cl::desc("Maximum depth of recursive constant evolving"), cl::init(32));
static cl::opt<unsigned>
MaxCastDepth("scalar-evolution-max-cast-depth", cl::Hidden,
cl::desc("Maximum depth of recursive SExt/ZExt/Trunc"),
cl::init(8));
static cl::opt<unsigned>
MaxAddRecSize("scalar-evolution-max-add-rec-size", cl::Hidden,
cl::desc("Max coefficients in AddRec during evolving"),
cl::init(8));
static cl::opt<unsigned>
HugeExprThreshold("scalar-evolution-huge-expr-threshold", cl::Hidden,
cl::desc("Size of the expression which is considered huge"),
cl::init(4096));
static cl::opt<bool>
ClassifyExpressions("scalar-evolution-classify-expressions",
cl::Hidden, cl::init(true),
cl::desc("When printing analysis, include information on every instruction"));
static cl::opt<bool> UseExpensiveRangeSharpening(
"scalar-evolution-use-expensive-range-sharpening", cl::Hidden,
cl::init(false),
cl::desc("Use more powerful methods of sharpening expression ranges. May "
"be costly in terms of compile time"));
static cl::opt<unsigned> MaxPhiSCCAnalysisSize(
"scalar-evolution-max-scc-analysis-depth", cl::Hidden,
cl::desc("Maximum amount of nodes to process while searching SCEVUnknown "
"Phi strongly connected components"),
cl::init(8));
static cl::opt<bool>
EnableFiniteLoopControl("scalar-evolution-finite-loop", cl::Hidden,
cl::desc("Handle <= and >= in finite loops"),
cl::init(true));
//===----------------------------------------------------------------------===//
// SCEV class definitions
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Implementation of the SCEV class.
//
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void SCEV::dump() const {
print(dbgs());
dbgs() << '\n';
}
#endif
void SCEV::print(raw_ostream &OS) const {
switch (getSCEVType()) {
case scConstant:
cast<SCEVConstant>(this)->getValue()->printAsOperand(OS, false);
return;
case scPtrToInt: {
const SCEVPtrToIntExpr *PtrToInt = cast<SCEVPtrToIntExpr>(this);
const SCEV *Op = PtrToInt->getOperand();
OS << "(ptrtoint " << *Op->getType() << " " << *Op << " to "
<< *PtrToInt->getType() << ")";
return;
}
case scTruncate: {
const SCEVTruncateExpr *Trunc = cast<SCEVTruncateExpr>(this);
const SCEV *Op = Trunc->getOperand();
OS << "(trunc " << *Op->getType() << " " << *Op << " to "
<< *Trunc->getType() << ")";
return;
}
case scZeroExtend: {
const SCEVZeroExtendExpr *ZExt = cast<SCEVZeroExtendExpr>(this);
const SCEV *Op = ZExt->getOperand();
OS << "(zext " << *Op->getType() << " " << *Op << " to "
<< *ZExt->getType() << ")";
return;
}
case scSignExtend: {
const SCEVSignExtendExpr *SExt = cast<SCEVSignExtendExpr>(this);
const SCEV *Op = SExt->getOperand();
OS << "(sext " << *Op->getType() << " " << *Op << " to "
<< *SExt->getType() << ")";
return;
}
case scAddRecExpr: {
const SCEVAddRecExpr *AR = cast<SCEVAddRecExpr>(this);
OS << "{" << *AR->getOperand(0);
for (unsigned i = 1, e = AR->getNumOperands(); i != e; ++i)
OS << ",+," << *AR->getOperand(i);
OS << "}<";
if (AR->hasNoUnsignedWrap())
OS << "nuw><";
if (AR->hasNoSignedWrap())
OS << "nsw><";
if (AR->hasNoSelfWrap() &&
!AR->getNoWrapFlags((NoWrapFlags)(FlagNUW | FlagNSW)))
OS << "nw><";
AR->getLoop()->getHeader()->printAsOperand(OS, /*PrintType=*/false);
OS << ">";
return;
}
case scAddExpr:
case scMulExpr:
case scUMaxExpr:
case scSMaxExpr:
case scUMinExpr:
case scSMinExpr:
case scSequentialUMinExpr: {
const SCEVNAryExpr *NAry = cast<SCEVNAryExpr>(this);
const char *OpStr = nullptr;
switch (NAry->getSCEVType()) {
case scAddExpr: OpStr = " + "; break;
case scMulExpr: OpStr = " * "; break;
case scUMaxExpr: OpStr = " umax "; break;
case scSMaxExpr: OpStr = " smax "; break;
case scUMinExpr:
OpStr = " umin ";
break;
case scSMinExpr:
OpStr = " smin ";
break;
case scSequentialUMinExpr:
OpStr = " umin_seq ";
break;
default:
llvm_unreachable("There are no other nary expression types.");
}
OS << "(";
ListSeparator LS(OpStr);
for (const SCEV *Op : NAry->operands())
OS << LS << *Op;
OS << ")";
switch (NAry->getSCEVType()) {
case scAddExpr:
case scMulExpr:
if (NAry->hasNoUnsignedWrap())
OS << "<nuw>";
if (NAry->hasNoSignedWrap())
OS << "<nsw>";
break;
default:
// Nothing to print for other nary expressions.
break;
}
return;
}
case scUDivExpr: {
const SCEVUDivExpr *UDiv = cast<SCEVUDivExpr>(this);
OS << "(" << *UDiv->getLHS() << " /u " << *UDiv->getRHS() << ")";
return;
}
case scUnknown: {
const SCEVUnknown *U = cast<SCEVUnknown>(this);
Type *AllocTy;
if (U->isSizeOf(AllocTy)) {
OS << "sizeof(" << *AllocTy << ")";
return;
}
if (U->isAlignOf(AllocTy)) {
OS << "alignof(" << *AllocTy << ")";
return;
}
Type *CTy;
Constant *FieldNo;
if (U->isOffsetOf(CTy, FieldNo)) {
OS << "offsetof(" << *CTy << ", ";
FieldNo->printAsOperand(OS, false);
OS << ")";
return;
}
// Otherwise just print it normally.
U->getValue()->printAsOperand(OS, false);
return;
}
case scCouldNotCompute:
OS << "***COULDNOTCOMPUTE***";
return;
}
llvm_unreachable("Unknown SCEV kind!");
}
Type *SCEV::getType() const {
switch (getSCEVType()) {
case scConstant:
return cast<SCEVConstant>(this)->getType();
case scPtrToInt:
case scTruncate:
case scZeroExtend:
case scSignExtend:
return cast<SCEVCastExpr>(this)->getType();
case scAddRecExpr:
return cast<SCEVAddRecExpr>(this)->getType();
case scMulExpr:
return cast<SCEVMulExpr>(this)->getType();
case scUMaxExpr:
case scSMaxExpr:
case scUMinExpr:
case scSMinExpr:
return cast<SCEVMinMaxExpr>(this)->getType();
case scSequentialUMinExpr:
return cast<SCEVSequentialMinMaxExpr>(this)->getType();
case scAddExpr:
return cast<SCEVAddExpr>(this)->getType();
case scUDivExpr:
return cast<SCEVUDivExpr>(this)->getType();
case scUnknown:
return cast<SCEVUnknown>(this)->getType();
case scCouldNotCompute:
llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!");
}
llvm_unreachable("Unknown SCEV kind!");
}
bool SCEV::isZero() const {
if (const SCEVConstant *SC = dyn_cast<SCEVConstant>(this))
return SC->getValue()->isZero();
return false;
}
bool SCEV::isOne() const {
if (const SCEVConstant *SC = dyn_cast<SCEVConstant>(this))
return SC->getValue()->isOne();
return false;
}
bool SCEV::isAllOnesValue() const {
if (const SCEVConstant *SC = dyn_cast<SCEVConstant>(this))
return SC->getValue()->isMinusOne();
return false;
}
bool SCEV::isNonConstantNegative() const {
const SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(this);
if (!Mul) return false;
// If there is a constant factor, it will be first.
const SCEVConstant *SC = dyn_cast<SCEVConstant>(Mul->getOperand(0));
if (!SC) return false;
// Return true if the value is negative, this matches things like (-42 * V).
return SC->getAPInt().isNegative();
}
SCEVCouldNotCompute::SCEVCouldNotCompute() :
SCEV(FoldingSetNodeIDRef(), scCouldNotCompute, 0) {}
bool SCEVCouldNotCompute::classof(const SCEV *S) {
return S->getSCEVType() == scCouldNotCompute;
}
const SCEV *ScalarEvolution::getConstant(ConstantInt *V) {
FoldingSetNodeID ID;
ID.AddInteger(scConstant);
ID.AddPointer(V);
void *IP = nullptr;
if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S;
SCEV *S = new (SCEVAllocator) SCEVConstant(ID.Intern(SCEVAllocator), V);
UniqueSCEVs.InsertNode(S, IP);
return S;
}
const SCEV *ScalarEvolution::getConstant(const APInt &Val) {
return getConstant(ConstantInt::get(getContext(), Val));
}
const SCEV *
ScalarEvolution::getConstant(Type *Ty, uint64_t V, bool isSigned) {
IntegerType *ITy = cast<IntegerType>(getEffectiveSCEVType(Ty));
return getConstant(ConstantInt::get(ITy, V, isSigned));
}
SCEVCastExpr::SCEVCastExpr(const FoldingSetNodeIDRef ID, SCEVTypes SCEVTy,
const SCEV *op, Type *ty)
: SCEV(ID, SCEVTy, computeExpressionSize(op)), Ty(ty) {
Operands[0] = op;
}
SCEVPtrToIntExpr::SCEVPtrToIntExpr(const FoldingSetNodeIDRef ID, const SCEV *Op,
Type *ITy)
: SCEVCastExpr(ID, scPtrToInt, Op, ITy) {
assert(getOperand()->getType()->isPointerTy() && Ty->isIntegerTy() &&
"Must be a non-bit-width-changing pointer-to-integer cast!");
}
SCEVIntegralCastExpr::SCEVIntegralCastExpr(const FoldingSetNodeIDRef ID,
SCEVTypes SCEVTy, const SCEV *op,
Type *ty)
: SCEVCastExpr(ID, SCEVTy, op, ty) {}
SCEVTruncateExpr::SCEVTruncateExpr(const FoldingSetNodeIDRef ID, const SCEV *op,
Type *ty)
: SCEVIntegralCastExpr(ID, scTruncate, op, ty) {
assert(getOperand()->getType()->isIntOrPtrTy() && Ty->isIntOrPtrTy() &&
"Cannot truncate non-integer value!");
}
SCEVZeroExtendExpr::SCEVZeroExtendExpr(const FoldingSetNodeIDRef ID,
const SCEV *op, Type *ty)
: SCEVIntegralCastExpr(ID, scZeroExtend, op, ty) {
assert(getOperand()->getType()->isIntOrPtrTy() && Ty->isIntOrPtrTy() &&
"Cannot zero extend non-integer value!");
}
SCEVSignExtendExpr::SCEVSignExtendExpr(const FoldingSetNodeIDRef ID,
const SCEV *op, Type *ty)
: SCEVIntegralCastExpr(ID, scSignExtend, op, ty) {
assert(getOperand()->getType()->isIntOrPtrTy() && Ty->isIntOrPtrTy() &&
"Cannot sign extend non-integer value!");
}
void SCEVUnknown::deleted() {
// Clear this SCEVUnknown from various maps.
SE->forgetMemoizedResults(this);
// Remove this SCEVUnknown from the uniquing map.
SE->UniqueSCEVs.RemoveNode(this);
// Release the value.
setValPtr(nullptr);
}
void SCEVUnknown::allUsesReplacedWith(Value *New) {
// Clear this SCEVUnknown from various maps.
SE->forgetMemoizedResults(this);
// Remove this SCEVUnknown from the uniquing map.
SE->UniqueSCEVs.RemoveNode(this);
// Replace the value pointer in case someone is still using this SCEVUnknown.
setValPtr(New);
}
bool SCEVUnknown::isSizeOf(Type *&AllocTy) const {
if (ConstantExpr *VCE = dyn_cast<ConstantExpr>(getValue()))
if (VCE->getOpcode() == Instruction::PtrToInt)
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(VCE->getOperand(0)))
if (CE->getOpcode() == Instruction::GetElementPtr &&
CE->getOperand(0)->isNullValue() &&
CE->getNumOperands() == 2)
if (ConstantInt *CI = dyn_cast<ConstantInt>(CE->getOperand(1)))
if (CI->isOne()) {
AllocTy = cast<GEPOperator>(CE)->getSourceElementType();
return true;
}
return false;
}
bool SCEVUnknown::isAlignOf(Type *&AllocTy) const {
if (ConstantExpr *VCE = dyn_cast<ConstantExpr>(getValue()))
if (VCE->getOpcode() == Instruction::PtrToInt)
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(VCE->getOperand(0)))
if (CE->getOpcode() == Instruction::GetElementPtr &&
CE->getOperand(0)->isNullValue()) {
Type *Ty = cast<GEPOperator>(CE)->getSourceElementType();
if (StructType *STy = dyn_cast<StructType>(Ty))
if (!STy->isPacked() &&
CE->getNumOperands() == 3 &&
CE->getOperand(1)->isNullValue()) {
if (ConstantInt *CI = dyn_cast<ConstantInt>(CE->getOperand(2)))
if (CI->isOne() &&
STy->getNumElements() == 2 &&
STy->getElementType(0)->isIntegerTy(1)) {
AllocTy = STy->getElementType(1);
return true;
}
}
}
return false;
}
bool SCEVUnknown::isOffsetOf(Type *&CTy, Constant *&FieldNo) const {
if (ConstantExpr *VCE = dyn_cast<ConstantExpr>(getValue()))
if (VCE->getOpcode() == Instruction::PtrToInt)
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(VCE->getOperand(0)))
if (CE->getOpcode() == Instruction::GetElementPtr &&
CE->getNumOperands() == 3 &&
CE->getOperand(0)->isNullValue() &&
CE->getOperand(1)->isNullValue()) {
Type *Ty = cast<GEPOperator>(CE)->getSourceElementType();
// Ignore vector types here so that ScalarEvolutionExpander doesn't
// emit getelementptrs that index into vectors.
if (Ty->isStructTy() || Ty->isArrayTy()) {
CTy = Ty;
FieldNo = CE->getOperand(2);
return true;
}
}
return false;
}
//===----------------------------------------------------------------------===//
// SCEV Utilities
//===----------------------------------------------------------------------===//
/// Compare the two values \p LV and \p RV in terms of their "complexity" where
/// "complexity" is a partial (and somewhat ad-hoc) relation used to order
/// operands in SCEV expressions. \p EqCache is a set of pairs of values that
/// have been previously deemed to be "equally complex" by this routine. It is
/// intended to avoid exponential time complexity in cases like:
///
/// %a = f(%x, %y)
/// %b = f(%a, %a)
/// %c = f(%b, %b)
///
/// %d = f(%x, %y)
/// %e = f(%d, %d)
/// %f = f(%e, %e)
///
/// CompareValueComplexity(%f, %c)
///
/// Since we do not continue running this routine on expression trees once we
/// have seen unequal values, there is no need to track them in the cache.
static int
CompareValueComplexity(EquivalenceClasses<const Value *> &EqCacheValue,
const LoopInfo *const LI, Value *LV, Value *RV,
unsigned Depth) {
if (Depth > MaxValueCompareDepth || EqCacheValue.isEquivalent(LV, RV))
return 0;
// Order pointer values after integer values. This helps SCEVExpander form
// GEPs.
bool LIsPointer = LV->getType()->isPointerTy(),
RIsPointer = RV->getType()->isPointerTy();
if (LIsPointer != RIsPointer)
return (int)LIsPointer - (int)RIsPointer;
// Compare getValueID values.
unsigned LID = LV->getValueID(), RID = RV->getValueID();
if (LID != RID)
return (int)LID - (int)RID;
// Sort arguments by their position.
if (const auto *LA = dyn_cast<Argument>(LV)) {
const auto *RA = cast<Argument>(RV);
unsigned LArgNo = LA->getArgNo(), RArgNo = RA->getArgNo();
return (int)LArgNo - (int)RArgNo;
}
if (const auto *LGV = dyn_cast<GlobalValue>(LV)) {
const auto *RGV = cast<GlobalValue>(RV);
const auto IsGVNameSemantic = [&](const GlobalValue *GV) {
auto LT = GV->getLinkage();
return !(GlobalValue::isPrivateLinkage(LT) ||
GlobalValue::isInternalLinkage(LT));
};
// Use the names to distinguish the two values, but only if the
// names are semantically important.
if (IsGVNameSemantic(LGV) && IsGVNameSemantic(RGV))
return LGV->getName().compare(RGV->getName());
}
// For instructions, compare their loop depth, and their operand count. This
// is pretty loose.
if (const auto *LInst = dyn_cast<Instruction>(LV)) {
const auto *RInst = cast<Instruction>(RV);
// Compare loop depths.
const BasicBlock *LParent = LInst->getParent(),
*RParent = RInst->getParent();
if (LParent != RParent) {
unsigned LDepth = LI->getLoopDepth(LParent),
RDepth = LI->getLoopDepth(RParent);
if (LDepth != RDepth)
return (int)LDepth - (int)RDepth;
}
// Compare the number of operands.
unsigned LNumOps = LInst->getNumOperands(),
RNumOps = RInst->getNumOperands();
if (LNumOps != RNumOps)
return (int)LNumOps - (int)RNumOps;
for (unsigned Idx : seq(0u, LNumOps)) {
int Result =
CompareValueComplexity(EqCacheValue, LI, LInst->getOperand(Idx),
RInst->getOperand(Idx), Depth + 1);
if (Result != 0)
return Result;
}
}
EqCacheValue.unionSets(LV, RV);
return 0;
}
// Return negative, zero, or positive, if LHS is less than, equal to, or greater
// than RHS, respectively. A three-way result allows recursive comparisons to be
// more efficient.
// If the max analysis depth was reached, return None, assuming we do not know
// if they are equivalent for sure.
static Optional<int>
CompareSCEVComplexity(EquivalenceClasses<const SCEV *> &EqCacheSCEV,
EquivalenceClasses<const Value *> &EqCacheValue,
const LoopInfo *const LI, const SCEV *LHS,
const SCEV *RHS, DominatorTree &DT, unsigned Depth = 0) {
// Fast-path: SCEVs are uniqued so we can do a quick equality check.
if (LHS == RHS)
return 0;
// Primarily, sort the SCEVs by their getSCEVType().
SCEVTypes LType = LHS->getSCEVType(), RType = RHS->getSCEVType();
if (LType != RType)
return (int)LType - (int)RType;
if (EqCacheSCEV.isEquivalent(LHS, RHS))
return 0;
if (Depth > MaxSCEVCompareDepth)
return None;
// Aside from the getSCEVType() ordering, the particular ordering
// isn't very important except that it's beneficial to be consistent,
// so that (a + b) and (b + a) don't end up as different expressions.
switch (LType) {
case scUnknown: {
const SCEVUnknown *LU = cast<SCEVUnknown>(LHS);
const SCEVUnknown *RU = cast<SCEVUnknown>(RHS);
int X = CompareValueComplexity(EqCacheValue, LI, LU->getValue(),
RU->getValue(), Depth + 1);
if (X == 0)
EqCacheSCEV.unionSets(LHS, RHS);
return X;
}
case scConstant: {
const SCEVConstant *LC = cast<SCEVConstant>(LHS);
const SCEVConstant *RC = cast<SCEVConstant>(RHS);
// Compare constant values.
const APInt &LA = LC->getAPInt();
const APInt &RA = RC->getAPInt();
unsigned LBitWidth = LA.getBitWidth(), RBitWidth = RA.getBitWidth();
if (LBitWidth != RBitWidth)
return (int)LBitWidth - (int)RBitWidth;
return LA.ult(RA) ? -1 : 1;
}
case scAddRecExpr: {
const SCEVAddRecExpr *LA = cast<SCEVAddRecExpr>(LHS);
const SCEVAddRecExpr *RA = cast<SCEVAddRecExpr>(RHS);
// There is always a dominance between two recs that are used by one SCEV,
// so we can safely sort recs by loop header dominance. We require such
// order in getAddExpr.
const Loop *LLoop = LA->getLoop(), *RLoop = RA->getLoop();
if (LLoop != RLoop) {
const BasicBlock *LHead = LLoop->getHeader(), *RHead = RLoop->getHeader();
assert(LHead != RHead && "Two loops share the same header?");
if (DT.dominates(LHead, RHead))
return 1;
else
assert(DT.dominates(RHead, LHead) &&
"No dominance between recurrences used by one SCEV?");
return -1;
}
// Addrec complexity grows with operand count.
unsigned LNumOps = LA->getNumOperands(), RNumOps = RA->getNumOperands();
if (LNumOps != RNumOps)
return (int)LNumOps - (int)RNumOps;
// Lexicographically compare.
for (unsigned i = 0; i != LNumOps; ++i) {
auto X = CompareSCEVComplexity(EqCacheSCEV, EqCacheValue, LI,
LA->getOperand(i), RA->getOperand(i), DT,
Depth + 1);
if (X != 0)
return X;
}
EqCacheSCEV.unionSets(LHS, RHS);
return 0;
}
case scAddExpr:
case scMulExpr:
case scSMaxExpr:
case scUMaxExpr:
case scSMinExpr:
case scUMinExpr:
case scSequentialUMinExpr: {
const SCEVNAryExpr *LC = cast<SCEVNAryExpr>(LHS);
const SCEVNAryExpr *RC = cast<SCEVNAryExpr>(RHS);
// Lexicographically compare n-ary expressions.
unsigned LNumOps = LC->getNumOperands(), RNumOps = RC->getNumOperands();
if (LNumOps != RNumOps)
return (int)LNumOps - (int)RNumOps;
for (unsigned i = 0; i != LNumOps; ++i) {
auto X = CompareSCEVComplexity(EqCacheSCEV, EqCacheValue, LI,
LC->getOperand(i), RC->getOperand(i), DT,
Depth + 1);
if (X != 0)
return X;
}
EqCacheSCEV.unionSets(LHS, RHS);
return 0;
}
case scUDivExpr: {
const SCEVUDivExpr *LC = cast<SCEVUDivExpr>(LHS);
const SCEVUDivExpr *RC = cast<SCEVUDivExpr>(RHS);
// Lexicographically compare udiv expressions.
auto X = CompareSCEVComplexity(EqCacheSCEV, EqCacheValue, LI, LC->getLHS(),
RC->getLHS(), DT, Depth + 1);
if (X != 0)
return X;
X = CompareSCEVComplexity(EqCacheSCEV, EqCacheValue, LI, LC->getRHS(),
RC->getRHS(), DT, Depth + 1);
if (X == 0)
EqCacheSCEV.unionSets(LHS, RHS);
return X;
}
case scPtrToInt:
case scTruncate:
case scZeroExtend:
case scSignExtend: {
const SCEVCastExpr *LC = cast<SCEVCastExpr>(LHS);
const SCEVCastExpr *RC = cast<SCEVCastExpr>(RHS);
// Compare cast expressions by operand.
auto X =
CompareSCEVComplexity(EqCacheSCEV, EqCacheValue, LI, LC->getOperand(),
RC->getOperand(), DT, Depth + 1);
if (X == 0)
EqCacheSCEV.unionSets(LHS, RHS);
return X;
}
case scCouldNotCompute:
llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!");
}
llvm_unreachable("Unknown SCEV kind!");
}
/// Given a list of SCEV objects, order them by their complexity, and group
/// objects of the same complexity together by value. When this routine is
/// finished, we know that any duplicates in the vector are consecutive and that
/// complexity is monotonically increasing.
///
/// Note that we go take special precautions to ensure that we get deterministic
/// results from this routine. In other words, we don't want the results of
/// this to depend on where the addresses of various SCEV objects happened to
/// land in memory.
static void GroupByComplexity(SmallVectorImpl<const SCEV *> &Ops,
LoopInfo *LI, DominatorTree &DT) {
if (Ops.size() < 2) return; // Noop
EquivalenceClasses<const SCEV *> EqCacheSCEV;
EquivalenceClasses<const Value *> EqCacheValue;
// Whether LHS has provably less complexity than RHS.
auto IsLessComplex = [&](const SCEV *LHS, const SCEV *RHS) {
auto Complexity =
CompareSCEVComplexity(EqCacheSCEV, EqCacheValue, LI, LHS, RHS, DT);
return Complexity && *Complexity < 0;
};
if (Ops.size() == 2) {
// This is the common case, which also happens to be trivially simple.
// Special case it.
const SCEV *&LHS = Ops[0], *&RHS = Ops[1];
if (IsLessComplex(RHS, LHS))
std::swap(LHS, RHS);
return;
}
// Do the rough sort by complexity.
llvm::stable_sort(Ops, [&](const SCEV *LHS, const SCEV *RHS) {
return IsLessComplex(LHS, RHS);
});
// Now that we are sorted by complexity, group elements of the same
// complexity. Note that this is, at worst, N^2, but the vector is likely to
// be extremely short in practice. Note that we take this approach because we
// do not want to depend on the addresses of the objects we are grouping.
for (unsigned i = 0, e = Ops.size(); i != e-2; ++i) {
const SCEV *S = Ops[i];
unsigned Complexity = S->getSCEVType();
// If there are any objects of the same complexity and same value as this
// one, group them.
for (unsigned j = i+1; j != e && Ops[j]->getSCEVType() == Complexity; ++j) {
if (Ops[j] == S) { // Found a duplicate.
// Move it to immediately after i'th element.
std::swap(Ops[i+1], Ops[j]);
++i; // no need to rescan it.
if (i == e-2) return; // Done!
}
}
}
}
/// Returns true if \p Ops contains a huge SCEV (the subtree of S contains at
/// least HugeExprThreshold nodes).
static bool hasHugeExpression(ArrayRef<const SCEV *> Ops) {
return any_of(Ops, [](const SCEV *S) {
return S->getExpressionSize() >= HugeExprThreshold;
});
}
//===----------------------------------------------------------------------===//
// Simple SCEV method implementations
//===----------------------------------------------------------------------===//
/// Compute BC(It, K). The result has width W. Assume, K > 0.
static const SCEV *BinomialCoefficient(const SCEV *It, unsigned K,
ScalarEvolution &SE,
Type *ResultTy) {
// Handle the simplest case efficiently.
if (K == 1)
return SE.getTruncateOrZeroExtend(It, ResultTy);
// We are using the following formula for BC(It, K):
//
// BC(It, K) = (It * (It - 1) * ... * (It - K + 1)) / K!
//
// Suppose, W is the bitwidth of the return value. We must be prepared for
// overflow. Hence, we must assure that the result of our computation is
// equal to the accurate one modulo 2^W. Unfortunately, division isn't
// safe in modular arithmetic.
//
// However, this code doesn't use exactly that formula; the formula it uses
// is something like the following, where T is the number of factors of 2 in
// K! (i.e. trailing zeros in the binary representation of K!), and ^ is
// exponentiation:
//
// BC(It, K) = (It * (It - 1) * ... * (It - K + 1)) / 2^T / (K! / 2^T)
//
// This formula is trivially equivalent to the previous formula. However,
// this formula can be implemented much more efficiently. The trick is that
// K! / 2^T is odd, and exact division by an odd number *is* safe in modular
// arithmetic. To do exact division in modular arithmetic, all we have
// to do is multiply by the inverse. Therefore, this step can be done at
// width W.
//
// The next issue is how to safely do the division by 2^T. The way this
// is done is by doing the multiplication step at a width of at least W + T
// bits. This way, the bottom W+T bits of the product are accurate. Then,
// when we perform the division by 2^T (which is equivalent to a right shift
// by T), the bottom W bits are accurate. Extra bits are okay; they'll get
// truncated out after the division by 2^T.
//
// In comparison to just directly using the first formula, this technique
// is much more efficient; using the first formula requires W * K bits,
// but this formula less than W + K bits. Also, the first formula requires
// a division step, whereas this formula only requires multiplies and shifts.
//
// It doesn't matter whether the subtraction step is done in the calculation
// width or the input iteration count's width; if the subtraction overflows,
// the result must be zero anyway. We prefer here to do it in the width of
// the induction variable because it helps a lot for certain cases; CodeGen
// isn't smart enough to ignore the overflow, which leads to much less
// efficient code if the width of the subtraction is wider than the native
// register width.
//
// (It's possible to not widen at all by pulling out factors of 2 before
// the multiplication; for example, K=2 can be calculated as
// It/2*(It+(It*INT_MIN/INT_MIN)+-1). However, it requires
// extra arithmetic, so it's not an obvious win, and it gets
// much more complicated for K > 3.)
// Protection from insane SCEVs; this bound is conservative,
// but it probably doesn't matter.
if (K > 1000)
return SE.getCouldNotCompute();
unsigned W = SE.getTypeSizeInBits(ResultTy);
// Calculate K! / 2^T and T; we divide out the factors of two before
// multiplying for calculating K! / 2^T to avoid overflow.
// Other overflow doesn't matter because we only care about the bottom
// W bits of the result.
APInt OddFactorial(W, 1);
unsigned T = 1;
for (unsigned i = 3; i <= K; ++i) {
APInt Mult(W, i);
unsigned TwoFactors = Mult.countTrailingZeros();
T += TwoFactors;
Mult.lshrInPlace(TwoFactors);
OddFactorial *= Mult;
}
// We need at least W + T bits for the multiplication step
unsigned CalculationBits = W + T;
// Calculate 2^T, at width T+W.
APInt DivFactor = APInt::getOneBitSet(CalculationBits, T);
// Calculate the multiplicative inverse of K! / 2^T;
// this multiplication factor will perform the exact division by
// K! / 2^T.
APInt Mod = APInt::getSignedMinValue(W+1);
APInt MultiplyFactor = OddFactorial.zext(W+1);
MultiplyFactor = MultiplyFactor.multiplicativeInverse(Mod);
MultiplyFactor = MultiplyFactor.trunc(W);
// Calculate the product, at width T+W
IntegerType *CalculationTy = IntegerType::get(SE.getContext(),
CalculationBits);
const SCEV *Dividend = SE.getTruncateOrZeroExtend(It, CalculationTy);
for (unsigned i = 1; i != K; ++i) {
const SCEV *S = SE.getMinusSCEV(It, SE.getConstant(It->getType(), i));
Dividend = SE.getMulExpr(Dividend,
SE.getTruncateOrZeroExtend(S, CalculationTy));
}
// Divide by 2^T
const SCEV *DivResult = SE.getUDivExpr(Dividend, SE.getConstant(DivFactor));
// Truncate the result, and divide by K! / 2^T.
return SE.getMulExpr(SE.getConstant(MultiplyFactor),
SE.getTruncateOrZeroExtend(DivResult, ResultTy));
}
/// Return the value of this chain of recurrences at the specified iteration
/// number. We can evaluate this recurrence by multiplying each element in the
/// chain by the binomial coefficient corresponding to it. In other words, we
/// can evaluate {A,+,B,+,C,+,D} as:
///
/// A*BC(It, 0) + B*BC(It, 1) + C*BC(It, 2) + D*BC(It, 3)
///
/// where BC(It, k) stands for binomial coefficient.
const SCEV *SCEVAddRecExpr::evaluateAtIteration(const SCEV *It,
ScalarEvolution &SE) const {
return evaluateAtIteration(makeArrayRef(op_begin(), op_end()), It, SE);
}
const SCEV *
SCEVAddRecExpr::evaluateAtIteration(ArrayRef<const SCEV *> Operands,
const SCEV *It, ScalarEvolution &SE) {
assert(Operands.size() > 0);
const SCEV *Result = Operands[0];
for (unsigned i = 1, e = Operands.size(); i != e; ++i) {
// The computation is correct in the face of overflow provided that the
// multiplication is performed _after_ the evaluation of the binomial
// coefficient.
const SCEV *Coeff = BinomialCoefficient(It, i, SE, Result->getType());
if (isa<SCEVCouldNotCompute>(Coeff))
return Coeff;
Result = SE.getAddExpr(Result, SE.getMulExpr(Operands[i], Coeff));
}
return Result;
}
//===----------------------------------------------------------------------===//
// SCEV Expression folder implementations
//===----------------------------------------------------------------------===//
const SCEV *ScalarEvolution::getLosslessPtrToIntExpr(const SCEV *Op,
unsigned Depth) {
assert(Depth <= 1 &&
"getLosslessPtrToIntExpr() should self-recurse at most once.");
// We could be called with an integer-typed operands during SCEV rewrites.
// Since the operand is an integer already, just perform zext/trunc/self cast.
if (!Op->getType()->isPointerTy())
return Op;
// What would be an ID for such a SCEV cast expression?
FoldingSetNodeID ID;
ID.AddInteger(scPtrToInt);
ID.AddPointer(Op);
void *IP = nullptr;
// Is there already an expression for such a cast?
if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP))
return S;
// It isn't legal for optimizations to construct new ptrtoint expressions
// for non-integral pointers.
if (getDataLayout().isNonIntegralPointerType(Op->getType()))
return getCouldNotCompute();
Type *IntPtrTy = getDataLayout().getIntPtrType(Op->getType());
// We can only trivially model ptrtoint if SCEV's effective (integer) type
// is sufficiently wide to represent all possible pointer values.
// We could theoretically teach SCEV to truncate wider pointers, but
// that isn't implemented for now.
if (getDataLayout().getTypeSizeInBits(getEffectiveSCEVType(Op->getType())) !=
getDataLayout().getTypeSizeInBits(IntPtrTy))
return getCouldNotCompute();
// If not, is this expression something we can't reduce any further?
if (auto *U = dyn_cast<SCEVUnknown>(Op)) {
// Perform some basic constant folding. If the operand of the ptr2int cast
// is a null pointer, don't create a ptr2int SCEV expression (that will be
// left as-is), but produce a zero constant.
// NOTE: We could handle a more general case, but lack motivational cases.
if (isa<ConstantPointerNull>(U->getValue()))
return getZero(IntPtrTy);
// Create an explicit cast node.
// We can reuse the existing insert position since if we get here,
// we won't have made any changes which would invalidate it.
SCEV *S = new (SCEVAllocator)
SCEVPtrToIntExpr(ID.Intern(SCEVAllocator), Op, IntPtrTy);
UniqueSCEVs.InsertNode(S, IP);
registerUser(S, Op);
return S;
}
assert(Depth == 0 && "getLosslessPtrToIntExpr() should not self-recurse for "
"non-SCEVUnknown's.");
// Otherwise, we've got some expression that is more complex than just a
// single SCEVUnknown. But we don't want to have a SCEVPtrToIntExpr of an
// arbitrary expression, we want to have SCEVPtrToIntExpr of an SCEVUnknown
// only, and the expressions must otherwise be integer-typed.
// So sink the cast down to the SCEVUnknown's.
/// The SCEVPtrToIntSinkingRewriter takes a scalar evolution expression,
/// which computes a pointer-typed value, and rewrites the whole expression
/// tree so that *all* the computations are done on integers, and the only
/// pointer-typed operands in the expression are SCEVUnknown.
class SCEVPtrToIntSinkingRewriter
: public SCEVRewriteVisitor<SCEVPtrToIntSinkingRewriter> {
using Base = SCEVRewriteVisitor<SCEVPtrToIntSinkingRewriter>;
public:
SCEVPtrToIntSinkingRewriter(ScalarEvolution &SE) : SCEVRewriteVisitor(SE) {}
static const SCEV *rewrite(const SCEV *Scev, ScalarEvolution &SE) {
SCEVPtrToIntSinkingRewriter Rewriter(SE);
return Rewriter.visit(Scev);
}
const SCEV *visit(const SCEV *S) {
Type *STy = S->getType();
// If the expression is not pointer-typed, just keep it as-is.
if (!STy->isPointerTy())
return S;
// Else, recursively sink the cast down into it.
return Base::visit(S);
}
const SCEV *visitAddExpr(const SCEVAddExpr *Expr) {
SmallVector<const SCEV *, 2> Operands;
bool Changed = false;
for (const auto *Op : Expr->operands()) {
Operands.push_back(visit(Op));
Changed |= Op != Operands.back();
}
return !Changed ? Expr : SE.getAddExpr(Operands, Expr->getNoWrapFlags());
}
const SCEV *visitMulExpr(const SCEVMulExpr *Expr) {
SmallVector<const SCEV *, 2> Operands;
bool Changed = false;
for (const auto *Op : Expr->operands()) {
Operands.push_back(visit(Op));
Changed |= Op != Operands.back();
}
return !Changed ? Expr : SE.getMulExpr(Operands, Expr->getNoWrapFlags());
}
const SCEV *visitUnknown(const SCEVUnknown *Expr) {
assert(Expr->getType()->isPointerTy() &&
"Should only reach pointer-typed SCEVUnknown's.");
return SE.getLosslessPtrToIntExpr(Expr, /*Depth=*/1);
}
};
// And actually perform the cast sinking.
const SCEV *IntOp = SCEVPtrToIntSinkingRewriter::rewrite(Op, *this);
assert(IntOp->getType()->isIntegerTy() &&
"We must have succeeded in sinking the cast, "
"and ending up with an integer-typed expression!");
return IntOp;
}
const SCEV *ScalarEvolution::getPtrToIntExpr(const SCEV *Op, Type *Ty) {
assert(Ty->isIntegerTy() && "Target type must be an integer type!");
const SCEV *IntOp = getLosslessPtrToIntExpr(Op);
if (isa<SCEVCouldNotCompute>(IntOp))
return IntOp;
return getTruncateOrZeroExtend(IntOp, Ty);
}
const SCEV *ScalarEvolution::getTruncateExpr(const SCEV *Op, Type *Ty,
unsigned Depth) {
assert(getTypeSizeInBits(Op->getType()) > getTypeSizeInBits(Ty) &&
"This is not a truncating conversion!");
assert(isSCEVable(Ty) &&
"This is not a conversion to a SCEVable type!");
assert(!Op->getType()->isPointerTy() && "Can't truncate pointer!");
Ty = getEffectiveSCEVType(Ty);
FoldingSetNodeID ID;
ID.AddInteger(scTruncate);
ID.AddPointer(Op);
ID.AddPointer(Ty);
void *IP = nullptr;
if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S;
// Fold if the operand is constant.
if (const SCEVConstant *SC = dyn_cast<SCEVConstant>(Op))
return getConstant(
cast<ConstantInt>(ConstantExpr::getTrunc(SC->getValue(), Ty)));
// trunc(trunc(x)) --> trunc(x)
if (const SCEVTruncateExpr *ST = dyn_cast<SCEVTruncateExpr>(Op))
return getTruncateExpr(ST->getOperand(), Ty, Depth + 1);
// trunc(sext(x)) --> sext(x) if widening or trunc(x) if narrowing
if (const SCEVSignExtendExpr *SS = dyn_cast<SCEVSignExtendExpr>(Op))
return getTruncateOrSignExtend(SS->getOperand(), Ty, Depth + 1);
// trunc(zext(x)) --> zext(x) if widening or trunc(x) if narrowing
if (const SCEVZeroExtendExpr *SZ = dyn_cast<SCEVZeroExtendExpr>(Op))
return getTruncateOrZeroExtend(SZ->getOperand(), Ty, Depth + 1);
if (Depth > MaxCastDepth) {
SCEV *S =
new (SCEVAllocator) SCEVTruncateExpr(ID.Intern(SCEVAllocator), Op, Ty);
UniqueSCEVs.InsertNode(S, IP);
registerUser(S, Op);
return S;
}
// trunc(x1 + ... + xN) --> trunc(x1) + ... + trunc(xN) and
// trunc(x1 * ... * xN) --> trunc(x1) * ... * trunc(xN),
// if after transforming we have at most one truncate, not counting truncates
// that replace other casts.
if (isa<SCEVAddExpr>(Op) || isa<SCEVMulExpr>(Op)) {
auto *CommOp = cast<SCEVCommutativeExpr>(Op);
SmallVector<const SCEV *, 4> Operands;
unsigned numTruncs = 0;
for (unsigned i = 0, e = CommOp->getNumOperands(); i != e && numTruncs < 2;
++i) {
const SCEV *S = getTruncateExpr(CommOp->getOperand(i), Ty, Depth + 1);
if (!isa<SCEVIntegralCastExpr>(CommOp->getOperand(i)) &&
isa<SCEVTruncateExpr>(S))
numTruncs++;
Operands.push_back(S);
}
if (numTruncs < 2) {
if (isa<SCEVAddExpr>(Op))
return getAddExpr(Operands);
else if (isa<SCEVMulExpr>(Op))
return getMulExpr(Operands);
else
llvm_unreachable("Unexpected SCEV type for Op.");
}
// Although we checked in the beginning that ID is not in the cache, it is
// possible that during recursion and different modification ID was inserted
// into the cache. So if we find it, just return it.
if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP))
return S;
}
// If the input value is a chrec scev, truncate the chrec's operands.
if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(Op)) {
SmallVector<const SCEV *, 4> Operands;
for (const SCEV *Op : AddRec->operands())
Operands.push_back(getTruncateExpr(Op, Ty, Depth + 1));
return getAddRecExpr(Operands, AddRec->getLoop(), SCEV::FlagAnyWrap);
}
// Return zero if truncating to known zeros.
uint32_t MinTrailingZeros = GetMinTrailingZeros(Op);
if (MinTrailingZeros >= getTypeSizeInBits(Ty))
return getZero(Ty);
// The cast wasn't folded; create an explicit cast node. We can reuse
// the existing insert position since if we get here, we won't have
// made any changes which would invalidate it.
SCEV *S = new (SCEVAllocator) SCEVTruncateExpr(ID.Intern(SCEVAllocator),
Op, Ty);
UniqueSCEVs.InsertNode(S, IP);
registerUser(S, Op);
return S;
}
// Get the limit of a recurrence such that incrementing by Step cannot cause
// signed overflow as long as the value of the recurrence within the
// loop does not exceed this limit before incrementing.
static const SCEV *getSignedOverflowLimitForStep(const SCEV *Step,
ICmpInst::Predicate *Pred,
ScalarEvolution *SE) {
unsigned BitWidth = SE->getTypeSizeInBits(Step->getType());
if (SE->isKnownPositive(Step)) {
*Pred = ICmpInst::ICMP_SLT;
return SE->getConstant(APInt::getSignedMinValue(BitWidth) -
SE->getSignedRangeMax(Step));
}
if (SE->isKnownNegative(Step)) {
*Pred = ICmpInst::ICMP_SGT;
return SE->getConstant(APInt::getSignedMaxValue(BitWidth) -
SE->getSignedRangeMin(Step));
}
return nullptr;
}
// Get the limit of a recurrence such that incrementing by Step cannot cause
// unsigned overflow as long as the value of the recurrence within the loop does
// not exceed this limit before incrementing.
static const SCEV *getUnsignedOverflowLimitForStep(const SCEV *Step,
ICmpInst::Predicate *Pred,
ScalarEvolution *SE) {
unsigned BitWidth = SE->getTypeSizeInBits(Step->getType());
*Pred = ICmpInst::ICMP_ULT;
return SE->getConstant(APInt::getMinValue(BitWidth) -
SE->getUnsignedRangeMax(Step));
}
namespace {
struct ExtendOpTraitsBase {
typedef const SCEV *(ScalarEvolution::*GetExtendExprTy)(const SCEV *, Type *,
unsigned);
};
// Used to make code generic over signed and unsigned overflow.
template <typename ExtendOp> struct ExtendOpTraits {
// Members present:
//
// static const SCEV::NoWrapFlags WrapType;
//
// static const ExtendOpTraitsBase::GetExtendExprTy GetExtendExpr;
//
// static const SCEV *getOverflowLimitForStep(const SCEV *Step,
// ICmpInst::Predicate *Pred,
// ScalarEvolution *SE);
};
template <>
struct ExtendOpTraits<SCEVSignExtendExpr> : public ExtendOpTraitsBase {
static const SCEV::NoWrapFlags WrapType = SCEV::FlagNSW;
static const GetExtendExprTy GetExtendExpr;
static const SCEV *getOverflowLimitForStep(const SCEV *Step,
ICmpInst::Predicate *Pred,
ScalarEvolution *SE) {
return getSignedOverflowLimitForStep(Step, Pred, SE);
}
};
const ExtendOpTraitsBase::GetExtendExprTy ExtendOpTraits<
SCEVSignExtendExpr>::GetExtendExpr = &ScalarEvolution::getSignExtendExpr;
template <>
struct ExtendOpTraits<SCEVZeroExtendExpr> : public ExtendOpTraitsBase {
static const SCEV::NoWrapFlags WrapType = SCEV::FlagNUW;
static const GetExtendExprTy GetExtendExpr;
static const SCEV *getOverflowLimitForStep(const SCEV *Step,
ICmpInst::Predicate *Pred,
ScalarEvolution *SE) {
return getUnsignedOverflowLimitForStep(Step, Pred, SE);
}
};
const ExtendOpTraitsBase::GetExtendExprTy ExtendOpTraits<
SCEVZeroExtendExpr>::GetExtendExpr = &ScalarEvolution::getZeroExtendExpr;
} // end anonymous namespace
// The recurrence AR has been shown to have no signed/unsigned wrap or something
// close to it. Typically, if we can prove NSW/NUW for AR, then we can just as
// easily prove NSW/NUW for its preincrement or postincrement sibling. This
// allows normalizing a sign/zero extended AddRec as such: {sext/zext(Step +
// Start),+,Step} => {(Step + sext/zext(Start),+,Step} As a result, the
// expression "Step + sext/zext(PreIncAR)" is congruent with
// "sext/zext(PostIncAR)"
template <typename ExtendOpTy>
static const SCEV *getPreStartForExtend(const SCEVAddRecExpr *AR, Type *Ty,
ScalarEvolution *SE, unsigned Depth) {
auto WrapType = ExtendOpTraits<ExtendOpTy>::WrapType;
auto GetExtendExpr = ExtendOpTraits<ExtendOpTy>::GetExtendExpr;
const Loop *L = AR->getLoop();
const SCEV *Start = AR->getStart();
const SCEV *Step = AR->getStepRecurrence(*SE);
// Check for a simple looking step prior to loop entry.
const SCEVAddExpr *SA = dyn_cast<SCEVAddExpr>(Start);
if (!SA)
return nullptr;
// Create an AddExpr for "PreStart" after subtracting Step. Full SCEV
// subtraction is expensive. For this purpose, perform a quick and dirty
// difference, by checking for Step in the operand list.
SmallVector<const SCEV *, 4> DiffOps;
for (const SCEV *Op : SA->operands())
if (Op != Step)
DiffOps.push_back(Op);
if (DiffOps.size() == SA->getNumOperands())
return nullptr;
// Try to prove `WrapType` (SCEV::FlagNSW or SCEV::FlagNUW) on `PreStart` +
// `Step`:
// 1. NSW/NUW flags on the step increment.
auto PreStartFlags =
ScalarEvolution::maskFlags(SA->getNoWrapFlags(), SCEV::FlagNUW);
const SCEV *PreStart = SE->getAddExpr(DiffOps, PreStartFlags);
const SCEVAddRecExpr *PreAR = dyn_cast<SCEVAddRecExpr>(
SE->getAddRecExpr(PreStart, Step, L, SCEV::FlagAnyWrap));
// "{S,+,X} is <nsw>/<nuw>" and "the backedge is taken at least once" implies
// "S+X does not sign/unsign-overflow".
//
const SCEV *BECount = SE->getBackedgeTakenCount(L);
if (PreAR && PreAR->getNoWrapFlags(WrapType) &&
!isa<SCEVCouldNotCompute>(BECount) && SE->isKnownPositive(BECount))
return PreStart;
// 2. Direct overflow check on the step operation's expression.
unsigned BitWidth = SE->getTypeSizeInBits(AR->getType());
Type *WideTy = IntegerType::get(SE->getContext(), BitWidth * 2);
const SCEV *OperandExtendedStart =
SE->getAddExpr((SE->*GetExtendExpr)(PreStart, WideTy, Depth),
(SE->*GetExtendExpr)(Step, WideTy, Depth));
if ((SE->*GetExtendExpr)(Start, WideTy, Depth) == OperandExtendedStart) {
if (PreAR && AR->getNoWrapFlags(WrapType)) {
// If we know `AR` == {`PreStart`+`Step`,+,`Step`} is `WrapType` (FlagNSW
// or FlagNUW) and that `PreStart` + `Step` is `WrapType` too, then
// `PreAR` == {`PreStart`,+,`Step`} is also `WrapType`. Cache this fact.
SE->setNoWrapFlags(const_cast<SCEVAddRecExpr *>(PreAR), WrapType);
}
return PreStart;
}
// 3. Loop precondition.
ICmpInst::Predicate Pred;
const SCEV *OverflowLimit =
ExtendOpTraits<ExtendOpTy>::getOverflowLimitForStep(Step, &Pred, SE);
if (OverflowLimit &&
SE->isLoopEntryGuardedByCond(L, Pred, PreStart, OverflowLimit))
return PreStart;
return nullptr;
}
// Get the normalized zero or sign extended expression for this AddRec's Start.
template <typename ExtendOpTy>
static const SCEV *getExtendAddRecStart(const SCEVAddRecExpr *AR, Type *Ty,
ScalarEvolution *SE,
unsigned Depth) {
auto GetExtendExpr = ExtendOpTraits<ExtendOpTy>::GetExtendExpr;
const SCEV *PreStart = getPreStartForExtend<ExtendOpTy>(AR, Ty, SE, Depth);
if (!PreStart)
return (SE->*GetExtendExpr)(AR->getStart(), Ty, Depth);
return SE->getAddExpr((SE->*GetExtendExpr)(AR->getStepRecurrence(*SE), Ty,
Depth),
(SE->*GetExtendExpr)(PreStart, Ty, Depth));
}
// Try to prove away overflow by looking at "nearby" add recurrences. A
// motivating example for this rule: if we know `{0,+,4}` is `ult` `-1` and it
// does not itself wrap then we can conclude that `{1,+,4}` is `nuw`.
//
// Formally:
//
// {S,+,X} == {S-T,+,X} + T
// => Ext({S,+,X}) == Ext({S-T,+,X} + T)
//
// If ({S-T,+,X} + T) does not overflow ... (1)
//
// RHS == Ext({S-T,+,X} + T) == Ext({S-T,+,X}) + Ext(T)
//
// If {S-T,+,X} does not overflow ... (2)
//
// RHS == Ext({S-T,+,X}) + Ext(T) == {Ext(S-T),+,Ext(X)} + Ext(T)
// == {Ext(S-T)+Ext(T),+,Ext(X)}
//
// If (S-T)+T does not overflow ... (3)
//
// RHS == {Ext(S-T)+Ext(T),+,Ext(X)} == {Ext(S-T+T),+,Ext(X)}
// == {Ext(S),+,Ext(X)} == LHS
//
// Thus, if (1), (2) and (3) are true for some T, then
// Ext({S,+,X}) == {Ext(S),+,Ext(X)}
//
// (3) is implied by (1) -- "(S-T)+T does not overflow" is simply "({S-T,+,X}+T)
// does not overflow" restricted to the 0th iteration. Therefore we only need
// to check for (1) and (2).
//
// In the current context, S is `Start`, X is `Step`, Ext is `ExtendOpTy` and T
// is `Delta` (defined below).
template <typename ExtendOpTy>
bool ScalarEvolution::proveNoWrapByVaryingStart(const SCEV *Start,
const SCEV *Step,
const Loop *L) {
auto WrapType = ExtendOpTraits<ExtendOpTy>::WrapType;
// We restrict `Start` to a constant to prevent SCEV from spending too much
// time here. It is correct (but more expensive) to continue with a
// non-constant `Start` and do a general SCEV subtraction to compute
// `PreStart` below.
const SCEVConstant *StartC = dyn_cast<SCEVConstant>(Start);
if (!StartC)
return false;
APInt StartAI = StartC->getAPInt();
for (unsigned Delta : {-2, -1, 1, 2}) {
const SCEV *PreStart = getConstant(StartAI - Delta);
FoldingSetNodeID ID;
ID.AddInteger(scAddRecExpr);
ID.AddPointer(PreStart);
ID.AddPointer(Step);
ID.AddPointer(L);
void *IP = nullptr;
const auto *PreAR =
static_cast<SCEVAddRecExpr *>(UniqueSCEVs.FindNodeOrInsertPos(ID, IP));
// Give up if we don't already have the add recurrence we need because
// actually constructing an add recurrence is relatively expensive.
if (PreAR && PreAR->getNoWrapFlags(WrapType)) { // proves (2)
const SCEV *DeltaS = getConstant(StartC->getType(), Delta);
ICmpInst::Predicate Pred = ICmpInst::BAD_ICMP_PREDICATE;
const SCEV *Limit = ExtendOpTraits<ExtendOpTy>::getOverflowLimitForStep(
DeltaS, &Pred, this);
if (Limit && isKnownPredicate(Pred, PreAR, Limit)) // proves (1)
return true;
}
}
return false;
}
// Finds an integer D for an expression (C + x + y + ...) such that the top
// level addition in (D + (C - D + x + y + ...)) would not wrap (signed or
// unsigned) and the number of trailing zeros of (C - D + x + y + ...) is
// maximized, where C is the \p ConstantTerm, x, y, ... are arbitrary SCEVs, and
// the (C + x + y + ...) expression is \p WholeAddExpr.
static APInt extractConstantWithoutWrapping(ScalarEvolution &SE,
const SCEVConstant *ConstantTerm,
const SCEVAddExpr *WholeAddExpr) {
const APInt &C = ConstantTerm->getAPInt();
const unsigned BitWidth = C.getBitWidth();
// Find number of trailing zeros of (x + y + ...) w/o the C first:
uint32_t TZ = BitWidth;
for (unsigned I = 1, E = WholeAddExpr->getNumOperands(); I < E && TZ; ++I)
TZ = std::min(TZ, SE.GetMinTrailingZeros(WholeAddExpr->getOperand(I)));
if (TZ) {
// Set D to be as many least significant bits of C as possible while still
// guaranteeing that adding D to (C - D + x + y + ...) won't cause a wrap:
return TZ < BitWidth ? C.trunc(TZ).zext(BitWidth) : C;
}
return APInt(BitWidth, 0);
}
// Finds an integer D for an affine AddRec expression {C,+,x} such that the top
// level addition in (D + {C-D,+,x}) would not wrap (signed or unsigned) and the
// number of trailing zeros of (C - D + x * n) is maximized, where C is the \p
// ConstantStart, x is an arbitrary \p Step, and n is the loop trip count.
static APInt extractConstantWithoutWrapping(ScalarEvolution &SE,
const APInt &ConstantStart,
const SCEV *Step) {
const unsigned BitWidth = ConstantStart.getBitWidth();
const uint32_t TZ = SE.GetMinTrailingZeros(Step);
if (TZ)
return TZ < BitWidth ? ConstantStart.trunc(TZ).zext(BitWidth)
: ConstantStart;
return APInt(BitWidth, 0);
}
const SCEV *
ScalarEvolution::getZeroExtendExpr(const SCEV *Op, Type *Ty, unsigned Depth) {
assert(getTypeSizeInBits(Op->getType()) < getTypeSizeInBits(Ty) &&
"This is not an extending conversion!");
assert(isSCEVable(Ty) &&
"This is not a conversion to a SCEVable type!");
assert(!Op->getType()->isPointerTy() && "Can't extend pointer!");
Ty = getEffectiveSCEVType(Ty);
// Fold if the operand is constant.
if (const SCEVConstant *SC = dyn_cast<SCEVConstant>(Op))
return getConstant(
cast<ConstantInt>(ConstantExpr::getZExt(SC->getValue(), Ty)));
// zext(zext(x)) --> zext(x)
if (const SCEVZeroExtendExpr *SZ = dyn_cast<SCEVZeroExtendExpr>(Op))
return getZeroExtendExpr(SZ->getOperand(), Ty, Depth + 1);
// Before doing any expensive analysis, check to see if we've already
// computed a SCEV for this Op and Ty.
FoldingSetNodeID ID;
ID.AddInteger(scZeroExtend);
ID.AddPointer(Op);
ID.AddPointer(Ty);
void *IP = nullptr;
if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S;
if (Depth > MaxCastDepth) {
SCEV *S = new (SCEVAllocator) SCEVZeroExtendExpr(ID.Intern(SCEVAllocator),
Op, Ty);
UniqueSCEVs.InsertNode(S, IP);
registerUser(S, Op);
return S;
}
// zext(trunc(x)) --> zext(x) or x or trunc(x)
if (const SCEVTruncateExpr *ST = dyn_cast<SCEVTruncateExpr>(Op)) {
// It's possible the bits taken off by the truncate were all zero bits. If
// so, we should be able to simplify this further.
const SCEV *X = ST->getOperand();
ConstantRange CR = getUnsignedRange(X);
unsigned TruncBits = getTypeSizeInBits(ST->getType());
unsigned NewBits = getTypeSizeInBits(Ty);
if (CR.truncate(TruncBits).zeroExtend(NewBits).contains(
CR.zextOrTrunc(NewBits)))
return getTruncateOrZeroExtend(X, Ty, Depth);
}
// If the input value is a chrec scev, and we can prove that the value
// did not overflow the old, smaller, value, we can zero extend all of the
// operands (often constants). This allows analysis of something like
// this: for (unsigned char X = 0; X < 100; ++X) { int Y = X; }
if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(Op))
if (AR->isAffine()) {
const SCEV *Start = AR->getStart();
const SCEV *Step = AR->getStepRecurrence(*this);
unsigned BitWidth = getTypeSizeInBits(AR->getType());
const Loop *L = AR->getLoop();
if (!AR->hasNoUnsignedWrap()) {
auto NewFlags = proveNoWrapViaConstantRanges(AR);
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), NewFlags);
}
// If we have special knowledge that this addrec won't overflow,
// we don't need to do any further analysis.
if (AR->hasNoUnsignedWrap()) {
Start =
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this, Depth + 1);
Step = getZeroExtendExpr(Step, Ty, Depth + 1);
return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
}
// Check whether the backedge-taken count is SCEVCouldNotCompute.
// Note that this serves two purposes: It filters out loops that are
// simply not analyzable, and it covers the case where this code is
// being called from within backedge-taken count analysis, such that
// attempting to ask for the backedge-taken count would likely result
// in infinite recursion. In the later case, the analysis code will
// cope with a conservative value, and it will take care to purge
// that value once it has finished.
const SCEV *MaxBECount = getConstantMaxBackedgeTakenCount(L);
if (!isa<SCEVCouldNotCompute>(MaxBECount)) {
// Manually compute the final value for AR, checking for overflow.
// Check whether the backedge-taken count can be losslessly casted to
// the addrec's type. The count is always unsigned.
const SCEV *CastedMaxBECount =
getTruncateOrZeroExtend(MaxBECount, Start->getType(), Depth);
const SCEV *RecastedMaxBECount = getTruncateOrZeroExtend(
CastedMaxBECount, MaxBECount->getType(), Depth);
if (MaxBECount == RecastedMaxBECount) {
Type *WideTy = IntegerType::get(getContext(), BitWidth * 2);
// Check whether Start+Step*MaxBECount has no unsigned overflow.
const SCEV *ZMul = getMulExpr(CastedMaxBECount, Step,
SCEV::FlagAnyWrap, Depth + 1);
const SCEV *ZAdd = getZeroExtendExpr(getAddExpr(Start, ZMul,
SCEV::FlagAnyWrap,
Depth + 1),
WideTy, Depth + 1);
const SCEV *WideStart = getZeroExtendExpr(Start, WideTy, Depth + 1);
const SCEV *WideMaxBECount =
getZeroExtendExpr(CastedMaxBECount, WideTy, Depth + 1);
const SCEV *OperandExtendedAdd =
getAddExpr(WideStart,
getMulExpr(WideMaxBECount,
getZeroExtendExpr(Step, WideTy, Depth + 1),
SCEV::FlagAnyWrap, Depth + 1),
SCEV::FlagAnyWrap, Depth + 1);
if (ZAdd == OperandExtendedAdd) {
// Cache knowledge of AR NUW, which is propagated to this AddRec.
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), SCEV::FlagNUW);
// Return the expression with the addrec on the outside.
Start = getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this,
Depth + 1);
Step = getZeroExtendExpr(Step, Ty, Depth + 1);
return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
}
// Similar to above, only this time treat the step value as signed.
// This covers loops that count down.
OperandExtendedAdd =
getAddExpr(WideStart,
getMulExpr(WideMaxBECount,
getSignExtendExpr(Step, WideTy, Depth + 1),
SCEV::FlagAnyWrap, Depth + 1),
SCEV::FlagAnyWrap, Depth + 1);
if (ZAdd == OperandExtendedAdd) {
// Cache knowledge of AR NW, which is propagated to this AddRec.
// Negative step causes unsigned wrap, but it still can't self-wrap.
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), SCEV::FlagNW);
// Return the expression with the addrec on the outside.
Start = getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this,
Depth + 1);
Step = getSignExtendExpr(Step, Ty, Depth + 1);
return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
}
}
}
// Normally, in the cases we can prove no-overflow via a
// backedge guarding condition, we can also compute a backedge
// taken count for the loop. The exceptions are assumptions and
// guards present in the loop -- SCEV is not great at exploiting
// these to compute max backedge taken counts, but can still use
// these to prove lack of overflow. Use this fact to avoid
// doing extra work that may not pay off.
if (!isa<SCEVCouldNotCompute>(MaxBECount) || HasGuards ||
!AC.assumptions().empty()) {
auto NewFlags = proveNoUnsignedWrapViaInduction(AR);
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), NewFlags);
if (AR->hasNoUnsignedWrap()) {
// Same as nuw case above - duplicated here to avoid a compile time
// issue. It's not clear that the order of checks does matter, but
// it's one of two issue possible causes for a change which was
// reverted. Be conservative for the moment.
Start =
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this, Depth + 1);
Step = getZeroExtendExpr(Step, Ty, Depth + 1);
return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
}
// For a negative step, we can extend the operands iff doing so only
// traverses values in the range zext([0,UINT_MAX]).
if (isKnownNegative(Step)) {
const SCEV *N = getConstant(APInt::getMaxValue(BitWidth) -
getSignedRangeMin(Step));
if (isLoopBackedgeGuardedByCond(L, ICmpInst::ICMP_UGT, AR, N) ||
isKnownOnEveryIteration(ICmpInst::ICMP_UGT, AR, N)) {
// Cache knowledge of AR NW, which is propagated to this
// AddRec. Negative step causes unsigned wrap, but it
// still can't self-wrap.
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), SCEV::FlagNW);
// Return the expression with the addrec on the outside.
Start = getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this,
Depth + 1);
Step = getSignExtendExpr(Step, Ty, Depth + 1);
return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
}
}
}
// zext({C,+,Step}) --> (zext(D) + zext({C-D,+,Step}))<nuw><nsw>
// if D + (C - D + Step * n) could be proven to not unsigned wrap
// where D maximizes the number of trailing zeros of (C - D + Step * n)
if (const auto *SC = dyn_cast<SCEVConstant>(Start)) {
const APInt &C = SC->getAPInt();
const APInt &D = extractConstantWithoutWrapping(*this, C, Step);
if (D != 0) {
const SCEV *SZExtD = getZeroExtendExpr(getConstant(D), Ty, Depth);
const SCEV *SResidual =
getAddRecExpr(getConstant(C - D), Step, L, AR->getNoWrapFlags());
const SCEV *SZExtR = getZeroExtendExpr(SResidual, Ty, Depth + 1);
return getAddExpr(SZExtD, SZExtR,
(SCEV::NoWrapFlags)(SCEV::FlagNSW | SCEV::FlagNUW),
Depth + 1);
}
}
if (proveNoWrapByVaryingStart<SCEVZeroExtendExpr>(Start, Step, L)) {
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), SCEV::FlagNUW);
Start =
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this, Depth + 1);
Step = getZeroExtendExpr(Step, Ty, Depth + 1);
return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
}
}
// zext(A % B) --> zext(A) % zext(B)
{
const SCEV *LHS;
const SCEV *RHS;
if (matchURem(Op, LHS, RHS))
return getURemExpr(getZeroExtendExpr(LHS, Ty, Depth + 1),
getZeroExtendExpr(RHS, Ty, Depth + 1));
}
// zext(A / B) --> zext(A) / zext(B).
if (auto *Div = dyn_cast<SCEVUDivExpr>(Op))
return getUDivExpr(getZeroExtendExpr(Div->getLHS(), Ty, Depth + 1),
getZeroExtendExpr(Div->getRHS(), Ty, Depth + 1));
if (auto *SA = dyn_cast<SCEVAddExpr>(Op)) {
// zext((A + B + ...)<nuw>) --> (zext(A) + zext(B) + ...)<nuw>
if (SA->hasNoUnsignedWrap()) {
// If the addition does not unsign overflow then we can, by definition,
// commute the zero extension with the addition operation.
SmallVector<const SCEV *, 4> Ops;
for (const auto *Op : SA->operands())
Ops.push_back(getZeroExtendExpr(Op, Ty, Depth + 1));
return getAddExpr(Ops, SCEV::FlagNUW, Depth + 1);
}
// zext(C + x + y + ...) --> (zext(D) + zext((C - D) + x + y + ...))
// if D + (C - D + x + y + ...) could be proven to not unsigned wrap
// where D maximizes the number of trailing zeros of (C - D + x + y + ...)
//
// Often address arithmetics contain expressions like
// (zext (add (shl X, C1), C2)), for instance, (zext (5 + (4 * X))).
// This transformation is useful while proving that such expressions are
// equal or differ by a small constant amount, see LoadStoreVectorizer pass.
if (const auto *SC = dyn_cast<SCEVConstant>(SA->getOperand(0))) {
const APInt &D = extractConstantWithoutWrapping(*this, SC, SA);
if (D != 0) {
const SCEV *SZExtD = getZeroExtendExpr(getConstant(D), Ty, Depth);
const SCEV *SResidual =
getAddExpr(getConstant(-D), SA, SCEV::FlagAnyWrap, Depth);
const SCEV *SZExtR = getZeroExtendExpr(SResidual, Ty, Depth + 1);
return getAddExpr(SZExtD, SZExtR,
(SCEV::NoWrapFlags)(SCEV::FlagNSW | SCEV::FlagNUW),
Depth + 1);
}
}
}
if (auto *SM = dyn_cast<SCEVMulExpr>(Op)) {
// zext((A * B * ...)<nuw>) --> (zext(A) * zext(B) * ...)<nuw>
if (SM->hasNoUnsignedWrap()) {
// If the multiply does not unsign overflow then we can, by definition,
// commute the zero extension with the multiply operation.
SmallVector<const SCEV *, 4> Ops;
for (const auto *Op : SM->operands())
Ops.push_back(getZeroExtendExpr(Op, Ty, Depth + 1));
return getMulExpr(Ops, SCEV::FlagNUW, Depth + 1);
}
// zext(2^K * (trunc X to iN)) to iM ->
// 2^K * (zext(trunc X to i{N-K}) to iM)<nuw>
//
// Proof:
//
// zext(2^K * (trunc X to iN)) to iM
// = zext((trunc X to iN) << K) to iM
// = zext((trunc X to i{N-K}) << K)<nuw> to iM
// (because shl removes the top K bits)
// = zext((2^K * (trunc X to i{N-K}))<nuw>) to iM
// = (2^K * (zext(trunc X to i{N-K}) to iM))<nuw>.
//
if (SM->getNumOperands() == 2)
if (auto *MulLHS = dyn_cast<SCEVConstant>(SM->getOperand(0)))
if (MulLHS->getAPInt().isPowerOf2())
if (auto *TruncRHS = dyn_cast<SCEVTruncateExpr>(SM->getOperand(1))) {
int NewTruncBits = getTypeSizeInBits(TruncRHS->getType()) -
MulLHS->getAPInt().logBase2();
Type *NewTruncTy = IntegerType::get(getContext(), NewTruncBits);
return getMulExpr(
getZeroExtendExpr(MulLHS, Ty),
getZeroExtendExpr(
getTruncateExpr(TruncRHS->getOperand(), NewTruncTy), Ty),
SCEV::FlagNUW, Depth + 1);
}
}
// The cast wasn't folded; create an explicit cast node.
// Recompute the insert position, as it may have been invalidated.
if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S;
SCEV *S = new (SCEVAllocator) SCEVZeroExtendExpr(ID.Intern(SCEVAllocator),
Op, Ty);
UniqueSCEVs.InsertNode(S, IP);
registerUser(S, Op);
return S;
}
const SCEV *
ScalarEvolution::getSignExtendExpr(const SCEV *Op, Type *Ty, unsigned Depth) {
assert(getTypeSizeInBits(Op->getType()) < getTypeSizeInBits(Ty) &&
"This is not an extending conversion!");
assert(isSCEVable(Ty) &&
"This is not a conversion to a SCEVable type!");
assert(!Op->getType()->isPointerTy() && "Can't extend pointer!");
Ty = getEffectiveSCEVType(Ty);
// Fold if the operand is constant.
if (const SCEVConstant *SC = dyn_cast<SCEVConstant>(Op))
return getConstant(
cast<ConstantInt>(ConstantExpr::getSExt(SC->getValue(), Ty)));
// sext(sext(x)) --> sext(x)
if (const SCEVSignExtendExpr *SS = dyn_cast<SCEVSignExtendExpr>(Op))
return getSignExtendExpr(SS->getOperand(), Ty, Depth + 1);
// sext(zext(x)) --> zext(x)
if (const SCEVZeroExtendExpr *SZ = dyn_cast<SCEVZeroExtendExpr>(Op))
return getZeroExtendExpr(SZ->getOperand(), Ty, Depth + 1);
// Before doing any expensive analysis, check to see if we've already
// computed a SCEV for this Op and Ty.
FoldingSetNodeID ID;
ID.AddInteger(scSignExtend);
ID.AddPointer(Op);
ID.AddPointer(Ty);
void *IP = nullptr;
if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S;
// Limit recursion depth.
if (Depth > MaxCastDepth) {
SCEV *S = new (SCEVAllocator) SCEVSignExtendExpr(ID.Intern(SCEVAllocator),
Op, Ty);
UniqueSCEVs.InsertNode(S, IP);
registerUser(S, Op);
return S;
}
// sext(trunc(x)) --> sext(x) or x or trunc(x)
if (const SCEVTruncateExpr *ST = dyn_cast<SCEVTruncateExpr>(Op)) {
// It's possible the bits taken off by the truncate were all sign bits. If
// so, we should be able to simplify this further.
const SCEV *X = ST->getOperand();
ConstantRange CR = getSignedRange(X);
unsigned TruncBits = getTypeSizeInBits(ST->getType());
unsigned NewBits = getTypeSizeInBits(Ty);
if (CR.truncate(TruncBits).signExtend(NewBits).contains(
CR.sextOrTrunc(NewBits)))
return getTruncateOrSignExtend(X, Ty, Depth);
}
if (auto *SA = dyn_cast<SCEVAddExpr>(Op)) {
// sext((A + B + ...)<nsw>) --> (sext(A) + sext(B) + ...)<nsw>
if (SA->hasNoSignedWrap()) {
// If the addition does not sign overflow then we can, by definition,
// commute the sign extension with the addition operation.
SmallVector<const SCEV *, 4> Ops;
for (const auto *Op : SA->operands())
Ops.push_back(getSignExtendExpr(Op, Ty, Depth + 1));
return getAddExpr(Ops, SCEV::FlagNSW, Depth + 1);
}
// sext(C + x + y + ...) --> (sext(D) + sext((C - D) + x + y + ...))
// if D + (C - D + x + y + ...) could be proven to not signed wrap
// where D maximizes the number of trailing zeros of (C - D + x + y + ...)
//
// For instance, this will bring two seemingly different expressions:
// 1 + sext(5 + 20 * %x + 24 * %y) and
// sext(6 + 20 * %x + 24 * %y)
// to the same form:
// 2 + sext(4 + 20 * %x + 24 * %y)
if (const auto *SC = dyn_cast<SCEVConstant>(SA->getOperand(0))) {
const APInt &D = extractConstantWithoutWrapping(*this, SC, SA);
if (D != 0) {
const SCEV *SSExtD = getSignExtendExpr(getConstant(D), Ty, Depth);
const SCEV *SResidual =
getAddExpr(getConstant(-D), SA, SCEV::FlagAnyWrap, Depth);
const SCEV *SSExtR = getSignExtendExpr(SResidual, Ty, Depth + 1);
return getAddExpr(SSExtD, SSExtR,
(SCEV::NoWrapFlags)(SCEV::FlagNSW | SCEV::FlagNUW),
Depth + 1);
}
}
}
// If the input value is a chrec scev, and we can prove that the value
// did not overflow the old, smaller, value, we can sign extend all of the
// operands (often constants). This allows analysis of something like
// this: for (signed char X = 0; X < 100; ++X) { int Y = X; }
if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(Op))
if (AR->isAffine()) {
const SCEV *Start = AR->getStart();
const SCEV *Step = AR->getStepRecurrence(*this);
unsigned BitWidth = getTypeSizeInBits(AR->getType());
const Loop *L = AR->getLoop();
if (!AR->hasNoSignedWrap()) {
auto NewFlags = proveNoWrapViaConstantRanges(AR);
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), NewFlags);
}
// If we have special knowledge that this addrec won't overflow,
// we don't need to do any further analysis.
if (AR->hasNoSignedWrap()) {
Start =
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Depth + 1);
Step = getSignExtendExpr(Step, Ty, Depth + 1);
return getAddRecExpr(Start, Step, L, SCEV::FlagNSW);
}
// Check whether the backedge-taken count is SCEVCouldNotCompute.
// Note that this serves two purposes: It filters out loops that are
// simply not analyzable, and it covers the case where this code is
// being called from within backedge-taken count analysis, such that
// attempting to ask for the backedge-taken count would likely result
// in infinite recursion. In the later case, the analysis code will
// cope with a conservative value, and it will take care to purge
// that value once it has finished.
const SCEV *MaxBECount = getConstantMaxBackedgeTakenCount(L);
if (!isa<SCEVCouldNotCompute>(MaxBECount)) {
// Manually compute the final value for AR, checking for
// overflow.
// Check whether the backedge-taken count can be losslessly casted to
// the addrec's type. The count is always unsigned.
const SCEV *CastedMaxBECount =
getTruncateOrZeroExtend(MaxBECount, Start->getType(), Depth);
const SCEV *RecastedMaxBECount = getTruncateOrZeroExtend(
CastedMaxBECount, MaxBECount->getType(), Depth);
if (MaxBECount == RecastedMaxBECount) {
Type *WideTy = IntegerType::get(getContext(), BitWidth * 2);
// Check whether Start+Step*MaxBECount has no signed overflow.
const SCEV *SMul = getMulExpr(CastedMaxBECount, Step,
SCEV::FlagAnyWrap, Depth + 1);
const SCEV *SAdd = getSignExtendExpr(getAddExpr(Start, SMul,
SCEV::FlagAnyWrap,
Depth + 1),
WideTy, Depth + 1);
const SCEV *WideStart = getSignExtendExpr(Start, WideTy, Depth + 1);
const SCEV *WideMaxBECount =
getZeroExtendExpr(CastedMaxBECount, WideTy, Depth + 1);
const SCEV *OperandExtendedAdd =
getAddExpr(WideStart,
getMulExpr(WideMaxBECount,
getSignExtendExpr(Step, WideTy, Depth + 1),
SCEV::FlagAnyWrap, Depth + 1),
SCEV::FlagAnyWrap, Depth + 1);
if (SAdd == OperandExtendedAdd) {
// Cache knowledge of AR NSW, which is propagated to this AddRec.
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), SCEV::FlagNSW);
// Return the expression with the addrec on the outside.
Start = getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this,
Depth + 1);
Step = getSignExtendExpr(Step, Ty, Depth + 1);
return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
}
// Similar to above, only this time treat the step value as unsigned.
// This covers loops that count up with an unsigned step.
OperandExtendedAdd =
getAddExpr(WideStart,
getMulExpr(WideMaxBECount,
getZeroExtendExpr(Step, WideTy, Depth + 1),
SCEV::FlagAnyWrap, Depth + 1),
SCEV::FlagAnyWrap, Depth + 1);
if (SAdd == OperandExtendedAdd) {
// If AR wraps around then
//
// abs(Step) * MaxBECount > unsigned-max(AR->getType())
// => SAdd != OperandExtendedAdd
//
// Thus (AR is not NW => SAdd != OperandExtendedAdd) <=>
// (SAdd == OperandExtendedAdd => AR is NW)
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), SCEV::FlagNW);
// Return the expression with the addrec on the outside.
Start = getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this,
Depth + 1);
Step = getZeroExtendExpr(Step, Ty, Depth + 1);
return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
}
}
}
auto NewFlags = proveNoSignedWrapViaInduction(AR);
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), NewFlags);
if (AR->hasNoSignedWrap()) {
// Same as nsw case above - duplicated here to avoid a compile time
// issue. It's not clear that the order of checks does matter, but
// it's one of two issue possible causes for a change which was
// reverted. Be conservative for the moment.
Start =
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Depth + 1);
Step = getSignExtendExpr(Step, Ty, Depth + 1);
return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
}
// sext({C,+,Step}) --> (sext(D) + sext({C-D,+,Step}))<nuw><nsw>
// if D + (C - D + Step * n) could be proven to not signed wrap
// where D maximizes the number of trailing zeros of (C - D + Step * n)
if (const auto *SC = dyn_cast<SCEVConstant>(Start)) {
const APInt &C = SC->getAPInt();
const APInt &D = extractConstantWithoutWrapping(*this, C, Step);
if (D != 0) {
const SCEV *SSExtD = getSignExtendExpr(getConstant(D), Ty, Depth);
const SCEV *SResidual =
getAddRecExpr(getConstant(C - D), Step, L, AR->getNoWrapFlags());
const SCEV *SSExtR = getSignExtendExpr(SResidual, Ty, Depth + 1);
return getAddExpr(SSExtD, SSExtR,
(SCEV::NoWrapFlags)(SCEV::FlagNSW | SCEV::FlagNUW),
Depth + 1);
}
}
if (proveNoWrapByVaryingStart<SCEVSignExtendExpr>(Start, Step, L)) {
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), SCEV::FlagNSW);
Start =
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Depth + 1);
Step = getSignExtendExpr(Step, Ty, Depth + 1);
return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
}
}
// If the input value is provably positive and we could not simplify
// away the sext build a zext instead.
if (isKnownNonNegative(Op))
return getZeroExtendExpr(Op, Ty, Depth + 1);
// The cast wasn't folded; create an explicit cast node.
// Recompute the insert position, as it may have been invalidated.
if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S;
SCEV *S = new (SCEVAllocator) SCEVSignExtendExpr(ID.Intern(SCEVAllocator),
Op, Ty);
UniqueSCEVs.InsertNode(S, IP);
registerUser(S, { Op });
return S;
}
const SCEV *ScalarEvolution::getCastExpr(SCEVTypes Kind, const SCEV *Op,
Type *Ty) {
switch (Kind) {
case scTruncate:
return getTruncateExpr(Op, Ty);
case scZeroExtend:
return getZeroExtendExpr(Op, Ty);
case scSignExtend:
return getSignExtendExpr(Op, Ty);
case scPtrToInt:
return getPtrToIntExpr(Op, Ty);
default:
llvm_unreachable("Not a SCEV cast expression!");
}
}
/// getAnyExtendExpr - Return a SCEV for the given operand extended with
/// unspecified bits out to the given type.
const SCEV *ScalarEvolution::getAnyExtendExpr(const SCEV *Op,
Type *Ty) {
assert(getTypeSizeInBits(Op->getType()) < getTypeSizeInBits(Ty) &&
"This is not an extending conversion!");
assert(isSCEVable(Ty) &&
"This is not a conversion to a SCEVable type!");
Ty = getEffectiveSCEVType(Ty);
// Sign-extend negative constants.
if (const SCEVConstant *SC = dyn_cast<SCEVConstant>(Op))
if (SC->getAPInt().isNegative())
return getSignExtendExpr(Op, Ty);
// Peel off a truncate cast.
if (const SCEVTruncateExpr *T = dyn_cast<SCEVTruncateExpr>(Op)) {
const SCEV *NewOp = T->getOperand();
if (getTypeSizeInBits(NewOp->getType()) < getTypeSizeInBits(Ty))
return getAnyExtendExpr(NewOp, Ty);
return getTruncateOrNoop(NewOp, Ty);
}
// Next try a zext cast. If the cast is folded, use it.
const SCEV *ZExt = getZeroExtendExpr(Op, Ty);
if (!isa<SCEVZeroExtendExpr>(ZExt))
return ZExt;
// Next try a sext cast. If the cast is folded, use it.
const SCEV *SExt = getSignExtendExpr(Op, Ty);
if (!isa<SCEVSignExtendExpr>(SExt))
return SExt;
// Force the cast to be folded into the operands of an addrec.
if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(Op)) {
SmallVector<const SCEV *, 4> Ops;
for (const SCEV *Op : AR->operands())
Ops.push_back(getAnyExtendExpr(Op, Ty));
return getAddRecExpr(Ops, AR->getLoop(), SCEV::FlagNW);
}
// If the expression is obviously signed, use the sext cast value.
if (isa<SCEVSMaxExpr>(Op))
return SExt;
// Absent any other information, use the zext cast value.
return ZExt;
}
/// Process the given Ops list, which is a list of operands to be added under
/// the given scale, update the given map. This is a helper function for
/// getAddRecExpr. As an example of what it does, given a sequence of operands
/// that would form an add expression like this:
///
/// m + n + 13 + (A * (o + p + (B * (q + m + 29)))) + r + (-1 * r)
///
/// where A and B are constants, update the map with these values:
///
/// (m, 1+A*B), (n, 1), (o, A), (p, A), (q, A*B), (r, 0)
///
/// and add 13 + A*B*29 to AccumulatedConstant.
/// This will allow getAddRecExpr to produce this:
///
/// 13+A*B*29 + n + (m * (1+A*B)) + ((o + p) * A) + (q * A*B)
///
/// This form often exposes folding opportunities that are hidden in
/// the original operand list.
///
/// Return true iff it appears that any interesting folding opportunities
/// may be exposed. This helps getAddRecExpr short-circuit extra work in
/// the common case where no interesting opportunities are present, and
/// is also used as a check to avoid infinite recursion.
static bool
CollectAddOperandsWithScales(DenseMap<const SCEV *, APInt> &M,
SmallVectorImpl<const SCEV *> &NewOps,
APInt &AccumulatedConstant,
const SCEV *const *Ops, size_t NumOperands,
const APInt &Scale,
ScalarEvolution &SE) {
bool Interesting = false;
// Iterate over the add operands. They are sorted, with constants first.
unsigned i = 0;
while (const SCEVConstant *C = dyn_cast<SCEVConstant>(Ops[i])) {
++i;
// Pull a buried constant out to the outside.
if (Scale != 1 || AccumulatedConstant != 0 || C->getValue()->isZero())
Interesting = true;
AccumulatedConstant += Scale * C->getAPInt();
}
// Next comes everything else. We're especially interested in multiplies
// here, but they're in the middle, so just visit the rest with one loop.
for (; i != NumOperands; ++i) {
const SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(Ops[i]);
if (Mul && isa<SCEVConstant>(Mul->getOperand(0))) {
APInt NewScale =
Scale * cast<SCEVConstant>(Mul->getOperand(0))->getAPInt();
if (Mul->getNumOperands() == 2 && isa<SCEVAddExpr>(Mul->getOperand(1))) {
// A multiplication of a constant with another add; recurse.
const SCEVAddExpr *Add = cast<SCEVAddExpr>(Mul->getOperand(1));
Interesting |=
CollectAddOperandsWithScales(M, NewOps, AccumulatedConstant,
Add->op_begin(), Add->getNumOperands(),
NewScale, SE);
} else {
// A multiplication of a constant with some other value. Update
// the map.
SmallVector<const SCEV *, 4> MulOps(drop_begin(Mul->operands()));
const SCEV *Key = SE.getMulExpr(MulOps);
auto Pair = M.insert({Key, NewScale});
if (Pair.second) {
NewOps.push_back(Pair.first->first);
} else {
Pair.first->second += NewScale;
// The map already had an entry for this value, which may indicate
// a folding opportunity.
Interesting = true;
}
}
} else {
// An ordinary operand. Update the map.
std::pair<DenseMap<const SCEV *, APInt>::iterator, bool> Pair =
M.insert({Ops[i], Scale});
if (Pair.second) {
NewOps.push_back(Pair.first->first);
} else {
Pair.first->second += Scale;
// The map already had an entry for this value, which may indicate
// a folding opportunity.
Interesting = true;
}
}
}
return Interesting;
}
bool ScalarEvolution::willNotOverflow(Instruction::BinaryOps BinOp, bool Signed,
const SCEV *LHS, const SCEV *RHS) {
const SCEV *(ScalarEvolution::*Operation)(const SCEV *, const SCEV *,
SCEV::NoWrapFlags, unsigned);
switch (BinOp) {
default:
llvm_unreachable("Unsupported binary op");
case Instruction::Add:
Operation = &ScalarEvolution::getAddExpr;
break;
case Instruction::Sub:
Operation = &ScalarEvolution::getMinusSCEV;
break;
case Instruction::Mul:
Operation = &ScalarEvolution::getMulExpr;
break;
}
const SCEV *(ScalarEvolution::*Extension)(const SCEV *, Type *, unsigned) =
Signed ? &ScalarEvolution::getSignExtendExpr
: &ScalarEvolution::getZeroExtendExpr;
// Check ext(LHS op RHS) == ext(LHS) op ext(RHS)
auto *NarrowTy = cast<IntegerType>(LHS->getType());
auto *WideTy =
IntegerType::get(NarrowTy->getContext(), NarrowTy->getBitWidth() * 2);
const SCEV *A = (this->*Extension)(
(this->*Operation)(LHS, RHS, SCEV::FlagAnyWrap, 0), WideTy, 0);
const SCEV *LHSB = (this->*Extension)(LHS, WideTy, 0);
const SCEV *RHSB = (this->*Extension)(RHS, WideTy, 0);
const SCEV *B = (this->*Operation)(LHSB, RHSB, SCEV::FlagAnyWrap, 0);
return A == B;
}
Optional<SCEV::NoWrapFlags>
ScalarEvolution::getStrengthenedNoWrapFlagsFromBinOp(
const OverflowingBinaryOperator *OBO) {
// It cannot be done any better.
if (OBO->hasNoUnsignedWrap() && OBO->hasNoSignedWrap())
return None;
SCEV::NoWrapFlags Flags = SCEV::NoWrapFlags::FlagAnyWrap;
if (OBO->hasNoUnsignedWrap())
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW);
if (OBO->hasNoSignedWrap())
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNSW);
bool Deduced = false;
if (OBO->getOpcode() != Instruction::Add &&
OBO->getOpcode() != Instruction::Sub &&
OBO->getOpcode() != Instruction::Mul)
return None;
const SCEV *LHS = getSCEV(OBO->getOperand(0));
const SCEV *RHS = getSCEV(OBO->getOperand(1));
if (!OBO->hasNoUnsignedWrap() &&
willNotOverflow((Instruction::BinaryOps)OBO->getOpcode(),
/* Signed */ false, LHS, RHS)) {
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW);
Deduced = true;
}
if (!OBO->hasNoSignedWrap() &&
willNotOverflow((Instruction::BinaryOps)OBO->getOpcode(),
/* Signed */ true, LHS, RHS)) {
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNSW);
Deduced = true;
}
if (Deduced)
return Flags;
return None;
}
// We're trying to construct a SCEV of type `Type' with `Ops' as operands and
// `OldFlags' as can't-wrap behavior. Infer a more aggressive set of
// can't-overflow flags for the operation if possible.
static SCEV::NoWrapFlags
StrengthenNoWrapFlags(ScalarEvolution *SE, SCEVTypes Type,
const ArrayRef<const SCEV *> Ops,
SCEV::NoWrapFlags Flags) {
using namespace std::placeholders;
using OBO = OverflowingBinaryOperator;
bool CanAnalyze =
Type == scAddExpr || Type == scAddRecExpr || Type == scMulExpr;
(void)CanAnalyze;
assert(CanAnalyze && "don't call from other places!");
int SignOrUnsignMask = SCEV::FlagNUW | SCEV::FlagNSW;
SCEV::NoWrapFlags SignOrUnsignWrap =
ScalarEvolution::maskFlags(Flags, SignOrUnsignMask);
// If FlagNSW is true and all the operands are non-negative, infer FlagNUW.
auto IsKnownNonNegative = [&](const SCEV *S) {
return SE->isKnownNonNegative(S);
};
if (SignOrUnsignWrap == SCEV::FlagNSW && all_of(Ops, IsKnownNonNegative))
Flags =
ScalarEvolution::setFlags(Flags, (SCEV::NoWrapFlags)SignOrUnsignMask);
SignOrUnsignWrap = ScalarEvolution::maskFlags(Flags, SignOrUnsignMask);
if (SignOrUnsignWrap != SignOrUnsignMask &&
(Type == scAddExpr || Type == scMulExpr) && Ops.size() == 2 &&
isa<SCEVConstant>(Ops[0])) {
auto Opcode = [&] {
switch (Type) {
case scAddExpr:
return Instruction::Add;
case scMulExpr:
return Instruction::Mul;
default:
llvm_unreachable("Unexpected SCEV op.");
}
}();
const APInt &C = cast<SCEVConstant>(Ops[0])->getAPInt();
// (A <opcode> C) --> (A <opcode> C)<nsw> if the op doesn't sign overflow.
if (!(SignOrUnsignWrap & SCEV::FlagNSW)) {
auto NSWRegion = ConstantRange::makeGuaranteedNoWrapRegion(
Opcode, C, OBO::NoSignedWrap);
if (NSWRegion.contains(SE->getSignedRange(Ops[1])))
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNSW);
}
// (A <opcode> C) --> (A <opcode> C)<nuw> if the op doesn't unsign overflow.
if (!(SignOrUnsignWrap & SCEV::FlagNUW)) {
auto NUWRegion = ConstantRange::makeGuaranteedNoWrapRegion(
Opcode, C, OBO::NoUnsignedWrap);
if (NUWRegion.contains(SE->getUnsignedRange(Ops[1])))
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW);
}
}
// <0,+,nonnegative><nw> is also nuw
// TODO: Add corresponding nsw case
if (Type == scAddRecExpr && ScalarEvolution::hasFlags(Flags, SCEV::FlagNW) &&
!ScalarEvolution::hasFlags(Flags, SCEV::FlagNUW) && Ops.size() == 2 &&
Ops[0]->isZero() && IsKnownNonNegative(Ops[1]))
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW);
// both (udiv X, Y) * Y and Y * (udiv X, Y) are always NUW
if (Type == scMulExpr && !ScalarEvolution::hasFlags(Flags, SCEV::FlagNUW) &&
Ops.size() == 2) {
if (auto *UDiv = dyn_cast<SCEVUDivExpr>(Ops[0]))
if (UDiv->getOperand(1) == Ops[1])
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW);
if (auto *UDiv = dyn_cast<SCEVUDivExpr>(Ops[1]))
if (UDiv->getOperand(1) == Ops[0])
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW);
}
return Flags;
}
bool ScalarEvolution::isAvailableAtLoopEntry(const SCEV *S, const Loop *L) {
return isLoopInvariant(S, L) && properlyDominates(S, L->getHeader());
}
/// Get a canonical add expression, or something simpler if possible.
const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl<const SCEV *> &Ops,
SCEV::NoWrapFlags OrigFlags,
unsigned Depth) {
assert(!(OrigFlags & ~(SCEV::FlagNUW | SCEV::FlagNSW)) &&
"only nuw or nsw allowed");
assert(!Ops.empty() && "Cannot get empty add!");
if (Ops.size() == 1) return Ops[0];
#ifndef NDEBUG
Type *ETy = getEffectiveSCEVType(Ops[0]->getType());
for (unsigned i = 1, e = Ops.size(); i != e; ++i)
assert(getEffectiveSCEVType(Ops[i]->getType()) == ETy &&
"SCEVAddExpr operand types don't match!");
unsigned NumPtrs = count_if(
Ops, [](const SCEV *Op) { return Op->getType()->isPointerTy(); });
assert(NumPtrs <= 1 && "add has at most one pointer operand");
#endif
// Sort by complexity, this groups all similar expression types together.
GroupByComplexity(Ops, &LI, DT);
// If there are any constants, fold them together.
unsigned Idx = 0;
if (const SCEVConstant *LHSC = dyn_cast<SCEVConstant>(Ops[0])) {
++Idx;
assert(Idx < Ops.size());
while (const SCEVConstant *RHSC = dyn_cast<SCEVConstant>(Ops[Idx])) {
// We found two constants, fold them together!
Ops[0] = getConstant(LHSC->getAPInt() + RHSC->getAPInt());
if (Ops.size() == 2) return Ops[0];
Ops.erase(Ops.begin()+1); // Erase the folded element
LHSC = cast<SCEVConstant>(Ops[0]);
}
// If we are left with a constant zero being added, strip it off.
if (LHSC->getValue()->isZero()) {
Ops.erase(Ops.begin());
--Idx;
}
if (Ops.size() == 1) return Ops[0];
}
// Delay expensive flag strengthening until necessary.
auto ComputeFlags = [this, OrigFlags](const ArrayRef<const SCEV *> Ops) {
return StrengthenNoWrapFlags(this, scAddExpr, Ops, OrigFlags);
};
// Limit recursion calls depth.
if (Depth > MaxArithDepth || hasHugeExpression(Ops))
return getOrCreateAddExpr(Ops, ComputeFlags(Ops));
if (SCEV *S = findExistingSCEVInCache(scAddExpr, Ops)) {
// Don't strengthen flags if we have no new information.
SCEVAddExpr *Add = static_cast<SCEVAddExpr *>(S);
if (Add->getNoWrapFlags(OrigFlags) != OrigFlags)
Add->setNoWrapFlags(ComputeFlags(Ops));
return S;
}
// Okay, check to see if the same value occurs in the operand list more than
// once. If so, merge them together into an multiply expression. Since we
// sorted the list, these values are required to be adjacent.
Type *Ty = Ops[0]->getType();
bool FoundMatch = false;
for (unsigned i = 0, e = Ops.size(); i != e-1; ++i)
if (Ops[i] == Ops[i+1]) { // X + Y + Y --> X + Y*2
// Scan ahead to count how many equal operands there are.
unsigned Count = 2;
while (i+Count != e && Ops[i+Count] == Ops[i])
++Count;
// Merge the values into a multiply.
const SCEV *Scale = getConstant(Ty, Count);
const SCEV *Mul = getMulExpr(Scale, Ops[i], SCEV::FlagAnyWrap, Depth + 1);
if (Ops.size() == Count)
return Mul;
Ops[i] = Mul;
Ops.erase(Ops.begin()+i+1, Ops.begin()+i+Count);
--i; e -= Count - 1;
FoundMatch = true;
}
if (FoundMatch)
return getAddExpr(Ops, OrigFlags, Depth + 1);
// Check for truncates. If all the operands are truncated from the same
// type, see if factoring out the truncate would permit the result to be
// folded. eg., n*trunc(x) + m*trunc(y) --> trunc(trunc(m)*x + trunc(n)*y)
// if the contents of the resulting outer trunc fold to something simple.
auto FindTruncSrcType = [&]() -> Type * {
// We're ultimately looking to fold an addrec of truncs and muls of only
// constants and truncs, so if we find any other types of SCEV
// as operands of the addrec then we bail and return nullptr here.
// Otherwise, we return the type of the operand of a trunc that we find.
if (auto *T = dyn_cast<SCEVTruncateExpr>(Ops[Idx]))
return T->getOperand()->getType();
if (const auto *Mul = dyn_cast<SCEVMulExpr>(Ops[Idx])) {
const auto *LastOp = Mul->getOperand(Mul->getNumOperands() - 1);
if (const auto *T = dyn_cast<SCEVTruncateExpr>(LastOp))
return T->getOperand()->getType();
}
return nullptr;
};
if (auto *SrcType = FindTruncSrcType()) {
SmallVector<const SCEV *, 8> LargeOps;
bool Ok = true;
// Check all the operands to see if they can be represented in the
// source type of the truncate.
for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
if (const SCEVTruncateExpr *T = dyn_cast<SCEVTruncateExpr>(Ops[i])) {
if (T->getOperand()->getType() != SrcType) {
Ok = false;
break;
}
LargeOps.push_back(T->getOperand());
} else if (const SCEVConstant *C = dyn_cast<SCEVConstant>(Ops[i])) {
LargeOps.push_back(getAnyExtendExpr(C, SrcType));
} else if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(Ops[i])) {
SmallVector<const SCEV *, 8> LargeMulOps;
for (unsigned j = 0, f = M->getNumOperands(); j != f && Ok; ++j) {
if (const SCEVTruncateExpr *T =
dyn_cast<SCEVTruncateExpr>(M->getOperand(j))) {
if (T->getOperand()->getType() != SrcType) {
Ok = false;
break;
}
LargeMulOps.push_back(T->getOperand());
} else if (const auto *C = dyn_cast<SCEVConstant>(M->getOperand(j))) {
LargeMulOps.push_back(getAnyExtendExpr(C, SrcType));
} else {
Ok = false;
break;
}
}
if (Ok)
LargeOps.push_back(getMulExpr(LargeMulOps, SCEV::FlagAnyWrap, Depth + 1));
} else {
Ok = false;
break;
}
}
if (Ok) {
// Evaluate the expression in the larger type.
const SCEV *Fold = getAddExpr(LargeOps, SCEV::FlagAnyWrap, Depth + 1);
// If it folds to something simple, use it. Otherwise, don't.
if (isa<SCEVConstant>(Fold) || isa<SCEVUnknown>(Fold))
return getTruncateExpr(Fold, Ty);
}
}
if (Ops.size() == 2) {
// Check if we have an expression of the form ((X + C1) - C2), where C1 and
// C2 can be folded in a way that allows retaining wrapping flags of (X +
// C1).
const SCEV *A = Ops[0];
const SCEV *B = Ops[1];
auto *AddExpr = dyn_cast<SCEVAddExpr>(B);
auto *C = dyn_cast<SCEVConstant>(A);
if (AddExpr && C && isa<SCEVConstant>(AddExpr->getOperand(0))) {
auto C1 = cast<SCEVConstant>(AddExpr->getOperand(0))->getAPInt();
auto C2 = C->getAPInt();
SCEV::NoWrapFlags PreservedFlags = SCEV::FlagAnyWrap;
APInt ConstAdd = C1 + C2;
auto AddFlags = AddExpr->getNoWrapFlags();
// Adding a smaller constant is NUW if the original AddExpr was NUW.
if (ScalarEvolution::hasFlags(AddFlags, SCEV::FlagNUW) &&
ConstAdd.ule(C1)) {
PreservedFlags =
ScalarEvolution::setFlags(PreservedFlags, SCEV::FlagNUW);
}
// Adding a constant with the same sign and small magnitude is NSW, if the
// original AddExpr was NSW.
if (ScalarEvolution::hasFlags(AddFlags, SCEV::FlagNSW) &&
C1.isSignBitSet() == ConstAdd.isSignBitSet() &&
ConstAdd.abs().ule(C1.abs())) {
PreservedFlags =
ScalarEvolution::setFlags(PreservedFlags, SCEV::FlagNSW);
}
if (PreservedFlags != SCEV::FlagAnyWrap) {
SmallVector<const SCEV *, 4> NewOps(AddExpr->operands());
NewOps[0] = getConstant(ConstAdd);
return getAddExpr(NewOps, PreservedFlags);
}
}
}
// Canonicalize (-1 * urem X, Y) + X --> (Y * X/Y)
if (Ops.size() == 2) {
const SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(Ops[0]);
if (Mul && Mul->getNumOperands() == 2 &&
Mul->getOperand(0)->isAllOnesValue()) {
const SCEV *X;
const SCEV *Y;
if (matchURem(Mul->getOperand(1), X, Y) && X == Ops[1]) {
return getMulExpr(Y, getUDivExpr(X, Y));
}
}
}
// Skip past any other cast SCEVs.
while (Idx < Ops.size() && Ops[Idx]->getSCEVType() < scAddExpr)
++Idx;
// If there are add operands they would be next.
if (Idx < Ops.size()) {
bool DeletedAdd = false;
// If the original flags and all inlined SCEVAddExprs are NUW, use the
// common NUW flag for expression after inlining. Other flags cannot be
// preserved, because they may depend on the original order of operations.
SCEV::NoWrapFlags CommonFlags = maskFlags(OrigFlags, SCEV::FlagNUW);
while (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(Ops[Idx])) {
if (Ops.size() > AddOpsInlineThreshold ||
Add->getNumOperands() > AddOpsInlineThreshold)
break;
// If we have an add, expand the add operands onto the end of the operands
// list.
Ops.erase(Ops.begin()+Idx);
Ops.append(Add->op_begin(), Add->op_end());
DeletedAdd = true;
CommonFlags = maskFlags(CommonFlags, Add->getNoWrapFlags());
}
// If we deleted at least one add, we added operands to the end of the list,
// and they are not necessarily sorted. Recurse to resort and resimplify
// any operands we just acquired.
if (DeletedAdd)
return getAddExpr(Ops, CommonFlags, Depth + 1);
}
// Skip over the add expression until we get to a multiply.
while (Idx < Ops.size() && Ops[Idx]->getSCEVType() < scMulExpr)
++Idx;
// Check to see if there are any folding opportunities present with
// operands multiplied by constant values.
if (Idx < Ops.size() && isa<SCEVMulExpr>(Ops[Idx])) {
uint64_t BitWidth = getTypeSizeInBits(Ty);
DenseMap<const SCEV *, APInt> M;
SmallVector<const SCEV *, 8> NewOps;
APInt AccumulatedConstant(BitWidth, 0);
if (CollectAddOperandsWithScales(M, NewOps, AccumulatedConstant,
Ops.data(), Ops.size(),
APInt(BitWidth, 1), *this)) {
struct APIntCompare {
bool operator()(const APInt &LHS, const APInt &RHS) const {
return LHS.ult(RHS);
}
};
// Some interesting folding opportunity is present, so its worthwhile to
// re-generate the operands list. Group the operands by constant scale,
// to avoid multiplying by the same constant scale multiple times.
std::map<APInt, SmallVector<const SCEV *, 4>, APIntCompare> MulOpLists;
for (const SCEV *NewOp : NewOps)
MulOpLists[M.find(NewOp)->second].push_back(NewOp);
// Re-generate the operands list.
Ops.clear();
if (AccumulatedConstant != 0)
Ops.push_back(getConstant(AccumulatedConstant));
for (auto &MulOp : MulOpLists) {
if (MulOp.first == 1) {
Ops.push_back(getAddExpr(MulOp.second, SCEV::FlagAnyWrap, Depth + 1));
} else if (MulOp.first != 0) {
Ops.push_back(getMulExpr(
getConstant(MulOp.first),
getAddExpr(MulOp.second, SCEV::FlagAnyWrap, Depth + 1),
SCEV::FlagAnyWrap, Depth + 1));
}
}
if (Ops.empty())
return getZero(Ty);
if (Ops.size() == 1)
return Ops[0];
return getAddExpr(Ops, SCEV::FlagAnyWrap, Depth + 1);
}
}
// If we are adding something to a multiply expression, make sure the
// something is not already an operand of the multiply. If so, merge it into
// the multiply.
for (; Idx < Ops.size() && isa<SCEVMulExpr>(Ops[Idx]); ++Idx) {
const SCEVMulExpr *Mul = cast<SCEVMulExpr>(Ops[Idx]);
for (unsigned MulOp = 0, e = Mul->getNumOperands(); MulOp != e; ++MulOp) {
const SCEV *MulOpSCEV = Mul->getOperand(MulOp);
if (isa<SCEVConstant>(MulOpSCEV))
continue;
for (unsigned AddOp = 0, e = Ops.size(); AddOp != e; ++AddOp)
if (MulOpSCEV == Ops[AddOp]) {
// Fold W + X + (X * Y * Z) --> W + (X * ((Y*Z)+1))
const SCEV *InnerMul = Mul->getOperand(MulOp == 0);
if (Mul->getNumOperands() != 2) {
// If the multiply has more than two operands, we must get the
// Y*Z term.
SmallVector<const SCEV *, 4> MulOps(Mul->op_begin(),
Mul->op_begin()+MulOp);
MulOps.append(Mul->op_begin()+MulOp+1, Mul->op_end());
InnerMul = getMulExpr(MulOps, SCEV::FlagAnyWrap, Depth + 1);
}
SmallVector<const SCEV *, 2> TwoOps = {getOne(Ty), InnerMul};
const SCEV *AddOne = getAddExpr(TwoOps, SCEV::FlagAnyWrap, Depth + 1);
const SCEV *OuterMul = getMulExpr(AddOne, MulOpSCEV,
SCEV::FlagAnyWrap, Depth + 1);
if (Ops.size() == 2) return OuterMul;
if (AddOp < Idx) {
Ops.erase(Ops.begin()+AddOp);
Ops.erase(Ops.begin()+Idx-1);
} else {
Ops.erase(Ops.begin()+Idx);
Ops.erase(Ops.begin()+AddOp-1);
}
Ops.push_back(OuterMul);
return getAddExpr(Ops, SCEV::FlagAnyWrap, Depth + 1);
}
// Check this multiply against other multiplies being added together.
for (unsigned OtherMulIdx = Idx+1;
OtherMulIdx < Ops.size() && isa<SCEVMulExpr>(Ops[OtherMulIdx]);
++OtherMulIdx) {
const SCEVMulExpr *OtherMul = cast<SCEVMulExpr>(Ops[OtherMulIdx]);
// If MulOp occurs in OtherMul, we can fold the two multiplies
// together.
for (unsigned OMulOp = 0, e = OtherMul->getNumOperands();
OMulOp != e; ++OMulOp)
if (OtherMul->getOperand(OMulOp) == MulOpSCEV) {
// Fold X + (A*B*C) + (A*D*E) --> X + (A*(B*C+D*E))
const SCEV *InnerMul1 = Mul->getOperand(MulOp == 0);
if (Mul->getNumOperands() != 2) {
SmallVector<const SCEV *, 4> MulOps(Mul->op_begin(),
Mul->op_begin()+MulOp);
MulOps.append(Mul->op_begin()+MulOp+1, Mul->op_end());
InnerMul1 = getMulExpr(MulOps, SCEV::FlagAnyWrap, Depth + 1);
}
const SCEV *InnerMul2 = OtherMul->getOperand(OMulOp == 0);
if (OtherMul->getNumOperands() != 2) {
SmallVector<const SCEV *, 4> MulOps(OtherMul->op_begin(),
OtherMul->op_begin()+OMulOp);
MulOps.append(OtherMul->op_begin()+OMulOp+1, OtherMul->op_end());
InnerMul2 = getMulExpr(MulOps, SCEV::FlagAnyWrap, Depth + 1);
}
SmallVector<const SCEV *, 2> TwoOps = {InnerMul1, InnerMul2};
const SCEV *InnerMulSum =
getAddExpr(TwoOps, SCEV::FlagAnyWrap, Depth + 1);
const SCEV *OuterMul = getMulExpr(MulOpSCEV, InnerMulSum,
SCEV::FlagAnyWrap, Depth + 1);
if (Ops.size() == 2) return OuterMul;
Ops.erase(Ops.begin()+Idx);
Ops.erase(Ops.begin()+OtherMulIdx-1);
Ops.push_back(OuterMul);
return getAddExpr(Ops, SCEV::FlagAnyWrap, Depth + 1);
}
}
}
}
// If there are any add recurrences in the operands list, see if any other
// added values are loop invariant. If so, we can fold them into the
// recurrence.
while (Idx < Ops.size() && Ops[Idx]->getSCEVType() < scAddRecExpr)
++Idx;
// Scan over all recurrences, trying to fold loop invariants into them.
for (; Idx < Ops.size() && isa<SCEVAddRecExpr>(Ops[Idx]); ++Idx) {
// Scan all of the other operands to this add and add them to the vector if
// they are loop invariant w.r.t. the recurrence.
SmallVector<const SCEV *, 8> LIOps;
const SCEVAddRecExpr *AddRec = cast<SCEVAddRecExpr>(Ops[Idx]);
const Loop *AddRecLoop = AddRec->getLoop();
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
if (isAvailableAtLoopEntry(Ops[i], AddRecLoop)) {
LIOps.push_back(Ops[i]);
Ops.erase(Ops.begin()+i);
--i; --e;
}
// If we found some loop invariants, fold them into the recurrence.
if (!LIOps.empty()) {
// Compute nowrap flags for the addition of the loop-invariant ops and
// the addrec. Temporarily push it as an operand for that purpose. These
// flags are valid in the scope of the addrec only.
LIOps.push_back(AddRec);
SCEV::NoWrapFlags Flags = ComputeFlags(LIOps);
LIOps.pop_back();
// NLI + LI + {Start,+,Step} --> NLI + {LI+Start,+,Step}
LIOps.push_back(AddRec->getStart());
SmallVector<const SCEV *, 4> AddRecOps(AddRec->operands());
// It is not in general safe to propagate flags valid on an add within
// the addrec scope to one outside it. We must prove that the inner
// scope is guaranteed to execute if the outer one does to be able to
// safely propagate. We know the program is undefined if poison is
// produced on the inner scoped addrec. We also know that *for this use*
// the outer scoped add can't overflow (because of the flags we just
// computed for the inner scoped add) without the program being undefined.
// Proving that entry to the outer scope neccesitates entry to the inner
// scope, thus proves the program undefined if the flags would be violated
// in the outer scope.
SCEV::NoWrapFlags AddFlags = Flags;
if (AddFlags != SCEV::FlagAnyWrap) {
auto *DefI = getDefiningScopeBound(LIOps);
auto *ReachI = &*AddRecLoop->getHeader()->begin();
if (!isGuaranteedToTransferExecutionTo(DefI, ReachI))
AddFlags = SCEV::FlagAnyWrap;
}
AddRecOps[0] = getAddExpr(LIOps, AddFlags, Depth + 1);
// Build the new addrec. Propagate the NUW and NSW flags if both the
// outer add and the inner addrec are guaranteed to have no overflow.
// Always propagate NW.
Flags = AddRec->getNoWrapFlags(setFlags(Flags, SCEV::FlagNW));
const SCEV *NewRec = getAddRecExpr(AddRecOps, AddRecLoop, Flags);
// If all of the other operands were loop invariant, we are done.
if (Ops.size() == 1) return NewRec;
// Otherwise, add the folded AddRec by the non-invariant parts.
for (unsigned i = 0;; ++i)
if (Ops[i] == AddRec) {
Ops[i] = NewRec;
break;
}
return getAddExpr(Ops, SCEV::FlagAnyWrap, Depth + 1);
}
// Okay, if there weren't any loop invariants to be folded, check to see if
// there are multiple AddRec's with the same loop induction variable being
// added together. If so, we can fold them.
for (unsigned OtherIdx = Idx+1;
OtherIdx < Ops.size() && isa<SCEVAddRecExpr>(Ops[OtherIdx]);
++OtherIdx) {
// We expect the AddRecExpr's to be sorted in reverse dominance order,
// so that the 1st found AddRecExpr is dominated by all others.
assert(DT.dominates(
cast<SCEVAddRecExpr>(Ops[OtherIdx])->getLoop()->getHeader(),
AddRec->getLoop()->getHeader()) &&
"AddRecExprs are not sorted in reverse dominance order?");
if (AddRecLoop == cast<SCEVAddRecExpr>(Ops[OtherIdx])->getLoop()) {
// Other + {A,+,B}<L> + {C,+,D}<L> --> Other + {A+C,+,B+D}<L>
SmallVector<const SCEV *, 4> AddRecOps(AddRec->operands());
for (; OtherIdx != Ops.size() && isa<SCEVAddRecExpr>(Ops[OtherIdx]);
++OtherIdx) {
const auto *OtherAddRec = cast<SCEVAddRecExpr>(Ops[OtherIdx]);
if (OtherAddRec->getLoop() == AddRecLoop) {
for (unsigned i = 0, e = OtherAddRec->getNumOperands();
i != e; ++i) {
if (i >= AddRecOps.size()) {
AddRecOps.append(OtherAddRec->op_begin()+i,
OtherAddRec->op_end());
break;
}
SmallVector<const SCEV *, 2> TwoOps = {
AddRecOps[i], OtherAddRec->getOperand(i)};
AddRecOps[i] = getAddExpr(TwoOps, SCEV::FlagAnyWrap, Depth + 1);
}
Ops.erase(Ops.begin() + OtherIdx); --OtherIdx;
}
}
// Step size has changed, so we cannot guarantee no self-wraparound.
Ops[Idx] = getAddRecExpr(AddRecOps, AddRecLoop, SCEV::FlagAnyWrap);
return getAddExpr(Ops, SCEV::FlagAnyWrap, Depth + 1);
}
}
// Otherwise couldn't fold anything into this recurrence. Move onto the
// next one.
}
// Okay, it looks like we really DO need an add expr. Check to see if we
// already have one, otherwise create a new one.
return getOrCreateAddExpr(Ops, ComputeFlags(Ops));
}
const SCEV *
ScalarEvolution::getOrCreateAddExpr(ArrayRef<const SCEV *> Ops,
SCEV::NoWrapFlags Flags) {
FoldingSetNodeID ID;
ID.AddInteger(scAddExpr);
for (const SCEV *Op : Ops)
ID.AddPointer(Op);
void *IP = nullptr;
SCEVAddExpr *S =
static_cast<SCEVAddExpr *>(UniqueSCEVs.FindNodeOrInsertPos(ID, IP));
if (!S) {
const SCEV **O = SCEVAllocator.Allocate<const SCEV *>(Ops.size());
std::uninitialized_copy(Ops.begin(), Ops.end(), O);
S = new (SCEVAllocator)
SCEVAddExpr(ID.Intern(SCEVAllocator), O, Ops.size());
UniqueSCEVs.InsertNode(S, IP);
registerUser(S, Ops);
}
S->setNoWrapFlags(Flags);
return S;
}
const SCEV *
ScalarEvolution::getOrCreateAddRecExpr(ArrayRef<const SCEV *> Ops,
const Loop *L, SCEV::NoWrapFlags Flags) {
FoldingSetNodeID ID;
ID.AddInteger(scAddRecExpr);
for (const SCEV *Op : Ops)
ID.AddPointer(Op);
ID.AddPointer(L);
void *IP = nullptr;
SCEVAddRecExpr *S =
static_cast<SCEVAddRecExpr *>(UniqueSCEVs.FindNodeOrInsertPos(ID, IP));
if (!S) {
const SCEV **O = SCEVAllocator.Allocate<const SCEV *>(Ops.size());
std::uninitialized_copy(Ops.begin(), Ops.end(), O);
S = new (SCEVAllocator)
SCEVAddRecExpr(ID.Intern(SCEVAllocator), O, Ops.size(), L);
UniqueSCEVs.InsertNode(S, IP);
LoopUsers[L].push_back(S);
registerUser(S, Ops);
}
setNoWrapFlags(S, Flags);
return S;
}
const SCEV *
ScalarEvolution::getOrCreateMulExpr(ArrayRef<const SCEV *> Ops,
SCEV::NoWrapFlags Flags) {
FoldingSetNodeID ID;
ID.AddInteger(scMulExpr);
for (const SCEV *Op : Ops)
ID.AddPointer(Op);
void *IP = nullptr;
SCEVMulExpr *S =
static_cast<SCEVMulExpr *>(UniqueSCEVs.FindNodeOrInsertPos(ID, IP));
if (!S) {
const SCEV **O = SCEVAllocator.Allocate<const SCEV *>(Ops.size());
std::uninitialized_copy(Ops.begin(), Ops.end(), O);
S = new (SCEVAllocator) SCEVMulExpr(ID.Intern(SCEVAllocator),
O, Ops.size());
UniqueSCEVs.InsertNode(S, IP);
registerUser(S, Ops);
}
S->setNoWrapFlags(Flags);
return S;
}
static uint64_t umul_ov(uint64_t i, uint64_t j, bool &Overflow) {
uint64_t k = i*j;
if (j > 1 && k / j != i) Overflow = true;
return k;
}
/// Compute the result of "n choose k", the binomial coefficient. If an
/// intermediate computation overflows, Overflow will be set and the return will
/// be garbage. Overflow is not cleared on absence of overflow.
static uint64_t Choose(uint64_t n, uint64_t k, bool &Overflow) {
// We use the multiplicative formula:
// n(n-1)(n-2)...(n-(k-1)) / k(k-1)(k-2)...1 .
// At each iteration, we take the n-th term of the numeral and divide by the
// (k-n)th term of the denominator. This division will always produce an
// integral result, and helps reduce the chance of overflow in the
// intermediate computations. However, we can still overflow even when the
// final result would fit.
if (n == 0 || n == k) return 1;
if (k > n) return 0;
if (k > n/2)
k = n-k;
uint64_t r = 1;
for (uint64_t i = 1; i <= k; ++i) {
r = umul_ov(r, n-(i-1), Overflow);
r /= i;
}
return r;
}
/// Determine if any of the operands in this SCEV are a constant or if
/// any of the add or multiply expressions in this SCEV contain a constant.
static bool containsConstantInAddMulChain(const SCEV *StartExpr) {
struct FindConstantInAddMulChain {
bool FoundConstant = false;
bool follow(const SCEV *S) {
FoundConstant |= isa<SCEVConstant>(S);
return isa<SCEVAddExpr>(S) || isa<SCEVMulExpr>(S);
}
bool isDone() const {
return FoundConstant;
}
};
FindConstantInAddMulChain F;
SCEVTraversal<FindConstantInAddMulChain> ST(F);
ST.visitAll(StartExpr);
return F.FoundConstant;
}
/// Get a canonical multiply expression, or something simpler if possible.
const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl<const SCEV *> &Ops,
SCEV::NoWrapFlags OrigFlags,
unsigned Depth) {
assert(OrigFlags == maskFlags(OrigFlags, SCEV::FlagNUW | SCEV::FlagNSW) &&
"only nuw or nsw allowed");
assert(!Ops.empty() && "Cannot get empty mul!");
if (Ops.size() == 1) return Ops[0];
#ifndef NDEBUG
Type *ETy = Ops[0]->getType();
assert(!ETy->isPointerTy());
for (unsigned i = 1, e = Ops.size(); i != e; ++i)
assert(Ops[i]->getType() == ETy &&
"SCEVMulExpr operand types don't match!");
#endif
// Sort by complexity, this groups all similar expression types together.
GroupByComplexity(Ops, &LI, DT);
// If there are any constants, fold them together.
unsigned Idx = 0;
if (const SCEVConstant *LHSC = dyn_cast<SCEVConstant>(Ops[0])) {
++Idx;
assert(Idx < Ops.size());
while (const SCEVConstant *RHSC = dyn_cast<SCEVConstant>(Ops[Idx])) {
// We found two constants, fold them together!
Ops[0] = getConstant(LHSC->getAPInt() * RHSC->getAPInt());
if (Ops.size() == 2) return Ops[0];
Ops.erase(Ops.begin()+1); // Erase the folded element
LHSC = cast<SCEVConstant>(Ops[0]);
}
// If we have a multiply of zero, it will always be zero.
if (LHSC->getValue()->isZero())
return LHSC;
// If we are left with a constant one being multiplied, strip it off.
if (LHSC->getValue()->isOne()) {
Ops.erase(Ops.begin());
--Idx;
}
if (Ops.size() == 1)
return Ops[0];
}
// Delay expensive flag strengthening until necessary.
auto ComputeFlags = [this, OrigFlags](const ArrayRef<const SCEV *> Ops) {
return StrengthenNoWrapFlags(this, scMulExpr, Ops, OrigFlags);
};
// Limit recursion calls depth.
if (Depth > MaxArithDepth || hasHugeExpression(Ops))
return getOrCreateMulExpr(Ops, ComputeFlags(Ops));
if (SCEV *S = findExistingSCEVInCache(scMulExpr, Ops)) {
// Don't strengthen flags if we have no new information.
SCEVMulExpr *Mul = static_cast<SCEVMulExpr *>(S);
if (Mul->getNoWrapFlags(OrigFlags) != OrigFlags)
Mul->setNoWrapFlags(ComputeFlags(Ops));
return S;
}
if (const SCEVConstant *LHSC = dyn_cast<SCEVConstant>(Ops[0])) {
if (Ops.size() == 2) {
// C1*(C2+V) -> C1*C2 + C1*V
if (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(Ops[1]))
// If any of Add's ops are Adds or Muls with a constant, apply this
// transformation as well.
//
// TODO: There are some cases where this transformation is not
// profitable; for example, Add = (C0 + X) * Y + Z. Maybe the scope of
// this transformation should be narrowed down.
if (Add->getNumOperands() == 2 && containsConstantInAddMulChain(Add)) {
const SCEV *LHS = getMulExpr(LHSC, Add->getOperand(0),
SCEV::FlagAnyWrap, Depth + 1);
const SCEV *RHS = getMulExpr(LHSC, Add->getOperand(1),
SCEV::FlagAnyWrap, Depth + 1);
return getAddExpr(LHS, RHS, SCEV::FlagAnyWrap, Depth + 1);
}
if (Ops[0]->isAllOnesValue()) {
// If we have a mul by -1 of an add, try distributing the -1 among the
// add operands.
if (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(Ops[1])) {
SmallVector<const SCEV *, 4> NewOps;
bool AnyFolded = false;
for (const SCEV *AddOp : Add->operands()) {
const SCEV *Mul = getMulExpr(Ops[0], AddOp, SCEV::FlagAnyWrap,
Depth + 1);
if (!isa<SCEVMulExpr>(Mul)) AnyFolded = true;
NewOps.push_back(Mul);
}
if (AnyFolded)
return getAddExpr(NewOps, SCEV::FlagAnyWrap, Depth + 1);
} else if (const auto *AddRec = dyn_cast<SCEVAddRecExpr>(Ops[1])) {
// Negation preserves a recurrence's no self-wrap property.
SmallVector<const SCEV *, 4> Operands;
for (const SCEV *AddRecOp : AddRec->operands())
Operands.push_back(getMulExpr(Ops[0], AddRecOp, SCEV::FlagAnyWrap,
Depth + 1));
return getAddRecExpr(Operands, AddRec->getLoop(),
AddRec->getNoWrapFlags(SCEV::FlagNW));
}
}
}
}
// Skip over the add expression until we get to a multiply.
while (Idx < Ops.size() && Ops[Idx]->getSCEVType() < scMulExpr)
++Idx;
// If there are mul operands inline them all into this expression.
if (Idx < Ops.size()) {
bool DeletedMul = false;
while (const SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(Ops[Idx])) {
if (Ops.size() > MulOpsInlineThreshold)
break;
// If we have an mul, expand the mul operands onto the end of the
// operands list.
Ops.erase(Ops.begin()+Idx);
Ops.append(Mul->op_begin(), Mul->op_end());
DeletedMul = true;
}
// If we deleted at least one mul, we added operands to the end of the
// list, and they are not necessarily sorted. Recurse to resort and
// resimplify any operands we just acquired.
if (DeletedMul)
return getMulExpr(Ops, SCEV::FlagAnyWrap, Depth + 1);
}
// If there are any add recurrences in the operands list, see if any other
// added values are loop invariant. If so, we can fold them into the
// recurrence.
while (Idx < Ops.size() && Ops[Idx]->getSCEVType() < scAddRecExpr)
++Idx;
// Scan over all recurrences, trying to fold loop invariants into them.
for (; Idx < Ops.size() && isa<SCEVAddRecExpr>(Ops[Idx]); ++Idx) {
// Scan all of the other operands to this mul and add them to the vector
// if they are loop invariant w.r.t. the recurrence.
SmallVector<const SCEV *, 8> LIOps;
const SCEVAddRecExpr *AddRec = cast<SCEVAddRecExpr>(Ops[Idx]);
const Loop *AddRecLoop = AddRec->getLoop();
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
if (isAvailableAtLoopEntry(Ops[i], AddRecLoop)) {
LIOps.push_back(Ops[i]);
Ops.erase(Ops.begin()+i);
--i; --e;
}
// If we found some loop invariants, fold them into the recurrence.
if (!LIOps.empty()) {
// NLI * LI * {Start,+,Step} --> NLI * {LI*Start,+,LI*Step}
SmallVector<const SCEV *, 4> NewOps;
NewOps.reserve(AddRec->getNumOperands());
const SCEV *Scale = getMulExpr(LIOps, SCEV::FlagAnyWrap, Depth + 1);
for (unsigned i = 0, e = AddRec->getNumOperands(); i != e; ++i)
NewOps.push_back(getMulExpr(Scale, AddRec->getOperand(i),
SCEV::FlagAnyWrap, Depth + 1));
// Build the new addrec. Propagate the NUW and NSW flags if both the
// outer mul and the inner addrec are guaranteed to have no overflow.
//
// No self-wrap cannot be guaranteed after changing the step size, but
// will be inferred if either NUW or NSW is true.
SCEV::NoWrapFlags Flags = ComputeFlags({Scale, AddRec});
const SCEV *NewRec = getAddRecExpr(
NewOps, AddRecLoop, AddRec->getNoWrapFlags(Flags));
// If all of the other operands were loop invariant, we are done.
if (Ops.size() == 1) return NewRec;
// Otherwise, multiply the folded AddRec by the non-invariant parts.
for (unsigned i = 0;; ++i)
if (Ops[i] == AddRec) {
Ops[i] = NewRec;
break;
}
return getMulExpr(Ops, SCEV::FlagAnyWrap, Depth + 1);
}
// Okay, if there weren't any loop invariants to be folded, check to see
// if there are multiple AddRec's with the same loop induction variable
// being multiplied together. If so, we can fold them.
// {A1,+,A2,+,...,+,An}<L> * {B1,+,B2,+,...,+,Bn}<L>
// = {x=1 in [ sum y=x..2x [ sum z=max(y-x, y-n)..min(x,n) [
// choose(x, 2x)*choose(2x-y, x-z)*A_{y-z}*B_z
// ]]],+,...up to x=2n}.
// Note that the arguments to choose() are always integers with values
// known at compile time, never SCEV objects.
//
// The implementation avoids pointless extra computations when the two
// addrec's are of different length (mathematically, it's equivalent to
// an infinite stream of zeros on the right).
bool OpsModified = false;
for (unsigned OtherIdx = Idx+1;
OtherIdx != Ops.size() && isa<SCEVAddRecExpr>(Ops[OtherIdx]);
++OtherIdx) {
const SCEVAddRecExpr *OtherAddRec =
dyn_cast<SCEVAddRecExpr>(Ops[OtherIdx]);
if (!OtherAddRec || OtherAddRec->getLoop() != AddRecLoop)
continue;
// Limit max number of arguments to avoid creation of unreasonably big
// SCEVAddRecs with very complex operands.
if (AddRec->getNumOperands() + OtherAddRec->getNumOperands() - 1 >
MaxAddRecSize || hasHugeExpression({AddRec, OtherAddRec}))
continue;
bool Overflow = false;
Type *Ty = AddRec->getType();
bool LargerThan64Bits = getTypeSizeInBits(Ty) > 64;
SmallVector<const SCEV*, 7> AddRecOps;
for (int x = 0, xe = AddRec->getNumOperands() +
OtherAddRec->getNumOperands() - 1; x != xe && !Overflow; ++x) {
SmallVector <const SCEV *, 7> SumOps;
for (int y = x, ye = 2*x+1; y != ye && !Overflow; ++y) {
uint64_t Coeff1 = Choose(x, 2*x - y, Overflow);
for (int z = std::max(y-x, y-(int)AddRec->getNumOperands()+1),
ze = std::min(x+1, (int)OtherAddRec->getNumOperands());
z < ze && !Overflow; ++z) {
uint64_t Coeff2 = Choose(2*x - y, x-z, Overflow);
uint64_t Coeff;
if (LargerThan64Bits)
Coeff = umul_ov(Coeff1, Coeff2, Overflow);
else
Coeff = Coeff1*Coeff2;
const SCEV *CoeffTerm = getConstant(Ty, Coeff);
const SCEV *Term1 = AddRec->getOperand(y-z);
const SCEV *Term2 = OtherAddRec->getOperand(z);
SumOps.push_back(getMulExpr(CoeffTerm, Term1, Term2,
SCEV::FlagAnyWrap, Depth + 1));
}
}
if (SumOps.empty())
SumOps.push_back(getZero(Ty));
AddRecOps.push_back(getAddExpr(SumOps, SCEV::FlagAnyWrap, Depth + 1));
}
if (!Overflow) {
const SCEV *NewAddRec = getAddRecExpr(AddRecOps, AddRecLoop,
SCEV::FlagAnyWrap);
if (Ops.size() == 2) return NewAddRec;
Ops[Idx] = NewAddRec;
Ops.erase(Ops.begin() + OtherIdx); --OtherIdx;
OpsModified = true;
AddRec = dyn_cast<SCEVAddRecExpr>(NewAddRec);
if (!AddRec)
break;
}
}
if (OpsModified)
return getMulExpr(Ops, SCEV::FlagAnyWrap, Depth + 1);
// Otherwise couldn't fold anything into this recurrence. Move onto the
// next one.
}
// Okay, it looks like we really DO need an mul expr. Check to see if we
// already have one, otherwise create a new one.
return getOrCreateMulExpr(Ops, ComputeFlags(Ops));
}
/// Represents an unsigned remainder expression based on unsigned division.
const SCEV *ScalarEvolution::getURemExpr(const SCEV *LHS,
const SCEV *RHS) {
assert(getEffectiveSCEVType(LHS->getType()) ==
getEffectiveSCEVType(RHS->getType()) &&
"SCEVURemExpr operand types don't match!");
// Short-circuit easy cases
if (const SCEVConstant *RHSC = dyn_cast<SCEVConstant>(RHS)) {
// If constant is one, the result is trivial
if (RHSC->getValue()->isOne())
return getZero(LHS->getType()); // X urem 1 --> 0
// If constant is a power of two, fold into a zext(trunc(LHS)).
if (RHSC->getAPInt().isPowerOf2()) {
Type *FullTy = LHS->getType();
Type *TruncTy =
IntegerType::get(getContext(), RHSC->getAPInt().logBase2());
return getZeroExtendExpr(getTruncateExpr(LHS, TruncTy), FullTy);
}
}
// Fallback to %a == %x urem %y == %x -<nuw> ((%x udiv %y) *<nuw> %y)
const SCEV *UDiv = getUDivExpr(LHS, RHS);
const SCEV *Mult = getMulExpr(UDiv, RHS, SCEV::FlagNUW);
return getMinusSCEV(LHS, Mult, SCEV::FlagNUW);
}
/// Get a canonical unsigned division expression, or something simpler if
/// possible.
const SCEV *ScalarEvolution::getUDivExpr(const SCEV *LHS,
const SCEV *RHS) {
assert(!LHS->getType()->isPointerTy() &&
"SCEVUDivExpr operand can't be pointer!");
assert(LHS->getType() == RHS->getType() &&
"SCEVUDivExpr operand types don't match!");
FoldingSetNodeID ID;
ID.AddInteger(scUDivExpr);
ID.AddPointer(LHS);
ID.AddPointer(RHS);
void *IP = nullptr;
if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP))
return S;
// 0 udiv Y == 0
if (const SCEVConstant *LHSC = dyn_cast<SCEVConstant>(LHS))
if (LHSC->getValue()->isZero())
return LHS;
if (const SCEVConstant *RHSC = dyn_cast<SCEVConstant>(RHS)) {
if (RHSC->getValue()->isOne())
return LHS; // X udiv 1 --> x
// If the denominator is zero, the result of the udiv is undefined. Don't
// try to analyze it, because the resolution chosen here may differ from
// the resolution chosen in other parts of the compiler.
if (!RHSC->getValue()->isZero()) {
// Determine if the division can be folded into the operands of
// its operands.
// TODO: Generalize this to non-constants by using known-bits information.
Type *Ty = LHS->getType();
unsigned LZ = RHSC->getAPInt().countLeadingZeros();
unsigned MaxShiftAmt = getTypeSizeInBits(Ty) - LZ - 1;
// For non-power-of-two values, effectively round the value up to the
// nearest power of two.
if (!RHSC->getAPInt().isPowerOf2())
++MaxShiftAmt;
IntegerType *ExtTy =
IntegerType::get(getContext(), getTypeSizeInBits(Ty) + MaxShiftAmt);
if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(LHS))
if (const SCEVConstant *Step =
dyn_cast<SCEVConstant>(AR->getStepRecurrence(*this))) {
// {X,+,N}/C --> {X/C,+,N/C} if safe and N/C can be folded.
const APInt &StepInt = Step->getAPInt();
const APInt &DivInt = RHSC->getAPInt();
if (!StepInt.urem(DivInt) &&
getZeroExtendExpr(AR, ExtTy) ==
getAddRecExpr(getZeroExtendExpr(AR->getStart(), ExtTy),
getZeroExtendExpr(Step, ExtTy),
AR->getLoop(), SCEV::FlagAnyWrap)) {
SmallVector<const SCEV *, 4> Operands;
for (const SCEV *Op : AR->operands())
Operands.push_back(getUDivExpr(Op, RHS));
return getAddRecExpr(Operands, AR->getLoop(), SCEV::FlagNW);
}
/// Get a canonical UDivExpr for a recurrence.
/// {X,+,N}/C => {Y,+,N}/C where Y=X-(X%N). Safe when C%N=0.
// We can currently only fold X%N if X is constant.
const SCEVConstant *StartC = dyn_cast<SCEVConstant>(AR->getStart());
if (StartC && !DivInt.urem(StepInt) &&
getZeroExtendExpr(AR, ExtTy) ==
getAddRecExpr(getZeroExtendExpr(AR->getStart(), ExtTy),
getZeroExtendExpr(Step, ExtTy),
AR->getLoop(), SCEV::FlagAnyWrap)) {
const APInt &StartInt = StartC->getAPInt();
const APInt &StartRem = StartInt.urem(StepInt);
if (StartRem != 0) {
const SCEV *NewLHS =
getAddRecExpr(getConstant(StartInt - StartRem), Step,
AR->getLoop(), SCEV::FlagNW);
if (LHS != NewLHS) {
LHS = NewLHS;
// Reset the ID to include the new LHS, and check if it is
// already cached.
ID.clear();
ID.AddInteger(scUDivExpr);
ID.AddPointer(LHS);
ID.AddPointer(RHS);
IP = nullptr;
if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP))
return S;
}
}
}
}
// (A*B)/C --> A*(B/C) if safe and B/C can be folded.
if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(LHS)) {
SmallVector<const SCEV *, 4> Operands;
for (const SCEV *Op : M->operands())
Operands.push_back(getZeroExtendExpr(Op, ExtTy));
if (getZeroExtendExpr(M, ExtTy) == getMulExpr(Operands))
// Find an operand that's safely divisible.
for (unsigned i = 0, e = M->getNumOperands(); i != e; ++i) {
const SCEV *Op = M->getOperand(i);
const SCEV *Div = getUDivExpr(Op, RHSC);
if (!isa<SCEVUDivExpr>(Div) && getMulExpr(Div, RHSC) == Op) {
Operands = SmallVector<const SCEV *, 4>(M->operands());
Operands[i] = Div;
return getMulExpr(Operands);
}
}
}
// (A/B)/C --> A/(B*C) if safe and B*C can be folded.
if (const SCEVUDivExpr *OtherDiv = dyn_cast<SCEVUDivExpr>(LHS)) {
if (auto *DivisorConstant =
dyn_cast<SCEVConstant>(OtherDiv->getRHS())) {
bool Overflow = false;
APInt NewRHS =
DivisorConstant->getAPInt().umul_ov(RHSC->getAPInt(), Overflow);
if (Overflow) {
return getConstant(RHSC->getType(), 0, false);
}
return getUDivExpr(OtherDiv->getLHS(), getConstant(NewRHS));
}
}
// (A+B)/C --> (A/C + B/C) if safe and A/C and B/C can be folded.
if (const SCEVAddExpr *A = dyn_cast<SCEVAddExpr>(LHS)) {
SmallVector<const SCEV *, 4> Operands;
for (const SCEV *Op : A->operands())
Operands.push_back(getZeroExtendExpr(Op, ExtTy));
if (getZeroExtendExpr(A, ExtTy) == getAddExpr(Operands)) {
Operands.clear();
for (unsigned i = 0, e = A->getNumOperands(); i != e; ++i) {
const SCEV *Op = getUDivExpr(A->getOperand(i), RHS);
if (isa<SCEVUDivExpr>(Op) ||
getMulExpr(Op, RHS) != A->getOperand(i))
break;
Operands.push_back(Op);
}
if (Operands.size() == A->getNumOperands())
return getAddExpr(Operands);
}
}
// Fold if both operands are constant.
if (const SCEVConstant *LHSC = dyn_cast<SCEVConstant>(LHS))
return getConstant(LHSC->getAPInt().udiv(RHSC->getAPInt()));
}
}
// The Insertion Point (IP) might be invalid by now (due to UniqueSCEVs
// changes). Make sure we get a new one.
IP = nullptr;
if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S;
SCEV *S = new (SCEVAllocator) SCEVUDivExpr(ID.Intern(SCEVAllocator),
LHS, RHS);
UniqueSCEVs.InsertNode(S, IP);
registerUser(S, {LHS, RHS});
return S;
}
APInt gcd(const SCEVConstant *C1, const SCEVConstant *C2) {
APInt A = C1->getAPInt().abs();
APInt B = C2->getAPInt().abs();
uint32_t ABW = A.getBitWidth();
uint32_t BBW = B.getBitWidth();
if (ABW > BBW)
B = B.zext(ABW);
else if (ABW < BBW)
A = A.zext(BBW);
return APIntOps::GreatestCommonDivisor(std::move(A), std::move(B));
}
/// Get a canonical unsigned division expression, or something simpler if
/// possible. There is no representation for an exact udiv in SCEV IR, but we
/// can attempt to remove factors from the LHS and RHS. We can't do this when
/// it's not exact because the udiv may be clearing bits.
const SCEV *ScalarEvolution::getUDivExactExpr(const SCEV *LHS,
const SCEV *RHS) {
// TODO: we could try to find factors in all sorts of things, but for now we
// just deal with u/exact (multiply, constant). See SCEVDivision towards the
// end of this file for inspiration.
const SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(LHS);
if (!Mul || !Mul->hasNoUnsignedWrap())
return getUDivExpr(LHS, RHS);
if (const SCEVConstant *RHSCst = dyn_cast<SCEVConstant>(RHS)) {
// If the mulexpr multiplies by a constant, then that constant must be the
// first element of the mulexpr.
if (const auto *LHSCst = dyn_cast<SCEVConstant>(Mul->getOperand(0))) {
if (LHSCst == RHSCst) {
SmallVector<const SCEV *, 2> Operands(drop_begin(Mul->operands()));
return getMulExpr(Operands);
}
// We can't just assume that LHSCst divides RHSCst cleanly, it could be
// that there's a factor provided by one of the other terms. We need to
// check.
APInt Factor = gcd(LHSCst, RHSCst);
if (!Factor.isIntN(1)) {
LHSCst =
cast<SCEVConstant>(getConstant(LHSCst->getAPInt().udiv(Factor)));
RHSCst =
cast<SCEVConstant>(getConstant(RHSCst->getAPInt().udiv(Factor)));
SmallVector<const SCEV *, 2> Operands;
Operands.push_back(LHSCst);
Operands.append(Mul->op_begin() + 1, Mul->op_end());
LHS = getMulExpr(Operands);
RHS = RHSCst;
Mul = dyn_cast<SCEVMulExpr>(LHS);
if (!Mul)
return getUDivExactExpr(LHS, RHS);
}
}
}
for (int i = 0, e = Mul->getNumOperands(); i != e; ++i) {
if (Mul->getOperand(i) == RHS) {
SmallVector<const SCEV *, 2> Operands;
Operands.append(Mul->op_begin(), Mul->op_begin() + i);
Operands.append(Mul->op_begin() + i + 1, Mul->op_end());
return getMulExpr(Operands);
}
}
return getUDivExpr(LHS, RHS);
}
/// Get an add recurrence expression for the specified loop. Simplify the
/// expression as much as possible.
const SCEV *ScalarEvolution::getAddRecExpr(const SCEV *Start, const SCEV *Step,
const Loop *L,
SCEV::NoWrapFlags Flags) {
SmallVector<const SCEV *, 4> Operands;
Operands.push_back(Start);
if (const SCEVAddRecExpr *StepChrec = dyn_cast<SCEVAddRecExpr>(Step))
if (StepChrec->getLoop() == L) {
Operands.append(StepChrec->op_begin(), StepChrec->op_end());
return getAddRecExpr(Operands, L, maskFlags(Flags, SCEV::FlagNW));
}
Operands.push_back(Step);
return getAddRecExpr(Operands, L, Flags);
}
/// Get an add recurrence expression for the specified loop. Simplify the
/// expression as much as possible.
const SCEV *
ScalarEvolution::getAddRecExpr(SmallVectorImpl<const SCEV *> &Operands,
const Loop *L, SCEV::NoWrapFlags Flags) {
if (Operands.size() == 1) return Operands[0];
#ifndef NDEBUG
Type *ETy = getEffectiveSCEVType(Operands[0]->getType());
for (unsigned i = 1, e = Operands.size(); i != e; ++i) {
assert(getEffectiveSCEVType(Operands[i]->getType()) == ETy &&
"SCEVAddRecExpr operand types don't match!");
assert(!Operands[i]->getType()->isPointerTy() && "Step must be integer");
}
for (unsigned i = 0, e = Operands.size(); i != e; ++i)
assert(isLoopInvariant(Operands[i], L) &&
"SCEVAddRecExpr operand is not loop-invariant!");
#endif
if (Operands.back()->isZero()) {
Operands.pop_back();
return getAddRecExpr(Operands, L, SCEV::FlagAnyWrap); // {X,+,0} --> X
}
// It's tempting to want to call getConstantMaxBackedgeTakenCount count here and
// use that information to infer NUW and NSW flags. However, computing a
// BE count requires calling getAddRecExpr, so we may not yet have a
// meaningful BE count at this point (and if we don't, we'd be stuck
// with a SCEVCouldNotCompute as the cached BE count).
Flags = StrengthenNoWrapFlags(this, scAddRecExpr, Operands, Flags);
// Canonicalize nested AddRecs in by nesting them in order of loop depth.
if (const SCEVAddRecExpr *NestedAR = dyn_cast<SCEVAddRecExpr>(Operands[0])) {
const Loop *NestedLoop = NestedAR->getLoop();
if (L->contains(NestedLoop)
? (L->getLoopDepth() < NestedLoop->getLoopDepth())
: (!NestedLoop->contains(L) &&
DT.dominates(L->getHeader(), NestedLoop->getHeader()))) {
SmallVector<const SCEV *, 4> NestedOperands(NestedAR->operands());
Operands[0] = NestedAR->getStart();
// AddRecs require their operands be loop-invariant with respect to their
// loops. Don't perform this transformation if it would break this
// requirement.
bool AllInvariant = all_of(
Operands, [&](const SCEV *Op) { return isLoopInvariant(Op, L); });
if (AllInvariant) {
// Create a recurrence for the outer loop with the same step size.
//
// The outer recurrence keeps its NW flag but only keeps NUW/NSW if the
// inner recurrence has the same property.
SCEV::NoWrapFlags OuterFlags =
maskFlags(Flags, SCEV::FlagNW | NestedAR->getNoWrapFlags());
NestedOperands[0] = getAddRecExpr(Operands, L, OuterFlags);
AllInvariant = all_of(NestedOperands, [&](const SCEV *Op) {
return isLoopInvariant(Op, NestedLoop);
});
if (AllInvariant) {
// Ok, both add recurrences are valid after the transformation.
//
// The inner recurrence keeps its NW flag but only keeps NUW/NSW if
// the outer recurrence has the same property.
SCEV::NoWrapFlags InnerFlags =
maskFlags(NestedAR->getNoWrapFlags(), SCEV::FlagNW | Flags);
return getAddRecExpr(NestedOperands, NestedLoop, InnerFlags);
}
}
// Reset Operands to its original state.
Operands[0] = NestedAR;
}
}
// Okay, it looks like we really DO need an addrec expr. Check to see if we
// already have one, otherwise create a new one.
return getOrCreateAddRecExpr(Operands, L, Flags);
}
const SCEV *
ScalarEvolution::getGEPExpr(GEPOperator *GEP,
const SmallVectorImpl<const SCEV *> &IndexExprs) {
const SCEV *BaseExpr = getSCEV(GEP->getPointerOperand());
// getSCEV(Base)->getType() has the same address space as Base->getType()
// because SCEV::getType() preserves the address space.
Type *IntIdxTy = getEffectiveSCEVType(BaseExpr->getType());
const bool AssumeInBoundsFlags = [&]() {
if (!GEP->isInBounds())
return false;
// We'd like to propagate flags from the IR to the corresponding SCEV nodes,
// but to do that, we have to ensure that said flag is valid in the entire
// defined scope of the SCEV.
auto *GEPI = dyn_cast<Instruction>(GEP);
// TODO: non-instructions have global scope. We might be able to prove
// some global scope cases
return GEPI && isSCEVExprNeverPoison(GEPI);
}();
SCEV::NoWrapFlags OffsetWrap =
AssumeInBoundsFlags ? SCEV::FlagNSW : SCEV::FlagAnyWrap;
Type *CurTy = GEP->getType();
bool FirstIter = true;
SmallVector<const SCEV *, 4> Offsets;
for (const SCEV *IndexExpr : IndexExprs) {
// Compute the (potentially symbolic) offset in bytes for this index.
if (StructType *STy = dyn_cast<StructType>(CurTy)) {
// For a struct, add the member offset.
ConstantInt *Index = cast<SCEVConstant>(IndexExpr)->getValue();
unsigned FieldNo = Index->getZExtValue();
const SCEV *FieldOffset = getOffsetOfExpr(IntIdxTy, STy, FieldNo);
Offsets.push_back(FieldOffset);
// Update CurTy to the type of the field at Index.
CurTy = STy->getTypeAtIndex(Index);
} else {
// Update CurTy to its element type.
if (FirstIter) {
assert(isa<PointerType>(CurTy) &&
"The first index of a GEP indexes a pointer");
CurTy = GEP->getSourceElementType();
FirstIter = false;
} else {
CurTy = GetElementPtrInst::getTypeAtIndex(CurTy, (uint64_t)0);
}
// For an array, add the element offset, explicitly scaled.
const SCEV *ElementSize = getSizeOfExpr(IntIdxTy, CurTy);
// Getelementptr indices are signed.
IndexExpr = getTruncateOrSignExtend(IndexExpr, IntIdxTy);
// Multiply the index by the element size to compute the element offset.
const SCEV *LocalOffset = getMulExpr(IndexExpr, ElementSize, OffsetWrap);
Offsets.push_back(LocalOffset);
}
}
// Handle degenerate case of GEP without offsets.
if (Offsets.empty())
return BaseExpr;
// Add the offsets together, assuming nsw if inbounds.
const SCEV *Offset = getAddExpr(Offsets, OffsetWrap);
// Add the base address and the offset. We cannot use the nsw flag, as the
// base address is unsigned. However, if we know that the offset is
// non-negative, we can use nuw.
SCEV::NoWrapFlags BaseWrap = AssumeInBoundsFlags && isKnownNonNegative(Offset)
? SCEV::FlagNUW : SCEV::FlagAnyWrap;
auto *GEPExpr = getAddExpr(BaseExpr, Offset, BaseWrap);
assert(BaseExpr->getType() == GEPExpr->getType() &&
"GEP should not change type mid-flight.");
return GEPExpr;
}
SCEV *ScalarEvolution::findExistingSCEVInCache(SCEVTypes SCEVType,
ArrayRef<const SCEV *> Ops) {
FoldingSetNodeID ID;
ID.AddInteger(SCEVType);
for (const SCEV *Op : Ops)
ID.AddPointer(Op);
void *IP = nullptr;
return UniqueSCEVs.FindNodeOrInsertPos(ID, IP);
}
const SCEV *ScalarEvolution::getAbsExpr(const SCEV *Op, bool IsNSW) {
SCEV::NoWrapFlags Flags = IsNSW ? SCEV::FlagNSW : SCEV::FlagAnyWrap;
return getSMaxExpr(Op, getNegativeSCEV(Op, Flags));
}
const SCEV *ScalarEvolution::getMinMaxExpr(SCEVTypes Kind,
SmallVectorImpl<const SCEV *> &Ops) {
assert(SCEVMinMaxExpr::isMinMaxType(Kind) && "Not a SCEVMinMaxExpr!");
assert(!Ops.empty() && "Cannot get empty (u|s)(min|max)!");
if (Ops.size() == 1) return Ops[0];
#ifndef NDEBUG
Type *ETy = getEffectiveSCEVType(Ops[0]->getType());
for (unsigned i = 1, e = Ops.size(); i != e; ++i) {
assert(getEffectiveSCEVType(Ops[i]->getType()) == ETy &&
"Operand types don't match!");
assert(Ops[0]->getType()->isPointerTy() ==
Ops[i]->getType()->isPointerTy() &&
"min/max should be consistently pointerish");
}
#endif
bool IsSigned = Kind == scSMaxExpr || Kind == scSMinExpr;
bool IsMax = Kind == scSMaxExpr || Kind == scUMaxExpr;
// Sort by complexity, this groups all similar expression types together.
GroupByComplexity(Ops, &LI, DT);
// Check if we have created the same expression before.
if (const SCEV *S = findExistingSCEVInCache(Kind, Ops)) {
return S;
}
// If there are any constants, fold them together.
unsigned Idx = 0;
if (const SCEVConstant *LHSC = dyn_cast<SCEVConstant>(Ops[0])) {
++Idx;
assert(Idx < Ops.size());
auto FoldOp = [&](const APInt &LHS, const APInt &RHS) {
if (Kind == scSMaxExpr)
return APIntOps::smax(LHS, RHS);
else if (Kind == scSMinExpr)
return APIntOps::smin(LHS, RHS);
else if (Kind == scUMaxExpr)
return APIntOps::umax(LHS, RHS);
else if (Kind == scUMinExpr)
return APIntOps::umin(LHS, RHS);
llvm_unreachable("Unknown SCEV min/max opcode");
};
while (const SCEVConstant *RHSC = dyn_cast<SCEVConstant>(Ops[Idx])) {
// We found two constants, fold them together!
ConstantInt *Fold = ConstantInt::get(
getContext(), FoldOp(LHSC->getAPInt(), RHSC->getAPInt()));
Ops[0] = getConstant(Fold);
Ops.erase(Ops.begin()+1); // Erase the folded element
if (Ops.size() == 1) return Ops[0];
LHSC = cast<SCEVConstant>(Ops[0]);
}
bool IsMinV = LHSC->getValue()->isMinValue(IsSigned);
bool IsMaxV = LHSC->getValue()->isMaxValue(IsSigned);
if (IsMax ? IsMinV : IsMaxV) {
// If we are left with a constant minimum(/maximum)-int, strip it off.
Ops.erase(Ops.begin());
--Idx;
} else if (IsMax ? IsMaxV : IsMinV) {
// If we have a max(/min) with a constant maximum(/minimum)-int,
// it will always be the extremum.
return LHSC;
}
if (Ops.size() == 1) return Ops[0];
}
// Find the first operation of the same kind
while (Idx < Ops.size() && Ops[Idx]->getSCEVType() < Kind)
++Idx;
// Check to see if one of the operands is of the same kind. If so, expand its
// operands onto our operand list, and recurse to simplify.
if (Idx < Ops.size()) {
bool DeletedAny = false;
while (Ops[Idx]->getSCEVType() == Kind) {
const SCEVMinMaxExpr *SMME = cast<SCEVMinMaxExpr>(Ops[Idx]);
Ops.erase(Ops.begin()+Idx);
Ops.append(SMME->op_begin(), SMME->op_end());
DeletedAny = true;
}
if (DeletedAny)
return getMinMaxExpr(Kind, Ops);
}
// Okay, check to see if the same value occurs in the operand list twice. If
// so, delete one. Since we sorted the list, these values are required to
// be adjacent.
llvm::CmpInst::Predicate GEPred =
IsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE;
llvm::CmpInst::Predicate LEPred =
IsSigned ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE;
llvm::CmpInst::Predicate FirstPred = IsMax ? GEPred : LEPred;
llvm::CmpInst::Predicate SecondPred = IsMax ? LEPred : GEPred;
for (unsigned i = 0, e = Ops.size() - 1; i != e; ++i) {
if (Ops[i] == Ops[i + 1] ||
isKnownViaNonRecursiveReasoning(FirstPred, Ops[i], Ops[i + 1])) {
// X op Y op Y --> X op Y
// X op Y --> X, if we know X, Y are ordered appropriately
Ops.erase(Ops.begin() + i + 1, Ops.begin() + i + 2);
--i;
--e;
} else if (isKnownViaNonRecursiveReasoning(SecondPred, Ops[i],
Ops[i + 1])) {
// X op Y --> Y, if we know X, Y are ordered appropriately
Ops.erase(Ops.begin() + i, Ops.begin() + i + 1);
--i;
--e;
}
}
if (Ops.size() == 1) return Ops[0];
assert(!Ops.empty() && "Reduced smax down to nothing!");
// Okay, it looks like we really DO need an expr. Check to see if we
// already have one, otherwise create a new one.
FoldingSetNodeID ID;
ID.AddInteger(Kind);
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
ID.AddPointer(Ops[i]);
void *IP = nullptr;
const SCEV *ExistingSCEV = UniqueSCEVs.FindNodeOrInsertPos(ID, IP);
if (ExistingSCEV)
return ExistingSCEV;
const SCEV **O = SCEVAllocator.Allocate<const SCEV *>(Ops.size());
std::uninitialized_copy(Ops.begin(), Ops.end(), O);
SCEV *S = new (SCEVAllocator)
SCEVMinMaxExpr(ID.Intern(SCEVAllocator), Kind, O, Ops.size());
UniqueSCEVs.InsertNode(S, IP);
registerUser(S, Ops);
return S;
}
namespace {
class SCEVSequentialMinMaxDeduplicatingVisitor final
: public SCEVVisitor<SCEVSequentialMinMaxDeduplicatingVisitor,
Optional<const SCEV *>> {
using RetVal = Optional<const SCEV *>;
using Base = SCEVVisitor<SCEVSequentialMinMaxDeduplicatingVisitor, RetVal>;
ScalarEvolution &SE;
const SCEVTypes RootKind; // Must be a sequential min/max expression.
const SCEVTypes NonSequentialRootKind; // Non-sequential variant of RootKind.
SmallPtrSet<const SCEV *, 16> SeenOps;
bool canRecurseInto(SCEVTypes Kind) const {
// We can only recurse into the SCEV expression of the same effective type
// as the type of our root SCEV expression.
return RootKind == Kind || NonSequentialRootKind == Kind;
};
RetVal visitAnyMinMaxExpr(const SCEV *S) {
assert((isa<SCEVMinMaxExpr>(S) || isa<SCEVSequentialMinMaxExpr>(S)) &&
"Only for min/max expressions.");
SCEVTypes Kind = S->getSCEVType();
if (!canRecurseInto(Kind))
return S;
auto *NAry = cast<SCEVNAryExpr>(S);
SmallVector<const SCEV *> NewOps;
bool Changed =
visit(Kind, makeArrayRef(NAry->op_begin(), NAry->op_end()), NewOps);
if (!Changed)
return S;
if (NewOps.empty())
return None;
return isa<SCEVSequentialMinMaxExpr>(S)
? SE.getSequentialMinMaxExpr(Kind, NewOps)
: SE.getMinMaxExpr(Kind, NewOps);
}
RetVal visit(const SCEV *S) {
// Has the whole operand been seen already?
if (!SeenOps.insert(S).second)
return None;
return Base::visit(S);
}
public:
SCEVSequentialMinMaxDeduplicatingVisitor(ScalarEvolution &SE,
SCEVTypes RootKind)
: SE(SE), RootKind(RootKind),
NonSequentialRootKind(
SCEVSequentialMinMaxExpr::getEquivalentNonSequentialSCEVType(
RootKind)) {}
bool /*Changed*/ visit(SCEVTypes Kind, ArrayRef<const SCEV *> OrigOps,
SmallVectorImpl<const SCEV *> &NewOps) {
bool Changed = false;
SmallVector<const SCEV *> Ops;
Ops.reserve(OrigOps.size());
for (const SCEV *Op : OrigOps) {
RetVal NewOp = visit(Op);
if (NewOp != Op)
Changed = true;
if (NewOp)
Ops.emplace_back(*NewOp);
}
if (Changed)
NewOps = std::move(Ops);
return Changed;
}
RetVal visitConstant(const SCEVConstant *Constant) { return Constant; }
RetVal visitPtrToIntExpr(const SCEVPtrToIntExpr *Expr) { return Expr; }
RetVal visitTruncateExpr(const SCEVTruncateExpr *Expr) { return Expr; }
RetVal visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) { return Expr; }
RetVal visitSignExtendExpr(const SCEVSignExtendExpr *Expr) { return Expr; }
RetVal visitAddExpr(const SCEVAddExpr *Expr) { return Expr; }
RetVal visitMulExpr(const SCEVMulExpr *Expr) { return Expr; }
RetVal visitUDivExpr(const SCEVUDivExpr *Expr) { return Expr; }
RetVal visitAddRecExpr(const SCEVAddRecExpr *Expr) { return Expr; }
RetVal visitSMaxExpr(const SCEVSMaxExpr *Expr) {
return visitAnyMinMaxExpr(Expr);
}
RetVal visitUMaxExpr(const SCEVUMaxExpr *Expr) {
return visitAnyMinMaxExpr(Expr);
}
RetVal visitSMinExpr(const SCEVSMinExpr *Expr) {
return visitAnyMinMaxExpr(Expr);
}
RetVal visitUMinExpr(const SCEVUMinExpr *Expr) {
return visitAnyMinMaxExpr(Expr);
}
RetVal visitSequentialUMinExpr(const SCEVSequentialUMinExpr *Expr) {
return visitAnyMinMaxExpr(Expr);
}
RetVal visitUnknown(const SCEVUnknown *Expr) { return Expr; }
RetVal visitCouldNotCompute(const SCEVCouldNotCompute *Expr) { return Expr; }
};
} // namespace
/// Return true if V is poison given that AssumedPoison is already poison.
static bool impliesPoison(const SCEV *AssumedPoison, const SCEV *S) {
// The only way poison may be introduced in a SCEV expression is from a
// poison SCEVUnknown (ConstantExprs are also represented as SCEVUnknown,
// not SCEVConstant). Notably, nowrap flags in SCEV nodes can *not*
// introduce poison -- they encode guaranteed, non-speculated knowledge.
//
// Additionally, all SCEV nodes propagate poison from inputs to outputs,
// with the notable exception of umin_seq, where only poison from the first
// operand is (unconditionally) propagated.
struct SCEVPoisonCollector {
bool LookThroughSeq;
SmallPtrSet<const SCEV *, 4> MaybePoison;
SCEVPoisonCollector(bool LookThroughSeq) : LookThroughSeq(LookThroughSeq) {}
bool follow(const SCEV *S) {
// TODO: We can always follow the first operand, but the SCEVTraversal
// API doesn't support this.
if (!LookThroughSeq && isa<SCEVSequentialMinMaxExpr>(S))
return false;
if (auto *SU = dyn_cast<SCEVUnknown>(S)) {
if (!isGuaranteedNotToBePoison(SU->getValue()))
MaybePoison.insert(S);
}
return true;
}
bool isDone() const { return false; }
};
// First collect all SCEVs that might result in AssumedPoison to be poison.
// We need to look through umin_seq here, because we want to find all SCEVs
// that *might* result in poison, not only those that are *required* to.
SCEVPoisonCollector PC1(/* LookThroughSeq */ true);
visitAll(AssumedPoison, PC1);
// AssumedPoison is never poison. As the assumption is false, the implication
// is true. Don't bother walking the other SCEV in this case.
if (PC1.MaybePoison.empty())
return true;
// Collect all SCEVs in S that, if poison, *will* result in S being poison
// as well. We cannot look through umin_seq here, as its argument only *may*
// make the result poison.
SCEVPoisonCollector PC2(/* LookThroughSeq */ false);
visitAll(S, PC2);
// Make sure that no matter which SCEV in PC1.MaybePoison is actually poison,
// it will also make S poison by being part of PC2.MaybePoison.
return all_of(PC1.MaybePoison,
[&](const SCEV *S) { return PC2.MaybePoison.contains(S); });
}
const SCEV *
ScalarEvolution::getSequentialMinMaxExpr(SCEVTypes Kind,
SmallVectorImpl<const SCEV *> &Ops) {
assert(SCEVSequentialMinMaxExpr::isSequentialMinMaxType(Kind) &&
"Not a SCEVSequentialMinMaxExpr!");
assert(!Ops.empty() && "Cannot get empty (u|s)(min|max)!");
if (Ops.size() == 1)
return Ops[0];
#ifndef NDEBUG
Type *ETy = getEffectiveSCEVType(Ops[0]->getType());
for (unsigned i = 1, e = Ops.size(); i != e; ++i) {
assert(getEffectiveSCEVType(Ops[i]->getType()) == ETy &&
"Operand types don't match!");
assert(Ops[0]->getType()->isPointerTy() ==
Ops[i]->getType()->isPointerTy() &&
"min/max should be consistently pointerish");
}
#endif
// Note that SCEVSequentialMinMaxExpr is *NOT* commutative,
// so we can *NOT* do any kind of sorting of the expressions!
// Check if we have created the same expression before.
if (const SCEV *S = findExistingSCEVInCache(Kind, Ops))
return S;
// FIXME: there are *some* simplifications that we can do here.
// Keep only the first instance of an operand.
{
SCEVSequentialMinMaxDeduplicatingVisitor Deduplicator(*this, Kind);
bool Changed = Deduplicator.visit(Kind, Ops, Ops);
if (Changed)
return getSequentialMinMaxExpr(Kind, Ops);
}
// Check to see if one of the operands is of the same kind. If so, expand its
// operands onto our operand list, and recurse to simplify.
{
unsigned Idx = 0;
bool DeletedAny = false;
while (Idx < Ops.size()) {
if (Ops[Idx]->getSCEVType() != Kind) {
++Idx;
continue;
}
const auto *SMME = cast<SCEVSequentialMinMaxExpr>(Ops[Idx]);
Ops.erase(Ops.begin() + Idx);
Ops.insert(Ops.begin() + Idx, SMME->op_begin(), SMME->op_end());
DeletedAny = true;
}
if (DeletedAny)
return getSequentialMinMaxExpr(Kind, Ops);
}
const SCEV *SaturationPoint;
ICmpInst::Predicate Pred;
switch (Kind) {
case scSequentialUMinExpr:
SaturationPoint = getZero(Ops[0]->getType());
Pred = ICmpInst::ICMP_ULE;
break;
default:
llvm_unreachable("Not a sequential min/max type.");
}
for (unsigned i = 1, e = Ops.size(); i != e; ++i) {
// We can replace %x umin_seq %y with %x umin %y if either:
// * %y being poison implies %x is also poison.
// * %x cannot be the saturating value (e.g. zero for umin).
if (::impliesPoison(Ops[i], Ops[i - 1]) ||
isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_NE, Ops[i - 1],
SaturationPoint)) {
SmallVector<const SCEV *> SeqOps = {Ops[i - 1], Ops[i]};
Ops[i - 1] = getMinMaxExpr(
SCEVSequentialMinMaxExpr::getEquivalentNonSequentialSCEVType(Kind),
SeqOps);
Ops.erase(Ops.begin() + i);
return getSequentialMinMaxExpr(Kind, Ops);
}
// Fold %x umin_seq %y to %x if %x ule %y.
// TODO: We might be able to prove the predicate for a later operand.
if (isKnownViaNonRecursiveReasoning(Pred, Ops[i - 1], Ops[i])) {
Ops.erase(Ops.begin() + i);
return getSequentialMinMaxExpr(Kind, Ops);
}
}
// Okay, it looks like we really DO need an expr. Check to see if we
// already have one, otherwise create a new one.
FoldingSetNodeID ID;
ID.AddInteger(Kind);
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
ID.AddPointer(Ops[i]);
void *IP = nullptr;
const SCEV *ExistingSCEV = UniqueSCEVs.FindNodeOrInsertPos(ID, IP);
if (ExistingSCEV)
return ExistingSCEV;
const SCEV **O = SCEVAllocator.Allocate<const SCEV *>(Ops.size());
std::uninitialized_copy(Ops.begin(), Ops.end(), O);
SCEV *S = new (SCEVAllocator)
SCEVSequentialMinMaxExpr(ID.Intern(SCEVAllocator), Kind, O, Ops.size());
UniqueSCEVs.InsertNode(S, IP);
registerUser(S, Ops);
return S;
}
const SCEV *ScalarEvolution::getSMaxExpr(const SCEV *LHS, const SCEV *RHS) {
SmallVector<const SCEV *, 2> Ops = {LHS, RHS};
return getSMaxExpr(Ops);
}
const SCEV *ScalarEvolution::getSMaxExpr(SmallVectorImpl<const SCEV *> &Ops) {
return getMinMaxExpr(scSMaxExpr, Ops);
}
const SCEV *ScalarEvolution::getUMaxExpr(const SCEV *LHS, const SCEV *RHS) {
SmallVector<const SCEV *, 2> Ops = {LHS, RHS};
return getUMaxExpr(Ops);
}
const SCEV *ScalarEvolution::getUMaxExpr(SmallVectorImpl<const SCEV *> &Ops) {
return getMinMaxExpr(scUMaxExpr, Ops);
}
const SCEV *ScalarEvolution::getSMinExpr(const SCEV *LHS,
const SCEV *RHS) {
SmallVector<const SCEV *, 2> Ops = { LHS, RHS };
return getSMinExpr(Ops);
}
const SCEV *ScalarEvolution::getSMinExpr(SmallVectorImpl<const SCEV *> &Ops) {
return getMinMaxExpr(scSMinExpr, Ops);
}
const SCEV *ScalarEvolution::getUMinExpr(const SCEV *LHS, const SCEV *RHS,
bool Sequential) {
SmallVector<const SCEV *, 2> Ops = { LHS, RHS };
return getUMinExpr(Ops, Sequential);
}
const SCEV *ScalarEvolution::getUMinExpr(SmallVectorImpl<const SCEV *> &Ops,
bool Sequential) {
return Sequential ? getSequentialMinMaxExpr(scSequentialUMinExpr, Ops)
: getMinMaxExpr(scUMinExpr, Ops);
}
const SCEV *
ScalarEvolution::getSizeOfScalableVectorExpr(Type *IntTy,
ScalableVectorType *ScalableTy) {
Constant *NullPtr = Constant::getNullValue(ScalableTy->getPointerTo());
Constant *One = ConstantInt::get(IntTy, 1);
Constant *GEP = ConstantExpr::getGetElementPtr(ScalableTy, NullPtr, One);
// Note that the expression we created is the final expression, we don't
// want to simplify it any further Also, if we call a normal getSCEV(),
// we'll end up in an endless recursion. So just create an SCEVUnknown.
return getUnknown(ConstantExpr::getPtrToInt(GEP, IntTy));
}
const SCEV *ScalarEvolution::getSizeOfExpr(Type *IntTy, Type *AllocTy) {
if (auto *ScalableAllocTy = dyn_cast<ScalableVectorType>(AllocTy))
return getSizeOfScalableVectorExpr(IntTy, ScalableAllocTy);
// We can bypass creating a target-independent constant expression and then
// folding it back into a ConstantInt. This is just a compile-time
// optimization.
return getConstant(IntTy, getDataLayout().getTypeAllocSize(AllocTy));
}
const SCEV *ScalarEvolution::getStoreSizeOfExpr(Type *IntTy, Type *StoreTy) {
if (auto *ScalableStoreTy = dyn_cast<ScalableVectorType>(StoreTy))
return getSizeOfScalableVectorExpr(IntTy, ScalableStoreTy);
// We can bypass creating a target-independent constant expression and then
// folding it back into a ConstantInt. This is just a compile-time
// optimization.
return getConstant(IntTy, getDataLayout().getTypeStoreSize(StoreTy));
}
const SCEV *ScalarEvolution::getOffsetOfExpr(Type *IntTy,
StructType *STy,
unsigned FieldNo) {
// We can bypass creating a target-independent constant expression and then
// folding it back into a ConstantInt. This is just a compile-time
// optimization.
return getConstant(
IntTy, getDataLayout().getStructLayout(STy)->getElementOffset(FieldNo));
}
const SCEV *ScalarEvolution::getUnknown(Value *V) {
// Don't attempt to do anything other than create a SCEVUnknown object
// here. createSCEV only calls getUnknown after checking for all other
// interesting possibilities, and any other code that calls getUnknown
// is doing so in order to hide a value from SCEV canonicalization.
FoldingSetNodeID ID;
ID.AddInteger(scUnknown);
ID.AddPointer(V);
void *IP = nullptr;
if (SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) {
assert(cast<SCEVUnknown>(S)->getValue() == V &&
"Stale SCEVUnknown in uniquing map!");
return S;
}
SCEV *S = new (SCEVAllocator) SCEVUnknown(ID.Intern(SCEVAllocator), V, this,
FirstUnknown);
FirstUnknown = cast<SCEVUnknown>(S);
UniqueSCEVs.InsertNode(S, IP);
return S;
}
//===----------------------------------------------------------------------===//
// Basic SCEV Analysis and PHI Idiom Recognition Code
//
/// Test if values of the given type are analyzable within the SCEV
/// framework. This primarily includes integer types, and it can optionally
/// include pointer types if the ScalarEvolution class has access to
/// target-specific information.
bool ScalarEvolution::isSCEVable(Type *Ty) const {
// Integers and pointers are always SCEVable.
return Ty->isIntOrPtrTy();
}
/// Return the size in bits of the specified type, for which isSCEVable must
/// return true.
uint64_t ScalarEvolution::getTypeSizeInBits(Type *Ty) const {
assert(isSCEVable(Ty) && "Type is not SCEVable!");
if (Ty->isPointerTy())
return getDataLayout().getIndexTypeSizeInBits(Ty);
return getDataLayout().getTypeSizeInBits(Ty);
}
/// Return a type with the same bitwidth as the given type and which represents
/// how SCEV will treat the given type, for which isSCEVable must return
/// true. For pointer types, this is the pointer index sized integer type.
Type *ScalarEvolution::getEffectiveSCEVType(Type *Ty) const {
assert(isSCEVable(Ty) && "Type is not SCEVable!");
if (Ty->isIntegerTy())
return Ty;
// The only other support type is pointer.
assert(Ty->isPointerTy() && "Unexpected non-pointer non-integer type!");
return getDataLayout().getIndexType(Ty);
}
Type *ScalarEvolution::getWiderType(Type *T1, Type *T2) const {
return getTypeSizeInBits(T1) >= getTypeSizeInBits(T2) ? T1 : T2;
}
bool ScalarEvolution::instructionCouldExistWitthOperands(const SCEV *A,
const SCEV *B) {
/// For a valid use point to exist, the defining scope of one operand
/// must dominate the other.
bool PreciseA, PreciseB;
auto *ScopeA = getDefiningScopeBound({A}, PreciseA);
auto *ScopeB = getDefiningScopeBound({B}, PreciseB);
if (!PreciseA || !PreciseB)
// Can't tell.
return false;
return (ScopeA == ScopeB) || DT.dominates(ScopeA, ScopeB) ||
DT.dominates(ScopeB, ScopeA);
}
const SCEV *ScalarEvolution::getCouldNotCompute() {
return CouldNotCompute.get();
}
bool ScalarEvolution::checkValidity(const SCEV *S) const {
bool ContainsNulls = SCEVExprContains(S, [](const SCEV *S) {
auto *SU = dyn_cast<SCEVUnknown>(S);
return SU && SU->getValue() == nullptr;
});
return !ContainsNulls;
}
bool ScalarEvolution::containsAddRecurrence(const SCEV *S) {
HasRecMapType::iterator I = HasRecMap.find(S);
if (I != HasRecMap.end())
return I->second;
bool FoundAddRec =
SCEVExprContains(S, [](const SCEV *S) { return isa<SCEVAddRecExpr>(S); });
HasRecMap.insert({S, FoundAddRec});
return FoundAddRec;
}
/// Return the ValueOffsetPair set for \p S. \p S can be represented
/// by the value and offset from any ValueOffsetPair in the set.
ArrayRef<Value *> ScalarEvolution::getSCEVValues(const SCEV *S) {
ExprValueMapType::iterator SI = ExprValueMap.find_as(S);
if (SI == ExprValueMap.end())
return None;
#ifndef NDEBUG
if (VerifySCEVMap) {
// Check there is no dangling Value in the set returned.
for (Value *V : SI->second)
assert(ValueExprMap.count(V));
}
#endif
return SI->second.getArrayRef();
}
/// Erase Value from ValueExprMap and ExprValueMap. ValueExprMap.erase(V)
/// cannot be used separately. eraseValueFromMap should be used to remove
/// V from ValueExprMap and ExprValueMap at the same time.
void ScalarEvolution::eraseValueFromMap(Value *V) {
ValueExprMapType::iterator I = ValueExprMap.find_as(V);
if (I != ValueExprMap.end()) {
auto EVIt = ExprValueMap.find(I->second);
bool Removed = EVIt->second.remove(V);
(void) Removed;
assert(Removed && "Value not in ExprValueMap?");
ValueExprMap.erase(I);
}
}
void ScalarEvolution::insertValueToMap(Value *V, const SCEV *S) {
// A recursive query may have already computed the SCEV. It should be
// equivalent, but may not necessarily be exactly the same, e.g. due to lazily
// inferred nowrap flags.
auto It = ValueExprMap.find_as(V);
if (It == ValueExprMap.end()) {
ValueExprMap.insert({SCEVCallbackVH(V, this), S});
ExprValueMap[S].insert(V);
}
}
/// Return an existing SCEV if it exists, otherwise analyze the expression and
/// create a new one.
const SCEV *ScalarEvolution::getSCEV(Value *V) {
assert(isSCEVable(V->getType()) && "Value is not SCEVable!");
if (const SCEV *S = getExistingSCEV(V))
return S;
return createSCEVIter(V);
}
const SCEV *ScalarEvolution::getExistingSCEV(Value *V) {
assert(isSCEVable(V->getType()) && "Value is not SCEVable!");
ValueExprMapType::iterator I = ValueExprMap.find_as(V);
if (I != ValueExprMap.end()) {
const SCEV *S = I->second;
assert(checkValidity(S) &&
"existing SCEV has not been properly invalidated");
return S;
}
return nullptr;
}
/// Return a SCEV corresponding to -V = -1*V
const SCEV *ScalarEvolution::getNegativeSCEV(const SCEV *V,
SCEV::NoWrapFlags Flags) {
if (const SCEVConstant *VC = dyn_cast<SCEVConstant>(V))
return getConstant(
cast<ConstantInt>(ConstantExpr::getNeg(VC->getValue())));
Type *Ty = V->getType();
Ty = getEffectiveSCEVType(Ty);
return getMulExpr(V, getMinusOne(Ty), Flags);
}
/// If Expr computes ~A, return A else return nullptr
static const SCEV *MatchNotExpr(const SCEV *Expr) {
const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(Expr);
if (!Add || Add->getNumOperands() != 2 ||
!Add->getOperand(0)->isAllOnesValue())
return nullptr;
const SCEVMulExpr *AddRHS = dyn_cast<SCEVMulExpr>(Add->getOperand(1));
if (!AddRHS || AddRHS->getNumOperands() != 2 ||
!AddRHS->getOperand(0)->isAllOnesValue())
return nullptr;
return AddRHS->getOperand(1);
}
/// Return a SCEV corresponding to ~V = -1-V
const SCEV *ScalarEvolution::getNotSCEV(const SCEV *V) {
assert(!V->getType()->isPointerTy() && "Can't negate pointer");
if (const SCEVConstant *VC = dyn_cast<SCEVConstant>(V))
return getConstant(
cast<ConstantInt>(ConstantExpr::getNot(VC->getValue())));
// Fold ~(u|s)(min|max)(~x, ~y) to (u|s)(max|min)(x, y)
if (const SCEVMinMaxExpr *MME = dyn_cast<SCEVMinMaxExpr>(V)) {
auto MatchMinMaxNegation = [&](const SCEVMinMaxExpr *MME) {
SmallVector<const SCEV *, 2> MatchedOperands;
for (const SCEV *Operand : MME->operands()) {
const SCEV *Matched = MatchNotExpr(Operand);
if (!Matched)
return (const SCEV *)nullptr;
MatchedOperands.push_back(Matched);
}
return getMinMaxExpr(SCEVMinMaxExpr::negate(MME->getSCEVType()),
MatchedOperands);
};
if (const SCEV *Replaced = MatchMinMaxNegation(MME))
return Replaced;
}
Type *Ty = V->getType();
Ty = getEffectiveSCEVType(Ty);
return getMinusSCEV(getMinusOne(Ty), V);
}
const SCEV *ScalarEvolution::removePointerBase(const SCEV *P) {
assert(P->getType()->isPointerTy());
if (auto *AddRec = dyn_cast<SCEVAddRecExpr>(P)) {
// The base of an AddRec is the first operand.
SmallVector<const SCEV *> Ops{AddRec->operands()};
Ops[0] = removePointerBase(Ops[0]);
// Don't try to transfer nowrap flags for now. We could in some cases
// (for example, if pointer operand of the AddRec is a SCEVUnknown).
return getAddRecExpr(Ops, AddRec->getLoop(), SCEV::FlagAnyWrap);
}
if (auto *Add = dyn_cast<SCEVAddExpr>(P)) {
// The base of an Add is the pointer operand.
SmallVector<const SCEV *> Ops{Add->operands()};
const SCEV **PtrOp = nullptr;
for (const SCEV *&AddOp : Ops) {
if (AddOp->getType()->isPointerTy()) {
assert(!PtrOp && "Cannot have multiple pointer ops");
PtrOp = &AddOp;
}
}
*PtrOp = removePointerBase(*PtrOp);
// Don't try to transfer nowrap flags for now. We could in some cases
// (for example, if the pointer operand of the Add is a SCEVUnknown).
return getAddExpr(Ops);
}
// Any other expression must be a pointer base.
return getZero(P->getType());
}
const SCEV *ScalarEvolution::getMinusSCEV(const SCEV *LHS, const SCEV *RHS,
SCEV::NoWrapFlags Flags,
unsigned Depth) {
// Fast path: X - X --> 0.
if (LHS == RHS)
return getZero(LHS->getType());
// If we subtract two pointers with different pointer bases, bail.
// Eventually, we're going to add an assertion to getMulExpr that we
// can't multiply by a pointer.
if (RHS->getType()->isPointerTy()) {
if (!LHS->getType()->isPointerTy() ||
getPointerBase(LHS) != getPointerBase(RHS))
return getCouldNotCompute();
LHS = removePointerBase(LHS);
RHS = removePointerBase(RHS);
}
// We represent LHS - RHS as LHS + (-1)*RHS. This transformation
// makes it so that we cannot make much use of NUW.
auto AddFlags = SCEV::FlagAnyWrap;
const bool RHSIsNotMinSigned =
!getSignedRangeMin(RHS).isMinSignedValue();
if (hasFlags(Flags, SCEV::FlagNSW)) {
// Let M be the minimum representable signed value. Then (-1)*RHS
// signed-wraps if and only if RHS is M. That can happen even for
// a NSW subtraction because e.g. (-1)*M signed-wraps even though
// -1 - M does not. So to transfer NSW from LHS - RHS to LHS +
// (-1)*RHS, we need to prove that RHS != M.
//
// If LHS is non-negative and we know that LHS - RHS does not
// signed-wrap, then RHS cannot be M. So we can rule out signed-wrap
// either by proving that RHS > M or that LHS >= 0.
if (RHSIsNotMinSigned || isKnownNonNegative(LHS)) {
AddFlags = SCEV::FlagNSW;
}
}
// FIXME: Find a correct way to transfer NSW to (-1)*M when LHS -
// RHS is NSW and LHS >= 0.
//
// The difficulty here is that the NSW flag may have been proven
// relative to a loop that is to be found in a recurrence in LHS and
// not in RHS. Applying NSW to (-1)*M may then let the NSW have a
// larger scope than intended.
auto NegFlags = RHSIsNotMinSigned ? SCEV::FlagNSW : SCEV::FlagAnyWrap;
return getAddExpr(LHS, getNegativeSCEV(RHS, NegFlags), AddFlags, Depth);
}
const SCEV *ScalarEvolution::getTruncateOrZeroExtend(const SCEV *V, Type *Ty,
unsigned Depth) {
Type *SrcTy = V->getType();
assert(SrcTy->isIntOrPtrTy() && Ty->isIntOrPtrTy() &&
"Cannot truncate or zero extend with non-integer arguments!");
if (getTypeSizeInBits(SrcTy) == getTypeSizeInBits(Ty))
return V; // No conversion
if (getTypeSizeInBits(SrcTy) > getTypeSizeInBits(Ty))
return getTruncateExpr(V, Ty, Depth);
return getZeroExtendExpr(V, Ty, Depth);
}
const SCEV *ScalarEvolution::getTruncateOrSignExtend(const SCEV *V, Type *Ty,
unsigned Depth) {
Type *SrcTy = V->getType();
assert(SrcTy->isIntOrPtrTy() && Ty->isIntOrPtrTy() &&
"Cannot truncate or zero extend with non-integer arguments!");
if (getTypeSizeInBits(SrcTy) == getTypeSizeInBits(Ty))
return V; // No conversion
if (getTypeSizeInBits(SrcTy) > getTypeSizeInBits(Ty))
return getTruncateExpr(V, Ty, Depth);
return getSignExtendExpr(V, Ty, Depth);
}
const SCEV *
ScalarEvolution::getNoopOrZeroExtend(const SCEV *V, Type *Ty) {
Type *SrcTy = V->getType();
assert(SrcTy->isIntOrPtrTy() && Ty->isIntOrPtrTy() &&
"Cannot noop or zero extend with non-integer arguments!");
assert(getTypeSizeInBits(SrcTy) <= getTypeSizeInBits(Ty) &&
"getNoopOrZeroExtend cannot truncate!");
if (getTypeSizeInBits(SrcTy) == getTypeSizeInBits(Ty))
return V; // No conversion
return getZeroExtendExpr(V, Ty);
}
const SCEV *
ScalarEvolution::getNoopOrSignExtend(const SCEV *V, Type *Ty) {
Type *SrcTy = V->getType();
assert(SrcTy->isIntOrPtrTy() && Ty->isIntOrPtrTy() &&
"Cannot noop or sign extend with non-integer arguments!");
assert(getTypeSizeInBits(SrcTy) <= getTypeSizeInBits(Ty) &&
"getNoopOrSignExtend cannot truncate!");
if (getTypeSizeInBits(SrcTy) == getTypeSizeInBits(Ty))
return V; // No conversion
return getSignExtendExpr(V, Ty);
}
const SCEV *
ScalarEvolution::getNoopOrAnyExtend(const SCEV *V, Type *Ty) {
Type *SrcTy = V->getType();
assert(SrcTy->isIntOrPtrTy() && Ty->isIntOrPtrTy() &&
"Cannot noop or any extend with non-integer arguments!");
assert(getTypeSizeInBits(SrcTy) <= getTypeSizeInBits(Ty) &&
"getNoopOrAnyExtend cannot truncate!");
if (getTypeSizeInBits(SrcTy) == getTypeSizeInBits(Ty))
return V; // No conversion
return getAnyExtendExpr(V, Ty);
}
const SCEV *
ScalarEvolution::getTruncateOrNoop(const SCEV *V, Type *Ty) {
Type *SrcTy = V->getType();
assert(SrcTy->isIntOrPtrTy() && Ty->isIntOrPtrTy() &&
"Cannot truncate or noop with non-integer arguments!");
assert(getTypeSizeInBits(SrcTy) >= getTypeSizeInBits(Ty) &&
"getTruncateOrNoop cannot extend!");
if (getTypeSizeInBits(SrcTy) == getTypeSizeInBits(Ty))
return V; // No conversion
return getTruncateExpr(V, Ty);
}
const SCEV *ScalarEvolution::getUMaxFromMismatchedTypes(const SCEV *LHS,
const SCEV *RHS) {
const SCEV *PromotedLHS = LHS;
const SCEV *PromotedRHS = RHS;
if (getTypeSizeInBits(LHS->getType()) > getTypeSizeInBits(RHS->getType()))
PromotedRHS = getZeroExtendExpr(RHS, LHS->getType());
else
PromotedLHS = getNoopOrZeroExtend(LHS, RHS->getType());
return getUMaxExpr(PromotedLHS, PromotedRHS);
}
const SCEV *ScalarEvolution::getUMinFromMismatchedTypes(const SCEV *LHS,
const SCEV *RHS,
bool Sequential) {
SmallVector<const SCEV *, 2> Ops = { LHS, RHS };
return getUMinFromMismatchedTypes(Ops, Sequential);
}
const SCEV *
ScalarEvolution::getUMinFromMismatchedTypes(SmallVectorImpl<const SCEV *> &Ops,
bool Sequential) {
assert(!Ops.empty() && "At least one operand must be!");
// Trivial case.
if (Ops.size() == 1)
return Ops[0];
// Find the max type first.
Type *MaxType = nullptr;
for (const auto *S : Ops)
if (MaxType)
MaxType = getWiderType(MaxType, S->getType());
else
MaxType = S->getType();
assert(MaxType && "Failed to find maximum type!");
// Extend all ops to max type.
SmallVector<const SCEV *, 2> PromotedOps;
for (const auto *S : Ops)
PromotedOps.push_back(getNoopOrZeroExtend(S, MaxType));
// Generate umin.
return getUMinExpr(PromotedOps, Sequential);
}
const SCEV *ScalarEvolution::getPointerBase(const SCEV *V) {
// A pointer operand may evaluate to a nonpointer expression, such as null.
if (!V->getType()->isPointerTy())
return V;
while (true) {
if (auto *AddRec = dyn_cast<SCEVAddRecExpr>(V)) {
V = AddRec->getStart();
} else if (auto *Add = dyn_cast<SCEVAddExpr>(V)) {
const SCEV *PtrOp = nullptr;
for (const SCEV *AddOp : Add->operands()) {
if (AddOp->getType()->isPointerTy()) {
assert(!PtrOp && "Cannot have multiple pointer ops");
PtrOp = AddOp;
}
}
assert(PtrOp && "Must have pointer op");
V = PtrOp;
} else // Not something we can look further into.
return V;
}
}
/// Push users of the given Instruction onto the given Worklist.
static void PushDefUseChildren(Instruction *I,
SmallVectorImpl<Instruction *> &Worklist,
SmallPtrSetImpl<Instruction *> &Visited) {
// Push the def-use children onto the Worklist stack.
for (User *U : I->users()) {
auto *UserInsn = cast<Instruction>(U);
if (Visited.insert(UserInsn).second)
Worklist.push_back(UserInsn);
}
}
namespace {
/// Takes SCEV S and Loop L. For each AddRec sub-expression, use its start
/// expression in case its Loop is L. If it is not L then
/// if IgnoreOtherLoops is true then use AddRec itself
/// otherwise rewrite cannot be done.
/// If SCEV contains non-invariant unknown SCEV rewrite cannot be done.
class SCEVInitRewriter : public SCEVRewriteVisitor<SCEVInitRewriter> {
public:
static const SCEV *rewrite(const SCEV *S, const Loop *L, ScalarEvolution &SE,
bool IgnoreOtherLoops = true) {
SCEVInitRewriter Rewriter(L, SE);
const SCEV *Result = Rewriter.visit(S);
if (Rewriter.hasSeenLoopVariantSCEVUnknown())
return SE.getCouldNotCompute();
return Rewriter.hasSeenOtherLoops() && !IgnoreOtherLoops
? SE.getCouldNotCompute()
: Result;
}
const SCEV *visitUnknown(const SCEVUnknown *Expr) {
if (!SE.isLoopInvariant(Expr, L))
SeenLoopVariantSCEVUnknown = true;
return Expr;
}
const SCEV *visitAddRecExpr(const SCEVAddRecExpr *Expr) {
// Only re-write AddRecExprs for this loop.
if (Expr->getLoop() == L)
return Expr->getStart();
SeenOtherLoops = true;
return Expr;
}
bool hasSeenLoopVariantSCEVUnknown() { return SeenLoopVariantSCEVUnknown; }
bool hasSeenOtherLoops() { return SeenOtherLoops; }
private:
explicit SCEVInitRewriter(const Loop *L, ScalarEvolution &SE)
: SCEVRewriteVisitor(SE), L(L) {}
const Loop *L;
bool SeenLoopVariantSCEVUnknown = false;
bool SeenOtherLoops = false;
};
/// Takes SCEV S and Loop L. For each AddRec sub-expression, use its post
/// increment expression in case its Loop is L. If it is not L then
/// use AddRec itself.
/// If SCEV contains non-invariant unknown SCEV rewrite cannot be done.
class SCEVPostIncRewriter : public SCEVRewriteVisitor<SCEVPostIncRewriter> {
public:
static const SCEV *rewrite(const SCEV *S, const Loop *L, ScalarEvolution &SE) {
SCEVPostIncRewriter Rewriter(L, SE);
const SCEV *Result = Rewriter.visit(S);
return Rewriter.hasSeenLoopVariantSCEVUnknown()
? SE.getCouldNotCompute()
: Result;
}
const SCEV *visitUnknown(const SCEVUnknown *Expr) {
if (!SE.isLoopInvariant(Expr, L))
SeenLoopVariantSCEVUnknown = true;
return Expr;
}
const SCEV *visitAddRecExpr(const SCEVAddRecExpr *Expr) {
// Only re-write AddRecExprs for this loop.
if (Expr->getLoop() == L)
return Expr->getPostIncExpr(SE);
SeenOtherLoops = true;
return Expr;
}
bool hasSeenLoopVariantSCEVUnknown() { return SeenLoopVariantSCEVUnknown; }
bool hasSeenOtherLoops() { return SeenOtherLoops; }
private:
explicit SCEVPostIncRewriter(const Loop *L, ScalarEvolution &SE)
: SCEVRewriteVisitor(SE), L(L) {}
const Loop *L;
bool SeenLoopVariantSCEVUnknown = false;
bool SeenOtherLoops = false;
};
/// This class evaluates the compare condition by matching it against the
/// condition of loop latch. If there is a match we assume a true value
/// for the condition while building SCEV nodes.
class SCEVBackedgeConditionFolder
: public SCEVRewriteVisitor<SCEVBackedgeConditionFolder> {
public:
static const SCEV *rewrite(const SCEV *S, const Loop *L,
ScalarEvolution &SE) {
bool IsPosBECond = false;
Value *BECond = nullptr;
if (BasicBlock *Latch = L->getLoopLatch()) {
BranchInst *BI = dyn_cast<BranchInst>(Latch->getTerminator());
if (BI && BI->isConditional()) {
assert(BI->getSuccessor(0) != BI->getSuccessor(1) &&
"Both outgoing branches should not target same header!");
BECond = BI->getCondition();
IsPosBECond = BI->getSuccessor(0) == L->getHeader();
} else {
return S;
}
}
SCEVBackedgeConditionFolder Rewriter(L, BECond, IsPosBECond, SE);
return Rewriter.visit(S);
}
const SCEV *visitUnknown(const SCEVUnknown *Expr) {
const SCEV *Result = Expr;
bool InvariantF = SE.isLoopInvariant(Expr, L);
if (!InvariantF) {
Instruction *I = cast<Instruction>(Expr->getValue());
switch (I->getOpcode()) {
case Instruction::Select: {
SelectInst *SI = cast<SelectInst>(I);
Optional<const SCEV *> Res =
compareWithBackedgeCondition(SI->getCondition());
if (Res) {
bool IsOne = cast<SCEVConstant>(Res.value())->getValue()->isOne();
Result = SE.getSCEV(IsOne ? SI->getTrueValue() : SI->getFalseValue());
}
break;
}
default: {
Optional<const SCEV *> Res = compareWithBackedgeCondition(I);
if (Res)
Result = Res.value();
break;
}
}
}
return Result;
}
private:
explicit SCEVBackedgeConditionFolder(const Loop *L, Value *BECond,
bool IsPosBECond, ScalarEvolution &SE)
: SCEVRewriteVisitor(SE), L(L), BackedgeCond(BECond),
IsPositiveBECond(IsPosBECond) {}
Optional<const SCEV *> compareWithBackedgeCondition(Value *IC);
const Loop *L;
/// Loop back condition.
Value *BackedgeCond = nullptr;
/// Set to true if loop back is on positive branch condition.
bool IsPositiveBECond;
};
Optional<const SCEV *>
SCEVBackedgeConditionFolder::compareWithBackedgeCondition(Value *IC) {
// If value matches the backedge condition for loop latch,
// then return a constant evolution node based on loopback
// branch taken.
if (BackedgeCond == IC)
return IsPositiveBECond ? SE.getOne(Type::getInt1Ty(SE.getContext()))
: SE.getZero(Type::getInt1Ty(SE.getContext()));
return None;
}
class SCEVShiftRewriter : public SCEVRewriteVisitor<SCEVShiftRewriter> {
public:
static const SCEV *rewrite(const SCEV *S, const Loop *L,
ScalarEvolution &SE) {
SCEVShiftRewriter Rewriter(L, SE);
const SCEV *Result = Rewriter.visit(S);
return Rewriter.isValid() ? Result : SE.getCouldNotCompute();
}
const SCEV *visitUnknown(const SCEVUnknown *Expr) {
// Only allow AddRecExprs for this loop.
if (!SE.isLoopInvariant(Expr, L))
Valid = false;
return Expr;
}
const SCEV *visitAddRecExpr(const SCEVAddRecExpr *Expr) {
if (Expr->getLoop() == L && Expr->isAffine())
return SE.getMinusSCEV(Expr, Expr->getStepRecurrence(SE));
Valid = false;
return Expr;
}
bool isValid() { return Valid; }
private:
explicit SCEVShiftRewriter(const Loop *L, ScalarEvolution &SE)
: SCEVRewriteVisitor(SE), L(L) {}
const Loop *L;
bool Valid = true;
};
} // end anonymous namespace
SCEV::NoWrapFlags
ScalarEvolution::proveNoWrapViaConstantRanges(const SCEVAddRecExpr *AR) {
if (!AR->isAffine())
return SCEV::FlagAnyWrap;
using OBO = OverflowingBinaryOperator;
SCEV::NoWrapFlags Result = SCEV::FlagAnyWrap;
if (!AR->hasNoSignedWrap()) {
ConstantRange AddRecRange = getSignedRange(AR);
ConstantRange IncRange = getSignedRange(AR->getStepRecurrence(*this));
auto NSWRegion = ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, IncRange, OBO::NoSignedWrap);
if (NSWRegion.contains(AddRecRange))
Result = ScalarEvolution::setFlags(Result, SCEV::FlagNSW);
}
if (!AR->hasNoUnsignedWrap()) {
ConstantRange AddRecRange = getUnsignedRange(AR);
ConstantRange IncRange = getUnsignedRange(AR->getStepRecurrence(*this));
auto NUWRegion = ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, IncRange, OBO::NoUnsignedWrap);
if (NUWRegion.contains(AddRecRange))
Result = ScalarEvolution::setFlags(Result, SCEV::FlagNUW);
}
return Result;
}
SCEV::NoWrapFlags
ScalarEvolution::proveNoSignedWrapViaInduction(const SCEVAddRecExpr *AR) {
SCEV::NoWrapFlags Result = AR->getNoWrapFlags();
if (AR->hasNoSignedWrap())
return Result;
if (!AR->isAffine())
return Result;
const SCEV *Step = AR->getStepRecurrence(*this);
const Loop *L = AR->getLoop();
// Check whether the backedge-taken count is SCEVCouldNotCompute.
// Note that this serves two purposes: It filters out loops that are
// simply not analyzable, and it covers the case where this code is
// being called from within backedge-taken count analysis, such that
// attempting to ask for the backedge-taken count would likely result
// in infinite recursion. In the later case, the analysis code will
// cope with a conservative value, and it will take care to purge
// that value once it has finished.
const SCEV *MaxBECount = getConstantMaxBackedgeTakenCount(L);
// Normally, in the cases we can prove no-overflow via a
// backedge guarding condition, we can also compute a backedge
// taken count for the loop. The exceptions are assumptions and
// guards present in the loop -- SCEV is not great at exploiting
// these to compute max backedge taken counts, but can still use
// these to prove lack of overflow. Use this fact to avoid
// doing extra work that may not pay off.
if (isa<SCEVCouldNotCompute>(MaxBECount) && !HasGuards &&
AC.assumptions().empty())
return Result;
// If the backedge is guarded by a comparison with the pre-inc value the
// addrec is safe. Also, if the entry is guarded by a comparison with the
// start value and the backedge is guarded by a comparison with the post-inc
// value, the addrec is safe.
ICmpInst::Predicate Pred;
const SCEV *OverflowLimit =
getSignedOverflowLimitForStep(Step, &Pred, this);
if (OverflowLimit &&
(isLoopBackedgeGuardedByCond(L, Pred, AR, OverflowLimit) ||
isKnownOnEveryIteration(Pred, AR, OverflowLimit))) {
Result = setFlags(Result, SCEV::FlagNSW);
}
return Result;
}
SCEV::NoWrapFlags
ScalarEvolution::proveNoUnsignedWrapViaInduction(const SCEVAddRecExpr *AR) {
SCEV::NoWrapFlags Result = AR->getNoWrapFlags();
if (AR->hasNoUnsignedWrap())
return Result;
if (!AR->isAffine())
return Result;
const SCEV *Step = AR->getStepRecurrence(*this);
unsigned BitWidth = getTypeSizeInBits(AR->getType());
const Loop *L = AR->getLoop();
// Check whether the backedge-taken count is SCEVCouldNotCompute.
// Note that this serves two purposes: It filters out loops that are
// simply not analyzable, and it covers the case where this code is
// being called from within backedge-taken count analysis, such that
// attempting to ask for the backedge-taken count would likely result
// in infinite recursion. In the later case, the analysis code will
// cope with a conservative value, and it will take care to purge
// that value once it has finished.
const SCEV *MaxBECount = getConstantMaxBackedgeTakenCount(L);
// Normally, in the cases we can prove no-overflow via a
// backedge guarding condition, we can also compute a backedge
// taken count for the loop. The exceptions are assumptions and
// guards present in the loop -- SCEV is not great at exploiting
// these to compute max backedge taken counts, but can still use
// these to prove lack of overflow. Use this fact to avoid
// doing extra work that may not pay off.
if (isa<SCEVCouldNotCompute>(MaxBECount) && !HasGuards &&
AC.assumptions().empty())
return Result;
// If the backedge is guarded by a comparison with the pre-inc value the
// addrec is safe. Also, if the entry is guarded by a comparison with the
// start value and the backedge is guarded by a comparison with the post-inc
// value, the addrec is safe.
if (isKnownPositive(Step)) {
const SCEV *N = getConstant(APInt::getMinValue(BitWidth) -
getUnsignedRangeMax(Step));
if (isLoopBackedgeGuardedByCond(L, ICmpInst::ICMP_ULT, AR, N) ||
isKnownOnEveryIteration(ICmpInst::ICMP_ULT, AR, N)) {
Result = setFlags(Result, SCEV::FlagNUW);
}
}
return Result;
}
namespace {
/// Represents an abstract binary operation. This may exist as a
/// normal instruction or constant expression, or may have been
/// derived from an expression tree.
struct BinaryOp {
unsigned Opcode;
Value *LHS;
Value *RHS;
bool IsNSW = false;
bool IsNUW = false;
/// Op is set if this BinaryOp corresponds to a concrete LLVM instruction or
/// constant expression.
Operator *Op = nullptr;
explicit BinaryOp(Operator *Op)
: Opcode(Op->getOpcode()), LHS(Op->getOperand(0)), RHS(Op->getOperand(1)),
Op(Op) {
if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(Op)) {
IsNSW = OBO->hasNoSignedWrap();
IsNUW = OBO->hasNoUnsignedWrap();
}
}
explicit BinaryOp(unsigned Opcode, Value *LHS, Value *RHS, bool IsNSW = false,
bool IsNUW = false)
: Opcode(Opcode), LHS(LHS), RHS(RHS), IsNSW(IsNSW), IsNUW(IsNUW) {}
};
} // end anonymous namespace
/// Try to map \p V into a BinaryOp, and return \c None on failure.
static Optional<BinaryOp> MatchBinaryOp(Value *V, DominatorTree &DT) {
auto *Op = dyn_cast<Operator>(V);
if (!Op)
return None;
// Implementation detail: all the cleverness here should happen without
// creating new SCEV expressions -- our caller knowns tricks to avoid creating
// SCEV expressions when possible, and we should not break that.
switch (Op->getOpcode()) {
case Instruction::Add:
case Instruction::Sub:
case Instruction::Mul:
case Instruction::UDiv:
case Instruction::URem:
case Instruction::And:
case Instruction::Or:
case Instruction::AShr:
case Instruction::Shl:
return BinaryOp(Op);
case Instruction::Xor:
if (auto *RHSC = dyn_cast<ConstantInt>(Op->getOperand(1)))
// If the RHS of the xor is a signmask, then this is just an add.
// Instcombine turns add of signmask into xor as a strength reduction step.
if (RHSC->getValue().isSignMask())
return BinaryOp(Instruction::Add, Op->getOperand(0), Op->getOperand(1));
// Binary `xor` is a bit-wise `add`.
if (V->getType()->isIntegerTy(1))
return BinaryOp(Instruction::Add, Op->getOperand(0), Op->getOperand(1));
return BinaryOp(Op);
case Instruction::LShr:
// Turn logical shift right of a constant into a unsigned divide.
if (ConstantInt *SA = dyn_cast<ConstantInt>(Op->getOperand(1))) {
uint32_t BitWidth = cast<IntegerType>(Op->getType())->getBitWidth();
// If the shift count is not less than the bitwidth, the result of
// the shift is undefined. Don't try to analyze it, because the
// resolution chosen here may differ from the resolution chosen in
// other parts of the compiler.
if (SA->getValue().ult(BitWidth)) {
Constant *X =
ConstantInt::get(SA->getContext(),
APInt::getOneBitSet(BitWidth, SA->getZExtValue()));
return BinaryOp(Instruction::UDiv, Op->getOperand(0), X);
}
}
return BinaryOp(Op);
case Instruction::ExtractValue: {
auto *EVI = cast<ExtractValueInst>(Op);
if (EVI->getNumIndices() != 1 || EVI->getIndices()[0] != 0)
break;
auto *WO = dyn_cast<WithOverflowInst>(EVI->getAggregateOperand());
if (!WO)
break;
Instruction::BinaryOps BinOp = WO->getBinaryOp();
bool Signed = WO->isSigned();
// TODO: Should add nuw/nsw flags for mul as well.
if (BinOp == Instruction::Mul || !isOverflowIntrinsicNoWrap(WO, DT))
return BinaryOp(BinOp, WO->getLHS(), WO->getRHS());
// Now that we know that all uses of the arithmetic-result component of
// CI are guarded by the overflow check, we can go ahead and pretend
// that the arithmetic is non-overflowing.
return BinaryOp(BinOp, WO->getLHS(), WO->getRHS(),
/* IsNSW = */ Signed, /* IsNUW = */ !Signed);
}
default:
break;
}
// Recognise intrinsic loop.decrement.reg, and as this has exactly the same
// semantics as a Sub, return a binary sub expression.
if (auto *II = dyn_cast<IntrinsicInst>(V))
if (II->getIntrinsicID() == Intrinsic::loop_decrement_reg)
return BinaryOp(Instruction::Sub, II->getOperand(0), II->getOperand(1));
return None;
}
/// Helper function to createAddRecFromPHIWithCasts. We have a phi
/// node whose symbolic (unknown) SCEV is \p SymbolicPHI, which is updated via
/// the loop backedge by a SCEVAddExpr, possibly also with a few casts on the
/// way. This function checks if \p Op, an operand of this SCEVAddExpr,
/// follows one of the following patterns:
/// Op == (SExt ix (Trunc iy (%SymbolicPHI) to ix) to iy)
/// Op == (ZExt ix (Trunc iy (%SymbolicPHI) to ix) to iy)
/// If the SCEV expression of \p Op conforms with one of the expected patterns
/// we return the type of the truncation operation, and indicate whether the
/// truncated type should be treated as signed/unsigned by setting
/// \p Signed to true/false, respectively.
static Type *isSimpleCastedPHI(const SCEV *Op, const SCEVUnknown *SymbolicPHI,
bool &Signed, ScalarEvolution &SE) {
// The case where Op == SymbolicPHI (that is, with no type conversions on
// the way) is handled by the regular add recurrence creating logic and
// would have already been triggered in createAddRecForPHI. Reaching it here
// means that createAddRecFromPHI had failed for this PHI before (e.g.,
// because one of the other operands of the SCEVAddExpr updating this PHI is
// not invariant).
//
// Here we look for the case where Op = (ext(trunc(SymbolicPHI))), and in
// this case predicates that allow us to prove that Op == SymbolicPHI will
// be added.
if (Op == SymbolicPHI)
return nullptr;
unsigned SourceBits = SE.getTypeSizeInBits(SymbolicPHI->getType());
unsigned NewBits = SE.getTypeSizeInBits(Op->getType());
if (SourceBits != NewBits)
return nullptr;
const SCEVSignExtendExpr *SExt = dyn_cast<SCEVSignExtendExpr>(Op);
const SCEVZeroExtendExpr *ZExt = dyn_cast<SCEVZeroExtendExpr>(Op);
if (!SExt && !ZExt)
return nullptr;
const SCEVTruncateExpr *Trunc =
SExt ? dyn_cast<SCEVTruncateExpr>(SExt->getOperand())
: dyn_cast<SCEVTruncateExpr>(ZExt->getOperand());
if (!Trunc)
return nullptr;
const SCEV *X = Trunc->getOperand();
if (X != SymbolicPHI)
return nullptr;
Signed = SExt != nullptr;
return Trunc->getType();
}
static const Loop *isIntegerLoopHeaderPHI(const PHINode *PN, LoopInfo &LI) {
if (!PN->getType()->isIntegerTy())
return nullptr;
const Loop *L = LI.getLoopFor(PN->getParent());
if (!L || L->getHeader() != PN->getParent())
return nullptr;
return L;
}
// Analyze \p SymbolicPHI, a SCEV expression of a phi node, and check if the
// computation that updates the phi follows the following pattern:
// (SExt/ZExt ix (Trunc iy (%SymbolicPHI) to ix) to iy) + InvariantAccum
// which correspond to a phi->trunc->sext/zext->add->phi update chain.
// If so, try to see if it can be rewritten as an AddRecExpr under some
// Predicates. If successful, return them as a pair. Also cache the results
// of the analysis.
//
// Example usage scenario:
// Say the Rewriter is called for the following SCEV:
// 8 * ((sext i32 (trunc i64 %X to i32) to i64) + %Step)
// where:
// %X = phi i64 (%Start, %BEValue)
// It will visitMul->visitAdd->visitSExt->visitTrunc->visitUnknown(%X),
// and call this function with %SymbolicPHI = %X.
//
// The analysis will find that the value coming around the backedge has
// the following SCEV:
// BEValue = ((sext i32 (trunc i64 %X to i32) to i64) + %Step)
// Upon concluding that this matches the desired pattern, the function
// will return the pair {NewAddRec, SmallPredsVec} where:
// NewAddRec = {%Start,+,%Step}
// SmallPredsVec = {P1, P2, P3} as follows:
// P1(WrapPred): AR: {trunc(%Start),+,(trunc %Step)}<nsw> Flags: <nssw>
// P2(EqualPred): %Start == (sext i32 (trunc i64 %Start to i32) to i64)
// P3(EqualPred): %Step == (sext i32 (trunc i64 %Step to i32) to i64)
// The returned pair means that SymbolicPHI can be rewritten into NewAddRec
// under the predicates {P1,P2,P3}.
// This predicated rewrite will be cached in PredicatedSCEVRewrites:
// PredicatedSCEVRewrites[{%X,L}] = {NewAddRec, {P1,P2,P3)}
//
// TODO's:
//
// 1) Extend the Induction descriptor to also support inductions that involve
// casts: When needed (namely, when we are called in the context of the
// vectorizer induction analysis), a Set of cast instructions will be
// populated by this method, and provided back to isInductionPHI. This is
// needed to allow the vectorizer to properly record them to be ignored by
// the cost model and to avoid vectorizing them (otherwise these casts,
// which are redundant under the runtime overflow checks, will be
// vectorized, which can be costly).
//
// 2) Support additional induction/PHISCEV patterns: We also want to support
// inductions where the sext-trunc / zext-trunc operations (partly) occur
// after the induction update operation (the induction increment):
//
// (Trunc iy (SExt/ZExt ix (%SymbolicPHI + InvariantAccum) to iy) to ix)
// which correspond to a phi->add->trunc->sext/zext->phi update chain.
//
// (Trunc iy ((SExt/ZExt ix (%SymbolicPhi) to iy) + InvariantAccum) to ix)
// which correspond to a phi->trunc->add->sext/zext->phi update chain.
//
// 3) Outline common code with createAddRecFromPHI to avoid duplication.
Optional<std::pair<const SCEV *, SmallVector<const SCEVPredicate *, 3>>>
ScalarEvolution::createAddRecFromPHIWithCastsImpl(const SCEVUnknown *SymbolicPHI) {
SmallVector<const SCEVPredicate *, 3> Predicates;
// *** Part1: Analyze if we have a phi-with-cast pattern for which we can
// return an AddRec expression under some predicate.
auto *PN = cast<PHINode>(SymbolicPHI->getValue());
const Loop *L = isIntegerLoopHeaderPHI(PN, LI);
assert(L && "Expecting an integer loop header phi");
// The loop may have multiple entrances or multiple exits; we can analyze
// this phi as an addrec if it has a unique entry value and a unique
// backedge value.
Value *BEValueV = nullptr, *StartValueV = nullptr;
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
Value *V = PN->getIncomingValue(i);
if (L->contains(PN->getIncomingBlock(i))) {
if (!BEValueV) {
BEValueV = V;
} else if (BEValueV != V) {
BEValueV = nullptr;
break;
}
} else if (!StartValueV) {
StartValueV = V;
} else if (StartValueV != V) {
StartValueV = nullptr;
break;
}
}
if (!BEValueV || !StartValueV)
return None;
const SCEV *BEValue = getSCEV(BEValueV);
// If the value coming around the backedge is an add with the symbolic
// value we just inserted, possibly with casts that we can ignore under
// an appropriate runtime guard, then we found a simple induction variable!
const auto *Add = dyn_cast<SCEVAddExpr>(BEValue);
if (!Add)
return None;
// If there is a single occurrence of the symbolic value, possibly
// casted, replace it with a recurrence.
unsigned FoundIndex = Add->getNumOperands();
Type *TruncTy = nullptr;
bool Signed;
for (unsigned i = 0, e = Add->getNumOperands(); i != e; ++i)
if ((TruncTy =
isSimpleCastedPHI(Add->getOperand(i), SymbolicPHI, Signed, *this)))
if (FoundIndex == e) {
FoundIndex = i;
break;
}
if (FoundIndex == Add->getNumOperands())
return None;
// Create an add with everything but the specified operand.
SmallVector<const SCEV *, 8> Ops;
for (unsigned i = 0, e = Add->getNumOperands(); i != e; ++i)
if (i != FoundIndex)
Ops.push_back(Add->getOperand(i));
const SCEV *Accum = getAddExpr(Ops);
// The runtime checks will not be valid if the step amount is
// varying inside the loop.
if (!isLoopInvariant(Accum, L))
return None;
// *** Part2: Create the predicates
// Analysis was successful: we have a phi-with-cast pattern for which we
// can return an AddRec expression under the following predicates:
//
// P1: A Wrap predicate that guarantees that Trunc(Start) + i*Trunc(Accum)
// fits within the truncated type (does not overflow) for i = 0 to n-1.
// P2: An Equal predicate that guarantees that
// Start = (Ext ix (Trunc iy (Start) to ix) to iy)
// P3: An Equal predicate that guarantees that
// Accum = (Ext ix (Trunc iy (Accum) to ix) to iy)
//
// As we next prove, the above predicates guarantee that:
// Start + i*Accum = (Ext ix (Trunc iy ( Start + i*Accum ) to ix) to iy)
//
//
// More formally, we want to prove that:
// Expr(i+1) = Start + (i+1) * Accum
// = (Ext ix (Trunc iy (Expr(i)) to ix) to iy) + Accum
//
// Given that:
// 1) Expr(0) = Start
// 2) Expr(1) = Start + Accum
// = (Ext ix (Trunc iy (Start) to ix) to iy) + Accum :: from P2
// 3) Induction hypothesis (step i):
// Expr(i) = (Ext ix (Trunc iy (Expr(i-1)) to ix) to iy) + Accum
//
// Proof:
// Expr(i+1) =
// = Start + (i+1)*Accum
// = (Start + i*Accum) + Accum
// = Expr(i) + Accum
// = (Ext ix (Trunc iy (Expr(i-1)) to ix) to iy) + Accum + Accum
// :: from step i
//
// = (Ext ix (Trunc iy (Start + (i-1)*Accum) to ix) to iy) + Accum + Accum
//
// = (Ext ix (Trunc iy (Start + (i-1)*Accum) to ix) to iy)
// + (Ext ix (Trunc iy (Accum) to ix) to iy)
// + Accum :: from P3
//
// = (Ext ix (Trunc iy ((Start + (i-1)*Accum) + Accum) to ix) to iy)
// + Accum :: from P1: Ext(x)+Ext(y)=>Ext(x+y)
//
// = (Ext ix (Trunc iy (Start + i*Accum) to ix) to iy) + Accum
// = (Ext ix (Trunc iy (Expr(i)) to ix) to iy) + Accum
//
// By induction, the same applies to all iterations 1<=i<n:
//
// Create a truncated addrec for which we will add a no overflow check (P1).
const SCEV *StartVal = getSCEV(StartValueV);
const SCEV *PHISCEV =
getAddRecExpr(getTruncateExpr(StartVal, TruncTy),
getTruncateExpr(Accum, TruncTy), L, SCEV::FlagAnyWrap);
// PHISCEV can be either a SCEVConstant or a SCEVAddRecExpr.
// ex: If truncated Accum is 0 and StartVal is a constant, then PHISCEV
// will be constant.
//
// If PHISCEV is a constant, then P1 degenerates into P2 or P3, so we don't
// add P1.
if (const auto *AR = dyn_cast<SCEVAddRecExpr>(PHISCEV)) {
SCEVWrapPredicate::IncrementWrapFlags AddedFlags =
Signed ? SCEVWrapPredicate::IncrementNSSW
: SCEVWrapPredicate::IncrementNUSW;
const SCEVPredicate *AddRecPred = getWrapPredicate(AR, AddedFlags);
Predicates.push_back(AddRecPred);
}
// Create the Equal Predicates P2,P3:
// It is possible that the predicates P2 and/or P3 are computable at
// compile time due to StartVal and/or Accum being constants.
// If either one is, then we can check that now and escape if either P2
// or P3 is false.
// Construct the extended SCEV: (Ext ix (Trunc iy (Expr) to ix) to iy)
// for each of StartVal and Accum
auto getExtendedExpr = [&](const SCEV *Expr,
bool CreateSignExtend) -> const SCEV * {
assert(isLoopInvariant(Expr, L) && "Expr is expected to be invariant");
const SCEV *TruncatedExpr = getTruncateExpr(Expr, TruncTy);
const SCEV *ExtendedExpr =
CreateSignExtend ? getSignExtendExpr(TruncatedExpr, Expr->getType())
: getZeroExtendExpr(TruncatedExpr, Expr->getType());
return ExtendedExpr;
};
// Given:
// ExtendedExpr = (Ext ix (Trunc iy (Expr) to ix) to iy
// = getExtendedExpr(Expr)
// Determine whether the predicate P: Expr == ExtendedExpr
// is known to be false at compile time
auto PredIsKnownFalse = [&](const SCEV *Expr,
const SCEV *ExtendedExpr) -> bool {
return Expr != ExtendedExpr &&
isKnownPredicate(ICmpInst::ICMP_NE, Expr, ExtendedExpr);
};
const SCEV *StartExtended = getExtendedExpr(StartVal, Signed);
if (PredIsKnownFalse(StartVal, StartExtended)) {
LLVM_DEBUG(dbgs() << "P2 is compile-time false\n";);
return None;
}
// The Step is always Signed (because the overflow checks are either
// NSSW or NUSW)
const SCEV *AccumExtended = getExtendedExpr(Accum, /*CreateSignExtend=*/true);
if (PredIsKnownFalse(Accum, AccumExtended)) {
LLVM_DEBUG(dbgs() << "P3 is compile-time false\n";);
return None;
}
auto AppendPredicate = [&](const SCEV *Expr,
const SCEV *ExtendedExpr) -> void {
if (Expr != ExtendedExpr &&
!isKnownPredicate(ICmpInst::ICMP_EQ, Expr, ExtendedExpr)) {
const SCEVPredicate *Pred = getEqualPredicate(Expr, ExtendedExpr);
LLVM_DEBUG(dbgs() << "Added Predicate: " << *Pred);
Predicates.push_back(Pred);
}
};
AppendPredicate(StartVal, StartExtended);
AppendPredicate(Accum, AccumExtended);
// *** Part3: Predicates are ready. Now go ahead and create the new addrec in
// which the casts had been folded away. The caller can rewrite SymbolicPHI
// into NewAR if it will also add the runtime overflow checks specified in
// Predicates.
auto *NewAR = getAddRecExpr(StartVal, Accum, L, SCEV::FlagAnyWrap);
std::pair<const SCEV *, SmallVector<const SCEVPredicate *, 3>> PredRewrite =
std::make_pair(NewAR, Predicates);
// Remember the result of the analysis for this SCEV at this locayyytion.
PredicatedSCEVRewrites[{SymbolicPHI, L}] = PredRewrite;
return PredRewrite;
}
Optional<std::pair<const SCEV *, SmallVector<const SCEVPredicate *, 3>>>
ScalarEvolution::createAddRecFromPHIWithCasts(const SCEVUnknown *SymbolicPHI) {
auto *PN = cast<PHINode>(SymbolicPHI->getValue());
const Loop *L = isIntegerLoopHeaderPHI(PN, LI);
if (!L)
return None;
// Check to see if we already analyzed this PHI.
auto I = PredicatedSCEVRewrites.find({SymbolicPHI, L});
if (I != PredicatedSCEVRewrites.end()) {
std::pair<const SCEV *, SmallVector<const SCEVPredicate *, 3>> Rewrite =
I->second;
// Analysis was done before and failed to create an AddRec:
if (Rewrite.first == SymbolicPHI)
return None;
// Analysis was done before and succeeded to create an AddRec under
// a predicate:
assert(isa<SCEVAddRecExpr>(Rewrite.first) && "Expected an AddRec");
assert(!(Rewrite.second).empty() && "Expected to find Predicates");
return Rewrite;
}
Optional<std::pair<const SCEV *, SmallVector<const SCEVPredicate *, 3>>>
Rewrite = createAddRecFromPHIWithCastsImpl(SymbolicPHI);
// Record in the cache that the analysis failed
if (!Rewrite) {
SmallVector<const SCEVPredicate *, 3> Predicates;
PredicatedSCEVRewrites[{SymbolicPHI, L}] = {SymbolicPHI, Predicates};
return None;
}
return Rewrite;
}
// FIXME: This utility is currently required because the Rewriter currently
// does not rewrite this expression:
// {0, +, (sext ix (trunc iy to ix) to iy)}
// into {0, +, %step},
// even when the following Equal predicate exists:
// "%step == (sext ix (trunc iy to ix) to iy)".
bool PredicatedScalarEvolution::areAddRecsEqualWithPreds(
const SCEVAddRecExpr *AR1, const SCEVAddRecExpr *AR2) const {
if (AR1 == AR2)
return true;
auto areExprsEqual = [&](const SCEV *Expr1, const SCEV *Expr2) -> bool {
if (Expr1 != Expr2 && !Preds->implies(SE.getEqualPredicate(Expr1, Expr2)) &&
!Preds->implies(SE.getEqualPredicate(Expr2, Expr1)))
return false;
return true;
};
if (!areExprsEqual(AR1->getStart(), AR2->getStart()) ||
!areExprsEqual(AR1->getStepRecurrence(SE), AR2->getStepRecurrence(SE)))
return false;
return true;
}
/// A helper function for createAddRecFromPHI to handle simple cases.
///
/// This function tries to find an AddRec expression for the simplest (yet most
/// common) cases: PN = PHI(Start, OP(Self, LoopInvariant)).
/// If it fails, createAddRecFromPHI will use a more general, but slow,
/// technique for finding the AddRec expression.
const SCEV *ScalarEvolution::createSimpleAffineAddRec(PHINode *PN,
Value *BEValueV,
Value *StartValueV) {
const Loop *L = LI.getLoopFor(PN->getParent());
assert(L && L->getHeader() == PN->getParent());
assert(BEValueV && StartValueV);
auto BO = MatchBinaryOp(BEValueV, DT);
if (!BO)
return nullptr;
if (BO->Opcode != Instruction::Add)
return nullptr;
const SCEV *Accum = nullptr;
if (BO->LHS == PN && L->isLoopInvariant(BO->RHS))
Accum = getSCEV(BO->RHS);
else if (BO->RHS == PN && L->isLoopInvariant(BO->LHS))
Accum = getSCEV(BO->LHS);
if (!Accum)
return nullptr;
SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap;
if (BO->IsNUW)
Flags = setFlags(Flags, SCEV::FlagNUW);
if (BO->IsNSW)
Flags = setFlags(Flags, SCEV::FlagNSW);
const SCEV *StartVal = getSCEV(StartValueV);
const SCEV *PHISCEV = getAddRecExpr(StartVal, Accum, L, Flags);
insertValueToMap(PN, PHISCEV);
// We can add Flags to the post-inc expression only if we
// know that it is *undefined behavior* for BEValueV to
// overflow.
if (auto *BEInst = dyn_cast<Instruction>(BEValueV)) {
assert(isLoopInvariant(Accum, L) &&
"Accum is defined outside L, but is not invariant?");
if (isAddRecNeverPoison(BEInst, L))
(void)getAddRecExpr(getAddExpr(StartVal, Accum), Accum, L, Flags);
}
return PHISCEV;
}
const SCEV *ScalarEvolution::createAddRecFromPHI(PHINode *PN) {
const Loop *L = LI.getLoopFor(PN->getParent());
if (!L || L->getHeader() != PN->getParent())
return nullptr;
// The loop may have multiple entrances or multiple exits; we can analyze
// this phi as an addrec if it has a unique entry value and a unique
// backedge value.
Value *BEValueV = nullptr, *StartValueV = nullptr;
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
Value *V = PN->getIncomingValue(i);
if (L->contains(PN->getIncomingBlock(i))) {
if (!BEValueV) {
BEValueV = V;
} else if (BEValueV != V) {
BEValueV = nullptr;
break;
}
} else if (!StartValueV) {
StartValueV = V;
} else if (StartValueV != V) {
StartValueV = nullptr;
break;
}
}
if (!BEValueV || !StartValueV)
return nullptr;
assert(ValueExprMap.find_as(PN) == ValueExprMap.end() &&
"PHI node already processed?");
// First, try to find AddRec expression without creating a fictituos symbolic
// value for PN.
if (auto *S = createSimpleAffineAddRec(PN, BEValueV, StartValueV))
return S;
// Handle PHI node value symbolically.
const SCEV *SymbolicName = getUnknown(PN);
insertValueToMap(PN, SymbolicName);
// Using this symbolic name for the PHI, analyze the value coming around
// the back-edge.
const SCEV *BEValue = getSCEV(BEValueV);
// NOTE: If BEValue is loop invariant, we know that the PHI node just
// has a special value for the first iteration of the loop.
// If the value coming around the backedge is an add with the symbolic
// value we just inserted, then we found a simple induction variable!
if (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(BEValue)) {
// If there is a single occurrence of the symbolic value, replace it
// with a recurrence.
unsigned FoundIndex = Add->getNumOperands();
for (unsigned i = 0, e = Add->getNumOperands(); i != e; ++i)
if (Add->getOperand(i) == SymbolicName)
if (FoundIndex == e) {
FoundIndex = i;
break;
}
if (FoundIndex != Add->getNumOperands()) {
// Create an add with everything but the specified operand.
SmallVector<const SCEV *, 8> Ops;
for (unsigned i = 0, e = Add->getNumOperands(); i != e; ++i)
if (i != FoundIndex)
Ops.push_back(SCEVBackedgeConditionFolder::rewrite(Add->getOperand(i),
L, *this));
const SCEV *Accum = getAddExpr(Ops);
// This is not a valid addrec if the step amount is varying each
// loop iteration, but is not itself an addrec in this loop.
if (isLoopInvariant(Accum, L) ||
(isa<SCEVAddRecExpr>(Accum) &&
cast<SCEVAddRecExpr>(Accum)->getLoop() == L)) {
SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap;
if (auto BO = MatchBinaryOp(BEValueV, DT)) {
if (BO->Opcode == Instruction::Add && BO->LHS == PN) {
if (BO->IsNUW)
Flags = setFlags(Flags, SCEV::FlagNUW);
if (BO->IsNSW)
Flags = setFlags(Flags, SCEV::FlagNSW);
}
} else if (GEPOperator *GEP = dyn_cast<GEPOperator>(BEValueV)) {
// If the increment is an inbounds GEP, then we know the address
// space cannot be wrapped around. We cannot make any guarantee
// about signed or unsigned overflow because pointers are
// unsigned but we may have a negative index from the base
// pointer. We can guarantee that no unsigned wrap occurs if the
// indices form a positive value.
if (GEP->isInBounds() && GEP->getOperand(0) == PN) {
Flags = setFlags(Flags, SCEV::FlagNW);
const SCEV *Ptr = getSCEV(GEP->getPointerOperand());
if (isKnownPositive(getMinusSCEV(getSCEV(GEP), Ptr)))
Flags = setFlags(Flags, SCEV::FlagNUW);
}
// We cannot transfer nuw and nsw flags from subtraction
// operations -- sub nuw X, Y is not the same as add nuw X, -Y
// for instance.
}
const SCEV *StartVal = getSCEV(StartValueV);
const SCEV *PHISCEV = getAddRecExpr(StartVal, Accum, L, Flags);
// Okay, for the entire analysis of this edge we assumed the PHI
// to be symbolic. We now need to go back and purge all of the
// entries for the scalars that use the symbolic expression.
forgetMemoizedResults(SymbolicName);
insertValueToMap(PN, PHISCEV);
// We can add Flags to the post-inc expression only if we
// know that it is *undefined behavior* for BEValueV to
// overflow.
if (auto *BEInst = dyn_cast<Instruction>(BEValueV))
if (isLoopInvariant(Accum, L) && isAddRecNeverPoison(BEInst, L))
(void)getAddRecExpr(getAddExpr(StartVal, Accum), Accum, L, Flags);
return PHISCEV;
}
}
} else {
// Otherwise, this could be a loop like this:
// i = 0; for (j = 1; ..; ++j) { .... i = j; }
// In this case, j = {1,+,1} and BEValue is j.
// Because the other in-value of i (0) fits the evolution of BEValue
// i really is an addrec evolution.
//
// We can generalize this saying that i is the shifted value of BEValue
// by one iteration:
// PHI(f(0), f({1,+,1})) --> f({0,+,1})
const SCEV *Shifted = SCEVShiftRewriter::rewrite(BEValue, L, *this);
const SCEV *Start = SCEVInitRewriter::rewrite(Shifted, L, *this, false);
if (Shifted != getCouldNotCompute() &&
Start != getCouldNotCompute()) {
const SCEV *StartVal = getSCEV(StartValueV);
if (Start == StartVal) {
// Okay, for the entire analysis of this edge we assumed the PHI
// to be symbolic. We now need to go back and purge all of the
// entries for the scalars that use the symbolic expression.
forgetMemoizedResults(SymbolicName);
insertValueToMap(PN, Shifted);
return Shifted;
}
}
}
// Remove the temporary PHI node SCEV that has been inserted while intending
// to create an AddRecExpr for this PHI node. We can not keep this temporary
// as it will prevent later (possibly simpler) SCEV expressions to be added
// to the ValueExprMap.
eraseValueFromMap(PN);
return nullptr;
}
// Checks if the SCEV S is available at BB. S is considered available at BB
// if S can be materialized at BB without introducing a fault.
static bool IsAvailableOnEntry(const Loop *L, DominatorTree &DT, const SCEV *S,
BasicBlock *BB) {
struct CheckAvailable {
bool TraversalDone = false;
bool Available = true;
const Loop *L = nullptr; // The loop BB is in (can be nullptr)
BasicBlock *BB = nullptr;
DominatorTree &DT;
CheckAvailable(const Loop *L, BasicBlock *BB, DominatorTree &DT)
: L(L), BB(BB), DT(DT) {}
bool setUnavailable() {
TraversalDone = true;
Available = false;
return false;
}
bool follow(const SCEV *S) {
switch (S->getSCEVType()) {
case scConstant:
case scPtrToInt:
case scTruncate:
case scZeroExtend:
case scSignExtend:
case scAddExpr:
case scMulExpr:
case scUMaxExpr:
case scSMaxExpr:
case scUMinExpr:
case scSMinExpr:
case scSequentialUMinExpr:
// These expressions are available if their operand(s) is/are.
return true;
case scAddRecExpr: {
// We allow add recurrences that are on the loop BB is in, or some
// outer loop. This guarantees availability because the value of the
// add recurrence at BB is simply the "current" value of the induction
// variable. We can relax this in the future; for instance an add
// recurrence on a sibling dominating loop is also available at BB.
const auto *ARLoop = cast<SCEVAddRecExpr>(S)->getLoop();
if (L && (ARLoop == L || ARLoop->contains(L)))
return true;
return setUnavailable();
}
case scUnknown: {
// For SCEVUnknown, we check for simple dominance.
const auto *SU = cast<SCEVUnknown>(S);
Value *V = SU->getValue();
if (isa<Argument>(V))
return false;
if (isa<Instruction>(V) && DT.dominates(cast<Instruction>(V), BB))
return false;
return setUnavailable();
}
case scUDivExpr:
case scCouldNotCompute:
// We do not try to smart about these at all.
return setUnavailable();
}
llvm_unreachable("Unknown SCEV kind!");
}
bool isDone() { return TraversalDone; }
};
CheckAvailable CA(L, BB, DT);
SCEVTraversal<CheckAvailable> ST(CA);
ST.visitAll(S);
return CA.Available;
}
// Try to match a control flow sequence that branches out at BI and merges back
// at Merge into a "C ? LHS : RHS" select pattern. Return true on a successful
// match.
static bool BrPHIToSelect(DominatorTree &DT, BranchInst *BI, PHINode *Merge,
Value *&C, Value *&LHS, Value *&RHS) {
C = BI->getCondition();
BasicBlockEdge LeftEdge(BI->getParent(), BI->getSuccessor(0));
BasicBlockEdge RightEdge(BI->getParent(), BI->getSuccessor(1));
if (!LeftEdge.isSingleEdge())
return false;
assert(RightEdge.isSingleEdge() && "Follows from LeftEdge.isSingleEdge()");
Use &LeftUse = Merge->getOperandUse(0);
Use &RightUse = Merge->getOperandUse(1);
if (DT.dominates(LeftEdge, LeftUse) && DT.dominates(RightEdge, RightUse)) {
LHS = LeftUse;
RHS = RightUse;
return true;
}
if (DT.dominates(LeftEdge, RightUse) && DT.dominates(RightEdge, LeftUse)) {
LHS = RightUse;
RHS = LeftUse;
return true;
}
return false;
}
const SCEV *ScalarEvolution::createNodeFromSelectLikePHI(PHINode *PN) {
auto IsReachable =
[&](BasicBlock *BB) { return DT.isReachableFromEntry(BB); };
if (PN->getNumIncomingValues() == 2 && all_of(PN->blocks(), IsReachable)) {
const Loop *L = LI.getLoopFor(PN->getParent());
// We don't want to break LCSSA, even in a SCEV expression tree.
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
if (LI.getLoopFor(PN->getIncomingBlock(i)) != L)
return nullptr;
// Try to match
//
// br %cond, label %left, label %right
// left:
// br label %merge
// right:
// br label %merge
// merge:
// V = phi [ %x, %left ], [ %y, %right ]
//
// as "select %cond, %x, %y"
BasicBlock *IDom = DT[PN->getParent()]->getIDom()->getBlock();
assert(IDom && "At least the entry block should dominate PN");
auto *BI = dyn_cast<BranchInst>(IDom->getTerminator());
Value *Cond = nullptr, *LHS = nullptr, *RHS = nullptr;
if (BI && BI->isConditional() &&
BrPHIToSelect(DT, BI, PN, Cond, LHS, RHS) &&
IsAvailableOnEntry(L, DT, getSCEV(LHS), PN->getParent()) &&
IsAvailableOnEntry(L, DT, getSCEV(RHS), PN->getParent()))
return createNodeForSelectOrPHI(PN, Cond, LHS, RHS);
}
return nullptr;
}
const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) {
if (const SCEV *S = createAddRecFromPHI(PN))
return S;
if (const SCEV *S = createNodeFromSelectLikePHI(PN))
return S;
+ // If the PHI has a single incoming value, follow that value, unless the
+ // PHI's incoming blocks are in a different loop, in which case doing so
+ // risks breaking LCSSA form. Instcombine would normally zap these, but
+ // it doesn't have DominatorTree information, so it may miss cases.
if (Value *V = simplifyInstruction(PN, {getDataLayout(), &TLI, &DT, &AC}))
- return getSCEV(V);
+ if (LI.replacementPreservesLCSSAForm(PN, V))
+ return getSCEV(V);
// If it's not a loop phi, we can't handle it yet.
return getUnknown(PN);
}
bool SCEVMinMaxExprContains(const SCEV *Root, const SCEV *OperandToFind,
SCEVTypes RootKind) {
struct FindClosure {
const SCEV *OperandToFind;
const SCEVTypes RootKind; // Must be a sequential min/max expression.
const SCEVTypes NonSequentialRootKind; // Non-seq variant of RootKind.
bool Found = false;
bool canRecurseInto(SCEVTypes Kind) const {
// We can only recurse into the SCEV expression of the same effective type
// as the type of our root SCEV expression, and into zero-extensions.
return RootKind == Kind || NonSequentialRootKind == Kind ||
scZeroExtend == Kind;
};
FindClosure(const SCEV *OperandToFind, SCEVTypes RootKind)
: OperandToFind(OperandToFind), RootKind(RootKind),
NonSequentialRootKind(
SCEVSequentialMinMaxExpr::getEquivalentNonSequentialSCEVType(
RootKind)) {}
bool follow(const SCEV *S) {
Found = S == OperandToFind;
return !isDone() && canRecurseInto(S->getSCEVType());
}
bool isDone() const { return Found; }
};
FindClosure FC(OperandToFind, RootKind);
visitAll(Root, FC);
return FC.Found;
}
const SCEV *ScalarEvolution::createNodeForSelectOrPHIInstWithICmpInstCond(
Instruction *I, ICmpInst *Cond, Value *TrueVal, Value *FalseVal) {
// Try to match some simple smax or umax patterns.
auto *ICI = Cond;
Value *LHS = ICI->getOperand(0);
Value *RHS = ICI->getOperand(1);
switch (ICI->getPredicate()) {
case ICmpInst::ICMP_SLT:
case ICmpInst::ICMP_SLE:
case ICmpInst::ICMP_ULT:
case ICmpInst::ICMP_ULE:
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ICmpInst::ICMP_SGT:
case ICmpInst::ICMP_SGE:
case ICmpInst::ICMP_UGT:
case ICmpInst::ICMP_UGE:
// a > b ? a+x : b+x -> max(a, b)+x
// a > b ? b+x : a+x -> min(a, b)+x
if (getTypeSizeInBits(LHS->getType()) <= getTypeSizeInBits(I->getType())) {
bool Signed = ICI->isSigned();
const SCEV *LA = getSCEV(TrueVal);
const SCEV *RA = getSCEV(FalseVal);
const SCEV *LS = getSCEV(LHS);
const SCEV *RS = getSCEV(RHS);
if (LA->getType()->isPointerTy()) {
// FIXME: Handle cases where LS/RS are pointers not equal to LA/RA.
// Need to make sure we can't produce weird expressions involving
// negated pointers.
if (LA == LS && RA == RS)
return Signed ? getSMaxExpr(LS, RS) : getUMaxExpr(LS, RS);
if (LA == RS && RA == LS)
return Signed ? getSMinExpr(LS, RS) : getUMinExpr(LS, RS);
}
auto CoerceOperand = [&](const SCEV *Op) -> const SCEV * {
if (Op->getType()->isPointerTy()) {
Op = getLosslessPtrToIntExpr(Op);
if (isa<SCEVCouldNotCompute>(Op))
return Op;
}
if (Signed)
Op = getNoopOrSignExtend(Op, I->getType());
else
Op = getNoopOrZeroExtend(Op, I->getType());
return Op;
};
LS = CoerceOperand(LS);
RS = CoerceOperand(RS);
if (isa<SCEVCouldNotCompute>(LS) || isa<SCEVCouldNotCompute>(RS))
break;
const SCEV *LDiff = getMinusSCEV(LA, LS);
const SCEV *RDiff = getMinusSCEV(RA, RS);
if (LDiff == RDiff)
return getAddExpr(Signed ? getSMaxExpr(LS, RS) : getUMaxExpr(LS, RS),
LDiff);
LDiff = getMinusSCEV(LA, RS);
RDiff = getMinusSCEV(RA, LS);
if (LDiff == RDiff)
return getAddExpr(Signed ? getSMinExpr(LS, RS) : getUMinExpr(LS, RS),
LDiff);
}
break;
case ICmpInst::ICMP_NE:
// x != 0 ? x+y : C+y -> x == 0 ? C+y : x+y
std::swap(TrueVal, FalseVal);
LLVM_FALLTHROUGH;
case ICmpInst::ICMP_EQ:
// x == 0 ? C+y : x+y -> umax(x, C)+y iff C u<= 1
if (getTypeSizeInBits(LHS->getType()) <= getTypeSizeInBits(I->getType()) &&
isa<ConstantInt>(RHS) && cast<ConstantInt>(RHS)->isZero()) {
const SCEV *X = getNoopOrZeroExtend(getSCEV(LHS), I->getType());
const SCEV *TrueValExpr = getSCEV(TrueVal); // C+y
const SCEV *FalseValExpr = getSCEV(FalseVal); // x+y
const SCEV *Y = getMinusSCEV(FalseValExpr, X); // y = (x+y)-x
const SCEV *C = getMinusSCEV(TrueValExpr, Y); // C = (C+y)-y
if (isa<SCEVConstant>(C) && cast<SCEVConstant>(C)->getAPInt().ule(1))
return getAddExpr(getUMaxExpr(X, C), Y);
}
// x == 0 ? 0 : umin (..., x, ...) -> umin_seq(x, umin (...))
// x == 0 ? 0 : umin_seq(..., x, ...) -> umin_seq(x, umin_seq(...))
// x == 0 ? 0 : umin (..., umin_seq(..., x, ...), ...)
// -> umin_seq(x, umin (..., umin_seq(...), ...))
if (isa<ConstantInt>(RHS) && cast<ConstantInt>(RHS)->isZero() &&
isa<ConstantInt>(TrueVal) && cast<ConstantInt>(TrueVal)->isZero()) {
const SCEV *X = getSCEV(LHS);
while (auto *ZExt = dyn_cast<SCEVZeroExtendExpr>(X))
X = ZExt->getOperand();
if (getTypeSizeInBits(X->getType()) <= getTypeSizeInBits(I->getType())) {
const SCEV *FalseValExpr = getSCEV(FalseVal);
if (SCEVMinMaxExprContains(FalseValExpr, X, scSequentialUMinExpr))
return getUMinExpr(getNoopOrZeroExtend(X, I->getType()), FalseValExpr,
/*Sequential=*/true);
}
}
break;
default:
break;
}
return getUnknown(I);
}
static Optional<const SCEV *>
createNodeForSelectViaUMinSeq(ScalarEvolution *SE, const SCEV *CondExpr,
const SCEV *TrueExpr, const SCEV *FalseExpr) {
assert(CondExpr->getType()->isIntegerTy(1) &&
TrueExpr->getType() == FalseExpr->getType() &&
TrueExpr->getType()->isIntegerTy(1) &&
"Unexpected operands of a select.");
// i1 cond ? i1 x : i1 C --> C + (i1 cond ? (i1 x - i1 C) : i1 0)
// --> C + (umin_seq cond, x - C)
//
// i1 cond ? i1 C : i1 x --> C + (i1 cond ? i1 0 : (i1 x - i1 C))
// --> C + (i1 ~cond ? (i1 x - i1 C) : i1 0)
// --> C + (umin_seq ~cond, x - C)
// FIXME: while we can't legally model the case where both of the hands
// are fully variable, we only require that the *difference* is constant.
if (!isa<SCEVConstant>(TrueExpr) && !isa<SCEVConstant>(FalseExpr))
return None;
const SCEV *X, *C;
if (isa<SCEVConstant>(TrueExpr)) {
CondExpr = SE->getNotSCEV(CondExpr);
X = FalseExpr;
C = TrueExpr;
} else {
X = TrueExpr;
C = FalseExpr;
}
return SE->getAddExpr(C, SE->getUMinExpr(CondExpr, SE->getMinusSCEV(X, C),
/*Sequential=*/true));
}
static Optional<const SCEV *> createNodeForSelectViaUMinSeq(ScalarEvolution *SE,
Value *Cond,
Value *TrueVal,
Value *FalseVal) {
if (!isa<ConstantInt>(TrueVal) && !isa<ConstantInt>(FalseVal))
return None;
const auto *SECond = SE->getSCEV(Cond);
const auto *SETrue = SE->getSCEV(TrueVal);
const auto *SEFalse = SE->getSCEV(FalseVal);
return createNodeForSelectViaUMinSeq(SE, SECond, SETrue, SEFalse);
}
const SCEV *ScalarEvolution::createNodeForSelectOrPHIViaUMinSeq(
Value *V, Value *Cond, Value *TrueVal, Value *FalseVal) {
assert(Cond->getType()->isIntegerTy(1) && "Select condition is not an i1?");
assert(TrueVal->getType() == FalseVal->getType() &&
V->getType() == TrueVal->getType() &&
"Types of select hands and of the result must match.");
// For now, only deal with i1-typed `select`s.
if (!V->getType()->isIntegerTy(1))
return getUnknown(V);
if (Optional<const SCEV *> S =
createNodeForSelectViaUMinSeq(this, Cond, TrueVal, FalseVal))
return *S;
return getUnknown(V);
}
const SCEV *ScalarEvolution::createNodeForSelectOrPHI(Value *V, Value *Cond,
Value *TrueVal,
Value *FalseVal) {
// Handle "constant" branch or select. This can occur for instance when a
// loop pass transforms an inner loop and moves on to process the outer loop.
if (auto *CI = dyn_cast<ConstantInt>(Cond))
return getSCEV(CI->isOne() ? TrueVal : FalseVal);
if (auto *I = dyn_cast<Instruction>(V)) {
if (auto *ICI = dyn_cast<ICmpInst>(Cond)) {
const SCEV *S = createNodeForSelectOrPHIInstWithICmpInstCond(
I, ICI, TrueVal, FalseVal);
if (!isa<SCEVUnknown>(S))
return S;
}
}
return createNodeForSelectOrPHIViaUMinSeq(V, Cond, TrueVal, FalseVal);
}
/// Expand GEP instructions into add and multiply operations. This allows them
/// to be analyzed by regular SCEV code.
const SCEV *ScalarEvolution::createNodeForGEP(GEPOperator *GEP) {
assert(GEP->getSourceElementType()->isSized() &&
"GEP source element type must be sized");
SmallVector<const SCEV *, 4> IndexExprs;
for (Value *Index : GEP->indices())
IndexExprs.push_back(getSCEV(Index));
return getGEPExpr(GEP, IndexExprs);
}
uint32_t ScalarEvolution::GetMinTrailingZerosImpl(const SCEV *S) {
if (const SCEVConstant *C = dyn_cast<SCEVConstant>(S))
return C->getAPInt().countTrailingZeros();
if (const SCEVPtrToIntExpr *I = dyn_cast<SCEVPtrToIntExpr>(S))
return GetMinTrailingZeros(I->getOperand());
if (const SCEVTruncateExpr *T = dyn_cast<SCEVTruncateExpr>(S))
return std::min(GetMinTrailingZeros(T->getOperand()),
(uint32_t)getTypeSizeInBits(T->getType()));
if (const SCEVZeroExtendExpr *E = dyn_cast<SCEVZeroExtendExpr>(S)) {
uint32_t OpRes = GetMinTrailingZeros(E->getOperand());
return OpRes == getTypeSizeInBits(E->getOperand()->getType())
? getTypeSizeInBits(E->getType())
: OpRes;
}
if (const SCEVSignExtendExpr *E = dyn_cast<SCEVSignExtendExpr>(S)) {
uint32_t OpRes = GetMinTrailingZeros(E->getOperand());
return OpRes == getTypeSizeInBits(E->getOperand()->getType())
? getTypeSizeInBits(E->getType())
: OpRes;
}
if (const SCEVAddExpr *A = dyn_cast<SCEVAddExpr>(S)) {
// The result is the min of all operands results.
uint32_t MinOpRes = GetMinTrailingZeros(A->getOperand(0));
for (unsigned i = 1, e = A->getNumOperands(); MinOpRes && i != e; ++i)
MinOpRes = std::min(MinOpRes, GetMinTrailingZeros(A->getOperand(i)));
return MinOpRes;
}
if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(S)) {
// The result is the sum of all operands results.
uint32_t SumOpRes = GetMinTrailingZeros(M->getOperand(0));
uint32_t BitWidth = getTypeSizeInBits(M->getType());
for (unsigned i = 1, e = M->getNumOperands();
SumOpRes != BitWidth && i != e; ++i)
SumOpRes =
std::min(SumOpRes + GetMinTrailingZeros(M->getOperand(i)), BitWidth);
return SumOpRes;
}
if (const SCEVAddRecExpr *A = dyn_cast<SCEVAddRecExpr>(S)) {
// The result is the min of all operands results.
uint32_t MinOpRes = GetMinTrailingZeros(A->getOperand(0));
for (unsigned i = 1, e = A->getNumOperands(); MinOpRes && i != e; ++i)
MinOpRes = std::min(MinOpRes, GetMinTrailingZeros(A->getOperand(i)));
return MinOpRes;
}
if (const SCEVSMaxExpr *M = dyn_cast<SCEVSMaxExpr>(S)) {
// The result is the min of all operands results.
uint32_t MinOpRes = GetMinTrailingZeros(M->getOperand(0));
for (unsigned i = 1, e = M->getNumOperands(); MinOpRes && i != e; ++i)
MinOpRes = std::min(MinOpRes, GetMinTrailingZeros(M->getOperand(i)));
return MinOpRes;
}
if (const SCEVUMaxExpr *M = dyn_cast<SCEVUMaxExpr>(S)) {
// The result is the min of all operands results.
uint32_t MinOpRes = GetMinTrailingZeros(M->getOperand(0));
for (unsigned i = 1, e = M->getNumOperands(); MinOpRes && i != e; ++i)
MinOpRes = std::min(MinOpRes, GetMinTrailingZeros(M->getOperand(i)));
return MinOpRes;
}
if (const SCEVUnknown *U = dyn_cast<SCEVUnknown>(S)) {
// For a SCEVUnknown, ask ValueTracking.
KnownBits Known = computeKnownBits(U->getValue(), getDataLayout(), 0, &AC, nullptr, &DT);
return Known.countMinTrailingZeros();
}
// SCEVUDivExpr
return 0;
}
uint32_t ScalarEvolution::GetMinTrailingZeros(const SCEV *S) {
auto I = MinTrailingZerosCache.find(S);
if (I != MinTrailingZerosCache.end())
return I->second;
uint32_t Result = GetMinTrailingZerosImpl(S);
auto InsertPair = MinTrailingZerosCache.insert({S, Result});
assert(InsertPair.second && "Should insert a new key");
return InsertPair.first->second;
}
/// Helper method to assign a range to V from metadata present in the IR.
static Optional<ConstantRange> GetRangeFromMetadata(Value *V) {
if (Instruction *I = dyn_cast<Instruction>(V))
if (MDNode *MD = I->getMetadata(LLVMContext::MD_range))
return getConstantRangeFromMetadata(*MD);
return None;
}
void ScalarEvolution::setNoWrapFlags(SCEVAddRecExpr *AddRec,
SCEV::NoWrapFlags Flags) {
if (AddRec->getNoWrapFlags(Flags) != Flags) {
AddRec->setNoWrapFlags(Flags);
UnsignedRanges.erase(AddRec);
SignedRanges.erase(AddRec);
}
}
ConstantRange ScalarEvolution::
getRangeForUnknownRecurrence(const SCEVUnknown *U) {
const DataLayout &DL = getDataLayout();
unsigned BitWidth = getTypeSizeInBits(U->getType());
const ConstantRange FullSet(BitWidth, /*isFullSet=*/true);
// Match a simple recurrence of the form: <start, ShiftOp, Step>, and then
// use information about the trip count to improve our available range. Note
// that the trip count independent cases are already handled by known bits.
// WARNING: The definition of recurrence used here is subtly different than
// the one used by AddRec (and thus most of this file). Step is allowed to
// be arbitrarily loop varying here, where AddRec allows only loop invariant
// and other addrecs in the same loop (for non-affine addrecs). The code
// below intentionally handles the case where step is not loop invariant.
auto *P = dyn_cast<PHINode>(U->getValue());
if (!P)
return FullSet;
// Make sure that no Phi input comes from an unreachable block. Otherwise,
// even the values that are not available in these blocks may come from them,
// and this leads to false-positive recurrence test.
for (auto *Pred : predecessors(P->getParent()))
if (!DT.isReachableFromEntry(Pred))
return FullSet;
BinaryOperator *BO;
Value *Start, *Step;
if (!matchSimpleRecurrence(P, BO, Start, Step))
return FullSet;
// If we found a recurrence in reachable code, we must be in a loop. Note
// that BO might be in some subloop of L, and that's completely okay.
auto *L = LI.getLoopFor(P->getParent());
assert(L && L->getHeader() == P->getParent());
if (!L->contains(BO->getParent()))
// NOTE: This bailout should be an assert instead. However, asserting
// the condition here exposes a case where LoopFusion is querying SCEV
// with malformed loop information during the midst of the transform.
// There doesn't appear to be an obvious fix, so for the moment bailout
// until the caller issue can be fixed. PR49566 tracks the bug.
return FullSet;
// TODO: Extend to other opcodes such as mul, and div
switch (BO->getOpcode()) {
default:
return FullSet;
case Instruction::AShr:
case Instruction::LShr:
case Instruction::Shl:
break;
};
if (BO->getOperand(0) != P)
// TODO: Handle the power function forms some day.
return FullSet;
unsigned TC = getSmallConstantMaxTripCount(L);
if (!TC || TC >= BitWidth)
return FullSet;
auto KnownStart = computeKnownBits(Start, DL, 0, &AC, nullptr, &DT);
auto KnownStep = computeKnownBits(Step, DL, 0, &AC, nullptr, &DT);
assert(KnownStart.getBitWidth() == BitWidth &&
KnownStep.getBitWidth() == BitWidth);
// Compute total shift amount, being careful of overflow and bitwidths.
auto MaxShiftAmt = KnownStep.getMaxValue();
APInt TCAP(BitWidth, TC-1);
bool Overflow = false;
auto TotalShift = MaxShiftAmt.umul_ov(TCAP, Overflow);
if (Overflow)
return FullSet;
switch (BO->getOpcode()) {
default:
llvm_unreachable("filtered out above");
case Instruction::AShr: {
// For each ashr, three cases:
// shift = 0 => unchanged value
// saturation => 0 or -1
// other => a value closer to zero (of the same sign)
// Thus, the end value is closer to zero than the start.
auto KnownEnd = KnownBits::ashr(KnownStart,
KnownBits::makeConstant(TotalShift));
if (KnownStart.isNonNegative())
// Analogous to lshr (simply not yet canonicalized)
return ConstantRange::getNonEmpty(KnownEnd.getMinValue(),
KnownStart.getMaxValue() + 1);
if (KnownStart.isNegative())
// End >=u Start && End <=s Start
return ConstantRange::getNonEmpty(KnownStart.getMinValue(),
KnownEnd.getMaxValue() + 1);
break;
}
case Instruction::LShr: {
// For each lshr, three cases:
// shift = 0 => unchanged value
// saturation => 0
// other => a smaller positive number
// Thus, the low end of the unsigned range is the last value produced.
auto KnownEnd = KnownBits::lshr(KnownStart,
KnownBits::makeConstant(TotalShift));
return ConstantRange::getNonEmpty(KnownEnd.getMinValue(),
KnownStart.getMaxValue() + 1);
}
case Instruction::Shl: {
// Iff no bits are shifted out, value increases on every shift.
auto KnownEnd = KnownBits::shl(KnownStart,
KnownBits::makeConstant(TotalShift));
if (TotalShift.ult(KnownStart.countMinLeadingZeros()))
return ConstantRange(KnownStart.getMinValue(),
KnownEnd.getMaxValue() + 1);
break;
}
};
return FullSet;
}
/// Determine the range for a particular SCEV. If SignHint is
/// HINT_RANGE_UNSIGNED (resp. HINT_RANGE_SIGNED) then getRange prefers ranges
/// with a "cleaner" unsigned (resp. signed) representation.
const ConstantRange &
ScalarEvolution::getRangeRef(const SCEV *S,
ScalarEvolution::RangeSignHint SignHint) {
DenseMap<const SCEV *, ConstantRange> &Cache =
SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED ? UnsignedRanges
: SignedRanges;
ConstantRange::PreferredRangeType RangeType =
SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED
? ConstantRange::Unsigned : ConstantRange::Signed;
// See if we've computed this range already.
DenseMap<const SCEV *, ConstantRange>::iterator I = Cache.find(S);
if (I != Cache.end())
return I->second;
if (const SCEVConstant *C = dyn_cast<SCEVConstant>(S))
return setRange(C, SignHint, ConstantRange(C->getAPInt()));
unsigned BitWidth = getTypeSizeInBits(S->getType());
ConstantRange ConservativeResult(BitWidth, /*isFullSet=*/true);
using OBO = OverflowingBinaryOperator;
// If the value has known zeros, the maximum value will have those known zeros
// as well.
uint32_t TZ = GetMinTrailingZeros(S);
if (TZ != 0) {
if (SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED)
ConservativeResult =
ConstantRange(APInt::getMinValue(BitWidth),
APInt::getMaxValue(BitWidth).lshr(TZ).shl(TZ) + 1);
else
ConservativeResult = ConstantRange(
APInt::getSignedMinValue(BitWidth),
APInt::getSignedMaxValue(BitWidth).ashr(TZ).shl(TZ) + 1);
}
if (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(S)) {
ConstantRange X = getRangeRef(Add->getOperand(0), SignHint);
unsigned WrapType = OBO::AnyWrap;
if (Add->hasNoSignedWrap())
WrapType |= OBO::NoSignedWrap;
if (Add->hasNoUnsignedWrap())
WrapType |= OBO::NoUnsignedWrap;
for (unsigned i = 1, e = Add->getNumOperands(); i != e; ++i)
X = X.addWithNoWrap(getRangeRef(Add->getOperand(i), SignHint),
WrapType, RangeType);
return setRange(Add, SignHint,
ConservativeResult.intersectWith(X, RangeType));
}
if (const SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(S)) {
ConstantRange X = getRangeRef(Mul->getOperand(0), SignHint);
for (unsigned i = 1, e = Mul->getNumOperands(); i != e; ++i)
X = X.multiply(getRangeRef(Mul->getOperand(i), SignHint));
return setRange(Mul, SignHint,
ConservativeResult.intersectWith(X, RangeType));
}
if (isa<SCEVMinMaxExpr>(S) || isa<SCEVSequentialMinMaxExpr>(S)) {
Intrinsic::ID ID;
switch (S->getSCEVType()) {
case scUMaxExpr:
ID = Intrinsic::umax;
break;
case scSMaxExpr:
ID = Intrinsic::smax;
break;
case scUMinExpr:
case scSequentialUMinExpr:
ID = Intrinsic::umin;
break;
case scSMinExpr:
ID = Intrinsic::smin;
break;
default:
llvm_unreachable("Unknown SCEVMinMaxExpr/SCEVSequentialMinMaxExpr.");
}
const auto *NAry = cast<SCEVNAryExpr>(S);
ConstantRange X = getRangeRef(NAry->getOperand(0), SignHint);
for (unsigned i = 1, e = NAry->getNumOperands(); i != e; ++i)
X = X.intrinsic(ID, {X, getRangeRef(NAry->getOperand(i), SignHint)});
return setRange(S, SignHint,
ConservativeResult.intersectWith(X, RangeType));
}
if (const SCEVUDivExpr *UDiv = dyn_cast<SCEVUDivExpr>(S)) {
ConstantRange X = getRangeRef(UDiv->getLHS(), SignHint);
ConstantRange Y = getRangeRef(UDiv->getRHS(), SignHint);
return setRange(UDiv, SignHint,
ConservativeResult.intersectWith(X.udiv(Y), RangeType));
}
if (const SCEVZeroExtendExpr *ZExt = dyn_cast<SCEVZeroExtendExpr>(S)) {
ConstantRange X = getRangeRef(ZExt->getOperand(), SignHint);
return setRange(ZExt, SignHint,
ConservativeResult.intersectWith(X.zeroExtend(BitWidth),
RangeType));
}
if (const SCEVSignExtendExpr *SExt = dyn_cast<SCEVSignExtendExpr>(S)) {
ConstantRange X = getRangeRef(SExt->getOperand(), SignHint);
return setRange(SExt, SignHint,
ConservativeResult.intersectWith(X.signExtend(BitWidth),
RangeType));
}
if (const SCEVPtrToIntExpr *PtrToInt = dyn_cast<SCEVPtrToIntExpr>(S)) {
ConstantRange X = getRangeRef(PtrToInt->getOperand(), SignHint);
return setRange(PtrToInt, SignHint, X);
}
if (const SCEVTruncateExpr *Trunc = dyn_cast<SCEVTruncateExpr>(S)) {
ConstantRange X = getRangeRef(Trunc->getOperand(), SignHint);
return setRange(Trunc, SignHint,
ConservativeResult.intersectWith(X.truncate(BitWidth),
RangeType));
}
if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(S)) {
// If there's no unsigned wrap, the value will never be less than its
// initial value.
if (AddRec->hasNoUnsignedWrap()) {
APInt UnsignedMinValue = getUnsignedRangeMin(AddRec->getStart());
if (!UnsignedMinValue.isZero())
ConservativeResult = ConservativeResult.intersectWith(
ConstantRange(UnsignedMinValue, APInt(BitWidth, 0)), RangeType);
}
// If there's no signed wrap, and all the operands except initial value have
// the same sign or zero, the value won't ever be:
// 1: smaller than initial value if operands are non negative,
// 2: bigger than initial value if operands are non positive.
// For both cases, value can not cross signed min/max boundary.
if (AddRec->hasNoSignedWrap()) {
bool AllNonNeg = true;
bool AllNonPos = true;
for (unsigned i = 1, e = AddRec->getNumOperands(); i != e; ++i) {
if (!isKnownNonNegative(AddRec->getOperand(i)))
AllNonNeg = false;
if (!isKnownNonPositive(AddRec->getOperand(i)))
AllNonPos = false;
}
if (AllNonNeg)
ConservativeResult = ConservativeResult.intersectWith(
ConstantRange::getNonEmpty(getSignedRangeMin(AddRec->getStart()),
APInt::getSignedMinValue(BitWidth)),
RangeType);
else if (AllNonPos)
ConservativeResult = ConservativeResult.intersectWith(
ConstantRange::getNonEmpty(
APInt::getSignedMinValue(BitWidth),
getSignedRangeMax(AddRec->getStart()) + 1),
RangeType);
}
// TODO: non-affine addrec
if (AddRec->isAffine()) {
const SCEV *MaxBECount = getConstantMaxBackedgeTakenCount(AddRec->getLoop());
if (!isa<SCEVCouldNotCompute>(MaxBECount) &&
getTypeSizeInBits(MaxBECount->getType()) <= BitWidth) {
auto RangeFromAffine = getRangeForAffineAR(
AddRec->getStart(), AddRec->getStepRecurrence(*this), MaxBECount,
BitWidth);
ConservativeResult =
ConservativeResult.intersectWith(RangeFromAffine, RangeType);
auto RangeFromFactoring = getRangeViaFactoring(
AddRec->getStart(), AddRec->getStepRecurrence(*this), MaxBECount,
BitWidth);
ConservativeResult =
ConservativeResult.intersectWith(RangeFromFactoring, RangeType);
}
// Now try symbolic BE count and more powerful methods.
if (UseExpensiveRangeSharpening) {
const SCEV *SymbolicMaxBECount =
getSymbolicMaxBackedgeTakenCount(AddRec->getLoop());
if (!isa<SCEVCouldNotCompute>(SymbolicMaxBECount) &&
getTypeSizeInBits(MaxBECount->getType()) <= BitWidth &&
AddRec->hasNoSelfWrap()) {
auto RangeFromAffineNew = getRangeForAffineNoSelfWrappingAR(
AddRec, SymbolicMaxBECount, BitWidth, SignHint);
ConservativeResult =
ConservativeResult.intersectWith(RangeFromAffineNew, RangeType);
}
}
}
return setRange(AddRec, SignHint, std::move(ConservativeResult));
}
if (const SCEVUnknown *U = dyn_cast<SCEVUnknown>(S)) {
// Check if the IR explicitly contains !range metadata.
Optional<ConstantRange> MDRange = GetRangeFromMetadata(U->getValue());
if (MDRange)
ConservativeResult =
ConservativeResult.intersectWith(MDRange.value(), RangeType);
// Use facts about recurrences in the underlying IR. Note that add
// recurrences are AddRecExprs and thus don't hit this path. This
// primarily handles shift recurrences.
auto CR = getRangeForUnknownRecurrence(U);
ConservativeResult = ConservativeResult.intersectWith(CR);
// See if ValueTracking can give us a useful range.
const DataLayout &DL = getDataLayout();
KnownBits Known = computeKnownBits(U->getValue(), DL, 0, &AC, nullptr, &DT);
if (Known.getBitWidth() != BitWidth)
Known = Known.zextOrTrunc(BitWidth);
// ValueTracking may be able to compute a tighter result for the number of
// sign bits than for the value of those sign bits.
unsigned NS = ComputeNumSignBits(U->getValue(), DL, 0, &AC, nullptr, &DT);
if (U->getType()->isPointerTy()) {
// If the pointer size is larger than the index size type, this can cause
// NS to be larger than BitWidth. So compensate for this.
unsigned ptrSize = DL.getPointerTypeSizeInBits(U->getType());
int ptrIdxDiff = ptrSize - BitWidth;
if (ptrIdxDiff > 0 && ptrSize > BitWidth && NS > (unsigned)ptrIdxDiff)
NS -= ptrIdxDiff;
}
if (NS > 1) {
// If we know any of the sign bits, we know all of the sign bits.
if (!Known.Zero.getHiBits(NS).isZero())
Known.Zero.setHighBits(NS);
if (!Known.One.getHiBits(NS).isZero())
Known.One.setHighBits(NS);
}
if (Known.getMinValue() != Known.getMaxValue() + 1)
ConservativeResult = ConservativeResult.intersectWith(
ConstantRange(Known.getMinValue(), Known.getMaxValue() + 1),
RangeType);
if (NS > 1)
ConservativeResult = ConservativeResult.intersectWith(
ConstantRange(APInt::getSignedMinValue(BitWidth).ashr(NS - 1),
APInt::getSignedMaxValue(BitWidth).ashr(NS - 1) + 1),
RangeType);
// A range of Phi is a subset of union of all ranges of its input.
if (const PHINode *Phi = dyn_cast<PHINode>(U->getValue())) {
// Make sure that we do not run over cycled Phis.
if (PendingPhiRanges.insert(Phi).second) {
ConstantRange RangeFromOps(BitWidth, /*isFullSet=*/false);
for (const auto &Op : Phi->operands()) {
auto OpRange = getRangeRef(getSCEV(Op), SignHint);
RangeFromOps = RangeFromOps.unionWith(OpRange);
// No point to continue if we already have a full set.
if (RangeFromOps.isFullSet())
break;
}
ConservativeResult =
ConservativeResult.intersectWith(RangeFromOps, RangeType);
bool Erased = PendingPhiRanges.erase(Phi);
assert(Erased && "Failed to erase Phi properly?");
(void) Erased;
}
}
// vscale can't be equal to zero
if (const auto *II = dyn_cast<IntrinsicInst>(U->getValue()))
if (II->getIntrinsicID() == Intrinsic::vscale) {
ConstantRange Disallowed = APInt::getZero(BitWidth);
ConservativeResult = ConservativeResult.difference(Disallowed);
}
return setRange(U, SignHint, std::move(ConservativeResult));
}
return setRange(S, SignHint, std::move(ConservativeResult));
}
// Given a StartRange, Step and MaxBECount for an expression compute a range of
// values that the expression can take. Initially, the expression has a value
// from StartRange and then is changed by Step up to MaxBECount times. Signed
// argument defines if we treat Step as signed or unsigned.
static ConstantRange getRangeForAffineARHelper(APInt Step,
const ConstantRange &StartRange,
const APInt &MaxBECount,
unsigned BitWidth, bool Signed) {
// If either Step or MaxBECount is 0, then the expression won't change, and we
// just need to return the initial range.
if (Step == 0 || MaxBECount == 0)
return StartRange;
// If we don't know anything about the initial value (i.e. StartRange is
// FullRange), then we don't know anything about the final range either.
// Return FullRange.
if (StartRange.isFullSet())
return ConstantRange::getFull(BitWidth);
// If Step is signed and negative, then we use its absolute value, but we also
// note that we're moving in the opposite direction.
bool Descending = Signed && Step.isNegative();
if (Signed)
// This is correct even for INT_SMIN. Let's look at i8 to illustrate this:
// abs(INT_SMIN) = abs(-128) = abs(0x80) = -0x80 = 0x80 = 128.
// This equations hold true due to the well-defined wrap-around behavior of
// APInt.
Step = Step.abs();
// Check if Offset is more than full span of BitWidth. If it is, the
// expression is guaranteed to overflow.
if (APInt::getMaxValue(StartRange.getBitWidth()).udiv(Step).ult(MaxBECount))
return ConstantRange::getFull(BitWidth);
// Offset is by how much the expression can change. Checks above guarantee no
// overflow here.
APInt Offset = Step * MaxBECount;
// Minimum value of the final range will match the minimal value of StartRange
// if the expression is increasing and will be decreased by Offset otherwise.
// Maximum value of the final range will match the maximal value of StartRange
// if the expression is decreasing and will be increased by Offset otherwise.
APInt StartLower = StartRange.getLower();
APInt StartUpper = StartRange.getUpper() - 1;
APInt MovedBoundary = Descending ? (StartLower - std::move(Offset))
: (StartUpper + std::move(Offset));
// It's possible that the new minimum/maximum value will fall into the initial
// range (due to wrap around). This means that the expression can take any
// value in this bitwidth, and we have to return full range.
if (StartRange.contains(MovedBoundary))
return ConstantRange::getFull(BitWidth);
APInt NewLower =
Descending ? std::move(MovedBoundary) : std::move(StartLower);
APInt NewUpper =
Descending ? std::move(StartUpper) : std::move(MovedBoundary);
NewUpper += 1;
// No overflow detected, return [StartLower, StartUpper + Offset + 1) range.
return ConstantRange::getNonEmpty(std::move(NewLower), std::move(NewUpper));
}
ConstantRange ScalarEvolution::getRangeForAffineAR(const SCEV *Start,
const SCEV *Step,
const SCEV *MaxBECount,
unsigned BitWidth) {
assert(!isa<SCEVCouldNotCompute>(MaxBECount) &&
getTypeSizeInBits(MaxBECount->getType()) <= BitWidth &&
"Precondition!");
MaxBECount = getNoopOrZeroExtend(MaxBECount, Start->getType());
APInt MaxBECountValue = getUnsignedRangeMax(MaxBECount);
// First, consider step signed.
ConstantRange StartSRange = getSignedRange(Start);
ConstantRange StepSRange = getSignedRange(Step);
// If Step can be both positive and negative, we need to find ranges for the
// maximum absolute step values in both directions and union them.
ConstantRange SR =
getRangeForAffineARHelper(StepSRange.getSignedMin(), StartSRange,
MaxBECountValue, BitWidth, /* Signed = */ true);
SR = SR.unionWith(getRangeForAffineARHelper(StepSRange.getSignedMax(),
StartSRange, MaxBECountValue,
BitWidth, /* Signed = */ true));
// Next, consider step unsigned.
ConstantRange UR = getRangeForAffineARHelper(
getUnsignedRangeMax(Step), getUnsignedRange(Start),
MaxBECountValue, BitWidth, /* Signed = */ false);
// Finally, intersect signed and unsigned ranges.
return SR.intersectWith(UR, ConstantRange::Smallest);
}
ConstantRange ScalarEvolution::getRangeForAffineNoSelfWrappingAR(
const SCEVAddRecExpr *AddRec, const SCEV *MaxBECount, unsigned BitWidth,
ScalarEvolution::RangeSignHint SignHint) {
assert(AddRec->isAffine() && "Non-affine AddRecs are not suppored!\n");
assert(AddRec->hasNoSelfWrap() &&
"This only works for non-self-wrapping AddRecs!");
const bool IsSigned = SignHint == HINT_RANGE_SIGNED;
const SCEV *Step = AddRec->getStepRecurrence(*this);
// Only deal with constant step to save compile time.
if (!isa<SCEVConstant>(Step))
return ConstantRange::getFull(BitWidth);
// Let's make sure that we can prove that we do not self-wrap during
// MaxBECount iterations. We need this because MaxBECount is a maximum
// iteration count estimate, and we might infer nw from some exit for which we
// do not know max exit count (or any other side reasoning).
// TODO: Turn into assert at some point.
if (getTypeSizeInBits(MaxBECount->getType()) >
getTypeSizeInBits(AddRec->getType()))
return ConstantRange::getFull(BitWidth);
MaxBECount = getNoopOrZeroExtend(MaxBECount, AddRec->getType());
const SCEV *RangeWidth = getMinusOne(AddRec->getType());
const SCEV *StepAbs = getUMinExpr(Step, getNegativeSCEV(Step));
const SCEV *MaxItersWithoutWrap = getUDivExpr(RangeWidth, StepAbs);
if (!isKnownPredicateViaConstantRanges(ICmpInst::ICMP_ULE, MaxBECount,
MaxItersWithoutWrap))
return ConstantRange::getFull(BitWidth);
ICmpInst::Predicate LEPred =
IsSigned ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE;
ICmpInst::Predicate GEPred =
IsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE;
const SCEV *End = AddRec->evaluateAtIteration(MaxBECount, *this);
// We know that there is no self-wrap. Let's take Start and End values and
// look at all intermediate values V1, V2, ..., Vn that IndVar takes during
// the iteration. They either lie inside the range [Min(Start, End),
// Max(Start, End)] or outside it:
//
// Case 1: RangeMin ... Start V1 ... VN End ... RangeMax;
// Case 2: RangeMin Vk ... V1 Start ... End Vn ... Vk + 1 RangeMax;
//
// No self wrap flag guarantees that the intermediate values cannot be BOTH
// outside and inside the range [Min(Start, End), Max(Start, End)]. Using that
// knowledge, let's try to prove that we are dealing with Case 1. It is so if
// Start <= End and step is positive, or Start >= End and step is negative.
const SCEV *Start = AddRec->getStart();
ConstantRange StartRange = getRangeRef(Start, SignHint);
ConstantRange EndRange = getRangeRef(End, SignHint);
ConstantRange RangeBetween = StartRange.unionWith(EndRange);
// If they already cover full iteration space, we will know nothing useful
// even if we prove what we want to prove.
if (RangeBetween.isFullSet())
return RangeBetween;
// Only deal with ranges that do not wrap (i.e. RangeMin < RangeMax).
bool IsWrappedSet = IsSigned ? RangeBetween.isSignWrappedSet()
: RangeBetween.isWrappedSet();
if (IsWrappedSet)
return ConstantRange::getFull(BitWidth);
if (isKnownPositive(Step) &&
isKnownPredicateViaConstantRanges(LEPred, Start, End))
return RangeBetween;
else if (isKnownNegative(Step) &&
isKnownPredicateViaConstantRanges(GEPred, Start, End))
return RangeBetween;
return ConstantRange::getFull(BitWidth);
}
ConstantRange ScalarEvolution::getRangeViaFactoring(const SCEV *Start,
const SCEV *Step,
const SCEV *MaxBECount,
unsigned BitWidth) {
// RangeOf({C?A:B,+,C?P:Q}) == RangeOf(C?{A,+,P}:{B,+,Q})
// == RangeOf({A,+,P}) union RangeOf({B,+,Q})
struct SelectPattern {
Value *Condition = nullptr;
APInt TrueValue;
APInt FalseValue;
explicit SelectPattern(ScalarEvolution &SE, unsigned BitWidth,
const SCEV *S) {
Optional<unsigned> CastOp;
APInt Offset(BitWidth, 0);
assert(SE.getTypeSizeInBits(S->getType()) == BitWidth &&
"Should be!");
// Peel off a constant offset:
if (auto *SA = dyn_cast<SCEVAddExpr>(S)) {
// In the future we could consider being smarter here and handle
// {Start+Step,+,Step} too.
if (SA->getNumOperands() != 2 || !isa<SCEVConstant>(SA->getOperand(0)))
return;
Offset = cast<SCEVConstant>(SA->getOperand(0))->getAPInt();
S = SA->getOperand(1);
}
// Peel off a cast operation
if (auto *SCast = dyn_cast<SCEVIntegralCastExpr>(S)) {
CastOp = SCast->getSCEVType();
S = SCast->getOperand();
}
using namespace llvm::PatternMatch;
auto *SU = dyn_cast<SCEVUnknown>(S);
const APInt *TrueVal, *FalseVal;
if (!SU ||
!match(SU->getValue(), m_Select(m_Value(Condition), m_APInt(TrueVal),
m_APInt(FalseVal)))) {
Condition = nullptr;
return;
}
TrueValue = *TrueVal;
FalseValue = *FalseVal;
// Re-apply the cast we peeled off earlier
if (CastOp)
switch (*CastOp) {
default:
llvm_unreachable("Unknown SCEV cast type!");
case scTruncate:
TrueValue = TrueValue.trunc(BitWidth);
FalseValue = FalseValue.trunc(BitWidth);
break;
case scZeroExtend:
TrueValue = TrueValue.zext(BitWidth);
FalseValue = FalseValue.zext(BitWidth);
break;
case scSignExtend:
TrueValue = TrueValue.sext(BitWidth);
FalseValue = FalseValue.sext(BitWidth);
break;
}
// Re-apply the constant offset we peeled off earlier
TrueValue += Offset;
FalseValue += Offset;
}
bool isRecognized() { return Condition != nullptr; }
};
SelectPattern StartPattern(*this, BitWidth, Start);
if (!StartPattern.isRecognized())
return ConstantRange::getFull(BitWidth);
SelectPattern StepPattern(*this, BitWidth, Step);
if (!StepPattern.isRecognized())
return ConstantRange::getFull(BitWidth);
if (StartPattern.Condition != StepPattern.Condition) {
// We don't handle this case today; but we could, by considering four
// possibilities below instead of two. I'm not sure if there are cases where
// that will help over what getRange already does, though.
return ConstantRange::getFull(BitWidth);
}
// NB! Calling ScalarEvolution::getConstant is fine, but we should not try to
// construct arbitrary general SCEV expressions here. This function is called
// from deep in the call stack, and calling getSCEV (on a sext instruction,
// say) can end up caching a suboptimal value.
// FIXME: without the explicit `this` receiver below, MSVC errors out with
// C2352 and C2512 (otherwise it isn't needed).
const SCEV *TrueStart = this->getConstant(StartPattern.TrueValue);
const SCEV *TrueStep = this->getConstant(StepPattern.TrueValue);
const SCEV *FalseStart = this->getConstant(StartPattern.FalseValue);
const SCEV *FalseStep = this->getConstant(StepPattern.FalseValue);
ConstantRange TrueRange =
this->getRangeForAffineAR(TrueStart, TrueStep, MaxBECount, BitWidth);
ConstantRange FalseRange =
this->getRangeForAffineAR(FalseStart, FalseStep, MaxBECount, BitWidth);
return TrueRange.unionWith(FalseRange);
}
SCEV::NoWrapFlags ScalarEvolution::getNoWrapFlagsFromUB(const Value *V) {
if (isa<ConstantExpr>(V)) return SCEV::FlagAnyWrap;
const BinaryOperator *BinOp = cast<BinaryOperator>(V);
// Return early if there are no flags to propagate to the SCEV.
SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap;
if (BinOp->hasNoUnsignedWrap())
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW);
if (BinOp->hasNoSignedWrap())
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNSW);
if (Flags == SCEV::FlagAnyWrap)
return SCEV::FlagAnyWrap;
return isSCEVExprNeverPoison(BinOp) ? Flags : SCEV::FlagAnyWrap;
}
const Instruction *
ScalarEvolution::getNonTrivialDefiningScopeBound(const SCEV *S) {
if (auto *AddRec = dyn_cast<SCEVAddRecExpr>(S))
return &*AddRec->getLoop()->getHeader()->begin();
if (auto *U = dyn_cast<SCEVUnknown>(S))
if (auto *I = dyn_cast<Instruction>(U->getValue()))
return I;
return nullptr;
}
/// Fills \p Ops with unique operands of \p S, if it has operands. If not,
/// \p Ops remains unmodified.
static void collectUniqueOps(const SCEV *S,
SmallVectorImpl<const SCEV *> &Ops) {
SmallPtrSet<const SCEV *, 4> Unique;
auto InsertUnique = [&](const SCEV *S) {
if (Unique.insert(S).second)
Ops.push_back(S);
};
if (auto *S2 = dyn_cast<SCEVCastExpr>(S))
for (const auto *Op : S2->operands())
InsertUnique(Op);
else if (auto *S2 = dyn_cast<SCEVNAryExpr>(S))
for (const auto *Op : S2->operands())
InsertUnique(Op);
else if (auto *S2 = dyn_cast<SCEVUDivExpr>(S))
for (const auto *Op : S2->operands())
InsertUnique(Op);
}
const Instruction *
ScalarEvolution::getDefiningScopeBound(ArrayRef<const SCEV *> Ops,
bool &Precise) {
Precise = true;
// Do a bounded search of the def relation of the requested SCEVs.
SmallSet<const SCEV *, 16> Visited;
SmallVector<const SCEV *> Worklist;
auto pushOp = [&](const SCEV *S) {
if (!Visited.insert(S).second)
return;
// Threshold of 30 here is arbitrary.
if (Visited.size() > 30) {
Precise = false;
return;
}
Worklist.push_back(S);
};
for (const auto *S : Ops)
pushOp(S);
const Instruction *Bound = nullptr;
while (!Worklist.empty()) {
auto *S = Worklist.pop_back_val();
if (auto *DefI = getNonTrivialDefiningScopeBound(S)) {
if (!Bound || DT.dominates(Bound, DefI))
Bound = DefI;
} else {
SmallVector<const SCEV *, 4> Ops;
collectUniqueOps(S, Ops);
for (const auto *Op : Ops)
pushOp(Op);
}
}
return Bound ? Bound : &*F.getEntryBlock().begin();
}
const Instruction *
ScalarEvolution::getDefiningScopeBound(ArrayRef<const SCEV *> Ops) {
bool Discard;
return getDefiningScopeBound(Ops, Discard);
}
bool ScalarEvolution::isGuaranteedToTransferExecutionTo(const Instruction *A,
const Instruction *B) {
if (A->getParent() == B->getParent() &&
isGuaranteedToTransferExecutionToSuccessor(A->getIterator(),
B->getIterator()))
return true;
auto *BLoop = LI.getLoopFor(B->getParent());
if (BLoop && BLoop->getHeader() == B->getParent() &&
BLoop->getLoopPreheader() == A->getParent() &&
isGuaranteedToTransferExecutionToSuccessor(A->getIterator(),
A->getParent()->end()) &&
isGuaranteedToTransferExecutionToSuccessor(B->getParent()->begin(),
B->getIterator()))
return true;
return false;
}
bool ScalarEvolution::isSCEVExprNeverPoison(const Instruction *I) {
// Only proceed if we can prove that I does not yield poison.
if (!programUndefinedIfPoison(I))
return false;
// At this point we know that if I is executed, then it does not wrap
// according to at least one of NSW or NUW. If I is not executed, then we do
// not know if the calculation that I represents would wrap. Multiple
// instructions can map to the same SCEV. If we apply NSW or NUW from I to
// the SCEV, we must guarantee no wrapping for that SCEV also when it is
// derived from other instructions that map to the same SCEV. We cannot make
// that guarantee for cases where I is not executed. So we need to find a
// upper bound on the defining scope for the SCEV, and prove that I is
// executed every time we enter that scope. When the bounding scope is a
// loop (the common case), this is equivalent to proving I executes on every
// iteration of that loop.
SmallVector<const SCEV *> SCEVOps;
for (const Use &Op : I->operands()) {
// I could be an extractvalue from a call to an overflow intrinsic.
// TODO: We can do better here in some cases.
if (isSCEVable(Op->getType()))
SCEVOps.push_back(getSCEV(Op));
}
auto *DefI = getDefiningScopeBound(SCEVOps);
return isGuaranteedToTransferExecutionTo(DefI, I);
}
bool ScalarEvolution::isAddRecNeverPoison(const Instruction *I, const Loop *L) {
// If we know that \c I can never be poison period, then that's enough.
if (isSCEVExprNeverPoison(I))
return true;
// For an add recurrence specifically, we assume that infinite loops without
// side effects are undefined behavior, and then reason as follows:
//
// If the add recurrence is poison in any iteration, it is poison on all
// future iterations (since incrementing poison yields poison). If the result
// of the add recurrence is fed into the loop latch condition and the loop
// does not contain any throws or exiting blocks other than the latch, we now
// have the ability to "choose" whether the backedge is taken or not (by
// choosing a sufficiently evil value for the poison feeding into the branch)
// for every iteration including and after the one in which \p I first became
// poison. There are two possibilities (let's call the iteration in which \p
// I first became poison as K):
//
// 1. In the set of iterations including and after K, the loop body executes
// no side effects. In this case executing the backege an infinte number
// of times will yield undefined behavior.
//
// 2. In the set of iterations including and after K, the loop body executes
// at least one side effect. In this case, that specific instance of side
// effect is control dependent on poison, which also yields undefined
// behavior.
auto *ExitingBB = L->getExitingBlock();
auto *LatchBB = L->getLoopLatch();
if (!ExitingBB || !LatchBB || ExitingBB != LatchBB)
return false;
SmallPtrSet<const Instruction *, 16> Pushed;
SmallVector<const Instruction *, 8> PoisonStack;
// We start by assuming \c I, the post-inc add recurrence, is poison. Only
// things that are known to be poison under that assumption go on the
// PoisonStack.
Pushed.insert(I);
PoisonStack.push_back(I);
bool LatchControlDependentOnPoison = false;
while (!PoisonStack.empty() && !LatchControlDependentOnPoison) {
const Instruction *Poison = PoisonStack.pop_back_val();
for (const auto *PoisonUser : Poison->users()) {
if (propagatesPoison(cast<Operator>(PoisonUser))) {
if (Pushed.insert(cast<Instruction>(PoisonUser)).second)
PoisonStack.push_back(cast<Instruction>(PoisonUser));
} else if (auto *BI = dyn_cast<BranchInst>(PoisonUser)) {
assert(BI->isConditional() && "Only possibility!");
if (BI->getParent() == LatchBB) {
LatchControlDependentOnPoison = true;
break;
}
}
}
}
return LatchControlDependentOnPoison && loopHasNoAbnormalExits(L);
}
ScalarEvolution::LoopProperties
ScalarEvolution::getLoopProperties(const Loop *L) {
using LoopProperties = ScalarEvolution::LoopProperties;
auto Itr = LoopPropertiesCache.find(L);
if (Itr == LoopPropertiesCache.end()) {
auto HasSideEffects = [](Instruction *I) {
if (auto *SI = dyn_cast<StoreInst>(I))
return !SI->isSimple();
return I->mayThrow() || I->mayWriteToMemory();
};
LoopProperties LP = {/* HasNoAbnormalExits */ true,
/*HasNoSideEffects*/ true};
for (auto *BB : L->getBlocks())
for (auto &I : *BB) {
if (!isGuaranteedToTransferExecutionToSuccessor(&I))
LP.HasNoAbnormalExits = false;
if (HasSideEffects(&I))
LP.HasNoSideEffects = false;
if (!LP.HasNoAbnormalExits && !LP.HasNoSideEffects)
break; // We're already as pessimistic as we can get.
}
auto InsertPair = LoopPropertiesCache.insert({L, LP});
assert(InsertPair.second && "We just checked!");
Itr = InsertPair.first;
}
return Itr->second;
}
bool ScalarEvolution::loopIsFiniteByAssumption(const Loop *L) {
// A mustprogress loop without side effects must be finite.
// TODO: The check used here is very conservative. It's only *specific*
// side effects which are well defined in infinite loops.
return isFinite(L) || (isMustProgress(L) && loopHasNoSideEffects(L));
}
const SCEV *ScalarEvolution::createSCEVIter(Value *V) {
// Worklist item with a Value and a bool indicating whether all operands have
// been visited already.
using PointerTy = PointerIntPair<Value *, 1, bool>;
SmallVector<PointerTy> Stack;
Stack.emplace_back(V, true);
Stack.emplace_back(V, false);
while (!Stack.empty()) {
auto E = Stack.pop_back_val();
Value *CurV = E.getPointer();
if (getExistingSCEV(CurV))
continue;
SmallVector<Value *> Ops;
const SCEV *CreatedSCEV = nullptr;
// If all operands have been visited already, create the SCEV.
if (E.getInt()) {
CreatedSCEV = createSCEV(CurV);
} else {
// Otherwise get the operands we need to create SCEV's for before creating
// the SCEV for CurV. If the SCEV for CurV can be constructed trivially,
// just use it.
CreatedSCEV = getOperandsToCreate(CurV, Ops);
}
if (CreatedSCEV) {
insertValueToMap(CurV, CreatedSCEV);
} else {
// Queue CurV for SCEV creation, followed by its's operands which need to
// be constructed first.
Stack.emplace_back(CurV, true);
for (Value *Op : Ops)
Stack.emplace_back(Op, false);
}
}
return getExistingSCEV(V);
}
const SCEV *
ScalarEvolution::getOperandsToCreate(Value *V, SmallVectorImpl<Value *> &Ops) {
if (!isSCEVable(V->getType()))
return getUnknown(V);
if (Instruction *I = dyn_cast<Instruction>(V)) {
// Don't attempt to analyze instructions in blocks that aren't
// reachable. Such instructions don't matter, and they aren't required
// to obey basic rules for definitions dominating uses which this
// analysis depends on.
if (!DT.isReachableFromEntry(I->getParent()))
return getUnknown(PoisonValue::get(V->getType()));
} else if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
return getConstant(CI);
else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
if (!GA->isInterposable()) {
Ops.push_back(GA->getAliasee());
return nullptr;
}
return getUnknown(V);
} else if (!isa<ConstantExpr>(V))
return getUnknown(V);
Operator *U = cast<Operator>(V);
if (auto BO = MatchBinaryOp(U, DT)) {
bool IsConstArg = isa<ConstantInt>(BO->RHS);
switch (BO->Opcode) {
case Instruction::Add: {
// For additions and multiplications, traverse add/mul chains for which we
// can potentially create a single SCEV, to reduce the number of
// get{Add,Mul}Expr calls.
do {
if (BO->Op) {
if (BO->Op != V && getExistingSCEV(BO->Op)) {
Ops.push_back(BO->Op);
break;
}
}
Ops.push_back(BO->RHS);
auto NewBO = MatchBinaryOp(BO->LHS, DT);
if (!NewBO || (NewBO->Opcode != Instruction::Add &&
NewBO->Opcode != Instruction::Sub)) {
Ops.push_back(BO->LHS);
break;
}
BO = NewBO;
} while (true);
return nullptr;
}
case Instruction::Mul: {
do {
if (BO->Op) {
if (BO->Op != V && getExistingSCEV(BO->Op)) {
Ops.push_back(BO->Op);
break;
}
}
Ops.push_back(BO->RHS);
auto NewBO = MatchBinaryOp(BO->LHS, DT);
if (!NewBO || NewBO->Opcode != Instruction::Mul) {
Ops.push_back(BO->LHS);
break;
}
BO = NewBO;
} while (true);
return nullptr;
}
case Instruction::Sub:
case Instruction::UDiv:
case Instruction::URem:
break;
case Instruction::AShr:
case Instruction::Shl:
case Instruction::Xor:
if (!IsConstArg)
return nullptr;
break;
case Instruction::And:
case Instruction::Or:
if (!IsConstArg && BO->LHS->getType()->isIntegerTy(1))
return nullptr;
break;
case Instruction::LShr:
return getUnknown(V);
default:
llvm_unreachable("Unhandled binop");
break;
}
Ops.push_back(BO->LHS);
Ops.push_back(BO->RHS);
return nullptr;
}
switch (U->getOpcode()) {
case Instruction::Trunc:
case Instruction::ZExt:
case Instruction::SExt:
case Instruction::PtrToInt:
Ops.push_back(U->getOperand(0));
return nullptr;
case Instruction::BitCast:
if (isSCEVable(U->getType()) && isSCEVable(U->getOperand(0)->getType())) {
Ops.push_back(U->getOperand(0));
return nullptr;
}
return getUnknown(V);
case Instruction::SDiv:
case Instruction::SRem:
Ops.push_back(U->getOperand(0));
Ops.push_back(U->getOperand(1));
return nullptr;
case Instruction::GetElementPtr:
assert(cast<GEPOperator>(U)->getSourceElementType()->isSized() &&
"GEP source element type must be sized");
for (Value *Index : U->operands())
Ops.push_back(Index);
return nullptr;
case Instruction::IntToPtr:
return getUnknown(V);
case Instruction::PHI:
// Keep constructing SCEVs' for phis recursively for now.
return nullptr;
case Instruction::Select: {
// Check if U is a select that can be simplified to a SCEVUnknown.
auto CanSimplifyToUnknown = [this, U]() {
if (U->getType()->isIntegerTy(1) || isa<ConstantInt>(U->getOperand(0)))
return false;
auto *ICI = dyn_cast<ICmpInst>(U->getOperand(0));
if (!ICI)
return false;
Value *LHS = ICI->getOperand(0);
Value *RHS = ICI->getOperand(1);
if (ICI->getPredicate() == CmpInst::ICMP_EQ ||
ICI->getPredicate() == CmpInst::ICMP_NE) {
if (!(isa<ConstantInt>(RHS) && cast<ConstantInt>(RHS)->isZero()))
return true;
} else if (getTypeSizeInBits(LHS->getType()) >
getTypeSizeInBits(U->getType()))
return true;
return false;
};
if (CanSimplifyToUnknown())
return getUnknown(U);
for (Value *Inc : U->operands())
Ops.push_back(Inc);
return nullptr;
break;
}
case Instruction::Call:
case Instruction::Invoke:
if (Value *RV = cast<CallBase>(U)->getReturnedArgOperand()) {
Ops.push_back(RV);
return nullptr;
}
if (auto *II = dyn_cast<IntrinsicInst>(U)) {
switch (II->getIntrinsicID()) {
case Intrinsic::abs:
Ops.push_back(II->getArgOperand(0));
return nullptr;
case Intrinsic::umax:
case Intrinsic::umin:
case Intrinsic::smax:
case Intrinsic::smin:
case Intrinsic::usub_sat:
case Intrinsic::uadd_sat:
Ops.push_back(II->getArgOperand(0));
Ops.push_back(II->getArgOperand(1));
return nullptr;
case Intrinsic::start_loop_iterations:
case Intrinsic::annotation:
case Intrinsic::ptr_annotation:
Ops.push_back(II->getArgOperand(0));
return nullptr;
default:
break;
}
}
break;
}
return nullptr;
}
const SCEV *ScalarEvolution::createSCEV(Value *V) {
if (!isSCEVable(V->getType()))
return getUnknown(V);
if (Instruction *I = dyn_cast<Instruction>(V)) {
// Don't attempt to analyze instructions in blocks that aren't
// reachable. Such instructions don't matter, and they aren't required
// to obey basic rules for definitions dominating uses which this
// analysis depends on.
if (!DT.isReachableFromEntry(I->getParent()))
return getUnknown(PoisonValue::get(V->getType()));
} else if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
return getConstant(CI);
else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V))
return GA->isInterposable() ? getUnknown(V) : getSCEV(GA->getAliasee());
else if (!isa<ConstantExpr>(V))
return getUnknown(V);
const SCEV *LHS;
const SCEV *RHS;
Operator *U = cast<Operator>(V);
if (auto BO = MatchBinaryOp(U, DT)) {
switch (BO->Opcode) {
case Instruction::Add: {
// The simple thing to do would be to just call getSCEV on both operands
// and call getAddExpr with the result. However if we're looking at a
// bunch of things all added together, this can be quite inefficient,
// because it leads to N-1 getAddExpr calls for N ultimate operands.
// Instead, gather up all the operands and make a single getAddExpr call.
// LLVM IR canonical form means we need only traverse the left operands.
SmallVector<const SCEV *, 4> AddOps;
do {
if (BO->Op) {
if (auto *OpSCEV = getExistingSCEV(BO->Op)) {
AddOps.push_back(OpSCEV);
break;
}
// If a NUW or NSW flag can be applied to the SCEV for this
// addition, then compute the SCEV for this addition by itself
// with a separate call to getAddExpr. We need to do that
// instead of pushing the operands of the addition onto AddOps,
// since the flags are only known to apply to this particular
// addition - they may not apply to other additions that can be
// formed with operands from AddOps.
const SCEV *RHS = getSCEV(BO->RHS);
SCEV::NoWrapFlags Flags = getNoWrapFlagsFromUB(BO->Op);
if (Flags != SCEV::FlagAnyWrap) {
const SCEV *LHS = getSCEV(BO->LHS);
if (BO->Opcode == Instruction::Sub)
AddOps.push_back(getMinusSCEV(LHS, RHS, Flags));
else
AddOps.push_back(getAddExpr(LHS, RHS, Flags));
break;
}
}
if (BO->Opcode == Instruction::Sub)
AddOps.push_back(getNegativeSCEV(getSCEV(BO->RHS)));
else
AddOps.push_back(getSCEV(BO->RHS));
auto NewBO = MatchBinaryOp(BO->LHS, DT);
if (!NewBO || (NewBO->Opcode != Instruction::Add &&
NewBO->Opcode != Instruction::Sub)) {
AddOps.push_back(getSCEV(BO->LHS));
break;
}
BO = NewBO;
} while (true);
return getAddExpr(AddOps);
}
case Instruction::Mul: {
SmallVector<const SCEV *, 4> MulOps;
do {
if (BO->Op) {
if (auto *OpSCEV = getExistingSCEV(BO->Op)) {
MulOps.push_back(OpSCEV);
break;
}
SCEV::NoWrapFlags Flags = getNoWrapFlagsFromUB(BO->Op);
if (Flags != SCEV::FlagAnyWrap) {
LHS = getSCEV(BO->LHS);
RHS = getSCEV(BO->RHS);
MulOps.push_back(getMulExpr(LHS, RHS, Flags));
break;
}
}
MulOps.push_back(getSCEV(BO->RHS));
auto NewBO = MatchBinaryOp(BO->LHS, DT);
if (!NewBO || NewBO->Opcode != Instruction::Mul) {
MulOps.push_back(getSCEV(BO->LHS));
break;
}
BO = NewBO;
} while (true);
return getMulExpr(MulOps);
}
case Instruction::UDiv:
LHS = getSCEV(BO->LHS);
RHS = getSCEV(BO->RHS);
return getUDivExpr(LHS, RHS);
case Instruction::URem:
LHS = getSCEV(BO->LHS);
RHS = getSCEV(BO->RHS);
return getURemExpr(LHS, RHS);
case Instruction::Sub: {
SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap;
if (BO->Op)
Flags = getNoWrapFlagsFromUB(BO->Op);
LHS = getSCEV(BO->LHS);
RHS = getSCEV(BO->RHS);
return getMinusSCEV(LHS, RHS, Flags);
}
case Instruction::And:
// For an expression like x&255 that merely masks off the high bits,
// use zext(trunc(x)) as the SCEV expression.
if (ConstantInt *CI = dyn_cast<ConstantInt>(BO->RHS)) {
if (CI->isZero())
return getSCEV(BO->RHS);
if (CI->isMinusOne())
return getSCEV(BO->LHS);
const APInt &A = CI->getValue();
// Instcombine's ShrinkDemandedConstant may strip bits out of
// constants, obscuring what would otherwise be a low-bits mask.
// Use computeKnownBits to compute what ShrinkDemandedConstant
// knew about to reconstruct a low-bits mask value.
unsigned LZ = A.countLeadingZeros();
unsigned TZ = A.countTrailingZeros();
unsigned BitWidth = A.getBitWidth();
KnownBits Known(BitWidth);
computeKnownBits(BO->LHS, Known, getDataLayout(),
0, &AC, nullptr, &DT);
APInt EffectiveMask =
APInt::getLowBitsSet(BitWidth, BitWidth - LZ - TZ).shl(TZ);
if ((LZ != 0 || TZ != 0) && !((~A & ~Known.Zero) & EffectiveMask)) {
const SCEV *MulCount = getConstant(APInt::getOneBitSet(BitWidth, TZ));
const SCEV *LHS = getSCEV(BO->LHS);
const SCEV *ShiftedLHS = nullptr;
if (auto *LHSMul = dyn_cast<SCEVMulExpr>(LHS)) {
if (auto *OpC = dyn_cast<SCEVConstant>(LHSMul->getOperand(0))) {
// For an expression like (x * 8) & 8, simplify the multiply.
unsigned MulZeros = OpC->getAPInt().countTrailingZeros();
unsigned GCD = std::min(MulZeros, TZ);
APInt DivAmt = APInt::getOneBitSet(BitWidth, TZ - GCD);
SmallVector<const SCEV*, 4> MulOps;
MulOps.push_back(getConstant(OpC->getAPInt().lshr(GCD)));
MulOps.append(LHSMul->op_begin() + 1, LHSMul->op_end());
auto *NewMul = getMulExpr(MulOps, LHSMul->getNoWrapFlags());
ShiftedLHS = getUDivExpr(NewMul, getConstant(DivAmt));
}
}
if (!ShiftedLHS)
ShiftedLHS = getUDivExpr(LHS, MulCount);
return getMulExpr(
getZeroExtendExpr(
getTruncateExpr(ShiftedLHS,
IntegerType::get(getContext(), BitWidth - LZ - TZ)),
BO->LHS->getType()),
MulCount);
}
}
// Binary `and` is a bit-wise `umin`.
if (BO->LHS->getType()->isIntegerTy(1)) {
LHS = getSCEV(BO->LHS);
RHS = getSCEV(BO->RHS);
return getUMinExpr(LHS, RHS);
}
break;
case Instruction::Or:
// If the RHS of the Or is a constant, we may have something like:
// X*4+1 which got turned into X*4|1. Handle this as an Add so loop
// optimizations will transparently handle this case.
//
// In order for this transformation to be safe, the LHS must be of the
// form X*(2^n) and the Or constant must be less than 2^n.
if (ConstantInt *CI = dyn_cast<ConstantInt>(BO->RHS)) {
const SCEV *LHS = getSCEV(BO->LHS);
const APInt &CIVal = CI->getValue();
if (GetMinTrailingZeros(LHS) >=
(CIVal.getBitWidth() - CIVal.countLeadingZeros())) {
// Build a plain add SCEV.
return getAddExpr(LHS, getSCEV(CI),
(SCEV::NoWrapFlags)(SCEV::FlagNUW | SCEV::FlagNSW));
}
}
// Binary `or` is a bit-wise `umax`.
if (BO->LHS->getType()->isIntegerTy(1)) {
LHS = getSCEV(BO->LHS);
RHS = getSCEV(BO->RHS);
return getUMaxExpr(LHS, RHS);
}
break;
case Instruction::Xor:
if (ConstantInt *CI = dyn_cast<ConstantInt>(BO->RHS)) {
// If the RHS of xor is -1, then this is a not operation.
if (CI->isMinusOne())
return getNotSCEV(getSCEV(BO->LHS));
// Model xor(and(x, C), C) as and(~x, C), if C is a low-bits mask.
// This is a variant of the check for xor with -1, and it handles
// the case where instcombine has trimmed non-demanded bits out
// of an xor with -1.
if (auto *LBO = dyn_cast<BinaryOperator>(BO->LHS))
if (ConstantInt *LCI = dyn_cast<ConstantInt>(LBO->getOperand(1)))
if (LBO->getOpcode() == Instruction::And &&
LCI->getValue() == CI->getValue())
if (const SCEVZeroExtendExpr *Z =
dyn_cast<SCEVZeroExtendExpr>(getSCEV(BO->LHS))) {
Type *UTy = BO->LHS->getType();
const SCEV *Z0 = Z->getOperand();
Type *Z0Ty = Z0->getType();
unsigned Z0TySize = getTypeSizeInBits(Z0Ty);
// If C is a low-bits mask, the zero extend is serving to
// mask off the high bits. Complement the operand and
// re-apply the zext.
if (CI->getValue().isMask(Z0TySize))
return getZeroExtendExpr(getNotSCEV(Z0), UTy);
// If C is a single bit, it may be in the sign-bit position
// before the zero-extend. In this case, represent the xor
// using an add, which is equivalent, and re-apply the zext.
APInt Trunc = CI->getValue().trunc(Z0TySize);
if (Trunc.zext(getTypeSizeInBits(UTy)) == CI->getValue() &&
Trunc.isSignMask())
return getZeroExtendExpr(getAddExpr(Z0, getConstant(Trunc)),
UTy);
}
}
break;
case Instruction::Shl:
// Turn shift left of a constant amount into a multiply.
if (ConstantInt *SA = dyn_cast<ConstantInt>(BO->RHS)) {
uint32_t BitWidth = cast<IntegerType>(SA->getType())->getBitWidth();
// If the shift count is not less than the bitwidth, the result of
// the shift is undefined. Don't try to analyze it, because the
// resolution chosen here may differ from the resolution chosen in
// other parts of the compiler.
if (SA->getValue().uge(BitWidth))
break;
// We can safely preserve the nuw flag in all cases. It's also safe to
// turn a nuw nsw shl into a nuw nsw mul. However, nsw in isolation
// requires special handling. It can be preserved as long as we're not
// left shifting by bitwidth - 1.
auto Flags = SCEV::FlagAnyWrap;
if (BO->Op) {
auto MulFlags = getNoWrapFlagsFromUB(BO->Op);
if ((MulFlags & SCEV::FlagNSW) &&
((MulFlags & SCEV::FlagNUW) || SA->getValue().ult(BitWidth - 1)))
Flags = (SCEV::NoWrapFlags)(Flags | SCEV::FlagNSW);
if (MulFlags & SCEV::FlagNUW)
Flags = (SCEV::NoWrapFlags)(Flags | SCEV::FlagNUW);
}
ConstantInt *X = ConstantInt::get(
getContext(), APInt::getOneBitSet(BitWidth, SA->getZExtValue()));
return getMulExpr(getSCEV(BO->LHS), getConstant(X), Flags);
}
break;
case Instruction::AShr: {
// AShr X, C, where C is a constant.
ConstantInt *CI = dyn_cast<ConstantInt>(BO->RHS);
if (!CI)
break;
Type *OuterTy = BO->LHS->getType();
uint64_t BitWidth = getTypeSizeInBits(OuterTy);
// If the shift count is not less than the bitwidth, the result of
// the shift is undefined. Don't try to analyze it, because the
// resolution chosen here may differ from the resolution chosen in
// other parts of the compiler.
if (CI->getValue().uge(BitWidth))
break;
if (CI->isZero())
return getSCEV(BO->LHS); // shift by zero --> noop
uint64_t AShrAmt = CI->getZExtValue();
Type *TruncTy = IntegerType::get(getContext(), BitWidth - AShrAmt);
Operator *L = dyn_cast<Operator>(BO->LHS);
if (L && L->getOpcode() == Instruction::Shl) {
// X = Shl A, n
// Y = AShr X, m
// Both n and m are constant.
const SCEV *ShlOp0SCEV = getSCEV(L->getOperand(0));
if (L->getOperand(1) == BO->RHS)
// For a two-shift sext-inreg, i.e. n = m,
// use sext(trunc(x)) as the SCEV expression.
return getSignExtendExpr(
getTruncateExpr(ShlOp0SCEV, TruncTy), OuterTy);
ConstantInt *ShlAmtCI = dyn_cast<ConstantInt>(L->getOperand(1));
if (ShlAmtCI && ShlAmtCI->getValue().ult(BitWidth)) {
uint64_t ShlAmt = ShlAmtCI->getZExtValue();
if (ShlAmt > AShrAmt) {
// When n > m, use sext(mul(trunc(x), 2^(n-m)))) as the SCEV
// expression. We already checked that ShlAmt < BitWidth, so
// the multiplier, 1 << (ShlAmt - AShrAmt), fits into TruncTy as
// ShlAmt - AShrAmt < Amt.
APInt Mul = APInt::getOneBitSet(BitWidth - AShrAmt,
ShlAmt - AShrAmt);
return getSignExtendExpr(
getMulExpr(getTruncateExpr(ShlOp0SCEV, TruncTy),
getConstant(Mul)), OuterTy);
}
}
}
break;
}
}
}
switch (U->getOpcode()) {
case Instruction::Trunc:
return getTruncateExpr(getSCEV(U->getOperand(0)), U->getType());
case Instruction::ZExt:
return getZeroExtendExpr(getSCEV(U->getOperand(0)), U->getType());
case Instruction::SExt:
if (auto BO = MatchBinaryOp(U->getOperand(0), DT)) {
// The NSW flag of a subtract does not always survive the conversion to
// A + (-1)*B. By pushing sign extension onto its operands we are much
// more likely to preserve NSW and allow later AddRec optimisations.
//
// NOTE: This is effectively duplicating this logic from getSignExtend:
// sext((A + B + ...)<nsw>) --> (sext(A) + sext(B) + ...)<nsw>
// but by that point the NSW information has potentially been lost.
if (BO->Opcode == Instruction::Sub && BO->IsNSW) {
Type *Ty = U->getType();
auto *V1 = getSignExtendExpr(getSCEV(BO->LHS), Ty);
auto *V2 = getSignExtendExpr(getSCEV(BO->RHS), Ty);
return getMinusSCEV(V1, V2, SCEV::FlagNSW);
}
}
return getSignExtendExpr(getSCEV(U->getOperand(0)), U->getType());
case Instruction::BitCast:
// BitCasts are no-op casts so we just eliminate the cast.
if (isSCEVable(U->getType()) && isSCEVable(U->getOperand(0)->getType()))
return getSCEV(U->getOperand(0));
break;
case Instruction::PtrToInt: {
// Pointer to integer cast is straight-forward, so do model it.
const SCEV *Op = getSCEV(U->getOperand(0));
Type *DstIntTy = U->getType();
// But only if effective SCEV (integer) type is wide enough to represent
// all possible pointer values.
const SCEV *IntOp = getPtrToIntExpr(Op, DstIntTy);
if (isa<SCEVCouldNotCompute>(IntOp))
return getUnknown(V);
return IntOp;
}
case Instruction::IntToPtr:
// Just don't deal with inttoptr casts.
return getUnknown(V);
case Instruction::SDiv:
// If both operands are non-negative, this is just an udiv.
if (isKnownNonNegative(getSCEV(U->getOperand(0))) &&
isKnownNonNegative(getSCEV(U->getOperand(1))))
return getUDivExpr(getSCEV(U->getOperand(0)), getSCEV(U->getOperand(1)));
break;
case Instruction::SRem:
// If both operands are non-negative, this is just an urem.
if (isKnownNonNegative(getSCEV(U->getOperand(0))) &&
isKnownNonNegative(getSCEV(U->getOperand(1))))
return getURemExpr(getSCEV(U->getOperand(0)), getSCEV(U->getOperand(1)));
break;
case Instruction::GetElementPtr:
return createNodeForGEP(cast<GEPOperator>(U));
case Instruction::PHI:
return createNodeForPHI(cast<PHINode>(U));
case Instruction::Select:
return createNodeForSelectOrPHI(U, U->getOperand(0), U->getOperand(1),
U->getOperand(2));
case Instruction::Call:
case Instruction::Invoke:
if (Value *RV = cast<CallBase>(U)->getReturnedArgOperand())
return getSCEV(RV);
if (auto *II = dyn_cast<IntrinsicInst>(U)) {
switch (II->getIntrinsicID()) {
case Intrinsic::abs:
return getAbsExpr(
getSCEV(II->getArgOperand(0)),
/*IsNSW=*/cast<ConstantInt>(II->getArgOperand(1))->isOne());
case Intrinsic::umax:
LHS = getSCEV(II->getArgOperand(0));
RHS = getSCEV(II->getArgOperand(1));
return getUMaxExpr(LHS, RHS);
case Intrinsic::umin:
LHS = getSCEV(II->getArgOperand(0));
RHS = getSCEV(II->getArgOperand(1));
return getUMinExpr(LHS, RHS);
case Intrinsic::smax:
LHS = getSCEV(II->getArgOperand(0));
RHS = getSCEV(II->getArgOperand(1));
return getSMaxExpr(LHS, RHS);
case Intrinsic::smin:
LHS = getSCEV(II->getArgOperand(0));
RHS = getSCEV(II->getArgOperand(1));
return getSMinExpr(LHS, RHS);
case Intrinsic::usub_sat: {
const SCEV *X = getSCEV(II->getArgOperand(0));
const SCEV *Y = getSCEV(II->getArgOperand(1));
const SCEV *ClampedY = getUMinExpr(X, Y);
return getMinusSCEV(X, ClampedY, SCEV::FlagNUW);
}
case Intrinsic::uadd_sat: {
const SCEV *X = getSCEV(II->getArgOperand(0));
const SCEV *Y = getSCEV(II->getArgOperand(1));
const SCEV *ClampedX = getUMinExpr(X, getNotSCEV(Y));
return getAddExpr(ClampedX, Y, SCEV::FlagNUW);
}
case Intrinsic::start_loop_iterations:
case Intrinsic::annotation:
case Intrinsic::ptr_annotation:
// A start_loop_iterations or llvm.annotation or llvm.prt.annotation is
// just eqivalent to the first operand for SCEV purposes.
return getSCEV(II->getArgOperand(0));
default:
break;
}
}
break;
}
return getUnknown(V);
}
//===----------------------------------------------------------------------===//
// Iteration Count Computation Code
//
const SCEV *ScalarEvolution::getTripCountFromExitCount(const SCEV *ExitCount,
bool Extend) {
if (isa<SCEVCouldNotCompute>(ExitCount))
return getCouldNotCompute();
auto *ExitCountType = ExitCount->getType();
assert(ExitCountType->isIntegerTy());
if (!Extend)
return getAddExpr(ExitCount, getOne(ExitCountType));
auto *WiderType = Type::getIntNTy(ExitCountType->getContext(),
1 + ExitCountType->getScalarSizeInBits());
return getAddExpr(getNoopOrZeroExtend(ExitCount, WiderType),
getOne(WiderType));
}
static unsigned getConstantTripCount(const SCEVConstant *ExitCount) {
if (!ExitCount)
return 0;
ConstantInt *ExitConst = ExitCount->getValue();
// Guard against huge trip counts.
if (ExitConst->getValue().getActiveBits() > 32)
return 0;
// In case of integer overflow, this returns 0, which is correct.
return ((unsigned)ExitConst->getZExtValue()) + 1;
}
unsigned ScalarEvolution::getSmallConstantTripCount(const Loop *L) {
auto *ExitCount = dyn_cast<SCEVConstant>(getBackedgeTakenCount(L, Exact));
return getConstantTripCount(ExitCount);
}
unsigned
ScalarEvolution::getSmallConstantTripCount(const Loop *L,
const BasicBlock *ExitingBlock) {
assert(ExitingBlock && "Must pass a non-null exiting block!");
assert(L->isLoopExiting(ExitingBlock) &&
"Exiting block must actually branch out of the loop!");
const SCEVConstant *ExitCount =
dyn_cast<SCEVConstant>(getExitCount(L, ExitingBlock));
return getConstantTripCount(ExitCount);
}
unsigned ScalarEvolution::getSmallConstantMaxTripCount(const Loop *L) {
const auto *MaxExitCount =
dyn_cast<SCEVConstant>(getConstantMaxBackedgeTakenCount(L));
return getConstantTripCount(MaxExitCount);
}
const SCEV *ScalarEvolution::getConstantMaxTripCountFromArray(const Loop *L) {
// We can't infer from Array in Irregular Loop.
// FIXME: It's hard to infer loop bound from array operated in Nested Loop.
if (!L->isLoopSimplifyForm() || !L->isInnermost())
return getCouldNotCompute();
// FIXME: To make the scene more typical, we only analysis loops that have
// one exiting block and that block must be the latch. To make it easier to
// capture loops that have memory access and memory access will be executed
// in each iteration.
const BasicBlock *LoopLatch = L->getLoopLatch();
assert(LoopLatch && "See defination of simplify form loop.");
if (L->getExitingBlock() != LoopLatch)
return getCouldNotCompute();
const DataLayout &DL = getDataLayout();
SmallVector<const SCEV *> InferCountColl;
for (auto *BB : L->getBlocks()) {
// Go here, we can know that Loop is a single exiting and simplified form
// loop. Make sure that infer from Memory Operation in those BBs must be
// executed in loop. First step, we can make sure that max execution time
// of MemAccessBB in loop represents latch max excution time.
// If MemAccessBB does not dom Latch, skip.
// Entry
// │
// ┌─────▼─────┐
// │Loop Header◄─────┐
// └──┬──────┬─┘ │
// │ │ │
// ┌────────▼──┐ ┌─▼─────┐ │
// │MemAccessBB│ │OtherBB│ │
// └────────┬──┘ └─┬─────┘ │
// │ │ │
// ┌─▼──────▼─┐ │
// │Loop Latch├─────┘
// └────┬─────┘
// ▼
// Exit
if (!DT.dominates(BB, LoopLatch))
continue;
for (Instruction &Inst : *BB) {
// Find Memory Operation Instruction.
auto *GEP = getLoadStorePointerOperand(&Inst);
if (!GEP)
continue;
auto *ElemSize = dyn_cast<SCEVConstant>(getElementSize(&Inst));
// Do not infer from scalar type, eg."ElemSize = sizeof()".
if (!ElemSize)
continue;
// Use a existing polynomial recurrence on the trip count.
auto *AddRec = dyn_cast<SCEVAddRecExpr>(getSCEV(GEP));
if (!AddRec)
continue;
auto *ArrBase = dyn_cast<SCEVUnknown>(getPointerBase(AddRec));
auto *Step = dyn_cast<SCEVConstant>(AddRec->getStepRecurrence(*this));
if (!ArrBase || !Step)
continue;
assert(isLoopInvariant(ArrBase, L) && "See addrec definition");
// Only handle { %array + step },
// FIXME: {(SCEVAddRecExpr) + step } could not be analysed here.
if (AddRec->getStart() != ArrBase)
continue;
// Memory operation pattern which have gaps.
// Or repeat memory opreation.
// And index of GEP wraps arround.
if (Step->getAPInt().getActiveBits() > 32 ||
Step->getAPInt().getZExtValue() !=
ElemSize->getAPInt().getZExtValue() ||
Step->isZero() || Step->getAPInt().isNegative())
continue;
// Only infer from stack array which has certain size.
// Make sure alloca instruction is not excuted in loop.
AllocaInst *AllocateInst = dyn_cast<AllocaInst>(ArrBase->getValue());
if (!AllocateInst || L->contains(AllocateInst->getParent()))
continue;
// Make sure only handle normal array.
auto *Ty = dyn_cast<ArrayType>(AllocateInst->getAllocatedType());
auto *ArrSize = dyn_cast<ConstantInt>(AllocateInst->getArraySize());
if (!Ty || !ArrSize || !ArrSize->isOne())
continue;
// FIXME: Since gep indices are silently zext to the indexing type,
// we will have a narrow gep index which wraps around rather than
// increasing strictly, we shoule ensure that step is increasing
// strictly by the loop iteration.
// Now we can infer a max execution time by MemLength/StepLength.
const SCEV *MemSize =
getConstant(Step->getType(), DL.getTypeAllocSize(Ty));
auto *MaxExeCount =
dyn_cast<SCEVConstant>(getUDivCeilSCEV(MemSize, Step));
if (!MaxExeCount || MaxExeCount->getAPInt().getActiveBits() > 32)
continue;
// If the loop reaches the maximum number of executions, we can not
// access bytes starting outside the statically allocated size without
// being immediate UB. But it is allowed to enter loop header one more
// time.
auto *InferCount = dyn_cast<SCEVConstant>(
getAddExpr(MaxExeCount, getOne(MaxExeCount->getType())));
// Discard the maximum number of execution times under 32bits.
if (!InferCount || InferCount->getAPInt().getActiveBits() > 32)
continue;
InferCountColl.push_back(InferCount);
}
}
if (InferCountColl.size() == 0)
return getCouldNotCompute();
return getUMinFromMismatchedTypes(InferCountColl);
}
unsigned ScalarEvolution::getSmallConstantTripMultiple(const Loop *L) {
SmallVector<BasicBlock *, 8> ExitingBlocks;
L->getExitingBlocks(ExitingBlocks);
Optional<unsigned> Res = None;
for (auto *ExitingBB : ExitingBlocks) {
unsigned Multiple = getSmallConstantTripMultiple(L, ExitingBB);
if (!Res)
Res = Multiple;
Res = (unsigned)GreatestCommonDivisor64(*Res, Multiple);
}
return Res.value_or(1);
}
unsigned ScalarEvolution::getSmallConstantTripMultiple(const Loop *L,
const SCEV *ExitCount) {
if (ExitCount == getCouldNotCompute())
return 1;
// Get the trip count
const SCEV *TCExpr = getTripCountFromExitCount(ExitCount);
const SCEVConstant *TC = dyn_cast<SCEVConstant>(TCExpr);
if (!TC)
// Attempt to factor more general cases. Returns the greatest power of
// two divisor. If overflow happens, the trip count expression is still
// divisible by the greatest power of 2 divisor returned.
return 1U << std::min((uint32_t)31,
GetMinTrailingZeros(applyLoopGuards(TCExpr, L)));
ConstantInt *Result = TC->getValue();
// Guard against huge trip counts (this requires checking
// for zero to handle the case where the trip count == -1 and the
// addition wraps).
if (!Result || Result->getValue().getActiveBits() > 32 ||
Result->getValue().getActiveBits() == 0)
return 1;
return (unsigned)Result->getZExtValue();
}
/// Returns the largest constant divisor of the trip count of this loop as a
/// normal unsigned value, if possible. This means that the actual trip count is
/// always a multiple of the returned value (don't forget the trip count could
/// very well be zero as well!).
///
/// Returns 1 if the trip count is unknown or not guaranteed to be the
/// multiple of a constant (which is also the case if the trip count is simply
/// constant, use getSmallConstantTripCount for that case), Will also return 1
/// if the trip count is very large (>= 2^32).
///
/// As explained in the comments for getSmallConstantTripCount, this assumes
/// that control exits the loop via ExitingBlock.
unsigned
ScalarEvolution::getSmallConstantTripMultiple(const Loop *L,
const BasicBlock *ExitingBlock) {
assert(ExitingBlock && "Must pass a non-null exiting block!");
assert(L->isLoopExiting(ExitingBlock) &&
"Exiting block must actually branch out of the loop!");
const SCEV *ExitCount = getExitCount(L, ExitingBlock);
return getSmallConstantTripMultiple(L, ExitCount);
}
const SCEV *ScalarEvolution::getExitCount(const Loop *L,
const BasicBlock *ExitingBlock,
ExitCountKind Kind) {
switch (Kind) {
case Exact:
case SymbolicMaximum:
return getBackedgeTakenInfo(L).getExact(ExitingBlock, this);
case ConstantMaximum:
return getBackedgeTakenInfo(L).getConstantMax(ExitingBlock, this);
};
llvm_unreachable("Invalid ExitCountKind!");
}
const SCEV *
ScalarEvolution::getPredicatedBackedgeTakenCount(const Loop *L,
SmallVector<const SCEVPredicate *, 4> &Preds) {
return getPredicatedBackedgeTakenInfo(L).getExact(L, this, &Preds);
}
const SCEV *ScalarEvolution::getBackedgeTakenCount(const Loop *L,
ExitCountKind Kind) {
switch (Kind) {
case Exact:
return getBackedgeTakenInfo(L).getExact(L, this);
case ConstantMaximum:
return getBackedgeTakenInfo(L).getConstantMax(this);
case SymbolicMaximum:
return getBackedgeTakenInfo(L).getSymbolicMax(L, this);
};
llvm_unreachable("Invalid ExitCountKind!");
}
bool ScalarEvolution::isBackedgeTakenCountMaxOrZero(const Loop *L) {
return getBackedgeTakenInfo(L).isConstantMaxOrZero(this);
}
/// Push PHI nodes in the header of the given loop onto the given Worklist.
static void PushLoopPHIs(const Loop *L,
SmallVectorImpl<Instruction *> &Worklist,
SmallPtrSetImpl<Instruction *> &Visited) {
BasicBlock *Header = L->getHeader();
// Push all Loop-header PHIs onto the Worklist stack.
for (PHINode &PN : Header->phis())
if (Visited.insert(&PN).second)
Worklist.push_back(&PN);
}
const ScalarEvolution::BackedgeTakenInfo &
ScalarEvolution::getPredicatedBackedgeTakenInfo(const Loop *L) {
auto &BTI = getBackedgeTakenInfo(L);
if (BTI.hasFullInfo())
return BTI;
auto Pair = PredicatedBackedgeTakenCounts.insert({L, BackedgeTakenInfo()});
if (!Pair.second)
return Pair.first->second;
BackedgeTakenInfo Result =
computeBackedgeTakenCount(L, /*AllowPredicates=*/true);
return PredicatedBackedgeTakenCounts.find(L)->second = std::move(Result);
}
ScalarEvolution::BackedgeTakenInfo &
ScalarEvolution::getBackedgeTakenInfo(const Loop *L) {
// Initially insert an invalid entry for this loop. If the insertion
// succeeds, proceed to actually compute a backedge-taken count and
// update the value. The temporary CouldNotCompute value tells SCEV
// code elsewhere that it shouldn't attempt to request a new
// backedge-taken count, which could result in infinite recursion.
std::pair<DenseMap<const Loop *, BackedgeTakenInfo>::iterator, bool> Pair =
BackedgeTakenCounts.insert({L, BackedgeTakenInfo()});
if (!Pair.second)
return Pair.first->second;
// computeBackedgeTakenCount may allocate memory for its result. Inserting it
// into the BackedgeTakenCounts map transfers ownership. Otherwise, the result
// must be cleared in this scope.
BackedgeTakenInfo Result = computeBackedgeTakenCount(L);
// In product build, there are no usage of statistic.
(void)NumTripCountsComputed;
(void)NumTripCountsNotComputed;
#if LLVM_ENABLE_STATS || !defined(NDEBUG)
const SCEV *BEExact = Result.getExact(L, this);
if (BEExact != getCouldNotCompute()) {
assert(isLoopInvariant(BEExact, L) &&
isLoopInvariant(Result.getConstantMax(this), L) &&
"Computed backedge-taken count isn't loop invariant for loop!");
++NumTripCountsComputed;
} else if (Result.getConstantMax(this) == getCouldNotCompute() &&
isa<PHINode>(L->getHeader()->begin())) {
// Only count loops that have phi nodes as not being computable.
++NumTripCountsNotComputed;
}
#endif // LLVM_ENABLE_STATS || !defined(NDEBUG)
// Now that we know more about the trip count for this loop, forget any
// existing SCEV values for PHI nodes in this loop since they are only
// conservative estimates made without the benefit of trip count
// information. This invalidation is not necessary for correctness, and is
// only done to produce more precise results.
if (Result.hasAnyInfo()) {
// Invalidate any expression using an addrec in this loop.
SmallVector<const SCEV *, 8> ToForget;
auto LoopUsersIt = LoopUsers.find(L);
if (LoopUsersIt != LoopUsers.end())
append_range(ToForget, LoopUsersIt->second);
forgetMemoizedResults(ToForget);
// Invalidate constant-evolved loop header phis.
for (PHINode &PN : L->getHeader()->phis())
ConstantEvolutionLoopExitValue.erase(&PN);
}
// Re-lookup the insert position, since the call to
// computeBackedgeTakenCount above could result in a
// recusive call to getBackedgeTakenInfo (on a different
// loop), which would invalidate the iterator computed
// earlier.
return BackedgeTakenCounts.find(L)->second = std::move(Result);
}
void ScalarEvolution::forgetAllLoops() {
// This method is intended to forget all info about loops. It should
// invalidate caches as if the following happened:
// - The trip counts of all loops have changed arbitrarily
// - Every llvm::Value has been updated in place to produce a different
// result.
BackedgeTakenCounts.clear();
PredicatedBackedgeTakenCounts.clear();
BECountUsers.clear();
LoopPropertiesCache.clear();
ConstantEvolutionLoopExitValue.clear();
ValueExprMap.clear();
ValuesAtScopes.clear();
ValuesAtScopesUsers.clear();
LoopDispositions.clear();
BlockDispositions.clear();
UnsignedRanges.clear();
SignedRanges.clear();
ExprValueMap.clear();
HasRecMap.clear();
MinTrailingZerosCache.clear();
PredicatedSCEVRewrites.clear();
}
void ScalarEvolution::forgetLoop(const Loop *L) {
SmallVector<const Loop *, 16> LoopWorklist(1, L);
SmallVector<Instruction *, 32> Worklist;
SmallPtrSet<Instruction *, 16> Visited;
SmallVector<const SCEV *, 16> ToForget;
// Iterate over all the loops and sub-loops to drop SCEV information.
while (!LoopWorklist.empty()) {
auto *CurrL = LoopWorklist.pop_back_val();
// Drop any stored trip count value.
forgetBackedgeTakenCounts(CurrL, /* Predicated */ false);
forgetBackedgeTakenCounts(CurrL, /* Predicated */ true);
// Drop information about predicated SCEV rewrites for this loop.
for (auto I = PredicatedSCEVRewrites.begin();
I != PredicatedSCEVRewrites.end();) {
std::pair<const SCEV *, const Loop *> Entry = I->first;
if (Entry.second == CurrL)
PredicatedSCEVRewrites.erase(I++);
else
++I;
}
auto LoopUsersItr = LoopUsers.find(CurrL);
if (LoopUsersItr != LoopUsers.end()) {
ToForget.insert(ToForget.end(), LoopUsersItr->second.begin(),
LoopUsersItr->second.end());
}
// Drop information about expressions based on loop-header PHIs.
PushLoopPHIs(CurrL, Worklist, Visited);
while (!Worklist.empty()) {
Instruction *I = Worklist.pop_back_val();
ValueExprMapType::iterator It =
ValueExprMap.find_as(static_cast<Value *>(I));
if (It != ValueExprMap.end()) {
eraseValueFromMap(It->first);
ToForget.push_back(It->second);
if (PHINode *PN = dyn_cast<PHINode>(I))
ConstantEvolutionLoopExitValue.erase(PN);
}
PushDefUseChildren(I, Worklist, Visited);
}
LoopPropertiesCache.erase(CurrL);
// Forget all contained loops too, to avoid dangling entries in the
// ValuesAtScopes map.
LoopWorklist.append(CurrL->begin(), CurrL->end());
}
forgetMemoizedResults(ToForget);
}
void ScalarEvolution::forgetTopmostLoop(const Loop *L) {
forgetLoop(L->getOutermostLoop());
}
void ScalarEvolution::forgetValue(Value *V) {
Instruction *I = dyn_cast<Instruction>(V);
if (!I) return;
// Drop information about expressions based on loop-header PHIs.
SmallVector<Instruction *, 16> Worklist;
SmallPtrSet<Instruction *, 8> Visited;
SmallVector<const SCEV *, 8> ToForget;
Worklist.push_back(I);
Visited.insert(I);
while (!Worklist.empty()) {
I = Worklist.pop_back_val();
ValueExprMapType::iterator It =
ValueExprMap.find_as(static_cast<Value *>(I));
if (It != ValueExprMap.end()) {
eraseValueFromMap(It->first);
ToForget.push_back(It->second);
if (PHINode *PN = dyn_cast<PHINode>(I))
ConstantEvolutionLoopExitValue.erase(PN);
}
PushDefUseChildren(I, Worklist, Visited);
}
forgetMemoizedResults(ToForget);
}
void ScalarEvolution::forgetLoopDispositions(const Loop *L) {
LoopDispositions.clear();
}
/// Get the exact loop backedge taken count considering all loop exits. A
/// computable result can only be returned for loops with all exiting blocks
/// dominating the latch. howFarToZero assumes that the limit of each loop test
/// is never skipped. This is a valid assumption as long as the loop exits via
/// that test. For precise results, it is the caller's responsibility to specify
/// the relevant loop exiting block using getExact(ExitingBlock, SE).
const SCEV *
ScalarEvolution::BackedgeTakenInfo::getExact(const Loop *L, ScalarEvolution *SE,
SmallVector<const SCEVPredicate *, 4> *Preds) const {
// If any exits were not computable, the loop is not computable.
if (!isComplete() || ExitNotTaken.empty())
return SE->getCouldNotCompute();
const BasicBlock *Latch = L->getLoopLatch();
// All exiting blocks we have collected must dominate the only backedge.
if (!Latch)
return SE->getCouldNotCompute();
// All exiting blocks we have gathered dominate loop's latch, so exact trip
// count is simply a minimum out of all these calculated exit counts.
SmallVector<const SCEV *, 2> Ops;
for (const auto &ENT : ExitNotTaken) {
const SCEV *BECount = ENT.ExactNotTaken;
assert(BECount != SE->getCouldNotCompute() && "Bad exit SCEV!");
assert(SE->DT.dominates(ENT.ExitingBlock, Latch) &&
"We should only have known counts for exiting blocks that dominate "
"latch!");
Ops.push_back(BECount);
if (Preds)
for (const auto *P : ENT.Predicates)
Preds->push_back(P);
assert((Preds || ENT.hasAlwaysTruePredicate()) &&
"Predicate should be always true!");
}
// If an earlier exit exits on the first iteration (exit count zero), then
// a later poison exit count should not propagate into the result. This are
// exactly the semantics provided by umin_seq.
return SE->getUMinFromMismatchedTypes(Ops, /* Sequential */ true);
}
/// Get the exact not taken count for this loop exit.
const SCEV *
ScalarEvolution::BackedgeTakenInfo::getExact(const BasicBlock *ExitingBlock,
ScalarEvolution *SE) const {
for (const auto &ENT : ExitNotTaken)
if (ENT.ExitingBlock == ExitingBlock && ENT.hasAlwaysTruePredicate())
return ENT.ExactNotTaken;
return SE->getCouldNotCompute();
}
const SCEV *ScalarEvolution::BackedgeTakenInfo::getConstantMax(
const BasicBlock *ExitingBlock, ScalarEvolution *SE) const {
for (const auto &ENT : ExitNotTaken)
if (ENT.ExitingBlock == ExitingBlock && ENT.hasAlwaysTruePredicate())
return ENT.MaxNotTaken;
return SE->getCouldNotCompute();
}
/// getConstantMax - Get the constant max backedge taken count for the loop.
const SCEV *
ScalarEvolution::BackedgeTakenInfo::getConstantMax(ScalarEvolution *SE) const {
auto PredicateNotAlwaysTrue = [](const ExitNotTakenInfo &ENT) {
return !ENT.hasAlwaysTruePredicate();
};
if (!getConstantMax() || any_of(ExitNotTaken, PredicateNotAlwaysTrue))
return SE->getCouldNotCompute();
assert((isa<SCEVCouldNotCompute>(getConstantMax()) ||
isa<SCEVConstant>(getConstantMax())) &&
"No point in having a non-constant max backedge taken count!");
return getConstantMax();
}
const SCEV *
ScalarEvolution::BackedgeTakenInfo::getSymbolicMax(const Loop *L,
ScalarEvolution *SE) {
if (!SymbolicMax)
SymbolicMax = SE->computeSymbolicMaxBackedgeTakenCount(L);
return SymbolicMax;
}
bool ScalarEvolution::BackedgeTakenInfo::isConstantMaxOrZero(
ScalarEvolution *SE) const {
auto PredicateNotAlwaysTrue = [](const ExitNotTakenInfo &ENT) {
return !ENT.hasAlwaysTruePredicate();
};
return MaxOrZero && !any_of(ExitNotTaken, PredicateNotAlwaysTrue);
}
ScalarEvolution::ExitLimit::ExitLimit(const SCEV *E)
: ExitLimit(E, E, false, None) {
}
ScalarEvolution::ExitLimit::ExitLimit(
const SCEV *E, const SCEV *M, bool MaxOrZero,
ArrayRef<const SmallPtrSetImpl<const SCEVPredicate *> *> PredSetList)
: ExactNotTaken(E), MaxNotTaken(M), MaxOrZero(MaxOrZero) {
// If we prove the max count is zero, so is the symbolic bound. This happens
// in practice due to differences in a) how context sensitive we've chosen
// to be and b) how we reason about bounds impied by UB.
if (MaxNotTaken->isZero())
ExactNotTaken = MaxNotTaken;
assert((isa<SCEVCouldNotCompute>(ExactNotTaken) ||
!isa<SCEVCouldNotCompute>(MaxNotTaken)) &&
"Exact is not allowed to be less precise than Max");
assert((isa<SCEVCouldNotCompute>(MaxNotTaken) ||
isa<SCEVConstant>(MaxNotTaken)) &&
"No point in having a non-constant max backedge taken count!");
for (const auto *PredSet : PredSetList)
for (const auto *P : *PredSet)
addPredicate(P);
assert((isa<SCEVCouldNotCompute>(E) || !E->getType()->isPointerTy()) &&
"Backedge count should be int");
assert((isa<SCEVCouldNotCompute>(M) || !M->getType()->isPointerTy()) &&
"Max backedge count should be int");
}
ScalarEvolution::ExitLimit::ExitLimit(
const SCEV *E, const SCEV *M, bool MaxOrZero,
const SmallPtrSetImpl<const SCEVPredicate *> &PredSet)
: ExitLimit(E, M, MaxOrZero, {&PredSet}) {
}
ScalarEvolution::ExitLimit::ExitLimit(const SCEV *E, const SCEV *M,
bool MaxOrZero)
: ExitLimit(E, M, MaxOrZero, None) {
}
/// Allocate memory for BackedgeTakenInfo and copy the not-taken count of each
/// computable exit into a persistent ExitNotTakenInfo array.
ScalarEvolution::BackedgeTakenInfo::BackedgeTakenInfo(
ArrayRef<ScalarEvolution::BackedgeTakenInfo::EdgeExitInfo> ExitCounts,
bool IsComplete, const SCEV *ConstantMax, bool MaxOrZero)
: ConstantMax(ConstantMax), IsComplete(IsComplete), MaxOrZero(MaxOrZero) {
using EdgeExitInfo = ScalarEvolution::BackedgeTakenInfo::EdgeExitInfo;
ExitNotTaken.reserve(ExitCounts.size());
std::transform(
ExitCounts.begin(), ExitCounts.end(), std::back_inserter(ExitNotTaken),
[&](const EdgeExitInfo &EEI) {
BasicBlock *ExitBB = EEI.first;
const ExitLimit &EL = EEI.second;
return ExitNotTakenInfo(ExitBB, EL.ExactNotTaken, EL.MaxNotTaken,
EL.Predicates);
});
assert((isa<SCEVCouldNotCompute>(ConstantMax) ||
isa<SCEVConstant>(ConstantMax)) &&
"No point in having a non-constant max backedge taken count!");
}
/// Compute the number of times the backedge of the specified loop will execute.
ScalarEvolution::BackedgeTakenInfo
ScalarEvolution::computeBackedgeTakenCount(const Loop *L,
bool AllowPredicates) {
SmallVector<BasicBlock *, 8> ExitingBlocks;
L->getExitingBlocks(ExitingBlocks);
using EdgeExitInfo = ScalarEvolution::BackedgeTakenInfo::EdgeExitInfo;
SmallVector<EdgeExitInfo, 4> ExitCounts;
bool CouldComputeBECount = true;
BasicBlock *Latch = L->getLoopLatch(); // may be NULL.
const SCEV *MustExitMaxBECount = nullptr;
const SCEV *MayExitMaxBECount = nullptr;
bool MustExitMaxOrZero = false;
// Compute the ExitLimit for each loop exit. Use this to populate ExitCounts
// and compute maxBECount.
// Do a union of all the predicates here.
for (unsigned i = 0, e = ExitingBlocks.size(); i != e; ++i) {
BasicBlock *ExitBB = ExitingBlocks[i];
// We canonicalize untaken exits to br (constant), ignore them so that
// proving an exit untaken doesn't negatively impact our ability to reason
// about the loop as whole.
if (auto *BI = dyn_cast<BranchInst>(ExitBB->getTerminator()))
if (auto *CI = dyn_cast<ConstantInt>(BI->getCondition())) {
bool ExitIfTrue = !L->contains(BI->getSuccessor(0));
if (ExitIfTrue == CI->isZero())
continue;
}
ExitLimit EL = computeExitLimit(L, ExitBB, AllowPredicates);
assert((AllowPredicates || EL.Predicates.empty()) &&
"Predicated exit limit when predicates are not allowed!");
// 1. For each exit that can be computed, add an entry to ExitCounts.
// CouldComputeBECount is true only if all exits can be computed.
if (EL.ExactNotTaken == getCouldNotCompute())
// We couldn't compute an exact value for this exit, so
// we won't be able to compute an exact value for the loop.
CouldComputeBECount = false;
else
ExitCounts.emplace_back(ExitBB, EL);
// 2. Derive the loop's MaxBECount from each exit's max number of
// non-exiting iterations. Partition the loop exits into two kinds:
// LoopMustExits and LoopMayExits.
//
// If the exit dominates the loop latch, it is a LoopMustExit otherwise it
// is a LoopMayExit. If any computable LoopMustExit is found, then
// MaxBECount is the minimum EL.MaxNotTaken of computable
// LoopMustExits. Otherwise, MaxBECount is conservatively the maximum
// EL.MaxNotTaken, where CouldNotCompute is considered greater than any
// computable EL.MaxNotTaken.
if (EL.MaxNotTaken != getCouldNotCompute() && Latch &&
DT.dominates(ExitBB, Latch)) {
if (!MustExitMaxBECount) {
MustExitMaxBECount = EL.MaxNotTaken;
MustExitMaxOrZero = EL.MaxOrZero;
} else {
MustExitMaxBECount =
getUMinFromMismatchedTypes(MustExitMaxBECount, EL.MaxNotTaken);
}
} else if (MayExitMaxBECount != getCouldNotCompute()) {
if (!MayExitMaxBECount || EL.MaxNotTaken == getCouldNotCompute())
MayExitMaxBECount = EL.MaxNotTaken;
else {
MayExitMaxBECount =
getUMaxFromMismatchedTypes(MayExitMaxBECount, EL.MaxNotTaken);
}
}
}
const SCEV *MaxBECount = MustExitMaxBECount ? MustExitMaxBECount :
(MayExitMaxBECount ? MayExitMaxBECount : getCouldNotCompute());
// The loop backedge will be taken the maximum or zero times if there's
// a single exit that must be taken the maximum or zero times.
bool MaxOrZero = (MustExitMaxOrZero && ExitingBlocks.size() == 1);
// Remember which SCEVs are used in exit limits for invalidation purposes.
// We only care about non-constant SCEVs here, so we can ignore EL.MaxNotTaken
// and MaxBECount, which must be SCEVConstant.
for (const auto &Pair : ExitCounts)
if (!isa<SCEVConstant>(Pair.second.ExactNotTaken))
BECountUsers[Pair.second.ExactNotTaken].insert({L, AllowPredicates});
return BackedgeTakenInfo(std::move(ExitCounts), CouldComputeBECount,
MaxBECount, MaxOrZero);
}
ScalarEvolution::ExitLimit
ScalarEvolution::computeExitLimit(const Loop *L, BasicBlock *ExitingBlock,
bool AllowPredicates) {
assert(L->contains(ExitingBlock) && "Exit count for non-loop block?");
// If our exiting block does not dominate the latch, then its connection with
// loop's exit limit may be far from trivial.
const BasicBlock *Latch = L->getLoopLatch();
if (!Latch || !DT.dominates(ExitingBlock, Latch))
return getCouldNotCompute();
bool IsOnlyExit = (L->getExitingBlock() != nullptr);
Instruction *Term = ExitingBlock->getTerminator();
if (BranchInst *BI = dyn_cast<BranchInst>(Term)) {
assert(BI->isConditional() && "If unconditional, it can't be in loop!");
bool ExitIfTrue = !L->contains(BI->getSuccessor(0));
assert(ExitIfTrue == L->contains(BI->getSuccessor(1)) &&
"It should have one successor in loop and one exit block!");
// Proceed to the next level to examine the exit condition expression.
return computeExitLimitFromCond(
L, BI->getCondition(), ExitIfTrue,
/*ControlsExit=*/IsOnlyExit, AllowPredicates);
}
if (SwitchInst *SI = dyn_cast<SwitchInst>(Term)) {
// For switch, make sure that there is a single exit from the loop.
BasicBlock *Exit = nullptr;
for (auto *SBB : successors(ExitingBlock))
if (!L->contains(SBB)) {
if (Exit) // Multiple exit successors.
return getCouldNotCompute();
Exit = SBB;
}
assert(Exit && "Exiting block must have at least one exit");
return computeExitLimitFromSingleExitSwitch(L, SI, Exit,
/*ControlsExit=*/IsOnlyExit);
}
return getCouldNotCompute();
}
ScalarEvolution::ExitLimit ScalarEvolution::computeExitLimitFromCond(
const Loop *L, Value *ExitCond, bool ExitIfTrue,
bool ControlsExit, bool AllowPredicates) {
ScalarEvolution::ExitLimitCacheTy Cache(L, ExitIfTrue, AllowPredicates);
return computeExitLimitFromCondCached(Cache, L, ExitCond, ExitIfTrue,
ControlsExit, AllowPredicates);
}
Optional<ScalarEvolution::ExitLimit>
ScalarEvolution::ExitLimitCache::find(const Loop *L, Value *ExitCond,
bool ExitIfTrue, bool ControlsExit,
bool AllowPredicates) {
(void)this->L;
(void)this->ExitIfTrue;
(void)this->AllowPredicates;
assert(this->L == L && this->ExitIfTrue == ExitIfTrue &&
this->AllowPredicates == AllowPredicates &&
"Variance in assumed invariant key components!");
auto Itr = TripCountMap.find({ExitCond, ControlsExit});
if (Itr == TripCountMap.end())
return None;
return Itr->second;
}
void ScalarEvolution::ExitLimitCache::insert(const Loop *L, Value *ExitCond,
bool ExitIfTrue,
bool ControlsExit,
bool AllowPredicates,
const ExitLimit &EL) {
assert(this->L == L && this->ExitIfTrue == ExitIfTrue &&
this->AllowPredicates == AllowPredicates &&
"Variance in assumed invariant key components!");
auto InsertResult = TripCountMap.insert({{ExitCond, ControlsExit}, EL});
assert(InsertResult.second && "Expected successful insertion!");
(void)InsertResult;
(void)ExitIfTrue;
}
ScalarEvolution::ExitLimit ScalarEvolution::computeExitLimitFromCondCached(
ExitLimitCacheTy &Cache, const Loop *L, Value *ExitCond, bool ExitIfTrue,
bool ControlsExit, bool AllowPredicates) {
if (auto MaybeEL =
Cache.find(L, ExitCond, ExitIfTrue, ControlsExit, AllowPredicates))
return *MaybeEL;
ExitLimit EL = computeExitLimitFromCondImpl(Cache, L, ExitCond, ExitIfTrue,
ControlsExit, AllowPredicates);
Cache.insert(L, ExitCond, ExitIfTrue, ControlsExit, AllowPredicates, EL);
return EL;
}
ScalarEvolution::ExitLimit ScalarEvolution::computeExitLimitFromCondImpl(
ExitLimitCacheTy &Cache, const Loop *L, Value *ExitCond, bool ExitIfTrue,
bool ControlsExit, bool AllowPredicates) {
// Handle BinOp conditions (And, Or).
if (auto LimitFromBinOp = computeExitLimitFromCondFromBinOp(
Cache, L, ExitCond, ExitIfTrue, ControlsExit, AllowPredicates))
return *LimitFromBinOp;
// With an icmp, it may be feasible to compute an exact backedge-taken count.
// Proceed to the next level to examine the icmp.
if (ICmpInst *ExitCondICmp = dyn_cast<ICmpInst>(ExitCond)) {
ExitLimit EL =
computeExitLimitFromICmp(L, ExitCondICmp, ExitIfTrue, ControlsExit);
if (EL.hasFullInfo() || !AllowPredicates)
return EL;
// Try again, but use SCEV predicates this time.
return computeExitLimitFromICmp(L, ExitCondICmp, ExitIfTrue, ControlsExit,
/*AllowPredicates=*/true);
}
// Check for a constant condition. These are normally stripped out by
// SimplifyCFG, but ScalarEvolution may be used by a pass which wishes to
// preserve the CFG and is temporarily leaving constant conditions
// in place.
if (ConstantInt *CI = dyn_cast<ConstantInt>(ExitCond)) {
if (ExitIfTrue == !CI->getZExtValue())
// The backedge is always taken.
return getCouldNotCompute();
else
// The backedge is never taken.
return getZero(CI->getType());
}
// If we're exiting based on the overflow flag of an x.with.overflow intrinsic
// with a constant step, we can form an equivalent icmp predicate and figure
// out how many iterations will be taken before we exit.
const WithOverflowInst *WO;
const APInt *C;
if (match(ExitCond, m_ExtractValue<1>(m_WithOverflowInst(WO))) &&
match(WO->getRHS(), m_APInt(C))) {
ConstantRange NWR =
ConstantRange::makeExactNoWrapRegion(WO->getBinaryOp(), *C,
WO->getNoWrapKind());
CmpInst::Predicate Pred;
APInt NewRHSC, Offset;
NWR.getEquivalentICmp(Pred, NewRHSC, Offset);
if (!ExitIfTrue)
Pred = ICmpInst::getInversePredicate(Pred);
auto *LHS = getSCEV(WO->getLHS());
if (Offset != 0)
LHS = getAddExpr(LHS, getConstant(Offset));
auto EL = computeExitLimitFromICmp(L, Pred, LHS, getConstant(NewRHSC),
ControlsExit, AllowPredicates);
if (EL.hasAnyInfo()) return EL;
}
// If it's not an integer or pointer comparison then compute it the hard way.
return computeExitCountExhaustively(L, ExitCond, ExitIfTrue);
}
Optional<ScalarEvolution::ExitLimit>
ScalarEvolution::computeExitLimitFromCondFromBinOp(
ExitLimitCacheTy &Cache, const Loop *L, Value *ExitCond, bool ExitIfTrue,
bool ControlsExit, bool AllowPredicates) {
// Check if the controlling expression for this loop is an And or Or.
Value *Op0, *Op1;
bool IsAnd = false;
if (match(ExitCond, m_LogicalAnd(m_Value(Op0), m_Value(Op1))))
IsAnd = true;
else if (match(ExitCond, m_LogicalOr(m_Value(Op0), m_Value(Op1))))
IsAnd = false;
else
return None;
// EitherMayExit is true in these two cases:
// br (and Op0 Op1), loop, exit
// br (or Op0 Op1), exit, loop
bool EitherMayExit = IsAnd ^ ExitIfTrue;
ExitLimit EL0 = computeExitLimitFromCondCached(Cache, L, Op0, ExitIfTrue,
ControlsExit && !EitherMayExit,
AllowPredicates);
ExitLimit EL1 = computeExitLimitFromCondCached(Cache, L, Op1, ExitIfTrue,
ControlsExit && !EitherMayExit,
AllowPredicates);
// Be robust against unsimplified IR for the form "op i1 X, NeutralElement"
const Constant *NeutralElement = ConstantInt::get(ExitCond->getType(), IsAnd);
if (isa<ConstantInt>(Op1))
return Op1 == NeutralElement ? EL0 : EL1;
if (isa<ConstantInt>(Op0))
return Op0 == NeutralElement ? EL1 : EL0;
const SCEV *BECount = getCouldNotCompute();
const SCEV *MaxBECount = getCouldNotCompute();
if (EitherMayExit) {
// Both conditions must be same for the loop to continue executing.
// Choose the less conservative count.
if (EL0.ExactNotTaken != getCouldNotCompute() &&
EL1.ExactNotTaken != getCouldNotCompute()) {
BECount = getUMinFromMismatchedTypes(
EL0.ExactNotTaken, EL1.ExactNotTaken,
/*Sequential=*/!isa<BinaryOperator>(ExitCond));
}
if (EL0.MaxNotTaken == getCouldNotCompute())
MaxBECount = EL1.MaxNotTaken;
else if (EL1.MaxNotTaken == getCouldNotCompute())
MaxBECount = EL0.MaxNotTaken;
else
MaxBECount = getUMinFromMismatchedTypes(EL0.MaxNotTaken, EL1.MaxNotTaken);
} else {
// Both conditions must be same at the same time for the loop to exit.
// For now, be conservative.
if (EL0.ExactNotTaken == EL1.ExactNotTaken)
BECount = EL0.ExactNotTaken;
}
// There are cases (e.g. PR26207) where computeExitLimitFromCond is able
// to be more aggressive when computing BECount than when computing
// MaxBECount. In these cases it is possible for EL0.ExactNotTaken and
// EL1.ExactNotTaken to match, but for EL0.MaxNotTaken and EL1.MaxNotTaken
// to not.
if (isa<SCEVCouldNotCompute>(MaxBECount) &&
!isa<SCEVCouldNotCompute>(BECount))
MaxBECount = getConstant(getUnsignedRangeMax(BECount));
return ExitLimit(BECount, MaxBECount, false,
{ &EL0.Predicates, &EL1.Predicates });
}
ScalarEvolution::ExitLimit
ScalarEvolution::computeExitLimitFromICmp(const Loop *L,
ICmpInst *ExitCond,
bool ExitIfTrue,
bool ControlsExit,
bool AllowPredicates) {
// If the condition was exit on true, convert the condition to exit on false
ICmpInst::Predicate Pred;
if (!ExitIfTrue)
Pred = ExitCond->getPredicate();
else
Pred = ExitCond->getInversePredicate();
const ICmpInst::Predicate OriginalPred = Pred;
const SCEV *LHS = getSCEV(ExitCond->getOperand(0));
const SCEV *RHS = getSCEV(ExitCond->getOperand(1));
ExitLimit EL = computeExitLimitFromICmp(L, Pred, LHS, RHS, ControlsExit,
AllowPredicates);
if (EL.hasAnyInfo()) return EL;
auto *ExhaustiveCount =
computeExitCountExhaustively(L, ExitCond, ExitIfTrue);
if (!isa<SCEVCouldNotCompute>(ExhaustiveCount))
return ExhaustiveCount;
return computeShiftCompareExitLimit(ExitCond->getOperand(0),
ExitCond->getOperand(1), L, OriginalPred);
}
ScalarEvolution::ExitLimit
ScalarEvolution::computeExitLimitFromICmp(const Loop *L,
ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS,
bool ControlsExit,
bool AllowPredicates) {
// Try to evaluate any dependencies out of the loop.
LHS = getSCEVAtScope(LHS, L);
RHS = getSCEVAtScope(RHS, L);
// At this point, we would like to compute how many iterations of the
// loop the predicate will return true for these inputs.
if (isLoopInvariant(LHS, L) && !isLoopInvariant(RHS, L)) {
// If there is a loop-invariant, force it into the RHS.
std::swap(LHS, RHS);
Pred = ICmpInst::getSwappedPredicate(Pred);
}
bool ControllingFiniteLoop =
ControlsExit && loopHasNoAbnormalExits(L) && loopIsFiniteByAssumption(L);
// Simplify the operands before analyzing them.
(void)SimplifyICmpOperands(Pred, LHS, RHS, /*Depth=*/0,
(EnableFiniteLoopControl ? ControllingFiniteLoop
: false));
// If we have a comparison of a chrec against a constant, try to use value
// ranges to answer this query.
if (const SCEVConstant *RHSC = dyn_cast<SCEVConstant>(RHS))
if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(LHS))
if (AddRec->getLoop() == L) {
// Form the constant range.
ConstantRange CompRange =
ConstantRange::makeExactICmpRegion(Pred, RHSC->getAPInt());
const SCEV *Ret = AddRec->getNumIterationsInRange(CompRange, *this);
if (!isa<SCEVCouldNotCompute>(Ret)) return Ret;
}
// If this loop must exit based on this condition (or execute undefined
// behaviour), and we can prove the test sequence produced must repeat
// the same values on self-wrap of the IV, then we can infer that IV
// doesn't self wrap because if it did, we'd have an infinite (undefined)
// loop.
if (ControllingFiniteLoop && isLoopInvariant(RHS, L)) {
// TODO: We can peel off any functions which are invertible *in L*. Loop
// invariant terms are effectively constants for our purposes here.
auto *InnerLHS = LHS;
if (auto *ZExt = dyn_cast<SCEVZeroExtendExpr>(LHS))
InnerLHS = ZExt->getOperand();
if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(InnerLHS)) {
auto *StrideC = dyn_cast<SCEVConstant>(AR->getStepRecurrence(*this));
if (!AR->hasNoSelfWrap() && AR->getLoop() == L && AR->isAffine() &&
StrideC && StrideC->getAPInt().isPowerOf2()) {
auto Flags = AR->getNoWrapFlags();
Flags = setFlags(Flags, SCEV::FlagNW);
SmallVector<const SCEV*> Operands{AR->operands()};
Flags = StrengthenNoWrapFlags(this, scAddRecExpr, Operands, Flags);
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), Flags);
}
}
}
switch (Pred) {
case ICmpInst::ICMP_NE: { // while (X != Y)
// Convert to: while (X-Y != 0)
if (LHS->getType()->isPointerTy()) {
LHS = getLosslessPtrToIntExpr(LHS);
if (isa<SCEVCouldNotCompute>(LHS))
return LHS;
}
if (RHS->getType()->isPointerTy()) {
RHS = getLosslessPtrToIntExpr(RHS);
if (isa<SCEVCouldNotCompute>(RHS))
return RHS;
}
ExitLimit EL = howFarToZero(getMinusSCEV(LHS, RHS), L, ControlsExit,
AllowPredicates);
if (EL.hasAnyInfo()) return EL;
break;
}
case ICmpInst::ICMP_EQ: { // while (X == Y)
// Convert to: while (X-Y == 0)
if (LHS->getType()->isPointerTy()) {
LHS = getLosslessPtrToIntExpr(LHS);
if (isa<SCEVCouldNotCompute>(LHS))
return LHS;
}
if (RHS->getType()->isPointerTy()) {
RHS = getLosslessPtrToIntExpr(RHS);
if (isa<SCEVCouldNotCompute>(RHS))
return RHS;
}
ExitLimit EL = howFarToNonZero(getMinusSCEV(LHS, RHS), L);
if (EL.hasAnyInfo()) return EL;
break;
}
case ICmpInst::ICMP_SLT:
case ICmpInst::ICMP_ULT: { // while (X < Y)
bool IsSigned = Pred == ICmpInst::ICMP_SLT;
ExitLimit EL = howManyLessThans(LHS, RHS, L, IsSigned, ControlsExit,
AllowPredicates);
if (EL.hasAnyInfo()) return EL;
break;
}
case ICmpInst::ICMP_SGT:
case ICmpInst::ICMP_UGT: { // while (X > Y)
bool IsSigned = Pred == ICmpInst::ICMP_SGT;
ExitLimit EL =
howManyGreaterThans(LHS, RHS, L, IsSigned, ControlsExit,
AllowPredicates);
if (EL.hasAnyInfo()) return EL;
break;
}
default:
break;
}
return getCouldNotCompute();
}
ScalarEvolution::ExitLimit
ScalarEvolution::computeExitLimitFromSingleExitSwitch(const Loop *L,
SwitchInst *Switch,
BasicBlock *ExitingBlock,
bool ControlsExit) {
assert(!L->contains(ExitingBlock) && "Not an exiting block!");
// Give up if the exit is the default dest of a switch.
if (Switch->getDefaultDest() == ExitingBlock)
return getCouldNotCompute();
assert(L->contains(Switch->getDefaultDest()) &&
"Default case must not exit the loop!");
const SCEV *LHS = getSCEVAtScope(Switch->getCondition(), L);
const SCEV *RHS = getConstant(Switch->findCaseDest(ExitingBlock));
// while (X != Y) --> while (X-Y != 0)
ExitLimit EL = howFarToZero(getMinusSCEV(LHS, RHS), L, ControlsExit);
if (EL.hasAnyInfo())
return EL;
return getCouldNotCompute();
}
static ConstantInt *
EvaluateConstantChrecAtConstant(const SCEVAddRecExpr *AddRec, ConstantInt *C,
ScalarEvolution &SE) {
const SCEV *InVal = SE.getConstant(C);
const SCEV *Val = AddRec->evaluateAtIteration(InVal, SE);
assert(isa<SCEVConstant>(Val) &&
"Evaluation of SCEV at constant didn't fold correctly?");
return cast<SCEVConstant>(Val)->getValue();
}
ScalarEvolution::ExitLimit ScalarEvolution::computeShiftCompareExitLimit(
Value *LHS, Value *RHSV, const Loop *L, ICmpInst::Predicate Pred) {
ConstantInt *RHS = dyn_cast<ConstantInt>(RHSV);
if (!RHS)
return getCouldNotCompute();
const BasicBlock *Latch = L->getLoopLatch();
if (!Latch)
return getCouldNotCompute();
const BasicBlock *Predecessor = L->getLoopPredecessor();
if (!Predecessor)
return getCouldNotCompute();
// Return true if V is of the form "LHS `shift_op` <positive constant>".
// Return LHS in OutLHS and shift_opt in OutOpCode.
auto MatchPositiveShift =
[](Value *V, Value *&OutLHS, Instruction::BinaryOps &OutOpCode) {
using namespace PatternMatch;
ConstantInt *ShiftAmt;
if (match(V, m_LShr(m_Value(OutLHS), m_ConstantInt(ShiftAmt))))
OutOpCode = Instruction::LShr;
else if (match(V, m_AShr(m_Value(OutLHS), m_ConstantInt(ShiftAmt))))
OutOpCode = Instruction::AShr;
else if (match(V, m_Shl(m_Value(OutLHS), m_ConstantInt(ShiftAmt))))
OutOpCode = Instruction::Shl;
else
return false;
return ShiftAmt->getValue().isStrictlyPositive();
};
// Recognize a "shift recurrence" either of the form %iv or of %iv.shifted in
//
// loop:
// %iv = phi i32 [ %iv.shifted, %loop ], [ %val, %preheader ]
// %iv.shifted = lshr i32 %iv, <positive constant>
//
// Return true on a successful match. Return the corresponding PHI node (%iv
// above) in PNOut and the opcode of the shift operation in OpCodeOut.
auto MatchShiftRecurrence =
[&](Value *V, PHINode *&PNOut, Instruction::BinaryOps &OpCodeOut) {
Optional<Instruction::BinaryOps> PostShiftOpCode;
{
Instruction::BinaryOps OpC;
Value *V;
// If we encounter a shift instruction, "peel off" the shift operation,
// and remember that we did so. Later when we inspect %iv's backedge
// value, we will make sure that the backedge value uses the same
// operation.
//
// Note: the peeled shift operation does not have to be the same
// instruction as the one feeding into the PHI's backedge value. We only
// really care about it being the same *kind* of shift instruction --
// that's all that is required for our later inferences to hold.
if (MatchPositiveShift(LHS, V, OpC)) {
PostShiftOpCode = OpC;
LHS = V;
}
}
PNOut = dyn_cast<PHINode>(LHS);
if (!PNOut || PNOut->getParent() != L->getHeader())
return false;
Value *BEValue = PNOut->getIncomingValueForBlock(Latch);
Value *OpLHS;
return
// The backedge value for the PHI node must be a shift by a positive
// amount
MatchPositiveShift(BEValue, OpLHS, OpCodeOut) &&
// of the PHI node itself
OpLHS == PNOut &&
// and the kind of shift should be match the kind of shift we peeled
// off, if any.
(!PostShiftOpCode || *PostShiftOpCode == OpCodeOut);
};
PHINode *PN;
Instruction::BinaryOps OpCode;
if (!MatchShiftRecurrence(LHS, PN, OpCode))
return getCouldNotCompute();
const DataLayout &DL = getDataLayout();
// The key rationale for this optimization is that for some kinds of shift
// recurrences, the value of the recurrence "stabilizes" to either 0 or -1
// within a finite number of iterations. If the condition guarding the
// backedge (in the sense that the backedge is taken if the condition is true)
// is false for the value the shift recurrence stabilizes to, then we know
// that the backedge is taken only a finite number of times.
ConstantInt *StableValue = nullptr;
switch (OpCode) {
default:
llvm_unreachable("Impossible case!");
case Instruction::AShr: {
// {K,ashr,<positive-constant>} stabilizes to signum(K) in at most
// bitwidth(K) iterations.
Value *FirstValue = PN->getIncomingValueForBlock(Predecessor);
KnownBits Known = computeKnownBits(FirstValue, DL, 0, &AC,
Predecessor->getTerminator(), &DT);
auto *Ty = cast<IntegerType>(RHS->getType());
if (Known.isNonNegative())
StableValue = ConstantInt::get(Ty, 0);
else if (Known.isNegative())
StableValue = ConstantInt::get(Ty, -1, true);
else
return getCouldNotCompute();
break;
}
case Instruction::LShr:
case Instruction::Shl:
// Both {K,lshr,<positive-constant>} and {K,shl,<positive-constant>}
// stabilize to 0 in at most bitwidth(K) iterations.
StableValue = ConstantInt::get(cast<IntegerType>(RHS->getType()), 0);
break;
}
auto *Result =
ConstantFoldCompareInstOperands(Pred, StableValue, RHS, DL, &TLI);
assert(Result->getType()->isIntegerTy(1) &&
"Otherwise cannot be an operand to a branch instruction");
if (Result->isZeroValue()) {
unsigned BitWidth = getTypeSizeInBits(RHS->getType());
const SCEV *UpperBound =
getConstant(getEffectiveSCEVType(RHS->getType()), BitWidth);
return ExitLimit(getCouldNotCompute(), UpperBound, false);
}
return getCouldNotCompute();
}
/// Return true if we can constant fold an instruction of the specified type,
/// assuming that all operands were constants.
static bool CanConstantFold(const Instruction *I) {
if (isa<BinaryOperator>(I) || isa<CmpInst>(I) ||
isa<SelectInst>(I) || isa<CastInst>(I) || isa<GetElementPtrInst>(I) ||
isa<LoadInst>(I) || isa<ExtractValueInst>(I))
return true;
if (const CallInst *CI = dyn_cast<CallInst>(I))
if (const Function *F = CI->getCalledFunction())
return canConstantFoldCallTo(CI, F);
return false;
}
/// Determine whether this instruction can constant evolve within this loop
/// assuming its operands can all constant evolve.
static bool canConstantEvolve(Instruction *I, const Loop *L) {
// An instruction outside of the loop can't be derived from a loop PHI.
if (!L->contains(I)) return false;
if (isa<PHINode>(I)) {
// We don't currently keep track of the control flow needed to evaluate
// PHIs, so we cannot handle PHIs inside of loops.
return L->getHeader() == I->getParent();
}
// If we won't be able to constant fold this expression even if the operands
// are constants, bail early.
return CanConstantFold(I);
}
/// getConstantEvolvingPHIOperands - Implement getConstantEvolvingPHI by
/// recursing through each instruction operand until reaching a loop header phi.
static PHINode *
getConstantEvolvingPHIOperands(Instruction *UseInst, const Loop *L,
DenseMap<Instruction *, PHINode *> &PHIMap,
unsigned Depth) {
if (Depth > MaxConstantEvolvingDepth)
return nullptr;
// Otherwise, we can evaluate this instruction if all of its operands are
// constant or derived from a PHI node themselves.
PHINode *PHI = nullptr;
for (Value *Op : UseInst->operands()) {
if (isa<Constant>(Op)) continue;
Instruction *OpInst = dyn_cast<Instruction>(Op);
if (!OpInst || !canConstantEvolve(OpInst, L)) return nullptr;
PHINode *P = dyn_cast<PHINode>(OpInst);
if (!P)
// If this operand is already visited, reuse the prior result.
// We may have P != PHI if this is the deepest point at which the
// inconsistent paths meet.
P = PHIMap.lookup(OpInst);
if (!P) {
// Recurse and memoize the results, whether a phi is found or not.
// This recursive call invalidates pointers into PHIMap.
P = getConstantEvolvingPHIOperands(OpInst, L, PHIMap, Depth + 1);
PHIMap[OpInst] = P;
}
if (!P)
return nullptr; // Not evolving from PHI
if (PHI && PHI != P)
return nullptr; // Evolving from multiple different PHIs.
PHI = P;
}
// This is a expression evolving from a constant PHI!
return PHI;
}
/// getConstantEvolvingPHI - Given an LLVM value and a loop, return a PHI node
/// in the loop that V is derived from. We allow arbitrary operations along the
/// way, but the operands of an operation must either be constants or a value
/// derived from a constant PHI. If this expression does not fit with these
/// constraints, return null.
static PHINode *getConstantEvolvingPHI(Value *V, const Loop *L) {
Instruction *I = dyn_cast<Instruction>(V);
if (!I || !canConstantEvolve(I, L)) return nullptr;
if (PHINode *PN = dyn_cast<PHINode>(I))
return PN;
// Record non-constant instructions contained by the loop.
DenseMap<Instruction *, PHINode *> PHIMap;
return getConstantEvolvingPHIOperands(I, L, PHIMap, 0);
}
/// EvaluateExpression - Given an expression that passes the
/// getConstantEvolvingPHI predicate, evaluate its value assuming the PHI node
/// in the loop has the value PHIVal. If we can't fold this expression for some
/// reason, return null.
static Constant *EvaluateExpression(Value *V, const Loop *L,
DenseMap<Instruction *, Constant *> &Vals,
const DataLayout &DL,
const TargetLibraryInfo *TLI) {
// Convenient constant check, but redundant for recursive calls.
if (Constant *C = dyn_cast<Constant>(V)) return C;
Instruction *I = dyn_cast<Instruction>(V);
if (!I) return nullptr;
if (Constant *C = Vals.lookup(I)) return C;
// An instruction inside the loop depends on a value outside the loop that we
// weren't given a mapping for, or a value such as a call inside the loop.
if (!canConstantEvolve(I, L)) return nullptr;
// An unmapped PHI can be due to a branch or another loop inside this loop,
// or due to this not being the initial iteration through a loop where we
// couldn't compute the evolution of this particular PHI last time.
if (isa<PHINode>(I)) return nullptr;
std::vector<Constant*> Operands(I->getNumOperands());
for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) {
Instruction *Operand = dyn_cast<Instruction>(I->getOperand(i));
if (!Operand) {
Operands[i] = dyn_cast<Constant>(I->getOperand(i));
if (!Operands[i]) return nullptr;
continue;
}
Constant *C = EvaluateExpression(Operand, L, Vals, DL, TLI);
Vals[Operand] = C;
if (!C) return nullptr;
Operands[i] = C;
}
return ConstantFoldInstOperands(I, Operands, DL, TLI);
}
// If every incoming value to PN except the one for BB is a specific Constant,
// return that, else return nullptr.
static Constant *getOtherIncomingValue(PHINode *PN, BasicBlock *BB) {
Constant *IncomingVal = nullptr;
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
if (PN->getIncomingBlock(i) == BB)
continue;
auto *CurrentVal = dyn_cast<Constant>(PN->getIncomingValue(i));
if (!CurrentVal)
return nullptr;
if (IncomingVal != CurrentVal) {
if (IncomingVal)
return nullptr;
IncomingVal = CurrentVal;
}
}
return IncomingVal;
}
/// getConstantEvolutionLoopExitValue - If we know that the specified Phi is
/// in the header of its containing loop, we know the loop executes a
/// constant number of times, and the PHI node is just a recurrence
/// involving constants, fold it.
Constant *
ScalarEvolution::getConstantEvolutionLoopExitValue(PHINode *PN,
const APInt &BEs,
const Loop *L) {
auto I = ConstantEvolutionLoopExitValue.find(PN);
if (I != ConstantEvolutionLoopExitValue.end())
return I->second;
if (BEs.ugt(MaxBruteForceIterations))
return ConstantEvolutionLoopExitValue[PN] = nullptr; // Not going to evaluate it.
Constant *&RetVal = ConstantEvolutionLoopExitValue[PN];
DenseMap<Instruction *, Constant *> CurrentIterVals;
BasicBlock *Header = L->getHeader();
assert(PN->getParent() == Header && "Can't evaluate PHI not in loop header!");
BasicBlock *Latch = L->getLoopLatch();
if (!Latch)
return nullptr;
for (PHINode &PHI : Header->phis()) {
if (auto *StartCST = getOtherIncomingValue(&PHI, Latch))
CurrentIterVals[&PHI] = StartCST;
}
if (!CurrentIterVals.count(PN))
return RetVal = nullptr;
Value *BEValue = PN->getIncomingValueForBlock(Latch);
// Execute the loop symbolically to determine the exit value.
assert(BEs.getActiveBits() < CHAR_BIT * sizeof(unsigned) &&
"BEs is <= MaxBruteForceIterations which is an 'unsigned'!");
unsigned NumIterations = BEs.getZExtValue(); // must be in range
unsigned IterationNum = 0;
const DataLayout &DL = getDataLayout();
for (; ; ++IterationNum) {
if (IterationNum == NumIterations)
return RetVal = CurrentIterVals[PN]; // Got exit value!
// Compute the value of the PHIs for the next iteration.
// EvaluateExpression adds non-phi values to the CurrentIterVals map.
DenseMap<Instruction *, Constant *> NextIterVals;
Constant *NextPHI =
EvaluateExpression(BEValue, L, CurrentIterVals, DL, &TLI);
if (!NextPHI)
return nullptr; // Couldn't evaluate!
NextIterVals[PN] = NextPHI;
bool StoppedEvolving = NextPHI == CurrentIterVals[PN];
// Also evaluate the other PHI nodes. However, we don't get to stop if we
// cease to be able to evaluate one of them or if they stop evolving,
// because that doesn't necessarily prevent us from computing PN.
SmallVector<std::pair<PHINode *, Constant *>, 8> PHIsToCompute;
for (const auto &I : CurrentIterVals) {
PHINode *PHI = dyn_cast<PHINode>(I.first);
if (!PHI || PHI == PN || PHI->getParent() != Header) continue;
PHIsToCompute.emplace_back(PHI, I.second);
}
// We use two distinct loops because EvaluateExpression may invalidate any
// iterators into CurrentIterVals.
for (const auto &I : PHIsToCompute) {
PHINode *PHI = I.first;
Constant *&NextPHI = NextIterVals[PHI];
if (!NextPHI) { // Not already computed.
Value *BEValue = PHI->getIncomingValueForBlock(Latch);
NextPHI = EvaluateExpression(BEValue, L, CurrentIterVals, DL, &TLI);
}
if (NextPHI != I.second)
StoppedEvolving = false;
}
// If all entries in CurrentIterVals == NextIterVals then we can stop
// iterating, the loop can't continue to change.
if (StoppedEvolving)
return RetVal = CurrentIterVals[PN];
CurrentIterVals.swap(NextIterVals);
}
}
const SCEV *ScalarEvolution::computeExitCountExhaustively(const Loop *L,
Value *Cond,
bool ExitWhen) {
PHINode *PN = getConstantEvolvingPHI(Cond, L);
if (!PN) return getCouldNotCompute();
// If the loop is canonicalized, the PHI will have exactly two entries.
// That's the only form we support here.
if (PN->getNumIncomingValues() != 2) return getCouldNotCompute();
DenseMap<Instruction *, Constant *> CurrentIterVals;
BasicBlock *Header = L->getHeader();
assert(PN->getParent() == Header && "Can't evaluate PHI not in loop header!");
BasicBlock *Latch = L->getLoopLatch();
assert(Latch && "Should follow from NumIncomingValues == 2!");
for (PHINode &PHI : Header->phis()) {
if (auto *StartCST = getOtherIncomingValue(&PHI, Latch))
CurrentIterVals[&PHI] = StartCST;
}
if (!CurrentIterVals.count(PN))
return getCouldNotCompute();
// Okay, we find a PHI node that defines the trip count of this loop. Execute
// the loop symbolically to determine when the condition gets a value of
// "ExitWhen".
unsigned MaxIterations = MaxBruteForceIterations; // Limit analysis.
const DataLayout &DL = getDataLayout();
for (unsigned IterationNum = 0; IterationNum != MaxIterations;++IterationNum){
auto *CondVal = dyn_cast_or_null<ConstantInt>(
EvaluateExpression(Cond, L, CurrentIterVals, DL, &TLI));
// Couldn't symbolically evaluate.
if (!CondVal) return getCouldNotCompute();
if (CondVal->getValue() == uint64_t(ExitWhen)) {
++NumBruteForceTripCountsComputed;
return getConstant(Type::getInt32Ty(getContext()), IterationNum);
}
// Update all the PHI nodes for the next iteration.
DenseMap<Instruction *, Constant *> NextIterVals;
// Create a list of which PHIs we need to compute. We want to do this before
// calling EvaluateExpression on them because that may invalidate iterators
// into CurrentIterVals.
SmallVector<PHINode *, 8> PHIsToCompute;
for (const auto &I : CurrentIterVals) {
PHINode *PHI = dyn_cast<PHINode>(I.first);
if (!PHI || PHI->getParent() != Header) continue;
PHIsToCompute.push_back(PHI);
}
for (PHINode *PHI : PHIsToCompute) {
Constant *&NextPHI = NextIterVals[PHI];
if (NextPHI) continue; // Already computed!
Value *BEValue = PHI->getIncomingValueForBlock(Latch);
NextPHI = EvaluateExpression(BEValue, L, CurrentIterVals, DL, &TLI);
}
CurrentIterVals.swap(NextIterVals);
}
// Too many iterations were needed to evaluate.
return getCouldNotCompute();
}
const SCEV *ScalarEvolution::getSCEVAtScope(const SCEV *V, const Loop *L) {
SmallVector<std::pair<const Loop *, const SCEV *>, 2> &Values =
ValuesAtScopes[V];
// Check to see if we've folded this expression at this loop before.
for (auto &LS : Values)
if (LS.first == L)
return LS.second ? LS.second : V;
Values.emplace_back(L, nullptr);
// Otherwise compute it.
const SCEV *C = computeSCEVAtScope(V, L);
for (auto &LS : reverse(ValuesAtScopes[V]))
if (LS.first == L) {
LS.second = C;
if (!isa<SCEVConstant>(C))
ValuesAtScopesUsers[C].push_back({L, V});
break;
}
return C;
}
/// This builds up a Constant using the ConstantExpr interface. That way, we
/// will return Constants for objects which aren't represented by a
/// SCEVConstant, because SCEVConstant is restricted to ConstantInt.
/// Returns NULL if the SCEV isn't representable as a Constant.
static Constant *BuildConstantFromSCEV(const SCEV *V) {
switch (V->getSCEVType()) {
case scCouldNotCompute:
case scAddRecExpr:
return nullptr;
case scConstant:
return cast<SCEVConstant>(V)->getValue();
case scUnknown:
return dyn_cast<Constant>(cast<SCEVUnknown>(V)->getValue());
case scSignExtend: {
const SCEVSignExtendExpr *SS = cast<SCEVSignExtendExpr>(V);
if (Constant *CastOp = BuildConstantFromSCEV(SS->getOperand()))
return ConstantExpr::getSExt(CastOp, SS->getType());
return nullptr;
}
case scZeroExtend: {
const SCEVZeroExtendExpr *SZ = cast<SCEVZeroExtendExpr>(V);
if (Constant *CastOp = BuildConstantFromSCEV(SZ->getOperand()))
return ConstantExpr::getZExt(CastOp, SZ->getType());
return nullptr;
}
case scPtrToInt: {
const SCEVPtrToIntExpr *P2I = cast<SCEVPtrToIntExpr>(V);
if (Constant *CastOp = BuildConstantFromSCEV(P2I->getOperand()))
return ConstantExpr::getPtrToInt(CastOp, P2I->getType());
return nullptr;
}
case scTruncate: {
const SCEVTruncateExpr *ST = cast<SCEVTruncateExpr>(V);
if (Constant *CastOp = BuildConstantFromSCEV(ST->getOperand()))
return ConstantExpr::getTrunc(CastOp, ST->getType());
return nullptr;
}
case scAddExpr: {
const SCEVAddExpr *SA = cast<SCEVAddExpr>(V);
Constant *C = nullptr;
for (const SCEV *Op : SA->operands()) {
Constant *OpC = BuildConstantFromSCEV(Op);
if (!OpC)
return nullptr;
if (!C) {
C = OpC;
continue;
}
assert(!C->getType()->isPointerTy() &&
"Can only have one pointer, and it must be last");
if (auto *PT = dyn_cast<PointerType>(OpC->getType())) {
// The offsets have been converted to bytes. We can add bytes to an
// i8* by GEP with the byte count in the first index.
Type *DestPtrTy =
Type::getInt8PtrTy(PT->getContext(), PT->getAddressSpace());
OpC = ConstantExpr::getBitCast(OpC, DestPtrTy);
C = ConstantExpr::getGetElementPtr(Type::getInt8Ty(C->getContext()),
OpC, C);
} else {
C = ConstantExpr::getAdd(C, OpC);
}
}
return C;
}
case scMulExpr: {
const SCEVMulExpr *SM = cast<SCEVMulExpr>(V);
Constant *C = nullptr;
for (const SCEV *Op : SM->operands()) {
assert(!Op->getType()->isPointerTy() && "Can't multiply pointers");
Constant *OpC = BuildConstantFromSCEV(Op);
if (!OpC)
return nullptr;
C = C ? ConstantExpr::getMul(C, OpC) : OpC;
}
return C;
}
case scUDivExpr:
case scSMaxExpr:
case scUMaxExpr:
case scSMinExpr:
case scUMinExpr:
case scSequentialUMinExpr:
return nullptr; // TODO: smax, umax, smin, umax, umin_seq.
}
llvm_unreachable("Unknown SCEV kind!");
}
const SCEV *ScalarEvolution::computeSCEVAtScope(const SCEV *V, const Loop *L) {
if (isa<SCEVConstant>(V)) return V;
// If this instruction is evolved from a constant-evolving PHI, compute the
// exit value from the loop without using SCEVs.
if (const SCEVUnknown *SU = dyn_cast<SCEVUnknown>(V)) {
if (Instruction *I = dyn_cast<Instruction>(SU->getValue())) {
if (PHINode *PN = dyn_cast<PHINode>(I)) {
const Loop *CurrLoop = this->LI[I->getParent()];
// Looking for loop exit value.
if (CurrLoop && CurrLoop->getParentLoop() == L &&
PN->getParent() == CurrLoop->getHeader()) {
// Okay, there is no closed form solution for the PHI node. Check
// to see if the loop that contains it has a known backedge-taken
// count. If so, we may be able to force computation of the exit
// value.
const SCEV *BackedgeTakenCount = getBackedgeTakenCount(CurrLoop);
// This trivial case can show up in some degenerate cases where
// the incoming IR has not yet been fully simplified.
if (BackedgeTakenCount->isZero()) {
Value *InitValue = nullptr;
bool MultipleInitValues = false;
for (unsigned i = 0; i < PN->getNumIncomingValues(); i++) {
if (!CurrLoop->contains(PN->getIncomingBlock(i))) {
if (!InitValue)
InitValue = PN->getIncomingValue(i);
else if (InitValue != PN->getIncomingValue(i)) {
MultipleInitValues = true;
break;
}
}
}
if (!MultipleInitValues && InitValue)
return getSCEV(InitValue);
}
// Do we have a loop invariant value flowing around the backedge
// for a loop which must execute the backedge?
if (!isa<SCEVCouldNotCompute>(BackedgeTakenCount) &&
isKnownPositive(BackedgeTakenCount) &&
PN->getNumIncomingValues() == 2) {
unsigned InLoopPred =
CurrLoop->contains(PN->getIncomingBlock(0)) ? 0 : 1;
Value *BackedgeVal = PN->getIncomingValue(InLoopPred);
if (CurrLoop->isLoopInvariant(BackedgeVal))
return getSCEV(BackedgeVal);
}
if (auto *BTCC = dyn_cast<SCEVConstant>(BackedgeTakenCount)) {
// Okay, we know how many times the containing loop executes. If
// this is a constant evolving PHI node, get the final value at
// the specified iteration number.
Constant *RV = getConstantEvolutionLoopExitValue(
PN, BTCC->getAPInt(), CurrLoop);
if (RV) return getSCEV(RV);
}
}
// If there is a single-input Phi, evaluate it at our scope. If we can
// prove that this replacement does not break LCSSA form, use new value.
if (PN->getNumOperands() == 1) {
const SCEV *Input = getSCEV(PN->getOperand(0));
const SCEV *InputAtScope = getSCEVAtScope(Input, L);
// TODO: We can generalize it using LI.replacementPreservesLCSSAForm,
// for the simplest case just support constants.
if (isa<SCEVConstant>(InputAtScope)) return InputAtScope;
}
}
// Okay, this is an expression that we cannot symbolically evaluate
// into a SCEV. Check to see if it's possible to symbolically evaluate
// the arguments into constants, and if so, try to constant propagate the
// result. This is particularly useful for computing loop exit values.
if (CanConstantFold(I)) {
SmallVector<Constant *, 4> Operands;
bool MadeImprovement = false;
for (Value *Op : I->operands()) {
if (Constant *C = dyn_cast<Constant>(Op)) {
Operands.push_back(C);
continue;
}
// If any of the operands is non-constant and if they are
// non-integer and non-pointer, don't even try to analyze them
// with scev techniques.
if (!isSCEVable(Op->getType()))
return V;
const SCEV *OrigV = getSCEV(Op);
const SCEV *OpV = getSCEVAtScope(OrigV, L);
MadeImprovement |= OrigV != OpV;
Constant *C = BuildConstantFromSCEV(OpV);
if (!C) return V;
if (C->getType() != Op->getType())
C = ConstantExpr::getCast(CastInst::getCastOpcode(C, false,
Op->getType(),
false),
C, Op->getType());
Operands.push_back(C);
}
// Check to see if getSCEVAtScope actually made an improvement.
if (MadeImprovement) {
Constant *C = nullptr;
const DataLayout &DL = getDataLayout();
C = ConstantFoldInstOperands(I, Operands, DL, &TLI);
if (!C) return V;
return getSCEV(C);
}
}
}
// This is some other type of SCEVUnknown, just return it.
return V;
}
if (isa<SCEVCommutativeExpr>(V) || isa<SCEVSequentialMinMaxExpr>(V)) {
const auto *Comm = cast<SCEVNAryExpr>(V);
// Avoid performing the look-up in the common case where the specified
// expression has no loop-variant portions.
for (unsigned i = 0, e = Comm->getNumOperands(); i != e; ++i) {
const SCEV *OpAtScope = getSCEVAtScope(Comm->getOperand(i), L);
if (OpAtScope != Comm->getOperand(i)) {
// Okay, at least one of these operands is loop variant but might be
// foldable. Build a new instance of the folded commutative expression.
SmallVector<const SCEV *, 8> NewOps(Comm->op_begin(),
Comm->op_begin()+i);
NewOps.push_back(OpAtScope);
for (++i; i != e; ++i) {
OpAtScope = getSCEVAtScope(Comm->getOperand(i), L);
NewOps.push_back(OpAtScope);
}
if (isa<SCEVAddExpr>(Comm))
return getAddExpr(NewOps, Comm->getNoWrapFlags());
if (isa<SCEVMulExpr>(Comm))
return getMulExpr(NewOps, Comm->getNoWrapFlags());
if (isa<SCEVMinMaxExpr>(Comm))
return getMinMaxExpr(Comm->getSCEVType(), NewOps);
if (isa<SCEVSequentialMinMaxExpr>(Comm))
return getSequentialMinMaxExpr(Comm->getSCEVType(), NewOps);
llvm_unreachable("Unknown commutative / sequential min/max SCEV type!");
}
}
// If we got here, all operands are loop invariant.
return Comm;
}
if (const SCEVUDivExpr *Div = dyn_cast<SCEVUDivExpr>(V)) {
const SCEV *LHS = getSCEVAtScope(Div->getLHS(), L);
const SCEV *RHS = getSCEVAtScope(Div->getRHS(), L);
if (LHS == Div->getLHS() && RHS == Div->getRHS())
return Div; // must be loop invariant
return getUDivExpr(LHS, RHS);
}
// If this is a loop recurrence for a loop that does not contain L, then we
// are dealing with the final value computed by the loop.
if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(V)) {
// First, attempt to evaluate each operand.
// Avoid performing the look-up in the common case where the specified
// expression has no loop-variant portions.
for (unsigned i = 0, e = AddRec->getNumOperands(); i != e; ++i) {
const SCEV *OpAtScope = getSCEVAtScope(AddRec->getOperand(i), L);
if (OpAtScope == AddRec->getOperand(i))
continue;
// Okay, at least one of these operands is loop variant but might be
// foldable. Build a new instance of the folded commutative expression.
SmallVector<const SCEV *, 8> NewOps(AddRec->op_begin(),
AddRec->op_begin()+i);
NewOps.push_back(OpAtScope);
for (++i; i != e; ++i)
NewOps.push_back(getSCEVAtScope(AddRec->getOperand(i), L));
const SCEV *FoldedRec =
getAddRecExpr(NewOps, AddRec->getLoop(),
AddRec->getNoWrapFlags(SCEV::FlagNW));
AddRec = dyn_cast<SCEVAddRecExpr>(FoldedRec);
// The addrec may be folded to a nonrecurrence, for example, if the
// induction variable is multiplied by zero after constant folding. Go
// ahead and return the folded value.
if (!AddRec)
return FoldedRec;
break;
}
// If the scope is outside the addrec's loop, evaluate it by using the
// loop exit value of the addrec.
if (!AddRec->getLoop()->contains(L)) {
// To evaluate this recurrence, we need to know how many times the AddRec
// loop iterates. Compute this now.
const SCEV *BackedgeTakenCount = getBackedgeTakenCount(AddRec->getLoop());
if (BackedgeTakenCount == getCouldNotCompute()) return AddRec;
// Then, evaluate the AddRec.
return AddRec->evaluateAtIteration(BackedgeTakenCount, *this);
}
return AddRec;
}
if (const SCEVCastExpr *Cast = dyn_cast<SCEVCastExpr>(V)) {
const SCEV *Op = getSCEVAtScope(Cast->getOperand(), L);
if (Op == Cast->getOperand())
return Cast; // must be loop invariant
return getCastExpr(Cast->getSCEVType(), Op, Cast->getType());
}
llvm_unreachable("Unknown SCEV type!");
}
const SCEV *ScalarEvolution::getSCEVAtScope(Value *V, const Loop *L) {
return getSCEVAtScope(getSCEV(V), L);
}
const SCEV *ScalarEvolution::stripInjectiveFunctions(const SCEV *S) const {
if (const SCEVZeroExtendExpr *ZExt = dyn_cast<SCEVZeroExtendExpr>(S))
return stripInjectiveFunctions(ZExt->getOperand());
if (const SCEVSignExtendExpr *SExt = dyn_cast<SCEVSignExtendExpr>(S))
return stripInjectiveFunctions(SExt->getOperand());
return S;
}
/// Finds the minimum unsigned root of the following equation:
///
/// A * X = B (mod N)
///
/// where N = 2^BW and BW is the common bit width of A and B. The signedness of
/// A and B isn't important.
///
/// If the equation does not have a solution, SCEVCouldNotCompute is returned.
static const SCEV *SolveLinEquationWithOverflow(const APInt &A, const SCEV *B,
ScalarEvolution &SE) {
uint32_t BW = A.getBitWidth();
assert(BW == SE.getTypeSizeInBits(B->getType()));
assert(A != 0 && "A must be non-zero.");
// 1. D = gcd(A, N)
//
// The gcd of A and N may have only one prime factor: 2. The number of
// trailing zeros in A is its multiplicity
uint32_t Mult2 = A.countTrailingZeros();
// D = 2^Mult2
// 2. Check if B is divisible by D.
//
// B is divisible by D if and only if the multiplicity of prime factor 2 for B
// is not less than multiplicity of this prime factor for D.
if (SE.GetMinTrailingZeros(B) < Mult2)
return SE.getCouldNotCompute();
// 3. Compute I: the multiplicative inverse of (A / D) in arithmetic
// modulo (N / D).
//
// If D == 1, (N / D) == N == 2^BW, so we need one extra bit to represent
// (N / D) in general. The inverse itself always fits into BW bits, though,
// so we immediately truncate it.
APInt AD = A.lshr(Mult2).zext(BW + 1); // AD = A / D
APInt Mod(BW + 1, 0);
Mod.setBit(BW - Mult2); // Mod = N / D
APInt I = AD.multiplicativeInverse(Mod).trunc(BW);
// 4. Compute the minimum unsigned root of the equation:
// I * (B / D) mod (N / D)
// To simplify the computation, we factor out the divide by D:
// (I * B mod N) / D
const SCEV *D = SE.getConstant(APInt::getOneBitSet(BW, Mult2));
return SE.getUDivExactExpr(SE.getMulExpr(B, SE.getConstant(I)), D);
}
/// For a given quadratic addrec, generate coefficients of the corresponding
/// quadratic equation, multiplied by a common value to ensure that they are
/// integers.
/// The returned value is a tuple { A, B, C, M, BitWidth }, where
/// Ax^2 + Bx + C is the quadratic function, M is the value that A, B and C
/// were multiplied by, and BitWidth is the bit width of the original addrec
/// coefficients.
/// This function returns None if the addrec coefficients are not compile-
/// time constants.
static Optional<std::tuple<APInt, APInt, APInt, APInt, unsigned>>
GetQuadraticEquation(const SCEVAddRecExpr *AddRec) {
assert(AddRec->getNumOperands() == 3 && "This is not a quadratic chrec!");
const SCEVConstant *LC = dyn_cast<SCEVConstant>(AddRec->getOperand(0));
const SCEVConstant *MC = dyn_cast<SCEVConstant>(AddRec->getOperand(1));
const SCEVConstant *NC = dyn_cast<SCEVConstant>(AddRec->getOperand(2));
LLVM_DEBUG(dbgs() << __func__ << ": analyzing quadratic addrec: "
<< *AddRec << '\n');
// We currently can only solve this if the coefficients are constants.
if (!LC || !MC || !NC) {
LLVM_DEBUG(dbgs() << __func__ << ": coefficients are not constant\n");
return None;
}
APInt L = LC->getAPInt();
APInt M = MC->getAPInt();
APInt N = NC->getAPInt();
assert(!N.isZero() && "This is not a quadratic addrec");
unsigned BitWidth = LC->getAPInt().getBitWidth();
unsigned NewWidth = BitWidth + 1;
LLVM_DEBUG(dbgs() << __func__ << ": addrec coeff bw: "
<< BitWidth << '\n');
// The sign-extension (as opposed to a zero-extension) here matches the
// extension used in SolveQuadraticEquationWrap (with the same motivation).
N = N.sext(NewWidth);
M = M.sext(NewWidth);
L = L.sext(NewWidth);
// The increments are M, M+N, M+2N, ..., so the accumulated values are
// L+M, (L+M)+(M+N), (L+M)+(M+N)+(M+2N), ..., that is,
// L+M, L+2M+N, L+3M+3N, ...
// After n iterations the accumulated value Acc is L + nM + n(n-1)/2 N.
//
// The equation Acc = 0 is then
// L + nM + n(n-1)/2 N = 0, or 2L + 2M n + n(n-1) N = 0.
// In a quadratic form it becomes:
// N n^2 + (2M-N) n + 2L = 0.
APInt A = N;
APInt B = 2 * M - A;
APInt C = 2 * L;
APInt T = APInt(NewWidth, 2);
LLVM_DEBUG(dbgs() << __func__ << ": equation " << A << "x^2 + " << B
<< "x + " << C << ", coeff bw: " << NewWidth
<< ", multiplied by " << T << '\n');
return std::make_tuple(A, B, C, T, BitWidth);
}
/// Helper function to compare optional APInts:
/// (a) if X and Y both exist, return min(X, Y),
/// (b) if neither X nor Y exist, return None,
/// (c) if exactly one of X and Y exists, return that value.
static Optional<APInt> MinOptional(Optional<APInt> X, Optional<APInt> Y) {
if (X && Y) {
unsigned W = std::max(X->getBitWidth(), Y->getBitWidth());
APInt XW = X->sext(W);
APInt YW = Y->sext(W);
return XW.slt(YW) ? *X : *Y;
}
if (!X && !Y)
return None;
return X ? *X : *Y;
}
/// Helper function to truncate an optional APInt to a given BitWidth.
/// When solving addrec-related equations, it is preferable to return a value
/// that has the same bit width as the original addrec's coefficients. If the
/// solution fits in the original bit width, truncate it (except for i1).
/// Returning a value of a different bit width may inhibit some optimizations.
///
/// In general, a solution to a quadratic equation generated from an addrec
/// may require BW+1 bits, where BW is the bit width of the addrec's
/// coefficients. The reason is that the coefficients of the quadratic
/// equation are BW+1 bits wide (to avoid truncation when converting from
/// the addrec to the equation).
static Optional<APInt> TruncIfPossible(Optional<APInt> X, unsigned BitWidth) {
if (!X)
return None;
unsigned W = X->getBitWidth();
if (BitWidth > 1 && BitWidth < W && X->isIntN(BitWidth))
return X->trunc(BitWidth);
return X;
}
/// Let c(n) be the value of the quadratic chrec {L,+,M,+,N} after n
/// iterations. The values L, M, N are assumed to be signed, and they
/// should all have the same bit widths.
/// Find the least n >= 0 such that c(n) = 0 in the arithmetic modulo 2^BW,
/// where BW is the bit width of the addrec's coefficients.
/// If the calculated value is a BW-bit integer (for BW > 1), it will be
/// returned as such, otherwise the bit width of the returned value may
/// be greater than BW.
///
/// This function returns None if
/// (a) the addrec coefficients are not constant, or
/// (b) SolveQuadraticEquationWrap was unable to find a solution. For cases
/// like x^2 = 5, no integer solutions exist, in other cases an integer
/// solution may exist, but SolveQuadraticEquationWrap may fail to find it.
static Optional<APInt>
SolveQuadraticAddRecExact(const SCEVAddRecExpr *AddRec, ScalarEvolution &SE) {
APInt A, B, C, M;
unsigned BitWidth;
auto T = GetQuadraticEquation(AddRec);
if (!T)
return None;
std::tie(A, B, C, M, BitWidth) = *T;
LLVM_DEBUG(dbgs() << __func__ << ": solving for unsigned overflow\n");
Optional<APInt> X = APIntOps::SolveQuadraticEquationWrap(A, B, C, BitWidth+1);
if (!X)
return None;
ConstantInt *CX = ConstantInt::get(SE.getContext(), *X);
ConstantInt *V = EvaluateConstantChrecAtConstant(AddRec, CX, SE);
if (!V->isZero())
return None;
return TruncIfPossible(X, BitWidth);
}
/// Let c(n) be the value of the quadratic chrec {0,+,M,+,N} after n
/// iterations. The values M, N are assumed to be signed, and they
/// should all have the same bit widths.
/// Find the least n such that c(n) does not belong to the given range,
/// while c(n-1) does.
///
/// This function returns None if
/// (a) the addrec coefficients are not constant, or
/// (b) SolveQuadraticEquationWrap was unable to find a solution for the
/// bounds of the range.
static Optional<APInt>
SolveQuadraticAddRecRange(const SCEVAddRecExpr *AddRec,
const ConstantRange &Range, ScalarEvolution &SE) {
assert(AddRec->getOperand(0)->isZero() &&
"Starting value of addrec should be 0");
LLVM_DEBUG(dbgs() << __func__ << ": solving boundary crossing for range "
<< Range << ", addrec " << *AddRec << '\n');
// This case is handled in getNumIterationsInRange. Here we can assume that
// we start in the range.
assert(Range.contains(APInt(SE.getTypeSizeInBits(AddRec->getType()), 0)) &&
"Addrec's initial value should be in range");
APInt A, B, C, M;
unsigned BitWidth;
auto T = GetQuadraticEquation(AddRec);
if (!T)
return None;
// Be careful about the return value: there can be two reasons for not
// returning an actual number. First, if no solutions to the equations
// were found, and second, if the solutions don't leave the given range.
// The first case means that the actual solution is "unknown", the second
// means that it's known, but not valid. If the solution is unknown, we
// cannot make any conclusions.
// Return a pair: the optional solution and a flag indicating if the
// solution was found.
auto SolveForBoundary = [&](APInt Bound) -> std::pair<Optional<APInt>,bool> {
// Solve for signed overflow and unsigned overflow, pick the lower
// solution.
LLVM_DEBUG(dbgs() << "SolveQuadraticAddRecRange: checking boundary "
<< Bound << " (before multiplying by " << M << ")\n");
Bound *= M; // The quadratic equation multiplier.
Optional<APInt> SO = None;
if (BitWidth > 1) {
LLVM_DEBUG(dbgs() << "SolveQuadraticAddRecRange: solving for "
"signed overflow\n");
SO = APIntOps::SolveQuadraticEquationWrap(A, B, -Bound, BitWidth);
}
LLVM_DEBUG(dbgs() << "SolveQuadraticAddRecRange: solving for "
"unsigned overflow\n");
Optional<APInt> UO = APIntOps::SolveQuadraticEquationWrap(A, B, -Bound,
BitWidth+1);
auto LeavesRange = [&] (const APInt &X) {
ConstantInt *C0 = ConstantInt::get(SE.getContext(), X);
ConstantInt *V0 = EvaluateConstantChrecAtConstant(AddRec, C0, SE);
if (Range.contains(V0->getValue()))
return false;
// X should be at least 1, so X-1 is non-negative.
ConstantInt *C1 = ConstantInt::get(SE.getContext(), X-1);
ConstantInt *V1 = EvaluateConstantChrecAtConstant(AddRec, C1, SE);
if (Range.contains(V1->getValue()))
return true;
return false;
};
// If SolveQuadraticEquationWrap returns None, it means that there can
// be a solution, but the function failed to find it. We cannot treat it
// as "no solution".
if (!SO || !UO)
return { None, false };
// Check the smaller value first to see if it leaves the range.
// At this point, both SO and UO must have values.
Optional<APInt> Min = MinOptional(SO, UO);
if (LeavesRange(*Min))
return { Min, true };
Optional<APInt> Max = Min == SO ? UO : SO;
if (LeavesRange(*Max))
return { Max, true };
// Solutions were found, but were eliminated, hence the "true".
return { None, true };
};
std::tie(A, B, C, M, BitWidth) = *T;
// Lower bound is inclusive, subtract 1 to represent the exiting value.
APInt Lower = Range.getLower().sext(A.getBitWidth()) - 1;
APInt Upper = Range.getUpper().sext(A.getBitWidth());
auto SL = SolveForBoundary(Lower);
auto SU = SolveForBoundary(Upper);
// If any of the solutions was unknown, no meaninigful conclusions can
// be made.
if (!SL.second || !SU.second)
return None;
// Claim: The correct solution is not some value between Min and Max.
//
// Justification: Assuming that Min and Max are different values, one of
// them is when the first signed overflow happens, the other is when the
// first unsigned overflow happens. Crossing the range boundary is only
// possible via an overflow (treating 0 as a special case of it, modeling
// an overflow as crossing k*2^W for some k).
//
// The interesting case here is when Min was eliminated as an invalid
// solution, but Max was not. The argument is that if there was another
// overflow between Min and Max, it would also have been eliminated if
// it was considered.
//
// For a given boundary, it is possible to have two overflows of the same
// type (signed/unsigned) without having the other type in between: this
// can happen when the vertex of the parabola is between the iterations
// corresponding to the overflows. This is only possible when the two
// overflows cross k*2^W for the same k. In such case, if the second one
// left the range (and was the first one to do so), the first overflow
// would have to enter the range, which would mean that either we had left
// the range before or that we started outside of it. Both of these cases
// are contradictions.
//
// Claim: In the case where SolveForBoundary returns None, the correct
// solution is not some value between the Max for this boundary and the
// Min of the other boundary.
//
// Justification: Assume that we had such Max_A and Min_B corresponding
// to range boundaries A and B and such that Max_A < Min_B. If there was
// a solution between Max_A and Min_B, it would have to be caused by an
// overflow corresponding to either A or B. It cannot correspond to B,
// since Min_B is the first occurrence of such an overflow. If it
// corresponded to A, it would have to be either a signed or an unsigned
// overflow that is larger than both eliminated overflows for A. But
// between the eliminated overflows and this overflow, the values would
// cover the entire value space, thus crossing the other boundary, which
// is a contradiction.
return TruncIfPossible(MinOptional(SL.first, SU.first), BitWidth);
}
ScalarEvolution::ExitLimit
ScalarEvolution::howFarToZero(const SCEV *V, const Loop *L, bool ControlsExit,
bool AllowPredicates) {
// This is only used for loops with a "x != y" exit test. The exit condition
// is now expressed as a single expression, V = x-y. So the exit test is
// effectively V != 0. We know and take advantage of the fact that this
// expression only being used in a comparison by zero context.
SmallPtrSet<const SCEVPredicate *, 4> Predicates;
// If the value is a constant
if (const SCEVConstant *C = dyn_cast<SCEVConstant>(V)) {
// If the value is already zero, the branch will execute zero times.
if (C->getValue()->isZero()) return C;
return getCouldNotCompute(); // Otherwise it will loop infinitely.
}
const SCEVAddRecExpr *AddRec =
dyn_cast<SCEVAddRecExpr>(stripInjectiveFunctions(V));
if (!AddRec && AllowPredicates)
// Try to make this an AddRec using runtime tests, in the first X
// iterations of this loop, where X is the SCEV expression found by the
// algorithm below.
AddRec = convertSCEVToAddRecWithPredicates(V, L, Predicates);
if (!AddRec || AddRec->getLoop() != L)
return getCouldNotCompute();
// If this is a quadratic (3-term) AddRec {L,+,M,+,N}, find the roots of
// the quadratic equation to solve it.
if (AddRec->isQuadratic() && AddRec->getType()->isIntegerTy()) {
// We can only use this value if the chrec ends up with an exact zero
// value at this index. When solving for "X*X != 5", for example, we
// should not accept a root of 2.
if (auto S = SolveQuadraticAddRecExact(AddRec, *this)) {
const auto *R = cast<SCEVConstant>(getConstant(*S));
return ExitLimit(R, R, false, Predicates);
}
return getCouldNotCompute();
}
// Otherwise we can only handle this if it is affine.
if (!AddRec->isAffine())
return getCouldNotCompute();
// If this is an affine expression, the execution count of this branch is
// the minimum unsigned root of the following equation:
//
// Start + Step*N = 0 (mod 2^BW)
//
// equivalent to:
//
// Step*N = -Start (mod 2^BW)
//
// where BW is the common bit width of Start and Step.
// Get the initial value for the loop.
const SCEV *Start = getSCEVAtScope(AddRec->getStart(), L->getParentLoop());
const SCEV *Step = getSCEVAtScope(AddRec->getOperand(1), L->getParentLoop());
// For now we handle only constant steps.
//
// TODO: Handle a nonconstant Step given AddRec<NUW>. If the
// AddRec is NUW, then (in an unsigned sense) it cannot be counting up to wrap
// to 0, it must be counting down to equal 0. Consequently, N = Start / -Step.
// We have not yet seen any such cases.
const SCEVConstant *StepC = dyn_cast<SCEVConstant>(Step);
if (!StepC || StepC->getValue()->isZero())
return getCouldNotCompute();
// For positive steps (counting up until unsigned overflow):
// N = -Start/Step (as unsigned)
// For negative steps (counting down to zero):
// N = Start/-Step
// First compute the unsigned distance from zero in the direction of Step.
bool CountDown = StepC->getAPInt().isNegative();
const SCEV *Distance = CountDown ? Start : getNegativeSCEV(Start);
// Handle unitary steps, which cannot wraparound.
// 1*N = -Start; -1*N = Start (mod 2^BW), so:
// N = Distance (as unsigned)
if (StepC->getValue()->isOne() || StepC->getValue()->isMinusOne()) {
APInt MaxBECount = getUnsignedRangeMax(applyLoopGuards(Distance, L));
MaxBECount = APIntOps::umin(MaxBECount, getUnsignedRangeMax(Distance));
// When a loop like "for (int i = 0; i != n; ++i) { /* body */ }" is rotated,
// we end up with a loop whose backedge-taken count is n - 1. Detect this
// case, and see if we can improve the bound.
//
// Explicitly handling this here is necessary because getUnsignedRange
// isn't context-sensitive; it doesn't know that we only care about the
// range inside the loop.
const SCEV *Zero = getZero(Distance->getType());
const SCEV *One = getOne(Distance->getType());
const SCEV *DistancePlusOne = getAddExpr(Distance, One);
if (isLoopEntryGuardedByCond(L, ICmpInst::ICMP_NE, DistancePlusOne, Zero)) {
// If Distance + 1 doesn't overflow, we can compute the maximum distance
// as "unsigned_max(Distance + 1) - 1".
ConstantRange CR = getUnsignedRange(DistancePlusOne);
MaxBECount = APIntOps::umin(MaxBECount, CR.getUnsignedMax() - 1);
}
return ExitLimit(Distance, getConstant(MaxBECount), false, Predicates);
}
// If the condition controls loop exit (the loop exits only if the expression
// is true) and the addition is no-wrap we can use unsigned divide to
// compute the backedge count. In this case, the step may not divide the
// distance, but we don't care because if the condition is "missed" the loop
// will have undefined behavior due to wrapping.
if (ControlsExit && AddRec->hasNoSelfWrap() &&
loopHasNoAbnormalExits(AddRec->getLoop())) {
const SCEV *Exact =
getUDivExpr(Distance, CountDown ? getNegativeSCEV(Step) : Step);
const SCEV *Max = getCouldNotCompute();
if (Exact != getCouldNotCompute()) {
APInt MaxInt = getUnsignedRangeMax(applyLoopGuards(Exact, L));
Max = getConstant(APIntOps::umin(MaxInt, getUnsignedRangeMax(Exact)));
}
return ExitLimit(Exact, Max, false, Predicates);
}
// Solve the general equation.
const SCEV *E = SolveLinEquationWithOverflow(StepC->getAPInt(),
getNegativeSCEV(Start), *this);
const SCEV *M = E;
if (E != getCouldNotCompute()) {
APInt MaxWithGuards = getUnsignedRangeMax(applyLoopGuards(E, L));
M = getConstant(APIntOps::umin(MaxWithGuards, getUnsignedRangeMax(E)));
}
return ExitLimit(E, M, false, Predicates);
}
ScalarEvolution::ExitLimit
ScalarEvolution::howFarToNonZero(const SCEV *V, const Loop *L) {
// Loops that look like: while (X == 0) are very strange indeed. We don't
// handle them yet except for the trivial case. This could be expanded in the
// future as needed.
// If the value is a constant, check to see if it is known to be non-zero
// already. If so, the backedge will execute zero times.
if (const SCEVConstant *C = dyn_cast<SCEVConstant>(V)) {
if (!C->getValue()->isZero())
return getZero(C->getType());
return getCouldNotCompute(); // Otherwise it will loop infinitely.
}
// We could implement others, but I really doubt anyone writes loops like
// this, and if they did, they would already be constant folded.
return getCouldNotCompute();
}
std::pair<const BasicBlock *, const BasicBlock *>
ScalarEvolution::getPredecessorWithUniqueSuccessorForBB(const BasicBlock *BB)
const {
// If the block has a unique predecessor, then there is no path from the
// predecessor to the block that does not go through the direct edge
// from the predecessor to the block.
if (const BasicBlock *Pred = BB->getSinglePredecessor())
return {Pred, BB};
// A loop's header is defined to be a block that dominates the loop.
// If the header has a unique predecessor outside the loop, it must be
// a block that has exactly one successor that can reach the loop.
if (const Loop *L = LI.getLoopFor(BB))
return {L->getLoopPredecessor(), L->getHeader()};
return {nullptr, nullptr};
}
/// SCEV structural equivalence is usually sufficient for testing whether two
/// expressions are equal, however for the purposes of looking for a condition
/// guarding a loop, it can be useful to be a little more general, since a
/// front-end may have replicated the controlling expression.
static bool HasSameValue(const SCEV *A, const SCEV *B) {
// Quick check to see if they are the same SCEV.
if (A == B) return true;
auto ComputesEqualValues = [](const Instruction *A, const Instruction *B) {
// Not all instructions that are "identical" compute the same value. For
// instance, two distinct alloca instructions allocating the same type are
// identical and do not read memory; but compute distinct values.
return A->isIdenticalTo(B) && (isa<BinaryOperator>(A) || isa<GetElementPtrInst>(A));
};
// Otherwise, if they're both SCEVUnknown, it's possible that they hold
// two different instructions with the same value. Check for this case.
if (const SCEVUnknown *AU = dyn_cast<SCEVUnknown>(A))
if (const SCEVUnknown *BU = dyn_cast<SCEVUnknown>(B))
if (const Instruction *AI = dyn_cast<Instruction>(AU->getValue()))
if (const Instruction *BI = dyn_cast<Instruction>(BU->getValue()))
if (ComputesEqualValues(AI, BI))
return true;
// Otherwise assume they may have a different value.
return false;
}
bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred,
const SCEV *&LHS, const SCEV *&RHS,
unsigned Depth,
bool ControllingFiniteLoop) {
bool Changed = false;
// Simplifies ICMP to trivial true or false by turning it into '0 == 0' or
// '0 != 0'.
auto TrivialCase = [&](bool TriviallyTrue) {
LHS = RHS = getConstant(ConstantInt::getFalse(getContext()));
Pred = TriviallyTrue ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE;
return true;
};
// If we hit the max recursion limit bail out.
if (Depth >= 3)
return false;
// Canonicalize a constant to the right side.
if (const SCEVConstant *LHSC = dyn_cast<SCEVConstant>(LHS)) {
// Check for both operands constant.
if (const SCEVConstant *RHSC = dyn_cast<SCEVConstant>(RHS)) {
if (ConstantExpr::getICmp(Pred,
LHSC->getValue(),
RHSC->getValue())->isNullValue())
return TrivialCase(false);
else
return TrivialCase(true);
}
// Otherwise swap the operands to put the constant on the right.
std::swap(LHS, RHS);
Pred = ICmpInst::getSwappedPredicate(Pred);
Changed = true;
}
// If we're comparing an addrec with a value which is loop-invariant in the
// addrec's loop, put the addrec on the left. Also make a dominance check,
// as both operands could be addrecs loop-invariant in each other's loop.
if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(RHS)) {
const Loop *L = AR->getLoop();
if (isLoopInvariant(LHS, L) && properlyDominates(LHS, L->getHeader())) {
std::swap(LHS, RHS);
Pred = ICmpInst::getSwappedPredicate(Pred);
Changed = true;
}
}
// If there's a constant operand, canonicalize comparisons with boundary
// cases, and canonicalize *-or-equal comparisons to regular comparisons.
if (const SCEVConstant *RC = dyn_cast<SCEVConstant>(RHS)) {
const APInt &RA = RC->getAPInt();
bool SimplifiedByConstantRange = false;
if (!ICmpInst::isEquality(Pred)) {
ConstantRange ExactCR = ConstantRange::makeExactICmpRegion(Pred, RA);
if (ExactCR.isFullSet())
return TrivialCase(true);
else if (ExactCR.isEmptySet())
return TrivialCase(false);
APInt NewRHS;
CmpInst::Predicate NewPred;
if (ExactCR.getEquivalentICmp(NewPred, NewRHS) &&
ICmpInst::isEquality(NewPred)) {
// We were able to convert an inequality to an equality.
Pred = NewPred;
RHS = getConstant(NewRHS);
Changed = SimplifiedByConstantRange = true;
}
}
if (!SimplifiedByConstantRange) {
switch (Pred) {
default:
break;
case ICmpInst::ICMP_EQ:
case ICmpInst::ICMP_NE:
// Fold ((-1) * %a) + %b == 0 (equivalent to %b-%a == 0) into %a == %b.
if (!RA)
if (const SCEVAddExpr *AE = dyn_cast<SCEVAddExpr>(LHS))
if (const SCEVMulExpr *ME =
dyn_cast<SCEVMulExpr>(AE->getOperand(0)))
if (AE->getNumOperands() == 2 && ME->getNumOperands() == 2 &&
ME->getOperand(0)->isAllOnesValue()) {
RHS = AE->getOperand(1);
LHS = ME->getOperand(1);
Changed = true;
}
break;
// The "Should have been caught earlier!" messages refer to the fact
// that the ExactCR.isFullSet() or ExactCR.isEmptySet() check above
// should have fired on the corresponding cases, and canonicalized the
// check to trivial case.
case ICmpInst::ICMP_UGE:
assert(!RA.isMinValue() && "Should have been caught earlier!");
Pred = ICmpInst::ICMP_UGT;
RHS = getConstant(RA - 1);
Changed = true;
break;
case ICmpInst::ICMP_ULE:
assert(!RA.isMaxValue() && "Should have been caught earlier!");
Pred = ICmpInst::ICMP_ULT;
RHS = getConstant(RA + 1);
Changed = true;
break;
case ICmpInst::ICMP_SGE:
assert(!RA.isMinSignedValue() && "Should have been caught earlier!");
Pred = ICmpInst::ICMP_SGT;
RHS = getConstant(RA - 1);
Changed = true;
break;
case ICmpInst::ICMP_SLE:
assert(!RA.isMaxSignedValue() && "Should have been caught earlier!");
Pred = ICmpInst::ICMP_SLT;
RHS = getConstant(RA + 1);
Changed = true;
break;
}
}
}
// Check for obvious equality.
if (HasSameValue(LHS, RHS)) {
if (ICmpInst::isTrueWhenEqual(Pred))
return TrivialCase(true);
if (ICmpInst::isFalseWhenEqual(Pred))
return TrivialCase(false);
}
// If possible, canonicalize GE/LE comparisons to GT/LT comparisons, by
// adding or subtracting 1 from one of the operands. This can be done for
// one of two reasons:
// 1) The range of the RHS does not include the (signed/unsigned) boundaries
// 2) The loop is finite, with this comparison controlling the exit. Since the
// loop is finite, the bound cannot include the corresponding boundary
// (otherwise it would loop forever).
switch (Pred) {
case ICmpInst::ICMP_SLE:
if (ControllingFiniteLoop || !getSignedRangeMax(RHS).isMaxSignedValue()) {
RHS = getAddExpr(getConstant(RHS->getType(), 1, true), RHS,
SCEV::FlagNSW);
Pred = ICmpInst::ICMP_SLT;
Changed = true;
} else if (!getSignedRangeMin(LHS).isMinSignedValue()) {
LHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), LHS,
SCEV::FlagNSW);
Pred = ICmpInst::ICMP_SLT;
Changed = true;
}
break;
case ICmpInst::ICMP_SGE:
if (ControllingFiniteLoop || !getSignedRangeMin(RHS).isMinSignedValue()) {
RHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), RHS,
SCEV::FlagNSW);
Pred = ICmpInst::ICMP_SGT;
Changed = true;
} else if (!getSignedRangeMax(LHS).isMaxSignedValue()) {
LHS = getAddExpr(getConstant(RHS->getType(), 1, true), LHS,
SCEV::FlagNSW);
Pred = ICmpInst::ICMP_SGT;
Changed = true;
}
break;
case ICmpInst::ICMP_ULE:
if (ControllingFiniteLoop || !getUnsignedRangeMax(RHS).isMaxValue()) {
RHS = getAddExpr(getConstant(RHS->getType(), 1, true), RHS,
SCEV::FlagNUW);
Pred = ICmpInst::ICMP_ULT;
Changed = true;
} else if (!getUnsignedRangeMin(LHS).isMinValue()) {
LHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), LHS);
Pred = ICmpInst::ICMP_ULT;
Changed = true;
}
break;
case ICmpInst::ICMP_UGE:
if (ControllingFiniteLoop || !getUnsignedRangeMin(RHS).isMinValue()) {
RHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), RHS);
Pred = ICmpInst::ICMP_UGT;
Changed = true;
} else if (!getUnsignedRangeMax(LHS).isMaxValue()) {
LHS = getAddExpr(getConstant(RHS->getType(), 1, true), LHS,
SCEV::FlagNUW);
Pred = ICmpInst::ICMP_UGT;
Changed = true;
}
break;
default:
break;
}
// TODO: More simplifications are possible here.
// Recursively simplify until we either hit a recursion limit or nothing
// changes.
if (Changed)
return SimplifyICmpOperands(Pred, LHS, RHS, Depth + 1,
ControllingFiniteLoop);
return Changed;
}
bool ScalarEvolution::isKnownNegative(const SCEV *S) {
return getSignedRangeMax(S).isNegative();
}
bool ScalarEvolution::isKnownPositive(const SCEV *S) {
return getSignedRangeMin(S).isStrictlyPositive();
}
bool ScalarEvolution::isKnownNonNegative(const SCEV *S) {
return !getSignedRangeMin(S).isNegative();
}
bool ScalarEvolution::isKnownNonPositive(const SCEV *S) {
return !getSignedRangeMax(S).isStrictlyPositive();
}
bool ScalarEvolution::isKnownNonZero(const SCEV *S) {
return getUnsignedRangeMin(S) != 0;
}
std::pair<const SCEV *, const SCEV *>
ScalarEvolution::SplitIntoInitAndPostInc(const Loop *L, const SCEV *S) {
// Compute SCEV on entry of loop L.
const SCEV *Start = SCEVInitRewriter::rewrite(S, L, *this);
if (Start == getCouldNotCompute())
return { Start, Start };
// Compute post increment SCEV for loop L.
const SCEV *PostInc = SCEVPostIncRewriter::rewrite(S, L, *this);
assert(PostInc != getCouldNotCompute() && "Unexpected could not compute");
return { Start, PostInc };
}
bool ScalarEvolution::isKnownViaInduction(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS) {
// First collect all loops.
SmallPtrSet<const Loop *, 8> LoopsUsed;
getUsedLoops(LHS, LoopsUsed);
getUsedLoops(RHS, LoopsUsed);
if (LoopsUsed.empty())
return false;
// Domination relationship must be a linear order on collected loops.
#ifndef NDEBUG
for (const auto *L1 : LoopsUsed)
for (const auto *L2 : LoopsUsed)
assert((DT.dominates(L1->getHeader(), L2->getHeader()) ||
DT.dominates(L2->getHeader(), L1->getHeader())) &&
"Domination relationship is not a linear order");
#endif
const Loop *MDL =
*std::max_element(LoopsUsed.begin(), LoopsUsed.end(),
[&](const Loop *L1, const Loop *L2) {
return DT.properlyDominates(L1->getHeader(), L2->getHeader());
});
// Get init and post increment value for LHS.
auto SplitLHS = SplitIntoInitAndPostInc(MDL, LHS);
// if LHS contains unknown non-invariant SCEV then bail out.
if (SplitLHS.first == getCouldNotCompute())
return false;
assert (SplitLHS.second != getCouldNotCompute() && "Unexpected CNC");
// Get init and post increment value for RHS.
auto SplitRHS = SplitIntoInitAndPostInc(MDL, RHS);
// if RHS contains unknown non-invariant SCEV then bail out.
if (SplitRHS.first == getCouldNotCompute())
return false;
assert (SplitRHS.second != getCouldNotCompute() && "Unexpected CNC");
// It is possible that init SCEV contains an invariant load but it does
// not dominate MDL and is not available at MDL loop entry, so we should
// check it here.
if (!isAvailableAtLoopEntry(SplitLHS.first, MDL) ||
!isAvailableAtLoopEntry(SplitRHS.first, MDL))
return false;
// It seems backedge guard check is faster than entry one so in some cases
// it can speed up whole estimation by short circuit
return isLoopBackedgeGuardedByCond(MDL, Pred, SplitLHS.second,
SplitRHS.second) &&
isLoopEntryGuardedByCond(MDL, Pred, SplitLHS.first, SplitRHS.first);
}
bool ScalarEvolution::isKnownPredicate(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS) {
// Canonicalize the inputs first.
(void)SimplifyICmpOperands(Pred, LHS, RHS);
if (isKnownViaInduction(Pred, LHS, RHS))
return true;
if (isKnownPredicateViaSplitting(Pred, LHS, RHS))
return true;
// Otherwise see what can be done with some simple reasoning.
return isKnownViaNonRecursiveReasoning(Pred, LHS, RHS);
}
Optional<bool> ScalarEvolution::evaluatePredicate(ICmpInst::Predicate Pred,
const SCEV *LHS,
const SCEV *RHS) {
if (isKnownPredicate(Pred, LHS, RHS))
return true;
else if (isKnownPredicate(ICmpInst::getInversePredicate(Pred), LHS, RHS))
return false;
return None;
}
bool ScalarEvolution::isKnownPredicateAt(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS,
const Instruction *CtxI) {
// TODO: Analyze guards and assumes from Context's block.
return isKnownPredicate(Pred, LHS, RHS) ||
isBasicBlockEntryGuardedByCond(CtxI->getParent(), Pred, LHS, RHS);
}
Optional<bool> ScalarEvolution::evaluatePredicateAt(ICmpInst::Predicate Pred,
const SCEV *LHS,
const SCEV *RHS,
const Instruction *CtxI) {
Optional<bool> KnownWithoutContext = evaluatePredicate(Pred, LHS, RHS);
if (KnownWithoutContext)
return KnownWithoutContext;
if (isBasicBlockEntryGuardedByCond(CtxI->getParent(), Pred, LHS, RHS))
return true;
else if (isBasicBlockEntryGuardedByCond(CtxI->getParent(),
ICmpInst::getInversePredicate(Pred),
LHS, RHS))
return false;
return None;
}
bool ScalarEvolution::isKnownOnEveryIteration(ICmpInst::Predicate Pred,
const SCEVAddRecExpr *LHS,
const SCEV *RHS) {
const Loop *L = LHS->getLoop();
return isLoopEntryGuardedByCond(L, Pred, LHS->getStart(), RHS) &&
isLoopBackedgeGuardedByCond(L, Pred, LHS->getPostIncExpr(*this), RHS);
}
Optional<ScalarEvolution::MonotonicPredicateType>
ScalarEvolution::getMonotonicPredicateType(const SCEVAddRecExpr *LHS,
ICmpInst::Predicate Pred) {
auto Result = getMonotonicPredicateTypeImpl(LHS, Pred);
#ifndef NDEBUG
// Verify an invariant: inverting the predicate should turn a monotonically
// increasing change to a monotonically decreasing one, and vice versa.
if (Result) {
auto ResultSwapped =
getMonotonicPredicateTypeImpl(LHS, ICmpInst::getSwappedPredicate(Pred));
assert(ResultSwapped && "should be able to analyze both!");
assert(ResultSwapped.value() != Result.value() &&
"monotonicity should flip as we flip the predicate");
}
#endif
return Result;
}
Optional<ScalarEvolution::MonotonicPredicateType>
ScalarEvolution::getMonotonicPredicateTypeImpl(const SCEVAddRecExpr *LHS,
ICmpInst::Predicate Pred) {
// A zero step value for LHS means the induction variable is essentially a
// loop invariant value. We don't really depend on the predicate actually
// flipping from false to true (for increasing predicates, and the other way
// around for decreasing predicates), all we care about is that *if* the
// predicate changes then it only changes from false to true.
//
// A zero step value in itself is not very useful, but there may be places
// where SCEV can prove X >= 0 but not prove X > 0, so it is helpful to be
// as general as possible.
// Only handle LE/LT/GE/GT predicates.
if (!ICmpInst::isRelational(Pred))
return None;
bool IsGreater = ICmpInst::isGE(Pred) || ICmpInst::isGT(Pred);
assert((IsGreater || ICmpInst::isLE(Pred) || ICmpInst::isLT(Pred)) &&
"Should be greater or less!");
// Check that AR does not wrap.
if (ICmpInst::isUnsigned(Pred)) {
if (!LHS->hasNoUnsignedWrap())
return None;
return IsGreater ? MonotonicallyIncreasing : MonotonicallyDecreasing;
} else {
assert(ICmpInst::isSigned(Pred) &&
"Relational predicate is either signed or unsigned!");
if (!LHS->hasNoSignedWrap())
return None;
const SCEV *Step = LHS->getStepRecurrence(*this);
if (isKnownNonNegative(Step))
return IsGreater ? MonotonicallyIncreasing : MonotonicallyDecreasing;
if (isKnownNonPositive(Step))
return !IsGreater ? MonotonicallyIncreasing : MonotonicallyDecreasing;
return None;
}
}
Optional<ScalarEvolution::LoopInvariantPredicate>
ScalarEvolution::getLoopInvariantPredicate(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS,
const Loop *L) {
// If there is a loop-invariant, force it into the RHS, otherwise bail out.
if (!isLoopInvariant(RHS, L)) {
if (!isLoopInvariant(LHS, L))
return None;
std::swap(LHS, RHS);
Pred = ICmpInst::getSwappedPredicate(Pred);
}
const SCEVAddRecExpr *ArLHS = dyn_cast<SCEVAddRecExpr>(LHS);
if (!ArLHS || ArLHS->getLoop() != L)
return None;
auto MonotonicType = getMonotonicPredicateType(ArLHS, Pred);
if (!MonotonicType)
return None;
// If the predicate "ArLHS `Pred` RHS" monotonically increases from false to
// true as the loop iterates, and the backedge is control dependent on
// "ArLHS `Pred` RHS" == true then we can reason as follows:
//
// * if the predicate was false in the first iteration then the predicate
// is never evaluated again, since the loop exits without taking the
// backedge.
// * if the predicate was true in the first iteration then it will
// continue to be true for all future iterations since it is
// monotonically increasing.
//
// For both the above possibilities, we can replace the loop varying
// predicate with its value on the first iteration of the loop (which is
// loop invariant).
//
// A similar reasoning applies for a monotonically decreasing predicate, by
// replacing true with false and false with true in the above two bullets.
bool Increasing = *MonotonicType == ScalarEvolution::MonotonicallyIncreasing;
auto P = Increasing ? Pred : ICmpInst::getInversePredicate(Pred);
if (!isLoopBackedgeGuardedByCond(L, P, LHS, RHS))
return None;
return ScalarEvolution::LoopInvariantPredicate(Pred, ArLHS->getStart(), RHS);
}
Optional<ScalarEvolution::LoopInvariantPredicate>
ScalarEvolution::getLoopInvariantExitCondDuringFirstIterations(
ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS, const Loop *L,
const Instruction *CtxI, const SCEV *MaxIter) {
// Try to prove the following set of facts:
// - The predicate is monotonic in the iteration space.
// - If the check does not fail on the 1st iteration:
// - No overflow will happen during first MaxIter iterations;
// - It will not fail on the MaxIter'th iteration.
// If the check does fail on the 1st iteration, we leave the loop and no
// other checks matter.
// If there is a loop-invariant, force it into the RHS, otherwise bail out.
if (!isLoopInvariant(RHS, L)) {
if (!isLoopInvariant(LHS, L))
return None;
std::swap(LHS, RHS);
Pred = ICmpInst::getSwappedPredicate(Pred);
}
auto *AR = dyn_cast<SCEVAddRecExpr>(LHS);
if (!AR || AR->getLoop() != L)
return None;
// The predicate must be relational (i.e. <, <=, >=, >).
if (!ICmpInst::isRelational(Pred))
return None;
// TODO: Support steps other than +/- 1.
const SCEV *Step = AR->getStepRecurrence(*this);
auto *One = getOne(Step->getType());
auto *MinusOne = getNegativeSCEV(One);
if (Step != One && Step != MinusOne)
return None;
// Type mismatch here means that MaxIter is potentially larger than max
// unsigned value in start type, which mean we cannot prove no wrap for the
// indvar.
if (AR->getType() != MaxIter->getType())
return None;
// Value of IV on suggested last iteration.
const SCEV *Last = AR->evaluateAtIteration(MaxIter, *this);
// Does it still meet the requirement?
if (!isLoopBackedgeGuardedByCond(L, Pred, Last, RHS))
return None;
// Because step is +/- 1 and MaxIter has same type as Start (i.e. it does
// not exceed max unsigned value of this type), this effectively proves
// that there is no wrap during the iteration. To prove that there is no
// signed/unsigned wrap, we need to check that
// Start <= Last for step = 1 or Start >= Last for step = -1.
ICmpInst::Predicate NoOverflowPred =
CmpInst::isSigned(Pred) ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE;
if (Step == MinusOne)
NoOverflowPred = CmpInst::getSwappedPredicate(NoOverflowPred);
const SCEV *Start = AR->getStart();
if (!isKnownPredicateAt(NoOverflowPred, Start, Last, CtxI))
return None;
// Everything is fine.
return ScalarEvolution::LoopInvariantPredicate(Pred, Start, RHS);
}
bool ScalarEvolution::isKnownPredicateViaConstantRanges(
ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS) {
if (HasSameValue(LHS, RHS))
return ICmpInst::isTrueWhenEqual(Pred);
// This code is split out from isKnownPredicate because it is called from
// within isLoopEntryGuardedByCond.
auto CheckRanges = [&](const ConstantRange &RangeLHS,
const ConstantRange &RangeRHS) {
return RangeLHS.icmp(Pred, RangeRHS);
};
// The check at the top of the function catches the case where the values are
// known to be equal.
if (Pred == CmpInst::ICMP_EQ)
return false;
if (Pred == CmpInst::ICMP_NE) {
auto SL = getSignedRange(LHS);
auto SR = getSignedRange(RHS);
if (CheckRanges(SL, SR))
return true;
auto UL = getUnsignedRange(LHS);
auto UR = getUnsignedRange(RHS);
if (CheckRanges(UL, UR))
return true;
auto *Diff = getMinusSCEV(LHS, RHS);
return !isa<SCEVCouldNotCompute>(Diff) && isKnownNonZero(Diff);
}
if (CmpInst::isSigned(Pred)) {
auto SL = getSignedRange(LHS);
auto SR = getSignedRange(RHS);
return CheckRanges(SL, SR);
}
auto UL = getUnsignedRange(LHS);
auto UR = getUnsignedRange(RHS);
return CheckRanges(UL, UR);
}
bool ScalarEvolution::isKnownPredicateViaNoOverflow(ICmpInst::Predicate Pred,
const SCEV *LHS,
const SCEV *RHS) {
// Match X to (A + C1)<ExpectedFlags> and Y to (A + C2)<ExpectedFlags>, where
// C1 and C2 are constant integers. If either X or Y are not add expressions,
// consider them as X + 0 and Y + 0 respectively. C1 and C2 are returned via
// OutC1 and OutC2.
auto MatchBinaryAddToConst = [this](const SCEV *X, const SCEV *Y,
APInt &OutC1, APInt &OutC2,
SCEV::NoWrapFlags ExpectedFlags) {
const SCEV *XNonConstOp, *XConstOp;
const SCEV *YNonConstOp, *YConstOp;
SCEV::NoWrapFlags XFlagsPresent;
SCEV::NoWrapFlags YFlagsPresent;
if (!splitBinaryAdd(X, XConstOp, XNonConstOp, XFlagsPresent)) {
XConstOp = getZero(X->getType());
XNonConstOp = X;
XFlagsPresent = ExpectedFlags;
}
if (!isa<SCEVConstant>(XConstOp) ||
(XFlagsPresent & ExpectedFlags) != ExpectedFlags)
return false;
if (!splitBinaryAdd(Y, YConstOp, YNonConstOp, YFlagsPresent)) {
YConstOp = getZero(Y->getType());
YNonConstOp = Y;
YFlagsPresent = ExpectedFlags;
}
if (!isa<SCEVConstant>(YConstOp) ||
(YFlagsPresent & ExpectedFlags) != ExpectedFlags)
return false;
if (YNonConstOp != XNonConstOp)
return false;
OutC1 = cast<SCEVConstant>(XConstOp)->getAPInt();
OutC2 = cast<SCEVConstant>(YConstOp)->getAPInt();
return true;
};
APInt C1;
APInt C2;
switch (Pred) {
default:
break;
case ICmpInst::ICMP_SGE:
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ICmpInst::ICMP_SLE:
// (X + C1)<nsw> s<= (X + C2)<nsw> if C1 s<= C2.
if (MatchBinaryAddToConst(LHS, RHS, C1, C2, SCEV::FlagNSW) && C1.sle(C2))
return true;
break;
case ICmpInst::ICMP_SGT:
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ICmpInst::ICMP_SLT:
// (X + C1)<nsw> s< (X + C2)<nsw> if C1 s< C2.
if (MatchBinaryAddToConst(LHS, RHS, C1, C2, SCEV::FlagNSW) && C1.slt(C2))
return true;
break;
case ICmpInst::ICMP_UGE:
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ICmpInst::ICMP_ULE:
// (X + C1)<nuw> u<= (X + C2)<nuw> for C1 u<= C2.
if (MatchBinaryAddToConst(RHS, LHS, C2, C1, SCEV::FlagNUW) && C1.ule(C2))
return true;
break;
case ICmpInst::ICMP_UGT:
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ICmpInst::ICMP_ULT:
// (X + C1)<nuw> u< (X + C2)<nuw> if C1 u< C2.
if (MatchBinaryAddToConst(RHS, LHS, C2, C1, SCEV::FlagNUW) && C1.ult(C2))
return true;
break;
}
return false;
}
bool ScalarEvolution::isKnownPredicateViaSplitting(ICmpInst::Predicate Pred,
const SCEV *LHS,
const SCEV *RHS) {
if (Pred != ICmpInst::ICMP_ULT || ProvingSplitPredicate)
return false;
// Allowing arbitrary number of activations of isKnownPredicateViaSplitting on
// the stack can result in exponential time complexity.
SaveAndRestore<bool> Restore(ProvingSplitPredicate, true);
// If L >= 0 then I `ult` L <=> I >= 0 && I `slt` L
//
// To prove L >= 0 we use isKnownNonNegative whereas to prove I >= 0 we use
// isKnownPredicate. isKnownPredicate is more powerful, but also more
// expensive; and using isKnownNonNegative(RHS) is sufficient for most of the
// interesting cases seen in practice. We can consider "upgrading" L >= 0 to
// use isKnownPredicate later if needed.
return isKnownNonNegative(RHS) &&
isKnownPredicate(CmpInst::ICMP_SGE, LHS, getZero(LHS->getType())) &&
isKnownPredicate(CmpInst::ICMP_SLT, LHS, RHS);
}
bool ScalarEvolution::isImpliedViaGuard(const BasicBlock *BB,
ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS) {
// No need to even try if we know the module has no guards.
if (!HasGuards)
return false;
return any_of(*BB, [&](const Instruction &I) {
using namespace llvm::PatternMatch;
Value *Condition;
return match(&I, m_Intrinsic<Intrinsic::experimental_guard>(
m_Value(Condition))) &&
isImpliedCond(Pred, LHS, RHS, Condition, false);
});
}
/// isLoopBackedgeGuardedByCond - Test whether the backedge of the loop is
/// protected by a conditional between LHS and RHS. This is used to
/// to eliminate casts.
bool
ScalarEvolution::isLoopBackedgeGuardedByCond(const Loop *L,
ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS) {
// Interpret a null as meaning no loop, where there is obviously no guard
// (interprocedural conditions notwithstanding). Do not bother about
// unreachable loops.
if (!L || !DT.isReachableFromEntry(L->getHeader()))
return true;
if (VerifyIR)
assert(!verifyFunction(*L->getHeader()->getParent(), &dbgs()) &&
"This cannot be done on broken IR!");
if (isKnownViaNonRecursiveReasoning(Pred, LHS, RHS))
return true;
BasicBlock *Latch = L->getLoopLatch();
if (!Latch)
return false;
BranchInst *LoopContinuePredicate =
dyn_cast<BranchInst>(Latch->getTerminator());
if (LoopContinuePredicate && LoopContinuePredicate->isConditional() &&
isImpliedCond(Pred, LHS, RHS,
LoopContinuePredicate->getCondition(),
LoopContinuePredicate->getSuccessor(0) != L->getHeader()))
return true;
// We don't want more than one activation of the following loops on the stack
// -- that can lead to O(n!) time complexity.
if (WalkingBEDominatingConds)
return false;
SaveAndRestore<bool> ClearOnExit(WalkingBEDominatingConds, true);
// See if we can exploit a trip count to prove the predicate.
const auto &BETakenInfo = getBackedgeTakenInfo(L);
const SCEV *LatchBECount = BETakenInfo.getExact(Latch, this);
if (LatchBECount != getCouldNotCompute()) {
// We know that Latch branches back to the loop header exactly
// LatchBECount times. This means the backdege condition at Latch is
// equivalent to "{0,+,1} u< LatchBECount".
Type *Ty = LatchBECount->getType();
auto NoWrapFlags = SCEV::NoWrapFlags(SCEV::FlagNUW | SCEV::FlagNW);
const SCEV *LoopCounter =
getAddRecExpr(getZero(Ty), getOne(Ty), L, NoWrapFlags);
if (isImpliedCond(Pred, LHS, RHS, ICmpInst::ICMP_ULT, LoopCounter,
LatchBECount))
return true;
}
// Check conditions due to any @llvm.assume intrinsics.
for (auto &AssumeVH : AC.assumptions()) {
if (!AssumeVH)
continue;
auto *CI = cast<CallInst>(AssumeVH);
if (!DT.dominates(CI, Latch->getTerminator()))
continue;
if (isImpliedCond(Pred, LHS, RHS, CI->getArgOperand(0), false))
return true;
}
if (isImpliedViaGuard(Latch, Pred, LHS, RHS))
return true;
for (DomTreeNode *DTN = DT[Latch], *HeaderDTN = DT[L->getHeader()];
DTN != HeaderDTN; DTN = DTN->getIDom()) {
assert(DTN && "should reach the loop header before reaching the root!");
BasicBlock *BB = DTN->getBlock();
if (isImpliedViaGuard(BB, Pred, LHS, RHS))
return true;
BasicBlock *PBB = BB->getSinglePredecessor();
if (!PBB)
continue;
BranchInst *ContinuePredicate = dyn_cast<BranchInst>(PBB->getTerminator());
if (!ContinuePredicate || !ContinuePredicate->isConditional())
continue;
Value *Condition = ContinuePredicate->getCondition();
// If we have an edge `E` within the loop body that dominates the only
// latch, the condition guarding `E` also guards the backedge. This
// reasoning works only for loops with a single latch.
BasicBlockEdge DominatingEdge(PBB, BB);
if (DominatingEdge.isSingleEdge()) {
// We're constructively (and conservatively) enumerating edges within the
// loop body that dominate the latch. The dominator tree better agree
// with us on this:
assert(DT.dominates(DominatingEdge, Latch) && "should be!");
if (isImpliedCond(Pred, LHS, RHS, Condition,
BB != ContinuePredicate->getSuccessor(0)))
return true;
}
}
return false;
}
bool ScalarEvolution::isBasicBlockEntryGuardedByCond(const BasicBlock *BB,
ICmpInst::Predicate Pred,
const SCEV *LHS,
const SCEV *RHS) {
// Do not bother proving facts for unreachable code.
if (!DT.isReachableFromEntry(BB))
return true;
if (VerifyIR)
assert(!verifyFunction(*BB->getParent(), &dbgs()) &&
"This cannot be done on broken IR!");
// If we cannot prove strict comparison (e.g. a > b), maybe we can prove
// the facts (a >= b && a != b) separately. A typical situation is when the
// non-strict comparison is known from ranges and non-equality is known from
// dominating predicates. If we are proving strict comparison, we always try
// to prove non-equality and non-strict comparison separately.
auto NonStrictPredicate = ICmpInst::getNonStrictPredicate(Pred);
const bool ProvingStrictComparison = (Pred != NonStrictPredicate);
bool ProvedNonStrictComparison = false;
bool ProvedNonEquality = false;
auto SplitAndProve =
[&](std::function<bool(ICmpInst::Predicate)> Fn) -> bool {
if (!ProvedNonStrictComparison)
ProvedNonStrictComparison = Fn(NonStrictPredicate);
if (!ProvedNonEquality)
ProvedNonEquality = Fn(ICmpInst::ICMP_NE);
if (ProvedNonStrictComparison && ProvedNonEquality)
return true;
return false;
};
if (ProvingStrictComparison) {
auto ProofFn = [&](ICmpInst::Predicate P) {
return isKnownViaNonRecursiveReasoning(P, LHS, RHS);
};
if (SplitAndProve(ProofFn))
return true;
}
// Try to prove (Pred, LHS, RHS) using isImpliedCond.
auto ProveViaCond = [&](const Value *Condition, bool Inverse) {
const Instruction *CtxI = &BB->front();
if (isImpliedCond(Pred, LHS, RHS, Condition, Inverse, CtxI))
return true;
if (ProvingStrictComparison) {
auto ProofFn = [&](ICmpInst::Predicate P) {
return isImpliedCond(P, LHS, RHS, Condition, Inverse, CtxI);
};
if (SplitAndProve(ProofFn))
return true;
}
return false;
};
// Starting at the block's predecessor, climb up the predecessor chain, as long
// as there are predecessors that can be found that have unique successors
// leading to the original block.
const Loop *ContainingLoop = LI.getLoopFor(BB);
const BasicBlock *PredBB;
if (ContainingLoop && ContainingLoop->getHeader() == BB)
PredBB = ContainingLoop->getLoopPredecessor();
else
PredBB = BB->getSinglePredecessor();
for (std::pair<const BasicBlock *, const BasicBlock *> Pair(PredBB, BB);
Pair.first; Pair = getPredecessorWithUniqueSuccessorForBB(Pair.first)) {
const BranchInst *BlockEntryPredicate =
dyn_cast<BranchInst>(Pair.first->getTerminator());
if (!BlockEntryPredicate || BlockEntryPredicate->isUnconditional())
continue;
if (ProveViaCond(BlockEntryPredicate->getCondition(),
BlockEntryPredicate->getSuccessor(0) != Pair.second))
return true;
}
// Check conditions due to any @llvm.assume intrinsics.
for (auto &AssumeVH : AC.assumptions()) {
if (!AssumeVH)
continue;
auto *CI = cast<CallInst>(AssumeVH);
if (!DT.dominates(CI, BB))
continue;
if (ProveViaCond(CI->getArgOperand(0), false))
return true;
}
// Check conditions due to any @llvm.experimental.guard intrinsics.
auto *GuardDecl = F.getParent()->getFunction(
Intrinsic::getName(Intrinsic::experimental_guard));
if (GuardDecl)
for (const auto *GU : GuardDecl->users())
if (const auto *Guard = dyn_cast<IntrinsicInst>(GU))
if (Guard->getFunction() == BB->getParent() && DT.dominates(Guard, BB))
if (ProveViaCond(Guard->getArgOperand(0), false))
return true;
return false;
}
bool ScalarEvolution::isLoopEntryGuardedByCond(const Loop *L,
ICmpInst::Predicate Pred,
const SCEV *LHS,
const SCEV *RHS) {
// Interpret a null as meaning no loop, where there is obviously no guard
// (interprocedural conditions notwithstanding).
if (!L)
return false;
// Both LHS and RHS must be available at loop entry.
assert(isAvailableAtLoopEntry(LHS, L) &&
"LHS is not available at Loop Entry");
assert(isAvailableAtLoopEntry(RHS, L) &&
"RHS is not available at Loop Entry");
if (isKnownViaNonRecursiveReasoning(Pred, LHS, RHS))
return true;
return isBasicBlockEntryGuardedByCond(L->getHeader(), Pred, LHS, RHS);
}
bool ScalarEvolution::isImpliedCond(ICmpInst::Predicate Pred, const SCEV *LHS,
const SCEV *RHS,
const Value *FoundCondValue, bool Inverse,
const Instruction *CtxI) {
// False conditions implies anything. Do not bother analyzing it further.
if (FoundCondValue ==
ConstantInt::getBool(FoundCondValue->getContext(), Inverse))
return true;
if (!PendingLoopPredicates.insert(FoundCondValue).second)
return false;
auto ClearOnExit =
make_scope_exit([&]() { PendingLoopPredicates.erase(FoundCondValue); });
// Recursively handle And and Or conditions.
const Value *Op0, *Op1;
if (match(FoundCondValue, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) {
if (!Inverse)
return isImpliedCond(Pred, LHS, RHS, Op0, Inverse, CtxI) ||
isImpliedCond(Pred, LHS, RHS, Op1, Inverse, CtxI);
} else if (match(FoundCondValue, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) {
if (Inverse)
return isImpliedCond(Pred, LHS, RHS, Op0, Inverse, CtxI) ||
isImpliedCond(Pred, LHS, RHS, Op1, Inverse, CtxI);
}
const ICmpInst *ICI = dyn_cast<ICmpInst>(FoundCondValue);
if (!ICI) return false;
// Now that we found a conditional branch that dominates the loop or controls
// the loop latch. Check to see if it is the comparison we are looking for.
ICmpInst::Predicate FoundPred;
if (Inverse)
FoundPred = ICI->getInversePredicate();
else
FoundPred = ICI->getPredicate();
const SCEV *FoundLHS = getSCEV(ICI->getOperand(0));
const SCEV *FoundRHS = getSCEV(ICI->getOperand(1));
return isImpliedCond(Pred, LHS, RHS, FoundPred, FoundLHS, FoundRHS, CtxI);
}
bool ScalarEvolution::isImpliedCond(ICmpInst::Predicate Pred, const SCEV *LHS,
const SCEV *RHS,
ICmpInst::Predicate FoundPred,
const SCEV *FoundLHS, const SCEV *FoundRHS,
const Instruction *CtxI) {
// Balance the types.
if (getTypeSizeInBits(LHS->getType()) <
getTypeSizeInBits(FoundLHS->getType())) {
// For unsigned and equality predicates, try to prove that both found
// operands fit into narrow unsigned range. If so, try to prove facts in
// narrow types.
if (!CmpInst::isSigned(FoundPred) && !FoundLHS->getType()->isPointerTy() &&
!FoundRHS->getType()->isPointerTy()) {
auto *NarrowType = LHS->getType();
auto *WideType = FoundLHS->getType();
auto BitWidth = getTypeSizeInBits(NarrowType);
const SCEV *MaxValue = getZeroExtendExpr(
getConstant(APInt::getMaxValue(BitWidth)), WideType);
if (isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_ULE, FoundLHS,
MaxValue) &&
isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_ULE, FoundRHS,
MaxValue)) {
const SCEV *TruncFoundLHS = getTruncateExpr(FoundLHS, NarrowType);
const SCEV *TruncFoundRHS = getTruncateExpr(FoundRHS, NarrowType);
if (isImpliedCondBalancedTypes(Pred, LHS, RHS, FoundPred, TruncFoundLHS,
TruncFoundRHS, CtxI))
return true;
}
}
if (LHS->getType()->isPointerTy() || RHS->getType()->isPointerTy())
return false;
if (CmpInst::isSigned(Pred)) {
LHS = getSignExtendExpr(LHS, FoundLHS->getType());
RHS = getSignExtendExpr(RHS, FoundLHS->getType());
} else {
LHS = getZeroExtendExpr(LHS, FoundLHS->getType());
RHS = getZeroExtendExpr(RHS, FoundLHS->getType());
}
} else if (getTypeSizeInBits(LHS->getType()) >
getTypeSizeInBits(FoundLHS->getType())) {
if (FoundLHS->getType()->isPointerTy() || FoundRHS->getType()->isPointerTy())
return false;
if (CmpInst::isSigned(FoundPred)) {
FoundLHS = getSignExtendExpr(FoundLHS, LHS->getType());
FoundRHS = getSignExtendExpr(FoundRHS, LHS->getType());
} else {
FoundLHS = getZeroExtendExpr(FoundLHS, LHS->getType());
FoundRHS = getZeroExtendExpr(FoundRHS, LHS->getType());
}
}
return isImpliedCondBalancedTypes(Pred, LHS, RHS, FoundPred, FoundLHS,
FoundRHS, CtxI);
}
bool ScalarEvolution::isImpliedCondBalancedTypes(
ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS,
ICmpInst::Predicate FoundPred, const SCEV *FoundLHS, const SCEV *FoundRHS,
const Instruction *CtxI) {
assert(getTypeSizeInBits(LHS->getType()) ==
getTypeSizeInBits(FoundLHS->getType()) &&
"Types should be balanced!");
// Canonicalize the query to match the way instcombine will have
// canonicalized the comparison.
if (SimplifyICmpOperands(Pred, LHS, RHS))
if (LHS == RHS)
return CmpInst::isTrueWhenEqual(Pred);
if (SimplifyICmpOperands(FoundPred, FoundLHS, FoundRHS))
if (FoundLHS == FoundRHS)
return CmpInst::isFalseWhenEqual(FoundPred);
// Check to see if we can make the LHS or RHS match.
if (LHS == FoundRHS || RHS == FoundLHS) {
if (isa<SCEVConstant>(RHS)) {
std::swap(FoundLHS, FoundRHS);
FoundPred = ICmpInst::getSwappedPredicate(FoundPred);
} else {
std::swap(LHS, RHS);
Pred = ICmpInst::getSwappedPredicate(Pred);
}
}
// Check whether the found predicate is the same as the desired predicate.
if (FoundPred == Pred)
return isImpliedCondOperands(Pred, LHS, RHS, FoundLHS, FoundRHS, CtxI);
// Check whether swapping the found predicate makes it the same as the
// desired predicate.
if (ICmpInst::getSwappedPredicate(FoundPred) == Pred) {
// We can write the implication
// 0. LHS Pred RHS <- FoundLHS SwapPred FoundRHS
// using one of the following ways:
// 1. LHS Pred RHS <- FoundRHS Pred FoundLHS
// 2. RHS SwapPred LHS <- FoundLHS SwapPred FoundRHS
// 3. LHS Pred RHS <- ~FoundLHS Pred ~FoundRHS
// 4. ~LHS SwapPred ~RHS <- FoundLHS SwapPred FoundRHS
// Forms 1. and 2. require swapping the operands of one condition. Don't
// do this if it would break canonical constant/addrec ordering.
if (!isa<SCEVConstant>(RHS) && !isa<SCEVAddRecExpr>(LHS))
return isImpliedCondOperands(FoundPred, RHS, LHS, FoundLHS, FoundRHS,
CtxI);
if (!isa<SCEVConstant>(FoundRHS) && !isa<SCEVAddRecExpr>(FoundLHS))
return isImpliedCondOperands(Pred, LHS, RHS, FoundRHS, FoundLHS, CtxI);
// There's no clear preference between forms 3. and 4., try both. Avoid
// forming getNotSCEV of pointer values as the resulting subtract is
// not legal.
if (!LHS->getType()->isPointerTy() && !RHS->getType()->isPointerTy() &&
isImpliedCondOperands(FoundPred, getNotSCEV(LHS), getNotSCEV(RHS),
FoundLHS, FoundRHS, CtxI))
return true;
if (!FoundLHS->getType()->isPointerTy() &&
!FoundRHS->getType()->isPointerTy() &&
isImpliedCondOperands(Pred, LHS, RHS, getNotSCEV(FoundLHS),
getNotSCEV(FoundRHS), CtxI))
return true;
return false;
}
auto IsSignFlippedPredicate = [](CmpInst::Predicate P1,
CmpInst::Predicate P2) {
assert(P1 != P2 && "Handled earlier!");
return CmpInst::isRelational(P2) &&
P1 == CmpInst::getFlippedSignednessPredicate(P2);
};
if (IsSignFlippedPredicate(Pred, FoundPred)) {
// Unsigned comparison is the same as signed comparison when both the
// operands are non-negative or negative.
if ((isKnownNonNegative(FoundLHS) && isKnownNonNegative(FoundRHS)) ||
(isKnownNegative(FoundLHS) && isKnownNegative(FoundRHS)))
return isImpliedCondOperands(Pred, LHS, RHS, FoundLHS, FoundRHS, CtxI);
// Create local copies that we can freely swap and canonicalize our
// conditions to "le/lt".
ICmpInst::Predicate CanonicalPred = Pred, CanonicalFoundPred = FoundPred;
const SCEV *CanonicalLHS = LHS, *CanonicalRHS = RHS,
*CanonicalFoundLHS = FoundLHS, *CanonicalFoundRHS = FoundRHS;
if (ICmpInst::isGT(CanonicalPred) || ICmpInst::isGE(CanonicalPred)) {
CanonicalPred = ICmpInst::getSwappedPredicate(CanonicalPred);
CanonicalFoundPred = ICmpInst::getSwappedPredicate(CanonicalFoundPred);
std::swap(CanonicalLHS, CanonicalRHS);
std::swap(CanonicalFoundLHS, CanonicalFoundRHS);
}
assert((ICmpInst::isLT(CanonicalPred) || ICmpInst::isLE(CanonicalPred)) &&
"Must be!");
assert((ICmpInst::isLT(CanonicalFoundPred) ||
ICmpInst::isLE(CanonicalFoundPred)) &&
"Must be!");
if (ICmpInst::isSigned(CanonicalPred) && isKnownNonNegative(CanonicalRHS))
// Use implication:
// x <u y && y >=s 0 --> x <s y.
// If we can prove the left part, the right part is also proven.
return isImpliedCondOperands(CanonicalFoundPred, CanonicalLHS,
CanonicalRHS, CanonicalFoundLHS,
CanonicalFoundRHS);
if (ICmpInst::isUnsigned(CanonicalPred) && isKnownNegative(CanonicalRHS))
// Use implication:
// x <s y && y <s 0 --> x <u y.
// If we can prove the left part, the right part is also proven.
return isImpliedCondOperands(CanonicalFoundPred, CanonicalLHS,
CanonicalRHS, CanonicalFoundLHS,
CanonicalFoundRHS);
}
// Check if we can make progress by sharpening ranges.
if (FoundPred == ICmpInst::ICMP_NE &&
(isa<SCEVConstant>(FoundLHS) || isa<SCEVConstant>(FoundRHS))) {
const SCEVConstant *C = nullptr;
const SCEV *V = nullptr;
if (isa<SCEVConstant>(FoundLHS)) {
C = cast<SCEVConstant>(FoundLHS);
V = FoundRHS;
} else {
C = cast<SCEVConstant>(FoundRHS);
V = FoundLHS;
}
// The guarding predicate tells us that C != V. If the known range
// of V is [C, t), we can sharpen the range to [C + 1, t). The
// range we consider has to correspond to same signedness as the
// predicate we're interested in folding.
APInt Min = ICmpInst::isSigned(Pred) ?
getSignedRangeMin(V) : getUnsignedRangeMin(V);
if (Min == C->getAPInt()) {
// Given (V >= Min && V != Min) we conclude V >= (Min + 1).
// This is true even if (Min + 1) wraps around -- in case of
// wraparound, (Min + 1) < Min, so (V >= Min => V >= (Min + 1)).
APInt SharperMin = Min + 1;
switch (Pred) {
case ICmpInst::ICMP_SGE:
case ICmpInst::ICMP_UGE:
// We know V `Pred` SharperMin. If this implies LHS `Pred`
// RHS, we're done.
if (isImpliedCondOperands(Pred, LHS, RHS, V, getConstant(SharperMin),
CtxI))
return true;
LLVM_FALLTHROUGH;
case ICmpInst::ICMP_SGT:
case ICmpInst::ICMP_UGT:
// We know from the range information that (V `Pred` Min ||
// V == Min). We know from the guarding condition that !(V
// == Min). This gives us
//
// V `Pred` Min || V == Min && !(V == Min)
// => V `Pred` Min
//
// If V `Pred` Min implies LHS `Pred` RHS, we're done.
if (isImpliedCondOperands(Pred, LHS, RHS, V, getConstant(Min), CtxI))
return true;
break;
// `LHS < RHS` and `LHS <= RHS` are handled in the same way as `RHS > LHS` and `RHS >= LHS` respectively.
case ICmpInst::ICMP_SLE:
case ICmpInst::ICMP_ULE:
if (isImpliedCondOperands(CmpInst::getSwappedPredicate(Pred), RHS,
LHS, V, getConstant(SharperMin), CtxI))
return true;
LLVM_FALLTHROUGH;
case ICmpInst::ICMP_SLT:
case ICmpInst::ICMP_ULT:
if (isImpliedCondOperands(CmpInst::getSwappedPredicate(Pred), RHS,
LHS, V, getConstant(Min), CtxI))
return true;
break;
default:
// No change
break;
}
}
}
// Check whether the actual condition is beyond sufficient.
if (FoundPred == ICmpInst::ICMP_EQ)
if (ICmpInst::isTrueWhenEqual(Pred))
if (isImpliedCondOperands(Pred, LHS, RHS, FoundLHS, FoundRHS, CtxI))
return true;
if (Pred == ICmpInst::ICMP_NE)
if (!ICmpInst::isTrueWhenEqual(FoundPred))
if (isImpliedCondOperands(FoundPred, LHS, RHS, FoundLHS, FoundRHS, CtxI))
return true;
// Otherwise assume the worst.
return false;
}
bool ScalarEvolution::splitBinaryAdd(const SCEV *Expr,
const SCEV *&L, const SCEV *&R,
SCEV::NoWrapFlags &Flags) {
const auto *AE = dyn_cast<SCEVAddExpr>(Expr);
if (!AE || AE->getNumOperands() != 2)
return false;
L = AE->getOperand(0);
R = AE->getOperand(1);
Flags = AE->getNoWrapFlags();
return true;
}
Optional<APInt> ScalarEvolution::computeConstantDifference(const SCEV *More,
const SCEV *Less) {
// We avoid subtracting expressions here because this function is usually
// fairly deep in the call stack (i.e. is called many times).
// X - X = 0.
if (More == Less)
return APInt(getTypeSizeInBits(More->getType()), 0);
if (isa<SCEVAddRecExpr>(Less) && isa<SCEVAddRecExpr>(More)) {
const auto *LAR = cast<SCEVAddRecExpr>(Less);
const auto *MAR = cast<SCEVAddRecExpr>(More);
if (LAR->getLoop() != MAR->getLoop())
return None;
// We look at affine expressions only; not for correctness but to keep
// getStepRecurrence cheap.
if (!LAR->isAffine() || !MAR->isAffine())
return None;
if (LAR->getStepRecurrence(*this) != MAR->getStepRecurrence(*this))
return None;
Less = LAR->getStart();
More = MAR->getStart();
// fall through
}
if (isa<SCEVConstant>(Less) && isa<SCEVConstant>(More)) {
const auto &M = cast<SCEVConstant>(More)->getAPInt();
const auto &L = cast<SCEVConstant>(Less)->getAPInt();
return M - L;
}
SCEV::NoWrapFlags Flags;
const SCEV *LLess = nullptr, *RLess = nullptr;
const SCEV *LMore = nullptr, *RMore = nullptr;
const SCEVConstant *C1 = nullptr, *C2 = nullptr;
// Compare (X + C1) vs X.
if (splitBinaryAdd(Less, LLess, RLess, Flags))
if ((C1 = dyn_cast<SCEVConstant>(LLess)))
if (RLess == More)
return -(C1->getAPInt());
// Compare X vs (X + C2).
if (splitBinaryAdd(More, LMore, RMore, Flags))
if ((C2 = dyn_cast<SCEVConstant>(LMore)))
if (RMore == Less)
return C2->getAPInt();
// Compare (X + C1) vs (X + C2).
if (C1 && C2 && RLess == RMore)
return C2->getAPInt() - C1->getAPInt();
return None;
}
bool ScalarEvolution::isImpliedCondOperandsViaAddRecStart(
ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS,
const SCEV *FoundLHS, const SCEV *FoundRHS, const Instruction *CtxI) {
// Try to recognize the following pattern:
//
// FoundRHS = ...
// ...
// loop:
// FoundLHS = {Start,+,W}
// context_bb: // Basic block from the same loop
// known(Pred, FoundLHS, FoundRHS)
//
// If some predicate is known in the context of a loop, it is also known on
// each iteration of this loop, including the first iteration. Therefore, in
// this case, `FoundLHS Pred FoundRHS` implies `Start Pred FoundRHS`. Try to
// prove the original pred using this fact.
if (!CtxI)
return false;
const BasicBlock *ContextBB = CtxI->getParent();
// Make sure AR varies in the context block.
if (auto *AR = dyn_cast<SCEVAddRecExpr>(FoundLHS)) {
const Loop *L = AR->getLoop();
// Make sure that context belongs to the loop and executes on 1st iteration
// (if it ever executes at all).
if (!L->contains(ContextBB) || !DT.dominates(ContextBB, L->getLoopLatch()))
return false;
if (!isAvailableAtLoopEntry(FoundRHS, AR->getLoop()))
return false;
return isImpliedCondOperands(Pred, LHS, RHS, AR->getStart(), FoundRHS);
}
if (auto *AR = dyn_cast<SCEVAddRecExpr>(FoundRHS)) {
const Loop *L = AR->getLoop();
// Make sure that context belongs to the loop and executes on 1st iteration
// (if it ever executes at all).
if (!L->contains(ContextBB) || !DT.dominates(ContextBB, L->getLoopLatch()))
return false;
if (!isAvailableAtLoopEntry(FoundLHS, AR->getLoop()))
return false;
return isImpliedCondOperands(Pred, LHS, RHS, FoundLHS, AR->getStart());
}
return false;
}
bool ScalarEvolution::isImpliedCondOperandsViaNoOverflow(
ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS,
const SCEV *FoundLHS, const SCEV *FoundRHS) {
if (Pred != CmpInst::ICMP_SLT && Pred != CmpInst::ICMP_ULT)
return false;
const auto *AddRecLHS = dyn_cast<SCEVAddRecExpr>(LHS);
if (!AddRecLHS)
return false;
const auto *AddRecFoundLHS = dyn_cast<SCEVAddRecExpr>(FoundLHS);
if (!AddRecFoundLHS)
return false;
// We'd like to let SCEV reason about control dependencies, so we constrain
// both the inequalities to be about add recurrences on the same loop. This
// way we can use isLoopEntryGuardedByCond later.
const Loop *L = AddRecFoundLHS->getLoop();
if (L != AddRecLHS->getLoop())
return false;
// FoundLHS u< FoundRHS u< -C => (FoundLHS + C) u< (FoundRHS + C) ... (1)
//
// FoundLHS s< FoundRHS s< INT_MIN - C => (FoundLHS + C) s< (FoundRHS + C)
// ... (2)
//
// Informal proof for (2), assuming (1) [*]:
//
// We'll also assume (A s< B) <=> ((A + INT_MIN) u< (B + INT_MIN)) ... (3)[**]
//
// Then
//
// FoundLHS s< FoundRHS s< INT_MIN - C
// <=> (FoundLHS + INT_MIN) u< (FoundRHS + INT_MIN) u< -C [ using (3) ]
// <=> (FoundLHS + INT_MIN + C) u< (FoundRHS + INT_MIN + C) [ using (1) ]
// <=> (FoundLHS + INT_MIN + C + INT_MIN) s<
// (FoundRHS + INT_MIN + C + INT_MIN) [ using (3) ]
// <=> FoundLHS + C s< FoundRHS + C
//
// [*]: (1) can be proved by ruling out overflow.
//
// [**]: This can be proved by analyzing all the four possibilities:
// (A s< 0, B s< 0), (A s< 0, B s>= 0), (A s>= 0, B s< 0) and
// (A s>= 0, B s>= 0).
//
// Note:
// Despite (2), "FoundRHS s< INT_MIN - C" does not mean that "FoundRHS + C"
// will not sign underflow. For instance, say FoundLHS = (i8 -128), FoundRHS
// = (i8 -127) and C = (i8 -100). Then INT_MIN - C = (i8 -28), and FoundRHS
// s< (INT_MIN - C). Lack of sign overflow / underflow in "FoundRHS + C" is
// neither necessary nor sufficient to prove "(FoundLHS + C) s< (FoundRHS +
// C)".
Optional<APInt> LDiff = computeConstantDifference(LHS, FoundLHS);
Optional<APInt> RDiff = computeConstantDifference(RHS, FoundRHS);
if (!LDiff || !RDiff || *LDiff != *RDiff)
return false;
if (LDiff->isMinValue())
return true;
APInt FoundRHSLimit;
if (Pred == CmpInst::ICMP_ULT) {
FoundRHSLimit = -(*RDiff);
} else {
assert(Pred == CmpInst::ICMP_SLT && "Checked above!");
FoundRHSLimit = APInt::getSignedMinValue(getTypeSizeInBits(RHS->getType())) - *RDiff;
}
// Try to prove (1) or (2), as needed.
return isAvailableAtLoopEntry(FoundRHS, L) &&
isLoopEntryGuardedByCond(L, Pred, FoundRHS,
getConstant(FoundRHSLimit));
}
bool ScalarEvolution::isImpliedViaMerge(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS,
const SCEV *FoundLHS,
const SCEV *FoundRHS, unsigned Depth) {
const PHINode *LPhi = nullptr, *RPhi = nullptr;
auto ClearOnExit = make_scope_exit([&]() {
if (LPhi) {
bool Erased = PendingMerges.erase(LPhi);
assert(Erased && "Failed to erase LPhi!");
(void)Erased;
}
if (RPhi) {
bool Erased = PendingMerges.erase(RPhi);
assert(Erased && "Failed to erase RPhi!");
(void)Erased;
}
});
// Find respective Phis and check that they are not being pending.
if (const SCEVUnknown *LU = dyn_cast<SCEVUnknown>(LHS))
if (auto *Phi = dyn_cast<PHINode>(LU->getValue())) {
if (!PendingMerges.insert(Phi).second)
return false;
LPhi = Phi;
}
if (const SCEVUnknown *RU = dyn_cast<SCEVUnknown>(RHS))
if (auto *Phi = dyn_cast<PHINode>(RU->getValue())) {
// If we detect a loop of Phi nodes being processed by this method, for
// example:
//
// %a = phi i32 [ %some1, %preheader ], [ %b, %latch ]
// %b = phi i32 [ %some2, %preheader ], [ %a, %latch ]
//
// we don't want to deal with a case that complex, so return conservative
// answer false.
if (!PendingMerges.insert(Phi).second)
return false;
RPhi = Phi;
}
// If none of LHS, RHS is a Phi, nothing to do here.
if (!LPhi && !RPhi)
return false;
// If there is a SCEVUnknown Phi we are interested in, make it left.
if (!LPhi) {
std::swap(LHS, RHS);
std::swap(FoundLHS, FoundRHS);
std::swap(LPhi, RPhi);
Pred = ICmpInst::getSwappedPredicate(Pred);
}
assert(LPhi && "LPhi should definitely be a SCEVUnknown Phi!");
const BasicBlock *LBB = LPhi->getParent();
const SCEVAddRecExpr *RAR = dyn_cast<SCEVAddRecExpr>(RHS);
auto ProvedEasily = [&](const SCEV *S1, const SCEV *S2) {
return isKnownViaNonRecursiveReasoning(Pred, S1, S2) ||
isImpliedCondOperandsViaRanges(Pred, S1, S2, FoundLHS, FoundRHS) ||
isImpliedViaOperations(Pred, S1, S2, FoundLHS, FoundRHS, Depth);
};
if (RPhi && RPhi->getParent() == LBB) {
// Case one: RHS is also a SCEVUnknown Phi from the same basic block.
// If we compare two Phis from the same block, and for each entry block
// the predicate is true for incoming values from this block, then the
// predicate is also true for the Phis.
for (const BasicBlock *IncBB : predecessors(LBB)) {
const SCEV *L = getSCEV(LPhi->getIncomingValueForBlock(IncBB));
const SCEV *R = getSCEV(RPhi->getIncomingValueForBlock(IncBB));
if (!ProvedEasily(L, R))
return false;
}
} else if (RAR && RAR->getLoop()->getHeader() == LBB) {
// Case two: RHS is also a Phi from the same basic block, and it is an
// AddRec. It means that there is a loop which has both AddRec and Unknown
// PHIs, for it we can compare incoming values of AddRec from above the loop
// and latch with their respective incoming values of LPhi.
// TODO: Generalize to handle loops with many inputs in a header.
if (LPhi->getNumIncomingValues() != 2) return false;
auto *RLoop = RAR->getLoop();
auto *Predecessor = RLoop->getLoopPredecessor();
assert(Predecessor && "Loop with AddRec with no predecessor?");
const SCEV *L1 = getSCEV(LPhi->getIncomingValueForBlock(Predecessor));
if (!ProvedEasily(L1, RAR->getStart()))
return false;
auto *Latch = RLoop->getLoopLatch();
assert(Latch && "Loop with AddRec with no latch?");
const SCEV *L2 = getSCEV(LPhi->getIncomingValueForBlock(Latch));
if (!ProvedEasily(L2, RAR->getPostIncExpr(*this)))
return false;
} else {
// In all other cases go over inputs of LHS and compare each of them to RHS,
// the predicate is true for (LHS, RHS) if it is true for all such pairs.
// At this point RHS is either a non-Phi, or it is a Phi from some block
// different from LBB.
for (const BasicBlock *IncBB : predecessors(LBB)) {
// Check that RHS is available in this block.
if (!dominates(RHS, IncBB))
return false;
const SCEV *L = getSCEV(LPhi->getIncomingValueForBlock(IncBB));
// Make sure L does not refer to a value from a potentially previous
// iteration of a loop.
if (!properlyDominates(L, LBB))
return false;
if (!ProvedEasily(L, RHS))
return false;
}
}
return true;
}
bool ScalarEvolution::isImpliedCondOperandsViaShift(ICmpInst::Predicate Pred,
const SCEV *LHS,
const SCEV *RHS,
const SCEV *FoundLHS,
const SCEV *FoundRHS) {
// We want to imply LHS < RHS from LHS < (RHS >> shiftvalue). First, make
// sure that we are dealing with same LHS.
if (RHS == FoundRHS) {
std::swap(LHS, RHS);
std::swap(FoundLHS, FoundRHS);
Pred = ICmpInst::getSwappedPredicate(Pred);
}
if (LHS != FoundLHS)
return false;
auto *SUFoundRHS = dyn_cast<SCEVUnknown>(FoundRHS);
if (!SUFoundRHS)
return false;
Value *Shiftee, *ShiftValue;
using namespace PatternMatch;
if (match(SUFoundRHS->getValue(),
m_LShr(m_Value(Shiftee), m_Value(ShiftValue)))) {
auto *ShifteeS = getSCEV(Shiftee);
// Prove one of the following:
// LHS <u (shiftee >> shiftvalue) && shiftee <=u RHS ---> LHS <u RHS
// LHS <=u (shiftee >> shiftvalue) && shiftee <=u RHS ---> LHS <=u RHS
// LHS <s (shiftee >> shiftvalue) && shiftee <=s RHS && shiftee >=s 0
// ---> LHS <s RHS
// LHS <=s (shiftee >> shiftvalue) && shiftee <=s RHS && shiftee >=s 0
// ---> LHS <=s RHS
if (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE)
return isKnownPredicate(ICmpInst::ICMP_ULE, ShifteeS, RHS);
if (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SLE)
if (isKnownNonNegative(ShifteeS))
return isKnownPredicate(ICmpInst::ICMP_SLE, ShifteeS, RHS);
}
return false;
}
bool ScalarEvolution::isImpliedCondOperands(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS,
const SCEV *FoundLHS,
const SCEV *FoundRHS,
const Instruction *CtxI) {
if (isImpliedCondOperandsViaRanges(Pred, LHS, RHS, FoundLHS, FoundRHS))
return true;
if (isImpliedCondOperandsViaNoOverflow(Pred, LHS, RHS, FoundLHS, FoundRHS))
return true;
if (isImpliedCondOperandsViaShift(Pred, LHS, RHS, FoundLHS, FoundRHS))
return true;
if (isImpliedCondOperandsViaAddRecStart(Pred, LHS, RHS, FoundLHS, FoundRHS,
CtxI))
return true;
return isImpliedCondOperandsHelper(Pred, LHS, RHS,
FoundLHS, FoundRHS);
}
/// Is MaybeMinMaxExpr an (U|S)(Min|Max) of Candidate and some other values?
template <typename MinMaxExprType>
static bool IsMinMaxConsistingOf(const SCEV *MaybeMinMaxExpr,
const SCEV *Candidate) {
const MinMaxExprType *MinMaxExpr = dyn_cast<MinMaxExprType>(MaybeMinMaxExpr);
if (!MinMaxExpr)
return false;
return is_contained(MinMaxExpr->operands(), Candidate);
}
static bool IsKnownPredicateViaAddRecStart(ScalarEvolution &SE,
ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS) {
// If both sides are affine addrecs for the same loop, with equal
// steps, and we know the recurrences don't wrap, then we only
// need to check the predicate on the starting values.
if (!ICmpInst::isRelational(Pred))
return false;
const SCEVAddRecExpr *LAR = dyn_cast<SCEVAddRecExpr>(LHS);
if (!LAR)
return false;
const SCEVAddRecExpr *RAR = dyn_cast<SCEVAddRecExpr>(RHS);
if (!RAR)
return false;
if (LAR->getLoop() != RAR->getLoop())
return false;
if (!LAR->isAffine() || !RAR->isAffine())
return false;
if (LAR->getStepRecurrence(SE) != RAR->getStepRecurrence(SE))
return false;
SCEV::NoWrapFlags NW = ICmpInst::isSigned(Pred) ?
SCEV::FlagNSW : SCEV::FlagNUW;
if (!LAR->getNoWrapFlags(NW) || !RAR->getNoWrapFlags(NW))
return false;
return SE.isKnownPredicate(Pred, LAR->getStart(), RAR->getStart());
}
/// Is LHS `Pred` RHS true on the virtue of LHS or RHS being a Min or Max
/// expression?
static bool IsKnownPredicateViaMinOrMax(ScalarEvolution &SE,
ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS) {
switch (Pred) {
default:
return false;
case ICmpInst::ICMP_SGE:
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ICmpInst::ICMP_SLE:
return
// min(A, ...) <= A
IsMinMaxConsistingOf<SCEVSMinExpr>(LHS, RHS) ||
// A <= max(A, ...)
IsMinMaxConsistingOf<SCEVSMaxExpr>(RHS, LHS);
case ICmpInst::ICMP_UGE:
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ICmpInst::ICMP_ULE:
return
// min(A, ...) <= A
// FIXME: what about umin_seq?
IsMinMaxConsistingOf<SCEVUMinExpr>(LHS, RHS) ||
// A <= max(A, ...)
IsMinMaxConsistingOf<SCEVUMaxExpr>(RHS, LHS);
}
llvm_unreachable("covered switch fell through?!");
}
bool ScalarEvolution::isImpliedViaOperations(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS,
const SCEV *FoundLHS,
const SCEV *FoundRHS,
unsigned Depth) {
assert(getTypeSizeInBits(LHS->getType()) ==
getTypeSizeInBits(RHS->getType()) &&
"LHS and RHS have different sizes?");
assert(getTypeSizeInBits(FoundLHS->getType()) ==
getTypeSizeInBits(FoundRHS->getType()) &&
"FoundLHS and FoundRHS have different sizes?");
// We want to avoid hurting the compile time with analysis of too big trees.
if (Depth > MaxSCEVOperationsImplicationDepth)
return false;
// We only want to work with GT comparison so far.
if (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_SLT) {
Pred = CmpInst::getSwappedPredicate(Pred);
std::swap(LHS, RHS);
std::swap(FoundLHS, FoundRHS);
}
// For unsigned, try to reduce it to corresponding signed comparison.
if (Pred == ICmpInst::ICMP_UGT)
// We can replace unsigned predicate with its signed counterpart if all
// involved values are non-negative.
// TODO: We could have better support for unsigned.
if (isKnownNonNegative(FoundLHS) && isKnownNonNegative(FoundRHS)) {
// Knowing that both FoundLHS and FoundRHS are non-negative, and knowing
// FoundLHS >u FoundRHS, we also know that FoundLHS >s FoundRHS. Let us
// use this fact to prove that LHS and RHS are non-negative.
const SCEV *MinusOne = getMinusOne(LHS->getType());
if (isImpliedCondOperands(ICmpInst::ICMP_SGT, LHS, MinusOne, FoundLHS,
FoundRHS) &&
isImpliedCondOperands(ICmpInst::ICMP_SGT, RHS, MinusOne, FoundLHS,
FoundRHS))
Pred = ICmpInst::ICMP_SGT;
}
if (Pred != ICmpInst::ICMP_SGT)
return false;
auto GetOpFromSExt = [&](const SCEV *S) {
if (auto *Ext = dyn_cast<SCEVSignExtendExpr>(S))
return Ext->getOperand();
// TODO: If S is a SCEVConstant then you can cheaply "strip" the sext off
// the constant in some cases.
return S;
};
// Acquire values from extensions.
auto *OrigLHS = LHS;
auto *OrigFoundLHS = FoundLHS;
LHS = GetOpFromSExt(LHS);
FoundLHS = GetOpFromSExt(FoundLHS);
// Is the SGT predicate can be proved trivially or using the found context.
auto IsSGTViaContext = [&](const SCEV *S1, const SCEV *S2) {
return isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_SGT, S1, S2) ||
isImpliedViaOperations(ICmpInst::ICMP_SGT, S1, S2, OrigFoundLHS,
FoundRHS, Depth + 1);
};
if (auto *LHSAddExpr = dyn_cast<SCEVAddExpr>(LHS)) {
// We want to avoid creation of any new non-constant SCEV. Since we are
// going to compare the operands to RHS, we should be certain that we don't
// need any size extensions for this. So let's decline all cases when the
// sizes of types of LHS and RHS do not match.
// TODO: Maybe try to get RHS from sext to catch more cases?
if (getTypeSizeInBits(LHS->getType()) != getTypeSizeInBits(RHS->getType()))
return false;
// Should not overflow.
if (!LHSAddExpr->hasNoSignedWrap())
return false;
auto *LL = LHSAddExpr->getOperand(0);
auto *LR = LHSAddExpr->getOperand(1);
auto *MinusOne = getMinusOne(RHS->getType());
// Checks that S1 >= 0 && S2 > RHS, trivially or using the found context.
auto IsSumGreaterThanRHS = [&](const SCEV *S1, const SCEV *S2) {
return IsSGTViaContext(S1, MinusOne) && IsSGTViaContext(S2, RHS);
};
// Try to prove the following rule:
// (LHS = LL + LR) && (LL >= 0) && (LR > RHS) => (LHS > RHS).
// (LHS = LL + LR) && (LR >= 0) && (LL > RHS) => (LHS > RHS).
if (IsSumGreaterThanRHS(LL, LR) || IsSumGreaterThanRHS(LR, LL))
return true;
} else if (auto *LHSUnknownExpr = dyn_cast<SCEVUnknown>(LHS)) {
Value *LL, *LR;
// FIXME: Once we have SDiv implemented, we can get rid of this matching.
using namespace llvm::PatternMatch;
if (match(LHSUnknownExpr->getValue(), m_SDiv(m_Value(LL), m_Value(LR)))) {
// Rules for division.
// We are going to perform some comparisons with Denominator and its
// derivative expressions. In general case, creating a SCEV for it may
// lead to a complex analysis of the entire graph, and in particular it
// can request trip count recalculation for the same loop. This would
// cache as SCEVCouldNotCompute to avoid the infinite recursion. To avoid
// this, we only want to create SCEVs that are constants in this section.
// So we bail if Denominator is not a constant.
if (!isa<ConstantInt>(LR))
return false;
auto *Denominator = cast<SCEVConstant>(getSCEV(LR));
// We want to make sure that LHS = FoundLHS / Denominator. If it is so,
// then a SCEV for the numerator already exists and matches with FoundLHS.
auto *Numerator = getExistingSCEV(LL);
if (!Numerator || Numerator->getType() != FoundLHS->getType())
return false;
// Make sure that the numerator matches with FoundLHS and the denominator
// is positive.
if (!HasSameValue(Numerator, FoundLHS) || !isKnownPositive(Denominator))
return false;
auto *DTy = Denominator->getType();
auto *FRHSTy = FoundRHS->getType();
if (DTy->isPointerTy() != FRHSTy->isPointerTy())
// One of types is a pointer and another one is not. We cannot extend
// them properly to a wider type, so let us just reject this case.
// TODO: Usage of getEffectiveSCEVType for DTy, FRHSTy etc should help
// to avoid this check.
return false;
// Given that:
// FoundLHS > FoundRHS, LHS = FoundLHS / Denominator, Denominator > 0.
auto *WTy = getWiderType(DTy, FRHSTy);
auto *DenominatorExt = getNoopOrSignExtend(Denominator, WTy);
auto *FoundRHSExt = getNoopOrSignExtend(FoundRHS, WTy);
// Try to prove the following rule:
// (FoundRHS > Denominator - 2) && (RHS <= 0) => (LHS > RHS).
// For example, given that FoundLHS > 2. It means that FoundLHS is at
// least 3. If we divide it by Denominator < 4, we will have at least 1.
auto *DenomMinusTwo = getMinusSCEV(DenominatorExt, getConstant(WTy, 2));
if (isKnownNonPositive(RHS) &&
IsSGTViaContext(FoundRHSExt, DenomMinusTwo))
return true;
// Try to prove the following rule:
// (FoundRHS > -1 - Denominator) && (RHS < 0) => (LHS > RHS).
// For example, given that FoundLHS > -3. Then FoundLHS is at least -2.
// If we divide it by Denominator > 2, then:
// 1. If FoundLHS is negative, then the result is 0.
// 2. If FoundLHS is non-negative, then the result is non-negative.
// Anyways, the result is non-negative.
auto *MinusOne = getMinusOne(WTy);
auto *NegDenomMinusOne = getMinusSCEV(MinusOne, DenominatorExt);
if (isKnownNegative(RHS) &&
IsSGTViaContext(FoundRHSExt, NegDenomMinusOne))
return true;
}
}
// If our expression contained SCEVUnknown Phis, and we split it down and now
// need to prove something for them, try to prove the predicate for every
// possible incoming values of those Phis.
if (isImpliedViaMerge(Pred, OrigLHS, RHS, OrigFoundLHS, FoundRHS, Depth + 1))
return true;
return false;
}
static bool isKnownPredicateExtendIdiom(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS) {
// zext x u<= sext x, sext x s<= zext x
switch (Pred) {
case ICmpInst::ICMP_SGE:
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ICmpInst::ICMP_SLE: {
// If operand >=s 0 then ZExt == SExt. If operand <s 0 then SExt <s ZExt.
const SCEVSignExtendExpr *SExt = dyn_cast<SCEVSignExtendExpr>(LHS);
const SCEVZeroExtendExpr *ZExt = dyn_cast<SCEVZeroExtendExpr>(RHS);
if (SExt && ZExt && SExt->getOperand() == ZExt->getOperand())
return true;
break;
}
case ICmpInst::ICMP_UGE:
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ICmpInst::ICMP_ULE: {
// If operand >=s 0 then ZExt == SExt. If operand <s 0 then ZExt <u SExt.
const SCEVZeroExtendExpr *ZExt = dyn_cast<SCEVZeroExtendExpr>(LHS);
const SCEVSignExtendExpr *SExt = dyn_cast<SCEVSignExtendExpr>(RHS);
if (SExt && ZExt && SExt->getOperand() == ZExt->getOperand())
return true;
break;
}
default:
break;
};
return false;
}
bool
ScalarEvolution::isKnownViaNonRecursiveReasoning(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS) {
return isKnownPredicateExtendIdiom(Pred, LHS, RHS) ||
isKnownPredicateViaConstantRanges(Pred, LHS, RHS) ||
IsKnownPredicateViaMinOrMax(*this, Pred, LHS, RHS) ||
IsKnownPredicateViaAddRecStart(*this, Pred, LHS, RHS) ||
isKnownPredicateViaNoOverflow(Pred, LHS, RHS);
}
bool
ScalarEvolution::isImpliedCondOperandsHelper(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS,
const SCEV *FoundLHS,
const SCEV *FoundRHS) {
switch (Pred) {
default: llvm_unreachable("Unexpected ICmpInst::Predicate value!");
case ICmpInst::ICMP_EQ:
case ICmpInst::ICMP_NE:
if (HasSameValue(LHS, FoundLHS) && HasSameValue(RHS, FoundRHS))
return true;
break;
case ICmpInst::ICMP_SLT:
case ICmpInst::ICMP_SLE:
if (isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_SLE, LHS, FoundLHS) &&
isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_SGE, RHS, FoundRHS))
return true;
break;
case ICmpInst::ICMP_SGT:
case ICmpInst::ICMP_SGE:
if (isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_SGE, LHS, FoundLHS) &&
isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_SLE, RHS, FoundRHS))
return true;
break;
case ICmpInst::ICMP_ULT:
case ICmpInst::ICMP_ULE:
if (isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_ULE, LHS, FoundLHS) &&
isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_UGE, RHS, FoundRHS))
return true;
break;
case ICmpInst::ICMP_UGT:
case ICmpInst::ICMP_UGE:
if (isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_UGE, LHS, FoundLHS) &&
isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_ULE, RHS, FoundRHS))
return true;
break;
}
// Maybe it can be proved via operations?
if (isImpliedViaOperations(Pred, LHS, RHS, FoundLHS, FoundRHS))
return true;
return false;
}
bool ScalarEvolution::isImpliedCondOperandsViaRanges(ICmpInst::Predicate Pred,
const SCEV *LHS,
const SCEV *RHS,
const SCEV *FoundLHS,
const SCEV *FoundRHS) {
if (!isa<SCEVConstant>(RHS) || !isa<SCEVConstant>(FoundRHS))
// The restriction on `FoundRHS` be lifted easily -- it exists only to
// reduce the compile time impact of this optimization.
return false;
Optional<APInt> Addend = computeConstantDifference(LHS, FoundLHS);
if (!Addend)
return false;
const APInt &ConstFoundRHS = cast<SCEVConstant>(FoundRHS)->getAPInt();
// `FoundLHSRange` is the range we know `FoundLHS` to be in by virtue of the
// antecedent "`FoundLHS` `Pred` `FoundRHS`".
ConstantRange FoundLHSRange =
ConstantRange::makeExactICmpRegion(Pred, ConstFoundRHS);
// Since `LHS` is `FoundLHS` + `Addend`, we can compute a range for `LHS`:
ConstantRange LHSRange = FoundLHSRange.add(ConstantRange(*Addend));
// We can also compute the range of values for `LHS` that satisfy the
// consequent, "`LHS` `Pred` `RHS`":
const APInt &ConstRHS = cast<SCEVConstant>(RHS)->getAPInt();
// The antecedent implies the consequent if every value of `LHS` that
// satisfies the antecedent also satisfies the consequent.
return LHSRange.icmp(Pred, ConstRHS);
}
bool ScalarEvolution::canIVOverflowOnLT(const SCEV *RHS, const SCEV *Stride,
bool IsSigned) {
assert(isKnownPositive(Stride) && "Positive stride expected!");
unsigned BitWidth = getTypeSizeInBits(RHS->getType());
const SCEV *One = getOne(Stride->getType());
if (IsSigned) {
APInt MaxRHS = getSignedRangeMax(RHS);
APInt MaxValue = APInt::getSignedMaxValue(BitWidth);
APInt MaxStrideMinusOne = getSignedRangeMax(getMinusSCEV(Stride, One));
// SMaxRHS + SMaxStrideMinusOne > SMaxValue => overflow!
return (std::move(MaxValue) - MaxStrideMinusOne).slt(MaxRHS);
}
APInt MaxRHS = getUnsignedRangeMax(RHS);
APInt MaxValue = APInt::getMaxValue(BitWidth);
APInt MaxStrideMinusOne = getUnsignedRangeMax(getMinusSCEV(Stride, One));
// UMaxRHS + UMaxStrideMinusOne > UMaxValue => overflow!
return (std::move(MaxValue) - MaxStrideMinusOne).ult(MaxRHS);
}
bool ScalarEvolution::canIVOverflowOnGT(const SCEV *RHS, const SCEV *Stride,
bool IsSigned) {
unsigned BitWidth = getTypeSizeInBits(RHS->getType());
const SCEV *One = getOne(Stride->getType());
if (IsSigned) {
APInt MinRHS = getSignedRangeMin(RHS);
APInt MinValue = APInt::getSignedMinValue(BitWidth);
APInt MaxStrideMinusOne = getSignedRangeMax(getMinusSCEV(Stride, One));
// SMinRHS - SMaxStrideMinusOne < SMinValue => overflow!
return (std::move(MinValue) + MaxStrideMinusOne).sgt(MinRHS);
}
APInt MinRHS = getUnsignedRangeMin(RHS);
APInt MinValue = APInt::getMinValue(BitWidth);
APInt MaxStrideMinusOne = getUnsignedRangeMax(getMinusSCEV(Stride, One));
// UMinRHS - UMaxStrideMinusOne < UMinValue => overflow!
return (std::move(MinValue) + MaxStrideMinusOne).ugt(MinRHS);
}
const SCEV *ScalarEvolution::getUDivCeilSCEV(const SCEV *N, const SCEV *D) {
// umin(N, 1) + floor((N - umin(N, 1)) / D)
// This is equivalent to "1 + floor((N - 1) / D)" for N != 0. The umin
// expression fixes the case of N=0.
const SCEV *MinNOne = getUMinExpr(N, getOne(N->getType()));
const SCEV *NMinusOne = getMinusSCEV(N, MinNOne);
return getAddExpr(MinNOne, getUDivExpr(NMinusOne, D));
}
const SCEV *ScalarEvolution::computeMaxBECountForLT(const SCEV *Start,
const SCEV *Stride,
const SCEV *End,
unsigned BitWidth,
bool IsSigned) {
// The logic in this function assumes we can represent a positive stride.
// If we can't, the backedge-taken count must be zero.
if (IsSigned && BitWidth == 1)
return getZero(Stride->getType());
// This code has only been closely audited for negative strides in the
// unsigned comparison case, it may be correct for signed comparison, but
// that needs to be established.
assert((!IsSigned || !isKnownNonPositive(Stride)) &&
"Stride is expected strictly positive for signed case!");
// Calculate the maximum backedge count based on the range of values
// permitted by Start, End, and Stride.
APInt MinStart =
IsSigned ? getSignedRangeMin(Start) : getUnsignedRangeMin(Start);
APInt MinStride =
IsSigned ? getSignedRangeMin(Stride) : getUnsignedRangeMin(Stride);
// We assume either the stride is positive, or the backedge-taken count
// is zero. So force StrideForMaxBECount to be at least one.
APInt One(BitWidth, 1);
APInt StrideForMaxBECount = IsSigned ? APIntOps::smax(One, MinStride)
: APIntOps::umax(One, MinStride);
APInt MaxValue = IsSigned ? APInt::getSignedMaxValue(BitWidth)
: APInt::getMaxValue(BitWidth);
APInt Limit = MaxValue - (StrideForMaxBECount - 1);
// Although End can be a MAX expression we estimate MaxEnd considering only
// the case End = RHS of the loop termination condition. This is safe because
// in the other case (End - Start) is zero, leading to a zero maximum backedge
// taken count.
APInt MaxEnd = IsSigned ? APIntOps::smin(getSignedRangeMax(End), Limit)
: APIntOps::umin(getUnsignedRangeMax(End), Limit);
// MaxBECount = ceil((max(MaxEnd, MinStart) - MinStart) / Stride)
MaxEnd = IsSigned ? APIntOps::smax(MaxEnd, MinStart)
: APIntOps::umax(MaxEnd, MinStart);
return getUDivCeilSCEV(getConstant(MaxEnd - MinStart) /* Delta */,
getConstant(StrideForMaxBECount) /* Step */);
}
ScalarEvolution::ExitLimit
ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS,
const Loop *L, bool IsSigned,
bool ControlsExit, bool AllowPredicates) {
SmallPtrSet<const SCEVPredicate *, 4> Predicates;
const SCEVAddRecExpr *IV = dyn_cast<SCEVAddRecExpr>(LHS);
bool PredicatedIV = false;
auto canAssumeNoSelfWrap = [&](const SCEVAddRecExpr *AR) {
// Can we prove this loop *must* be UB if overflow of IV occurs?
// Reasoning goes as follows:
// * Suppose the IV did self wrap.
// * If Stride evenly divides the iteration space, then once wrap
// occurs, the loop must revisit the same values.
// * We know that RHS is invariant, and that none of those values
// caused this exit to be taken previously. Thus, this exit is
// dynamically dead.
// * If this is the sole exit, then a dead exit implies the loop
// must be infinite if there are no abnormal exits.
// * If the loop were infinite, then it must either not be mustprogress
// or have side effects. Otherwise, it must be UB.
// * It can't (by assumption), be UB so we have contradicted our
// premise and can conclude the IV did not in fact self-wrap.
if (!isLoopInvariant(RHS, L))
return false;
auto *StrideC = dyn_cast<SCEVConstant>(AR->getStepRecurrence(*this));
if (!StrideC || !StrideC->getAPInt().isPowerOf2())
return false;
if (!ControlsExit || !loopHasNoAbnormalExits(L))
return false;
return loopIsFiniteByAssumption(L);
};
if (!IV) {
if (auto *ZExt = dyn_cast<SCEVZeroExtendExpr>(LHS)) {
const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(ZExt->getOperand());
if (AR && AR->getLoop() == L && AR->isAffine()) {
auto canProveNUW = [&]() {
if (!isLoopInvariant(RHS, L))
return false;
if (!isKnownNonZero(AR->getStepRecurrence(*this)))
// We need the sequence defined by AR to strictly increase in the
// unsigned integer domain for the logic below to hold.
return false;
const unsigned InnerBitWidth = getTypeSizeInBits(AR->getType());
const unsigned OuterBitWidth = getTypeSizeInBits(RHS->getType());
// If RHS <=u Limit, then there must exist a value V in the sequence
// defined by AR (e.g. {Start,+,Step}) such that V >u RHS, and
// V <=u UINT_MAX. Thus, we must exit the loop before unsigned
// overflow occurs. This limit also implies that a signed comparison
// (in the wide bitwidth) is equivalent to an unsigned comparison as
// the high bits on both sides must be zero.
APInt StrideMax = getUnsignedRangeMax(AR->getStepRecurrence(*this));
APInt Limit = APInt::getMaxValue(InnerBitWidth) - (StrideMax - 1);
Limit = Limit.zext(OuterBitWidth);
return getUnsignedRangeMax(applyLoopGuards(RHS, L)).ule(Limit);
};
auto Flags = AR->getNoWrapFlags();
if (!hasFlags(Flags, SCEV::FlagNUW) && canProveNUW())
Flags = setFlags(Flags, SCEV::FlagNUW);
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), Flags);
if (AR->hasNoUnsignedWrap()) {
// Emulate what getZeroExtendExpr would have done during construction
// if we'd been able to infer the fact just above at that time.
const SCEV *Step = AR->getStepRecurrence(*this);
Type *Ty = ZExt->getType();
auto *S = getAddRecExpr(
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this, 0),
getZeroExtendExpr(Step, Ty, 0), L, AR->getNoWrapFlags());
IV = dyn_cast<SCEVAddRecExpr>(S);
}
}
}
}
if (!IV && AllowPredicates) {
// Try to make this an AddRec using runtime tests, in the first X
// iterations of this loop, where X is the SCEV expression found by the
// algorithm below.
IV = convertSCEVToAddRecWithPredicates(LHS, L, Predicates);
PredicatedIV = true;
}
// Avoid weird loops
if (!IV || IV->getLoop() != L || !IV->isAffine())
return getCouldNotCompute();
// A precondition of this method is that the condition being analyzed
// reaches an exiting branch which dominates the latch. Given that, we can
// assume that an increment which violates the nowrap specification and
// produces poison must cause undefined behavior when the resulting poison
// value is branched upon and thus we can conclude that the backedge is
// taken no more often than would be required to produce that poison value.
// Note that a well defined loop can exit on the iteration which violates
// the nowrap specification if there is another exit (either explicit or
// implicit/exceptional) which causes the loop to execute before the
// exiting instruction we're analyzing would trigger UB.
auto WrapType = IsSigned ? SCEV::FlagNSW : SCEV::FlagNUW;
bool NoWrap = ControlsExit && IV->getNoWrapFlags(WrapType);
ICmpInst::Predicate Cond = IsSigned ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT;
const SCEV *Stride = IV->getStepRecurrence(*this);
bool PositiveStride = isKnownPositive(Stride);
// Avoid negative or zero stride values.
if (!PositiveStride) {
// We can compute the correct backedge taken count for loops with unknown
// strides if we can prove that the loop is not an infinite loop with side
// effects. Here's the loop structure we are trying to handle -
//
// i = start
// do {
// A[i] = i;
// i += s;
// } while (i < end);
//
// The backedge taken count for such loops is evaluated as -
// (max(end, start + stride) - start - 1) /u stride
//
// The additional preconditions that we need to check to prove correctness
// of the above formula is as follows -
//
// a) IV is either nuw or nsw depending upon signedness (indicated by the
// NoWrap flag).
// b) the loop is guaranteed to be finite (e.g. is mustprogress and has
// no side effects within the loop)
// c) loop has a single static exit (with no abnormal exits)
//
// Precondition a) implies that if the stride is negative, this is a single
// trip loop. The backedge taken count formula reduces to zero in this case.
//
// Precondition b) and c) combine to imply that if rhs is invariant in L,
// then a zero stride means the backedge can't be taken without executing
// undefined behavior.
//
// The positive stride case is the same as isKnownPositive(Stride) returning
// true (original behavior of the function).
//
if (PredicatedIV || !NoWrap || !loopIsFiniteByAssumption(L) ||
!loopHasNoAbnormalExits(L))
return getCouldNotCompute();
// This bailout is protecting the logic in computeMaxBECountForLT which
// has not yet been sufficiently auditted or tested with negative strides.
// We used to filter out all known-non-positive cases here, we're in the
// process of being less restrictive bit by bit.
if (IsSigned && isKnownNonPositive(Stride))
return getCouldNotCompute();
if (!isKnownNonZero(Stride)) {
// If we have a step of zero, and RHS isn't invariant in L, we don't know
// if it might eventually be greater than start and if so, on which
// iteration. We can't even produce a useful upper bound.
if (!isLoopInvariant(RHS, L))
return getCouldNotCompute();
// We allow a potentially zero stride, but we need to divide by stride
// below. Since the loop can't be infinite and this check must control
// the sole exit, we can infer the exit must be taken on the first
// iteration (e.g. backedge count = 0) if the stride is zero. Given that,
// we know the numerator in the divides below must be zero, so we can
// pick an arbitrary non-zero value for the denominator (e.g. stride)
// and produce the right result.
// FIXME: Handle the case where Stride is poison?
auto wouldZeroStrideBeUB = [&]() {
// Proof by contradiction. Suppose the stride were zero. If we can
// prove that the backedge *is* taken on the first iteration, then since
// we know this condition controls the sole exit, we must have an
// infinite loop. We can't have a (well defined) infinite loop per
// check just above.
// Note: The (Start - Stride) term is used to get the start' term from
// (start' + stride,+,stride). Remember that we only care about the
// result of this expression when stride == 0 at runtime.
auto *StartIfZero = getMinusSCEV(IV->getStart(), Stride);
return isLoopEntryGuardedByCond(L, Cond, StartIfZero, RHS);
};
if (!wouldZeroStrideBeUB()) {
Stride = getUMaxExpr(Stride, getOne(Stride->getType()));
}
}
} else if (!Stride->isOne() && !NoWrap) {
auto isUBOnWrap = [&]() {
// From no-self-wrap, we need to then prove no-(un)signed-wrap. This
// follows trivially from the fact that every (un)signed-wrapped, but
// not self-wrapped value must be LT than the last value before
// (un)signed wrap. Since we know that last value didn't exit, nor
// will any smaller one.
return canAssumeNoSelfWrap(IV);
};
// Avoid proven overflow cases: this will ensure that the backedge taken
// count will not generate any unsigned overflow. Relaxed no-overflow
// conditions exploit NoWrapFlags, allowing to optimize in presence of
// undefined behaviors like the case of C language.
if (canIVOverflowOnLT(RHS, Stride, IsSigned) && !isUBOnWrap())
return getCouldNotCompute();
}
// On all paths just preceeding, we established the following invariant:
// IV can be assumed not to overflow up to and including the exiting
// iteration. We proved this in one of two ways:
// 1) We can show overflow doesn't occur before the exiting iteration
// 1a) canIVOverflowOnLT, and b) step of one
// 2) We can show that if overflow occurs, the loop must execute UB
// before any possible exit.
// Note that we have not yet proved RHS invariant (in general).
const SCEV *Start = IV->getStart();
// Preserve pointer-typed Start/RHS to pass to isLoopEntryGuardedByCond.
// If we convert to integers, isLoopEntryGuardedByCond will miss some cases.
// Use integer-typed versions for actual computation; we can't subtract
// pointers in general.
const SCEV *OrigStart = Start;
const SCEV *OrigRHS = RHS;
if (Start->getType()->isPointerTy()) {
Start = getLosslessPtrToIntExpr(Start);
if (isa<SCEVCouldNotCompute>(Start))
return Start;
}
if (RHS->getType()->isPointerTy()) {
RHS = getLosslessPtrToIntExpr(RHS);
if (isa<SCEVCouldNotCompute>(RHS))
return RHS;
}
// When the RHS is not invariant, we do not know the end bound of the loop and
// cannot calculate the ExactBECount needed by ExitLimit. However, we can
// calculate the MaxBECount, given the start, stride and max value for the end
// bound of the loop (RHS), and the fact that IV does not overflow (which is
// checked above).
if (!isLoopInvariant(RHS, L)) {
const SCEV *MaxBECount = computeMaxBECountForLT(
Start, Stride, RHS, getTypeSizeInBits(LHS->getType()), IsSigned);
return ExitLimit(getCouldNotCompute() /* ExactNotTaken */, MaxBECount,
false /*MaxOrZero*/, Predicates);
}
// We use the expression (max(End,Start)-Start)/Stride to describe the
// backedge count, as if the backedge is taken at least once max(End,Start)
// is End and so the result is as above, and if not max(End,Start) is Start
// so we get a backedge count of zero.
const SCEV *BECount = nullptr;
auto *OrigStartMinusStride = getMinusSCEV(OrigStart, Stride);
assert(isAvailableAtLoopEntry(OrigStartMinusStride, L) && "Must be!");
assert(isAvailableAtLoopEntry(OrigStart, L) && "Must be!");
assert(isAvailableAtLoopEntry(OrigRHS, L) && "Must be!");
// Can we prove (max(RHS,Start) > Start - Stride?
if (isLoopEntryGuardedByCond(L, Cond, OrigStartMinusStride, OrigStart) &&
isLoopEntryGuardedByCond(L, Cond, OrigStartMinusStride, OrigRHS)) {
// In this case, we can use a refined formula for computing backedge taken
// count. The general formula remains:
// "End-Start /uceiling Stride" where "End = max(RHS,Start)"
// We want to use the alternate formula:
// "((End - 1) - (Start - Stride)) /u Stride"
// Let's do a quick case analysis to show these are equivalent under
// our precondition that max(RHS,Start) > Start - Stride.
// * For RHS <= Start, the backedge-taken count must be zero.
// "((End - 1) - (Start - Stride)) /u Stride" reduces to
// "((Start - 1) - (Start - Stride)) /u Stride" which simplies to
// "Stride - 1 /u Stride" which is indeed zero for all non-zero values
// of Stride. For 0 stride, we've use umin(1,Stride) above, reducing
// this to the stride of 1 case.
// * For RHS >= Start, the backedge count must be "RHS-Start /uceil Stride".
// "((End - 1) - (Start - Stride)) /u Stride" reduces to
// "((RHS - 1) - (Start - Stride)) /u Stride" reassociates to
// "((RHS - (Start - Stride) - 1) /u Stride".
// Our preconditions trivially imply no overflow in that form.
const SCEV *MinusOne = getMinusOne(Stride->getType());
const SCEV *Numerator =
getMinusSCEV(getAddExpr(RHS, MinusOne), getMinusSCEV(Start, Stride));
BECount = getUDivExpr(Numerator, Stride);
}
const SCEV *BECountIfBackedgeTaken = nullptr;
if (!BECount) {
auto canProveRHSGreaterThanEqualStart = [&]() {
auto CondGE = IsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE;
if (isLoopEntryGuardedByCond(L, CondGE, OrigRHS, OrigStart))
return true;
// (RHS > Start - 1) implies RHS >= Start.
// * "RHS >= Start" is trivially equivalent to "RHS > Start - 1" if
// "Start - 1" doesn't overflow.
// * For signed comparison, if Start - 1 does overflow, it's equal
// to INT_MAX, and "RHS >s INT_MAX" is trivially false.
// * For unsigned comparison, if Start - 1 does overflow, it's equal
// to UINT_MAX, and "RHS >u UINT_MAX" is trivially false.
//
// FIXME: Should isLoopEntryGuardedByCond do this for us?
auto CondGT = IsSigned ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT;
auto *StartMinusOne = getAddExpr(OrigStart,
getMinusOne(OrigStart->getType()));
return isLoopEntryGuardedByCond(L, CondGT, OrigRHS, StartMinusOne);
};
// If we know that RHS >= Start in the context of loop, then we know that
// max(RHS, Start) = RHS at this point.
const SCEV *End;
if (canProveRHSGreaterThanEqualStart()) {
End = RHS;
} else {
// If RHS < Start, the backedge will be taken zero times. So in
// general, we can write the backedge-taken count as:
//
// RHS >= Start ? ceil(RHS - Start) / Stride : 0
//
// We convert it to the following to make it more convenient for SCEV:
//
// ceil(max(RHS, Start) - Start) / Stride
End = IsSigned ? getSMaxExpr(RHS, Start) : getUMaxExpr(RHS, Start);
// See what would happen if we assume the backedge is taken. This is
// used to compute MaxBECount.
BECountIfBackedgeTaken = getUDivCeilSCEV(getMinusSCEV(RHS, Start), Stride);
}
// At this point, we know:
//
// 1. If IsSigned, Start <=s End; otherwise, Start <=u End
// 2. The index variable doesn't overflow.
//
// Therefore, we know N exists such that
// (Start + Stride * N) >= End, and computing "(Start + Stride * N)"
// doesn't overflow.
//
// Using this information, try to prove whether the addition in
// "(Start - End) + (Stride - 1)" has unsigned overflow.
const SCEV *One = getOne(Stride->getType());
bool MayAddOverflow = [&] {
if (auto *StrideC = dyn_cast<SCEVConstant>(Stride)) {
if (StrideC->getAPInt().isPowerOf2()) {
// Suppose Stride is a power of two, and Start/End are unsigned
// integers. Let UMAX be the largest representable unsigned
// integer.
//
// By the preconditions of this function, we know
// "(Start + Stride * N) >= End", and this doesn't overflow.
// As a formula:
//
// End <= (Start + Stride * N) <= UMAX
//
// Subtracting Start from all the terms:
//
// End - Start <= Stride * N <= UMAX - Start
//
// Since Start is unsigned, UMAX - Start <= UMAX. Therefore:
//
// End - Start <= Stride * N <= UMAX
//
// Stride * N is a multiple of Stride. Therefore,
//
// End - Start <= Stride * N <= UMAX - (UMAX mod Stride)
//
// Since Stride is a power of two, UMAX + 1 is divisible by Stride.
// Therefore, UMAX mod Stride == Stride - 1. So we can write:
//
// End - Start <= Stride * N <= UMAX - Stride - 1
//
// Dropping the middle term:
//
// End - Start <= UMAX - Stride - 1
//
// Adding Stride - 1 to both sides:
//
// (End - Start) + (Stride - 1) <= UMAX
//
// In other words, the addition doesn't have unsigned overflow.
//
// A similar proof works if we treat Start/End as signed values.
// Just rewrite steps before "End - Start <= Stride * N <= UMAX" to
// use signed max instead of unsigned max. Note that we're trying
// to prove a lack of unsigned overflow in either case.
return false;
}
}
if (Start == Stride || Start == getMinusSCEV(Stride, One)) {
// If Start is equal to Stride, (End - Start) + (Stride - 1) == End - 1.
// If !IsSigned, 0 <u Stride == Start <=u End; so 0 <u End - 1 <u End.
// If IsSigned, 0 <s Stride == Start <=s End; so 0 <s End - 1 <s End.
//
// If Start is equal to Stride - 1, (End - Start) + Stride - 1 == End.
return false;
}
return true;
}();
const SCEV *Delta = getMinusSCEV(End, Start);
if (!MayAddOverflow) {
// floor((D + (S - 1)) / S)
// We prefer this formulation if it's legal because it's fewer operations.
BECount =
getUDivExpr(getAddExpr(Delta, getMinusSCEV(Stride, One)), Stride);
} else {
BECount = getUDivCeilSCEV(Delta, Stride);
}
}
const SCEV *MaxBECount;
bool MaxOrZero = false;
if (isa<SCEVConstant>(BECount)) {
MaxBECount = BECount;
} else if (BECountIfBackedgeTaken &&
isa<SCEVConstant>(BECountIfBackedgeTaken)) {
// If we know exactly how many times the backedge will be taken if it's
// taken at least once, then the backedge count will either be that or
// zero.
MaxBECount = BECountIfBackedgeTaken;
MaxOrZero = true;
} else {
MaxBECount = computeMaxBECountForLT(
Start, Stride, RHS, getTypeSizeInBits(LHS->getType()), IsSigned);
}
if (isa<SCEVCouldNotCompute>(MaxBECount) &&
!isa<SCEVCouldNotCompute>(BECount))
MaxBECount = getConstant(getUnsignedRangeMax(BECount));
return ExitLimit(BECount, MaxBECount, MaxOrZero, Predicates);
}
ScalarEvolution::ExitLimit
ScalarEvolution::howManyGreaterThans(const SCEV *LHS, const SCEV *RHS,
const Loop *L, bool IsSigned,
bool ControlsExit, bool AllowPredicates) {
SmallPtrSet<const SCEVPredicate *, 4> Predicates;
// We handle only IV > Invariant
if (!isLoopInvariant(RHS, L))
return getCouldNotCompute();
const SCEVAddRecExpr *IV = dyn_cast<SCEVAddRecExpr>(LHS);
if (!IV && AllowPredicates)
// Try to make this an AddRec using runtime tests, in the first X
// iterations of this loop, where X is the SCEV expression found by the
// algorithm below.
IV = convertSCEVToAddRecWithPredicates(LHS, L, Predicates);
// Avoid weird loops
if (!IV || IV->getLoop() != L || !IV->isAffine())
return getCouldNotCompute();
auto WrapType = IsSigned ? SCEV::FlagNSW : SCEV::FlagNUW;
bool NoWrap = ControlsExit && IV->getNoWrapFlags(WrapType);
ICmpInst::Predicate Cond = IsSigned ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT;
const SCEV *Stride = getNegativeSCEV(IV->getStepRecurrence(*this));
// Avoid negative or zero stride values
if (!isKnownPositive(Stride))
return getCouldNotCompute();
// Avoid proven overflow cases: this will ensure that the backedge taken count
// will not generate any unsigned overflow. Relaxed no-overflow conditions
// exploit NoWrapFlags, allowing to optimize in presence of undefined
// behaviors like the case of C language.
if (!Stride->isOne() && !NoWrap)
if (canIVOverflowOnGT(RHS, Stride, IsSigned))
return getCouldNotCompute();
const SCEV *Start = IV->getStart();
const SCEV *End = RHS;
if (!isLoopEntryGuardedByCond(L, Cond, getAddExpr(Start, Stride), RHS)) {
// If we know that Start >= RHS in the context of loop, then we know that
// min(RHS, Start) = RHS at this point.
if (isLoopEntryGuardedByCond(
L, IsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE, Start, RHS))
End = RHS;
else
End = IsSigned ? getSMinExpr(RHS, Start) : getUMinExpr(RHS, Start);
}
if (Start->getType()->isPointerTy()) {
Start = getLosslessPtrToIntExpr(Start);
if (isa<SCEVCouldNotCompute>(Start))
return Start;
}
if (End->getType()->isPointerTy()) {
End = getLosslessPtrToIntExpr(End);
if (isa<SCEVCouldNotCompute>(End))
return End;
}
// Compute ((Start - End) + (Stride - 1)) / Stride.
// FIXME: This can overflow. Holding off on fixing this for now;
// howManyGreaterThans will hopefully be gone soon.
const SCEV *One = getOne(Stride->getType());
const SCEV *BECount = getUDivExpr(
getAddExpr(getMinusSCEV(Start, End), getMinusSCEV(Stride, One)), Stride);
APInt MaxStart = IsSigned ? getSignedRangeMax(Start)
: getUnsignedRangeMax(Start);
APInt MinStride = IsSigned ? getSignedRangeMin(Stride)
: getUnsignedRangeMin(Stride);
unsigned BitWidth = getTypeSizeInBits(LHS->getType());
APInt Limit = IsSigned ? APInt::getSignedMinValue(BitWidth) + (MinStride - 1)
: APInt::getMinValue(BitWidth) + (MinStride - 1);
// Although End can be a MIN expression we estimate MinEnd considering only
// the case End = RHS. This is safe because in the other case (Start - End)
// is zero, leading to a zero maximum backedge taken count.
APInt MinEnd =
IsSigned ? APIntOps::smax(getSignedRangeMin(RHS), Limit)
: APIntOps::umax(getUnsignedRangeMin(RHS), Limit);
const SCEV *MaxBECount = isa<SCEVConstant>(BECount)
? BECount
: getUDivCeilSCEV(getConstant(MaxStart - MinEnd),
getConstant(MinStride));
if (isa<SCEVCouldNotCompute>(MaxBECount))
MaxBECount = BECount;
return ExitLimit(BECount, MaxBECount, false, Predicates);
}
const SCEV *SCEVAddRecExpr::getNumIterationsInRange(const ConstantRange &Range,
ScalarEvolution &SE) const {
if (Range.isFullSet()) // Infinite loop.
return SE.getCouldNotCompute();
// If the start is a non-zero constant, shift the range to simplify things.
if (const SCEVConstant *SC = dyn_cast<SCEVConstant>(getStart()))
if (!SC->getValue()->isZero()) {
SmallVector<const SCEV *, 4> Operands(operands());
Operands[0] = SE.getZero(SC->getType());
const SCEV *Shifted = SE.getAddRecExpr(Operands, getLoop(),
getNoWrapFlags(FlagNW));
if (const auto *ShiftedAddRec = dyn_cast<SCEVAddRecExpr>(Shifted))
return ShiftedAddRec->getNumIterationsInRange(
Range.subtract(SC->getAPInt()), SE);
// This is strange and shouldn't happen.
return SE.getCouldNotCompute();
}
// The only time we can solve this is when we have all constant indices.
// Otherwise, we cannot determine the overflow conditions.
if (any_of(operands(), [](const SCEV *Op) { return !isa<SCEVConstant>(Op); }))
return SE.getCouldNotCompute();
// Okay at this point we know that all elements of the chrec are constants and
// that the start element is zero.
// First check to see if the range contains zero. If not, the first
// iteration exits.
unsigned BitWidth = SE.getTypeSizeInBits(getType());
if (!Range.contains(APInt(BitWidth, 0)))
return SE.getZero(getType());
if (isAffine()) {
// If this is an affine expression then we have this situation:
// Solve {0,+,A} in Range === Ax in Range
// We know that zero is in the range. If A is positive then we know that
// the upper value of the range must be the first possible exit value.
// If A is negative then the lower of the range is the last possible loop
// value. Also note that we already checked for a full range.
APInt A = cast<SCEVConstant>(getOperand(1))->getAPInt();
APInt End = A.sge(1) ? (Range.getUpper() - 1) : Range.getLower();
// The exit value should be (End+A)/A.
APInt ExitVal = (End + A).udiv(A);
ConstantInt *ExitValue = ConstantInt::get(SE.getContext(), ExitVal);
// Evaluate at the exit value. If we really did fall out of the valid
// range, then we computed our trip count, otherwise wrap around or other
// things must have happened.
ConstantInt *Val = EvaluateConstantChrecAtConstant(this, ExitValue, SE);
if (Range.contains(Val->getValue()))
return SE.getCouldNotCompute(); // Something strange happened
// Ensure that the previous value is in the range.
assert(Range.contains(
EvaluateConstantChrecAtConstant(this,
ConstantInt::get(SE.getContext(), ExitVal - 1), SE)->getValue()) &&
"Linear scev computation is off in a bad way!");
return SE.getConstant(ExitValue);
}
if (isQuadratic()) {
if (auto S = SolveQuadraticAddRecRange(this, Range, SE))
return SE.getConstant(*S);
}
return SE.getCouldNotCompute();
}
const SCEVAddRecExpr *
SCEVAddRecExpr::getPostIncExpr(ScalarEvolution &SE) const {
assert(getNumOperands() > 1 && "AddRec with zero step?");
// There is a temptation to just call getAddExpr(this, getStepRecurrence(SE)),
// but in this case we cannot guarantee that the value returned will be an
// AddRec because SCEV does not have a fixed point where it stops
// simplification: it is legal to return ({rec1} + {rec2}). For example, it
// may happen if we reach arithmetic depth limit while simplifying. So we
// construct the returned value explicitly.
SmallVector<const SCEV *, 3> Ops;
// If this is {A,+,B,+,C,...,+,N}, then its step is {B,+,C,+,...,+,N}, and
// (this + Step) is {A+B,+,B+C,+...,+,N}.
for (unsigned i = 0, e = getNumOperands() - 1; i < e; ++i)
Ops.push_back(SE.getAddExpr(getOperand(i), getOperand(i + 1)));
// We know that the last operand is not a constant zero (otherwise it would
// have been popped out earlier). This guarantees us that if the result has
// the same last operand, then it will also not be popped out, meaning that
// the returned value will be an AddRec.
const SCEV *Last = getOperand(getNumOperands() - 1);
assert(!Last->isZero() && "Recurrency with zero step?");
Ops.push_back(Last);
return cast<SCEVAddRecExpr>(SE.getAddRecExpr(Ops, getLoop(),
SCEV::FlagAnyWrap));
}
// Return true when S contains at least an undef value.
bool ScalarEvolution::containsUndefs(const SCEV *S) const {
return SCEVExprContains(S, [](const SCEV *S) {
if (const auto *SU = dyn_cast<SCEVUnknown>(S))
return isa<UndefValue>(SU->getValue());
return false;
});
}
// Return true when S contains a value that is a nullptr.
bool ScalarEvolution::containsErasedValue(const SCEV *S) const {
return SCEVExprContains(S, [](const SCEV *S) {
if (const auto *SU = dyn_cast<SCEVUnknown>(S))
return SU->getValue() == nullptr;
return false;
});
}
/// Return the size of an element read or written by Inst.
const SCEV *ScalarEvolution::getElementSize(Instruction *Inst) {
Type *Ty;
if (StoreInst *Store = dyn_cast<StoreInst>(Inst))
Ty = Store->getValueOperand()->getType();
else if (LoadInst *Load = dyn_cast<LoadInst>(Inst))
Ty = Load->getType();
else
return nullptr;
Type *ETy = getEffectiveSCEVType(PointerType::getUnqual(Ty));
return getSizeOfExpr(ETy, Ty);
}
//===----------------------------------------------------------------------===//
// SCEVCallbackVH Class Implementation
//===----------------------------------------------------------------------===//
void ScalarEvolution::SCEVCallbackVH::deleted() {
assert(SE && "SCEVCallbackVH called with a null ScalarEvolution!");
if (PHINode *PN = dyn_cast<PHINode>(getValPtr()))
SE->ConstantEvolutionLoopExitValue.erase(PN);
SE->eraseValueFromMap(getValPtr());
// this now dangles!
}
void ScalarEvolution::SCEVCallbackVH::allUsesReplacedWith(Value *V) {
assert(SE && "SCEVCallbackVH called with a null ScalarEvolution!");
// Forget all the expressions associated with users of the old value,
// so that future queries will recompute the expressions using the new
// value.
Value *Old = getValPtr();
SmallVector<User *, 16> Worklist(Old->users());
SmallPtrSet<User *, 8> Visited;
while (!Worklist.empty()) {
User *U = Worklist.pop_back_val();
// Deleting the Old value will cause this to dangle. Postpone
// that until everything else is done.
if (U == Old)
continue;
if (!Visited.insert(U).second)
continue;
if (PHINode *PN = dyn_cast<PHINode>(U))
SE->ConstantEvolutionLoopExitValue.erase(PN);
SE->eraseValueFromMap(U);
llvm::append_range(Worklist, U->users());
}
// Delete the Old value.
if (PHINode *PN = dyn_cast<PHINode>(Old))
SE->ConstantEvolutionLoopExitValue.erase(PN);
SE->eraseValueFromMap(Old);
// this now dangles!
}
ScalarEvolution::SCEVCallbackVH::SCEVCallbackVH(Value *V, ScalarEvolution *se)
: CallbackVH(V), SE(se) {}
//===----------------------------------------------------------------------===//
// ScalarEvolution Class Implementation
//===----------------------------------------------------------------------===//
ScalarEvolution::ScalarEvolution(Function &F, TargetLibraryInfo &TLI,
AssumptionCache &AC, DominatorTree &DT,
LoopInfo &LI)
: F(F), TLI(TLI), AC(AC), DT(DT), LI(LI),
CouldNotCompute(new SCEVCouldNotCompute()), ValuesAtScopes(64),
LoopDispositions(64), BlockDispositions(64) {
// To use guards for proving predicates, we need to scan every instruction in
// relevant basic blocks, and not just terminators. Doing this is a waste of
// time if the IR does not actually contain any calls to
// @llvm.experimental.guard, so do a quick check and remember this beforehand.
//
// This pessimizes the case where a pass that preserves ScalarEvolution wants
// to _add_ guards to the module when there weren't any before, and wants
// ScalarEvolution to optimize based on those guards. For now we prefer to be
// efficient in lieu of being smart in that rather obscure case.
auto *GuardDecl = F.getParent()->getFunction(
Intrinsic::getName(Intrinsic::experimental_guard));
HasGuards = GuardDecl && !GuardDecl->use_empty();
}
ScalarEvolution::ScalarEvolution(ScalarEvolution &&Arg)
: F(Arg.F), HasGuards(Arg.HasGuards), TLI(Arg.TLI), AC(Arg.AC), DT(Arg.DT),
LI(Arg.LI), CouldNotCompute(std::move(Arg.CouldNotCompute)),
ValueExprMap(std::move(Arg.ValueExprMap)),
PendingLoopPredicates(std::move(Arg.PendingLoopPredicates)),
PendingPhiRanges(std::move(Arg.PendingPhiRanges)),
PendingMerges(std::move(Arg.PendingMerges)),
MinTrailingZerosCache(std::move(Arg.MinTrailingZerosCache)),
BackedgeTakenCounts(std::move(Arg.BackedgeTakenCounts)),
PredicatedBackedgeTakenCounts(
std::move(Arg.PredicatedBackedgeTakenCounts)),
BECountUsers(std::move(Arg.BECountUsers)),
ConstantEvolutionLoopExitValue(
std::move(Arg.ConstantEvolutionLoopExitValue)),
ValuesAtScopes(std::move(Arg.ValuesAtScopes)),
ValuesAtScopesUsers(std::move(Arg.ValuesAtScopesUsers)),
LoopDispositions(std::move(Arg.LoopDispositions)),
LoopPropertiesCache(std::move(Arg.LoopPropertiesCache)),
BlockDispositions(std::move(Arg.BlockDispositions)),
SCEVUsers(std::move(Arg.SCEVUsers)),
UnsignedRanges(std::move(Arg.UnsignedRanges)),
SignedRanges(std::move(Arg.SignedRanges)),
UniqueSCEVs(std::move(Arg.UniqueSCEVs)),
UniquePreds(std::move(Arg.UniquePreds)),
SCEVAllocator(std::move(Arg.SCEVAllocator)),
LoopUsers(std::move(Arg.LoopUsers)),
PredicatedSCEVRewrites(std::move(Arg.PredicatedSCEVRewrites)),
FirstUnknown(Arg.FirstUnknown) {
Arg.FirstUnknown = nullptr;
}
ScalarEvolution::~ScalarEvolution() {
// Iterate through all the SCEVUnknown instances and call their
// destructors, so that they release their references to their values.
for (SCEVUnknown *U = FirstUnknown; U;) {
SCEVUnknown *Tmp = U;
U = U->Next;
Tmp->~SCEVUnknown();
}
FirstUnknown = nullptr;
ExprValueMap.clear();
ValueExprMap.clear();
HasRecMap.clear();
BackedgeTakenCounts.clear();
PredicatedBackedgeTakenCounts.clear();
assert(PendingLoopPredicates.empty() && "isImpliedCond garbage");
assert(PendingPhiRanges.empty() && "getRangeRef garbage");
assert(PendingMerges.empty() && "isImpliedViaMerge garbage");
assert(!WalkingBEDominatingConds && "isLoopBackedgeGuardedByCond garbage!");
assert(!ProvingSplitPredicate && "ProvingSplitPredicate garbage!");
}
bool ScalarEvolution::hasLoopInvariantBackedgeTakenCount(const Loop *L) {
return !isa<SCEVCouldNotCompute>(getBackedgeTakenCount(L));
}
static void PrintLoopInfo(raw_ostream &OS, ScalarEvolution *SE,
const Loop *L) {
// Print all inner loops first
for (Loop *I : *L)
PrintLoopInfo(OS, SE, I);
OS << "Loop ";
L->getHeader()->printAsOperand(OS, /*PrintType=*/false);
OS << ": ";
SmallVector<BasicBlock *, 8> ExitingBlocks;
L->getExitingBlocks(ExitingBlocks);
if (ExitingBlocks.size() != 1)
OS << "<multiple exits> ";
if (SE->hasLoopInvariantBackedgeTakenCount(L))
OS << "backedge-taken count is " << *SE->getBackedgeTakenCount(L) << "\n";
else
OS << "Unpredictable backedge-taken count.\n";
if (ExitingBlocks.size() > 1)
for (BasicBlock *ExitingBlock : ExitingBlocks) {
OS << " exit count for " << ExitingBlock->getName() << ": "
<< *SE->getExitCount(L, ExitingBlock) << "\n";
}
OS << "Loop ";
L->getHeader()->printAsOperand(OS, /*PrintType=*/false);
OS << ": ";
if (!isa<SCEVCouldNotCompute>(SE->getConstantMaxBackedgeTakenCount(L))) {
OS << "max backedge-taken count is " << *SE->getConstantMaxBackedgeTakenCount(L);
if (SE->isBackedgeTakenCountMaxOrZero(L))
OS << ", actual taken count either this or zero.";
} else {
OS << "Unpredictable max backedge-taken count. ";
}
OS << "\n"
"Loop ";
L->getHeader()->printAsOperand(OS, /*PrintType=*/false);
OS << ": ";
SmallVector<const SCEVPredicate *, 4> Preds;
auto PBT = SE->getPredicatedBackedgeTakenCount(L, Preds);
if (!isa<SCEVCouldNotCompute>(PBT)) {
OS << "Predicated backedge-taken count is " << *PBT << "\n";
OS << " Predicates:\n";
for (const auto *P : Preds)
P->print(OS, 4);
} else {
OS << "Unpredictable predicated backedge-taken count. ";
}
OS << "\n";
if (SE->hasLoopInvariantBackedgeTakenCount(L)) {
OS << "Loop ";
L->getHeader()->printAsOperand(OS, /*PrintType=*/false);
OS << ": ";
OS << "Trip multiple is " << SE->getSmallConstantTripMultiple(L) << "\n";
}
}
static StringRef loopDispositionToStr(ScalarEvolution::LoopDisposition LD) {
switch (LD) {
case ScalarEvolution::LoopVariant:
return "Variant";
case ScalarEvolution::LoopInvariant:
return "Invariant";
case ScalarEvolution::LoopComputable:
return "Computable";
}
llvm_unreachable("Unknown ScalarEvolution::LoopDisposition kind!");
}
void ScalarEvolution::print(raw_ostream &OS) const {
// ScalarEvolution's implementation of the print method is to print
// out SCEV values of all instructions that are interesting. Doing
// this potentially causes it to create new SCEV objects though,
// which technically conflicts with the const qualifier. This isn't
// observable from outside the class though, so casting away the
// const isn't dangerous.
ScalarEvolution &SE = *const_cast<ScalarEvolution *>(this);
if (ClassifyExpressions) {
OS << "Classifying expressions for: ";
F.printAsOperand(OS, /*PrintType=*/false);
OS << "\n";
for (Instruction &I : instructions(F))
if (isSCEVable(I.getType()) && !isa<CmpInst>(I)) {
OS << I << '\n';
OS << " --> ";
const SCEV *SV = SE.getSCEV(&I);
SV->print(OS);
if (!isa<SCEVCouldNotCompute>(SV)) {
OS << " U: ";
SE.getUnsignedRange(SV).print(OS);
OS << " S: ";
SE.getSignedRange(SV).print(OS);
}
const Loop *L = LI.getLoopFor(I.getParent());
const SCEV *AtUse = SE.getSCEVAtScope(SV, L);
if (AtUse != SV) {
OS << " --> ";
AtUse->print(OS);
if (!isa<SCEVCouldNotCompute>(AtUse)) {
OS << " U: ";
SE.getUnsignedRange(AtUse).print(OS);
OS << " S: ";
SE.getSignedRange(AtUse).print(OS);
}
}
if (L) {
OS << "\t\t" "Exits: ";
const SCEV *ExitValue = SE.getSCEVAtScope(SV, L->getParentLoop());
if (!SE.isLoopInvariant(ExitValue, L)) {
OS << "<<Unknown>>";
} else {
OS << *ExitValue;
}
bool First = true;
for (const auto *Iter = L; Iter; Iter = Iter->getParentLoop()) {
if (First) {
OS << "\t\t" "LoopDispositions: { ";
First = false;
} else {
OS << ", ";
}
Iter->getHeader()->printAsOperand(OS, /*PrintType=*/false);
OS << ": " << loopDispositionToStr(SE.getLoopDisposition(SV, Iter));
}
for (const auto *InnerL : depth_first(L)) {
if (InnerL == L)
continue;
if (First) {
OS << "\t\t" "LoopDispositions: { ";
First = false;
} else {
OS << ", ";
}
InnerL->getHeader()->printAsOperand(OS, /*PrintType=*/false);
OS << ": " << loopDispositionToStr(SE.getLoopDisposition(SV, InnerL));
}
OS << " }";
}
OS << "\n";
}
}
OS << "Determining loop execution counts for: ";
F.printAsOperand(OS, /*PrintType=*/false);
OS << "\n";
for (Loop *I : LI)
PrintLoopInfo(OS, &SE, I);
}
ScalarEvolution::LoopDisposition
ScalarEvolution::getLoopDisposition(const SCEV *S, const Loop *L) {
auto &Values = LoopDispositions[S];
for (auto &V : Values) {
if (V.getPointer() == L)
return V.getInt();
}
Values.emplace_back(L, LoopVariant);
LoopDisposition D = computeLoopDisposition(S, L);
auto &Values2 = LoopDispositions[S];
for (auto &V : llvm::reverse(Values2)) {
if (V.getPointer() == L) {
V.setInt(D);
break;
}
}
return D;
}
ScalarEvolution::LoopDisposition
ScalarEvolution::computeLoopDisposition(const SCEV *S, const Loop *L) {
switch (S->getSCEVType()) {
case scConstant:
return LoopInvariant;
case scPtrToInt:
case scTruncate:
case scZeroExtend:
case scSignExtend:
return getLoopDisposition(cast<SCEVCastExpr>(S)->getOperand(), L);
case scAddRecExpr: {
const SCEVAddRecExpr *AR = cast<SCEVAddRecExpr>(S);
// If L is the addrec's loop, it's computable.
if (AR->getLoop() == L)
return LoopComputable;
// Add recurrences are never invariant in the function-body (null loop).
if (!L)
return LoopVariant;
// Everything that is not defined at loop entry is variant.
if (DT.dominates(L->getHeader(), AR->getLoop()->getHeader()))
return LoopVariant;
assert(!L->contains(AR->getLoop()) && "Containing loop's header does not"
" dominate the contained loop's header?");
// This recurrence is invariant w.r.t. L if AR's loop contains L.
if (AR->getLoop()->contains(L))
return LoopInvariant;
// This recurrence is variant w.r.t. L if any of its operands
// are variant.
for (const auto *Op : AR->operands())
if (!isLoopInvariant(Op, L))
return LoopVariant;
// Otherwise it's loop-invariant.
return LoopInvariant;
}
case scAddExpr:
case scMulExpr:
case scUMaxExpr:
case scSMaxExpr:
case scUMinExpr:
case scSMinExpr:
case scSequentialUMinExpr: {
bool HasVarying = false;
for (const auto *Op : cast<SCEVNAryExpr>(S)->operands()) {
LoopDisposition D = getLoopDisposition(Op, L);
if (D == LoopVariant)
return LoopVariant;
if (D == LoopComputable)
HasVarying = true;
}
return HasVarying ? LoopComputable : LoopInvariant;
}
case scUDivExpr: {
const SCEVUDivExpr *UDiv = cast<SCEVUDivExpr>(S);
LoopDisposition LD = getLoopDisposition(UDiv->getLHS(), L);
if (LD == LoopVariant)
return LoopVariant;
LoopDisposition RD = getLoopDisposition(UDiv->getRHS(), L);
if (RD == LoopVariant)
return LoopVariant;
return (LD == LoopInvariant && RD == LoopInvariant) ?
LoopInvariant : LoopComputable;
}
case scUnknown:
// All non-instruction values are loop invariant. All instructions are loop
// invariant if they are not contained in the specified loop.
// Instructions are never considered invariant in the function body
// (null loop) because they are defined within the "loop".
if (auto *I = dyn_cast<Instruction>(cast<SCEVUnknown>(S)->getValue()))
return (L && !L->contains(I)) ? LoopInvariant : LoopVariant;
return LoopInvariant;
case scCouldNotCompute:
llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!");
}
llvm_unreachable("Unknown SCEV kind!");
}
bool ScalarEvolution::isLoopInvariant(const SCEV *S, const Loop *L) {
return getLoopDisposition(S, L) == LoopInvariant;
}
bool ScalarEvolution::hasComputableLoopEvolution(const SCEV *S, const Loop *L) {
return getLoopDisposition(S, L) == LoopComputable;
}
ScalarEvolution::BlockDisposition
ScalarEvolution::getBlockDisposition(const SCEV *S, const BasicBlock *BB) {
auto &Values = BlockDispositions[S];
for (auto &V : Values) {
if (V.getPointer() == BB)
return V.getInt();
}
Values.emplace_back(BB, DoesNotDominateBlock);
BlockDisposition D = computeBlockDisposition(S, BB);
auto &Values2 = BlockDispositions[S];
for (auto &V : llvm::reverse(Values2)) {
if (V.getPointer() == BB) {
V.setInt(D);
break;
}
}
return D;
}
ScalarEvolution::BlockDisposition
ScalarEvolution::computeBlockDisposition(const SCEV *S, const BasicBlock *BB) {
switch (S->getSCEVType()) {
case scConstant:
return ProperlyDominatesBlock;
case scPtrToInt:
case scTruncate:
case scZeroExtend:
case scSignExtend:
return getBlockDisposition(cast<SCEVCastExpr>(S)->getOperand(), BB);
case scAddRecExpr: {
// This uses a "dominates" query instead of "properly dominates" query
// to test for proper dominance too, because the instruction which
// produces the addrec's value is a PHI, and a PHI effectively properly
// dominates its entire containing block.
const SCEVAddRecExpr *AR = cast<SCEVAddRecExpr>(S);
if (!DT.dominates(AR->getLoop()->getHeader(), BB))
return DoesNotDominateBlock;
// Fall through into SCEVNAryExpr handling.
LLVM_FALLTHROUGH;
}
case scAddExpr:
case scMulExpr:
case scUMaxExpr:
case scSMaxExpr:
case scUMinExpr:
case scSMinExpr:
case scSequentialUMinExpr: {
const SCEVNAryExpr *NAry = cast<SCEVNAryExpr>(S);
bool Proper = true;
for (const SCEV *NAryOp : NAry->operands()) {
BlockDisposition D = getBlockDisposition(NAryOp, BB);
if (D == DoesNotDominateBlock)
return DoesNotDominateBlock;
if (D == DominatesBlock)
Proper = false;
}
return Proper ? ProperlyDominatesBlock : DominatesBlock;
}
case scUDivExpr: {
const SCEVUDivExpr *UDiv = cast<SCEVUDivExpr>(S);
const SCEV *LHS = UDiv->getLHS(), *RHS = UDiv->getRHS();
BlockDisposition LD = getBlockDisposition(LHS, BB);
if (LD == DoesNotDominateBlock)
return DoesNotDominateBlock;
BlockDisposition RD = getBlockDisposition(RHS, BB);
if (RD == DoesNotDominateBlock)
return DoesNotDominateBlock;
return (LD == ProperlyDominatesBlock && RD == ProperlyDominatesBlock) ?
ProperlyDominatesBlock : DominatesBlock;
}
case scUnknown:
if (Instruction *I =
dyn_cast<Instruction>(cast<SCEVUnknown>(S)->getValue())) {
if (I->getParent() == BB)
return DominatesBlock;
if (DT.properlyDominates(I->getParent(), BB))
return ProperlyDominatesBlock;
return DoesNotDominateBlock;
}
return ProperlyDominatesBlock;
case scCouldNotCompute:
llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!");
}
llvm_unreachable("Unknown SCEV kind!");
}
bool ScalarEvolution::dominates(const SCEV *S, const BasicBlock *BB) {
return getBlockDisposition(S, BB) >= DominatesBlock;
}
bool ScalarEvolution::properlyDominates(const SCEV *S, const BasicBlock *BB) {
return getBlockDisposition(S, BB) == ProperlyDominatesBlock;
}
bool ScalarEvolution::hasOperand(const SCEV *S, const SCEV *Op) const {
return SCEVExprContains(S, [&](const SCEV *Expr) { return Expr == Op; });
}
void ScalarEvolution::forgetBackedgeTakenCounts(const Loop *L,
bool Predicated) {
auto &BECounts =
Predicated ? PredicatedBackedgeTakenCounts : BackedgeTakenCounts;
auto It = BECounts.find(L);
if (It != BECounts.end()) {
for (const ExitNotTakenInfo &ENT : It->second.ExitNotTaken) {
if (!isa<SCEVConstant>(ENT.ExactNotTaken)) {
auto UserIt = BECountUsers.find(ENT.ExactNotTaken);
assert(UserIt != BECountUsers.end());
UserIt->second.erase({L, Predicated});
}
}
BECounts.erase(It);
}
}
void ScalarEvolution::forgetMemoizedResults(ArrayRef<const SCEV *> SCEVs) {
SmallPtrSet<const SCEV *, 8> ToForget(SCEVs.begin(), SCEVs.end());
SmallVector<const SCEV *, 8> Worklist(ToForget.begin(), ToForget.end());
while (!Worklist.empty()) {
const SCEV *Curr = Worklist.pop_back_val();
auto Users = SCEVUsers.find(Curr);
if (Users != SCEVUsers.end())
for (const auto *User : Users->second)
if (ToForget.insert(User).second)
Worklist.push_back(User);
}
for (const auto *S : ToForget)
forgetMemoizedResultsImpl(S);
for (auto I = PredicatedSCEVRewrites.begin();
I != PredicatedSCEVRewrites.end();) {
std::pair<const SCEV *, const Loop *> Entry = I->first;
if (ToForget.count(Entry.first))
PredicatedSCEVRewrites.erase(I++);
else
++I;
}
}
void ScalarEvolution::forgetMemoizedResultsImpl(const SCEV *S) {
LoopDispositions.erase(S);
BlockDispositions.erase(S);
UnsignedRanges.erase(S);
SignedRanges.erase(S);
HasRecMap.erase(S);
MinTrailingZerosCache.erase(S);
auto ExprIt = ExprValueMap.find(S);
if (ExprIt != ExprValueMap.end()) {
for (Value *V : ExprIt->second) {
auto ValueIt = ValueExprMap.find_as(V);
if (ValueIt != ValueExprMap.end())
ValueExprMap.erase(ValueIt);
}
ExprValueMap.erase(ExprIt);
}
auto ScopeIt = ValuesAtScopes.find(S);
if (ScopeIt != ValuesAtScopes.end()) {
for (const auto &Pair : ScopeIt->second)
if (!isa_and_nonnull<SCEVConstant>(Pair.second))
erase_value(ValuesAtScopesUsers[Pair.second],
std::make_pair(Pair.first, S));
ValuesAtScopes.erase(ScopeIt);
}
auto ScopeUserIt = ValuesAtScopesUsers.find(S);
if (ScopeUserIt != ValuesAtScopesUsers.end()) {
for (const auto &Pair : ScopeUserIt->second)
erase_value(ValuesAtScopes[Pair.second], std::make_pair(Pair.first, S));
ValuesAtScopesUsers.erase(ScopeUserIt);
}
auto BEUsersIt = BECountUsers.find(S);
if (BEUsersIt != BECountUsers.end()) {
// Work on a copy, as forgetBackedgeTakenCounts() will modify the original.
auto Copy = BEUsersIt->second;
for (const auto &Pair : Copy)
forgetBackedgeTakenCounts(Pair.getPointer(), Pair.getInt());
BECountUsers.erase(BEUsersIt);
}
}
void
ScalarEvolution::getUsedLoops(const SCEV *S,
SmallPtrSetImpl<const Loop *> &LoopsUsed) {
struct FindUsedLoops {
FindUsedLoops(SmallPtrSetImpl<const Loop *> &LoopsUsed)
: LoopsUsed(LoopsUsed) {}
SmallPtrSetImpl<const Loop *> &LoopsUsed;
bool follow(const SCEV *S) {
if (auto *AR = dyn_cast<SCEVAddRecExpr>(S))
LoopsUsed.insert(AR->getLoop());
return true;
}
bool isDone() const { return false; }
};
FindUsedLoops F(LoopsUsed);
SCEVTraversal<FindUsedLoops>(F).visitAll(S);
}
void ScalarEvolution::getReachableBlocks(
SmallPtrSetImpl<BasicBlock *> &Reachable, Function &F) {
SmallVector<BasicBlock *> Worklist;
Worklist.push_back(&F.getEntryBlock());
while (!Worklist.empty()) {
BasicBlock *BB = Worklist.pop_back_val();
if (!Reachable.insert(BB).second)
continue;
Value *Cond;
BasicBlock *TrueBB, *FalseBB;
if (match(BB->getTerminator(), m_Br(m_Value(Cond), m_BasicBlock(TrueBB),
m_BasicBlock(FalseBB)))) {
if (auto *C = dyn_cast<ConstantInt>(Cond)) {
Worklist.push_back(C->isOne() ? TrueBB : FalseBB);
continue;
}
if (auto *Cmp = dyn_cast<ICmpInst>(Cond)) {
const SCEV *L = getSCEV(Cmp->getOperand(0));
const SCEV *R = getSCEV(Cmp->getOperand(1));
if (isKnownPredicateViaConstantRanges(Cmp->getPredicate(), L, R)) {
Worklist.push_back(TrueBB);
continue;
}
if (isKnownPredicateViaConstantRanges(Cmp->getInversePredicate(), L,
R)) {
Worklist.push_back(FalseBB);
continue;
}
}
}
append_range(Worklist, successors(BB));
}
}
void ScalarEvolution::verify() const {
ScalarEvolution &SE = *const_cast<ScalarEvolution *>(this);
ScalarEvolution SE2(F, TLI, AC, DT, LI);
SmallVector<Loop *, 8> LoopStack(LI.begin(), LI.end());
// Map's SCEV expressions from one ScalarEvolution "universe" to another.
struct SCEVMapper : public SCEVRewriteVisitor<SCEVMapper> {
SCEVMapper(ScalarEvolution &SE) : SCEVRewriteVisitor<SCEVMapper>(SE) {}
const SCEV *visitConstant(const SCEVConstant *Constant) {
return SE.getConstant(Constant->getAPInt());
}
const SCEV *visitUnknown(const SCEVUnknown *Expr) {
return SE.getUnknown(Expr->getValue());
}
const SCEV *visitCouldNotCompute(const SCEVCouldNotCompute *Expr) {
return SE.getCouldNotCompute();
}
};
SCEVMapper SCM(SE2);
SmallPtrSet<BasicBlock *, 16> ReachableBlocks;
SE2.getReachableBlocks(ReachableBlocks, F);
auto GetDelta = [&](const SCEV *Old, const SCEV *New) -> const SCEV * {
if (containsUndefs(Old) || containsUndefs(New)) {
// SCEV treats "undef" as an unknown but consistent value (i.e. it does
// not propagate undef aggressively). This means we can (and do) fail
// verification in cases where a transform makes a value go from "undef"
// to "undef+1" (say). The transform is fine, since in both cases the
// result is "undef", but SCEV thinks the value increased by 1.
return nullptr;
}
// Unless VerifySCEVStrict is set, we only compare constant deltas.
const SCEV *Delta = SE2.getMinusSCEV(Old, New);
if (!VerifySCEVStrict && !isa<SCEVConstant>(Delta))
return nullptr;
return Delta;
};
while (!LoopStack.empty()) {
auto *L = LoopStack.pop_back_val();
llvm::append_range(LoopStack, *L);
// Only verify BECounts in reachable loops. For an unreachable loop,
// any BECount is legal.
if (!ReachableBlocks.contains(L->getHeader()))
continue;
// Only verify cached BECounts. Computing new BECounts may change the
// results of subsequent SCEV uses.
auto It = BackedgeTakenCounts.find(L);
if (It == BackedgeTakenCounts.end())
continue;
auto *CurBECount =
SCM.visit(It->second.getExact(L, const_cast<ScalarEvolution *>(this)));
auto *NewBECount = SE2.getBackedgeTakenCount(L);
if (CurBECount == SE2.getCouldNotCompute() ||
NewBECount == SE2.getCouldNotCompute()) {
// NB! This situation is legal, but is very suspicious -- whatever pass
// change the loop to make a trip count go from could not compute to
// computable or vice-versa *should have* invalidated SCEV. However, we
// choose not to assert here (for now) since we don't want false
// positives.
continue;
}
if (SE.getTypeSizeInBits(CurBECount->getType()) >
SE.getTypeSizeInBits(NewBECount->getType()))
NewBECount = SE2.getZeroExtendExpr(NewBECount, CurBECount->getType());
else if (SE.getTypeSizeInBits(CurBECount->getType()) <
SE.getTypeSizeInBits(NewBECount->getType()))
CurBECount = SE2.getZeroExtendExpr(CurBECount, NewBECount->getType());
const SCEV *Delta = GetDelta(CurBECount, NewBECount);
if (Delta && !Delta->isZero()) {
dbgs() << "Trip Count for " << *L << " Changed!\n";
dbgs() << "Old: " << *CurBECount << "\n";
dbgs() << "New: " << *NewBECount << "\n";
dbgs() << "Delta: " << *Delta << "\n";
std::abort();
}
}
// Collect all valid loops currently in LoopInfo.
SmallPtrSet<Loop *, 32> ValidLoops;
SmallVector<Loop *, 32> Worklist(LI.begin(), LI.end());
while (!Worklist.empty()) {
Loop *L = Worklist.pop_back_val();
if (ValidLoops.insert(L).second)
Worklist.append(L->begin(), L->end());
}
for (const auto &KV : ValueExprMap) {
#ifndef NDEBUG
// Check for SCEV expressions referencing invalid/deleted loops.
if (auto *AR = dyn_cast<SCEVAddRecExpr>(KV.second)) {
assert(ValidLoops.contains(AR->getLoop()) &&
"AddRec references invalid loop");
}
#endif
// Check that the value is also part of the reverse map.
auto It = ExprValueMap.find(KV.second);
if (It == ExprValueMap.end() || !It->second.contains(KV.first)) {
dbgs() << "Value " << *KV.first
<< " is in ValueExprMap but not in ExprValueMap\n";
std::abort();
}
if (auto *I = dyn_cast<Instruction>(&*KV.first)) {
if (!ReachableBlocks.contains(I->getParent()))
continue;
const SCEV *OldSCEV = SCM.visit(KV.second);
const SCEV *NewSCEV = SE2.getSCEV(I);
const SCEV *Delta = GetDelta(OldSCEV, NewSCEV);
if (Delta && !Delta->isZero()) {
dbgs() << "SCEV for value " << *I << " changed!\n"
<< "Old: " << *OldSCEV << "\n"
<< "New: " << *NewSCEV << "\n"
<< "Delta: " << *Delta << "\n";
std::abort();
}
}
}
for (const auto &KV : ExprValueMap) {
for (Value *V : KV.second) {
auto It = ValueExprMap.find_as(V);
if (It == ValueExprMap.end()) {
dbgs() << "Value " << *V
<< " is in ExprValueMap but not in ValueExprMap\n";
std::abort();
}
if (It->second != KV.first) {
dbgs() << "Value " << *V << " mapped to " << *It->second
<< " rather than " << *KV.first << "\n";
std::abort();
}
}
}
// Verify integrity of SCEV users.
for (const auto &S : UniqueSCEVs) {
SmallVector<const SCEV *, 4> Ops;
collectUniqueOps(&S, Ops);
for (const auto *Op : Ops) {
// We do not store dependencies of constants.
if (isa<SCEVConstant>(Op))
continue;
auto It = SCEVUsers.find(Op);
if (It != SCEVUsers.end() && It->second.count(&S))
continue;
dbgs() << "Use of operand " << *Op << " by user " << S
<< " is not being tracked!\n";
std::abort();
}
}
// Verify integrity of ValuesAtScopes users.
for (const auto &ValueAndVec : ValuesAtScopes) {
const SCEV *Value = ValueAndVec.first;
for (const auto &LoopAndValueAtScope : ValueAndVec.second) {
const Loop *L = LoopAndValueAtScope.first;
const SCEV *ValueAtScope = LoopAndValueAtScope.second;
if (!isa<SCEVConstant>(ValueAtScope)) {
auto It = ValuesAtScopesUsers.find(ValueAtScope);
if (It != ValuesAtScopesUsers.end() &&
is_contained(It->second, std::make_pair(L, Value)))
continue;
dbgs() << "Value: " << *Value << ", Loop: " << *L << ", ValueAtScope: "
<< *ValueAtScope << " missing in ValuesAtScopesUsers\n";
std::abort();
}
}
}
for (const auto &ValueAtScopeAndVec : ValuesAtScopesUsers) {
const SCEV *ValueAtScope = ValueAtScopeAndVec.first;
for (const auto &LoopAndValue : ValueAtScopeAndVec.second) {
const Loop *L = LoopAndValue.first;
const SCEV *Value = LoopAndValue.second;
assert(!isa<SCEVConstant>(Value));
auto It = ValuesAtScopes.find(Value);
if (It != ValuesAtScopes.end() &&
is_contained(It->second, std::make_pair(L, ValueAtScope)))
continue;
dbgs() << "Value: " << *Value << ", Loop: " << *L << ", ValueAtScope: "
<< *ValueAtScope << " missing in ValuesAtScopes\n";
std::abort();
}
}
// Verify integrity of BECountUsers.
auto VerifyBECountUsers = [&](bool Predicated) {
auto &BECounts =
Predicated ? PredicatedBackedgeTakenCounts : BackedgeTakenCounts;
for (const auto &LoopAndBEInfo : BECounts) {
for (const ExitNotTakenInfo &ENT : LoopAndBEInfo.second.ExitNotTaken) {
if (!isa<SCEVConstant>(ENT.ExactNotTaken)) {
auto UserIt = BECountUsers.find(ENT.ExactNotTaken);
if (UserIt != BECountUsers.end() &&
UserIt->second.contains({ LoopAndBEInfo.first, Predicated }))
continue;
dbgs() << "Value " << *ENT.ExactNotTaken << " for loop "
<< *LoopAndBEInfo.first << " missing from BECountUsers\n";
std::abort();
}
}
}
};
VerifyBECountUsers(/* Predicated */ false);
VerifyBECountUsers(/* Predicated */ true);
}
bool ScalarEvolution::invalidate(
Function &F, const PreservedAnalyses &PA,
FunctionAnalysisManager::Invalidator &Inv) {
// Invalidate the ScalarEvolution object whenever it isn't preserved or one
// of its dependencies is invalidated.
auto PAC = PA.getChecker<ScalarEvolutionAnalysis>();
return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>()) ||
Inv.invalidate<AssumptionAnalysis>(F, PA) ||
Inv.invalidate<DominatorTreeAnalysis>(F, PA) ||
Inv.invalidate<LoopAnalysis>(F, PA);
}
AnalysisKey ScalarEvolutionAnalysis::Key;
ScalarEvolution ScalarEvolutionAnalysis::run(Function &F,
FunctionAnalysisManager &AM) {
return ScalarEvolution(F, AM.getResult<TargetLibraryAnalysis>(F),
AM.getResult<AssumptionAnalysis>(F),
AM.getResult<DominatorTreeAnalysis>(F),
AM.getResult<LoopAnalysis>(F));
}
PreservedAnalyses
ScalarEvolutionVerifierPass::run(Function &F, FunctionAnalysisManager &AM) {
AM.getResult<ScalarEvolutionAnalysis>(F).verify();
return PreservedAnalyses::all();
}
PreservedAnalyses
ScalarEvolutionPrinterPass::run(Function &F, FunctionAnalysisManager &AM) {
// For compatibility with opt's -analyze feature under legacy pass manager
// which was not ported to NPM. This keeps tests using
// update_analyze_test_checks.py working.
OS << "Printing analysis 'Scalar Evolution Analysis' for function '"
<< F.getName() << "':\n";
AM.getResult<ScalarEvolutionAnalysis>(F).print(OS);
return PreservedAnalyses::all();
}
INITIALIZE_PASS_BEGIN(ScalarEvolutionWrapperPass, "scalar-evolution",
"Scalar Evolution Analysis", false, true)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(ScalarEvolutionWrapperPass, "scalar-evolution",
"Scalar Evolution Analysis", false, true)
char ScalarEvolutionWrapperPass::ID = 0;
ScalarEvolutionWrapperPass::ScalarEvolutionWrapperPass() : FunctionPass(ID) {
initializeScalarEvolutionWrapperPassPass(*PassRegistry::getPassRegistry());
}
bool ScalarEvolutionWrapperPass::runOnFunction(Function &F) {
SE.reset(new ScalarEvolution(
F, getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F),
getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F),
getAnalysis<DominatorTreeWrapperPass>().getDomTree(),
getAnalysis<LoopInfoWrapperPass>().getLoopInfo()));
return false;
}
void ScalarEvolutionWrapperPass::releaseMemory() { SE.reset(); }
void ScalarEvolutionWrapperPass::print(raw_ostream &OS, const Module *) const {
SE->print(OS);
}
void ScalarEvolutionWrapperPass::verifyAnalysis() const {
if (!VerifySCEV)
return;
SE->verify();
}
void ScalarEvolutionWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequiredTransitive<AssumptionCacheTracker>();
AU.addRequiredTransitive<LoopInfoWrapperPass>();
AU.addRequiredTransitive<DominatorTreeWrapperPass>();
AU.addRequiredTransitive<TargetLibraryInfoWrapperPass>();
}
const SCEVPredicate *ScalarEvolution::getEqualPredicate(const SCEV *LHS,
const SCEV *RHS) {
return getComparePredicate(ICmpInst::ICMP_EQ, LHS, RHS);
}
const SCEVPredicate *
ScalarEvolution::getComparePredicate(const ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS) {
FoldingSetNodeID ID;
assert(LHS->getType() == RHS->getType() &&
"Type mismatch between LHS and RHS");
// Unique this node based on the arguments
ID.AddInteger(SCEVPredicate::P_Compare);
ID.AddInteger(Pred);
ID.AddPointer(LHS);
ID.AddPointer(RHS);
void *IP = nullptr;
if (const auto *S = UniquePreds.FindNodeOrInsertPos(ID, IP))
return S;
SCEVComparePredicate *Eq = new (SCEVAllocator)
SCEVComparePredicate(ID.Intern(SCEVAllocator), Pred, LHS, RHS);
UniquePreds.InsertNode(Eq, IP);
return Eq;
}
const SCEVPredicate *ScalarEvolution::getWrapPredicate(
const SCEVAddRecExpr *AR,
SCEVWrapPredicate::IncrementWrapFlags AddedFlags) {
FoldingSetNodeID ID;
// Unique this node based on the arguments
ID.AddInteger(SCEVPredicate::P_Wrap);
ID.AddPointer(AR);
ID.AddInteger(AddedFlags);
void *IP = nullptr;
if (const auto *S = UniquePreds.FindNodeOrInsertPos(ID, IP))
return S;
auto *OF = new (SCEVAllocator)
SCEVWrapPredicate(ID.Intern(SCEVAllocator), AR, AddedFlags);
UniquePreds.InsertNode(OF, IP);
return OF;
}
namespace {
class SCEVPredicateRewriter : public SCEVRewriteVisitor<SCEVPredicateRewriter> {
public:
/// Rewrites \p S in the context of a loop L and the SCEV predication
/// infrastructure.
///
/// If \p Pred is non-null, the SCEV expression is rewritten to respect the
/// equivalences present in \p Pred.
///
/// If \p NewPreds is non-null, rewrite is free to add further predicates to
/// \p NewPreds such that the result will be an AddRecExpr.
static const SCEV *rewrite(const SCEV *S, const Loop *L, ScalarEvolution &SE,
SmallPtrSetImpl<const SCEVPredicate *> *NewPreds,
const SCEVPredicate *Pred) {
SCEVPredicateRewriter Rewriter(L, SE, NewPreds, Pred);
return Rewriter.visit(S);
}
const SCEV *visitUnknown(const SCEVUnknown *Expr) {
if (Pred) {
if (auto *U = dyn_cast<SCEVUnionPredicate>(Pred)) {
for (const auto *Pred : U->getPredicates())
if (const auto *IPred = dyn_cast<SCEVComparePredicate>(Pred))
if (IPred->getLHS() == Expr &&
IPred->getPredicate() == ICmpInst::ICMP_EQ)
return IPred->getRHS();
} else if (const auto *IPred = dyn_cast<SCEVComparePredicate>(Pred)) {
if (IPred->getLHS() == Expr &&
IPred->getPredicate() == ICmpInst::ICMP_EQ)
return IPred->getRHS();
}
}
return convertToAddRecWithPreds(Expr);
}
const SCEV *visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
const SCEV *Operand = visit(Expr->getOperand());
const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(Operand);
if (AR && AR->getLoop() == L && AR->isAffine()) {
// This couldn't be folded because the operand didn't have the nuw
// flag. Add the nusw flag as an assumption that we could make.
const SCEV *Step = AR->getStepRecurrence(SE);
Type *Ty = Expr->getType();
if (addOverflowAssumption(AR, SCEVWrapPredicate::IncrementNUSW))
return SE.getAddRecExpr(SE.getZeroExtendExpr(AR->getStart(), Ty),
SE.getSignExtendExpr(Step, Ty), L,
AR->getNoWrapFlags());
}
return SE.getZeroExtendExpr(Operand, Expr->getType());
}
const SCEV *visitSignExtendExpr(const SCEVSignExtendExpr *Expr) {
const SCEV *Operand = visit(Expr->getOperand());
const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(Operand);
if (AR && AR->getLoop() == L && AR->isAffine()) {
// This couldn't be folded because the operand didn't have the nsw
// flag. Add the nssw flag as an assumption that we could make.
const SCEV *Step = AR->getStepRecurrence(SE);
Type *Ty = Expr->getType();
if (addOverflowAssumption(AR, SCEVWrapPredicate::IncrementNSSW))
return SE.getAddRecExpr(SE.getSignExtendExpr(AR->getStart(), Ty),
SE.getSignExtendExpr(Step, Ty), L,
AR->getNoWrapFlags());
}
return SE.getSignExtendExpr(Operand, Expr->getType());
}
private:
explicit SCEVPredicateRewriter(const Loop *L, ScalarEvolution &SE,
SmallPtrSetImpl<const SCEVPredicate *> *NewPreds,
const SCEVPredicate *Pred)
: SCEVRewriteVisitor(SE), NewPreds(NewPreds), Pred(Pred), L(L) {}
bool addOverflowAssumption(const SCEVPredicate *P) {
if (!NewPreds) {
// Check if we've already made this assumption.
return Pred && Pred->implies(P);
}
NewPreds->insert(P);
return true;
}
bool addOverflowAssumption(const SCEVAddRecExpr *AR,
SCEVWrapPredicate::IncrementWrapFlags AddedFlags) {
auto *A = SE.getWrapPredicate(AR, AddedFlags);
return addOverflowAssumption(A);
}
// If \p Expr represents a PHINode, we try to see if it can be represented
// as an AddRec, possibly under a predicate (PHISCEVPred). If it is possible
// to add this predicate as a runtime overflow check, we return the AddRec.
// If \p Expr does not meet these conditions (is not a PHI node, or we
// couldn't create an AddRec for it, or couldn't add the predicate), we just
// return \p Expr.
const SCEV *convertToAddRecWithPreds(const SCEVUnknown *Expr) {
if (!isa<PHINode>(Expr->getValue()))
return Expr;
Optional<std::pair<const SCEV *, SmallVector<const SCEVPredicate *, 3>>>
PredicatedRewrite = SE.createAddRecFromPHIWithCasts(Expr);
if (!PredicatedRewrite)
return Expr;
for (const auto *P : PredicatedRewrite->second){
// Wrap predicates from outer loops are not supported.
if (auto *WP = dyn_cast<const SCEVWrapPredicate>(P)) {
if (L != WP->getExpr()->getLoop())
return Expr;
}
if (!addOverflowAssumption(P))
return Expr;
}
return PredicatedRewrite->first;
}
SmallPtrSetImpl<const SCEVPredicate *> *NewPreds;
const SCEVPredicate *Pred;
const Loop *L;
};
} // end anonymous namespace
const SCEV *
ScalarEvolution::rewriteUsingPredicate(const SCEV *S, const Loop *L,
const SCEVPredicate &Preds) {
return SCEVPredicateRewriter::rewrite(S, L, *this, nullptr, &Preds);
}
const SCEVAddRecExpr *ScalarEvolution::convertSCEVToAddRecWithPredicates(
const SCEV *S, const Loop *L,
SmallPtrSetImpl<const SCEVPredicate *> &Preds) {
SmallPtrSet<const SCEVPredicate *, 4> TransformPreds;
S = SCEVPredicateRewriter::rewrite(S, L, *this, &TransformPreds, nullptr);
auto *AddRec = dyn_cast<SCEVAddRecExpr>(S);
if (!AddRec)
return nullptr;
// Since the transformation was successful, we can now transfer the SCEV
// predicates.
for (const auto *P : TransformPreds)
Preds.insert(P);
return AddRec;
}
/// SCEV predicates
SCEVPredicate::SCEVPredicate(const FoldingSetNodeIDRef ID,
SCEVPredicateKind Kind)
: FastID(ID), Kind(Kind) {}
SCEVComparePredicate::SCEVComparePredicate(const FoldingSetNodeIDRef ID,
const ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS)
: SCEVPredicate(ID, P_Compare), Pred(Pred), LHS(LHS), RHS(RHS) {
assert(LHS->getType() == RHS->getType() && "LHS and RHS types don't match");
assert(LHS != RHS && "LHS and RHS are the same SCEV");
}
bool SCEVComparePredicate::implies(const SCEVPredicate *N) const {
const auto *Op = dyn_cast<SCEVComparePredicate>(N);
if (!Op)
return false;
if (Pred != ICmpInst::ICMP_EQ)
return false;
return Op->LHS == LHS && Op->RHS == RHS;
}
bool SCEVComparePredicate::isAlwaysTrue() const { return false; }
void SCEVComparePredicate::print(raw_ostream &OS, unsigned Depth) const {
if (Pred == ICmpInst::ICMP_EQ)
OS.indent(Depth) << "Equal predicate: " << *LHS << " == " << *RHS << "\n";
else
OS.indent(Depth) << "Compare predicate: " << *LHS
<< " " << CmpInst::getPredicateName(Pred) << ") "
<< *RHS << "\n";
}
SCEVWrapPredicate::SCEVWrapPredicate(const FoldingSetNodeIDRef ID,
const SCEVAddRecExpr *AR,
IncrementWrapFlags Flags)
: SCEVPredicate(ID, P_Wrap), AR(AR), Flags(Flags) {}
const SCEVAddRecExpr *SCEVWrapPredicate::getExpr() const { return AR; }
bool SCEVWrapPredicate::implies(const SCEVPredicate *N) const {
const auto *Op = dyn_cast<SCEVWrapPredicate>(N);
return Op && Op->AR == AR && setFlags(Flags, Op->Flags) == Flags;
}
bool SCEVWrapPredicate::isAlwaysTrue() const {
SCEV::NoWrapFlags ScevFlags = AR->getNoWrapFlags();
IncrementWrapFlags IFlags = Flags;
if (ScalarEvolution::setFlags(ScevFlags, SCEV::FlagNSW) == ScevFlags)
IFlags = clearFlags(IFlags, IncrementNSSW);
return IFlags == IncrementAnyWrap;
}
void SCEVWrapPredicate::print(raw_ostream &OS, unsigned Depth) const {
OS.indent(Depth) << *getExpr() << " Added Flags: ";
if (SCEVWrapPredicate::IncrementNUSW & getFlags())
OS << "<nusw>";
if (SCEVWrapPredicate::IncrementNSSW & getFlags())
OS << "<nssw>";
OS << "\n";
}
SCEVWrapPredicate::IncrementWrapFlags
SCEVWrapPredicate::getImpliedFlags(const SCEVAddRecExpr *AR,
ScalarEvolution &SE) {
IncrementWrapFlags ImpliedFlags = IncrementAnyWrap;
SCEV::NoWrapFlags StaticFlags = AR->getNoWrapFlags();
// We can safely transfer the NSW flag as NSSW.
if (ScalarEvolution::setFlags(StaticFlags, SCEV::FlagNSW) == StaticFlags)
ImpliedFlags = IncrementNSSW;
if (ScalarEvolution::setFlags(StaticFlags, SCEV::FlagNUW) == StaticFlags) {
// If the increment is positive, the SCEV NUW flag will also imply the
// WrapPredicate NUSW flag.
if (const auto *Step = dyn_cast<SCEVConstant>(AR->getStepRecurrence(SE)))
if (Step->getValue()->getValue().isNonNegative())
ImpliedFlags = setFlags(ImpliedFlags, IncrementNUSW);
}
return ImpliedFlags;
}
/// Union predicates don't get cached so create a dummy set ID for it.
SCEVUnionPredicate::SCEVUnionPredicate(ArrayRef<const SCEVPredicate *> Preds)
: SCEVPredicate(FoldingSetNodeIDRef(nullptr, 0), P_Union) {
for (const auto *P : Preds)
add(P);
}
bool SCEVUnionPredicate::isAlwaysTrue() const {
return all_of(Preds,
[](const SCEVPredicate *I) { return I->isAlwaysTrue(); });
}
bool SCEVUnionPredicate::implies(const SCEVPredicate *N) const {
if (const auto *Set = dyn_cast<SCEVUnionPredicate>(N))
return all_of(Set->Preds,
[this](const SCEVPredicate *I) { return this->implies(I); });
return any_of(Preds,
[N](const SCEVPredicate *I) { return I->implies(N); });
}
void SCEVUnionPredicate::print(raw_ostream &OS, unsigned Depth) const {
for (const auto *Pred : Preds)
Pred->print(OS, Depth);
}
void SCEVUnionPredicate::add(const SCEVPredicate *N) {
if (const auto *Set = dyn_cast<SCEVUnionPredicate>(N)) {
for (const auto *Pred : Set->Preds)
add(Pred);
return;
}
Preds.push_back(N);
}
PredicatedScalarEvolution::PredicatedScalarEvolution(ScalarEvolution &SE,
Loop &L)
: SE(SE), L(L) {
SmallVector<const SCEVPredicate*, 4> Empty;
Preds = std::make_unique<SCEVUnionPredicate>(Empty);
}
void ScalarEvolution::registerUser(const SCEV *User,
ArrayRef<const SCEV *> Ops) {
for (const auto *Op : Ops)
// We do not expect that forgetting cached data for SCEVConstants will ever
// open any prospects for sharpening or introduce any correctness issues,
// so we don't bother storing their dependencies.
if (!isa<SCEVConstant>(Op))
SCEVUsers[Op].insert(User);
}
const SCEV *PredicatedScalarEvolution::getSCEV(Value *V) {
const SCEV *Expr = SE.getSCEV(V);
RewriteEntry &Entry = RewriteMap[Expr];
// If we already have an entry and the version matches, return it.
if (Entry.second && Generation == Entry.first)
return Entry.second;
// We found an entry but it's stale. Rewrite the stale entry
// according to the current predicate.
if (Entry.second)
Expr = Entry.second;
const SCEV *NewSCEV = SE.rewriteUsingPredicate(Expr, &L, *Preds);
Entry = {Generation, NewSCEV};
return NewSCEV;
}
const SCEV *PredicatedScalarEvolution::getBackedgeTakenCount() {
if (!BackedgeCount) {
SmallVector<const SCEVPredicate *, 4> Preds;
BackedgeCount = SE.getPredicatedBackedgeTakenCount(&L, Preds);
for (const auto *P : Preds)
addPredicate(*P);
}
return BackedgeCount;
}
void PredicatedScalarEvolution::addPredicate(const SCEVPredicate &Pred) {
if (Preds->implies(&Pred))
return;
auto &OldPreds = Preds->getPredicates();
SmallVector<const SCEVPredicate*, 4> NewPreds(OldPreds.begin(), OldPreds.end());
NewPreds.push_back(&Pred);
Preds = std::make_unique<SCEVUnionPredicate>(NewPreds);
updateGeneration();
}
const SCEVPredicate &PredicatedScalarEvolution::getPredicate() const {
return *Preds;
}
void PredicatedScalarEvolution::updateGeneration() {
// If the generation number wrapped recompute everything.
if (++Generation == 0) {
for (auto &II : RewriteMap) {
const SCEV *Rewritten = II.second.second;
II.second = {Generation, SE.rewriteUsingPredicate(Rewritten, &L, *Preds)};
}
}
}
void PredicatedScalarEvolution::setNoOverflow(
Value *V, SCEVWrapPredicate::IncrementWrapFlags Flags) {
const SCEV *Expr = getSCEV(V);
const auto *AR = cast<SCEVAddRecExpr>(Expr);
auto ImpliedFlags = SCEVWrapPredicate::getImpliedFlags(AR, SE);
// Clear the statically implied flags.
Flags = SCEVWrapPredicate::clearFlags(Flags, ImpliedFlags);
addPredicate(*SE.getWrapPredicate(AR, Flags));
auto II = FlagsMap.insert({V, Flags});
if (!II.second)
II.first->second = SCEVWrapPredicate::setFlags(Flags, II.first->second);
}
bool PredicatedScalarEvolution::hasNoOverflow(
Value *V, SCEVWrapPredicate::IncrementWrapFlags Flags) {
const SCEV *Expr = getSCEV(V);
const auto *AR = cast<SCEVAddRecExpr>(Expr);
Flags = SCEVWrapPredicate::clearFlags(
Flags, SCEVWrapPredicate::getImpliedFlags(AR, SE));
auto II = FlagsMap.find(V);
if (II != FlagsMap.end())
Flags = SCEVWrapPredicate::clearFlags(Flags, II->second);
return Flags == SCEVWrapPredicate::IncrementAnyWrap;
}
const SCEVAddRecExpr *PredicatedScalarEvolution::getAsAddRec(Value *V) {
const SCEV *Expr = this->getSCEV(V);
SmallPtrSet<const SCEVPredicate *, 4> NewPreds;
auto *New = SE.convertSCEVToAddRecWithPredicates(Expr, &L, NewPreds);
if (!New)
return nullptr;
for (const auto *P : NewPreds)
addPredicate(*P);
RewriteMap[SE.getSCEV(V)] = {Generation, New};
return New;
}
PredicatedScalarEvolution::PredicatedScalarEvolution(
const PredicatedScalarEvolution &Init)
: RewriteMap(Init.RewriteMap), SE(Init.SE), L(Init.L),
Preds(std::make_unique<SCEVUnionPredicate>(Init.Preds->getPredicates())),
Generation(Init.Generation), BackedgeCount(Init.BackedgeCount) {
for (auto I : Init.FlagsMap)
FlagsMap.insert(I);
}
void PredicatedScalarEvolution::print(raw_ostream &OS, unsigned Depth) const {
// For each block.
for (auto *BB : L.getBlocks())
for (auto &I : *BB) {
if (!SE.isSCEVable(I.getType()))
continue;
auto *Expr = SE.getSCEV(&I);
auto II = RewriteMap.find(Expr);
if (II == RewriteMap.end())
continue;
// Don't print things that are not interesting.
if (II->second.second == Expr)
continue;
OS.indent(Depth) << "[PSE]" << I << ":\n";
OS.indent(Depth + 2) << *Expr << "\n";
OS.indent(Depth + 2) << "--> " << *II->second.second << "\n";
}
}
// Match the mathematical pattern A - (A / B) * B, where A and B can be
// arbitrary expressions. Also match zext (trunc A to iB) to iY, which is used
// for URem with constant power-of-2 second operands.
// It's not always easy, as A and B can be folded (imagine A is X / 2, and B is
// 4, A / B becomes X / 8).
bool ScalarEvolution::matchURem(const SCEV *Expr, const SCEV *&LHS,
const SCEV *&RHS) {
// Try to match 'zext (trunc A to iB) to iY', which is used
// for URem with constant power-of-2 second operands. Make sure the size of
// the operand A matches the size of the whole expressions.
if (const auto *ZExt = dyn_cast<SCEVZeroExtendExpr>(Expr))
if (const auto *Trunc = dyn_cast<SCEVTruncateExpr>(ZExt->getOperand(0))) {
LHS = Trunc->getOperand();
// Bail out if the type of the LHS is larger than the type of the
// expression for now.
if (getTypeSizeInBits(LHS->getType()) >
getTypeSizeInBits(Expr->getType()))
return false;
if (LHS->getType() != Expr->getType())
LHS = getZeroExtendExpr(LHS, Expr->getType());
RHS = getConstant(APInt(getTypeSizeInBits(Expr->getType()), 1)
<< getTypeSizeInBits(Trunc->getType()));
return true;
}
const auto *Add = dyn_cast<SCEVAddExpr>(Expr);
if (Add == nullptr || Add->getNumOperands() != 2)
return false;
const SCEV *A = Add->getOperand(1);
const auto *Mul = dyn_cast<SCEVMulExpr>(Add->getOperand(0));
if (Mul == nullptr)
return false;
const auto MatchURemWithDivisor = [&](const SCEV *B) {
// (SomeExpr + (-(SomeExpr / B) * B)).
if (Expr == getURemExpr(A, B)) {
LHS = A;
RHS = B;
return true;
}
return false;
};
// (SomeExpr + (-1 * (SomeExpr / B) * B)).
if (Mul->getNumOperands() == 3 && isa<SCEVConstant>(Mul->getOperand(0)))
return MatchURemWithDivisor(Mul->getOperand(1)) ||
MatchURemWithDivisor(Mul->getOperand(2));
// (SomeExpr + ((-SomeExpr / B) * B)) or (SomeExpr + ((SomeExpr / B) * -B)).
if (Mul->getNumOperands() == 2)
return MatchURemWithDivisor(Mul->getOperand(1)) ||
MatchURemWithDivisor(Mul->getOperand(0)) ||
MatchURemWithDivisor(getNegativeSCEV(Mul->getOperand(1))) ||
MatchURemWithDivisor(getNegativeSCEV(Mul->getOperand(0)));
return false;
}
const SCEV *
ScalarEvolution::computeSymbolicMaxBackedgeTakenCount(const Loop *L) {
SmallVector<BasicBlock*, 16> ExitingBlocks;
L->getExitingBlocks(ExitingBlocks);
// Form an expression for the maximum exit count possible for this loop. We
// merge the max and exact information to approximate a version of
// getConstantMaxBackedgeTakenCount which isn't restricted to just constants.
SmallVector<const SCEV*, 4> ExitCounts;
for (BasicBlock *ExitingBB : ExitingBlocks) {
const SCEV *ExitCount = getExitCount(L, ExitingBB);
if (isa<SCEVCouldNotCompute>(ExitCount))
ExitCount = getExitCount(L, ExitingBB,
ScalarEvolution::ConstantMaximum);
if (!isa<SCEVCouldNotCompute>(ExitCount)) {
assert(DT.dominates(ExitingBB, L->getLoopLatch()) &&
"We should only have known counts for exiting blocks that "
"dominate latch!");
ExitCounts.push_back(ExitCount);
}
}
if (ExitCounts.empty())
return getCouldNotCompute();
return getUMinFromMismatchedTypes(ExitCounts);
}
/// A rewriter to replace SCEV expressions in Map with the corresponding entry
/// in the map. It skips AddRecExpr because we cannot guarantee that the
/// replacement is loop invariant in the loop of the AddRec.
///
/// At the moment only rewriting SCEVUnknown and SCEVZeroExtendExpr is
/// supported.
class SCEVLoopGuardRewriter : public SCEVRewriteVisitor<SCEVLoopGuardRewriter> {
const DenseMap<const SCEV *, const SCEV *> &Map;
public:
SCEVLoopGuardRewriter(ScalarEvolution &SE,
DenseMap<const SCEV *, const SCEV *> &M)
: SCEVRewriteVisitor(SE), Map(M) {}
const SCEV *visitAddRecExpr(const SCEVAddRecExpr *Expr) { return Expr; }
const SCEV *visitUnknown(const SCEVUnknown *Expr) {
auto I = Map.find(Expr);
if (I == Map.end())
return Expr;
return I->second;
}
const SCEV *visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
auto I = Map.find(Expr);
if (I == Map.end())
return SCEVRewriteVisitor<SCEVLoopGuardRewriter>::visitZeroExtendExpr(
Expr);
return I->second;
}
};
const SCEV *ScalarEvolution::applyLoopGuards(const SCEV *Expr, const Loop *L) {
SmallVector<const SCEV *> ExprsToRewrite;
auto CollectCondition = [&](ICmpInst::Predicate Predicate, const SCEV *LHS,
const SCEV *RHS,
DenseMap<const SCEV *, const SCEV *>
&RewriteMap) {
// WARNING: It is generally unsound to apply any wrap flags to the proposed
// replacement SCEV which isn't directly implied by the structure of that
// SCEV. In particular, using contextual facts to imply flags is *NOT*
// legal. See the scoping rules for flags in the header to understand why.
// If LHS is a constant, apply information to the other expression.
if (isa<SCEVConstant>(LHS)) {
std::swap(LHS, RHS);
Predicate = CmpInst::getSwappedPredicate(Predicate);
}
// Check for a condition of the form (-C1 + X < C2). InstCombine will
// create this form when combining two checks of the form (X u< C2 + C1) and
// (X >=u C1).
auto MatchRangeCheckIdiom = [this, Predicate, LHS, RHS, &RewriteMap,
&ExprsToRewrite]() {
auto *AddExpr = dyn_cast<SCEVAddExpr>(LHS);
if (!AddExpr || AddExpr->getNumOperands() != 2)
return false;
auto *C1 = dyn_cast<SCEVConstant>(AddExpr->getOperand(0));
auto *LHSUnknown = dyn_cast<SCEVUnknown>(AddExpr->getOperand(1));
auto *C2 = dyn_cast<SCEVConstant>(RHS);
if (!C1 || !C2 || !LHSUnknown)
return false;
auto ExactRegion =
ConstantRange::makeExactICmpRegion(Predicate, C2->getAPInt())
.sub(C1->getAPInt());
// Bail out, unless we have a non-wrapping, monotonic range.
if (ExactRegion.isWrappedSet() || ExactRegion.isFullSet())
return false;
auto I = RewriteMap.find(LHSUnknown);
const SCEV *RewrittenLHS = I != RewriteMap.end() ? I->second : LHSUnknown;
RewriteMap[LHSUnknown] = getUMaxExpr(
getConstant(ExactRegion.getUnsignedMin()),
getUMinExpr(RewrittenLHS, getConstant(ExactRegion.getUnsignedMax())));
ExprsToRewrite.push_back(LHSUnknown);
return true;
};
if (MatchRangeCheckIdiom())
return;
// If we have LHS == 0, check if LHS is computing a property of some unknown
// SCEV %v which we can rewrite %v to express explicitly.
const SCEVConstant *RHSC = dyn_cast<SCEVConstant>(RHS);
if (Predicate == CmpInst::ICMP_EQ && RHSC &&
RHSC->getValue()->isNullValue()) {
// If LHS is A % B, i.e. A % B == 0, rewrite A to (A /u B) * B to
// explicitly express that.
const SCEV *URemLHS = nullptr;
const SCEV *URemRHS = nullptr;
if (matchURem(LHS, URemLHS, URemRHS)) {
if (const SCEVUnknown *LHSUnknown = dyn_cast<SCEVUnknown>(URemLHS)) {
auto Multiple = getMulExpr(getUDivExpr(URemLHS, URemRHS), URemRHS);
RewriteMap[LHSUnknown] = Multiple;
ExprsToRewrite.push_back(LHSUnknown);
return;
}
}
}
// Do not apply information for constants or if RHS contains an AddRec.
if (isa<SCEVConstant>(LHS) || containsAddRecurrence(RHS))
return;
// If RHS is SCEVUnknown, make sure the information is applied to it.
if (!isa<SCEVUnknown>(LHS) && isa<SCEVUnknown>(RHS)) {
std::swap(LHS, RHS);
Predicate = CmpInst::getSwappedPredicate(Predicate);
}
// Limit to expressions that can be rewritten.
if (!isa<SCEVUnknown>(LHS) && !isa<SCEVZeroExtendExpr>(LHS))
return;
// Check whether LHS has already been rewritten. In that case we want to
// chain further rewrites onto the already rewritten value.
auto I = RewriteMap.find(LHS);
const SCEV *RewrittenLHS = I != RewriteMap.end() ? I->second : LHS;
const SCEV *RewrittenRHS = nullptr;
switch (Predicate) {
case CmpInst::ICMP_ULT:
RewrittenRHS =
getUMinExpr(RewrittenLHS, getMinusSCEV(RHS, getOne(RHS->getType())));
break;
case CmpInst::ICMP_SLT:
RewrittenRHS =
getSMinExpr(RewrittenLHS, getMinusSCEV(RHS, getOne(RHS->getType())));
break;
case CmpInst::ICMP_ULE:
RewrittenRHS = getUMinExpr(RewrittenLHS, RHS);
break;
case CmpInst::ICMP_SLE:
RewrittenRHS = getSMinExpr(RewrittenLHS, RHS);
break;
case CmpInst::ICMP_UGT:
RewrittenRHS =
getUMaxExpr(RewrittenLHS, getAddExpr(RHS, getOne(RHS->getType())));
break;
case CmpInst::ICMP_SGT:
RewrittenRHS =
getSMaxExpr(RewrittenLHS, getAddExpr(RHS, getOne(RHS->getType())));
break;
case CmpInst::ICMP_UGE:
RewrittenRHS = getUMaxExpr(RewrittenLHS, RHS);
break;
case CmpInst::ICMP_SGE:
RewrittenRHS = getSMaxExpr(RewrittenLHS, RHS);
break;
case CmpInst::ICMP_EQ:
if (isa<SCEVConstant>(RHS))
RewrittenRHS = RHS;
break;
case CmpInst::ICMP_NE:
if (isa<SCEVConstant>(RHS) &&
cast<SCEVConstant>(RHS)->getValue()->isNullValue())
RewrittenRHS = getUMaxExpr(RewrittenLHS, getOne(RHS->getType()));
break;
default:
break;
}
if (RewrittenRHS) {
RewriteMap[LHS] = RewrittenRHS;
if (LHS == RewrittenLHS)
ExprsToRewrite.push_back(LHS);
}
};
SmallVector<std::pair<Value *, bool>> Terms;
// First, collect information from assumptions dominating the loop.
for (auto &AssumeVH : AC.assumptions()) {
if (!AssumeVH)
continue;
auto *AssumeI = cast<CallInst>(AssumeVH);
if (!DT.dominates(AssumeI, L->getHeader()))
continue;
Terms.emplace_back(AssumeI->getOperand(0), true);
}
// Second, collect conditions from dominating branches. Starting at the loop
// predecessor, climb up the predecessor chain, as long as there are
// predecessors that can be found that have unique successors leading to the
// original header.
// TODO: share this logic with isLoopEntryGuardedByCond.
for (std::pair<const BasicBlock *, const BasicBlock *> Pair(
L->getLoopPredecessor(), L->getHeader());
Pair.first; Pair = getPredecessorWithUniqueSuccessorForBB(Pair.first)) {
const BranchInst *LoopEntryPredicate =
dyn_cast<BranchInst>(Pair.first->getTerminator());
if (!LoopEntryPredicate || LoopEntryPredicate->isUnconditional())
continue;
Terms.emplace_back(LoopEntryPredicate->getCondition(),
LoopEntryPredicate->getSuccessor(0) == Pair.second);
}
// Now apply the information from the collected conditions to RewriteMap.
// Conditions are processed in reverse order, so the earliest conditions is
// processed first. This ensures the SCEVs with the shortest dependency chains
// are constructed first.
DenseMap<const SCEV *, const SCEV *> RewriteMap;
for (auto &E : reverse(Terms)) {
bool EnterIfTrue = E.second;
SmallVector<Value *, 8> Worklist;
SmallPtrSet<Value *, 8> Visited;
Worklist.push_back(E.first);
while (!Worklist.empty()) {
Value *Cond = Worklist.pop_back_val();
if (!Visited.insert(Cond).second)
continue;
if (auto *Cmp = dyn_cast<ICmpInst>(Cond)) {
auto Predicate =
EnterIfTrue ? Cmp->getPredicate() : Cmp->getInversePredicate();
const auto *LHS = getSCEV(Cmp->getOperand(0));
const auto *RHS = getSCEV(Cmp->getOperand(1));
CollectCondition(Predicate, LHS, RHS, RewriteMap);
continue;
}
Value *L, *R;
if (EnterIfTrue ? match(Cond, m_LogicalAnd(m_Value(L), m_Value(R)))
: match(Cond, m_LogicalOr(m_Value(L), m_Value(R)))) {
Worklist.push_back(L);
Worklist.push_back(R);
}
}
}
if (RewriteMap.empty())
return Expr;
// Now that all rewrite information is collect, rewrite the collected
// expressions with the information in the map. This applies information to
// sub-expressions.
if (ExprsToRewrite.size() > 1) {
for (const SCEV *Expr : ExprsToRewrite) {
const SCEV *RewriteTo = RewriteMap[Expr];
RewriteMap.erase(Expr);
SCEVLoopGuardRewriter Rewriter(*this, RewriteMap);
RewriteMap.insert({Expr, Rewriter.visit(RewriteTo)});
}
}
SCEVLoopGuardRewriter Rewriter(*this, RewriteMap);
return Rewriter.visit(Expr);
}
diff --git a/contrib/llvm-project/llvm/lib/Analysis/ValueTracking.cpp b/contrib/llvm-project/llvm/lib/Analysis/ValueTracking.cpp
index 2dd671b4ab9e..569ee6b3ea86 100644
--- a/contrib/llvm-project/llvm/lib/Analysis/ValueTracking.cpp
+++ b/contrib/llvm-project/llvm/lib/Analysis/ValueTracking.cpp
@@ -1,7342 +1,7351 @@
//===- ValueTracking.cpp - Walk computations to compute properties --------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains routines that help analyze properties that chains of
// computations have.
//
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AssumeBundleQueries.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/Analysis/GuardUtils.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/Loads.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsAArch64.h"
#include "llvm/IR/IntrinsicsRISCV.h"
#include "llvm/IR/IntrinsicsX86.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/KnownBits.h"
#include "llvm/Support/MathExtras.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <utility>
using namespace llvm;
using namespace llvm::PatternMatch;
// Controls the number of uses of the value searched for possible
// dominating comparisons.
static cl::opt<unsigned> DomConditionsMaxUses("dom-conditions-max-uses",
cl::Hidden, cl::init(20));
// According to the LangRef, branching on a poison condition is absolutely
// immediate full UB. However, historically we haven't implemented that
// consistently as we had an important transformation (non-trivial unswitch)
// which introduced instances of branch on poison/undef to otherwise well
// defined programs. This issue has since been fixed, but the flag is
// temporarily retained to easily diagnose potential regressions.
static cl::opt<bool> BranchOnPoisonAsUB("branch-on-poison-as-ub",
cl::Hidden, cl::init(true));
/// Returns the bitwidth of the given scalar or pointer type. For vector types,
/// returns the element type's bitwidth.
static unsigned getBitWidth(Type *Ty, const DataLayout &DL) {
if (unsigned BitWidth = Ty->getScalarSizeInBits())
return BitWidth;
return DL.getPointerTypeSizeInBits(Ty);
}
namespace {
// Simplifying using an assume can only be done in a particular control-flow
// context (the context instruction provides that context). If an assume and
// the context instruction are not in the same block then the DT helps in
// figuring out if we can use it.
struct Query {
const DataLayout &DL;
AssumptionCache *AC;
const Instruction *CxtI;
const DominatorTree *DT;
// Unlike the other analyses, this may be a nullptr because not all clients
// provide it currently.
OptimizationRemarkEmitter *ORE;
/// If true, it is safe to use metadata during simplification.
InstrInfoQuery IIQ;
Query(const DataLayout &DL, AssumptionCache *AC, const Instruction *CxtI,
const DominatorTree *DT, bool UseInstrInfo,
OptimizationRemarkEmitter *ORE = nullptr)
: DL(DL), AC(AC), CxtI(CxtI), DT(DT), ORE(ORE), IIQ(UseInstrInfo) {}
};
} // end anonymous namespace
// Given the provided Value and, potentially, a context instruction, return
// the preferred context instruction (if any).
static const Instruction *safeCxtI(const Value *V, const Instruction *CxtI) {
// If we've been provided with a context instruction, then use that (provided
// it has been inserted).
if (CxtI && CxtI->getParent())
return CxtI;
// If the value is really an already-inserted instruction, then use that.
CxtI = dyn_cast<Instruction>(V);
if (CxtI && CxtI->getParent())
return CxtI;
return nullptr;
}
static const Instruction *safeCxtI(const Value *V1, const Value *V2, const Instruction *CxtI) {
// If we've been provided with a context instruction, then use that (provided
// it has been inserted).
if (CxtI && CxtI->getParent())
return CxtI;
// If the value is really an already-inserted instruction, then use that.
CxtI = dyn_cast<Instruction>(V1);
if (CxtI && CxtI->getParent())
return CxtI;
CxtI = dyn_cast<Instruction>(V2);
if (CxtI && CxtI->getParent())
return CxtI;
return nullptr;
}
static bool getShuffleDemandedElts(const ShuffleVectorInst *Shuf,
const APInt &DemandedElts,
APInt &DemandedLHS, APInt &DemandedRHS) {
// The length of scalable vectors is unknown at compile time, thus we
// cannot check their values
if (isa<ScalableVectorType>(Shuf->getType()))
return false;
int NumElts =
cast<FixedVectorType>(Shuf->getOperand(0)->getType())->getNumElements();
int NumMaskElts = cast<FixedVectorType>(Shuf->getType())->getNumElements();
DemandedLHS = DemandedRHS = APInt::getZero(NumElts);
if (DemandedElts.isZero())
return true;
// Simple case of a shuffle with zeroinitializer.
if (all_of(Shuf->getShuffleMask(), [](int Elt) { return Elt == 0; })) {
DemandedLHS.setBit(0);
return true;
}
for (int i = 0; i != NumMaskElts; ++i) {
if (!DemandedElts[i])
continue;
int M = Shuf->getMaskValue(i);
assert(M < (NumElts * 2) && "Invalid shuffle mask constant");
// For undef elements, we don't know anything about the common state of
// the shuffle result.
if (M == -1)
return false;
if (M < NumElts)
DemandedLHS.setBit(M % NumElts);
else
DemandedRHS.setBit(M % NumElts);
}
return true;
}
static void computeKnownBits(const Value *V, const APInt &DemandedElts,
KnownBits &Known, unsigned Depth, const Query &Q);
static void computeKnownBits(const Value *V, KnownBits &Known, unsigned Depth,
const Query &Q) {
// FIXME: We currently have no way to represent the DemandedElts of a scalable
// vector
if (isa<ScalableVectorType>(V->getType())) {
Known.resetAll();
return;
}
auto *FVTy = dyn_cast<FixedVectorType>(V->getType());
APInt DemandedElts =
FVTy ? APInt::getAllOnes(FVTy->getNumElements()) : APInt(1, 1);
computeKnownBits(V, DemandedElts, Known, Depth, Q);
}
void llvm::computeKnownBits(const Value *V, KnownBits &Known,
const DataLayout &DL, unsigned Depth,
AssumptionCache *AC, const Instruction *CxtI,
const DominatorTree *DT,
OptimizationRemarkEmitter *ORE, bool UseInstrInfo) {
::computeKnownBits(V, Known, Depth,
Query(DL, AC, safeCxtI(V, CxtI), DT, UseInstrInfo, ORE));
}
void llvm::computeKnownBits(const Value *V, const APInt &DemandedElts,
KnownBits &Known, const DataLayout &DL,
unsigned Depth, AssumptionCache *AC,
const Instruction *CxtI, const DominatorTree *DT,
OptimizationRemarkEmitter *ORE, bool UseInstrInfo) {
::computeKnownBits(V, DemandedElts, Known, Depth,
Query(DL, AC, safeCxtI(V, CxtI), DT, UseInstrInfo, ORE));
}
static KnownBits computeKnownBits(const Value *V, const APInt &DemandedElts,
unsigned Depth, const Query &Q);
static KnownBits computeKnownBits(const Value *V, unsigned Depth,
const Query &Q);
KnownBits llvm::computeKnownBits(const Value *V, const DataLayout &DL,
unsigned Depth, AssumptionCache *AC,
const Instruction *CxtI,
const DominatorTree *DT,
OptimizationRemarkEmitter *ORE,
bool UseInstrInfo) {
return ::computeKnownBits(
V, Depth, Query(DL, AC, safeCxtI(V, CxtI), DT, UseInstrInfo, ORE));
}
KnownBits llvm::computeKnownBits(const Value *V, const APInt &DemandedElts,
const DataLayout &DL, unsigned Depth,
AssumptionCache *AC, const Instruction *CxtI,
const DominatorTree *DT,
OptimizationRemarkEmitter *ORE,
bool UseInstrInfo) {
return ::computeKnownBits(
V, DemandedElts, Depth,
Query(DL, AC, safeCxtI(V, CxtI), DT, UseInstrInfo, ORE));
}
bool llvm::haveNoCommonBitsSet(const Value *LHS, const Value *RHS,
const DataLayout &DL, AssumptionCache *AC,
const Instruction *CxtI, const DominatorTree *DT,
bool UseInstrInfo) {
assert(LHS->getType() == RHS->getType() &&
"LHS and RHS should have the same type");
assert(LHS->getType()->isIntOrIntVectorTy() &&
"LHS and RHS should be integers");
// Look for an inverted mask: (X & ~M) op (Y & M).
{
Value *M;
if (match(LHS, m_c_And(m_Not(m_Value(M)), m_Value())) &&
match(RHS, m_c_And(m_Specific(M), m_Value())))
return true;
if (match(RHS, m_c_And(m_Not(m_Value(M)), m_Value())) &&
match(LHS, m_c_And(m_Specific(M), m_Value())))
return true;
}
// X op (Y & ~X)
if (match(RHS, m_c_And(m_Not(m_Specific(LHS)), m_Value())) ||
match(LHS, m_c_And(m_Not(m_Specific(RHS)), m_Value())))
return true;
// X op ((X & Y) ^ Y) -- this is the canonical form of the previous pattern
// for constant Y.
Value *Y;
if (match(RHS,
m_c_Xor(m_c_And(m_Specific(LHS), m_Value(Y)), m_Deferred(Y))) ||
match(LHS, m_c_Xor(m_c_And(m_Specific(RHS), m_Value(Y)), m_Deferred(Y))))
return true;
// Look for: (A & B) op ~(A | B)
{
Value *A, *B;
if (match(LHS, m_And(m_Value(A), m_Value(B))) &&
match(RHS, m_Not(m_c_Or(m_Specific(A), m_Specific(B)))))
return true;
if (match(RHS, m_And(m_Value(A), m_Value(B))) &&
match(LHS, m_Not(m_c_Or(m_Specific(A), m_Specific(B)))))
return true;
}
IntegerType *IT = cast<IntegerType>(LHS->getType()->getScalarType());
KnownBits LHSKnown(IT->getBitWidth());
KnownBits RHSKnown(IT->getBitWidth());
computeKnownBits(LHS, LHSKnown, DL, 0, AC, CxtI, DT, nullptr, UseInstrInfo);
computeKnownBits(RHS, RHSKnown, DL, 0, AC, CxtI, DT, nullptr, UseInstrInfo);
return KnownBits::haveNoCommonBitsSet(LHSKnown, RHSKnown);
}
bool llvm::isOnlyUsedInZeroEqualityComparison(const Instruction *I) {
return !I->user_empty() && all_of(I->users(), [](const User *U) {
ICmpInst::Predicate P;
return match(U, m_ICmp(P, m_Value(), m_Zero())) && ICmpInst::isEquality(P);
});
}
static bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth,
const Query &Q);
bool llvm::isKnownToBeAPowerOfTwo(const Value *V, const DataLayout &DL,
bool OrZero, unsigned Depth,
AssumptionCache *AC, const Instruction *CxtI,
const DominatorTree *DT, bool UseInstrInfo) {
return ::isKnownToBeAPowerOfTwo(
V, OrZero, Depth, Query(DL, AC, safeCxtI(V, CxtI), DT, UseInstrInfo));
}
static bool isKnownNonZero(const Value *V, const APInt &DemandedElts,
unsigned Depth, const Query &Q);
static bool isKnownNonZero(const Value *V, unsigned Depth, const Query &Q);
bool llvm::isKnownNonZero(const Value *V, const DataLayout &DL, unsigned Depth,
AssumptionCache *AC, const Instruction *CxtI,
const DominatorTree *DT, bool UseInstrInfo) {
return ::isKnownNonZero(V, Depth,
Query(DL, AC, safeCxtI(V, CxtI), DT, UseInstrInfo));
}
bool llvm::isKnownNonNegative(const Value *V, const DataLayout &DL,
unsigned Depth, AssumptionCache *AC,
const Instruction *CxtI, const DominatorTree *DT,
bool UseInstrInfo) {
KnownBits Known =
computeKnownBits(V, DL, Depth, AC, CxtI, DT, nullptr, UseInstrInfo);
return Known.isNonNegative();
}
bool llvm::isKnownPositive(const Value *V, const DataLayout &DL, unsigned Depth,
AssumptionCache *AC, const Instruction *CxtI,
const DominatorTree *DT, bool UseInstrInfo) {
if (auto *CI = dyn_cast<ConstantInt>(V))
return CI->getValue().isStrictlyPositive();
// TODO: We'd doing two recursive queries here. We should factor this such
// that only a single query is needed.
return isKnownNonNegative(V, DL, Depth, AC, CxtI, DT, UseInstrInfo) &&
isKnownNonZero(V, DL, Depth, AC, CxtI, DT, UseInstrInfo);
}
bool llvm::isKnownNegative(const Value *V, const DataLayout &DL, unsigned Depth,
AssumptionCache *AC, const Instruction *CxtI,
const DominatorTree *DT, bool UseInstrInfo) {
KnownBits Known =
computeKnownBits(V, DL, Depth, AC, CxtI, DT, nullptr, UseInstrInfo);
return Known.isNegative();
}
static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
const Query &Q);
bool llvm::isKnownNonEqual(const Value *V1, const Value *V2,
const DataLayout &DL, AssumptionCache *AC,
const Instruction *CxtI, const DominatorTree *DT,
bool UseInstrInfo) {
return ::isKnownNonEqual(V1, V2, 0,
Query(DL, AC, safeCxtI(V2, V1, CxtI), DT,
UseInstrInfo, /*ORE=*/nullptr));
}
static bool MaskedValueIsZero(const Value *V, const APInt &Mask, unsigned Depth,
const Query &Q);
bool llvm::MaskedValueIsZero(const Value *V, const APInt &Mask,
const DataLayout &DL, unsigned Depth,
AssumptionCache *AC, const Instruction *CxtI,
const DominatorTree *DT, bool UseInstrInfo) {
return ::MaskedValueIsZero(
V, Mask, Depth, Query(DL, AC, safeCxtI(V, CxtI), DT, UseInstrInfo));
}
static unsigned ComputeNumSignBits(const Value *V, const APInt &DemandedElts,
unsigned Depth, const Query &Q);
static unsigned ComputeNumSignBits(const Value *V, unsigned Depth,
const Query &Q) {
// FIXME: We currently have no way to represent the DemandedElts of a scalable
// vector
if (isa<ScalableVectorType>(V->getType()))
return 1;
auto *FVTy = dyn_cast<FixedVectorType>(V->getType());
APInt DemandedElts =
FVTy ? APInt::getAllOnes(FVTy->getNumElements()) : APInt(1, 1);
return ComputeNumSignBits(V, DemandedElts, Depth, Q);
}
unsigned llvm::ComputeNumSignBits(const Value *V, const DataLayout &DL,
unsigned Depth, AssumptionCache *AC,
const Instruction *CxtI,
const DominatorTree *DT, bool UseInstrInfo) {
return ::ComputeNumSignBits(
V, Depth, Query(DL, AC, safeCxtI(V, CxtI), DT, UseInstrInfo));
}
unsigned llvm::ComputeMaxSignificantBits(const Value *V, const DataLayout &DL,
unsigned Depth, AssumptionCache *AC,
const Instruction *CxtI,
const DominatorTree *DT) {
unsigned SignBits = ComputeNumSignBits(V, DL, Depth, AC, CxtI, DT);
return V->getType()->getScalarSizeInBits() - SignBits + 1;
}
static void computeKnownBitsAddSub(bool Add, const Value *Op0, const Value *Op1,
bool NSW, const APInt &DemandedElts,
KnownBits &KnownOut, KnownBits &Known2,
unsigned Depth, const Query &Q) {
computeKnownBits(Op1, DemandedElts, KnownOut, Depth + 1, Q);
// If one operand is unknown and we have no nowrap information,
// the result will be unknown independently of the second operand.
if (KnownOut.isUnknown() && !NSW)
return;
computeKnownBits(Op0, DemandedElts, Known2, Depth + 1, Q);
KnownOut = KnownBits::computeForAddSub(Add, NSW, Known2, KnownOut);
}
static void computeKnownBitsMul(const Value *Op0, const Value *Op1, bool NSW,
const APInt &DemandedElts, KnownBits &Known,
KnownBits &Known2, unsigned Depth,
const Query &Q) {
computeKnownBits(Op1, DemandedElts, Known, Depth + 1, Q);
computeKnownBits(Op0, DemandedElts, Known2, Depth + 1, Q);
bool isKnownNegative = false;
bool isKnownNonNegative = false;
// If the multiplication is known not to overflow, compute the sign bit.
if (NSW) {
if (Op0 == Op1) {
// The product of a number with itself is non-negative.
isKnownNonNegative = true;
} else {
bool isKnownNonNegativeOp1 = Known.isNonNegative();
bool isKnownNonNegativeOp0 = Known2.isNonNegative();
bool isKnownNegativeOp1 = Known.isNegative();
bool isKnownNegativeOp0 = Known2.isNegative();
// The product of two numbers with the same sign is non-negative.
isKnownNonNegative = (isKnownNegativeOp1 && isKnownNegativeOp0) ||
(isKnownNonNegativeOp1 && isKnownNonNegativeOp0);
// The product of a negative number and a non-negative number is either
// negative or zero.
if (!isKnownNonNegative)
isKnownNegative =
(isKnownNegativeOp1 && isKnownNonNegativeOp0 &&
Known2.isNonZero()) ||
(isKnownNegativeOp0 && isKnownNonNegativeOp1 && Known.isNonZero());
}
}
bool SelfMultiply = Op0 == Op1;
// TODO: SelfMultiply can be poison, but not undef.
if (SelfMultiply)
SelfMultiply &=
isGuaranteedNotToBeUndefOrPoison(Op0, Q.AC, Q.CxtI, Q.DT, Depth + 1);
Known = KnownBits::mul(Known, Known2, SelfMultiply);
// Only make use of no-wrap flags if we failed to compute the sign bit
// directly. This matters if the multiplication always overflows, in
// which case we prefer to follow the result of the direct computation,
// though as the program is invoking undefined behaviour we can choose
// whatever we like here.
if (isKnownNonNegative && !Known.isNegative())
Known.makeNonNegative();
else if (isKnownNegative && !Known.isNonNegative())
Known.makeNegative();
}
void llvm::computeKnownBitsFromRangeMetadata(const MDNode &Ranges,
KnownBits &Known) {
unsigned BitWidth = Known.getBitWidth();
unsigned NumRanges = Ranges.getNumOperands() / 2;
assert(NumRanges >= 1);
Known.Zero.setAllBits();
Known.One.setAllBits();
for (unsigned i = 0; i < NumRanges; ++i) {
ConstantInt *Lower =
mdconst::extract<ConstantInt>(Ranges.getOperand(2 * i + 0));
ConstantInt *Upper =
mdconst::extract<ConstantInt>(Ranges.getOperand(2 * i + 1));
ConstantRange Range(Lower->getValue(), Upper->getValue());
// The first CommonPrefixBits of all values in Range are equal.
unsigned CommonPrefixBits =
(Range.getUnsignedMax() ^ Range.getUnsignedMin()).countLeadingZeros();
APInt Mask = APInt::getHighBitsSet(BitWidth, CommonPrefixBits);
APInt UnsignedMax = Range.getUnsignedMax().zextOrTrunc(BitWidth);
Known.One &= UnsignedMax & Mask;
Known.Zero &= ~UnsignedMax & Mask;
}
}
static bool isEphemeralValueOf(const Instruction *I, const Value *E) {
SmallVector<const Value *, 16> WorkSet(1, I);
SmallPtrSet<const Value *, 32> Visited;
SmallPtrSet<const Value *, 16> EphValues;
// The instruction defining an assumption's condition itself is always
// considered ephemeral to that assumption (even if it has other
// non-ephemeral users). See r246696's test case for an example.
if (is_contained(I->operands(), E))
return true;
while (!WorkSet.empty()) {
const Value *V = WorkSet.pop_back_val();
if (!Visited.insert(V).second)
continue;
// If all uses of this value are ephemeral, then so is this value.
if (llvm::all_of(V->users(), [&](const User *U) {
return EphValues.count(U);
})) {
if (V == E)
return true;
if (V == I || (isa<Instruction>(V) &&
!cast<Instruction>(V)->mayHaveSideEffects() &&
!cast<Instruction>(V)->isTerminator())) {
EphValues.insert(V);
if (const User *U = dyn_cast<User>(V))
append_range(WorkSet, U->operands());
}
}
}
return false;
}
// Is this an intrinsic that cannot be speculated but also cannot trap?
bool llvm::isAssumeLikeIntrinsic(const Instruction *I) {
if (const IntrinsicInst *CI = dyn_cast<IntrinsicInst>(I))
return CI->isAssumeLikeIntrinsic();
return false;
}
bool llvm::isValidAssumeForContext(const Instruction *Inv,
const Instruction *CxtI,
const DominatorTree *DT) {
// There are two restrictions on the use of an assume:
// 1. The assume must dominate the context (or the control flow must
// reach the assume whenever it reaches the context).
// 2. The context must not be in the assume's set of ephemeral values
// (otherwise we will use the assume to prove that the condition
// feeding the assume is trivially true, thus causing the removal of
// the assume).
if (Inv->getParent() == CxtI->getParent()) {
// If Inv and CtxI are in the same block, check if the assume (Inv) is first
// in the BB.
if (Inv->comesBefore(CxtI))
return true;
// Don't let an assume affect itself - this would cause the problems
// `isEphemeralValueOf` is trying to prevent, and it would also make
// the loop below go out of bounds.
if (Inv == CxtI)
return false;
// The context comes first, but they're both in the same block.
// Make sure there is nothing in between that might interrupt
// the control flow, not even CxtI itself.
// We limit the scan distance between the assume and its context instruction
// to avoid a compile-time explosion. This limit is chosen arbitrarily, so
// it can be adjusted if needed (could be turned into a cl::opt).
auto Range = make_range(CxtI->getIterator(), Inv->getIterator());
if (!isGuaranteedToTransferExecutionToSuccessor(Range, 15))
return false;
return !isEphemeralValueOf(Inv, CxtI);
}
// Inv and CxtI are in different blocks.
if (DT) {
if (DT->dominates(Inv, CxtI))
return true;
} else if (Inv->getParent() == CxtI->getParent()->getSinglePredecessor()) {
// We don't have a DT, but this trivially dominates.
return true;
}
return false;
}
static bool cmpExcludesZero(CmpInst::Predicate Pred, const Value *RHS) {
// v u> y implies v != 0.
if (Pred == ICmpInst::ICMP_UGT)
return true;
// Special-case v != 0 to also handle v != null.
if (Pred == ICmpInst::ICMP_NE)
return match(RHS, m_Zero());
// All other predicates - rely on generic ConstantRange handling.
const APInt *C;
if (!match(RHS, m_APInt(C)))
return false;
ConstantRange TrueValues = ConstantRange::makeExactICmpRegion(Pred, *C);
return !TrueValues.contains(APInt::getZero(C->getBitWidth()));
}
static bool isKnownNonZeroFromAssume(const Value *V, const Query &Q) {
// Use of assumptions is context-sensitive. If we don't have a context, we
// cannot use them!
if (!Q.AC || !Q.CxtI)
return false;
if (Q.CxtI && V->getType()->isPointerTy()) {
SmallVector<Attribute::AttrKind, 2> AttrKinds{Attribute::NonNull};
if (!NullPointerIsDefined(Q.CxtI->getFunction(),
V->getType()->getPointerAddressSpace()))
AttrKinds.push_back(Attribute::Dereferenceable);
if (getKnowledgeValidInContext(V, AttrKinds, Q.CxtI, Q.DT, Q.AC))
return true;
}
for (auto &AssumeVH : Q.AC->assumptionsFor(V)) {
if (!AssumeVH)
continue;
CallInst *I = cast<CallInst>(AssumeVH);
assert(I->getFunction() == Q.CxtI->getFunction() &&
"Got assumption for the wrong function!");
// Warning: This loop can end up being somewhat performance sensitive.
// We're running this loop for once for each value queried resulting in a
// runtime of ~O(#assumes * #values).
assert(I->getCalledFunction()->getIntrinsicID() == Intrinsic::assume &&
"must be an assume intrinsic");
Value *RHS;
CmpInst::Predicate Pred;
auto m_V = m_CombineOr(m_Specific(V), m_PtrToInt(m_Specific(V)));
if (!match(I->getArgOperand(0), m_c_ICmp(Pred, m_V, m_Value(RHS))))
return false;
if (cmpExcludesZero(Pred, RHS) && isValidAssumeForContext(I, Q.CxtI, Q.DT))
return true;
}
return false;
}
static void computeKnownBitsFromAssume(const Value *V, KnownBits &Known,
unsigned Depth, const Query &Q) {
// Use of assumptions is context-sensitive. If we don't have a context, we
// cannot use them!
if (!Q.AC || !Q.CxtI)
return;
unsigned BitWidth = Known.getBitWidth();
// Refine Known set if the pointer alignment is set by assume bundles.
if (V->getType()->isPointerTy()) {
if (RetainedKnowledge RK = getKnowledgeValidInContext(
V, {Attribute::Alignment}, Q.CxtI, Q.DT, Q.AC)) {
if (isPowerOf2_64(RK.ArgValue))
Known.Zero.setLowBits(Log2_64(RK.ArgValue));
}
}
// Note that the patterns below need to be kept in sync with the code
// in AssumptionCache::updateAffectedValues.
for (auto &AssumeVH : Q.AC->assumptionsFor(V)) {
if (!AssumeVH)
continue;
CallInst *I = cast<CallInst>(AssumeVH);
assert(I->getParent()->getParent() == Q.CxtI->getParent()->getParent() &&
"Got assumption for the wrong function!");
// Warning: This loop can end up being somewhat performance sensitive.
// We're running this loop for once for each value queried resulting in a
// runtime of ~O(#assumes * #values).
assert(I->getCalledFunction()->getIntrinsicID() == Intrinsic::assume &&
"must be an assume intrinsic");
Value *Arg = I->getArgOperand(0);
if (Arg == V && isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
assert(BitWidth == 1 && "assume operand is not i1?");
Known.setAllOnes();
return;
}
if (match(Arg, m_Not(m_Specific(V))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
assert(BitWidth == 1 && "assume operand is not i1?");
Known.setAllZero();
return;
}
// The remaining tests are all recursive, so bail out if we hit the limit.
if (Depth == MaxAnalysisRecursionDepth)
continue;
ICmpInst *Cmp = dyn_cast<ICmpInst>(Arg);
if (!Cmp)
continue;
// We are attempting to compute known bits for the operands of an assume.
// Do not try to use other assumptions for those recursive calls because
// that can lead to mutual recursion and a compile-time explosion.
// An example of the mutual recursion: computeKnownBits can call
// isKnownNonZero which calls computeKnownBitsFromAssume (this function)
// and so on.
Query QueryNoAC = Q;
QueryNoAC.AC = nullptr;
// Note that ptrtoint may change the bitwidth.
Value *A, *B;
auto m_V = m_CombineOr(m_Specific(V), m_PtrToInt(m_Specific(V)));
CmpInst::Predicate Pred;
uint64_t C;
switch (Cmp->getPredicate()) {
default:
break;
case ICmpInst::ICMP_EQ:
// assume(v = a)
if (match(Cmp, m_c_ICmp(Pred, m_V, m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
Known.Zero |= RHSKnown.Zero;
Known.One |= RHSKnown.One;
// assume(v & b = a)
} else if (match(Cmp,
m_c_ICmp(Pred, m_c_And(m_V, m_Value(B)), m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
KnownBits MaskKnown =
computeKnownBits(B, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
// For those bits in the mask that are known to be one, we can propagate
// known bits from the RHS to V.
Known.Zero |= RHSKnown.Zero & MaskKnown.One;
Known.One |= RHSKnown.One & MaskKnown.One;
// assume(~(v & b) = a)
} else if (match(Cmp, m_c_ICmp(Pred, m_Not(m_c_And(m_V, m_Value(B))),
m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
KnownBits MaskKnown =
computeKnownBits(B, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
// For those bits in the mask that are known to be one, we can propagate
// inverted known bits from the RHS to V.
Known.Zero |= RHSKnown.One & MaskKnown.One;
Known.One |= RHSKnown.Zero & MaskKnown.One;
// assume(v | b = a)
} else if (match(Cmp,
m_c_ICmp(Pred, m_c_Or(m_V, m_Value(B)), m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
KnownBits BKnown =
computeKnownBits(B, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
// For those bits in B that are known to be zero, we can propagate known
// bits from the RHS to V.
Known.Zero |= RHSKnown.Zero & BKnown.Zero;
Known.One |= RHSKnown.One & BKnown.Zero;
// assume(~(v | b) = a)
} else if (match(Cmp, m_c_ICmp(Pred, m_Not(m_c_Or(m_V, m_Value(B))),
m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
KnownBits BKnown =
computeKnownBits(B, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
// For those bits in B that are known to be zero, we can propagate
// inverted known bits from the RHS to V.
Known.Zero |= RHSKnown.One & BKnown.Zero;
Known.One |= RHSKnown.Zero & BKnown.Zero;
// assume(v ^ b = a)
} else if (match(Cmp,
m_c_ICmp(Pred, m_c_Xor(m_V, m_Value(B)), m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
KnownBits BKnown =
computeKnownBits(B, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
// For those bits in B that are known to be zero, we can propagate known
// bits from the RHS to V. For those bits in B that are known to be one,
// we can propagate inverted known bits from the RHS to V.
Known.Zero |= RHSKnown.Zero & BKnown.Zero;
Known.One |= RHSKnown.One & BKnown.Zero;
Known.Zero |= RHSKnown.One & BKnown.One;
Known.One |= RHSKnown.Zero & BKnown.One;
// assume(~(v ^ b) = a)
} else if (match(Cmp, m_c_ICmp(Pred, m_Not(m_c_Xor(m_V, m_Value(B))),
m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
KnownBits BKnown =
computeKnownBits(B, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
// For those bits in B that are known to be zero, we can propagate
// inverted known bits from the RHS to V. For those bits in B that are
// known to be one, we can propagate known bits from the RHS to V.
Known.Zero |= RHSKnown.One & BKnown.Zero;
Known.One |= RHSKnown.Zero & BKnown.Zero;
Known.Zero |= RHSKnown.Zero & BKnown.One;
Known.One |= RHSKnown.One & BKnown.One;
// assume(v << c = a)
} else if (match(Cmp, m_c_ICmp(Pred, m_Shl(m_V, m_ConstantInt(C)),
m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT) && C < BitWidth) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
// For those bits in RHS that are known, we can propagate them to known
// bits in V shifted to the right by C.
RHSKnown.Zero.lshrInPlace(C);
Known.Zero |= RHSKnown.Zero;
RHSKnown.One.lshrInPlace(C);
Known.One |= RHSKnown.One;
// assume(~(v << c) = a)
} else if (match(Cmp, m_c_ICmp(Pred, m_Not(m_Shl(m_V, m_ConstantInt(C))),
m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT) && C < BitWidth) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
// For those bits in RHS that are known, we can propagate them inverted
// to known bits in V shifted to the right by C.
RHSKnown.One.lshrInPlace(C);
Known.Zero |= RHSKnown.One;
RHSKnown.Zero.lshrInPlace(C);
Known.One |= RHSKnown.Zero;
// assume(v >> c = a)
} else if (match(Cmp, m_c_ICmp(Pred, m_Shr(m_V, m_ConstantInt(C)),
m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT) && C < BitWidth) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
// For those bits in RHS that are known, we can propagate them to known
// bits in V shifted to the right by C.
Known.Zero |= RHSKnown.Zero << C;
Known.One |= RHSKnown.One << C;
// assume(~(v >> c) = a)
} else if (match(Cmp, m_c_ICmp(Pred, m_Not(m_Shr(m_V, m_ConstantInt(C))),
m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT) && C < BitWidth) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
// For those bits in RHS that are known, we can propagate them inverted
// to known bits in V shifted to the right by C.
Known.Zero |= RHSKnown.One << C;
Known.One |= RHSKnown.Zero << C;
}
break;
case ICmpInst::ICMP_SGE:
// assume(v >=_s c) where c is non-negative
if (match(Cmp, m_ICmp(Pred, m_V, m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth + 1, QueryNoAC).anyextOrTrunc(BitWidth);
if (RHSKnown.isNonNegative()) {
// We know that the sign bit is zero.
Known.makeNonNegative();
}
}
break;
case ICmpInst::ICMP_SGT:
// assume(v >_s c) where c is at least -1.
if (match(Cmp, m_ICmp(Pred, m_V, m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth + 1, QueryNoAC).anyextOrTrunc(BitWidth);
if (RHSKnown.isAllOnes() || RHSKnown.isNonNegative()) {
// We know that the sign bit is zero.
Known.makeNonNegative();
}
}
break;
case ICmpInst::ICMP_SLE:
// assume(v <=_s c) where c is negative
if (match(Cmp, m_ICmp(Pred, m_V, m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth + 1, QueryNoAC).anyextOrTrunc(BitWidth);
if (RHSKnown.isNegative()) {
// We know that the sign bit is one.
Known.makeNegative();
}
}
break;
case ICmpInst::ICMP_SLT:
// assume(v <_s c) where c is non-positive
if (match(Cmp, m_ICmp(Pred, m_V, m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
if (RHSKnown.isZero() || RHSKnown.isNegative()) {
// We know that the sign bit is one.
Known.makeNegative();
}
}
break;
case ICmpInst::ICMP_ULE:
// assume(v <=_u c)
if (match(Cmp, m_ICmp(Pred, m_V, m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
// Whatever high bits in c are zero are known to be zero.
Known.Zero.setHighBits(RHSKnown.countMinLeadingZeros());
}
break;
case ICmpInst::ICMP_ULT:
// assume(v <_u c)
if (match(Cmp, m_ICmp(Pred, m_V, m_Value(A))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
KnownBits RHSKnown =
computeKnownBits(A, Depth+1, QueryNoAC).anyextOrTrunc(BitWidth);
// If the RHS is known zero, then this assumption must be wrong (nothing
// is unsigned less than zero). Signal a conflict and get out of here.
if (RHSKnown.isZero()) {
Known.Zero.setAllBits();
Known.One.setAllBits();
break;
}
// Whatever high bits in c are zero are known to be zero (if c is a power
// of 2, then one more).
if (isKnownToBeAPowerOfTwo(A, false, Depth + 1, QueryNoAC))
Known.Zero.setHighBits(RHSKnown.countMinLeadingZeros() + 1);
else
Known.Zero.setHighBits(RHSKnown.countMinLeadingZeros());
}
break;
}
}
// If assumptions conflict with each other or previous known bits, then we
// have a logical fallacy. It's possible that the assumption is not reachable,
// so this isn't a real bug. On the other hand, the program may have undefined
// behavior, or we might have a bug in the compiler. We can't assert/crash, so
// clear out the known bits, try to warn the user, and hope for the best.
if (Known.Zero.intersects(Known.One)) {
Known.resetAll();
if (Q.ORE)
Q.ORE->emit([&]() {
auto *CxtI = const_cast<Instruction *>(Q.CxtI);
return OptimizationRemarkAnalysis("value-tracking", "BadAssumption",
CxtI)
<< "Detected conflicting code assumptions. Program may "
"have undefined behavior, or compiler may have "
"internal error.";
});
}
}
/// Compute known bits from a shift operator, including those with a
/// non-constant shift amount. Known is the output of this function. Known2 is a
/// pre-allocated temporary with the same bit width as Known and on return
/// contains the known bit of the shift value source. KF is an
/// operator-specific function that, given the known-bits and a shift amount,
/// compute the implied known-bits of the shift operator's result respectively
/// for that shift amount. The results from calling KF are conservatively
/// combined for all permitted shift amounts.
static void computeKnownBitsFromShiftOperator(
const Operator *I, const APInt &DemandedElts, KnownBits &Known,
KnownBits &Known2, unsigned Depth, const Query &Q,
function_ref<KnownBits(const KnownBits &, const KnownBits &)> KF) {
unsigned BitWidth = Known.getBitWidth();
computeKnownBits(I->getOperand(0), DemandedElts, Known2, Depth + 1, Q);
computeKnownBits(I->getOperand(1), DemandedElts, Known, Depth + 1, Q);
// Note: We cannot use Known.Zero.getLimitedValue() here, because if
// BitWidth > 64 and any upper bits are known, we'll end up returning the
// limit value (which implies all bits are known).
uint64_t ShiftAmtKZ = Known.Zero.zextOrTrunc(64).getZExtValue();
uint64_t ShiftAmtKO = Known.One.zextOrTrunc(64).getZExtValue();
bool ShiftAmtIsConstant = Known.isConstant();
bool MaxShiftAmtIsOutOfRange = Known.getMaxValue().uge(BitWidth);
if (ShiftAmtIsConstant) {
Known = KF(Known2, Known);
// If the known bits conflict, this must be an overflowing left shift, so
// the shift result is poison. We can return anything we want. Choose 0 for
// the best folding opportunity.
if (Known.hasConflict())
Known.setAllZero();
return;
}
// If the shift amount could be greater than or equal to the bit-width of the
// LHS, the value could be poison, but bail out because the check below is
// expensive.
// TODO: Should we just carry on?
if (MaxShiftAmtIsOutOfRange) {
Known.resetAll();
return;
}
// It would be more-clearly correct to use the two temporaries for this
// calculation. Reusing the APInts here to prevent unnecessary allocations.
Known.resetAll();
// If we know the shifter operand is nonzero, we can sometimes infer more
// known bits. However this is expensive to compute, so be lazy about it and
// only compute it when absolutely necessary.
Optional<bool> ShifterOperandIsNonZero;
// Early exit if we can't constrain any well-defined shift amount.
if (!(ShiftAmtKZ & (PowerOf2Ceil(BitWidth) - 1)) &&
!(ShiftAmtKO & (PowerOf2Ceil(BitWidth) - 1))) {
ShifterOperandIsNonZero =
isKnownNonZero(I->getOperand(1), DemandedElts, Depth + 1, Q);
if (!*ShifterOperandIsNonZero)
return;
}
Known.Zero.setAllBits();
Known.One.setAllBits();
for (unsigned ShiftAmt = 0; ShiftAmt < BitWidth; ++ShiftAmt) {
// Combine the shifted known input bits only for those shift amounts
// compatible with its known constraints.
if ((ShiftAmt & ~ShiftAmtKZ) != ShiftAmt)
continue;
if ((ShiftAmt | ShiftAmtKO) != ShiftAmt)
continue;
// If we know the shifter is nonzero, we may be able to infer more known
// bits. This check is sunk down as far as possible to avoid the expensive
// call to isKnownNonZero if the cheaper checks above fail.
if (ShiftAmt == 0) {
if (!ShifterOperandIsNonZero)
ShifterOperandIsNonZero =
isKnownNonZero(I->getOperand(1), DemandedElts, Depth + 1, Q);
if (*ShifterOperandIsNonZero)
continue;
}
Known = KnownBits::commonBits(
Known, KF(Known2, KnownBits::makeConstant(APInt(32, ShiftAmt))));
}
// If the known bits conflict, the result is poison. Return a 0 and hope the
// caller can further optimize that.
if (Known.hasConflict())
Known.setAllZero();
}
static void computeKnownBitsFromOperator(const Operator *I,
const APInt &DemandedElts,
KnownBits &Known, unsigned Depth,
const Query &Q) {
unsigned BitWidth = Known.getBitWidth();
KnownBits Known2(BitWidth);
switch (I->getOpcode()) {
default: break;
case Instruction::Load:
if (MDNode *MD =
Q.IIQ.getMetadata(cast<LoadInst>(I), LLVMContext::MD_range))
computeKnownBitsFromRangeMetadata(*MD, Known);
break;
case Instruction::And: {
// If either the LHS or the RHS are Zero, the result is zero.
computeKnownBits(I->getOperand(1), DemandedElts, Known, Depth + 1, Q);
computeKnownBits(I->getOperand(0), DemandedElts, Known2, Depth + 1, Q);
Known &= Known2;
// and(x, add (x, -1)) is a common idiom that always clears the low bit;
// here we handle the more general case of adding any odd number by
// matching the form add(x, add(x, y)) where y is odd.
// TODO: This could be generalized to clearing any bit set in y where the
// following bit is known to be unset in y.
Value *X = nullptr, *Y = nullptr;
if (!Known.Zero[0] && !Known.One[0] &&
match(I, m_c_BinOp(m_Value(X), m_Add(m_Deferred(X), m_Value(Y))))) {
Known2.resetAll();
computeKnownBits(Y, DemandedElts, Known2, Depth + 1, Q);
if (Known2.countMinTrailingOnes() > 0)
Known.Zero.setBit(0);
}
break;
}
case Instruction::Or:
computeKnownBits(I->getOperand(1), DemandedElts, Known, Depth + 1, Q);
computeKnownBits(I->getOperand(0), DemandedElts, Known2, Depth + 1, Q);
Known |= Known2;
break;
case Instruction::Xor:
computeKnownBits(I->getOperand(1), DemandedElts, Known, Depth + 1, Q);
computeKnownBits(I->getOperand(0), DemandedElts, Known2, Depth + 1, Q);
Known ^= Known2;
break;
case Instruction::Mul: {
bool NSW = Q.IIQ.hasNoSignedWrap(cast<OverflowingBinaryOperator>(I));
computeKnownBitsMul(I->getOperand(0), I->getOperand(1), NSW, DemandedElts,
Known, Known2, Depth, Q);
break;
}
case Instruction::UDiv: {
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);
Known = KnownBits::udiv(Known, Known2);
break;
}
case Instruction::Select: {
const Value *LHS = nullptr, *RHS = nullptr;
SelectPatternFlavor SPF = matchSelectPattern(I, LHS, RHS).Flavor;
if (SelectPatternResult::isMinOrMax(SPF)) {
computeKnownBits(RHS, Known, Depth + 1, Q);
computeKnownBits(LHS, Known2, Depth + 1, Q);
switch (SPF) {
default:
llvm_unreachable("Unhandled select pattern flavor!");
case SPF_SMAX:
Known = KnownBits::smax(Known, Known2);
break;
case SPF_SMIN:
Known = KnownBits::smin(Known, Known2);
break;
case SPF_UMAX:
Known = KnownBits::umax(Known, Known2);
break;
case SPF_UMIN:
Known = KnownBits::umin(Known, Known2);
break;
}
break;
}
computeKnownBits(I->getOperand(2), Known, Depth + 1, Q);
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);
// Only known if known in both the LHS and RHS.
Known = KnownBits::commonBits(Known, Known2);
if (SPF == SPF_ABS) {
// RHS from matchSelectPattern returns the negation part of abs pattern.
// If the negate has an NSW flag we can assume the sign bit of the result
// will be 0 because that makes abs(INT_MIN) undefined.
if (match(RHS, m_Neg(m_Specific(LHS))) &&
Q.IIQ.hasNoSignedWrap(cast<OverflowingBinaryOperator>(RHS)))
Known.Zero.setSignBit();
}
break;
}
case Instruction::FPTrunc:
case Instruction::FPExt:
case Instruction::FPToUI:
case Instruction::FPToSI:
case Instruction::SIToFP:
case Instruction::UIToFP:
break; // Can't work with floating point.
case Instruction::PtrToInt:
case Instruction::IntToPtr:
// Fall through and handle them the same as zext/trunc.
LLVM_FALLTHROUGH;
case Instruction::ZExt:
case Instruction::Trunc: {
Type *SrcTy = I->getOperand(0)->getType();
unsigned SrcBitWidth;
// Note that we handle pointer operands here because of inttoptr/ptrtoint
// which fall through here.
Type *ScalarTy = SrcTy->getScalarType();
SrcBitWidth = ScalarTy->isPointerTy() ?
Q.DL.getPointerTypeSizeInBits(ScalarTy) :
Q.DL.getTypeSizeInBits(ScalarTy);
assert(SrcBitWidth && "SrcBitWidth can't be zero");
Known = Known.anyextOrTrunc(SrcBitWidth);
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
Known = Known.zextOrTrunc(BitWidth);
break;
}
case Instruction::BitCast: {
Type *SrcTy = I->getOperand(0)->getType();
if (SrcTy->isIntOrPtrTy() &&
// TODO: For now, not handling conversions like:
// (bitcast i64 %x to <2 x i32>)
!I->getType()->isVectorTy()) {
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
break;
}
// Handle cast from vector integer type to scalar or vector integer.
auto *SrcVecTy = dyn_cast<FixedVectorType>(SrcTy);
if (!SrcVecTy || !SrcVecTy->getElementType()->isIntegerTy() ||
!I->getType()->isIntOrIntVectorTy())
break;
// Look through a cast from narrow vector elements to wider type.
// Examples: v4i32 -> v2i64, v3i8 -> v24
unsigned SubBitWidth = SrcVecTy->getScalarSizeInBits();
if (BitWidth % SubBitWidth == 0) {
// Known bits are automatically intersected across demanded elements of a
// vector. So for example, if a bit is computed as known zero, it must be
// zero across all demanded elements of the vector.
//
// For this bitcast, each demanded element of the output is sub-divided
// across a set of smaller vector elements in the source vector. To get
// the known bits for an entire element of the output, compute the known
// bits for each sub-element sequentially. This is done by shifting the
// one-set-bit demanded elements parameter across the sub-elements for
// consecutive calls to computeKnownBits. We are using the demanded
// elements parameter as a mask operator.
//
// The known bits of each sub-element are then inserted into place
// (dependent on endian) to form the full result of known bits.
unsigned NumElts = DemandedElts.getBitWidth();
unsigned SubScale = BitWidth / SubBitWidth;
APInt SubDemandedElts = APInt::getZero(NumElts * SubScale);
for (unsigned i = 0; i != NumElts; ++i) {
if (DemandedElts[i])
SubDemandedElts.setBit(i * SubScale);
}
KnownBits KnownSrc(SubBitWidth);
for (unsigned i = 0; i != SubScale; ++i) {
computeKnownBits(I->getOperand(0), SubDemandedElts.shl(i), KnownSrc,
Depth + 1, Q);
unsigned ShiftElt = Q.DL.isLittleEndian() ? i : SubScale - 1 - i;
Known.insertBits(KnownSrc, ShiftElt * SubBitWidth);
}
}
break;
}
case Instruction::SExt: {
// Compute the bits in the result that are not present in the input.
unsigned SrcBitWidth = I->getOperand(0)->getType()->getScalarSizeInBits();
Known = Known.trunc(SrcBitWidth);
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
// If the sign bit of the input is known set or clear, then we know the
// top bits of the result.
Known = Known.sext(BitWidth);
break;
}
case Instruction::Shl: {
bool NSW = Q.IIQ.hasNoSignedWrap(cast<OverflowingBinaryOperator>(I));
auto KF = [NSW](const KnownBits &KnownVal, const KnownBits &KnownAmt) {
KnownBits Result = KnownBits::shl(KnownVal, KnownAmt);
// If this shift has "nsw" keyword, then the result is either a poison
// value or has the same sign bit as the first operand.
if (NSW) {
if (KnownVal.Zero.isSignBitSet())
Result.Zero.setSignBit();
if (KnownVal.One.isSignBitSet())
Result.One.setSignBit();
}
return Result;
};
computeKnownBitsFromShiftOperator(I, DemandedElts, Known, Known2, Depth, Q,
KF);
// Trailing zeros of a right-shifted constant never decrease.
const APInt *C;
if (match(I->getOperand(0), m_APInt(C)))
Known.Zero.setLowBits(C->countTrailingZeros());
break;
}
case Instruction::LShr: {
auto KF = [](const KnownBits &KnownVal, const KnownBits &KnownAmt) {
return KnownBits::lshr(KnownVal, KnownAmt);
};
computeKnownBitsFromShiftOperator(I, DemandedElts, Known, Known2, Depth, Q,
KF);
// Leading zeros of a left-shifted constant never decrease.
const APInt *C;
if (match(I->getOperand(0), m_APInt(C)))
Known.Zero.setHighBits(C->countLeadingZeros());
break;
}
case Instruction::AShr: {
auto KF = [](const KnownBits &KnownVal, const KnownBits &KnownAmt) {
return KnownBits::ashr(KnownVal, KnownAmt);
};
computeKnownBitsFromShiftOperator(I, DemandedElts, Known, Known2, Depth, Q,
KF);
break;
}
case Instruction::Sub: {
bool NSW = Q.IIQ.hasNoSignedWrap(cast<OverflowingBinaryOperator>(I));
computeKnownBitsAddSub(false, I->getOperand(0), I->getOperand(1), NSW,
DemandedElts, Known, Known2, Depth, Q);
break;
}
case Instruction::Add: {
bool NSW = Q.IIQ.hasNoSignedWrap(cast<OverflowingBinaryOperator>(I));
computeKnownBitsAddSub(true, I->getOperand(0), I->getOperand(1), NSW,
DemandedElts, Known, Known2, Depth, Q);
break;
}
case Instruction::SRem:
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);
Known = KnownBits::srem(Known, Known2);
break;
case Instruction::URem:
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);
Known = KnownBits::urem(Known, Known2);
break;
case Instruction::Alloca:
Known.Zero.setLowBits(Log2(cast<AllocaInst>(I)->getAlign()));
break;
case Instruction::GetElementPtr: {
// Analyze all of the subscripts of this getelementptr instruction
// to determine if we can prove known low zero bits.
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
// Accumulate the constant indices in a separate variable
// to minimize the number of calls to computeForAddSub.
APInt AccConstIndices(BitWidth, 0, /*IsSigned*/ true);
gep_type_iterator GTI = gep_type_begin(I);
for (unsigned i = 1, e = I->getNumOperands(); i != e; ++i, ++GTI) {
// TrailZ can only become smaller, short-circuit if we hit zero.
if (Known.isUnknown())
break;
Value *Index = I->getOperand(i);
// Handle case when index is zero.
Constant *CIndex = dyn_cast<Constant>(Index);
if (CIndex && CIndex->isZeroValue())
continue;
if (StructType *STy = GTI.getStructTypeOrNull()) {
// Handle struct member offset arithmetic.
assert(CIndex &&
"Access to structure field must be known at compile time");
if (CIndex->getType()->isVectorTy())
Index = CIndex->getSplatValue();
unsigned Idx = cast<ConstantInt>(Index)->getZExtValue();
const StructLayout *SL = Q.DL.getStructLayout(STy);
uint64_t Offset = SL->getElementOffset(Idx);
AccConstIndices += Offset;
continue;
}
// Handle array index arithmetic.
Type *IndexedTy = GTI.getIndexedType();
if (!IndexedTy->isSized()) {
Known.resetAll();
break;
}
unsigned IndexBitWidth = Index->getType()->getScalarSizeInBits();
KnownBits IndexBits(IndexBitWidth);
computeKnownBits(Index, IndexBits, Depth + 1, Q);
TypeSize IndexTypeSize = Q.DL.getTypeAllocSize(IndexedTy);
uint64_t TypeSizeInBytes = IndexTypeSize.getKnownMinSize();
KnownBits ScalingFactor(IndexBitWidth);
// Multiply by current sizeof type.
// &A[i] == A + i * sizeof(*A[i]).
if (IndexTypeSize.isScalable()) {
// For scalable types the only thing we know about sizeof is
// that this is a multiple of the minimum size.
ScalingFactor.Zero.setLowBits(countTrailingZeros(TypeSizeInBytes));
} else if (IndexBits.isConstant()) {
APInt IndexConst = IndexBits.getConstant();
APInt ScalingFactor(IndexBitWidth, TypeSizeInBytes);
IndexConst *= ScalingFactor;
AccConstIndices += IndexConst.sextOrTrunc(BitWidth);
continue;
} else {
ScalingFactor =
KnownBits::makeConstant(APInt(IndexBitWidth, TypeSizeInBytes));
}
IndexBits = KnownBits::mul(IndexBits, ScalingFactor);
// If the offsets have a different width from the pointer, according
// to the language reference we need to sign-extend or truncate them
// to the width of the pointer.
IndexBits = IndexBits.sextOrTrunc(BitWidth);
// Note that inbounds does *not* guarantee nsw for the addition, as only
// the offset is signed, while the base address is unsigned.
Known = KnownBits::computeForAddSub(
/*Add=*/true, /*NSW=*/false, Known, IndexBits);
}
if (!Known.isUnknown() && !AccConstIndices.isZero()) {
KnownBits Index = KnownBits::makeConstant(AccConstIndices);
Known = KnownBits::computeForAddSub(
/*Add=*/true, /*NSW=*/false, Known, Index);
}
break;
}
case Instruction::PHI: {
const PHINode *P = cast<PHINode>(I);
BinaryOperator *BO = nullptr;
Value *R = nullptr, *L = nullptr;
if (matchSimpleRecurrence(P, BO, R, L)) {
// Handle the case of a simple two-predecessor recurrence PHI.
// There's a lot more that could theoretically be done here, but
// this is sufficient to catch some interesting cases.
unsigned Opcode = BO->getOpcode();
// If this is a shift recurrence, we know the bits being shifted in.
// We can combine that with information about the start value of the
// recurrence to conclude facts about the result.
if ((Opcode == Instruction::LShr || Opcode == Instruction::AShr ||
Opcode == Instruction::Shl) &&
BO->getOperand(0) == I) {
// We have matched a recurrence of the form:
// %iv = [R, %entry], [%iv.next, %backedge]
// %iv.next = shift_op %iv, L
// Recurse with the phi context to avoid concern about whether facts
// inferred hold at original context instruction. TODO: It may be
// correct to use the original context. IF warranted, explore and
// add sufficient tests to cover.
Query RecQ = Q;
RecQ.CxtI = P;
computeKnownBits(R, DemandedElts, Known2, Depth + 1, RecQ);
switch (Opcode) {
case Instruction::Shl:
// A shl recurrence will only increase the tailing zeros
Known.Zero.setLowBits(Known2.countMinTrailingZeros());
break;
case Instruction::LShr:
// A lshr recurrence will preserve the leading zeros of the
// start value
Known.Zero.setHighBits(Known2.countMinLeadingZeros());
break;
case Instruction::AShr:
// An ashr recurrence will extend the initial sign bit
Known.Zero.setHighBits(Known2.countMinLeadingZeros());
Known.One.setHighBits(Known2.countMinLeadingOnes());
break;
};
}
// Check for operations that have the property that if
// both their operands have low zero bits, the result
// will have low zero bits.
if (Opcode == Instruction::Add ||
Opcode == Instruction::Sub ||
Opcode == Instruction::And ||
Opcode == Instruction::Or ||
Opcode == Instruction::Mul) {
// Change the context instruction to the "edge" that flows into the
// phi. This is important because that is where the value is actually
// "evaluated" even though it is used later somewhere else. (see also
// D69571).
Query RecQ = Q;
unsigned OpNum = P->getOperand(0) == R ? 0 : 1;
Instruction *RInst = P->getIncomingBlock(OpNum)->getTerminator();
Instruction *LInst = P->getIncomingBlock(1-OpNum)->getTerminator();
// Ok, we have a PHI of the form L op= R. Check for low
// zero bits.
RecQ.CxtI = RInst;
computeKnownBits(R, Known2, Depth + 1, RecQ);
// We need to take the minimum number of known bits
KnownBits Known3(BitWidth);
RecQ.CxtI = LInst;
computeKnownBits(L, Known3, Depth + 1, RecQ);
Known.Zero.setLowBits(std::min(Known2.countMinTrailingZeros(),
Known3.countMinTrailingZeros()));
auto *OverflowOp = dyn_cast<OverflowingBinaryOperator>(BO);
if (OverflowOp && Q.IIQ.hasNoSignedWrap(OverflowOp)) {
// If initial value of recurrence is nonnegative, and we are adding
// a nonnegative number with nsw, the result can only be nonnegative
// or poison value regardless of the number of times we execute the
// add in phi recurrence. If initial value is negative and we are
// adding a negative number with nsw, the result can only be
// negative or poison value. Similar arguments apply to sub and mul.
//
// (add non-negative, non-negative) --> non-negative
// (add negative, negative) --> negative
if (Opcode == Instruction::Add) {
if (Known2.isNonNegative() && Known3.isNonNegative())
Known.makeNonNegative();
else if (Known2.isNegative() && Known3.isNegative())
Known.makeNegative();
}
// (sub nsw non-negative, negative) --> non-negative
// (sub nsw negative, non-negative) --> negative
else if (Opcode == Instruction::Sub && BO->getOperand(0) == I) {
if (Known2.isNonNegative() && Known3.isNegative())
Known.makeNonNegative();
else if (Known2.isNegative() && Known3.isNonNegative())
Known.makeNegative();
}
// (mul nsw non-negative, non-negative) --> non-negative
else if (Opcode == Instruction::Mul && Known2.isNonNegative() &&
Known3.isNonNegative())
Known.makeNonNegative();
}
break;
}
}
// Unreachable blocks may have zero-operand PHI nodes.
if (P->getNumIncomingValues() == 0)
break;
// Otherwise take the unions of the known bit sets of the operands,
// taking conservative care to avoid excessive recursion.
if (Depth < MaxAnalysisRecursionDepth - 1 && !Known.Zero && !Known.One) {
// Skip if every incoming value references to ourself.
if (isa_and_nonnull<UndefValue>(P->hasConstantValue()))
break;
Known.Zero.setAllBits();
Known.One.setAllBits();
for (unsigned u = 0, e = P->getNumIncomingValues(); u < e; ++u) {
Value *IncValue = P->getIncomingValue(u);
// Skip direct self references.
if (IncValue == P) continue;
// Change the context instruction to the "edge" that flows into the
// phi. This is important because that is where the value is actually
// "evaluated" even though it is used later somewhere else. (see also
// D69571).
Query RecQ = Q;
RecQ.CxtI = P->getIncomingBlock(u)->getTerminator();
Known2 = KnownBits(BitWidth);
// Recurse, but cap the recursion to one level, because we don't
// want to waste time spinning around in loops.
computeKnownBits(IncValue, Known2, MaxAnalysisRecursionDepth - 1, RecQ);
Known = KnownBits::commonBits(Known, Known2);
// If all bits have been ruled out, there's no need to check
// more operands.
if (Known.isUnknown())
break;
}
}
break;
}
case Instruction::Call:
case Instruction::Invoke:
// If range metadata is attached to this call, set known bits from that,
// and then intersect with known bits based on other properties of the
// function.
if (MDNode *MD =
Q.IIQ.getMetadata(cast<Instruction>(I), LLVMContext::MD_range))
computeKnownBitsFromRangeMetadata(*MD, Known);
if (const Value *RV = cast<CallBase>(I)->getReturnedArgOperand()) {
computeKnownBits(RV, Known2, Depth + 1, Q);
Known.Zero |= Known2.Zero;
Known.One |= Known2.One;
}
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
switch (II->getIntrinsicID()) {
default: break;
case Intrinsic::abs: {
computeKnownBits(I->getOperand(0), Known2, Depth + 1, Q);
bool IntMinIsPoison = match(II->getArgOperand(1), m_One());
Known = Known2.abs(IntMinIsPoison);
break;
}
case Intrinsic::bitreverse:
computeKnownBits(I->getOperand(0), DemandedElts, Known2, Depth + 1, Q);
Known.Zero |= Known2.Zero.reverseBits();
Known.One |= Known2.One.reverseBits();
break;
case Intrinsic::bswap:
computeKnownBits(I->getOperand(0), DemandedElts, Known2, Depth + 1, Q);
Known.Zero |= Known2.Zero.byteSwap();
Known.One |= Known2.One.byteSwap();
break;
case Intrinsic::ctlz: {
computeKnownBits(I->getOperand(0), Known2, Depth + 1, Q);
// If we have a known 1, its position is our upper bound.
unsigned PossibleLZ = Known2.countMaxLeadingZeros();
// If this call is poison for 0 input, the result will be less than 2^n.
if (II->getArgOperand(1) == ConstantInt::getTrue(II->getContext()))
PossibleLZ = std::min(PossibleLZ, BitWidth - 1);
unsigned LowBits = Log2_32(PossibleLZ)+1;
Known.Zero.setBitsFrom(LowBits);
break;
}
case Intrinsic::cttz: {
computeKnownBits(I->getOperand(0), Known2, Depth + 1, Q);
// If we have a known 1, its position is our upper bound.
unsigned PossibleTZ = Known2.countMaxTrailingZeros();
// If this call is poison for 0 input, the result will be less than 2^n.
if (II->getArgOperand(1) == ConstantInt::getTrue(II->getContext()))
PossibleTZ = std::min(PossibleTZ, BitWidth - 1);
unsigned LowBits = Log2_32(PossibleTZ)+1;
Known.Zero.setBitsFrom(LowBits);
break;
}
case Intrinsic::ctpop: {
computeKnownBits(I->getOperand(0), Known2, Depth + 1, Q);
// We can bound the space the count needs. Also, bits known to be zero
// can't contribute to the population.
unsigned BitsPossiblySet = Known2.countMaxPopulation();
unsigned LowBits = Log2_32(BitsPossiblySet)+1;
Known.Zero.setBitsFrom(LowBits);
// TODO: we could bound KnownOne using the lower bound on the number
// of bits which might be set provided by popcnt KnownOne2.
break;
}
case Intrinsic::fshr:
case Intrinsic::fshl: {
const APInt *SA;
if (!match(I->getOperand(2), m_APInt(SA)))
break;
// Normalize to funnel shift left.
uint64_t ShiftAmt = SA->urem(BitWidth);
if (II->getIntrinsicID() == Intrinsic::fshr)
ShiftAmt = BitWidth - ShiftAmt;
KnownBits Known3(BitWidth);
computeKnownBits(I->getOperand(0), Known2, Depth + 1, Q);
computeKnownBits(I->getOperand(1), Known3, Depth + 1, Q);
Known.Zero =
Known2.Zero.shl(ShiftAmt) | Known3.Zero.lshr(BitWidth - ShiftAmt);
Known.One =
Known2.One.shl(ShiftAmt) | Known3.One.lshr(BitWidth - ShiftAmt);
break;
}
case Intrinsic::uadd_sat:
case Intrinsic::usub_sat: {
bool IsAdd = II->getIntrinsicID() == Intrinsic::uadd_sat;
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);
// Add: Leading ones of either operand are preserved.
// Sub: Leading zeros of LHS and leading ones of RHS are preserved
// as leading zeros in the result.
unsigned LeadingKnown;
if (IsAdd)
LeadingKnown = std::max(Known.countMinLeadingOnes(),
Known2.countMinLeadingOnes());
else
LeadingKnown = std::max(Known.countMinLeadingZeros(),
Known2.countMinLeadingOnes());
Known = KnownBits::computeForAddSub(
IsAdd, /* NSW */ false, Known, Known2);
// We select between the operation result and all-ones/zero
// respectively, so we can preserve known ones/zeros.
if (IsAdd) {
Known.One.setHighBits(LeadingKnown);
Known.Zero.clearAllBits();
} else {
Known.Zero.setHighBits(LeadingKnown);
Known.One.clearAllBits();
}
break;
}
case Intrinsic::umin:
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);
Known = KnownBits::umin(Known, Known2);
break;
case Intrinsic::umax:
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);
Known = KnownBits::umax(Known, Known2);
break;
case Intrinsic::smin:
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);
Known = KnownBits::smin(Known, Known2);
break;
case Intrinsic::smax:
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);
Known = KnownBits::smax(Known, Known2);
break;
case Intrinsic::x86_sse42_crc32_64_64:
Known.Zero.setBitsFrom(32);
break;
case Intrinsic::riscv_vsetvli:
case Intrinsic::riscv_vsetvlimax:
// Assume that VL output is positive and would fit in an int32_t.
// TODO: VLEN might be capped at 16 bits in a future V spec update.
if (BitWidth >= 32)
Known.Zero.setBitsFrom(31);
break;
case Intrinsic::vscale: {
if (!II->getParent() || !II->getFunction() ||
!II->getFunction()->hasFnAttribute(Attribute::VScaleRange))
break;
auto Attr = II->getFunction()->getFnAttribute(Attribute::VScaleRange);
Optional<unsigned> VScaleMax = Attr.getVScaleRangeMax();
if (!VScaleMax)
break;
unsigned VScaleMin = Attr.getVScaleRangeMin();
// If vscale min = max then we know the exact value at compile time
// and hence we know the exact bits.
if (VScaleMin == VScaleMax) {
Known.One = VScaleMin;
Known.Zero = VScaleMin;
Known.Zero.flipAllBits();
break;
}
unsigned FirstZeroHighBit = 32 - countLeadingZeros(*VScaleMax);
if (FirstZeroHighBit < BitWidth)
Known.Zero.setBitsFrom(FirstZeroHighBit);
break;
}
}
}
break;
case Instruction::ShuffleVector: {
auto *Shuf = dyn_cast<ShuffleVectorInst>(I);
// FIXME: Do we need to handle ConstantExpr involving shufflevectors?
if (!Shuf) {
Known.resetAll();
return;
}
// For undef elements, we don't know anything about the common state of
// the shuffle result.
APInt DemandedLHS, DemandedRHS;
if (!getShuffleDemandedElts(Shuf, DemandedElts, DemandedLHS, DemandedRHS)) {
Known.resetAll();
return;
}
Known.One.setAllBits();
Known.Zero.setAllBits();
if (!!DemandedLHS) {
const Value *LHS = Shuf->getOperand(0);
computeKnownBits(LHS, DemandedLHS, Known, Depth + 1, Q);
// If we don't know any bits, early out.
if (Known.isUnknown())
break;
}
if (!!DemandedRHS) {
const Value *RHS = Shuf->getOperand(1);
computeKnownBits(RHS, DemandedRHS, Known2, Depth + 1, Q);
Known = KnownBits::commonBits(Known, Known2);
}
break;
}
case Instruction::InsertElement: {
const Value *Vec = I->getOperand(0);
const Value *Elt = I->getOperand(1);
auto *CIdx = dyn_cast<ConstantInt>(I->getOperand(2));
// Early out if the index is non-constant or out-of-range.
unsigned NumElts = DemandedElts.getBitWidth();
if (!CIdx || CIdx->getValue().uge(NumElts)) {
Known.resetAll();
return;
}
Known.One.setAllBits();
Known.Zero.setAllBits();
unsigned EltIdx = CIdx->getZExtValue();
// Do we demand the inserted element?
if (DemandedElts[EltIdx]) {
computeKnownBits(Elt, Known, Depth + 1, Q);
// If we don't know any bits, early out.
if (Known.isUnknown())
break;
}
// We don't need the base vector element that has been inserted.
APInt DemandedVecElts = DemandedElts;
DemandedVecElts.clearBit(EltIdx);
if (!!DemandedVecElts) {
computeKnownBits(Vec, DemandedVecElts, Known2, Depth + 1, Q);
Known = KnownBits::commonBits(Known, Known2);
}
break;
}
case Instruction::ExtractElement: {
// Look through extract element. If the index is non-constant or
// out-of-range demand all elements, otherwise just the extracted element.
const Value *Vec = I->getOperand(0);
const Value *Idx = I->getOperand(1);
auto *CIdx = dyn_cast<ConstantInt>(Idx);
if (isa<ScalableVectorType>(Vec->getType())) {
// FIXME: there's probably *something* we can do with scalable vectors
Known.resetAll();
break;
}
unsigned NumElts = cast<FixedVectorType>(Vec->getType())->getNumElements();
APInt DemandedVecElts = APInt::getAllOnes(NumElts);
if (CIdx && CIdx->getValue().ult(NumElts))
DemandedVecElts = APInt::getOneBitSet(NumElts, CIdx->getZExtValue());
computeKnownBits(Vec, DemandedVecElts, Known, Depth + 1, Q);
break;
}
case Instruction::ExtractValue:
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I->getOperand(0))) {
const ExtractValueInst *EVI = cast<ExtractValueInst>(I);
if (EVI->getNumIndices() != 1) break;
if (EVI->getIndices()[0] == 0) {
switch (II->getIntrinsicID()) {
default: break;
case Intrinsic::uadd_with_overflow:
case Intrinsic::sadd_with_overflow:
computeKnownBitsAddSub(true, II->getArgOperand(0),
II->getArgOperand(1), false, DemandedElts,
Known, Known2, Depth, Q);
break;
case Intrinsic::usub_with_overflow:
case Intrinsic::ssub_with_overflow:
computeKnownBitsAddSub(false, II->getArgOperand(0),
II->getArgOperand(1), false, DemandedElts,
Known, Known2, Depth, Q);
break;
case Intrinsic::umul_with_overflow:
case Intrinsic::smul_with_overflow:
computeKnownBitsMul(II->getArgOperand(0), II->getArgOperand(1), false,
DemandedElts, Known, Known2, Depth, Q);
break;
}
}
}
break;
case Instruction::Freeze:
if (isGuaranteedNotToBePoison(I->getOperand(0), Q.AC, Q.CxtI, Q.DT,
Depth + 1))
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
break;
}
}
/// Determine which bits of V are known to be either zero or one and return
/// them.
KnownBits computeKnownBits(const Value *V, const APInt &DemandedElts,
unsigned Depth, const Query &Q) {
KnownBits Known(getBitWidth(V->getType(), Q.DL));
computeKnownBits(V, DemandedElts, Known, Depth, Q);
return Known;
}
/// Determine which bits of V are known to be either zero or one and return
/// them.
KnownBits computeKnownBits(const Value *V, unsigned Depth, const Query &Q) {
KnownBits Known(getBitWidth(V->getType(), Q.DL));
computeKnownBits(V, Known, Depth, Q);
return Known;
}
/// Determine which bits of V are known to be either zero or one and return
/// them in the Known bit set.
///
/// NOTE: we cannot consider 'undef' to be "IsZero" here. The problem is that
/// we cannot optimize based on the assumption that it is zero without changing
/// it to be an explicit zero. If we don't change it to zero, other code could
/// optimized based on the contradictory assumption that it is non-zero.
/// Because instcombine aggressively folds operations with undef args anyway,
/// this won't lose us code quality.
///
/// This function is defined on values with integer type, values with pointer
/// type, and vectors of integers. In the case
/// where V is a vector, known zero, and known one values are the
/// same width as the vector element, and the bit is set only if it is true
/// for all of the demanded elements in the vector specified by DemandedElts.
void computeKnownBits(const Value *V, const APInt &DemandedElts,
KnownBits &Known, unsigned Depth, const Query &Q) {
if (!DemandedElts || isa<ScalableVectorType>(V->getType())) {
// No demanded elts or V is a scalable vector, better to assume we don't
// know anything.
Known.resetAll();
return;
}
assert(V && "No Value?");
assert(Depth <= MaxAnalysisRecursionDepth && "Limit Search Depth");
#ifndef NDEBUG
Type *Ty = V->getType();
unsigned BitWidth = Known.getBitWidth();
assert((Ty->isIntOrIntVectorTy(BitWidth) || Ty->isPtrOrPtrVectorTy()) &&
"Not integer or pointer type!");
if (auto *FVTy = dyn_cast<FixedVectorType>(Ty)) {
assert(
FVTy->getNumElements() == DemandedElts.getBitWidth() &&
"DemandedElt width should equal the fixed vector number of elements");
} else {
assert(DemandedElts == APInt(1, 1) &&
"DemandedElt width should be 1 for scalars");
}
Type *ScalarTy = Ty->getScalarType();
if (ScalarTy->isPointerTy()) {
assert(BitWidth == Q.DL.getPointerTypeSizeInBits(ScalarTy) &&
"V and Known should have same BitWidth");
} else {
assert(BitWidth == Q.DL.getTypeSizeInBits(ScalarTy) &&
"V and Known should have same BitWidth");
}
#endif
const APInt *C;
if (match(V, m_APInt(C))) {
// We know all of the bits for a scalar constant or a splat vector constant!
Known = KnownBits::makeConstant(*C);
return;
}
// Null and aggregate-zero are all-zeros.
if (isa<ConstantPointerNull>(V) || isa<ConstantAggregateZero>(V)) {
Known.setAllZero();
return;
}
// Handle a constant vector by taking the intersection of the known bits of
// each element.
if (const ConstantDataVector *CDV = dyn_cast<ConstantDataVector>(V)) {
// We know that CDV must be a vector of integers. Take the intersection of
// each element.
Known.Zero.setAllBits(); Known.One.setAllBits();
for (unsigned i = 0, e = CDV->getNumElements(); i != e; ++i) {
if (!DemandedElts[i])
continue;
APInt Elt = CDV->getElementAsAPInt(i);
Known.Zero &= ~Elt;
Known.One &= Elt;
}
return;
}
if (const auto *CV = dyn_cast<ConstantVector>(V)) {
// We know that CV must be a vector of integers. Take the intersection of
// each element.
Known.Zero.setAllBits(); Known.One.setAllBits();
for (unsigned i = 0, e = CV->getNumOperands(); i != e; ++i) {
if (!DemandedElts[i])
continue;
Constant *Element = CV->getAggregateElement(i);
auto *ElementCI = dyn_cast_or_null<ConstantInt>(Element);
if (!ElementCI) {
Known.resetAll();
return;
}
const APInt &Elt = ElementCI->getValue();
Known.Zero &= ~Elt;
Known.One &= Elt;
}
return;
}
// Start out not knowing anything.
Known.resetAll();
// We can't imply anything about undefs.
if (isa<UndefValue>(V))
return;
// There's no point in looking through other users of ConstantData for
// assumptions. Confirm that we've handled them all.
assert(!isa<ConstantData>(V) && "Unhandled constant data!");
// All recursive calls that increase depth must come after this.
if (Depth == MaxAnalysisRecursionDepth)
return;
// A weak GlobalAlias is totally unknown. A non-weak GlobalAlias has
// the bits of its aliasee.
if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
if (!GA->isInterposable())
computeKnownBits(GA->getAliasee(), Known, Depth + 1, Q);
return;
}
if (const Operator *I = dyn_cast<Operator>(V))
computeKnownBitsFromOperator(I, DemandedElts, Known, Depth, Q);
// Aligned pointers have trailing zeros - refine Known.Zero set
if (isa<PointerType>(V->getType())) {
Align Alignment = V->getPointerAlignment(Q.DL);
Known.Zero.setLowBits(Log2(Alignment));
}
// computeKnownBitsFromAssume strictly refines Known.
// Therefore, we run them after computeKnownBitsFromOperator.
// Check whether a nearby assume intrinsic can determine some known bits.
computeKnownBitsFromAssume(V, Known, Depth, Q);
assert((Known.Zero & Known.One) == 0 && "Bits known to be one AND zero?");
}
/// Try to detect a recurrence that the value of the induction variable is
/// always a power of two (or zero).
static bool isPowerOfTwoRecurrence(const PHINode *PN, bool OrZero,
unsigned Depth, Query &Q) {
BinaryOperator *BO = nullptr;
Value *Start = nullptr, *Step = nullptr;
if (!matchSimpleRecurrence(PN, BO, Start, Step))
return false;
// Initial value must be a power of two.
for (const Use &U : PN->operands()) {
if (U.get() == Start) {
// Initial value comes from a different BB, need to adjust context
// instruction for analysis.
Q.CxtI = PN->getIncomingBlock(U)->getTerminator();
if (!isKnownToBeAPowerOfTwo(Start, OrZero, Depth, Q))
return false;
}
}
// Except for Mul, the induction variable must be on the left side of the
// increment expression, otherwise its value can be arbitrary.
if (BO->getOpcode() != Instruction::Mul && BO->getOperand(1) != Step)
return false;
Q.CxtI = BO->getParent()->getTerminator();
switch (BO->getOpcode()) {
case Instruction::Mul:
// Power of two is closed under multiplication.
return (OrZero || Q.IIQ.hasNoUnsignedWrap(BO) ||
Q.IIQ.hasNoSignedWrap(BO)) &&
isKnownToBeAPowerOfTwo(Step, OrZero, Depth, Q);
case Instruction::SDiv:
// Start value must not be signmask for signed division, so simply being a
// power of two is not sufficient, and it has to be a constant.
if (!match(Start, m_Power2()) || match(Start, m_SignMask()))
return false;
LLVM_FALLTHROUGH;
case Instruction::UDiv:
// Divisor must be a power of two.
// If OrZero is false, cannot guarantee induction variable is non-zero after
// division, same for Shr, unless it is exact division.
return (OrZero || Q.IIQ.isExact(BO)) &&
isKnownToBeAPowerOfTwo(Step, false, Depth, Q);
case Instruction::Shl:
return OrZero || Q.IIQ.hasNoUnsignedWrap(BO) || Q.IIQ.hasNoSignedWrap(BO);
case Instruction::AShr:
if (!match(Start, m_Power2()) || match(Start, m_SignMask()))
return false;
LLVM_FALLTHROUGH;
case Instruction::LShr:
return OrZero || Q.IIQ.isExact(BO);
default:
return false;
}
}
/// Return true if the given value is known to have exactly one
/// bit set when defined. For vectors return true if every element is known to
/// be a power of two when defined. Supports values with integer or pointer
/// types and vectors of integers.
bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth,
const Query &Q) {
assert(Depth <= MaxAnalysisRecursionDepth && "Limit Search Depth");
// Attempt to match against constants.
if (OrZero && match(V, m_Power2OrZero()))
return true;
if (match(V, m_Power2()))
return true;
// 1 << X is clearly a power of two if the one is not shifted off the end. If
// it is shifted off the end then the result is undefined.
if (match(V, m_Shl(m_One(), m_Value())))
return true;
// (signmask) >>l X is clearly a power of two if the one is not shifted off
// the bottom. If it is shifted off the bottom then the result is undefined.
if (match(V, m_LShr(m_SignMask(), m_Value())))
return true;
// The remaining tests are all recursive, so bail out if we hit the limit.
if (Depth++ == MaxAnalysisRecursionDepth)
return false;
Value *X = nullptr, *Y = nullptr;
// A shift left or a logical shift right of a power of two is a power of two
// or zero.
if (OrZero && (match(V, m_Shl(m_Value(X), m_Value())) ||
match(V, m_LShr(m_Value(X), m_Value()))))
return isKnownToBeAPowerOfTwo(X, /*OrZero*/ true, Depth, Q);
if (const ZExtInst *ZI = dyn_cast<ZExtInst>(V))
return isKnownToBeAPowerOfTwo(ZI->getOperand(0), OrZero, Depth, Q);
if (const SelectInst *SI = dyn_cast<SelectInst>(V))
return isKnownToBeAPowerOfTwo(SI->getTrueValue(), OrZero, Depth, Q) &&
isKnownToBeAPowerOfTwo(SI->getFalseValue(), OrZero, Depth, Q);
// Peek through min/max.
if (match(V, m_MaxOrMin(m_Value(X), m_Value(Y)))) {
return isKnownToBeAPowerOfTwo(X, OrZero, Depth, Q) &&
isKnownToBeAPowerOfTwo(Y, OrZero, Depth, Q);
}
if (OrZero && match(V, m_And(m_Value(X), m_Value(Y)))) {
// A power of two and'd with anything is a power of two or zero.
if (isKnownToBeAPowerOfTwo(X, /*OrZero*/ true, Depth, Q) ||
isKnownToBeAPowerOfTwo(Y, /*OrZero*/ true, Depth, Q))
return true;
// X & (-X) is always a power of two or zero.
if (match(X, m_Neg(m_Specific(Y))) || match(Y, m_Neg(m_Specific(X))))
return true;
return false;
}
// Adding a power-of-two or zero to the same power-of-two or zero yields
// either the original power-of-two, a larger power-of-two or zero.
if (match(V, m_Add(m_Value(X), m_Value(Y)))) {
const OverflowingBinaryOperator *VOBO = cast<OverflowingBinaryOperator>(V);
if (OrZero || Q.IIQ.hasNoUnsignedWrap(VOBO) ||
Q.IIQ.hasNoSignedWrap(VOBO)) {
if (match(X, m_And(m_Specific(Y), m_Value())) ||
match(X, m_And(m_Value(), m_Specific(Y))))
if (isKnownToBeAPowerOfTwo(Y, OrZero, Depth, Q))
return true;
if (match(Y, m_And(m_Specific(X), m_Value())) ||
match(Y, m_And(m_Value(), m_Specific(X))))
if (isKnownToBeAPowerOfTwo(X, OrZero, Depth, Q))
return true;
unsigned BitWidth = V->getType()->getScalarSizeInBits();
KnownBits LHSBits(BitWidth);
computeKnownBits(X, LHSBits, Depth, Q);
KnownBits RHSBits(BitWidth);
computeKnownBits(Y, RHSBits, Depth, Q);
// If i8 V is a power of two or zero:
// ZeroBits: 1 1 1 0 1 1 1 1
// ~ZeroBits: 0 0 0 1 0 0 0 0
if ((~(LHSBits.Zero & RHSBits.Zero)).isPowerOf2())
// If OrZero isn't set, we cannot give back a zero result.
// Make sure either the LHS or RHS has a bit set.
if (OrZero || RHSBits.One.getBoolValue() || LHSBits.One.getBoolValue())
return true;
}
}
// A PHI node is power of two if all incoming values are power of two, or if
// it is an induction variable where in each step its value is a power of two.
if (const PHINode *PN = dyn_cast<PHINode>(V)) {
Query RecQ = Q;
// Check if it is an induction variable and always power of two.
if (isPowerOfTwoRecurrence(PN, OrZero, Depth, RecQ))
return true;
// Recursively check all incoming values. Limit recursion to 2 levels, so
// that search complexity is limited to number of operands^2.
unsigned NewDepth = std::max(Depth, MaxAnalysisRecursionDepth - 1);
return llvm::all_of(PN->operands(), [&](const Use &U) {
// Value is power of 2 if it is coming from PHI node itself by induction.
if (U.get() == PN)
return true;
// Change the context instruction to the incoming block where it is
// evaluated.
RecQ.CxtI = PN->getIncomingBlock(U)->getTerminator();
return isKnownToBeAPowerOfTwo(U.get(), OrZero, NewDepth, RecQ);
});
}
// An exact divide or right shift can only shift off zero bits, so the result
// is a power of two only if the first operand is a power of two and not
// copying a sign bit (sdiv int_min, 2).
if (match(V, m_Exact(m_LShr(m_Value(), m_Value()))) ||
match(V, m_Exact(m_UDiv(m_Value(), m_Value())))) {
return isKnownToBeAPowerOfTwo(cast<Operator>(V)->getOperand(0), OrZero,
Depth, Q);
}
return false;
}
/// Test whether a GEP's result is known to be non-null.
///
/// Uses properties inherent in a GEP to try to determine whether it is known
/// to be non-null.
///
/// Currently this routine does not support vector GEPs.
static bool isGEPKnownNonNull(const GEPOperator *GEP, unsigned Depth,
const Query &Q) {
const Function *F = nullptr;
if (const Instruction *I = dyn_cast<Instruction>(GEP))
F = I->getFunction();
if (!GEP->isInBounds() ||
NullPointerIsDefined(F, GEP->getPointerAddressSpace()))
return false;
// FIXME: Support vector-GEPs.
assert(GEP->getType()->isPointerTy() && "We only support plain pointer GEP");
// If the base pointer is non-null, we cannot walk to a null address with an
// inbounds GEP in address space zero.
if (isKnownNonZero(GEP->getPointerOperand(), Depth, Q))
return true;
// Walk the GEP operands and see if any operand introduces a non-zero offset.
// If so, then the GEP cannot produce a null pointer, as doing so would
// inherently violate the inbounds contract within address space zero.
for (gep_type_iterator GTI = gep_type_begin(GEP), GTE = gep_type_end(GEP);
GTI != GTE; ++GTI) {
// Struct types are easy -- they must always be indexed by a constant.
if (StructType *STy = GTI.getStructTypeOrNull()) {
ConstantInt *OpC = cast<ConstantInt>(GTI.getOperand());
unsigned ElementIdx = OpC->getZExtValue();
const StructLayout *SL = Q.DL.getStructLayout(STy);
uint64_t ElementOffset = SL->getElementOffset(ElementIdx);
if (ElementOffset > 0)
return true;
continue;
}
// If we have a zero-sized type, the index doesn't matter. Keep looping.
if (Q.DL.getTypeAllocSize(GTI.getIndexedType()).getKnownMinSize() == 0)
continue;
// Fast path the constant operand case both for efficiency and so we don't
// increment Depth when just zipping down an all-constant GEP.
if (ConstantInt *OpC = dyn_cast<ConstantInt>(GTI.getOperand())) {
if (!OpC->isZero())
return true;
continue;
}
// We post-increment Depth here because while isKnownNonZero increments it
// as well, when we pop back up that increment won't persist. We don't want
// to recurse 10k times just because we have 10k GEP operands. We don't
// bail completely out because we want to handle constant GEPs regardless
// of depth.
if (Depth++ >= MaxAnalysisRecursionDepth)
continue;
if (isKnownNonZero(GTI.getOperand(), Depth, Q))
return true;
}
return false;
}
static bool isKnownNonNullFromDominatingCondition(const Value *V,
const Instruction *CtxI,
const DominatorTree *DT) {
if (isa<Constant>(V))
return false;
if (!CtxI || !DT)
return false;
unsigned NumUsesExplored = 0;
for (const auto *U : V->users()) {
// Avoid massive lists
if (NumUsesExplored >= DomConditionsMaxUses)
break;
NumUsesExplored++;
// If the value is used as an argument to a call or invoke, then argument
// attributes may provide an answer about null-ness.
if (const auto *CB = dyn_cast<CallBase>(U))
if (auto *CalledFunc = CB->getCalledFunction())
for (const Argument &Arg : CalledFunc->args())
if (CB->getArgOperand(Arg.getArgNo()) == V &&
Arg.hasNonNullAttr(/* AllowUndefOrPoison */ false) &&
DT->dominates(CB, CtxI))
return true;
// If the value is used as a load/store, then the pointer must be non null.
if (V == getLoadStorePointerOperand(U)) {
const Instruction *I = cast<Instruction>(U);
if (!NullPointerIsDefined(I->getFunction(),
V->getType()->getPointerAddressSpace()) &&
DT->dominates(I, CtxI))
return true;
}
// Consider only compare instructions uniquely controlling a branch
Value *RHS;
CmpInst::Predicate Pred;
if (!match(U, m_c_ICmp(Pred, m_Specific(V), m_Value(RHS))))
continue;
bool NonNullIfTrue;
if (cmpExcludesZero(Pred, RHS))
NonNullIfTrue = true;
else if (cmpExcludesZero(CmpInst::getInversePredicate(Pred), RHS))
NonNullIfTrue = false;
else
continue;
SmallVector<const User *, 4> WorkList;
SmallPtrSet<const User *, 4> Visited;
for (const auto *CmpU : U->users()) {
assert(WorkList.empty() && "Should be!");
if (Visited.insert(CmpU).second)
WorkList.push_back(CmpU);
while (!WorkList.empty()) {
auto *Curr = WorkList.pop_back_val();
// If a user is an AND, add all its users to the work list. We only
// propagate "pred != null" condition through AND because it is only
// correct to assume that all conditions of AND are met in true branch.
// TODO: Support similar logic of OR and EQ predicate?
if (NonNullIfTrue)
if (match(Curr, m_LogicalAnd(m_Value(), m_Value()))) {
for (const auto *CurrU : Curr->users())
if (Visited.insert(CurrU).second)
WorkList.push_back(CurrU);
continue;
}
if (const BranchInst *BI = dyn_cast<BranchInst>(Curr)) {
assert(BI->isConditional() && "uses a comparison!");
BasicBlock *NonNullSuccessor =
BI->getSuccessor(NonNullIfTrue ? 0 : 1);
BasicBlockEdge Edge(BI->getParent(), NonNullSuccessor);
if (Edge.isSingleEdge() && DT->dominates(Edge, CtxI->getParent()))
return true;
} else if (NonNullIfTrue && isGuard(Curr) &&
DT->dominates(cast<Instruction>(Curr), CtxI)) {
return true;
}
}
}
}
return false;
}
/// Does the 'Range' metadata (which must be a valid MD_range operand list)
/// ensure that the value it's attached to is never Value? 'RangeType' is
/// is the type of the value described by the range.
static bool rangeMetadataExcludesValue(const MDNode* Ranges, const APInt& Value) {
const unsigned NumRanges = Ranges->getNumOperands() / 2;
assert(NumRanges >= 1);
for (unsigned i = 0; i < NumRanges; ++i) {
ConstantInt *Lower =
mdconst::extract<ConstantInt>(Ranges->getOperand(2 * i + 0));
ConstantInt *Upper =
mdconst::extract<ConstantInt>(Ranges->getOperand(2 * i + 1));
ConstantRange Range(Lower->getValue(), Upper->getValue());
if (Range.contains(Value))
return false;
}
return true;
}
/// Try to detect a recurrence that monotonically increases/decreases from a
/// non-zero starting value. These are common as induction variables.
static bool isNonZeroRecurrence(const PHINode *PN) {
BinaryOperator *BO = nullptr;
Value *Start = nullptr, *Step = nullptr;
const APInt *StartC, *StepC;
if (!matchSimpleRecurrence(PN, BO, Start, Step) ||
!match(Start, m_APInt(StartC)) || StartC->isZero())
return false;
switch (BO->getOpcode()) {
case Instruction::Add:
// Starting from non-zero and stepping away from zero can never wrap back
// to zero.
return BO->hasNoUnsignedWrap() ||
(BO->hasNoSignedWrap() && match(Step, m_APInt(StepC)) &&
StartC->isNegative() == StepC->isNegative());
case Instruction::Mul:
return (BO->hasNoUnsignedWrap() || BO->hasNoSignedWrap()) &&
match(Step, m_APInt(StepC)) && !StepC->isZero();
case Instruction::Shl:
return BO->hasNoUnsignedWrap() || BO->hasNoSignedWrap();
case Instruction::AShr:
case Instruction::LShr:
return BO->isExact();
default:
return false;
}
}
/// Return true if the given value is known to be non-zero when defined. For
/// vectors, return true if every demanded element is known to be non-zero when
/// defined. For pointers, if the context instruction and dominator tree are
/// specified, perform context-sensitive analysis and return true if the
/// pointer couldn't possibly be null at the specified instruction.
/// Supports values with integer or pointer type and vectors of integers.
bool isKnownNonZero(const Value *V, const APInt &DemandedElts, unsigned Depth,
const Query &Q) {
// FIXME: We currently have no way to represent the DemandedElts of a scalable
// vector
if (isa<ScalableVectorType>(V->getType()))
return false;
if (auto *C = dyn_cast<Constant>(V)) {
if (C->isNullValue())
return false;
if (isa<ConstantInt>(C))
// Must be non-zero due to null test above.
return true;
if (auto *CE = dyn_cast<ConstantExpr>(C)) {
// See the comment for IntToPtr/PtrToInt instructions below.
if (CE->getOpcode() == Instruction::IntToPtr ||
CE->getOpcode() == Instruction::PtrToInt)
if (Q.DL.getTypeSizeInBits(CE->getOperand(0)->getType())
.getFixedSize() <=
Q.DL.getTypeSizeInBits(CE->getType()).getFixedSize())
return isKnownNonZero(CE->getOperand(0), Depth, Q);
}
// For constant vectors, check that all elements are undefined or known
// non-zero to determine that the whole vector is known non-zero.
if (auto *VecTy = dyn_cast<FixedVectorType>(C->getType())) {
for (unsigned i = 0, e = VecTy->getNumElements(); i != e; ++i) {
if (!DemandedElts[i])
continue;
Constant *Elt = C->getAggregateElement(i);
if (!Elt || Elt->isNullValue())
return false;
if (!isa<UndefValue>(Elt) && !isa<ConstantInt>(Elt))
return false;
}
return true;
}
// A global variable in address space 0 is non null unless extern weak
// or an absolute symbol reference. Other address spaces may have null as a
// valid address for a global, so we can't assume anything.
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
if (!GV->isAbsoluteSymbolRef() && !GV->hasExternalWeakLinkage() &&
GV->getType()->getAddressSpace() == 0)
return true;
} else
return false;
}
if (auto *I = dyn_cast<Instruction>(V)) {
if (MDNode *Ranges = Q.IIQ.getMetadata(I, LLVMContext::MD_range)) {
// If the possible ranges don't contain zero, then the value is
// definitely non-zero.
if (auto *Ty = dyn_cast<IntegerType>(V->getType())) {
const APInt ZeroValue(Ty->getBitWidth(), 0);
if (rangeMetadataExcludesValue(Ranges, ZeroValue))
return true;
}
}
}
if (isKnownNonZeroFromAssume(V, Q))
return true;
// Some of the tests below are recursive, so bail out if we hit the limit.
if (Depth++ >= MaxAnalysisRecursionDepth)
return false;
// Check for pointer simplifications.
if (PointerType *PtrTy = dyn_cast<PointerType>(V->getType())) {
// Alloca never returns null, malloc might.
if (isa<AllocaInst>(V) && Q.DL.getAllocaAddrSpace() == 0)
return true;
// A byval, inalloca may not be null in a non-default addres space. A
// nonnull argument is assumed never 0.
if (const Argument *A = dyn_cast<Argument>(V)) {
if (((A->hasPassPointeeByValueCopyAttr() &&
!NullPointerIsDefined(A->getParent(), PtrTy->getAddressSpace())) ||
A->hasNonNullAttr()))
return true;
}
// A Load tagged with nonnull metadata is never null.
if (const LoadInst *LI = dyn_cast<LoadInst>(V))
if (Q.IIQ.getMetadata(LI, LLVMContext::MD_nonnull))
return true;
if (const auto *Call = dyn_cast<CallBase>(V)) {
if (Call->isReturnNonNull())
return true;
if (const auto *RP = getArgumentAliasingToReturnedPointer(Call, true))
return isKnownNonZero(RP, Depth, Q);
}
}
if (isKnownNonNullFromDominatingCondition(V, Q.CxtI, Q.DT))
return true;
// Check for recursive pointer simplifications.
if (V->getType()->isPointerTy()) {
// Look through bitcast operations, GEPs, and int2ptr instructions as they
// do not alter the value, or at least not the nullness property of the
// value, e.g., int2ptr is allowed to zero/sign extend the value.
//
// Note that we have to take special care to avoid looking through
// truncating casts, e.g., int2ptr/ptr2int with appropriate sizes, as well
// as casts that can alter the value, e.g., AddrSpaceCasts.
if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V))
return isGEPKnownNonNull(GEP, Depth, Q);
if (auto *BCO = dyn_cast<BitCastOperator>(V))
return isKnownNonZero(BCO->getOperand(0), Depth, Q);
if (auto *I2P = dyn_cast<IntToPtrInst>(V))
if (Q.DL.getTypeSizeInBits(I2P->getSrcTy()).getFixedSize() <=
Q.DL.getTypeSizeInBits(I2P->getDestTy()).getFixedSize())
return isKnownNonZero(I2P->getOperand(0), Depth, Q);
}
// Similar to int2ptr above, we can look through ptr2int here if the cast
// is a no-op or an extend and not a truncate.
if (auto *P2I = dyn_cast<PtrToIntInst>(V))
if (Q.DL.getTypeSizeInBits(P2I->getSrcTy()).getFixedSize() <=
Q.DL.getTypeSizeInBits(P2I->getDestTy()).getFixedSize())
return isKnownNonZero(P2I->getOperand(0), Depth, Q);
unsigned BitWidth = getBitWidth(V->getType()->getScalarType(), Q.DL);
// X | Y != 0 if X != 0 or Y != 0.
Value *X = nullptr, *Y = nullptr;
if (match(V, m_Or(m_Value(X), m_Value(Y))))
return isKnownNonZero(X, DemandedElts, Depth, Q) ||
isKnownNonZero(Y, DemandedElts, Depth, Q);
// ext X != 0 if X != 0.
if (isa<SExtInst>(V) || isa<ZExtInst>(V))
return isKnownNonZero(cast<Instruction>(V)->getOperand(0), Depth, Q);
// shl X, Y != 0 if X is odd. Note that the value of the shift is undefined
// if the lowest bit is shifted off the end.
if (match(V, m_Shl(m_Value(X), m_Value(Y)))) {
// shl nuw can't remove any non-zero bits.
const OverflowingBinaryOperator *BO = cast<OverflowingBinaryOperator>(V);
if (Q.IIQ.hasNoUnsignedWrap(BO))
return isKnownNonZero(X, Depth, Q);
KnownBits Known(BitWidth);
computeKnownBits(X, DemandedElts, Known, Depth, Q);
if (Known.One[0])
return true;
}
// shr X, Y != 0 if X is negative. Note that the value of the shift is not
// defined if the sign bit is shifted off the end.
else if (match(V, m_Shr(m_Value(X), m_Value(Y)))) {
// shr exact can only shift out zero bits.
const PossiblyExactOperator *BO = cast<PossiblyExactOperator>(V);
if (BO->isExact())
return isKnownNonZero(X, Depth, Q);
KnownBits Known = computeKnownBits(X, DemandedElts, Depth, Q);
if (Known.isNegative())
return true;
// If the shifter operand is a constant, and all of the bits shifted
// out are known to be zero, and X is known non-zero then at least one
// non-zero bit must remain.
if (ConstantInt *Shift = dyn_cast<ConstantInt>(Y)) {
auto ShiftVal = Shift->getLimitedValue(BitWidth - 1);
// Is there a known one in the portion not shifted out?
if (Known.countMaxLeadingZeros() < BitWidth - ShiftVal)
return true;
// Are all the bits to be shifted out known zero?
if (Known.countMinTrailingZeros() >= ShiftVal)
return isKnownNonZero(X, DemandedElts, Depth, Q);
}
}
// div exact can only produce a zero if the dividend is zero.
else if (match(V, m_Exact(m_IDiv(m_Value(X), m_Value())))) {
return isKnownNonZero(X, DemandedElts, Depth, Q);
}
// X + Y.
else if (match(V, m_Add(m_Value(X), m_Value(Y)))) {
KnownBits XKnown = computeKnownBits(X, DemandedElts, Depth, Q);
KnownBits YKnown = computeKnownBits(Y, DemandedElts, Depth, Q);
// If X and Y are both non-negative (as signed values) then their sum is not
// zero unless both X and Y are zero.
if (XKnown.isNonNegative() && YKnown.isNonNegative())
if (isKnownNonZero(X, DemandedElts, Depth, Q) ||
isKnownNonZero(Y, DemandedElts, Depth, Q))
return true;
// If X and Y are both negative (as signed values) then their sum is not
// zero unless both X and Y equal INT_MIN.
if (XKnown.isNegative() && YKnown.isNegative()) {
APInt Mask = APInt::getSignedMaxValue(BitWidth);
// The sign bit of X is set. If some other bit is set then X is not equal
// to INT_MIN.
if (XKnown.One.intersects(Mask))
return true;
// The sign bit of Y is set. If some other bit is set then Y is not equal
// to INT_MIN.
if (YKnown.One.intersects(Mask))
return true;
}
// The sum of a non-negative number and a power of two is not zero.
if (XKnown.isNonNegative() &&
isKnownToBeAPowerOfTwo(Y, /*OrZero*/ false, Depth, Q))
return true;
if (YKnown.isNonNegative() &&
isKnownToBeAPowerOfTwo(X, /*OrZero*/ false, Depth, Q))
return true;
}
// X * Y.
else if (match(V, m_Mul(m_Value(X), m_Value(Y)))) {
const OverflowingBinaryOperator *BO = cast<OverflowingBinaryOperator>(V);
// If X and Y are non-zero then so is X * Y as long as the multiplication
// does not overflow.
if ((Q.IIQ.hasNoSignedWrap(BO) || Q.IIQ.hasNoUnsignedWrap(BO)) &&
isKnownNonZero(X, DemandedElts, Depth, Q) &&
isKnownNonZero(Y, DemandedElts, Depth, Q))
return true;
}
// (C ? X : Y) != 0 if X != 0 and Y != 0.
else if (const SelectInst *SI = dyn_cast<SelectInst>(V)) {
if (isKnownNonZero(SI->getTrueValue(), DemandedElts, Depth, Q) &&
isKnownNonZero(SI->getFalseValue(), DemandedElts, Depth, Q))
return true;
}
// PHI
else if (const PHINode *PN = dyn_cast<PHINode>(V)) {
if (Q.IIQ.UseInstrInfo && isNonZeroRecurrence(PN))
return true;
// Check if all incoming values are non-zero using recursion.
Query RecQ = Q;
unsigned NewDepth = std::max(Depth, MaxAnalysisRecursionDepth - 1);
return llvm::all_of(PN->operands(), [&](const Use &U) {
if (U.get() == PN)
return true;
RecQ.CxtI = PN->getIncomingBlock(U)->getTerminator();
return isKnownNonZero(U.get(), DemandedElts, NewDepth, RecQ);
});
}
// ExtractElement
else if (const auto *EEI = dyn_cast<ExtractElementInst>(V)) {
const Value *Vec = EEI->getVectorOperand();
const Value *Idx = EEI->getIndexOperand();
auto *CIdx = dyn_cast<ConstantInt>(Idx);
if (auto *VecTy = dyn_cast<FixedVectorType>(Vec->getType())) {
unsigned NumElts = VecTy->getNumElements();
APInt DemandedVecElts = APInt::getAllOnes(NumElts);
if (CIdx && CIdx->getValue().ult(NumElts))
DemandedVecElts = APInt::getOneBitSet(NumElts, CIdx->getZExtValue());
return isKnownNonZero(Vec, DemandedVecElts, Depth, Q);
}
}
// Freeze
else if (const FreezeInst *FI = dyn_cast<FreezeInst>(V)) {
auto *Op = FI->getOperand(0);
if (isKnownNonZero(Op, Depth, Q) &&
isGuaranteedNotToBePoison(Op, Q.AC, Q.CxtI, Q.DT, Depth))
return true;
} else if (const auto *II = dyn_cast<IntrinsicInst>(V)) {
if (II->getIntrinsicID() == Intrinsic::vscale)
return true;
}
KnownBits Known(BitWidth);
computeKnownBits(V, DemandedElts, Known, Depth, Q);
return Known.One != 0;
}
bool isKnownNonZero(const Value* V, unsigned Depth, const Query& Q) {
// FIXME: We currently have no way to represent the DemandedElts of a scalable
// vector
if (isa<ScalableVectorType>(V->getType()))
return false;
auto *FVTy = dyn_cast<FixedVectorType>(V->getType());
APInt DemandedElts =
FVTy ? APInt::getAllOnes(FVTy->getNumElements()) : APInt(1, 1);
return isKnownNonZero(V, DemandedElts, Depth, Q);
}
/// If the pair of operators are the same invertible function, return the
/// the operands of the function corresponding to each input. Otherwise,
/// return None. An invertible function is one that is 1-to-1 and maps
/// every input value to exactly one output value. This is equivalent to
/// saying that Op1 and Op2 are equal exactly when the specified pair of
/// operands are equal, (except that Op1 and Op2 may be poison more often.)
static Optional<std::pair<Value*, Value*>>
getInvertibleOperands(const Operator *Op1,
const Operator *Op2) {
if (Op1->getOpcode() != Op2->getOpcode())
return None;
auto getOperands = [&](unsigned OpNum) -> auto {
return std::make_pair(Op1->getOperand(OpNum), Op2->getOperand(OpNum));
};
switch (Op1->getOpcode()) {
default:
break;
case Instruction::Add:
case Instruction::Sub:
if (Op1->getOperand(0) == Op2->getOperand(0))
return getOperands(1);
if (Op1->getOperand(1) == Op2->getOperand(1))
return getOperands(0);
break;
case Instruction::Mul: {
// invertible if A * B == (A * B) mod 2^N where A, and B are integers
// and N is the bitwdith. The nsw case is non-obvious, but proven by
// alive2: https://alive2.llvm.org/ce/z/Z6D5qK
auto *OBO1 = cast<OverflowingBinaryOperator>(Op1);
auto *OBO2 = cast<OverflowingBinaryOperator>(Op2);
if ((!OBO1->hasNoUnsignedWrap() || !OBO2->hasNoUnsignedWrap()) &&
(!OBO1->hasNoSignedWrap() || !OBO2->hasNoSignedWrap()))
break;
// Assume operand order has been canonicalized
if (Op1->getOperand(1) == Op2->getOperand(1) &&
isa<ConstantInt>(Op1->getOperand(1)) &&
!cast<ConstantInt>(Op1->getOperand(1))->isZero())
return getOperands(0);
break;
}
case Instruction::Shl: {
// Same as multiplies, with the difference that we don't need to check
// for a non-zero multiply. Shifts always multiply by non-zero.
auto *OBO1 = cast<OverflowingBinaryOperator>(Op1);
auto *OBO2 = cast<OverflowingBinaryOperator>(Op2);
if ((!OBO1->hasNoUnsignedWrap() || !OBO2->hasNoUnsignedWrap()) &&
(!OBO1->hasNoSignedWrap() || !OBO2->hasNoSignedWrap()))
break;
if (Op1->getOperand(1) == Op2->getOperand(1))
return getOperands(0);
break;
}
case Instruction::AShr:
case Instruction::LShr: {
auto *PEO1 = cast<PossiblyExactOperator>(Op1);
auto *PEO2 = cast<PossiblyExactOperator>(Op2);
if (!PEO1->isExact() || !PEO2->isExact())
break;
if (Op1->getOperand(1) == Op2->getOperand(1))
return getOperands(0);
break;
}
case Instruction::SExt:
case Instruction::ZExt:
if (Op1->getOperand(0)->getType() == Op2->getOperand(0)->getType())
return getOperands(0);
break;
case Instruction::PHI: {
const PHINode *PN1 = cast<PHINode>(Op1);
const PHINode *PN2 = cast<PHINode>(Op2);
// If PN1 and PN2 are both recurrences, can we prove the entire recurrences
// are a single invertible function of the start values? Note that repeated
// application of an invertible function is also invertible
BinaryOperator *BO1 = nullptr;
Value *Start1 = nullptr, *Step1 = nullptr;
BinaryOperator *BO2 = nullptr;
Value *Start2 = nullptr, *Step2 = nullptr;
if (PN1->getParent() != PN2->getParent() ||
!matchSimpleRecurrence(PN1, BO1, Start1, Step1) ||
!matchSimpleRecurrence(PN2, BO2, Start2, Step2))
break;
auto Values = getInvertibleOperands(cast<Operator>(BO1),
cast<Operator>(BO2));
if (!Values)
break;
// We have to be careful of mutually defined recurrences here. Ex:
// * X_i = X_(i-1) OP Y_(i-1), and Y_i = X_(i-1) OP V
// * X_i = Y_i = X_(i-1) OP Y_(i-1)
// The invertibility of these is complicated, and not worth reasoning
// about (yet?).
if (Values->first != PN1 || Values->second != PN2)
break;
return std::make_pair(Start1, Start2);
}
}
return None;
}
/// Return true if V2 == V1 + X, where X is known non-zero.
static bool isAddOfNonZero(const Value *V1, const Value *V2, unsigned Depth,
const Query &Q) {
const BinaryOperator *BO = dyn_cast<BinaryOperator>(V1);
if (!BO || BO->getOpcode() != Instruction::Add)
return false;
Value *Op = nullptr;
if (V2 == BO->getOperand(0))
Op = BO->getOperand(1);
else if (V2 == BO->getOperand(1))
Op = BO->getOperand(0);
else
return false;
return isKnownNonZero(Op, Depth + 1, Q);
}
/// Return true if V2 == V1 * C, where V1 is known non-zero, C is not 0/1 and
/// the multiplication is nuw or nsw.
static bool isNonEqualMul(const Value *V1, const Value *V2, unsigned Depth,
const Query &Q) {
if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(V2)) {
const APInt *C;
return match(OBO, m_Mul(m_Specific(V1), m_APInt(C))) &&
(OBO->hasNoUnsignedWrap() || OBO->hasNoSignedWrap()) &&
!C->isZero() && !C->isOne() && isKnownNonZero(V1, Depth + 1, Q);
}
return false;
}
/// Return true if V2 == V1 << C, where V1 is known non-zero, C is not 0 and
/// the shift is nuw or nsw.
static bool isNonEqualShl(const Value *V1, const Value *V2, unsigned Depth,
const Query &Q) {
if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(V2)) {
const APInt *C;
return match(OBO, m_Shl(m_Specific(V1), m_APInt(C))) &&
(OBO->hasNoUnsignedWrap() || OBO->hasNoSignedWrap()) &&
!C->isZero() && isKnownNonZero(V1, Depth + 1, Q);
}
return false;
}
static bool isNonEqualPHIs(const PHINode *PN1, const PHINode *PN2,
unsigned Depth, const Query &Q) {
// Check two PHIs are in same block.
if (PN1->getParent() != PN2->getParent())
return false;
SmallPtrSet<const BasicBlock *, 8> VisitedBBs;
bool UsedFullRecursion = false;
for (const BasicBlock *IncomBB : PN1->blocks()) {
if (!VisitedBBs.insert(IncomBB).second)
continue; // Don't reprocess blocks that we have dealt with already.
const Value *IV1 = PN1->getIncomingValueForBlock(IncomBB);
const Value *IV2 = PN2->getIncomingValueForBlock(IncomBB);
const APInt *C1, *C2;
if (match(IV1, m_APInt(C1)) && match(IV2, m_APInt(C2)) && *C1 != *C2)
continue;
// Only one pair of phi operands is allowed for full recursion.
if (UsedFullRecursion)
return false;
Query RecQ = Q;
RecQ.CxtI = IncomBB->getTerminator();
if (!isKnownNonEqual(IV1, IV2, Depth + 1, RecQ))
return false;
UsedFullRecursion = true;
}
return true;
}
/// Return true if it is known that V1 != V2.
static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
const Query &Q) {
if (V1 == V2)
return false;
if (V1->getType() != V2->getType())
// We can't look through casts yet.
return false;
if (Depth >= MaxAnalysisRecursionDepth)
return false;
// See if we can recurse through (exactly one of) our operands. This
// requires our operation be 1-to-1 and map every input value to exactly
// one output value. Such an operation is invertible.
auto *O1 = dyn_cast<Operator>(V1);
auto *O2 = dyn_cast<Operator>(V2);
if (O1 && O2 && O1->getOpcode() == O2->getOpcode()) {
if (auto Values = getInvertibleOperands(O1, O2))
return isKnownNonEqual(Values->first, Values->second, Depth + 1, Q);
if (const PHINode *PN1 = dyn_cast<PHINode>(V1)) {
const PHINode *PN2 = cast<PHINode>(V2);
// FIXME: This is missing a generalization to handle the case where one is
// a PHI and another one isn't.
if (isNonEqualPHIs(PN1, PN2, Depth, Q))
return true;
};
}
if (isAddOfNonZero(V1, V2, Depth, Q) || isAddOfNonZero(V2, V1, Depth, Q))
return true;
if (isNonEqualMul(V1, V2, Depth, Q) || isNonEqualMul(V2, V1, Depth, Q))
return true;
if (isNonEqualShl(V1, V2, Depth, Q) || isNonEqualShl(V2, V1, Depth, Q))
return true;
if (V1->getType()->isIntOrIntVectorTy()) {
// Are any known bits in V1 contradictory to known bits in V2? If V1
// has a known zero where V2 has a known one, they must not be equal.
KnownBits Known1 = computeKnownBits(V1, Depth, Q);
KnownBits Known2 = computeKnownBits(V2, Depth, Q);
if (Known1.Zero.intersects(Known2.One) ||
Known2.Zero.intersects(Known1.One))
return true;
}
return false;
}
/// Return true if 'V & Mask' is known to be zero. We use this predicate to
/// simplify operations downstream. Mask is known to be zero for bits that V
/// cannot have.
///
/// This function is defined on values with integer type, values with pointer
/// type, and vectors of integers. In the case
/// where V is a vector, the mask, known zero, and known one values are the
/// same width as the vector element, and the bit is set only if it is true
/// for all of the elements in the vector.
bool MaskedValueIsZero(const Value *V, const APInt &Mask, unsigned Depth,
const Query &Q) {
KnownBits Known(Mask.getBitWidth());
computeKnownBits(V, Known, Depth, Q);
return Mask.isSubsetOf(Known.Zero);
}
// Match a signed min+max clamp pattern like smax(smin(In, CHigh), CLow).
// Returns the input and lower/upper bounds.
static bool isSignedMinMaxClamp(const Value *Select, const Value *&In,
const APInt *&CLow, const APInt *&CHigh) {
assert(isa<Operator>(Select) &&
cast<Operator>(Select)->getOpcode() == Instruction::Select &&
"Input should be a Select!");
const Value *LHS = nullptr, *RHS = nullptr;
SelectPatternFlavor SPF = matchSelectPattern(Select, LHS, RHS).Flavor;
if (SPF != SPF_SMAX && SPF != SPF_SMIN)
return false;
if (!match(RHS, m_APInt(CLow)))
return false;
const Value *LHS2 = nullptr, *RHS2 = nullptr;
SelectPatternFlavor SPF2 = matchSelectPattern(LHS, LHS2, RHS2).Flavor;
if (getInverseMinMaxFlavor(SPF) != SPF2)
return false;
if (!match(RHS2, m_APInt(CHigh)))
return false;
if (SPF == SPF_SMIN)
std::swap(CLow, CHigh);
In = LHS2;
return CLow->sle(*CHigh);
}
static bool isSignedMinMaxIntrinsicClamp(const IntrinsicInst *II,
const APInt *&CLow,
const APInt *&CHigh) {
assert((II->getIntrinsicID() == Intrinsic::smin ||
II->getIntrinsicID() == Intrinsic::smax) && "Must be smin/smax");
Intrinsic::ID InverseID = getInverseMinMaxIntrinsic(II->getIntrinsicID());
auto *InnerII = dyn_cast<IntrinsicInst>(II->getArgOperand(0));
if (!InnerII || InnerII->getIntrinsicID() != InverseID ||
!match(II->getArgOperand(1), m_APInt(CLow)) ||
!match(InnerII->getArgOperand(1), m_APInt(CHigh)))
return false;
if (II->getIntrinsicID() == Intrinsic::smin)
std::swap(CLow, CHigh);
return CLow->sle(*CHigh);
}
/// For vector constants, loop over the elements and find the constant with the
/// minimum number of sign bits. Return 0 if the value is not a vector constant
/// or if any element was not analyzed; otherwise, return the count for the
/// element with the minimum number of sign bits.
static unsigned computeNumSignBitsVectorConstant(const Value *V,
const APInt &DemandedElts,
unsigned TyBits) {
const auto *CV = dyn_cast<Constant>(V);
if (!CV || !isa<FixedVectorType>(CV->getType()))
return 0;
unsigned MinSignBits = TyBits;
unsigned NumElts = cast<FixedVectorType>(CV->getType())->getNumElements();
for (unsigned i = 0; i != NumElts; ++i) {
if (!DemandedElts[i])
continue;
// If we find a non-ConstantInt, bail out.
auto *Elt = dyn_cast_or_null<ConstantInt>(CV->getAggregateElement(i));
if (!Elt)
return 0;
MinSignBits = std::min(MinSignBits, Elt->getValue().getNumSignBits());
}
return MinSignBits;
}
static unsigned ComputeNumSignBitsImpl(const Value *V,
const APInt &DemandedElts,
unsigned Depth, const Query &Q);
static unsigned ComputeNumSignBits(const Value *V, const APInt &DemandedElts,
unsigned Depth, const Query &Q) {
unsigned Result = ComputeNumSignBitsImpl(V, DemandedElts, Depth, Q);
assert(Result > 0 && "At least one sign bit needs to be present!");
return Result;
}
/// Return the number of times the sign bit of the register is replicated into
/// the other bits. We know that at least 1 bit is always equal to the sign bit
/// (itself), but other cases can give us information. For example, immediately
/// after an "ashr X, 2", we know that the top 3 bits are all equal to each
/// other, so we return 3. For vectors, return the number of sign bits for the
/// vector element with the minimum number of known sign bits of the demanded
/// elements in the vector specified by DemandedElts.
static unsigned ComputeNumSignBitsImpl(const Value *V,
const APInt &DemandedElts,
unsigned Depth, const Query &Q) {
Type *Ty = V->getType();
// FIXME: We currently have no way to represent the DemandedElts of a scalable
// vector
if (isa<ScalableVectorType>(Ty))
return 1;
#ifndef NDEBUG
assert(Depth <= MaxAnalysisRecursionDepth && "Limit Search Depth");
if (auto *FVTy = dyn_cast<FixedVectorType>(Ty)) {
assert(
FVTy->getNumElements() == DemandedElts.getBitWidth() &&
"DemandedElt width should equal the fixed vector number of elements");
} else {
assert(DemandedElts == APInt(1, 1) &&
"DemandedElt width should be 1 for scalars");
}
#endif
// We return the minimum number of sign bits that are guaranteed to be present
// in V, so for undef we have to conservatively return 1. We don't have the
// same behavior for poison though -- that's a FIXME today.
Type *ScalarTy = Ty->getScalarType();
unsigned TyBits = ScalarTy->isPointerTy() ?
Q.DL.getPointerTypeSizeInBits(ScalarTy) :
Q.DL.getTypeSizeInBits(ScalarTy);
unsigned Tmp, Tmp2;
unsigned FirstAnswer = 1;
// Note that ConstantInt is handled by the general computeKnownBits case
// below.
if (Depth == MaxAnalysisRecursionDepth)
return 1;
if (auto *U = dyn_cast<Operator>(V)) {
switch (Operator::getOpcode(V)) {
default: break;
case Instruction::SExt:
Tmp = TyBits - U->getOperand(0)->getType()->getScalarSizeInBits();
return ComputeNumSignBits(U->getOperand(0), Depth + 1, Q) + Tmp;
case Instruction::SDiv: {
const APInt *Denominator;
// sdiv X, C -> adds log(C) sign bits.
if (match(U->getOperand(1), m_APInt(Denominator))) {
// Ignore non-positive denominator.
if (!Denominator->isStrictlyPositive())
break;
// Calculate the incoming numerator bits.
unsigned NumBits = ComputeNumSignBits(U->getOperand(0), Depth + 1, Q);
// Add floor(log(C)) bits to the numerator bits.
return std::min(TyBits, NumBits + Denominator->logBase2());
}
break;
}
case Instruction::SRem: {
Tmp = ComputeNumSignBits(U->getOperand(0), Depth + 1, Q);
const APInt *Denominator;
// srem X, C -> we know that the result is within [-C+1,C) when C is a
// positive constant. This let us put a lower bound on the number of sign
// bits.
if (match(U->getOperand(1), m_APInt(Denominator))) {
// Ignore non-positive denominator.
if (Denominator->isStrictlyPositive()) {
// Calculate the leading sign bit constraints by examining the
// denominator. Given that the denominator is positive, there are two
// cases:
//
// 1. The numerator is positive. The result range is [0,C) and
// [0,C) u< (1 << ceilLogBase2(C)).
//
// 2. The numerator is negative. Then the result range is (-C,0] and
// integers in (-C,0] are either 0 or >u (-1 << ceilLogBase2(C)).
//
// Thus a lower bound on the number of sign bits is `TyBits -
// ceilLogBase2(C)`.
unsigned ResBits = TyBits - Denominator->ceilLogBase2();
Tmp = std::max(Tmp, ResBits);
}
}
return Tmp;
}
case Instruction::AShr: {
Tmp = ComputeNumSignBits(U->getOperand(0), Depth + 1, Q);
// ashr X, C -> adds C sign bits. Vectors too.
const APInt *ShAmt;
if (match(U->getOperand(1), m_APInt(ShAmt))) {
if (ShAmt->uge(TyBits))
break; // Bad shift.
unsigned ShAmtLimited = ShAmt->getZExtValue();
Tmp += ShAmtLimited;
if (Tmp > TyBits) Tmp = TyBits;
}
return Tmp;
}
case Instruction::Shl: {
const APInt *ShAmt;
if (match(U->getOperand(1), m_APInt(ShAmt))) {
// shl destroys sign bits.
Tmp = ComputeNumSignBits(U->getOperand(0), Depth + 1, Q);
if (ShAmt->uge(TyBits) || // Bad shift.
ShAmt->uge(Tmp)) break; // Shifted all sign bits out.
Tmp2 = ShAmt->getZExtValue();
return Tmp - Tmp2;
}
break;
}
case Instruction::And:
case Instruction::Or:
case Instruction::Xor: // NOT is handled here.
// Logical binary ops preserve the number of sign bits at the worst.
Tmp = ComputeNumSignBits(U->getOperand(0), Depth + 1, Q);
if (Tmp != 1) {
Tmp2 = ComputeNumSignBits(U->getOperand(1), Depth + 1, Q);
FirstAnswer = std::min(Tmp, Tmp2);
// We computed what we know about the sign bits as our first
// answer. Now proceed to the generic code that uses
// computeKnownBits, and pick whichever answer is better.
}
break;
case Instruction::Select: {
// If we have a clamp pattern, we know that the number of sign bits will
// be the minimum of the clamp min/max range.
const Value *X;
const APInt *CLow, *CHigh;
if (isSignedMinMaxClamp(U, X, CLow, CHigh))
return std::min(CLow->getNumSignBits(), CHigh->getNumSignBits());
Tmp = ComputeNumSignBits(U->getOperand(1), Depth + 1, Q);
if (Tmp == 1) break;
Tmp2 = ComputeNumSignBits(U->getOperand(2), Depth + 1, Q);
return std::min(Tmp, Tmp2);
}
case Instruction::Add:
// Add can have at most one carry bit. Thus we know that the output
// is, at worst, one more bit than the inputs.
Tmp = ComputeNumSignBits(U->getOperand(0), Depth + 1, Q);
if (Tmp == 1) break;
// Special case decrementing a value (ADD X, -1):
if (const auto *CRHS = dyn_cast<Constant>(U->getOperand(1)))
if (CRHS->isAllOnesValue()) {
KnownBits Known(TyBits);
computeKnownBits(U->getOperand(0), Known, Depth + 1, Q);
// If the input is known to be 0 or 1, the output is 0/-1, which is
// all sign bits set.
if ((Known.Zero | 1).isAllOnes())
return TyBits;
// If we are subtracting one from a positive number, there is no carry
// out of the result.
if (Known.isNonNegative())
return Tmp;
}
Tmp2 = ComputeNumSignBits(U->getOperand(1), Depth + 1, Q);
if (Tmp2 == 1) break;
return std::min(Tmp, Tmp2) - 1;
case Instruction::Sub:
Tmp2 = ComputeNumSignBits(U->getOperand(1), Depth + 1, Q);
if (Tmp2 == 1) break;
// Handle NEG.
if (const auto *CLHS = dyn_cast<Constant>(U->getOperand(0)))
if (CLHS->isNullValue()) {
KnownBits Known(TyBits);
computeKnownBits(U->getOperand(1), Known, Depth + 1, Q);
// If the input is known to be 0 or 1, the output is 0/-1, which is
// all sign bits set.
if ((Known.Zero | 1).isAllOnes())
return TyBits;
// If the input is known to be positive (the sign bit is known clear),
// the output of the NEG has the same number of sign bits as the
// input.
if (Known.isNonNegative())
return Tmp2;
// Otherwise, we treat this like a SUB.
}
// Sub can have at most one carry bit. Thus we know that the output
// is, at worst, one more bit than the inputs.
Tmp = ComputeNumSignBits(U->getOperand(0), Depth + 1, Q);
if (Tmp == 1) break;
return std::min(Tmp, Tmp2) - 1;
case Instruction::Mul: {
// The output of the Mul can be at most twice the valid bits in the
// inputs.
unsigned SignBitsOp0 = ComputeNumSignBits(U->getOperand(0), Depth + 1, Q);
if (SignBitsOp0 == 1) break;
unsigned SignBitsOp1 = ComputeNumSignBits(U->getOperand(1), Depth + 1, Q);
if (SignBitsOp1 == 1) break;
unsigned OutValidBits =
(TyBits - SignBitsOp0 + 1) + (TyBits - SignBitsOp1 + 1);
return OutValidBits > TyBits ? 1 : TyBits - OutValidBits + 1;
}
case Instruction::PHI: {
const PHINode *PN = cast<PHINode>(U);
unsigned NumIncomingValues = PN->getNumIncomingValues();
// Don't analyze large in-degree PHIs.
if (NumIncomingValues > 4) break;
// Unreachable blocks may have zero-operand PHI nodes.
if (NumIncomingValues == 0) break;
// Take the minimum of all incoming values. This can't infinitely loop
// because of our depth threshold.
Query RecQ = Q;
Tmp = TyBits;
for (unsigned i = 0, e = NumIncomingValues; i != e; ++i) {
if (Tmp == 1) return Tmp;
RecQ.CxtI = PN->getIncomingBlock(i)->getTerminator();
Tmp = std::min(
Tmp, ComputeNumSignBits(PN->getIncomingValue(i), Depth + 1, RecQ));
}
return Tmp;
}
case Instruction::Trunc:
// FIXME: it's tricky to do anything useful for this, but it is an
// important case for targets like X86.
break;
case Instruction::ExtractElement:
// Look through extract element. At the moment we keep this simple and
// skip tracking the specific element. But at least we might find
// information valid for all elements of the vector (for example if vector
// is sign extended, shifted, etc).
return ComputeNumSignBits(U->getOperand(0), Depth + 1, Q);
case Instruction::ShuffleVector: {
// Collect the minimum number of sign bits that are shared by every vector
// element referenced by the shuffle.
auto *Shuf = dyn_cast<ShuffleVectorInst>(U);
if (!Shuf) {
// FIXME: Add support for shufflevector constant expressions.
return 1;
}
APInt DemandedLHS, DemandedRHS;
// For undef elements, we don't know anything about the common state of
// the shuffle result.
if (!getShuffleDemandedElts(Shuf, DemandedElts, DemandedLHS, DemandedRHS))
return 1;
Tmp = std::numeric_limits<unsigned>::max();
if (!!DemandedLHS) {
const Value *LHS = Shuf->getOperand(0);
Tmp = ComputeNumSignBits(LHS, DemandedLHS, Depth + 1, Q);
}
// If we don't know anything, early out and try computeKnownBits
// fall-back.
if (Tmp == 1)
break;
if (!!DemandedRHS) {
const Value *RHS = Shuf->getOperand(1);
Tmp2 = ComputeNumSignBits(RHS, DemandedRHS, Depth + 1, Q);
Tmp = std::min(Tmp, Tmp2);
}
// If we don't know anything, early out and try computeKnownBits
// fall-back.
if (Tmp == 1)
break;
assert(Tmp <= TyBits && "Failed to determine minimum sign bits");
return Tmp;
}
case Instruction::Call: {
if (const auto *II = dyn_cast<IntrinsicInst>(U)) {
switch (II->getIntrinsicID()) {
default: break;
case Intrinsic::abs:
Tmp = ComputeNumSignBits(U->getOperand(0), Depth + 1, Q);
if (Tmp == 1) break;
// Absolute value reduces number of sign bits by at most 1.
return Tmp - 1;
case Intrinsic::smin:
case Intrinsic::smax: {
const APInt *CLow, *CHigh;
if (isSignedMinMaxIntrinsicClamp(II, CLow, CHigh))
return std::min(CLow->getNumSignBits(), CHigh->getNumSignBits());
}
}
}
}
}
}
// Finally, if we can prove that the top bits of the result are 0's or 1's,
// use this information.
// If we can examine all elements of a vector constant successfully, we're
// done (we can't do any better than that). If not, keep trying.
if (unsigned VecSignBits =
computeNumSignBitsVectorConstant(V, DemandedElts, TyBits))
return VecSignBits;
KnownBits Known(TyBits);
computeKnownBits(V, DemandedElts, Known, Depth, Q);
// If we know that the sign bit is either zero or one, determine the number of
// identical bits in the top of the input value.
return std::max(FirstAnswer, Known.countMinSignBits());
}
Intrinsic::ID llvm::getIntrinsicForCallSite(const CallBase &CB,
const TargetLibraryInfo *TLI) {
const Function *F = CB.getCalledFunction();
if (!F)
return Intrinsic::not_intrinsic;
if (F->isIntrinsic())
return F->getIntrinsicID();
// We are going to infer semantics of a library function based on mapping it
// to an LLVM intrinsic. Check that the library function is available from
// this callbase and in this environment.
LibFunc Func;
if (F->hasLocalLinkage() || !TLI || !TLI->getLibFunc(CB, Func) ||
!CB.onlyReadsMemory())
return Intrinsic::not_intrinsic;
switch (Func) {
default:
break;
case LibFunc_sin:
case LibFunc_sinf:
case LibFunc_sinl:
return Intrinsic::sin;
case LibFunc_cos:
case LibFunc_cosf:
case LibFunc_cosl:
return Intrinsic::cos;
case LibFunc_exp:
case LibFunc_expf:
case LibFunc_expl:
return Intrinsic::exp;
case LibFunc_exp2:
case LibFunc_exp2f:
case LibFunc_exp2l:
return Intrinsic::exp2;
case LibFunc_log:
case LibFunc_logf:
case LibFunc_logl:
return Intrinsic::log;
case LibFunc_log10:
case LibFunc_log10f:
case LibFunc_log10l:
return Intrinsic::log10;
case LibFunc_log2:
case LibFunc_log2f:
case LibFunc_log2l:
return Intrinsic::log2;
case LibFunc_fabs:
case LibFunc_fabsf:
case LibFunc_fabsl:
return Intrinsic::fabs;
case LibFunc_fmin:
case LibFunc_fminf:
case LibFunc_fminl:
return Intrinsic::minnum;
case LibFunc_fmax:
case LibFunc_fmaxf:
case LibFunc_fmaxl:
return Intrinsic::maxnum;
case LibFunc_copysign:
case LibFunc_copysignf:
case LibFunc_copysignl:
return Intrinsic::copysign;
case LibFunc_floor:
case LibFunc_floorf:
case LibFunc_floorl:
return Intrinsic::floor;
case LibFunc_ceil:
case LibFunc_ceilf:
case LibFunc_ceill:
return Intrinsic::ceil;
case LibFunc_trunc:
case LibFunc_truncf:
case LibFunc_truncl:
return Intrinsic::trunc;
case LibFunc_rint:
case LibFunc_rintf:
case LibFunc_rintl:
return Intrinsic::rint;
case LibFunc_nearbyint:
case LibFunc_nearbyintf:
case LibFunc_nearbyintl:
return Intrinsic::nearbyint;
case LibFunc_round:
case LibFunc_roundf:
case LibFunc_roundl:
return Intrinsic::round;
case LibFunc_roundeven:
case LibFunc_roundevenf:
case LibFunc_roundevenl:
return Intrinsic::roundeven;
case LibFunc_pow:
case LibFunc_powf:
case LibFunc_powl:
return Intrinsic::pow;
case LibFunc_sqrt:
case LibFunc_sqrtf:
case LibFunc_sqrtl:
return Intrinsic::sqrt;
}
return Intrinsic::not_intrinsic;
}
/// Return true if we can prove that the specified FP value is never equal to
/// -0.0.
/// NOTE: Do not check 'nsz' here because that fast-math-flag does not guarantee
/// that a value is not -0.0. It only guarantees that -0.0 may be treated
/// the same as +0.0 in floating-point ops.
bool llvm::CannotBeNegativeZero(const Value *V, const TargetLibraryInfo *TLI,
unsigned Depth) {
if (auto *CFP = dyn_cast<ConstantFP>(V))
return !CFP->getValueAPF().isNegZero();
if (Depth == MaxAnalysisRecursionDepth)
return false;
auto *Op = dyn_cast<Operator>(V);
if (!Op)
return false;
// (fadd x, 0.0) is guaranteed to return +0.0, not -0.0.
if (match(Op, m_FAdd(m_Value(), m_PosZeroFP())))
return true;
// sitofp and uitofp turn into +0.0 for zero.
if (isa<SIToFPInst>(Op) || isa<UIToFPInst>(Op))
return true;
if (auto *Call = dyn_cast<CallInst>(Op)) {
Intrinsic::ID IID = getIntrinsicForCallSite(*Call, TLI);
switch (IID) {
default:
break;
// sqrt(-0.0) = -0.0, no other negative results are possible.
case Intrinsic::sqrt:
case Intrinsic::canonicalize:
return CannotBeNegativeZero(Call->getArgOperand(0), TLI, Depth + 1);
case Intrinsic::experimental_constrained_sqrt: {
// NOTE: This rounding mode restriction may be too strict.
const auto *CI = cast<ConstrainedFPIntrinsic>(Call);
if (CI->getRoundingMode() == RoundingMode::NearestTiesToEven)
return CannotBeNegativeZero(Call->getArgOperand(0), TLI, Depth + 1);
else
return false;
}
// fabs(x) != -0.0
case Intrinsic::fabs:
return true;
// sitofp and uitofp turn into +0.0 for zero.
case Intrinsic::experimental_constrained_sitofp:
case Intrinsic::experimental_constrained_uitofp:
return true;
}
}
return false;
}
/// If \p SignBitOnly is true, test for a known 0 sign bit rather than a
/// standard ordered compare. e.g. make -0.0 olt 0.0 be true because of the sign
/// bit despite comparing equal.
static bool cannotBeOrderedLessThanZeroImpl(const Value *V,
const TargetLibraryInfo *TLI,
bool SignBitOnly,
unsigned Depth) {
// TODO: This function does not do the right thing when SignBitOnly is true
// and we're lowering to a hypothetical IEEE 754-compliant-but-evil platform
// which flips the sign bits of NaNs. See
// https://llvm.org/bugs/show_bug.cgi?id=31702.
if (const ConstantFP *CFP = dyn_cast<ConstantFP>(V)) {
return !CFP->getValueAPF().isNegative() ||
(!SignBitOnly && CFP->getValueAPF().isZero());
}
// Handle vector of constants.
if (auto *CV = dyn_cast<Constant>(V)) {
if (auto *CVFVTy = dyn_cast<FixedVectorType>(CV->getType())) {
unsigned NumElts = CVFVTy->getNumElements();
for (unsigned i = 0; i != NumElts; ++i) {
auto *CFP = dyn_cast_or_null<ConstantFP>(CV->getAggregateElement(i));
if (!CFP)
return false;
if (CFP->getValueAPF().isNegative() &&
(SignBitOnly || !CFP->getValueAPF().isZero()))
return false;
}
// All non-negative ConstantFPs.
return true;
}
}
if (Depth == MaxAnalysisRecursionDepth)
return false;
const Operator *I = dyn_cast<Operator>(V);
if (!I)
return false;
switch (I->getOpcode()) {
default:
break;
// Unsigned integers are always nonnegative.
case Instruction::UIToFP:
return true;
- case Instruction::FMul:
case Instruction::FDiv:
- // X * X is always non-negative or a NaN.
// X / X is always exactly 1.0 or a NaN.
if (I->getOperand(0) == I->getOperand(1) &&
(!SignBitOnly || cast<FPMathOperator>(I)->hasNoNaNs()))
return true;
+ // Set SignBitOnly for RHS, because X / -0.0 is -Inf (or NaN).
+ return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly,
+ Depth + 1) &&
+ cannotBeOrderedLessThanZeroImpl(I->getOperand(1), TLI,
+ /*SignBitOnly*/ true, Depth + 1);
+ case Instruction::FMul:
+ // X * X is always non-negative or a NaN.
+ if (I->getOperand(0) == I->getOperand(1) &&
+ (!SignBitOnly || cast<FPMathOperator>(I)->hasNoNaNs()))
+ return true;
+
LLVM_FALLTHROUGH;
case Instruction::FAdd:
case Instruction::FRem:
return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly,
Depth + 1) &&
cannotBeOrderedLessThanZeroImpl(I->getOperand(1), TLI, SignBitOnly,
Depth + 1);
case Instruction::Select:
return cannotBeOrderedLessThanZeroImpl(I->getOperand(1), TLI, SignBitOnly,
Depth + 1) &&
cannotBeOrderedLessThanZeroImpl(I->getOperand(2), TLI, SignBitOnly,
Depth + 1);
case Instruction::FPExt:
case Instruction::FPTrunc:
// Widening/narrowing never change sign.
return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly,
Depth + 1);
case Instruction::ExtractElement:
// Look through extract element. At the moment we keep this simple and skip
// tracking the specific element. But at least we might find information
// valid for all elements of the vector.
return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly,
Depth + 1);
case Instruction::Call:
const auto *CI = cast<CallInst>(I);
Intrinsic::ID IID = getIntrinsicForCallSite(*CI, TLI);
switch (IID) {
default:
break;
case Intrinsic::maxnum: {
Value *V0 = I->getOperand(0), *V1 = I->getOperand(1);
auto isPositiveNum = [&](Value *V) {
if (SignBitOnly) {
// With SignBitOnly, this is tricky because the result of
// maxnum(+0.0, -0.0) is unspecified. Just check if the operand is
// a constant strictly greater than 0.0.
const APFloat *C;
return match(V, m_APFloat(C)) &&
*C > APFloat::getZero(C->getSemantics());
}
// -0.0 compares equal to 0.0, so if this operand is at least -0.0,
// maxnum can't be ordered-less-than-zero.
return isKnownNeverNaN(V, TLI) &&
cannotBeOrderedLessThanZeroImpl(V, TLI, false, Depth + 1);
};
// TODO: This could be improved. We could also check that neither operand
// has its sign bit set (and at least 1 is not-NAN?).
return isPositiveNum(V0) || isPositiveNum(V1);
}
case Intrinsic::maximum:
return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly,
Depth + 1) ||
cannotBeOrderedLessThanZeroImpl(I->getOperand(1), TLI, SignBitOnly,
Depth + 1);
case Intrinsic::minnum:
case Intrinsic::minimum:
return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly,
Depth + 1) &&
cannotBeOrderedLessThanZeroImpl(I->getOperand(1), TLI, SignBitOnly,
Depth + 1);
case Intrinsic::exp:
case Intrinsic::exp2:
case Intrinsic::fabs:
return true;
case Intrinsic::sqrt:
// sqrt(x) is always >= -0 or NaN. Moreover, sqrt(x) == -0 iff x == -0.
if (!SignBitOnly)
return true;
return CI->hasNoNaNs() && (CI->hasNoSignedZeros() ||
CannotBeNegativeZero(CI->getOperand(0), TLI));
case Intrinsic::powi:
if (ConstantInt *Exponent = dyn_cast<ConstantInt>(I->getOperand(1))) {
// powi(x,n) is non-negative if n is even.
if (Exponent->getBitWidth() <= 64 && Exponent->getSExtValue() % 2u == 0)
return true;
}
// TODO: This is not correct. Given that exp is an integer, here are the
// ways that pow can return a negative value:
//
// pow(x, exp) --> negative if exp is odd and x is negative.
// pow(-0, exp) --> -inf if exp is negative odd.
// pow(-0, exp) --> -0 if exp is positive odd.
// pow(-inf, exp) --> -0 if exp is negative odd.
// pow(-inf, exp) --> -inf if exp is positive odd.
//
// Therefore, if !SignBitOnly, we can return true if x >= +0 or x is NaN,
// but we must return false if x == -0. Unfortunately we do not currently
// have a way of expressing this constraint. See details in
// https://llvm.org/bugs/show_bug.cgi?id=31702.
return cannotBeOrderedLessThanZeroImpl(I->getOperand(0), TLI, SignBitOnly,
Depth + 1);
case Intrinsic::fma:
case Intrinsic::fmuladd:
// x*x+y is non-negative if y is non-negative.
return I->getOperand(0) == I->getOperand(1) &&
(!SignBitOnly || cast<FPMathOperator>(I)->hasNoNaNs()) &&
cannotBeOrderedLessThanZeroImpl(I->getOperand(2), TLI, SignBitOnly,
Depth + 1);
}
break;
}
return false;
}
bool llvm::CannotBeOrderedLessThanZero(const Value *V,
const TargetLibraryInfo *TLI) {
return cannotBeOrderedLessThanZeroImpl(V, TLI, false, 0);
}
bool llvm::SignBitMustBeZero(const Value *V, const TargetLibraryInfo *TLI) {
return cannotBeOrderedLessThanZeroImpl(V, TLI, true, 0);
}
bool llvm::isKnownNeverInfinity(const Value *V, const TargetLibraryInfo *TLI,
unsigned Depth) {
assert(V->getType()->isFPOrFPVectorTy() && "Querying for Inf on non-FP type");
// If we're told that infinities won't happen, assume they won't.
if (auto *FPMathOp = dyn_cast<FPMathOperator>(V))
if (FPMathOp->hasNoInfs())
return true;
// Handle scalar constants.
if (auto *CFP = dyn_cast<ConstantFP>(V))
return !CFP->isInfinity();
if (Depth == MaxAnalysisRecursionDepth)
return false;
if (auto *Inst = dyn_cast<Instruction>(V)) {
switch (Inst->getOpcode()) {
case Instruction::Select: {
return isKnownNeverInfinity(Inst->getOperand(1), TLI, Depth + 1) &&
isKnownNeverInfinity(Inst->getOperand(2), TLI, Depth + 1);
}
case Instruction::SIToFP:
case Instruction::UIToFP: {
// Get width of largest magnitude integer (remove a bit if signed).
// This still works for a signed minimum value because the largest FP
// value is scaled by some fraction close to 2.0 (1.0 + 0.xxxx).
int IntSize = Inst->getOperand(0)->getType()->getScalarSizeInBits();
if (Inst->getOpcode() == Instruction::SIToFP)
--IntSize;
// If the exponent of the largest finite FP value can hold the largest
// integer, the result of the cast must be finite.
Type *FPTy = Inst->getType()->getScalarType();
return ilogb(APFloat::getLargest(FPTy->getFltSemantics())) >= IntSize;
}
default:
break;
}
}
// try to handle fixed width vector constants
auto *VFVTy = dyn_cast<FixedVectorType>(V->getType());
if (VFVTy && isa<Constant>(V)) {
// For vectors, verify that each element is not infinity.
unsigned NumElts = VFVTy->getNumElements();
for (unsigned i = 0; i != NumElts; ++i) {
Constant *Elt = cast<Constant>(V)->getAggregateElement(i);
if (!Elt)
return false;
if (isa<UndefValue>(Elt))
continue;
auto *CElt = dyn_cast<ConstantFP>(Elt);
if (!CElt || CElt->isInfinity())
return false;
}
// All elements were confirmed non-infinity or undefined.
return true;
}
// was not able to prove that V never contains infinity
return false;
}
bool llvm::isKnownNeverNaN(const Value *V, const TargetLibraryInfo *TLI,
unsigned Depth) {
assert(V->getType()->isFPOrFPVectorTy() && "Querying for NaN on non-FP type");
// If we're told that NaNs won't happen, assume they won't.
if (auto *FPMathOp = dyn_cast<FPMathOperator>(V))
if (FPMathOp->hasNoNaNs())
return true;
// Handle scalar constants.
if (auto *CFP = dyn_cast<ConstantFP>(V))
return !CFP->isNaN();
if (Depth == MaxAnalysisRecursionDepth)
return false;
if (auto *Inst = dyn_cast<Instruction>(V)) {
switch (Inst->getOpcode()) {
case Instruction::FAdd:
case Instruction::FSub:
// Adding positive and negative infinity produces NaN.
return isKnownNeverNaN(Inst->getOperand(0), TLI, Depth + 1) &&
isKnownNeverNaN(Inst->getOperand(1), TLI, Depth + 1) &&
(isKnownNeverInfinity(Inst->getOperand(0), TLI, Depth + 1) ||
isKnownNeverInfinity(Inst->getOperand(1), TLI, Depth + 1));
case Instruction::FMul:
// Zero multiplied with infinity produces NaN.
// FIXME: If neither side can be zero fmul never produces NaN.
return isKnownNeverNaN(Inst->getOperand(0), TLI, Depth + 1) &&
isKnownNeverInfinity(Inst->getOperand(0), TLI, Depth + 1) &&
isKnownNeverNaN(Inst->getOperand(1), TLI, Depth + 1) &&
isKnownNeverInfinity(Inst->getOperand(1), TLI, Depth + 1);
case Instruction::FDiv:
case Instruction::FRem:
// FIXME: Only 0/0, Inf/Inf, Inf REM x and x REM 0 produce NaN.
return false;
case Instruction::Select: {
return isKnownNeverNaN(Inst->getOperand(1), TLI, Depth + 1) &&
isKnownNeverNaN(Inst->getOperand(2), TLI, Depth + 1);
}
case Instruction::SIToFP:
case Instruction::UIToFP:
return true;
case Instruction::FPTrunc:
case Instruction::FPExt:
return isKnownNeverNaN(Inst->getOperand(0), TLI, Depth + 1);
default:
break;
}
}
if (const auto *II = dyn_cast<IntrinsicInst>(V)) {
switch (II->getIntrinsicID()) {
case Intrinsic::canonicalize:
case Intrinsic::fabs:
case Intrinsic::copysign:
case Intrinsic::exp:
case Intrinsic::exp2:
case Intrinsic::floor:
case Intrinsic::ceil:
case Intrinsic::trunc:
case Intrinsic::rint:
case Intrinsic::nearbyint:
case Intrinsic::round:
case Intrinsic::roundeven:
return isKnownNeverNaN(II->getArgOperand(0), TLI, Depth + 1);
case Intrinsic::sqrt:
return isKnownNeverNaN(II->getArgOperand(0), TLI, Depth + 1) &&
CannotBeOrderedLessThanZero(II->getArgOperand(0), TLI);
case Intrinsic::minnum:
case Intrinsic::maxnum:
// If either operand is not NaN, the result is not NaN.
return isKnownNeverNaN(II->getArgOperand(0), TLI, Depth + 1) ||
isKnownNeverNaN(II->getArgOperand(1), TLI, Depth + 1);
default:
return false;
}
}
// Try to handle fixed width vector constants
auto *VFVTy = dyn_cast<FixedVectorType>(V->getType());
if (VFVTy && isa<Constant>(V)) {
// For vectors, verify that each element is not NaN.
unsigned NumElts = VFVTy->getNumElements();
for (unsigned i = 0; i != NumElts; ++i) {
Constant *Elt = cast<Constant>(V)->getAggregateElement(i);
if (!Elt)
return false;
if (isa<UndefValue>(Elt))
continue;
auto *CElt = dyn_cast<ConstantFP>(Elt);
if (!CElt || CElt->isNaN())
return false;
}
// All elements were confirmed not-NaN or undefined.
return true;
}
// Was not able to prove that V never contains NaN
return false;
}
Value *llvm::isBytewiseValue(Value *V, const DataLayout &DL) {
// All byte-wide stores are splatable, even of arbitrary variables.
if (V->getType()->isIntegerTy(8))
return V;
LLVMContext &Ctx = V->getContext();
// Undef don't care.
auto *UndefInt8 = UndefValue::get(Type::getInt8Ty(Ctx));
if (isa<UndefValue>(V))
return UndefInt8;
// Return Undef for zero-sized type.
if (!DL.getTypeStoreSize(V->getType()).isNonZero())
return UndefInt8;
Constant *C = dyn_cast<Constant>(V);
if (!C) {
// Conceptually, we could handle things like:
// %a = zext i8 %X to i16
// %b = shl i16 %a, 8
// %c = or i16 %a, %b
// but until there is an example that actually needs this, it doesn't seem
// worth worrying about.
return nullptr;
}
// Handle 'null' ConstantArrayZero etc.
if (C->isNullValue())
return Constant::getNullValue(Type::getInt8Ty(Ctx));
// Constant floating-point values can be handled as integer values if the
// corresponding integer value is "byteable". An important case is 0.0.
if (ConstantFP *CFP = dyn_cast<ConstantFP>(C)) {
Type *Ty = nullptr;
if (CFP->getType()->isHalfTy())
Ty = Type::getInt16Ty(Ctx);
else if (CFP->getType()->isFloatTy())
Ty = Type::getInt32Ty(Ctx);
else if (CFP->getType()->isDoubleTy())
Ty = Type::getInt64Ty(Ctx);
// Don't handle long double formats, which have strange constraints.
return Ty ? isBytewiseValue(ConstantExpr::getBitCast(CFP, Ty), DL)
: nullptr;
}
// We can handle constant integers that are multiple of 8 bits.
if (ConstantInt *CI = dyn_cast<ConstantInt>(C)) {
if (CI->getBitWidth() % 8 == 0) {
assert(CI->getBitWidth() > 8 && "8 bits should be handled above!");
if (!CI->getValue().isSplat(8))
return nullptr;
return ConstantInt::get(Ctx, CI->getValue().trunc(8));
}
}
if (auto *CE = dyn_cast<ConstantExpr>(C)) {
if (CE->getOpcode() == Instruction::IntToPtr) {
if (auto *PtrTy = dyn_cast<PointerType>(CE->getType())) {
unsigned BitWidth = DL.getPointerSizeInBits(PtrTy->getAddressSpace());
return isBytewiseValue(
ConstantExpr::getIntegerCast(CE->getOperand(0),
Type::getIntNTy(Ctx, BitWidth), false),
DL);
}
}
}
auto Merge = [&](Value *LHS, Value *RHS) -> Value * {
if (LHS == RHS)
return LHS;
if (!LHS || !RHS)
return nullptr;
if (LHS == UndefInt8)
return RHS;
if (RHS == UndefInt8)
return LHS;
return nullptr;
};
if (ConstantDataSequential *CA = dyn_cast<ConstantDataSequential>(C)) {
Value *Val = UndefInt8;
for (unsigned I = 0, E = CA->getNumElements(); I != E; ++I)
if (!(Val = Merge(Val, isBytewiseValue(CA->getElementAsConstant(I), DL))))
return nullptr;
return Val;
}
if (isa<ConstantAggregate>(C)) {
Value *Val = UndefInt8;
for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I)
if (!(Val = Merge(Val, isBytewiseValue(C->getOperand(I), DL))))
return nullptr;
return Val;
}
// Don't try to handle the handful of other constants.
return nullptr;
}
// This is the recursive version of BuildSubAggregate. It takes a few different
// arguments. Idxs is the index within the nested struct From that we are
// looking at now (which is of type IndexedType). IdxSkip is the number of
// indices from Idxs that should be left out when inserting into the resulting
// struct. To is the result struct built so far, new insertvalue instructions
// build on that.
static Value *BuildSubAggregate(Value *From, Value* To, Type *IndexedType,
SmallVectorImpl<unsigned> &Idxs,
unsigned IdxSkip,
Instruction *InsertBefore) {
StructType *STy = dyn_cast<StructType>(IndexedType);
if (STy) {
// Save the original To argument so we can modify it
Value *OrigTo = To;
// General case, the type indexed by Idxs is a struct
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
// Process each struct element recursively
Idxs.push_back(i);
Value *PrevTo = To;
To = BuildSubAggregate(From, To, STy->getElementType(i), Idxs, IdxSkip,
InsertBefore);
Idxs.pop_back();
if (!To) {
// Couldn't find any inserted value for this index? Cleanup
while (PrevTo != OrigTo) {
InsertValueInst* Del = cast<InsertValueInst>(PrevTo);
PrevTo = Del->getAggregateOperand();
Del->eraseFromParent();
}
// Stop processing elements
break;
}
}
// If we successfully found a value for each of our subaggregates
if (To)
return To;
}
// Base case, the type indexed by SourceIdxs is not a struct, or not all of
// the struct's elements had a value that was inserted directly. In the latter
// case, perhaps we can't determine each of the subelements individually, but
// we might be able to find the complete struct somewhere.
// Find the value that is at that particular spot
Value *V = FindInsertedValue(From, Idxs);
if (!V)
return nullptr;
// Insert the value in the new (sub) aggregate
return InsertValueInst::Create(To, V, makeArrayRef(Idxs).slice(IdxSkip),
"tmp", InsertBefore);
}
// This helper takes a nested struct and extracts a part of it (which is again a
// struct) into a new value. For example, given the struct:
// { a, { b, { c, d }, e } }
// and the indices "1, 1" this returns
// { c, d }.
//
// It does this by inserting an insertvalue for each element in the resulting
// struct, as opposed to just inserting a single struct. This will only work if
// each of the elements of the substruct are known (ie, inserted into From by an
// insertvalue instruction somewhere).
//
// All inserted insertvalue instructions are inserted before InsertBefore
static Value *BuildSubAggregate(Value *From, ArrayRef<unsigned> idx_range,
Instruction *InsertBefore) {
assert(InsertBefore && "Must have someplace to insert!");
Type *IndexedType = ExtractValueInst::getIndexedType(From->getType(),
idx_range);
Value *To = UndefValue::get(IndexedType);
SmallVector<unsigned, 10> Idxs(idx_range.begin(), idx_range.end());
unsigned IdxSkip = Idxs.size();
return BuildSubAggregate(From, To, IndexedType, Idxs, IdxSkip, InsertBefore);
}
/// Given an aggregate and a sequence of indices, see if the scalar value
/// indexed is already around as a register, for example if it was inserted
/// directly into the aggregate.
///
/// If InsertBefore is not null, this function will duplicate (modified)
/// insertvalues when a part of a nested struct is extracted.
Value *llvm::FindInsertedValue(Value *V, ArrayRef<unsigned> idx_range,
Instruction *InsertBefore) {
// Nothing to index? Just return V then (this is useful at the end of our
// recursion).
if (idx_range.empty())
return V;
// We have indices, so V should have an indexable type.
assert((V->getType()->isStructTy() || V->getType()->isArrayTy()) &&
"Not looking at a struct or array?");
assert(ExtractValueInst::getIndexedType(V->getType(), idx_range) &&
"Invalid indices for type?");
if (Constant *C = dyn_cast<Constant>(V)) {
C = C->getAggregateElement(idx_range[0]);
if (!C) return nullptr;
return FindInsertedValue(C, idx_range.slice(1), InsertBefore);
}
if (InsertValueInst *I = dyn_cast<InsertValueInst>(V)) {
// Loop the indices for the insertvalue instruction in parallel with the
// requested indices
const unsigned *req_idx = idx_range.begin();
for (const unsigned *i = I->idx_begin(), *e = I->idx_end();
i != e; ++i, ++req_idx) {
if (req_idx == idx_range.end()) {
// We can't handle this without inserting insertvalues
if (!InsertBefore)
return nullptr;
// The requested index identifies a part of a nested aggregate. Handle
// this specially. For example,
// %A = insertvalue { i32, {i32, i32 } } undef, i32 10, 1, 0
// %B = insertvalue { i32, {i32, i32 } } %A, i32 11, 1, 1
// %C = extractvalue {i32, { i32, i32 } } %B, 1
// This can be changed into
// %A = insertvalue {i32, i32 } undef, i32 10, 0
// %C = insertvalue {i32, i32 } %A, i32 11, 1
// which allows the unused 0,0 element from the nested struct to be
// removed.
return BuildSubAggregate(V, makeArrayRef(idx_range.begin(), req_idx),
InsertBefore);
}
// This insert value inserts something else than what we are looking for.
// See if the (aggregate) value inserted into has the value we are
// looking for, then.
if (*req_idx != *i)
return FindInsertedValue(I->getAggregateOperand(), idx_range,
InsertBefore);
}
// If we end up here, the indices of the insertvalue match with those
// requested (though possibly only partially). Now we recursively look at
// the inserted value, passing any remaining indices.
return FindInsertedValue(I->getInsertedValueOperand(),
makeArrayRef(req_idx, idx_range.end()),
InsertBefore);
}
if (ExtractValueInst *I = dyn_cast<ExtractValueInst>(V)) {
// If we're extracting a value from an aggregate that was extracted from
// something else, we can extract from that something else directly instead.
// However, we will need to chain I's indices with the requested indices.
// Calculate the number of indices required
unsigned size = I->getNumIndices() + idx_range.size();
// Allocate some space to put the new indices in
SmallVector<unsigned, 5> Idxs;
Idxs.reserve(size);
// Add indices from the extract value instruction
Idxs.append(I->idx_begin(), I->idx_end());
// Add requested indices
Idxs.append(idx_range.begin(), idx_range.end());
assert(Idxs.size() == size
&& "Number of indices added not correct?");
return FindInsertedValue(I->getAggregateOperand(), Idxs, InsertBefore);
}
// Otherwise, we don't know (such as, extracting from a function return value
// or load instruction)
return nullptr;
}
bool llvm::isGEPBasedOnPointerToString(const GEPOperator *GEP,
unsigned CharSize) {
// Make sure the GEP has exactly three arguments.
if (GEP->getNumOperands() != 3)
return false;
// Make sure the index-ee is a pointer to array of \p CharSize integers.
// CharSize.
ArrayType *AT = dyn_cast<ArrayType>(GEP->getSourceElementType());
if (!AT || !AT->getElementType()->isIntegerTy(CharSize))
return false;
// Check to make sure that the first operand of the GEP is an integer and
// has value 0 so that we are sure we're indexing into the initializer.
const ConstantInt *FirstIdx = dyn_cast<ConstantInt>(GEP->getOperand(1));
if (!FirstIdx || !FirstIdx->isZero())
return false;
return true;
}
// If V refers to an initialized global constant, set Slice either to
// its initializer if the size of its elements equals ElementSize, or,
// for ElementSize == 8, to its representation as an array of unsiged
// char. Return true on success.
bool llvm::getConstantDataArrayInfo(const Value *V,
ConstantDataArraySlice &Slice,
unsigned ElementSize, uint64_t Offset) {
assert(V);
// Drill down into the pointer expression V, ignoring any intervening
// casts, and determine the identity of the object it references along
// with the cumulative byte offset into it.
const GlobalVariable *GV =
dyn_cast<GlobalVariable>(getUnderlyingObject(V));
if (!GV || !GV->isConstant() || !GV->hasDefinitiveInitializer())
// Fail if V is not based on constant global object.
return false;
const DataLayout &DL = GV->getParent()->getDataLayout();
APInt Off(DL.getIndexTypeSizeInBits(V->getType()), 0);
if (GV != V->stripAndAccumulateConstantOffsets(DL, Off,
/*AllowNonInbounds*/ true))
// Fail if a constant offset could not be determined.
return false;
uint64_t StartIdx = Off.getLimitedValue();
if (StartIdx == UINT64_MAX)
// Fail if the constant offset is excessive.
return false;
Offset += StartIdx;
ConstantDataArray *Array = nullptr;
ArrayType *ArrayTy = nullptr;
if (GV->getInitializer()->isNullValue()) {
Type *GVTy = GV->getValueType();
uint64_t SizeInBytes = DL.getTypeStoreSize(GVTy).getFixedSize();
uint64_t Length = SizeInBytes / (ElementSize / 8);
Slice.Array = nullptr;
Slice.Offset = 0;
// Return an empty Slice for undersized constants to let callers
// transform even undefined library calls into simpler, well-defined
// expressions. This is preferable to making the calls although it
// prevents sanitizers from detecting such calls.
Slice.Length = Length < Offset ? 0 : Length - Offset;
return true;
}
auto *Init = const_cast<Constant *>(GV->getInitializer());
if (auto *ArrayInit = dyn_cast<ConstantDataArray>(Init)) {
Type *InitElTy = ArrayInit->getElementType();
if (InitElTy->isIntegerTy(ElementSize)) {
// If Init is an initializer for an array of the expected type
// and size, use it as is.
Array = ArrayInit;
ArrayTy = ArrayInit->getType();
}
}
if (!Array) {
if (ElementSize != 8)
// TODO: Handle conversions to larger integral types.
return false;
// Otherwise extract the portion of the initializer starting
// at Offset as an array of bytes, and reset Offset.
Init = ReadByteArrayFromGlobal(GV, Offset);
if (!Init)
return false;
Offset = 0;
Array = dyn_cast<ConstantDataArray>(Init);
ArrayTy = dyn_cast<ArrayType>(Init->getType());
}
uint64_t NumElts = ArrayTy->getArrayNumElements();
if (Offset > NumElts)
return false;
Slice.Array = Array;
Slice.Offset = Offset;
Slice.Length = NumElts - Offset;
return true;
}
/// Extract bytes from the initializer of the constant array V, which need
/// not be a nul-terminated string. On success, store the bytes in Str and
/// return true. When TrimAtNul is set, Str will contain only the bytes up
/// to but not including the first nul. Return false on failure.
bool llvm::getConstantStringInfo(const Value *V, StringRef &Str,
uint64_t Offset, bool TrimAtNul) {
ConstantDataArraySlice Slice;
if (!getConstantDataArrayInfo(V, Slice, 8, Offset))
return false;
if (Slice.Array == nullptr) {
if (TrimAtNul) {
// Return a nul-terminated string even for an empty Slice. This is
// safe because all existing SimplifyLibcalls callers require string
// arguments and the behavior of the functions they fold is undefined
// otherwise. Folding the calls this way is preferable to making
// the undefined library calls, even though it prevents sanitizers
// from reporting such calls.
Str = StringRef();
return true;
}
if (Slice.Length == 1) {
Str = StringRef("", 1);
return true;
}
// We cannot instantiate a StringRef as we do not have an appropriate string
// of 0s at hand.
return false;
}
// Start out with the entire array in the StringRef.
Str = Slice.Array->getAsString();
// Skip over 'offset' bytes.
Str = Str.substr(Slice.Offset);
if (TrimAtNul) {
// Trim off the \0 and anything after it. If the array is not nul
// terminated, we just return the whole end of string. The client may know
// some other way that the string is length-bound.
Str = Str.substr(0, Str.find('\0'));
}
return true;
}
// These next two are very similar to the above, but also look through PHI
// nodes.
// TODO: See if we can integrate these two together.
/// If we can compute the length of the string pointed to by
/// the specified pointer, return 'len+1'. If we can't, return 0.
static uint64_t GetStringLengthH(const Value *V,
SmallPtrSetImpl<const PHINode*> &PHIs,
unsigned CharSize) {
// Look through noop bitcast instructions.
V = V->stripPointerCasts();
// If this is a PHI node, there are two cases: either we have already seen it
// or we haven't.
if (const PHINode *PN = dyn_cast<PHINode>(V)) {
if (!PHIs.insert(PN).second)
return ~0ULL; // already in the set.
// If it was new, see if all the input strings are the same length.
uint64_t LenSoFar = ~0ULL;
for (Value *IncValue : PN->incoming_values()) {
uint64_t Len = GetStringLengthH(IncValue, PHIs, CharSize);
if (Len == 0) return 0; // Unknown length -> unknown.
if (Len == ~0ULL) continue;
if (Len != LenSoFar && LenSoFar != ~0ULL)
return 0; // Disagree -> unknown.
LenSoFar = Len;
}
// Success, all agree.
return LenSoFar;
}
// strlen(select(c,x,y)) -> strlen(x) ^ strlen(y)
if (const SelectInst *SI = dyn_cast<SelectInst>(V)) {
uint64_t Len1 = GetStringLengthH(SI->getTrueValue(), PHIs, CharSize);
if (Len1 == 0) return 0;
uint64_t Len2 = GetStringLengthH(SI->getFalseValue(), PHIs, CharSize);
if (Len2 == 0) return 0;
if (Len1 == ~0ULL) return Len2;
if (Len2 == ~0ULL) return Len1;
if (Len1 != Len2) return 0;
return Len1;
}
// Otherwise, see if we can read the string.
ConstantDataArraySlice Slice;
if (!getConstantDataArrayInfo(V, Slice, CharSize))
return 0;
if (Slice.Array == nullptr)
// Zeroinitializer (including an empty one).
return 1;
// Search for the first nul character. Return a conservative result even
// when there is no nul. This is safe since otherwise the string function
// being folded such as strlen is undefined, and can be preferable to
// making the undefined library call.
unsigned NullIndex = 0;
for (unsigned E = Slice.Length; NullIndex < E; ++NullIndex) {
if (Slice.Array->getElementAsInteger(Slice.Offset + NullIndex) == 0)
break;
}
return NullIndex + 1;
}
/// If we can compute the length of the string pointed to by
/// the specified pointer, return 'len+1'. If we can't, return 0.
uint64_t llvm::GetStringLength(const Value *V, unsigned CharSize) {
if (!V->getType()->isPointerTy())
return 0;
SmallPtrSet<const PHINode*, 32> PHIs;
uint64_t Len = GetStringLengthH(V, PHIs, CharSize);
// If Len is ~0ULL, we had an infinite phi cycle: this is dead code, so return
// an empty string as a length.
return Len == ~0ULL ? 1 : Len;
}
const Value *
llvm::getArgumentAliasingToReturnedPointer(const CallBase *Call,
bool MustPreserveNullness) {
assert(Call &&
"getArgumentAliasingToReturnedPointer only works on nonnull calls");
if (const Value *RV = Call->getReturnedArgOperand())
return RV;
// This can be used only as a aliasing property.
if (isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(
Call, MustPreserveNullness))
return Call->getArgOperand(0);
return nullptr;
}
bool llvm::isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(
const CallBase *Call, bool MustPreserveNullness) {
switch (Call->getIntrinsicID()) {
case Intrinsic::launder_invariant_group:
case Intrinsic::strip_invariant_group:
case Intrinsic::aarch64_irg:
case Intrinsic::aarch64_tagp:
return true;
case Intrinsic::ptrmask:
return !MustPreserveNullness;
default:
return false;
}
}
/// \p PN defines a loop-variant pointer to an object. Check if the
/// previous iteration of the loop was referring to the same object as \p PN.
static bool isSameUnderlyingObjectInLoop(const PHINode *PN,
const LoopInfo *LI) {
// Find the loop-defined value.
Loop *L = LI->getLoopFor(PN->getParent());
if (PN->getNumIncomingValues() != 2)
return true;
// Find the value from previous iteration.
auto *PrevValue = dyn_cast<Instruction>(PN->getIncomingValue(0));
if (!PrevValue || LI->getLoopFor(PrevValue->getParent()) != L)
PrevValue = dyn_cast<Instruction>(PN->getIncomingValue(1));
if (!PrevValue || LI->getLoopFor(PrevValue->getParent()) != L)
return true;
// If a new pointer is loaded in the loop, the pointer references a different
// object in every iteration. E.g.:
// for (i)
// int *p = a[i];
// ...
if (auto *Load = dyn_cast<LoadInst>(PrevValue))
if (!L->isLoopInvariant(Load->getPointerOperand()))
return false;
return true;
}
const Value *llvm::getUnderlyingObject(const Value *V, unsigned MaxLookup) {
if (!V->getType()->isPointerTy())
return V;
for (unsigned Count = 0; MaxLookup == 0 || Count < MaxLookup; ++Count) {
if (auto *GEP = dyn_cast<GEPOperator>(V)) {
V = GEP->getPointerOperand();
} else if (Operator::getOpcode(V) == Instruction::BitCast ||
Operator::getOpcode(V) == Instruction::AddrSpaceCast) {
V = cast<Operator>(V)->getOperand(0);
if (!V->getType()->isPointerTy())
return V;
} else if (auto *GA = dyn_cast<GlobalAlias>(V)) {
if (GA->isInterposable())
return V;
V = GA->getAliasee();
} else {
if (auto *PHI = dyn_cast<PHINode>(V)) {
// Look through single-arg phi nodes created by LCSSA.
if (PHI->getNumIncomingValues() == 1) {
V = PHI->getIncomingValue(0);
continue;
}
} else if (auto *Call = dyn_cast<CallBase>(V)) {
// CaptureTracking can know about special capturing properties of some
// intrinsics like launder.invariant.group, that can't be expressed with
// the attributes, but have properties like returning aliasing pointer.
// Because some analysis may assume that nocaptured pointer is not
// returned from some special intrinsic (because function would have to
// be marked with returns attribute), it is crucial to use this function
// because it should be in sync with CaptureTracking. Not using it may
// cause weird miscompilations where 2 aliasing pointers are assumed to
// noalias.
if (auto *RP = getArgumentAliasingToReturnedPointer(Call, false)) {
V = RP;
continue;
}
}
return V;
}
assert(V->getType()->isPointerTy() && "Unexpected operand type!");
}
return V;
}
void llvm::getUnderlyingObjects(const Value *V,
SmallVectorImpl<const Value *> &Objects,
LoopInfo *LI, unsigned MaxLookup) {
SmallPtrSet<const Value *, 4> Visited;
SmallVector<const Value *, 4> Worklist;
Worklist.push_back(V);
do {
const Value *P = Worklist.pop_back_val();
P = getUnderlyingObject(P, MaxLookup);
if (!Visited.insert(P).second)
continue;
if (auto *SI = dyn_cast<SelectInst>(P)) {
Worklist.push_back(SI->getTrueValue());
Worklist.push_back(SI->getFalseValue());
continue;
}
if (auto *PN = dyn_cast<PHINode>(P)) {
// If this PHI changes the underlying object in every iteration of the
// loop, don't look through it. Consider:
// int **A;
// for (i) {
// Prev = Curr; // Prev = PHI (Prev_0, Curr)
// Curr = A[i];
// *Prev, *Curr;
//
// Prev is tracking Curr one iteration behind so they refer to different
// underlying objects.
if (!LI || !LI->isLoopHeader(PN->getParent()) ||
isSameUnderlyingObjectInLoop(PN, LI))
append_range(Worklist, PN->incoming_values());
continue;
}
Objects.push_back(P);
} while (!Worklist.empty());
}
/// This is the function that does the work of looking through basic
/// ptrtoint+arithmetic+inttoptr sequences.
static const Value *getUnderlyingObjectFromInt(const Value *V) {
do {
if (const Operator *U = dyn_cast<Operator>(V)) {
// If we find a ptrtoint, we can transfer control back to the
// regular getUnderlyingObjectFromInt.
if (U->getOpcode() == Instruction::PtrToInt)
return U->getOperand(0);
// If we find an add of a constant, a multiplied value, or a phi, it's
// likely that the other operand will lead us to the base
// object. We don't have to worry about the case where the
// object address is somehow being computed by the multiply,
// because our callers only care when the result is an
// identifiable object.
if (U->getOpcode() != Instruction::Add ||
(!isa<ConstantInt>(U->getOperand(1)) &&
Operator::getOpcode(U->getOperand(1)) != Instruction::Mul &&
!isa<PHINode>(U->getOperand(1))))
return V;
V = U->getOperand(0);
} else {
return V;
}
assert(V->getType()->isIntegerTy() && "Unexpected operand type!");
} while (true);
}
/// This is a wrapper around getUnderlyingObjects and adds support for basic
/// ptrtoint+arithmetic+inttoptr sequences.
/// It returns false if unidentified object is found in getUnderlyingObjects.
bool llvm::getUnderlyingObjectsForCodeGen(const Value *V,
SmallVectorImpl<Value *> &Objects) {
SmallPtrSet<const Value *, 16> Visited;
SmallVector<const Value *, 4> Working(1, V);
do {
V = Working.pop_back_val();
SmallVector<const Value *, 4> Objs;
getUnderlyingObjects(V, Objs);
for (const Value *V : Objs) {
if (!Visited.insert(V).second)
continue;
if (Operator::getOpcode(V) == Instruction::IntToPtr) {
const Value *O =
getUnderlyingObjectFromInt(cast<User>(V)->getOperand(0));
if (O->getType()->isPointerTy()) {
Working.push_back(O);
continue;
}
}
// If getUnderlyingObjects fails to find an identifiable object,
// getUnderlyingObjectsForCodeGen also fails for safety.
if (!isIdentifiedObject(V)) {
Objects.clear();
return false;
}
Objects.push_back(const_cast<Value *>(V));
}
} while (!Working.empty());
return true;
}
AllocaInst *llvm::findAllocaForValue(Value *V, bool OffsetZero) {
AllocaInst *Result = nullptr;
SmallPtrSet<Value *, 4> Visited;
SmallVector<Value *, 4> Worklist;
auto AddWork = [&](Value *V) {
if (Visited.insert(V).second)
Worklist.push_back(V);
};
AddWork(V);
do {
V = Worklist.pop_back_val();
assert(Visited.count(V));
if (AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
if (Result && Result != AI)
return nullptr;
Result = AI;
} else if (CastInst *CI = dyn_cast<CastInst>(V)) {
AddWork(CI->getOperand(0));
} else if (PHINode *PN = dyn_cast<PHINode>(V)) {
for (Value *IncValue : PN->incoming_values())
AddWork(IncValue);
} else if (auto *SI = dyn_cast<SelectInst>(V)) {
AddWork(SI->getTrueValue());
AddWork(SI->getFalseValue());
} else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V)) {
if (OffsetZero && !GEP->hasAllZeroIndices())
return nullptr;
AddWork(GEP->getPointerOperand());
} else if (CallBase *CB = dyn_cast<CallBase>(V)) {
Value *Returned = CB->getReturnedArgOperand();
if (Returned)
AddWork(Returned);
else
return nullptr;
} else {
return nullptr;
}
} while (!Worklist.empty());
return Result;
}
static bool onlyUsedByLifetimeMarkersOrDroppableInstsHelper(
const Value *V, bool AllowLifetime, bool AllowDroppable) {
for (const User *U : V->users()) {
const IntrinsicInst *II = dyn_cast<IntrinsicInst>(U);
if (!II)
return false;
if (AllowLifetime && II->isLifetimeStartOrEnd())
continue;
if (AllowDroppable && II->isDroppable())
continue;
return false;
}
return true;
}
bool llvm::onlyUsedByLifetimeMarkers(const Value *V) {
return onlyUsedByLifetimeMarkersOrDroppableInstsHelper(
V, /* AllowLifetime */ true, /* AllowDroppable */ false);
}
bool llvm::onlyUsedByLifetimeMarkersOrDroppableInsts(const Value *V) {
return onlyUsedByLifetimeMarkersOrDroppableInstsHelper(
V, /* AllowLifetime */ true, /* AllowDroppable */ true);
}
bool llvm::mustSuppressSpeculation(const LoadInst &LI) {
if (!LI.isUnordered())
return true;
const Function &F = *LI.getFunction();
// Speculative load may create a race that did not exist in the source.
return F.hasFnAttribute(Attribute::SanitizeThread) ||
// Speculative load may load data from dirty regions.
F.hasFnAttribute(Attribute::SanitizeAddress) ||
F.hasFnAttribute(Attribute::SanitizeHWAddress);
}
bool llvm::isSafeToSpeculativelyExecute(const Instruction *Inst,
const Instruction *CtxI,
const DominatorTree *DT,
const TargetLibraryInfo *TLI) {
return isSafeToSpeculativelyExecuteWithOpcode(Inst->getOpcode(), Inst, CtxI,
DT, TLI);
}
bool llvm::isSafeToSpeculativelyExecuteWithOpcode(
unsigned Opcode, const Instruction *Inst, const Instruction *CtxI,
const DominatorTree *DT, const TargetLibraryInfo *TLI) {
#ifndef NDEBUG
if (Inst->getOpcode() != Opcode) {
// Check that the operands are actually compatible with the Opcode override.
auto hasEqualReturnAndLeadingOperandTypes =
[](const Instruction *Inst, unsigned NumLeadingOperands) {
if (Inst->getNumOperands() < NumLeadingOperands)
return false;
const Type *ExpectedType = Inst->getType();
for (unsigned ItOp = 0; ItOp < NumLeadingOperands; ++ItOp)
if (Inst->getOperand(ItOp)->getType() != ExpectedType)
return false;
return true;
};
assert(!Instruction::isBinaryOp(Opcode) ||
hasEqualReturnAndLeadingOperandTypes(Inst, 2));
assert(!Instruction::isUnaryOp(Opcode) ||
hasEqualReturnAndLeadingOperandTypes(Inst, 1));
}
#endif
switch (Opcode) {
default:
return true;
case Instruction::UDiv:
case Instruction::URem: {
// x / y is undefined if y == 0.
const APInt *V;
if (match(Inst->getOperand(1), m_APInt(V)))
return *V != 0;
return false;
}
case Instruction::SDiv:
case Instruction::SRem: {
// x / y is undefined if y == 0 or x == INT_MIN and y == -1
const APInt *Numerator, *Denominator;
if (!match(Inst->getOperand(1), m_APInt(Denominator)))
return false;
// We cannot hoist this division if the denominator is 0.
if (*Denominator == 0)
return false;
// It's safe to hoist if the denominator is not 0 or -1.
if (!Denominator->isAllOnes())
return true;
// At this point we know that the denominator is -1. It is safe to hoist as
// long we know that the numerator is not INT_MIN.
if (match(Inst->getOperand(0), m_APInt(Numerator)))
return !Numerator->isMinSignedValue();
// The numerator *might* be MinSignedValue.
return false;
}
case Instruction::Load: {
const LoadInst *LI = dyn_cast<LoadInst>(Inst);
if (!LI)
return false;
if (mustSuppressSpeculation(*LI))
return false;
const DataLayout &DL = LI->getModule()->getDataLayout();
return isDereferenceableAndAlignedPointer(
LI->getPointerOperand(), LI->getType(), LI->getAlign(), DL, CtxI, DT,
TLI);
}
case Instruction::Call: {
auto *CI = dyn_cast<const CallInst>(Inst);
if (!CI)
return false;
const Function *Callee = CI->getCalledFunction();
// The called function could have undefined behavior or side-effects, even
// if marked readnone nounwind.
return Callee && Callee->isSpeculatable();
}
case Instruction::VAArg:
case Instruction::Alloca:
case Instruction::Invoke:
case Instruction::CallBr:
case Instruction::PHI:
case Instruction::Store:
case Instruction::Ret:
case Instruction::Br:
case Instruction::IndirectBr:
case Instruction::Switch:
case Instruction::Unreachable:
case Instruction::Fence:
case Instruction::AtomicRMW:
case Instruction::AtomicCmpXchg:
case Instruction::LandingPad:
case Instruction::Resume:
case Instruction::CatchSwitch:
case Instruction::CatchPad:
case Instruction::CatchRet:
case Instruction::CleanupPad:
case Instruction::CleanupRet:
return false; // Misc instructions which have effects
}
}
bool llvm::mayHaveNonDefUseDependency(const Instruction &I) {
if (I.mayReadOrWriteMemory())
// Memory dependency possible
return true;
if (!isSafeToSpeculativelyExecute(&I))
// Can't move above a maythrow call or infinite loop. Or if an
// inalloca alloca, above a stacksave call.
return true;
if (!isGuaranteedToTransferExecutionToSuccessor(&I))
// 1) Can't reorder two inf-loop calls, even if readonly
// 2) Also can't reorder an inf-loop call below a instruction which isn't
// safe to speculative execute. (Inverse of above)
return true;
return false;
}
/// Convert ConstantRange OverflowResult into ValueTracking OverflowResult.
static OverflowResult mapOverflowResult(ConstantRange::OverflowResult OR) {
switch (OR) {
case ConstantRange::OverflowResult::MayOverflow:
return OverflowResult::MayOverflow;
case ConstantRange::OverflowResult::AlwaysOverflowsLow:
return OverflowResult::AlwaysOverflowsLow;
case ConstantRange::OverflowResult::AlwaysOverflowsHigh:
return OverflowResult::AlwaysOverflowsHigh;
case ConstantRange::OverflowResult::NeverOverflows:
return OverflowResult::NeverOverflows;
}
llvm_unreachable("Unknown OverflowResult");
}
/// Combine constant ranges from computeConstantRange() and computeKnownBits().
static ConstantRange computeConstantRangeIncludingKnownBits(
const Value *V, bool ForSigned, const DataLayout &DL, unsigned Depth,
AssumptionCache *AC, const Instruction *CxtI, const DominatorTree *DT,
OptimizationRemarkEmitter *ORE = nullptr, bool UseInstrInfo = true) {
KnownBits Known = computeKnownBits(
V, DL, Depth, AC, CxtI, DT, ORE, UseInstrInfo);
ConstantRange CR1 = ConstantRange::fromKnownBits(Known, ForSigned);
ConstantRange CR2 = computeConstantRange(V, UseInstrInfo);
ConstantRange::PreferredRangeType RangeType =
ForSigned ? ConstantRange::Signed : ConstantRange::Unsigned;
return CR1.intersectWith(CR2, RangeType);
}
OverflowResult llvm::computeOverflowForUnsignedMul(
const Value *LHS, const Value *RHS, const DataLayout &DL,
AssumptionCache *AC, const Instruction *CxtI, const DominatorTree *DT,
bool UseInstrInfo) {
KnownBits LHSKnown = computeKnownBits(LHS, DL, /*Depth=*/0, AC, CxtI, DT,
nullptr, UseInstrInfo);
KnownBits RHSKnown = computeKnownBits(RHS, DL, /*Depth=*/0, AC, CxtI, DT,
nullptr, UseInstrInfo);
ConstantRange LHSRange = ConstantRange::fromKnownBits(LHSKnown, false);
ConstantRange RHSRange = ConstantRange::fromKnownBits(RHSKnown, false);
return mapOverflowResult(LHSRange.unsignedMulMayOverflow(RHSRange));
}
OverflowResult
llvm::computeOverflowForSignedMul(const Value *LHS, const Value *RHS,
const DataLayout &DL, AssumptionCache *AC,
const Instruction *CxtI,
const DominatorTree *DT, bool UseInstrInfo) {
// Multiplying n * m significant bits yields a result of n + m significant
// bits. If the total number of significant bits does not exceed the
// result bit width (minus 1), there is no overflow.
// This means if we have enough leading sign bits in the operands
// we can guarantee that the result does not overflow.
// Ref: "Hacker's Delight" by Henry Warren
unsigned BitWidth = LHS->getType()->getScalarSizeInBits();
// Note that underestimating the number of sign bits gives a more
// conservative answer.
unsigned SignBits = ComputeNumSignBits(LHS, DL, 0, AC, CxtI, DT) +
ComputeNumSignBits(RHS, DL, 0, AC, CxtI, DT);
// First handle the easy case: if we have enough sign bits there's
// definitely no overflow.
if (SignBits > BitWidth + 1)
return OverflowResult::NeverOverflows;
// There are two ambiguous cases where there can be no overflow:
// SignBits == BitWidth + 1 and
// SignBits == BitWidth
// The second case is difficult to check, therefore we only handle the
// first case.
if (SignBits == BitWidth + 1) {
// It overflows only when both arguments are negative and the true
// product is exactly the minimum negative number.
// E.g. mul i16 with 17 sign bits: 0xff00 * 0xff80 = 0x8000
// For simplicity we just check if at least one side is not negative.
KnownBits LHSKnown = computeKnownBits(LHS, DL, /*Depth=*/0, AC, CxtI, DT,
nullptr, UseInstrInfo);
KnownBits RHSKnown = computeKnownBits(RHS, DL, /*Depth=*/0, AC, CxtI, DT,
nullptr, UseInstrInfo);
if (LHSKnown.isNonNegative() || RHSKnown.isNonNegative())
return OverflowResult::NeverOverflows;
}
return OverflowResult::MayOverflow;
}
OverflowResult llvm::computeOverflowForUnsignedAdd(
const Value *LHS, const Value *RHS, const DataLayout &DL,
AssumptionCache *AC, const Instruction *CxtI, const DominatorTree *DT,
bool UseInstrInfo) {
ConstantRange LHSRange = computeConstantRangeIncludingKnownBits(
LHS, /*ForSigned=*/false, DL, /*Depth=*/0, AC, CxtI, DT,
nullptr, UseInstrInfo);
ConstantRange RHSRange = computeConstantRangeIncludingKnownBits(
RHS, /*ForSigned=*/false, DL, /*Depth=*/0, AC, CxtI, DT,
nullptr, UseInstrInfo);
return mapOverflowResult(LHSRange.unsignedAddMayOverflow(RHSRange));
}
static OverflowResult computeOverflowForSignedAdd(const Value *LHS,
const Value *RHS,
const AddOperator *Add,
const DataLayout &DL,
AssumptionCache *AC,
const Instruction *CxtI,
const DominatorTree *DT) {
if (Add && Add->hasNoSignedWrap()) {
return OverflowResult::NeverOverflows;
}
// If LHS and RHS each have at least two sign bits, the addition will look
// like
//
// XX..... +
// YY.....
//
// If the carry into the most significant position is 0, X and Y can't both
// be 1 and therefore the carry out of the addition is also 0.
//
// If the carry into the most significant position is 1, X and Y can't both
// be 0 and therefore the carry out of the addition is also 1.
//
// Since the carry into the most significant position is always equal to
// the carry out of the addition, there is no signed overflow.
if (ComputeNumSignBits(LHS, DL, 0, AC, CxtI, DT) > 1 &&
ComputeNumSignBits(RHS, DL, 0, AC, CxtI, DT) > 1)
return OverflowResult::NeverOverflows;
ConstantRange LHSRange = computeConstantRangeIncludingKnownBits(
LHS, /*ForSigned=*/true, DL, /*Depth=*/0, AC, CxtI, DT);
ConstantRange RHSRange = computeConstantRangeIncludingKnownBits(
RHS, /*ForSigned=*/true, DL, /*Depth=*/0, AC, CxtI, DT);
OverflowResult OR =
mapOverflowResult(LHSRange.signedAddMayOverflow(RHSRange));
if (OR != OverflowResult::MayOverflow)
return OR;
// The remaining code needs Add to be available. Early returns if not so.
if (!Add)
return OverflowResult::MayOverflow;
// If the sign of Add is the same as at least one of the operands, this add
// CANNOT overflow. If this can be determined from the known bits of the
// operands the above signedAddMayOverflow() check will have already done so.
// The only other way to improve on the known bits is from an assumption, so
// call computeKnownBitsFromAssume() directly.
bool LHSOrRHSKnownNonNegative =
(LHSRange.isAllNonNegative() || RHSRange.isAllNonNegative());
bool LHSOrRHSKnownNegative =
(LHSRange.isAllNegative() || RHSRange.isAllNegative());
if (LHSOrRHSKnownNonNegative || LHSOrRHSKnownNegative) {
KnownBits AddKnown(LHSRange.getBitWidth());
computeKnownBitsFromAssume(
Add, AddKnown, /*Depth=*/0, Query(DL, AC, CxtI, DT, true));
if ((AddKnown.isNonNegative() && LHSOrRHSKnownNonNegative) ||
(AddKnown.isNegative() && LHSOrRHSKnownNegative))
return OverflowResult::NeverOverflows;
}
return OverflowResult::MayOverflow;
}
OverflowResult llvm::computeOverflowForUnsignedSub(const Value *LHS,
const Value *RHS,
const DataLayout &DL,
AssumptionCache *AC,
const Instruction *CxtI,
const DominatorTree *DT) {
// X - (X % ?)
// The remainder of a value can't have greater magnitude than itself,
// so the subtraction can't overflow.
// X - (X -nuw ?)
// In the minimal case, this would simplify to "?", so there's no subtract
// at all. But if this analysis is used to peek through casts, for example,
// then determining no-overflow may allow other transforms.
// TODO: There are other patterns like this.
// See simplifyICmpWithBinOpOnLHS() for candidates.
if (match(RHS, m_URem(m_Specific(LHS), m_Value())) ||
match(RHS, m_NUWSub(m_Specific(LHS), m_Value())))
if (isGuaranteedNotToBeUndefOrPoison(LHS, AC, CxtI, DT))
return OverflowResult::NeverOverflows;
// Checking for conditions implied by dominating conditions may be expensive.
// Limit it to usub_with_overflow calls for now.
if (match(CxtI,
m_Intrinsic<Intrinsic::usub_with_overflow>(m_Value(), m_Value())))
if (auto C =
isImpliedByDomCondition(CmpInst::ICMP_UGE, LHS, RHS, CxtI, DL)) {
if (*C)
return OverflowResult::NeverOverflows;
return OverflowResult::AlwaysOverflowsLow;
}
ConstantRange LHSRange = computeConstantRangeIncludingKnownBits(
LHS, /*ForSigned=*/false, DL, /*Depth=*/0, AC, CxtI, DT);
ConstantRange RHSRange = computeConstantRangeIncludingKnownBits(
RHS, /*ForSigned=*/false, DL, /*Depth=*/0, AC, CxtI, DT);
return mapOverflowResult(LHSRange.unsignedSubMayOverflow(RHSRange));
}
OverflowResult llvm::computeOverflowForSignedSub(const Value *LHS,
const Value *RHS,
const DataLayout &DL,
AssumptionCache *AC,
const Instruction *CxtI,
const DominatorTree *DT) {
// X - (X % ?)
// The remainder of a value can't have greater magnitude than itself,
// so the subtraction can't overflow.
// X - (X -nsw ?)
// In the minimal case, this would simplify to "?", so there's no subtract
// at all. But if this analysis is used to peek through casts, for example,
// then determining no-overflow may allow other transforms.
if (match(RHS, m_SRem(m_Specific(LHS), m_Value())) ||
match(RHS, m_NSWSub(m_Specific(LHS), m_Value())))
if (isGuaranteedNotToBeUndefOrPoison(LHS, AC, CxtI, DT))
return OverflowResult::NeverOverflows;
// If LHS and RHS each have at least two sign bits, the subtraction
// cannot overflow.
if (ComputeNumSignBits(LHS, DL, 0, AC, CxtI, DT) > 1 &&
ComputeNumSignBits(RHS, DL, 0, AC, CxtI, DT) > 1)
return OverflowResult::NeverOverflows;
ConstantRange LHSRange = computeConstantRangeIncludingKnownBits(
LHS, /*ForSigned=*/true, DL, /*Depth=*/0, AC, CxtI, DT);
ConstantRange RHSRange = computeConstantRangeIncludingKnownBits(
RHS, /*ForSigned=*/true, DL, /*Depth=*/0, AC, CxtI, DT);
return mapOverflowResult(LHSRange.signedSubMayOverflow(RHSRange));
}
bool llvm::isOverflowIntrinsicNoWrap(const WithOverflowInst *WO,
const DominatorTree &DT) {
SmallVector<const BranchInst *, 2> GuardingBranches;
SmallVector<const ExtractValueInst *, 2> Results;
for (const User *U : WO->users()) {
if (const auto *EVI = dyn_cast<ExtractValueInst>(U)) {
assert(EVI->getNumIndices() == 1 && "Obvious from CI's type");
if (EVI->getIndices()[0] == 0)
Results.push_back(EVI);
else {
assert(EVI->getIndices()[0] == 1 && "Obvious from CI's type");
for (const auto *U : EVI->users())
if (const auto *B = dyn_cast<BranchInst>(U)) {
assert(B->isConditional() && "How else is it using an i1?");
GuardingBranches.push_back(B);
}
}
} else {
// We are using the aggregate directly in a way we don't want to analyze
// here (storing it to a global, say).
return false;
}
}
auto AllUsesGuardedByBranch = [&](const BranchInst *BI) {
BasicBlockEdge NoWrapEdge(BI->getParent(), BI->getSuccessor(1));
if (!NoWrapEdge.isSingleEdge())
return false;
// Check if all users of the add are provably no-wrap.
for (const auto *Result : Results) {
// If the extractvalue itself is not executed on overflow, the we don't
// need to check each use separately, since domination is transitive.
if (DT.dominates(NoWrapEdge, Result->getParent()))
continue;
for (const auto &RU : Result->uses())
if (!DT.dominates(NoWrapEdge, RU))
return false;
}
return true;
};
return llvm::any_of(GuardingBranches, AllUsesGuardedByBranch);
}
static bool canCreateUndefOrPoison(const Operator *Op, bool PoisonOnly,
bool ConsiderFlags) {
if (ConsiderFlags && Op->hasPoisonGeneratingFlags())
return true;
unsigned Opcode = Op->getOpcode();
// Check whether opcode is a poison/undef-generating operation
switch (Opcode) {
case Instruction::Shl:
case Instruction::AShr:
case Instruction::LShr: {
// Shifts return poison if shiftwidth is larger than the bitwidth.
if (auto *C = dyn_cast<Constant>(Op->getOperand(1))) {
SmallVector<Constant *, 4> ShiftAmounts;
if (auto *FVTy = dyn_cast<FixedVectorType>(C->getType())) {
unsigned NumElts = FVTy->getNumElements();
for (unsigned i = 0; i < NumElts; ++i)
ShiftAmounts.push_back(C->getAggregateElement(i));
} else if (isa<ScalableVectorType>(C->getType()))
return true; // Can't tell, just return true to be safe
else
ShiftAmounts.push_back(C);
bool Safe = llvm::all_of(ShiftAmounts, [](Constant *C) {
auto *CI = dyn_cast_or_null<ConstantInt>(C);
return CI && CI->getValue().ult(C->getType()->getIntegerBitWidth());
});
return !Safe;
}
return true;
}
case Instruction::FPToSI:
case Instruction::FPToUI:
// fptosi/ui yields poison if the resulting value does not fit in the
// destination type.
return true;
case Instruction::Call:
if (auto *II = dyn_cast<IntrinsicInst>(Op)) {
switch (II->getIntrinsicID()) {
// TODO: Add more intrinsics.
case Intrinsic::ctpop:
case Intrinsic::sadd_with_overflow:
case Intrinsic::ssub_with_overflow:
case Intrinsic::smul_with_overflow:
case Intrinsic::uadd_with_overflow:
case Intrinsic::usub_with_overflow:
case Intrinsic::umul_with_overflow:
return false;
}
}
LLVM_FALLTHROUGH;
case Instruction::CallBr:
case Instruction::Invoke: {
const auto *CB = cast<CallBase>(Op);
return !CB->hasRetAttr(Attribute::NoUndef);
}
case Instruction::InsertElement:
case Instruction::ExtractElement: {
// If index exceeds the length of the vector, it returns poison
auto *VTy = cast<VectorType>(Op->getOperand(0)->getType());
unsigned IdxOp = Op->getOpcode() == Instruction::InsertElement ? 2 : 1;
auto *Idx = dyn_cast<ConstantInt>(Op->getOperand(IdxOp));
if (!Idx || Idx->getValue().uge(VTy->getElementCount().getKnownMinValue()))
return true;
return false;
}
case Instruction::ShuffleVector: {
// shufflevector may return undef.
if (PoisonOnly)
return false;
ArrayRef<int> Mask = isa<ConstantExpr>(Op)
? cast<ConstantExpr>(Op)->getShuffleMask()
: cast<ShuffleVectorInst>(Op)->getShuffleMask();
return is_contained(Mask, UndefMaskElem);
}
case Instruction::FNeg:
case Instruction::PHI:
case Instruction::Select:
case Instruction::URem:
case Instruction::SRem:
case Instruction::ExtractValue:
case Instruction::InsertValue:
case Instruction::Freeze:
case Instruction::ICmp:
case Instruction::FCmp:
return false;
case Instruction::GetElementPtr:
// inbounds is handled above
// TODO: what about inrange on constexpr?
return false;
default: {
const auto *CE = dyn_cast<ConstantExpr>(Op);
if (isa<CastInst>(Op) || (CE && CE->isCast()))
return false;
else if (Instruction::isBinaryOp(Opcode))
return false;
// Be conservative and return true.
return true;
}
}
}
bool llvm::canCreateUndefOrPoison(const Operator *Op, bool ConsiderFlags) {
return ::canCreateUndefOrPoison(Op, /*PoisonOnly=*/false, ConsiderFlags);
}
bool llvm::canCreatePoison(const Operator *Op, bool ConsiderFlags) {
return ::canCreateUndefOrPoison(Op, /*PoisonOnly=*/true, ConsiderFlags);
}
static bool directlyImpliesPoison(const Value *ValAssumedPoison,
const Value *V, unsigned Depth) {
if (ValAssumedPoison == V)
return true;
const unsigned MaxDepth = 2;
if (Depth >= MaxDepth)
return false;
if (const auto *I = dyn_cast<Instruction>(V)) {
if (propagatesPoison(cast<Operator>(I)))
return any_of(I->operands(), [=](const Value *Op) {
return directlyImpliesPoison(ValAssumedPoison, Op, Depth + 1);
});
// 'select ValAssumedPoison, _, _' is poison.
if (const auto *SI = dyn_cast<SelectInst>(I))
return directlyImpliesPoison(ValAssumedPoison, SI->getCondition(),
Depth + 1);
// V = extractvalue V0, idx
// V2 = extractvalue V0, idx2
// V0's elements are all poison or not. (e.g., add_with_overflow)
const WithOverflowInst *II;
if (match(I, m_ExtractValue(m_WithOverflowInst(II))) &&
(match(ValAssumedPoison, m_ExtractValue(m_Specific(II))) ||
llvm::is_contained(II->args(), ValAssumedPoison)))
return true;
}
return false;
}
static bool impliesPoison(const Value *ValAssumedPoison, const Value *V,
unsigned Depth) {
if (isGuaranteedNotToBeUndefOrPoison(ValAssumedPoison))
return true;
if (directlyImpliesPoison(ValAssumedPoison, V, /* Depth */ 0))
return true;
const unsigned MaxDepth = 2;
if (Depth >= MaxDepth)
return false;
const auto *I = dyn_cast<Instruction>(ValAssumedPoison);
if (I && !canCreatePoison(cast<Operator>(I))) {
return all_of(I->operands(), [=](const Value *Op) {
return impliesPoison(Op, V, Depth + 1);
});
}
return false;
}
bool llvm::impliesPoison(const Value *ValAssumedPoison, const Value *V) {
return ::impliesPoison(ValAssumedPoison, V, /* Depth */ 0);
}
static bool programUndefinedIfUndefOrPoison(const Value *V,
bool PoisonOnly);
static bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
AssumptionCache *AC,
const Instruction *CtxI,
const DominatorTree *DT,
unsigned Depth, bool PoisonOnly) {
if (Depth >= MaxAnalysisRecursionDepth)
return false;
if (isa<MetadataAsValue>(V))
return false;
if (const auto *A = dyn_cast<Argument>(V)) {
if (A->hasAttribute(Attribute::NoUndef))
return true;
}
if (auto *C = dyn_cast<Constant>(V)) {
if (isa<UndefValue>(C))
return PoisonOnly && !isa<PoisonValue>(C);
if (isa<ConstantInt>(C) || isa<GlobalVariable>(C) || isa<ConstantFP>(V) ||
isa<ConstantPointerNull>(C) || isa<Function>(C))
return true;
if (C->getType()->isVectorTy() && !isa<ConstantExpr>(C))
return (PoisonOnly ? !C->containsPoisonElement()
: !C->containsUndefOrPoisonElement()) &&
!C->containsConstantExpression();
}
// Strip cast operations from a pointer value.
// Note that stripPointerCastsSameRepresentation can strip off getelementptr
// inbounds with zero offset. To guarantee that the result isn't poison, the
// stripped pointer is checked as it has to be pointing into an allocated
// object or be null `null` to ensure `inbounds` getelement pointers with a
// zero offset could not produce poison.
// It can strip off addrspacecast that do not change bit representation as
// well. We believe that such addrspacecast is equivalent to no-op.
auto *StrippedV = V->stripPointerCastsSameRepresentation();
if (isa<AllocaInst>(StrippedV) || isa<GlobalVariable>(StrippedV) ||
isa<Function>(StrippedV) || isa<ConstantPointerNull>(StrippedV))
return true;
auto OpCheck = [&](const Value *V) {
return isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth + 1,
PoisonOnly);
};
if (auto *Opr = dyn_cast<Operator>(V)) {
// If the value is a freeze instruction, then it can never
// be undef or poison.
if (isa<FreezeInst>(V))
return true;
if (const auto *CB = dyn_cast<CallBase>(V)) {
if (CB->hasRetAttr(Attribute::NoUndef))
return true;
}
if (const auto *PN = dyn_cast<PHINode>(V)) {
unsigned Num = PN->getNumIncomingValues();
bool IsWellDefined = true;
for (unsigned i = 0; i < Num; ++i) {
auto *TI = PN->getIncomingBlock(i)->getTerminator();
if (!isGuaranteedNotToBeUndefOrPoison(PN->getIncomingValue(i), AC, TI,
DT, Depth + 1, PoisonOnly)) {
IsWellDefined = false;
break;
}
}
if (IsWellDefined)
return true;
} else if (!canCreateUndefOrPoison(Opr) && all_of(Opr->operands(), OpCheck))
return true;
}
if (auto *I = dyn_cast<LoadInst>(V))
if (I->hasMetadata(LLVMContext::MD_noundef) ||
I->hasMetadata(LLVMContext::MD_dereferenceable) ||
I->hasMetadata(LLVMContext::MD_dereferenceable_or_null))
return true;
if (programUndefinedIfUndefOrPoison(V, PoisonOnly))
return true;
// CxtI may be null or a cloned instruction.
if (!CtxI || !CtxI->getParent() || !DT)
return false;
auto *DNode = DT->getNode(CtxI->getParent());
if (!DNode)
// Unreachable block
return false;
// If V is used as a branch condition before reaching CtxI, V cannot be
// undef or poison.
// br V, BB1, BB2
// BB1:
// CtxI ; V cannot be undef or poison here
auto *Dominator = DNode->getIDom();
while (Dominator) {
auto *TI = Dominator->getBlock()->getTerminator();
Value *Cond = nullptr;
if (auto BI = dyn_cast_or_null<BranchInst>(TI)) {
if (BI->isConditional())
Cond = BI->getCondition();
} else if (auto SI = dyn_cast_or_null<SwitchInst>(TI)) {
Cond = SI->getCondition();
}
if (Cond) {
if (Cond == V)
return true;
else if (PoisonOnly && isa<Operator>(Cond)) {
// For poison, we can analyze further
auto *Opr = cast<Operator>(Cond);
if (propagatesPoison(Opr) && is_contained(Opr->operand_values(), V))
return true;
}
}
Dominator = Dominator->getIDom();
}
if (getKnowledgeValidInContext(V, {Attribute::NoUndef}, CtxI, DT, AC))
return true;
return false;
}
bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC,
const Instruction *CtxI,
const DominatorTree *DT,
unsigned Depth) {
return ::isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth, false);
}
bool llvm::isGuaranteedNotToBePoison(const Value *V, AssumptionCache *AC,
const Instruction *CtxI,
const DominatorTree *DT, unsigned Depth) {
return ::isGuaranteedNotToBeUndefOrPoison(V, AC, CtxI, DT, Depth, true);
}
OverflowResult llvm::computeOverflowForSignedAdd(const AddOperator *Add,
const DataLayout &DL,
AssumptionCache *AC,
const Instruction *CxtI,
const DominatorTree *DT) {
return ::computeOverflowForSignedAdd(Add->getOperand(0), Add->getOperand(1),
Add, DL, AC, CxtI, DT);
}
OverflowResult llvm::computeOverflowForSignedAdd(const Value *LHS,
const Value *RHS,
const DataLayout &DL,
AssumptionCache *AC,
const Instruction *CxtI,
const DominatorTree *DT) {
return ::computeOverflowForSignedAdd(LHS, RHS, nullptr, DL, AC, CxtI, DT);
}
bool llvm::isGuaranteedToTransferExecutionToSuccessor(const Instruction *I) {
// Note: An atomic operation isn't guaranteed to return in a reasonable amount
// of time because it's possible for another thread to interfere with it for an
// arbitrary length of time, but programs aren't allowed to rely on that.
// If there is no successor, then execution can't transfer to it.
if (isa<ReturnInst>(I))
return false;
if (isa<UnreachableInst>(I))
return false;
// Note: Do not add new checks here; instead, change Instruction::mayThrow or
// Instruction::willReturn.
//
// FIXME: Move this check into Instruction::willReturn.
if (isa<CatchPadInst>(I)) {
switch (classifyEHPersonality(I->getFunction()->getPersonalityFn())) {
default:
// A catchpad may invoke exception object constructors and such, which
// in some languages can be arbitrary code, so be conservative by default.
return false;
case EHPersonality::CoreCLR:
// For CoreCLR, it just involves a type test.
return true;
}
}
// An instruction that returns without throwing must transfer control flow
// to a successor.
return !I->mayThrow() && I->willReturn();
}
bool llvm::isGuaranteedToTransferExecutionToSuccessor(const BasicBlock *BB) {
// TODO: This is slightly conservative for invoke instruction since exiting
// via an exception *is* normal control for them.
for (const Instruction &I : *BB)
if (!isGuaranteedToTransferExecutionToSuccessor(&I))
return false;
return true;
}
bool llvm::isGuaranteedToTransferExecutionToSuccessor(
BasicBlock::const_iterator Begin, BasicBlock::const_iterator End,
unsigned ScanLimit) {
return isGuaranteedToTransferExecutionToSuccessor(make_range(Begin, End),
ScanLimit);
}
bool llvm::isGuaranteedToTransferExecutionToSuccessor(
iterator_range<BasicBlock::const_iterator> Range, unsigned ScanLimit) {
assert(ScanLimit && "scan limit must be non-zero");
for (const Instruction &I : Range) {
if (isa<DbgInfoIntrinsic>(I))
continue;
if (--ScanLimit == 0)
return false;
if (!isGuaranteedToTransferExecutionToSuccessor(&I))
return false;
}
return true;
}
bool llvm::isGuaranteedToExecuteForEveryIteration(const Instruction *I,
const Loop *L) {
// The loop header is guaranteed to be executed for every iteration.
//
// FIXME: Relax this constraint to cover all basic blocks that are
// guaranteed to be executed at every iteration.
if (I->getParent() != L->getHeader()) return false;
for (const Instruction &LI : *L->getHeader()) {
if (&LI == I) return true;
if (!isGuaranteedToTransferExecutionToSuccessor(&LI)) return false;
}
llvm_unreachable("Instruction not contained in its own parent basic block.");
}
bool llvm::propagatesPoison(const Operator *I) {
switch (I->getOpcode()) {
case Instruction::Freeze:
case Instruction::Select:
case Instruction::PHI:
case Instruction::Invoke:
return false;
case Instruction::Call:
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
switch (II->getIntrinsicID()) {
// TODO: Add more intrinsics.
case Intrinsic::sadd_with_overflow:
case Intrinsic::ssub_with_overflow:
case Intrinsic::smul_with_overflow:
case Intrinsic::uadd_with_overflow:
case Intrinsic::usub_with_overflow:
case Intrinsic::umul_with_overflow:
// If an input is a vector containing a poison element, the
// two output vectors (calculated results, overflow bits)'
// corresponding lanes are poison.
return true;
case Intrinsic::ctpop:
return true;
}
}
return false;
case Instruction::ICmp:
case Instruction::FCmp:
case Instruction::GetElementPtr:
return true;
default:
if (isa<BinaryOperator>(I) || isa<UnaryOperator>(I) || isa<CastInst>(I))
return true;
// Be conservative and return false.
return false;
}
}
void llvm::getGuaranteedWellDefinedOps(
const Instruction *I, SmallPtrSetImpl<const Value *> &Operands) {
switch (I->getOpcode()) {
case Instruction::Store:
Operands.insert(cast<StoreInst>(I)->getPointerOperand());
break;
case Instruction::Load:
Operands.insert(cast<LoadInst>(I)->getPointerOperand());
break;
// Since dereferenceable attribute imply noundef, atomic operations
// also implicitly have noundef pointers too
case Instruction::AtomicCmpXchg:
Operands.insert(cast<AtomicCmpXchgInst>(I)->getPointerOperand());
break;
case Instruction::AtomicRMW:
Operands.insert(cast<AtomicRMWInst>(I)->getPointerOperand());
break;
case Instruction::Call:
case Instruction::Invoke: {
const CallBase *CB = cast<CallBase>(I);
if (CB->isIndirectCall())
Operands.insert(CB->getCalledOperand());
for (unsigned i = 0; i < CB->arg_size(); ++i) {
if (CB->paramHasAttr(i, Attribute::NoUndef) ||
CB->paramHasAttr(i, Attribute::Dereferenceable))
Operands.insert(CB->getArgOperand(i));
}
break;
}
case Instruction::Ret:
if (I->getFunction()->hasRetAttribute(Attribute::NoUndef))
Operands.insert(I->getOperand(0));
break;
default:
break;
}
}
void llvm::getGuaranteedNonPoisonOps(const Instruction *I,
SmallPtrSetImpl<const Value *> &Operands) {
getGuaranteedWellDefinedOps(I, Operands);
switch (I->getOpcode()) {
// Divisors of these operations are allowed to be partially undef.
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::URem:
case Instruction::SRem:
Operands.insert(I->getOperand(1));
break;
case Instruction::Switch:
if (BranchOnPoisonAsUB)
Operands.insert(cast<SwitchInst>(I)->getCondition());
break;
case Instruction::Br: {
auto *BR = cast<BranchInst>(I);
if (BranchOnPoisonAsUB && BR->isConditional())
Operands.insert(BR->getCondition());
break;
}
default:
break;
}
}
bool llvm::mustTriggerUB(const Instruction *I,
const SmallSet<const Value *, 16>& KnownPoison) {
SmallPtrSet<const Value *, 4> NonPoisonOps;
getGuaranteedNonPoisonOps(I, NonPoisonOps);
for (const auto *V : NonPoisonOps)
if (KnownPoison.count(V))
return true;
return false;
}
static bool programUndefinedIfUndefOrPoison(const Value *V,
bool PoisonOnly) {
// We currently only look for uses of values within the same basic
// block, as that makes it easier to guarantee that the uses will be
// executed given that Inst is executed.
//
// FIXME: Expand this to consider uses beyond the same basic block. To do
// this, look out for the distinction between post-dominance and strong
// post-dominance.
const BasicBlock *BB = nullptr;
BasicBlock::const_iterator Begin;
if (const auto *Inst = dyn_cast<Instruction>(V)) {
BB = Inst->getParent();
Begin = Inst->getIterator();
Begin++;
} else if (const auto *Arg = dyn_cast<Argument>(V)) {
BB = &Arg->getParent()->getEntryBlock();
Begin = BB->begin();
} else {
return false;
}
// Limit number of instructions we look at, to avoid scanning through large
// blocks. The current limit is chosen arbitrarily.
unsigned ScanLimit = 32;
BasicBlock::const_iterator End = BB->end();
if (!PoisonOnly) {
// Since undef does not propagate eagerly, be conservative & just check
// whether a value is directly passed to an instruction that must take
// well-defined operands.
for (const auto &I : make_range(Begin, End)) {
if (isa<DbgInfoIntrinsic>(I))
continue;
if (--ScanLimit == 0)
break;
SmallPtrSet<const Value *, 4> WellDefinedOps;
getGuaranteedWellDefinedOps(&I, WellDefinedOps);
if (WellDefinedOps.contains(V))
return true;
if (!isGuaranteedToTransferExecutionToSuccessor(&I))
break;
}
return false;
}
// Set of instructions that we have proved will yield poison if Inst
// does.
SmallSet<const Value *, 16> YieldsPoison;
SmallSet<const BasicBlock *, 4> Visited;
YieldsPoison.insert(V);
auto Propagate = [&](const User *User) {
if (propagatesPoison(cast<Operator>(User)))
YieldsPoison.insert(User);
};
for_each(V->users(), Propagate);
Visited.insert(BB);
while (true) {
for (const auto &I : make_range(Begin, End)) {
if (isa<DbgInfoIntrinsic>(I))
continue;
if (--ScanLimit == 0)
return false;
if (mustTriggerUB(&I, YieldsPoison))
return true;
if (!isGuaranteedToTransferExecutionToSuccessor(&I))
return false;
// Mark poison that propagates from I through uses of I.
if (YieldsPoison.count(&I))
for_each(I.users(), Propagate);
}
BB = BB->getSingleSuccessor();
if (!BB || !Visited.insert(BB).second)
break;
Begin = BB->getFirstNonPHI()->getIterator();
End = BB->end();
}
return false;
}
bool llvm::programUndefinedIfUndefOrPoison(const Instruction *Inst) {
return ::programUndefinedIfUndefOrPoison(Inst, false);
}
bool llvm::programUndefinedIfPoison(const Instruction *Inst) {
return ::programUndefinedIfUndefOrPoison(Inst, true);
}
static bool isKnownNonNaN(const Value *V, FastMathFlags FMF) {
if (FMF.noNaNs())
return true;
if (auto *C = dyn_cast<ConstantFP>(V))
return !C->isNaN();
if (auto *C = dyn_cast<ConstantDataVector>(V)) {
if (!C->getElementType()->isFloatingPointTy())
return false;
for (unsigned I = 0, E = C->getNumElements(); I < E; ++I) {
if (C->getElementAsAPFloat(I).isNaN())
return false;
}
return true;
}
if (isa<ConstantAggregateZero>(V))
return true;
return false;
}
static bool isKnownNonZero(const Value *V) {
if (auto *C = dyn_cast<ConstantFP>(V))
return !C->isZero();
if (auto *C = dyn_cast<ConstantDataVector>(V)) {
if (!C->getElementType()->isFloatingPointTy())
return false;
for (unsigned I = 0, E = C->getNumElements(); I < E; ++I) {
if (C->getElementAsAPFloat(I).isZero())
return false;
}
return true;
}
return false;
}
/// Match clamp pattern for float types without care about NaNs or signed zeros.
/// Given non-min/max outer cmp/select from the clamp pattern this
/// function recognizes if it can be substitued by a "canonical" min/max
/// pattern.
static SelectPatternResult matchFastFloatClamp(CmpInst::Predicate Pred,
Value *CmpLHS, Value *CmpRHS,
Value *TrueVal, Value *FalseVal,
Value *&LHS, Value *&RHS) {
// Try to match
// X < C1 ? C1 : Min(X, C2) --> Max(C1, Min(X, C2))
// X > C1 ? C1 : Max(X, C2) --> Min(C1, Max(X, C2))
// and return description of the outer Max/Min.
// First, check if select has inverse order:
if (CmpRHS == FalseVal) {
std::swap(TrueVal, FalseVal);
Pred = CmpInst::getInversePredicate(Pred);
}
// Assume success now. If there's no match, callers should not use these anyway.
LHS = TrueVal;
RHS = FalseVal;
const APFloat *FC1;
if (CmpRHS != TrueVal || !match(CmpRHS, m_APFloat(FC1)) || !FC1->isFinite())
return {SPF_UNKNOWN, SPNB_NA, false};
const APFloat *FC2;
switch (Pred) {
case CmpInst::FCMP_OLT:
case CmpInst::FCMP_OLE:
case CmpInst::FCMP_ULT:
case CmpInst::FCMP_ULE:
if (match(FalseVal,
m_CombineOr(m_OrdFMin(m_Specific(CmpLHS), m_APFloat(FC2)),
m_UnordFMin(m_Specific(CmpLHS), m_APFloat(FC2)))) &&
*FC1 < *FC2)
return {SPF_FMAXNUM, SPNB_RETURNS_ANY, false};
break;
case CmpInst::FCMP_OGT:
case CmpInst::FCMP_OGE:
case CmpInst::FCMP_UGT:
case CmpInst::FCMP_UGE:
if (match(FalseVal,
m_CombineOr(m_OrdFMax(m_Specific(CmpLHS), m_APFloat(FC2)),
m_UnordFMax(m_Specific(CmpLHS), m_APFloat(FC2)))) &&
*FC1 > *FC2)
return {SPF_FMINNUM, SPNB_RETURNS_ANY, false};
break;
default:
break;
}
return {SPF_UNKNOWN, SPNB_NA, false};
}
/// Recognize variations of:
/// CLAMP(v,l,h) ==> ((v) < (l) ? (l) : ((v) > (h) ? (h) : (v)))
static SelectPatternResult matchClamp(CmpInst::Predicate Pred,
Value *CmpLHS, Value *CmpRHS,
Value *TrueVal, Value *FalseVal) {
// Swap the select operands and predicate to match the patterns below.
if (CmpRHS != TrueVal) {
Pred = ICmpInst::getSwappedPredicate(Pred);
std::swap(TrueVal, FalseVal);
}
const APInt *C1;
if (CmpRHS == TrueVal && match(CmpRHS, m_APInt(C1))) {
const APInt *C2;
// (X <s C1) ? C1 : SMIN(X, C2) ==> SMAX(SMIN(X, C2), C1)
if (match(FalseVal, m_SMin(m_Specific(CmpLHS), m_APInt(C2))) &&
C1->slt(*C2) && Pred == CmpInst::ICMP_SLT)
return {SPF_SMAX, SPNB_NA, false};
// (X >s C1) ? C1 : SMAX(X, C2) ==> SMIN(SMAX(X, C2), C1)
if (match(FalseVal, m_SMax(m_Specific(CmpLHS), m_APInt(C2))) &&
C1->sgt(*C2) && Pred == CmpInst::ICMP_SGT)
return {SPF_SMIN, SPNB_NA, false};
// (X <u C1) ? C1 : UMIN(X, C2) ==> UMAX(UMIN(X, C2), C1)
if (match(FalseVal, m_UMin(m_Specific(CmpLHS), m_APInt(C2))) &&
C1->ult(*C2) && Pred == CmpInst::ICMP_ULT)
return {SPF_UMAX, SPNB_NA, false};
// (X >u C1) ? C1 : UMAX(X, C2) ==> UMIN(UMAX(X, C2), C1)
if (match(FalseVal, m_UMax(m_Specific(CmpLHS), m_APInt(C2))) &&
C1->ugt(*C2) && Pred == CmpInst::ICMP_UGT)
return {SPF_UMIN, SPNB_NA, false};
}
return {SPF_UNKNOWN, SPNB_NA, false};
}
/// Recognize variations of:
/// a < c ? min(a,b) : min(b,c) ==> min(min(a,b),min(b,c))
static SelectPatternResult matchMinMaxOfMinMax(CmpInst::Predicate Pred,
Value *CmpLHS, Value *CmpRHS,
Value *TVal, Value *FVal,
unsigned Depth) {
// TODO: Allow FP min/max with nnan/nsz.
assert(CmpInst::isIntPredicate(Pred) && "Expected integer comparison");
Value *A = nullptr, *B = nullptr;
SelectPatternResult L = matchSelectPattern(TVal, A, B, nullptr, Depth + 1);
if (!SelectPatternResult::isMinOrMax(L.Flavor))
return {SPF_UNKNOWN, SPNB_NA, false};
Value *C = nullptr, *D = nullptr;
SelectPatternResult R = matchSelectPattern(FVal, C, D, nullptr, Depth + 1);
if (L.Flavor != R.Flavor)
return {SPF_UNKNOWN, SPNB_NA, false};
// We have something like: x Pred y ? min(a, b) : min(c, d).
// Try to match the compare to the min/max operations of the select operands.
// First, make sure we have the right compare predicate.
switch (L.Flavor) {
case SPF_SMIN:
if (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SGE) {
Pred = ICmpInst::getSwappedPredicate(Pred);
std::swap(CmpLHS, CmpRHS);
}
if (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SLE)
break;
return {SPF_UNKNOWN, SPNB_NA, false};
case SPF_SMAX:
if (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SLE) {
Pred = ICmpInst::getSwappedPredicate(Pred);
std::swap(CmpLHS, CmpRHS);
}
if (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SGE)
break;
return {SPF_UNKNOWN, SPNB_NA, false};
case SPF_UMIN:
if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_UGE) {
Pred = ICmpInst::getSwappedPredicate(Pred);
std::swap(CmpLHS, CmpRHS);
}
if (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE)
break;
return {SPF_UNKNOWN, SPNB_NA, false};
case SPF_UMAX:
if (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE) {
Pred = ICmpInst::getSwappedPredicate(Pred);
std::swap(CmpLHS, CmpRHS);
}
if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_UGE)
break;
return {SPF_UNKNOWN, SPNB_NA, false};
default:
return {SPF_UNKNOWN, SPNB_NA, false};
}
// If there is a common operand in the already matched min/max and the other
// min/max operands match the compare operands (either directly or inverted),
// then this is min/max of the same flavor.
// a pred c ? m(a, b) : m(c, b) --> m(m(a, b), m(c, b))
// ~c pred ~a ? m(a, b) : m(c, b) --> m(m(a, b), m(c, b))
if (D == B) {
if ((CmpLHS == A && CmpRHS == C) || (match(C, m_Not(m_Specific(CmpLHS))) &&
match(A, m_Not(m_Specific(CmpRHS)))))
return {L.Flavor, SPNB_NA, false};
}
// a pred d ? m(a, b) : m(b, d) --> m(m(a, b), m(b, d))
// ~d pred ~a ? m(a, b) : m(b, d) --> m(m(a, b), m(b, d))
if (C == B) {
if ((CmpLHS == A && CmpRHS == D) || (match(D, m_Not(m_Specific(CmpLHS))) &&
match(A, m_Not(m_Specific(CmpRHS)))))
return {L.Flavor, SPNB_NA, false};
}
// b pred c ? m(a, b) : m(c, a) --> m(m(a, b), m(c, a))
// ~c pred ~b ? m(a, b) : m(c, a) --> m(m(a, b), m(c, a))
if (D == A) {
if ((CmpLHS == B && CmpRHS == C) || (match(C, m_Not(m_Specific(CmpLHS))) &&
match(B, m_Not(m_Specific(CmpRHS)))))
return {L.Flavor, SPNB_NA, false};
}
// b pred d ? m(a, b) : m(a, d) --> m(m(a, b), m(a, d))
// ~d pred ~b ? m(a, b) : m(a, d) --> m(m(a, b), m(a, d))
if (C == A) {
if ((CmpLHS == B && CmpRHS == D) || (match(D, m_Not(m_Specific(CmpLHS))) &&
match(B, m_Not(m_Specific(CmpRHS)))))
return {L.Flavor, SPNB_NA, false};
}
return {SPF_UNKNOWN, SPNB_NA, false};
}
/// If the input value is the result of a 'not' op, constant integer, or vector
/// splat of a constant integer, return the bitwise-not source value.
/// TODO: This could be extended to handle non-splat vector integer constants.
static Value *getNotValue(Value *V) {
Value *NotV;
if (match(V, m_Not(m_Value(NotV))))
return NotV;
const APInt *C;
if (match(V, m_APInt(C)))
return ConstantInt::get(V->getType(), ~(*C));
return nullptr;
}
/// Match non-obvious integer minimum and maximum sequences.
static SelectPatternResult matchMinMax(CmpInst::Predicate Pred,
Value *CmpLHS, Value *CmpRHS,
Value *TrueVal, Value *FalseVal,
Value *&LHS, Value *&RHS,
unsigned Depth) {
// Assume success. If there's no match, callers should not use these anyway.
LHS = TrueVal;
RHS = FalseVal;
SelectPatternResult SPR = matchClamp(Pred, CmpLHS, CmpRHS, TrueVal, FalseVal);
if (SPR.Flavor != SelectPatternFlavor::SPF_UNKNOWN)
return SPR;
SPR = matchMinMaxOfMinMax(Pred, CmpLHS, CmpRHS, TrueVal, FalseVal, Depth);
if (SPR.Flavor != SelectPatternFlavor::SPF_UNKNOWN)
return SPR;
// Look through 'not' ops to find disguised min/max.
// (X > Y) ? ~X : ~Y ==> (~X < ~Y) ? ~X : ~Y ==> MIN(~X, ~Y)
// (X < Y) ? ~X : ~Y ==> (~X > ~Y) ? ~X : ~Y ==> MAX(~X, ~Y)
if (CmpLHS == getNotValue(TrueVal) && CmpRHS == getNotValue(FalseVal)) {
switch (Pred) {
case CmpInst::ICMP_SGT: return {SPF_SMIN, SPNB_NA, false};
case CmpInst::ICMP_SLT: return {SPF_SMAX, SPNB_NA, false};
case CmpInst::ICMP_UGT: return {SPF_UMIN, SPNB_NA, false};
case CmpInst::ICMP_ULT: return {SPF_UMAX, SPNB_NA, false};
default: break;
}
}
// (X > Y) ? ~Y : ~X ==> (~X < ~Y) ? ~Y : ~X ==> MAX(~Y, ~X)
// (X < Y) ? ~Y : ~X ==> (~X > ~Y) ? ~Y : ~X ==> MIN(~Y, ~X)
if (CmpLHS == getNotValue(FalseVal) && CmpRHS == getNotValue(TrueVal)) {
switch (Pred) {
case CmpInst::ICMP_SGT: return {SPF_SMAX, SPNB_NA, false};
case CmpInst::ICMP_SLT: return {SPF_SMIN, SPNB_NA, false};
case CmpInst::ICMP_UGT: return {SPF_UMAX, SPNB_NA, false};
case CmpInst::ICMP_ULT: return {SPF_UMIN, SPNB_NA, false};
default: break;
}
}
if (Pred != CmpInst::ICMP_SGT && Pred != CmpInst::ICMP_SLT)
return {SPF_UNKNOWN, SPNB_NA, false};
const APInt *C1;
if (!match(CmpRHS, m_APInt(C1)))
return {SPF_UNKNOWN, SPNB_NA, false};
// An unsigned min/max can be written with a signed compare.
const APInt *C2;
if ((CmpLHS == TrueVal && match(FalseVal, m_APInt(C2))) ||
(CmpLHS == FalseVal && match(TrueVal, m_APInt(C2)))) {
// Is the sign bit set?
// (X <s 0) ? X : MAXVAL ==> (X >u MAXVAL) ? X : MAXVAL ==> UMAX
// (X <s 0) ? MAXVAL : X ==> (X >u MAXVAL) ? MAXVAL : X ==> UMIN
if (Pred == CmpInst::ICMP_SLT && C1->isZero() && C2->isMaxSignedValue())
return {CmpLHS == TrueVal ? SPF_UMAX : SPF_UMIN, SPNB_NA, false};
// Is the sign bit clear?
// (X >s -1) ? MINVAL : X ==> (X <u MINVAL) ? MINVAL : X ==> UMAX
// (X >s -1) ? X : MINVAL ==> (X <u MINVAL) ? X : MINVAL ==> UMIN
if (Pred == CmpInst::ICMP_SGT && C1->isAllOnes() && C2->isMinSignedValue())
return {CmpLHS == FalseVal ? SPF_UMAX : SPF_UMIN, SPNB_NA, false};
}
return {SPF_UNKNOWN, SPNB_NA, false};
}
bool llvm::isKnownNegation(const Value *X, const Value *Y, bool NeedNSW) {
assert(X && Y && "Invalid operand");
// X = sub (0, Y) || X = sub nsw (0, Y)
if ((!NeedNSW && match(X, m_Sub(m_ZeroInt(), m_Specific(Y)))) ||
(NeedNSW && match(X, m_NSWSub(m_ZeroInt(), m_Specific(Y)))))
return true;
// Y = sub (0, X) || Y = sub nsw (0, X)
if ((!NeedNSW && match(Y, m_Sub(m_ZeroInt(), m_Specific(X)))) ||
(NeedNSW && match(Y, m_NSWSub(m_ZeroInt(), m_Specific(X)))))
return true;
// X = sub (A, B), Y = sub (B, A) || X = sub nsw (A, B), Y = sub nsw (B, A)
Value *A, *B;
return (!NeedNSW && (match(X, m_Sub(m_Value(A), m_Value(B))) &&
match(Y, m_Sub(m_Specific(B), m_Specific(A))))) ||
(NeedNSW && (match(X, m_NSWSub(m_Value(A), m_Value(B))) &&
match(Y, m_NSWSub(m_Specific(B), m_Specific(A)))));
}
static SelectPatternResult matchSelectPattern(CmpInst::Predicate Pred,
FastMathFlags FMF,
Value *CmpLHS, Value *CmpRHS,
Value *TrueVal, Value *FalseVal,
Value *&LHS, Value *&RHS,
unsigned Depth) {
if (CmpInst::isFPPredicate(Pred)) {
// IEEE-754 ignores the sign of 0.0 in comparisons. So if the select has one
// 0.0 operand, set the compare's 0.0 operands to that same value for the
// purpose of identifying min/max. Disregard vector constants with undefined
// elements because those can not be back-propagated for analysis.
Value *OutputZeroVal = nullptr;
if (match(TrueVal, m_AnyZeroFP()) && !match(FalseVal, m_AnyZeroFP()) &&
!cast<Constant>(TrueVal)->containsUndefOrPoisonElement())
OutputZeroVal = TrueVal;
else if (match(FalseVal, m_AnyZeroFP()) && !match(TrueVal, m_AnyZeroFP()) &&
!cast<Constant>(FalseVal)->containsUndefOrPoisonElement())
OutputZeroVal = FalseVal;
if (OutputZeroVal) {
if (match(CmpLHS, m_AnyZeroFP()))
CmpLHS = OutputZeroVal;
if (match(CmpRHS, m_AnyZeroFP()))
CmpRHS = OutputZeroVal;
}
}
LHS = CmpLHS;
RHS = CmpRHS;
// Signed zero may return inconsistent results between implementations.
// (0.0 <= -0.0) ? 0.0 : -0.0 // Returns 0.0
// minNum(0.0, -0.0) // May return -0.0 or 0.0 (IEEE 754-2008 5.3.1)
// Therefore, we behave conservatively and only proceed if at least one of the
// operands is known to not be zero or if we don't care about signed zero.
switch (Pred) {
default: break;
// FIXME: Include OGT/OLT/UGT/ULT.
case CmpInst::FCMP_OGE: case CmpInst::FCMP_OLE:
case CmpInst::FCMP_UGE: case CmpInst::FCMP_ULE:
if (!FMF.noSignedZeros() && !isKnownNonZero(CmpLHS) &&
!isKnownNonZero(CmpRHS))
return {SPF_UNKNOWN, SPNB_NA, false};
}
SelectPatternNaNBehavior NaNBehavior = SPNB_NA;
bool Ordered = false;
// When given one NaN and one non-NaN input:
// - maxnum/minnum (C99 fmaxf()/fminf()) return the non-NaN input.
// - A simple C99 (a < b ? a : b) construction will return 'b' (as the
// ordered comparison fails), which could be NaN or non-NaN.
// so here we discover exactly what NaN behavior is required/accepted.
if (CmpInst::isFPPredicate(Pred)) {
bool LHSSafe = isKnownNonNaN(CmpLHS, FMF);
bool RHSSafe = isKnownNonNaN(CmpRHS, FMF);
if (LHSSafe && RHSSafe) {
// Both operands are known non-NaN.
NaNBehavior = SPNB_RETURNS_ANY;
} else if (CmpInst::isOrdered(Pred)) {
// An ordered comparison will return false when given a NaN, so it
// returns the RHS.
Ordered = true;
if (LHSSafe)
// LHS is non-NaN, so if RHS is NaN then NaN will be returned.
NaNBehavior = SPNB_RETURNS_NAN;
else if (RHSSafe)
NaNBehavior = SPNB_RETURNS_OTHER;
else
// Completely unsafe.
return {SPF_UNKNOWN, SPNB_NA, false};
} else {
Ordered = false;
// An unordered comparison will return true when given a NaN, so it
// returns the LHS.
if (LHSSafe)
// LHS is non-NaN, so if RHS is NaN then non-NaN will be returned.
NaNBehavior = SPNB_RETURNS_OTHER;
else if (RHSSafe)
NaNBehavior = SPNB_RETURNS_NAN;
else
// Completely unsafe.
return {SPF_UNKNOWN, SPNB_NA, false};
}
}
if (TrueVal == CmpRHS && FalseVal == CmpLHS) {
std::swap(CmpLHS, CmpRHS);
Pred = CmpInst::getSwappedPredicate(Pred);
if (NaNBehavior == SPNB_RETURNS_NAN)
NaNBehavior = SPNB_RETURNS_OTHER;
else if (NaNBehavior == SPNB_RETURNS_OTHER)
NaNBehavior = SPNB_RETURNS_NAN;
Ordered = !Ordered;
}
// ([if]cmp X, Y) ? X : Y
if (TrueVal == CmpLHS && FalseVal == CmpRHS) {
switch (Pred) {
default: return {SPF_UNKNOWN, SPNB_NA, false}; // Equality.
case ICmpInst::ICMP_UGT:
case ICmpInst::ICMP_UGE: return {SPF_UMAX, SPNB_NA, false};
case ICmpInst::ICMP_SGT:
case ICmpInst::ICMP_SGE: return {SPF_SMAX, SPNB_NA, false};
case ICmpInst::ICMP_ULT:
case ICmpInst::ICMP_ULE: return {SPF_UMIN, SPNB_NA, false};
case ICmpInst::ICMP_SLT:
case ICmpInst::ICMP_SLE: return {SPF_SMIN, SPNB_NA, false};
case FCmpInst::FCMP_UGT:
case FCmpInst::FCMP_UGE:
case FCmpInst::FCMP_OGT:
case FCmpInst::FCMP_OGE: return {SPF_FMAXNUM, NaNBehavior, Ordered};
case FCmpInst::FCMP_ULT:
case FCmpInst::FCMP_ULE:
case FCmpInst::FCMP_OLT:
case FCmpInst::FCMP_OLE: return {SPF_FMINNUM, NaNBehavior, Ordered};
}
}
if (isKnownNegation(TrueVal, FalseVal)) {
// Sign-extending LHS does not change its sign, so TrueVal/FalseVal can
// match against either LHS or sext(LHS).
auto MaybeSExtCmpLHS =
m_CombineOr(m_Specific(CmpLHS), m_SExt(m_Specific(CmpLHS)));
auto ZeroOrAllOnes = m_CombineOr(m_ZeroInt(), m_AllOnes());
auto ZeroOrOne = m_CombineOr(m_ZeroInt(), m_One());
if (match(TrueVal, MaybeSExtCmpLHS)) {
// Set the return values. If the compare uses the negated value (-X >s 0),
// swap the return values because the negated value is always 'RHS'.
LHS = TrueVal;
RHS = FalseVal;
if (match(CmpLHS, m_Neg(m_Specific(FalseVal))))
std::swap(LHS, RHS);
// (X >s 0) ? X : -X or (X >s -1) ? X : -X --> ABS(X)
// (-X >s 0) ? -X : X or (-X >s -1) ? -X : X --> ABS(X)
if (Pred == ICmpInst::ICMP_SGT && match(CmpRHS, ZeroOrAllOnes))
return {SPF_ABS, SPNB_NA, false};
// (X >=s 0) ? X : -X or (X >=s 1) ? X : -X --> ABS(X)
if (Pred == ICmpInst::ICMP_SGE && match(CmpRHS, ZeroOrOne))
return {SPF_ABS, SPNB_NA, false};
// (X <s 0) ? X : -X or (X <s 1) ? X : -X --> NABS(X)
// (-X <s 0) ? -X : X or (-X <s 1) ? -X : X --> NABS(X)
if (Pred == ICmpInst::ICMP_SLT && match(CmpRHS, ZeroOrOne))
return {SPF_NABS, SPNB_NA, false};
}
else if (match(FalseVal, MaybeSExtCmpLHS)) {
// Set the return values. If the compare uses the negated value (-X >s 0),
// swap the return values because the negated value is always 'RHS'.
LHS = FalseVal;
RHS = TrueVal;
if (match(CmpLHS, m_Neg(m_Specific(TrueVal))))
std::swap(LHS, RHS);
// (X >s 0) ? -X : X or (X >s -1) ? -X : X --> NABS(X)
// (-X >s 0) ? X : -X or (-X >s -1) ? X : -X --> NABS(X)
if (Pred == ICmpInst::ICMP_SGT && match(CmpRHS, ZeroOrAllOnes))
return {SPF_NABS, SPNB_NA, false};
// (X <s 0) ? -X : X or (X <s 1) ? -X : X --> ABS(X)
// (-X <s 0) ? X : -X or (-X <s 1) ? X : -X --> ABS(X)
if (Pred == ICmpInst::ICMP_SLT && match(CmpRHS, ZeroOrOne))
return {SPF_ABS, SPNB_NA, false};
}
}
if (CmpInst::isIntPredicate(Pred))
return matchMinMax(Pred, CmpLHS, CmpRHS, TrueVal, FalseVal, LHS, RHS, Depth);
// According to (IEEE 754-2008 5.3.1), minNum(0.0, -0.0) and similar
// may return either -0.0 or 0.0, so fcmp/select pair has stricter
// semantics than minNum. Be conservative in such case.
if (NaNBehavior != SPNB_RETURNS_ANY ||
(!FMF.noSignedZeros() && !isKnownNonZero(CmpLHS) &&
!isKnownNonZero(CmpRHS)))
return {SPF_UNKNOWN, SPNB_NA, false};
return matchFastFloatClamp(Pred, CmpLHS, CmpRHS, TrueVal, FalseVal, LHS, RHS);
}
/// Helps to match a select pattern in case of a type mismatch.
///
/// The function processes the case when type of true and false values of a
/// select instruction differs from type of the cmp instruction operands because
/// of a cast instruction. The function checks if it is legal to move the cast
/// operation after "select". If yes, it returns the new second value of
/// "select" (with the assumption that cast is moved):
/// 1. As operand of cast instruction when both values of "select" are same cast
/// instructions.
/// 2. As restored constant (by applying reverse cast operation) when the first
/// value of the "select" is a cast operation and the second value is a
/// constant.
/// NOTE: We return only the new second value because the first value could be
/// accessed as operand of cast instruction.
static Value *lookThroughCast(CmpInst *CmpI, Value *V1, Value *V2,
Instruction::CastOps *CastOp) {
auto *Cast1 = dyn_cast<CastInst>(V1);
if (!Cast1)
return nullptr;
*CastOp = Cast1->getOpcode();
Type *SrcTy = Cast1->getSrcTy();
if (auto *Cast2 = dyn_cast<CastInst>(V2)) {
// If V1 and V2 are both the same cast from the same type, look through V1.
if (*CastOp == Cast2->getOpcode() && SrcTy == Cast2->getSrcTy())
return Cast2->getOperand(0);
return nullptr;
}
auto *C = dyn_cast<Constant>(V2);
if (!C)
return nullptr;
Constant *CastedTo = nullptr;
switch (*CastOp) {
case Instruction::ZExt:
if (CmpI->isUnsigned())
CastedTo = ConstantExpr::getTrunc(C, SrcTy);
break;
case Instruction::SExt:
if (CmpI->isSigned())
CastedTo = ConstantExpr::getTrunc(C, SrcTy, true);
break;
case Instruction::Trunc:
Constant *CmpConst;
if (match(CmpI->getOperand(1), m_Constant(CmpConst)) &&
CmpConst->getType() == SrcTy) {
// Here we have the following case:
//
// %cond = cmp iN %x, CmpConst
// %tr = trunc iN %x to iK
// %narrowsel = select i1 %cond, iK %t, iK C
//
// We can always move trunc after select operation:
//
// %cond = cmp iN %x, CmpConst
// %widesel = select i1 %cond, iN %x, iN CmpConst
// %tr = trunc iN %widesel to iK
//
// Note that C could be extended in any way because we don't care about
// upper bits after truncation. It can't be abs pattern, because it would
// look like:
//
// select i1 %cond, x, -x.
//
// So only min/max pattern could be matched. Such match requires widened C
// == CmpConst. That is why set widened C = CmpConst, condition trunc
// CmpConst == C is checked below.
CastedTo = CmpConst;
} else {
CastedTo = ConstantExpr::getIntegerCast(C, SrcTy, CmpI->isSigned());
}
break;
case Instruction::FPTrunc:
CastedTo = ConstantExpr::getFPExtend(C, SrcTy, true);
break;
case Instruction::FPExt:
CastedTo = ConstantExpr::getFPTrunc(C, SrcTy, true);
break;
case Instruction::FPToUI:
CastedTo = ConstantExpr::getUIToFP(C, SrcTy, true);
break;
case Instruction::FPToSI:
CastedTo = ConstantExpr::getSIToFP(C, SrcTy, true);
break;
case Instruction::UIToFP:
CastedTo = ConstantExpr::getFPToUI(C, SrcTy, true);
break;
case Instruction::SIToFP:
CastedTo = ConstantExpr::getFPToSI(C, SrcTy, true);
break;
default:
break;
}
if (!CastedTo)
return nullptr;
// Make sure the cast doesn't lose any information.
Constant *CastedBack =
ConstantExpr::getCast(*CastOp, CastedTo, C->getType(), true);
if (CastedBack != C)
return nullptr;
return CastedTo;
}
SelectPatternResult llvm::matchSelectPattern(Value *V, Value *&LHS, Value *&RHS,
Instruction::CastOps *CastOp,
unsigned Depth) {
if (Depth >= MaxAnalysisRecursionDepth)
return {SPF_UNKNOWN, SPNB_NA, false};
SelectInst *SI = dyn_cast<SelectInst>(V);
if (!SI) return {SPF_UNKNOWN, SPNB_NA, false};
CmpInst *CmpI = dyn_cast<CmpInst>(SI->getCondition());
if (!CmpI) return {SPF_UNKNOWN, SPNB_NA, false};
Value *TrueVal = SI->getTrueValue();
Value *FalseVal = SI->getFalseValue();
return llvm::matchDecomposedSelectPattern(CmpI, TrueVal, FalseVal, LHS, RHS,
CastOp, Depth);
}
SelectPatternResult llvm::matchDecomposedSelectPattern(
CmpInst *CmpI, Value *TrueVal, Value *FalseVal, Value *&LHS, Value *&RHS,
Instruction::CastOps *CastOp, unsigned Depth) {
CmpInst::Predicate Pred = CmpI->getPredicate();
Value *CmpLHS = CmpI->getOperand(0);
Value *CmpRHS = CmpI->getOperand(1);
FastMathFlags FMF;
if (isa<FPMathOperator>(CmpI))
FMF = CmpI->getFastMathFlags();
// Bail out early.
if (CmpI->isEquality())
return {SPF_UNKNOWN, SPNB_NA, false};
// Deal with type mismatches.
if (CastOp && CmpLHS->getType() != TrueVal->getType()) {
if (Value *C = lookThroughCast(CmpI, TrueVal, FalseVal, CastOp)) {
// If this is a potential fmin/fmax with a cast to integer, then ignore
// -0.0 because there is no corresponding integer value.
if (*CastOp == Instruction::FPToSI || *CastOp == Instruction::FPToUI)
FMF.setNoSignedZeros();
return ::matchSelectPattern(Pred, FMF, CmpLHS, CmpRHS,
cast<CastInst>(TrueVal)->getOperand(0), C,
LHS, RHS, Depth);
}
if (Value *C = lookThroughCast(CmpI, FalseVal, TrueVal, CastOp)) {
// If this is a potential fmin/fmax with a cast to integer, then ignore
// -0.0 because there is no corresponding integer value.
if (*CastOp == Instruction::FPToSI || *CastOp == Instruction::FPToUI)
FMF.setNoSignedZeros();
return ::matchSelectPattern(Pred, FMF, CmpLHS, CmpRHS,
C, cast<CastInst>(FalseVal)->getOperand(0),
LHS, RHS, Depth);
}
}
return ::matchSelectPattern(Pred, FMF, CmpLHS, CmpRHS, TrueVal, FalseVal,
LHS, RHS, Depth);
}
CmpInst::Predicate llvm::getMinMaxPred(SelectPatternFlavor SPF, bool Ordered) {
if (SPF == SPF_SMIN) return ICmpInst::ICMP_SLT;
if (SPF == SPF_UMIN) return ICmpInst::ICMP_ULT;
if (SPF == SPF_SMAX) return ICmpInst::ICMP_SGT;
if (SPF == SPF_UMAX) return ICmpInst::ICMP_UGT;
if (SPF == SPF_FMINNUM)
return Ordered ? FCmpInst::FCMP_OLT : FCmpInst::FCMP_ULT;
if (SPF == SPF_FMAXNUM)
return Ordered ? FCmpInst::FCMP_OGT : FCmpInst::FCMP_UGT;
llvm_unreachable("unhandled!");
}
SelectPatternFlavor llvm::getInverseMinMaxFlavor(SelectPatternFlavor SPF) {
if (SPF == SPF_SMIN) return SPF_SMAX;
if (SPF == SPF_UMIN) return SPF_UMAX;
if (SPF == SPF_SMAX) return SPF_SMIN;
if (SPF == SPF_UMAX) return SPF_UMIN;
llvm_unreachable("unhandled!");
}
Intrinsic::ID llvm::getInverseMinMaxIntrinsic(Intrinsic::ID MinMaxID) {
switch (MinMaxID) {
case Intrinsic::smax: return Intrinsic::smin;
case Intrinsic::smin: return Intrinsic::smax;
case Intrinsic::umax: return Intrinsic::umin;
case Intrinsic::umin: return Intrinsic::umax;
default: llvm_unreachable("Unexpected intrinsic");
}
}
CmpInst::Predicate llvm::getInverseMinMaxPred(SelectPatternFlavor SPF) {
return getMinMaxPred(getInverseMinMaxFlavor(SPF));
}
APInt llvm::getMinMaxLimit(SelectPatternFlavor SPF, unsigned BitWidth) {
switch (SPF) {
case SPF_SMAX: return APInt::getSignedMaxValue(BitWidth);
case SPF_SMIN: return APInt::getSignedMinValue(BitWidth);
case SPF_UMAX: return APInt::getMaxValue(BitWidth);
case SPF_UMIN: return APInt::getMinValue(BitWidth);
default: llvm_unreachable("Unexpected flavor");
}
}
std::pair<Intrinsic::ID, bool>
llvm::canConvertToMinOrMaxIntrinsic(ArrayRef<Value *> VL) {
// Check if VL contains select instructions that can be folded into a min/max
// vector intrinsic and return the intrinsic if it is possible.
// TODO: Support floating point min/max.
bool AllCmpSingleUse = true;
SelectPatternResult SelectPattern;
SelectPattern.Flavor = SPF_UNKNOWN;
if (all_of(VL, [&SelectPattern, &AllCmpSingleUse](Value *I) {
Value *LHS, *RHS;
auto CurrentPattern = matchSelectPattern(I, LHS, RHS);
if (!SelectPatternResult::isMinOrMax(CurrentPattern.Flavor) ||
CurrentPattern.Flavor == SPF_FMINNUM ||
CurrentPattern.Flavor == SPF_FMAXNUM ||
!I->getType()->isIntOrIntVectorTy())
return false;
if (SelectPattern.Flavor != SPF_UNKNOWN &&
SelectPattern.Flavor != CurrentPattern.Flavor)
return false;
SelectPattern = CurrentPattern;
AllCmpSingleUse &=
match(I, m_Select(m_OneUse(m_Value()), m_Value(), m_Value()));
return true;
})) {
switch (SelectPattern.Flavor) {
case SPF_SMIN:
return {Intrinsic::smin, AllCmpSingleUse};
case SPF_UMIN:
return {Intrinsic::umin, AllCmpSingleUse};
case SPF_SMAX:
return {Intrinsic::smax, AllCmpSingleUse};
case SPF_UMAX:
return {Intrinsic::umax, AllCmpSingleUse};
default:
llvm_unreachable("unexpected select pattern flavor");
}
}
return {Intrinsic::not_intrinsic, false};
}
bool llvm::matchSimpleRecurrence(const PHINode *P, BinaryOperator *&BO,
Value *&Start, Value *&Step) {
// Handle the case of a simple two-predecessor recurrence PHI.
// There's a lot more that could theoretically be done here, but
// this is sufficient to catch some interesting cases.
if (P->getNumIncomingValues() != 2)
return false;
for (unsigned i = 0; i != 2; ++i) {
Value *L = P->getIncomingValue(i);
Value *R = P->getIncomingValue(!i);
Operator *LU = dyn_cast<Operator>(L);
if (!LU)
continue;
unsigned Opcode = LU->getOpcode();
switch (Opcode) {
default:
continue;
// TODO: Expand list -- xor, div, gep, uaddo, etc..
case Instruction::LShr:
case Instruction::AShr:
case Instruction::Shl:
case Instruction::Add:
case Instruction::Sub:
case Instruction::And:
case Instruction::Or:
case Instruction::Mul: {
Value *LL = LU->getOperand(0);
Value *LR = LU->getOperand(1);
// Find a recurrence.
if (LL == P)
L = LR;
else if (LR == P)
L = LL;
else
continue; // Check for recurrence with L and R flipped.
break; // Match!
}
};
// We have matched a recurrence of the form:
// %iv = [R, %entry], [%iv.next, %backedge]
// %iv.next = binop %iv, L
// OR
// %iv = [R, %entry], [%iv.next, %backedge]
// %iv.next = binop L, %iv
BO = cast<BinaryOperator>(LU);
Start = R;
Step = L;
return true;
}
return false;
}
bool llvm::matchSimpleRecurrence(const BinaryOperator *I, PHINode *&P,
Value *&Start, Value *&Step) {
BinaryOperator *BO = nullptr;
P = dyn_cast<PHINode>(I->getOperand(0));
if (!P)
P = dyn_cast<PHINode>(I->getOperand(1));
return P && matchSimpleRecurrence(P, BO, Start, Step) && BO == I;
}
/// Return true if "icmp Pred LHS RHS" is always true.
static bool isTruePredicate(CmpInst::Predicate Pred, const Value *LHS,
const Value *RHS, const DataLayout &DL,
unsigned Depth) {
if (ICmpInst::isTrueWhenEqual(Pred) && LHS == RHS)
return true;
switch (Pred) {
default:
return false;
case CmpInst::ICMP_SLE: {
const APInt *C;
// LHS s<= LHS +_{nsw} C if C >= 0
if (match(RHS, m_NSWAdd(m_Specific(LHS), m_APInt(C))))
return !C->isNegative();
return false;
}
case CmpInst::ICMP_ULE: {
const APInt *C;
// LHS u<= LHS +_{nuw} C for any C
if (match(RHS, m_NUWAdd(m_Specific(LHS), m_APInt(C))))
return true;
// Match A to (X +_{nuw} CA) and B to (X +_{nuw} CB)
auto MatchNUWAddsToSameValue = [&](const Value *A, const Value *B,
const Value *&X,
const APInt *&CA, const APInt *&CB) {
if (match(A, m_NUWAdd(m_Value(X), m_APInt(CA))) &&
match(B, m_NUWAdd(m_Specific(X), m_APInt(CB))))
return true;
// If X & C == 0 then (X | C) == X +_{nuw} C
if (match(A, m_Or(m_Value(X), m_APInt(CA))) &&
match(B, m_Or(m_Specific(X), m_APInt(CB)))) {
KnownBits Known(CA->getBitWidth());
computeKnownBits(X, Known, DL, Depth + 1, /*AC*/ nullptr,
/*CxtI*/ nullptr, /*DT*/ nullptr);
if (CA->isSubsetOf(Known.Zero) && CB->isSubsetOf(Known.Zero))
return true;
}
return false;
};
const Value *X;
const APInt *CLHS, *CRHS;
if (MatchNUWAddsToSameValue(LHS, RHS, X, CLHS, CRHS))
return CLHS->ule(*CRHS);
return false;
}
}
}
/// Return true if "icmp Pred BLHS BRHS" is true whenever "icmp Pred
/// ALHS ARHS" is true. Otherwise, return None.
static Optional<bool>
isImpliedCondOperands(CmpInst::Predicate Pred, const Value *ALHS,
const Value *ARHS, const Value *BLHS, const Value *BRHS,
const DataLayout &DL, unsigned Depth) {
switch (Pred) {
default:
return None;
case CmpInst::ICMP_SLT:
case CmpInst::ICMP_SLE:
if (isTruePredicate(CmpInst::ICMP_SLE, BLHS, ALHS, DL, Depth) &&
isTruePredicate(CmpInst::ICMP_SLE, ARHS, BRHS, DL, Depth))
return true;
return None;
case CmpInst::ICMP_ULT:
case CmpInst::ICMP_ULE:
if (isTruePredicate(CmpInst::ICMP_ULE, BLHS, ALHS, DL, Depth) &&
isTruePredicate(CmpInst::ICMP_ULE, ARHS, BRHS, DL, Depth))
return true;
return None;
}
}
/// Return true if the operands of the two compares match. IsSwappedOps is true
/// when the operands match, but are swapped.
static bool isMatchingOps(const Value *ALHS, const Value *ARHS,
const Value *BLHS, const Value *BRHS,
bool &IsSwappedOps) {
bool IsMatchingOps = (ALHS == BLHS && ARHS == BRHS);
IsSwappedOps = (ALHS == BRHS && ARHS == BLHS);
return IsMatchingOps || IsSwappedOps;
}
/// Return true if "icmp1 APred X, Y" implies "icmp2 BPred X, Y" is true.
/// Return false if "icmp1 APred X, Y" implies "icmp2 BPred X, Y" is false.
/// Otherwise, return None if we can't infer anything.
static Optional<bool> isImpliedCondMatchingOperands(CmpInst::Predicate APred,
CmpInst::Predicate BPred,
bool AreSwappedOps) {
// Canonicalize the predicate as if the operands were not commuted.
if (AreSwappedOps)
BPred = ICmpInst::getSwappedPredicate(BPred);
if (CmpInst::isImpliedTrueByMatchingCmp(APred, BPred))
return true;
if (CmpInst::isImpliedFalseByMatchingCmp(APred, BPred))
return false;
return None;
}
/// Return true if "icmp APred X, C1" implies "icmp BPred X, C2" is true.
/// Return false if "icmp APred X, C1" implies "icmp BPred X, C2" is false.
/// Otherwise, return None if we can't infer anything.
static Optional<bool> isImpliedCondMatchingImmOperands(CmpInst::Predicate APred,
const APInt &C1,
CmpInst::Predicate BPred,
const APInt &C2) {
ConstantRange DomCR = ConstantRange::makeExactICmpRegion(APred, C1);
ConstantRange CR = ConstantRange::makeExactICmpRegion(BPred, C2);
ConstantRange Intersection = DomCR.intersectWith(CR);
ConstantRange Difference = DomCR.difference(CR);
if (Intersection.isEmptySet())
return false;
if (Difference.isEmptySet())
return true;
return None;
}
/// Return true if LHS implies RHS is true. Return false if LHS implies RHS is
/// false. Otherwise, return None if we can't infer anything.
static Optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
CmpInst::Predicate BPred,
const Value *BLHS, const Value *BRHS,
const DataLayout &DL, bool LHSIsTrue,
unsigned Depth) {
Value *ALHS = LHS->getOperand(0);
Value *ARHS = LHS->getOperand(1);
// The rest of the logic assumes the LHS condition is true. If that's not the
// case, invert the predicate to make it so.
CmpInst::Predicate APred =
LHSIsTrue ? LHS->getPredicate() : LHS->getInversePredicate();
// Can we infer anything when the two compares have matching operands?
bool AreSwappedOps;
if (isMatchingOps(ALHS, ARHS, BLHS, BRHS, AreSwappedOps)) {
if (Optional<bool> Implication = isImpliedCondMatchingOperands(
APred, BPred, AreSwappedOps))
return Implication;
// No amount of additional analysis will infer the second condition, so
// early exit.
return None;
}
// Can we infer anything when the LHS operands match and the RHS operands are
// constants (not necessarily matching)?
const APInt *AC, *BC;
if (ALHS == BLHS && match(ARHS, m_APInt(AC)) && match(BRHS, m_APInt(BC)))
return isImpliedCondMatchingImmOperands(APred, *AC, BPred, *BC);
if (APred == BPred)
return isImpliedCondOperands(APred, ALHS, ARHS, BLHS, BRHS, DL, Depth);
return None;
}
/// Return true if LHS implies RHS is true. Return false if LHS implies RHS is
/// false. Otherwise, return None if we can't infer anything. We expect the
/// RHS to be an icmp and the LHS to be an 'and', 'or', or a 'select' instruction.
static Optional<bool>
isImpliedCondAndOr(const Instruction *LHS, CmpInst::Predicate RHSPred,
const Value *RHSOp0, const Value *RHSOp1,
const DataLayout &DL, bool LHSIsTrue, unsigned Depth) {
// The LHS must be an 'or', 'and', or a 'select' instruction.
assert((LHS->getOpcode() == Instruction::And ||
LHS->getOpcode() == Instruction::Or ||
LHS->getOpcode() == Instruction::Select) &&
"Expected LHS to be 'and', 'or', or 'select'.");
assert(Depth <= MaxAnalysisRecursionDepth && "Hit recursion limit");
// If the result of an 'or' is false, then we know both legs of the 'or' are
// false. Similarly, if the result of an 'and' is true, then we know both
// legs of the 'and' are true.
const Value *ALHS, *ARHS;
if ((!LHSIsTrue && match(LHS, m_LogicalOr(m_Value(ALHS), m_Value(ARHS)))) ||
(LHSIsTrue && match(LHS, m_LogicalAnd(m_Value(ALHS), m_Value(ARHS))))) {
// FIXME: Make this non-recursion.
if (Optional<bool> Implication = isImpliedCondition(
ALHS, RHSPred, RHSOp0, RHSOp1, DL, LHSIsTrue, Depth + 1))
return Implication;
if (Optional<bool> Implication = isImpliedCondition(
ARHS, RHSPred, RHSOp0, RHSOp1, DL, LHSIsTrue, Depth + 1))
return Implication;
return None;
}
return None;
}
Optional<bool>
llvm::isImpliedCondition(const Value *LHS, CmpInst::Predicate RHSPred,
const Value *RHSOp0, const Value *RHSOp1,
const DataLayout &DL, bool LHSIsTrue, unsigned Depth) {
// Bail out when we hit the limit.
if (Depth == MaxAnalysisRecursionDepth)
return None;
// A mismatch occurs when we compare a scalar cmp to a vector cmp, for
// example.
if (RHSOp0->getType()->isVectorTy() != LHS->getType()->isVectorTy())
return None;
assert(LHS->getType()->isIntOrIntVectorTy(1) &&
"Expected integer type only!");
// Both LHS and RHS are icmps.
const ICmpInst *LHSCmp = dyn_cast<ICmpInst>(LHS);
if (LHSCmp)
return isImpliedCondICmps(LHSCmp, RHSPred, RHSOp0, RHSOp1, DL, LHSIsTrue,
Depth);
/// The LHS should be an 'or', 'and', or a 'select' instruction. We expect
/// the RHS to be an icmp.
/// FIXME: Add support for and/or/select on the RHS.
if (const Instruction *LHSI = dyn_cast<Instruction>(LHS)) {
if ((LHSI->getOpcode() == Instruction::And ||
LHSI->getOpcode() == Instruction::Or ||
LHSI->getOpcode() == Instruction::Select))
return isImpliedCondAndOr(LHSI, RHSPred, RHSOp0, RHSOp1, DL, LHSIsTrue,
Depth);
}
return None;
}
Optional<bool> llvm::isImpliedCondition(const Value *LHS, const Value *RHS,
const DataLayout &DL, bool LHSIsTrue,
unsigned Depth) {
// LHS ==> RHS by definition
if (LHS == RHS)
return LHSIsTrue;
if (const ICmpInst *RHSCmp = dyn_cast<ICmpInst>(RHS))
return isImpliedCondition(LHS, RHSCmp->getPredicate(),
RHSCmp->getOperand(0), RHSCmp->getOperand(1), DL,
LHSIsTrue, Depth);
if (Depth == MaxAnalysisRecursionDepth)
return None;
// LHS ==> (RHS1 || RHS2) if LHS ==> RHS1 or LHS ==> RHS2
// LHS ==> !(RHS1 && RHS2) if LHS ==> !RHS1 or LHS ==> !RHS2
const Value *RHS1, *RHS2;
if (match(RHS, m_LogicalOr(m_Value(RHS1), m_Value(RHS2)))) {
if (Optional<bool> Imp =
isImpliedCondition(LHS, RHS1, DL, LHSIsTrue, Depth + 1))
if (*Imp == true)
return true;
if (Optional<bool> Imp =
isImpliedCondition(LHS, RHS2, DL, LHSIsTrue, Depth + 1))
if (*Imp == true)
return true;
}
if (match(RHS, m_LogicalAnd(m_Value(RHS1), m_Value(RHS2)))) {
if (Optional<bool> Imp =
isImpliedCondition(LHS, RHS1, DL, LHSIsTrue, Depth + 1))
if (*Imp == false)
return false;
if (Optional<bool> Imp =
isImpliedCondition(LHS, RHS2, DL, LHSIsTrue, Depth + 1))
if (*Imp == false)
return false;
}
return None;
}
// Returns a pair (Condition, ConditionIsTrue), where Condition is a branch
// condition dominating ContextI or nullptr, if no condition is found.
static std::pair<Value *, bool>
getDomPredecessorCondition(const Instruction *ContextI) {
if (!ContextI || !ContextI->getParent())
return {nullptr, false};
// TODO: This is a poor/cheap way to determine dominance. Should we use a
// dominator tree (eg, from a SimplifyQuery) instead?
const BasicBlock *ContextBB = ContextI->getParent();
const BasicBlock *PredBB = ContextBB->getSinglePredecessor();
if (!PredBB)
return {nullptr, false};
// We need a conditional branch in the predecessor.
Value *PredCond;
BasicBlock *TrueBB, *FalseBB;
if (!match(PredBB->getTerminator(), m_Br(m_Value(PredCond), TrueBB, FalseBB)))
return {nullptr, false};
// The branch should get simplified. Don't bother simplifying this condition.
if (TrueBB == FalseBB)
return {nullptr, false};
assert((TrueBB == ContextBB || FalseBB == ContextBB) &&
"Predecessor block does not point to successor?");
// Is this condition implied by the predecessor condition?
return {PredCond, TrueBB == ContextBB};
}
Optional<bool> llvm::isImpliedByDomCondition(const Value *Cond,
const Instruction *ContextI,
const DataLayout &DL) {
assert(Cond->getType()->isIntOrIntVectorTy(1) && "Condition must be bool");
auto PredCond = getDomPredecessorCondition(ContextI);
if (PredCond.first)
return isImpliedCondition(PredCond.first, Cond, DL, PredCond.second);
return None;
}
Optional<bool> llvm::isImpliedByDomCondition(CmpInst::Predicate Pred,
const Value *LHS, const Value *RHS,
const Instruction *ContextI,
const DataLayout &DL) {
auto PredCond = getDomPredecessorCondition(ContextI);
if (PredCond.first)
return isImpliedCondition(PredCond.first, Pred, LHS, RHS, DL,
PredCond.second);
return None;
}
static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
APInt &Upper, const InstrInfoQuery &IIQ,
bool PreferSignedRange) {
unsigned Width = Lower.getBitWidth();
const APInt *C;
switch (BO.getOpcode()) {
case Instruction::Add:
if (match(BO.getOperand(1), m_APInt(C)) && !C->isZero()) {
bool HasNSW = IIQ.hasNoSignedWrap(&BO);
bool HasNUW = IIQ.hasNoUnsignedWrap(&BO);
// If the caller expects a signed compare, then try to use a signed range.
// Otherwise if both no-wraps are set, use the unsigned range because it
// is never larger than the signed range. Example:
// "add nuw nsw i8 X, -2" is unsigned [254,255] vs. signed [-128, 125].
if (PreferSignedRange && HasNSW && HasNUW)
HasNUW = false;
if (HasNUW) {
// 'add nuw x, C' produces [C, UINT_MAX].
Lower = *C;
} else if (HasNSW) {
if (C->isNegative()) {
// 'add nsw x, -C' produces [SINT_MIN, SINT_MAX - C].
Lower = APInt::getSignedMinValue(Width);
Upper = APInt::getSignedMaxValue(Width) + *C + 1;
} else {
// 'add nsw x, +C' produces [SINT_MIN + C, SINT_MAX].
Lower = APInt::getSignedMinValue(Width) + *C;
Upper = APInt::getSignedMaxValue(Width) + 1;
}
}
}
break;
case Instruction::And:
if (match(BO.getOperand(1), m_APInt(C)))
// 'and x, C' produces [0, C].
Upper = *C + 1;
break;
case Instruction::Or:
if (match(BO.getOperand(1), m_APInt(C)))
// 'or x, C' produces [C, UINT_MAX].
Lower = *C;
break;
case Instruction::AShr:
if (match(BO.getOperand(1), m_APInt(C)) && C->ult(Width)) {
// 'ashr x, C' produces [INT_MIN >> C, INT_MAX >> C].
Lower = APInt::getSignedMinValue(Width).ashr(*C);
Upper = APInt::getSignedMaxValue(Width).ashr(*C) + 1;
} else if (match(BO.getOperand(0), m_APInt(C))) {
unsigned ShiftAmount = Width - 1;
if (!C->isZero() && IIQ.isExact(&BO))
ShiftAmount = C->countTrailingZeros();
if (C->isNegative()) {
// 'ashr C, x' produces [C, C >> (Width-1)]
Lower = *C;
Upper = C->ashr(ShiftAmount) + 1;
} else {
// 'ashr C, x' produces [C >> (Width-1), C]
Lower = C->ashr(ShiftAmount);
Upper = *C + 1;
}
}
break;
case Instruction::LShr:
if (match(BO.getOperand(1), m_APInt(C)) && C->ult(Width)) {
// 'lshr x, C' produces [0, UINT_MAX >> C].
Upper = APInt::getAllOnes(Width).lshr(*C) + 1;
} else if (match(BO.getOperand(0), m_APInt(C))) {
// 'lshr C, x' produces [C >> (Width-1), C].
unsigned ShiftAmount = Width - 1;
if (!C->isZero() && IIQ.isExact(&BO))
ShiftAmount = C->countTrailingZeros();
Lower = C->lshr(ShiftAmount);
Upper = *C + 1;
}
break;
case Instruction::Shl:
if (match(BO.getOperand(0), m_APInt(C))) {
if (IIQ.hasNoUnsignedWrap(&BO)) {
// 'shl nuw C, x' produces [C, C << CLZ(C)]
Lower = *C;
Upper = Lower.shl(Lower.countLeadingZeros()) + 1;
} else if (BO.hasNoSignedWrap()) { // TODO: What if both nuw+nsw?
if (C->isNegative()) {
// 'shl nsw C, x' produces [C << CLO(C)-1, C]
unsigned ShiftAmount = C->countLeadingOnes() - 1;
Lower = C->shl(ShiftAmount);
Upper = *C + 1;
} else {
// 'shl nsw C, x' produces [C, C << CLZ(C)-1]
unsigned ShiftAmount = C->countLeadingZeros() - 1;
Lower = *C;
Upper = C->shl(ShiftAmount) + 1;
}
}
}
break;
case Instruction::SDiv:
if (match(BO.getOperand(1), m_APInt(C))) {
APInt IntMin = APInt::getSignedMinValue(Width);
APInt IntMax = APInt::getSignedMaxValue(Width);
if (C->isAllOnes()) {
// 'sdiv x, -1' produces [INT_MIN + 1, INT_MAX]
// where C != -1 and C != 0 and C != 1
Lower = IntMin + 1;
Upper = IntMax + 1;
} else if (C->countLeadingZeros() < Width - 1) {
// 'sdiv x, C' produces [INT_MIN / C, INT_MAX / C]
// where C != -1 and C != 0 and C != 1
Lower = IntMin.sdiv(*C);
Upper = IntMax.sdiv(*C);
if (Lower.sgt(Upper))
std::swap(Lower, Upper);
Upper = Upper + 1;
assert(Upper != Lower && "Upper part of range has wrapped!");
}
} else if (match(BO.getOperand(0), m_APInt(C))) {
if (C->isMinSignedValue()) {
// 'sdiv INT_MIN, x' produces [INT_MIN, INT_MIN / -2].
Lower = *C;
Upper = Lower.lshr(1) + 1;
} else {
// 'sdiv C, x' produces [-|C|, |C|].
Upper = C->abs() + 1;
Lower = (-Upper) + 1;
}
}
break;
case Instruction::UDiv:
if (match(BO.getOperand(1), m_APInt(C)) && !C->isZero()) {
// 'udiv x, C' produces [0, UINT_MAX / C].
Upper = APInt::getMaxValue(Width).udiv(*C) + 1;
} else if (match(BO.getOperand(0), m_APInt(C))) {
// 'udiv C, x' produces [0, C].
Upper = *C + 1;
}
break;
case Instruction::SRem:
if (match(BO.getOperand(1), m_APInt(C))) {
// 'srem x, C' produces (-|C|, |C|).
Upper = C->abs();
Lower = (-Upper) + 1;
}
break;
case Instruction::URem:
if (match(BO.getOperand(1), m_APInt(C)))
// 'urem x, C' produces [0, C).
Upper = *C;
break;
default:
break;
}
}
static void setLimitsForIntrinsic(const IntrinsicInst &II, APInt &Lower,
APInt &Upper) {
unsigned Width = Lower.getBitWidth();
const APInt *C;
switch (II.getIntrinsicID()) {
case Intrinsic::ctpop:
case Intrinsic::ctlz:
case Intrinsic::cttz:
// Maximum of set/clear bits is the bit width.
assert(Lower == 0 && "Expected lower bound to be zero");
Upper = Width + 1;
break;
case Intrinsic::uadd_sat:
// uadd.sat(x, C) produces [C, UINT_MAX].
if (match(II.getOperand(0), m_APInt(C)) ||
match(II.getOperand(1), m_APInt(C)))
Lower = *C;
break;
case Intrinsic::sadd_sat:
if (match(II.getOperand(0), m_APInt(C)) ||
match(II.getOperand(1), m_APInt(C))) {
if (C->isNegative()) {
// sadd.sat(x, -C) produces [SINT_MIN, SINT_MAX + (-C)].
Lower = APInt::getSignedMinValue(Width);
Upper = APInt::getSignedMaxValue(Width) + *C + 1;
} else {
// sadd.sat(x, +C) produces [SINT_MIN + C, SINT_MAX].
Lower = APInt::getSignedMinValue(Width) + *C;
Upper = APInt::getSignedMaxValue(Width) + 1;
}
}
break;
case Intrinsic::usub_sat:
// usub.sat(C, x) produces [0, C].
if (match(II.getOperand(0), m_APInt(C)))
Upper = *C + 1;
// usub.sat(x, C) produces [0, UINT_MAX - C].
else if (match(II.getOperand(1), m_APInt(C)))
Upper = APInt::getMaxValue(Width) - *C + 1;
break;
case Intrinsic::ssub_sat:
if (match(II.getOperand(0), m_APInt(C))) {
if (C->isNegative()) {
// ssub.sat(-C, x) produces [SINT_MIN, -SINT_MIN + (-C)].
Lower = APInt::getSignedMinValue(Width);
Upper = *C - APInt::getSignedMinValue(Width) + 1;
} else {
// ssub.sat(+C, x) produces [-SINT_MAX + C, SINT_MAX].
Lower = *C - APInt::getSignedMaxValue(Width);
Upper = APInt::getSignedMaxValue(Width) + 1;
}
} else if (match(II.getOperand(1), m_APInt(C))) {
if (C->isNegative()) {
// ssub.sat(x, -C) produces [SINT_MIN - (-C), SINT_MAX]:
Lower = APInt::getSignedMinValue(Width) - *C;
Upper = APInt::getSignedMaxValue(Width) + 1;
} else {
// ssub.sat(x, +C) produces [SINT_MIN, SINT_MAX - C].
Lower = APInt::getSignedMinValue(Width);
Upper = APInt::getSignedMaxValue(Width) - *C + 1;
}
}
break;
case Intrinsic::umin:
case Intrinsic::umax:
case Intrinsic::smin:
case Intrinsic::smax:
if (!match(II.getOperand(0), m_APInt(C)) &&
!match(II.getOperand(1), m_APInt(C)))
break;
switch (II.getIntrinsicID()) {
case Intrinsic::umin:
Upper = *C + 1;
break;
case Intrinsic::umax:
Lower = *C;
break;
case Intrinsic::smin:
Lower = APInt::getSignedMinValue(Width);
Upper = *C + 1;
break;
case Intrinsic::smax:
Lower = *C;
Upper = APInt::getSignedMaxValue(Width) + 1;
break;
default:
llvm_unreachable("Must be min/max intrinsic");
}
break;
case Intrinsic::abs:
// If abs of SIGNED_MIN is poison, then the result is [0..SIGNED_MAX],
// otherwise it is [0..SIGNED_MIN], as -SIGNED_MIN == SIGNED_MIN.
if (match(II.getOperand(1), m_One()))
Upper = APInt::getSignedMaxValue(Width) + 1;
else
Upper = APInt::getSignedMinValue(Width) + 1;
break;
default:
break;
}
}
static void setLimitsForSelectPattern(const SelectInst &SI, APInt &Lower,
APInt &Upper, const InstrInfoQuery &IIQ) {
const Value *LHS = nullptr, *RHS = nullptr;
SelectPatternResult R = matchSelectPattern(&SI, LHS, RHS);
if (R.Flavor == SPF_UNKNOWN)
return;
unsigned BitWidth = SI.getType()->getScalarSizeInBits();
if (R.Flavor == SelectPatternFlavor::SPF_ABS) {
// If the negation part of the abs (in RHS) has the NSW flag,
// then the result of abs(X) is [0..SIGNED_MAX],
// otherwise it is [0..SIGNED_MIN], as -SIGNED_MIN == SIGNED_MIN.
Lower = APInt::getZero(BitWidth);
if (match(RHS, m_Neg(m_Specific(LHS))) &&
IIQ.hasNoSignedWrap(cast<Instruction>(RHS)))
Upper = APInt::getSignedMaxValue(BitWidth) + 1;
else
Upper = APInt::getSignedMinValue(BitWidth) + 1;
return;
}
if (R.Flavor == SelectPatternFlavor::SPF_NABS) {
// The result of -abs(X) is <= 0.
Lower = APInt::getSignedMinValue(BitWidth);
Upper = APInt(BitWidth, 1);
return;
}
const APInt *C;
if (!match(LHS, m_APInt(C)) && !match(RHS, m_APInt(C)))
return;
switch (R.Flavor) {
case SPF_UMIN:
Upper = *C + 1;
break;
case SPF_UMAX:
Lower = *C;
break;
case SPF_SMIN:
Lower = APInt::getSignedMinValue(BitWidth);
Upper = *C + 1;
break;
case SPF_SMAX:
Lower = *C;
Upper = APInt::getSignedMaxValue(BitWidth) + 1;
break;
default:
break;
}
}
static void setLimitForFPToI(const Instruction *I, APInt &Lower, APInt &Upper) {
// The maximum representable value of a half is 65504. For floats the maximum
// value is 3.4e38 which requires roughly 129 bits.
unsigned BitWidth = I->getType()->getScalarSizeInBits();
if (!I->getOperand(0)->getType()->getScalarType()->isHalfTy())
return;
if (isa<FPToSIInst>(I) && BitWidth >= 17) {
Lower = APInt(BitWidth, -65504);
Upper = APInt(BitWidth, 65505);
}
if (isa<FPToUIInst>(I) && BitWidth >= 16) {
// For a fptoui the lower limit is left as 0.
Upper = APInt(BitWidth, 65505);
}
}
ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
bool UseInstrInfo, AssumptionCache *AC,
const Instruction *CtxI,
const DominatorTree *DT,
unsigned Depth) {
assert(V->getType()->isIntOrIntVectorTy() && "Expected integer instruction");
if (Depth == MaxAnalysisRecursionDepth)
return ConstantRange::getFull(V->getType()->getScalarSizeInBits());
const APInt *C;
if (match(V, m_APInt(C)))
return ConstantRange(*C);
InstrInfoQuery IIQ(UseInstrInfo);
unsigned BitWidth = V->getType()->getScalarSizeInBits();
APInt Lower = APInt(BitWidth, 0);
APInt Upper = APInt(BitWidth, 0);
if (auto *BO = dyn_cast<BinaryOperator>(V))
setLimitsForBinOp(*BO, Lower, Upper, IIQ, ForSigned);
else if (auto *II = dyn_cast<IntrinsicInst>(V))
setLimitsForIntrinsic(*II, Lower, Upper);
else if (auto *SI = dyn_cast<SelectInst>(V))
setLimitsForSelectPattern(*SI, Lower, Upper, IIQ);
else if (isa<FPToUIInst>(V) || isa<FPToSIInst>(V))
setLimitForFPToI(cast<Instruction>(V), Lower, Upper);
ConstantRange CR = ConstantRange::getNonEmpty(Lower, Upper);
if (auto *I = dyn_cast<Instruction>(V))
if (auto *Range = IIQ.getMetadata(I, LLVMContext::MD_range))
CR = CR.intersectWith(getConstantRangeFromMetadata(*Range));
if (CtxI && AC) {
// Try to restrict the range based on information from assumptions.
for (auto &AssumeVH : AC->assumptionsFor(V)) {
if (!AssumeVH)
continue;
CallInst *I = cast<CallInst>(AssumeVH);
assert(I->getParent()->getParent() == CtxI->getParent()->getParent() &&
"Got assumption for the wrong function!");
assert(I->getCalledFunction()->getIntrinsicID() == Intrinsic::assume &&
"must be an assume intrinsic");
if (!isValidAssumeForContext(I, CtxI, DT))
continue;
Value *Arg = I->getArgOperand(0);
ICmpInst *Cmp = dyn_cast<ICmpInst>(Arg);
// Currently we just use information from comparisons.
if (!Cmp || Cmp->getOperand(0) != V)
continue;
// TODO: Set "ForSigned" parameter via Cmp->isSigned()?
ConstantRange RHS =
computeConstantRange(Cmp->getOperand(1), /* ForSigned */ false,
UseInstrInfo, AC, I, DT, Depth + 1);
CR = CR.intersectWith(
ConstantRange::makeAllowedICmpRegion(Cmp->getPredicate(), RHS));
}
}
return CR;
}
static Optional<int64_t>
getOffsetFromIndex(const GEPOperator *GEP, unsigned Idx, const DataLayout &DL) {
// Skip over the first indices.
gep_type_iterator GTI = gep_type_begin(GEP);
for (unsigned i = 1; i != Idx; ++i, ++GTI)
/*skip along*/;
// Compute the offset implied by the rest of the indices.
int64_t Offset = 0;
for (unsigned i = Idx, e = GEP->getNumOperands(); i != e; ++i, ++GTI) {
ConstantInt *OpC = dyn_cast<ConstantInt>(GEP->getOperand(i));
if (!OpC)
return None;
if (OpC->isZero())
continue; // No offset.
// Handle struct indices, which add their field offset to the pointer.
if (StructType *STy = GTI.getStructTypeOrNull()) {
Offset += DL.getStructLayout(STy)->getElementOffset(OpC->getZExtValue());
continue;
}
// Otherwise, we have a sequential type like an array or fixed-length
// vector. Multiply the index by the ElementSize.
TypeSize Size = DL.getTypeAllocSize(GTI.getIndexedType());
if (Size.isScalable())
return None;
Offset += Size.getFixedSize() * OpC->getSExtValue();
}
return Offset;
}
Optional<int64_t> llvm::isPointerOffset(const Value *Ptr1, const Value *Ptr2,
const DataLayout &DL) {
APInt Offset1(DL.getIndexTypeSizeInBits(Ptr1->getType()), 0);
APInt Offset2(DL.getIndexTypeSizeInBits(Ptr2->getType()), 0);
Ptr1 = Ptr1->stripAndAccumulateConstantOffsets(DL, Offset1, true);
Ptr2 = Ptr2->stripAndAccumulateConstantOffsets(DL, Offset2, true);
// Handle the trivial case first.
if (Ptr1 == Ptr2)
return Offset2.getSExtValue() - Offset1.getSExtValue();
const GEPOperator *GEP1 = dyn_cast<GEPOperator>(Ptr1);
const GEPOperator *GEP2 = dyn_cast<GEPOperator>(Ptr2);
// Right now we handle the case when Ptr1/Ptr2 are both GEPs with an identical
// base. After that base, they may have some number of common (and
// potentially variable) indices. After that they handle some constant
// offset, which determines their offset from each other. At this point, we
// handle no other case.
if (!GEP1 || !GEP2 || GEP1->getOperand(0) != GEP2->getOperand(0) ||
GEP1->getSourceElementType() != GEP2->getSourceElementType())
return None;
// Skip any common indices and track the GEP types.
unsigned Idx = 1;
for (; Idx != GEP1->getNumOperands() && Idx != GEP2->getNumOperands(); ++Idx)
if (GEP1->getOperand(Idx) != GEP2->getOperand(Idx))
break;
auto IOffset1 = getOffsetFromIndex(GEP1, Idx, DL);
auto IOffset2 = getOffsetFromIndex(GEP2, Idx, DL);
if (!IOffset1 || !IOffset2)
return None;
return *IOffset2 - *IOffset1 + Offset2.getSExtValue() -
Offset1.getSExtValue();
}
diff --git a/contrib/llvm-project/llvm/lib/CodeGen/DwarfEHPrepare.cpp b/contrib/llvm-project/llvm/lib/CodeGen/DwarfEHPrepare.cpp
index fb8a3e383950..aa81f618dc59 100644
--- a/contrib/llvm-project/llvm/lib/CodeGen/DwarfEHPrepare.cpp
+++ b/contrib/llvm-project/llvm/lib/CodeGen/DwarfEHPrepare.cpp
@@ -1,372 +1,380 @@
//===- DwarfEHPrepare - Prepare exception handling for code generation ----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This pass mulches exception handling code into a form adapted to code
// generation. Required if using dwarf exception handling.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/DomTreeUpdater.h"
#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/CodeGen/RuntimeLibcalls.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Utils/Local.h"
#include <cstddef>
using namespace llvm;
#define DEBUG_TYPE "dwarfehprepare"
STATISTIC(NumResumesLowered, "Number of resume calls lowered");
STATISTIC(NumCleanupLandingPadsUnreachable,
"Number of cleanup landing pads found unreachable");
STATISTIC(NumCleanupLandingPadsRemaining,
"Number of cleanup landing pads remaining");
STATISTIC(NumNoUnwind, "Number of functions with nounwind");
STATISTIC(NumUnwind, "Number of functions with unwind");
namespace {
class DwarfEHPrepare {
CodeGenOpt::Level OptLevel;
Function &F;
const TargetLowering &TLI;
DomTreeUpdater *DTU;
const TargetTransformInfo *TTI;
const Triple &TargetTriple;
/// Return the exception object from the value passed into
/// the 'resume' instruction (typically an aggregate). Clean up any dead
/// instructions, including the 'resume' instruction.
Value *GetExceptionObject(ResumeInst *RI);
/// Replace resumes that are not reachable from a cleanup landing pad with
/// unreachable and then simplify those blocks.
size_t
pruneUnreachableResumes(SmallVectorImpl<ResumeInst *> &Resumes,
SmallVectorImpl<LandingPadInst *> &CleanupLPads);
/// Convert the ResumeInsts that are still present
/// into calls to the appropriate _Unwind_Resume function.
bool InsertUnwindResumeCalls();
public:
DwarfEHPrepare(CodeGenOpt::Level OptLevel_, Function &F_,
const TargetLowering &TLI_, DomTreeUpdater *DTU_,
const TargetTransformInfo *TTI_, const Triple &TargetTriple_)
: OptLevel(OptLevel_), F(F_), TLI(TLI_), DTU(DTU_), TTI(TTI_),
TargetTriple(TargetTriple_) {}
bool run();
};
} // namespace
Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) {
Value *V = RI->getOperand(0);
Value *ExnObj = nullptr;
InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V);
LoadInst *SelLoad = nullptr;
InsertValueInst *ExcIVI = nullptr;
bool EraseIVIs = false;
if (SelIVI) {
if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) {
ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0));
if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) &&
ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) {
ExnObj = ExcIVI->getOperand(1);
SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1));
EraseIVIs = true;
}
}
}
if (!ExnObj)
ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI);
RI->eraseFromParent();
if (EraseIVIs) {
if (SelIVI->use_empty())
SelIVI->eraseFromParent();
if (ExcIVI->use_empty())
ExcIVI->eraseFromParent();
if (SelLoad && SelLoad->use_empty())
SelLoad->eraseFromParent();
}
return ExnObj;
}
size_t DwarfEHPrepare::pruneUnreachableResumes(
SmallVectorImpl<ResumeInst *> &Resumes,
SmallVectorImpl<LandingPadInst *> &CleanupLPads) {
assert(DTU && "Should have DomTreeUpdater here.");
BitVector ResumeReachable(Resumes.size());
size_t ResumeIndex = 0;
for (auto *RI : Resumes) {
for (auto *LP : CleanupLPads) {
if (isPotentiallyReachable(LP, RI, nullptr, &DTU->getDomTree())) {
ResumeReachable.set(ResumeIndex);
break;
}
}
++ResumeIndex;
}
// If everything is reachable, there is no change.
if (ResumeReachable.all())
return Resumes.size();
LLVMContext &Ctx = F.getContext();
// Otherwise, insert unreachable instructions and call simplifycfg.
size_t ResumesLeft = 0;
for (size_t I = 0, E = Resumes.size(); I < E; ++I) {
ResumeInst *RI = Resumes[I];
if (ResumeReachable[I]) {
Resumes[ResumesLeft++] = RI;
} else {
BasicBlock *BB = RI->getParent();
new UnreachableInst(Ctx, RI);
RI->eraseFromParent();
simplifyCFG(BB, *TTI, DTU);
}
}
Resumes.resize(ResumesLeft);
return ResumesLeft;
}
bool DwarfEHPrepare::InsertUnwindResumeCalls() {
SmallVector<ResumeInst *, 16> Resumes;
SmallVector<LandingPadInst *, 16> CleanupLPads;
if (F.doesNotThrow())
NumNoUnwind++;
else
NumUnwind++;
for (BasicBlock &BB : F) {
if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
Resumes.push_back(RI);
if (auto *LP = BB.getLandingPadInst())
if (LP->isCleanup())
CleanupLPads.push_back(LP);
}
NumCleanupLandingPadsRemaining += CleanupLPads.size();
if (Resumes.empty())
return false;
// Check the personality, don't do anything if it's scope-based.
EHPersonality Pers = classifyEHPersonality(F.getPersonalityFn());
if (isScopedEHPersonality(Pers))
return false;
LLVMContext &Ctx = F.getContext();
size_t ResumesLeft = Resumes.size();
if (OptLevel != CodeGenOpt::None) {
ResumesLeft = pruneUnreachableResumes(Resumes, CleanupLPads);
#if LLVM_ENABLE_STATS
unsigned NumRemainingLPs = 0;
for (BasicBlock &BB : F) {
if (auto *LP = BB.getLandingPadInst())
if (LP->isCleanup())
NumRemainingLPs++;
}
NumCleanupLandingPadsUnreachable += CleanupLPads.size() - NumRemainingLPs;
NumCleanupLandingPadsRemaining -= CleanupLPads.size() - NumRemainingLPs;
#endif
}
if (ResumesLeft == 0)
return true; // We pruned them all.
// RewindFunction - _Unwind_Resume or the target equivalent.
FunctionCallee RewindFunction;
CallingConv::ID RewindFunctionCallingConv;
FunctionType *FTy;
const char *RewindName;
bool DoesRewindFunctionNeedExceptionObject;
if ((Pers == EHPersonality::GNU_CXX || Pers == EHPersonality::GNU_CXX_SjLj) &&
TargetTriple.isTargetEHABICompatible()) {
RewindName = TLI.getLibcallName(RTLIB::CXA_END_CLEANUP);
FTy = FunctionType::get(Type::getVoidTy(Ctx), false);
RewindFunctionCallingConv =
TLI.getLibcallCallingConv(RTLIB::CXA_END_CLEANUP);
DoesRewindFunctionNeedExceptionObject = false;
} else {
RewindName = TLI.getLibcallName(RTLIB::UNWIND_RESUME);
FTy =
FunctionType::get(Type::getVoidTy(Ctx), Type::getInt8PtrTy(Ctx), false);
RewindFunctionCallingConv = TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME);
DoesRewindFunctionNeedExceptionObject = true;
}
RewindFunction = F.getParent()->getOrInsertFunction(RewindName, FTy);
// Create the basic block where the _Unwind_Resume call will live.
if (ResumesLeft == 1) {
// Instead of creating a new BB and PHI node, just append the call to
// _Unwind_Resume to the end of the single resume block.
ResumeInst *RI = Resumes.front();
BasicBlock *UnwindBB = RI->getParent();
Value *ExnObj = GetExceptionObject(RI);
llvm::SmallVector<Value *, 1> RewindFunctionArgs;
if (DoesRewindFunctionNeedExceptionObject)
RewindFunctionArgs.push_back(ExnObj);
// Call the rewind function.
CallInst *CI =
CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
+ // The verifier requires that all calls of debug-info-bearing functions
+ // from debug-info-bearing functions have a debug location (for inlining
+ // purposes). Assign a dummy location to satisfy the constraint.
+ Function *RewindFn = dyn_cast<Function>(RewindFunction.getCallee());
+ if (RewindFn && RewindFn->getSubprogram())
+ if (DISubprogram *SP = F.getSubprogram())
+ CI->setDebugLoc(DILocation::get(SP->getContext(), 0, 0, SP));
CI->setCallingConv(RewindFunctionCallingConv);
// We never expect _Unwind_Resume to return.
CI->setDoesNotReturn();
new UnreachableInst(Ctx, UnwindBB);
return true;
}
std::vector<DominatorTree::UpdateType> Updates;
Updates.reserve(Resumes.size());
llvm::SmallVector<Value *, 1> RewindFunctionArgs;
BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &F);
PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesLeft, "exn.obj",
UnwindBB);
// Extract the exception object from the ResumeInst and add it to the PHI node
// that feeds the _Unwind_Resume call.
for (ResumeInst *RI : Resumes) {
BasicBlock *Parent = RI->getParent();
BranchInst::Create(UnwindBB, Parent);
Updates.push_back({DominatorTree::Insert, Parent, UnwindBB});
Value *ExnObj = GetExceptionObject(RI);
PN->addIncoming(ExnObj, Parent);
++NumResumesLowered;
}
if (DoesRewindFunctionNeedExceptionObject)
RewindFunctionArgs.push_back(PN);
// Call the function.
CallInst *CI =
CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
CI->setCallingConv(RewindFunctionCallingConv);
// We never expect _Unwind_Resume to return.
CI->setDoesNotReturn();
new UnreachableInst(Ctx, UnwindBB);
if (DTU)
DTU->applyUpdates(Updates);
return true;
}
bool DwarfEHPrepare::run() {
bool Changed = InsertUnwindResumeCalls();
return Changed;
}
static bool prepareDwarfEH(CodeGenOpt::Level OptLevel, Function &F,
const TargetLowering &TLI, DominatorTree *DT,
const TargetTransformInfo *TTI,
const Triple &TargetTriple) {
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
return DwarfEHPrepare(OptLevel, F, TLI, DT ? &DTU : nullptr, TTI,
TargetTriple)
.run();
}
namespace {
class DwarfEHPrepareLegacyPass : public FunctionPass {
CodeGenOpt::Level OptLevel;
public:
static char ID; // Pass identification, replacement for typeid.
DwarfEHPrepareLegacyPass(CodeGenOpt::Level OptLevel = CodeGenOpt::Default)
: FunctionPass(ID), OptLevel(OptLevel) {}
bool runOnFunction(Function &F) override {
const TargetMachine &TM =
getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
const TargetLowering &TLI = *TM.getSubtargetImpl(F)->getTargetLowering();
DominatorTree *DT = nullptr;
const TargetTransformInfo *TTI = nullptr;
if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
DT = &DTWP->getDomTree();
if (OptLevel != CodeGenOpt::None) {
if (!DT)
DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
}
return prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM.getTargetTriple());
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<TargetPassConfig>();
AU.addRequired<TargetTransformInfoWrapperPass>();
if (OptLevel != CodeGenOpt::None) {
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<TargetTransformInfoWrapperPass>();
}
AU.addPreserved<DominatorTreeWrapperPass>();
}
StringRef getPassName() const override {
return "Exception handling preparation";
}
};
} // end anonymous namespace
char DwarfEHPrepareLegacyPass::ID = 0;
INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
"Prepare DWARF exceptions", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
"Prepare DWARF exceptions", false, false)
FunctionPass *llvm::createDwarfEHPass(CodeGenOpt::Level OptLevel) {
return new DwarfEHPrepareLegacyPass(OptLevel);
}
diff --git a/contrib/llvm-project/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/contrib/llvm-project/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 89a43c4f57f6..85d051cfdbe7 100644
--- a/contrib/llvm-project/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/contrib/llvm-project/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -1,1469 +1,1470 @@
//===- PrologEpilogInserter.cpp - Insert Prolog/Epilog code in function ---===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This pass is responsible for finalizing the functions frame layout, saving
// callee saved registers, and for emitting prolog & epilog code for the
// function.
//
// This pass must be run after register allocation. After this pass is
// executed, it is illegal to construct MO_FrameIndex operands.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/CodeGen/WinEHFuncInfo.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/InitializePasses.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Pass.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <functional>
#include <limits>
#include <utility>
#include <vector>
using namespace llvm;
#define DEBUG_TYPE "prologepilog"
using MBBVector = SmallVector<MachineBasicBlock *, 4>;
STATISTIC(NumLeafFuncWithSpills, "Number of leaf functions with CSRs");
STATISTIC(NumFuncSeen, "Number of functions seen in PEI");
namespace {
class PEI : public MachineFunctionPass {
public:
static char ID;
PEI() : MachineFunctionPass(ID) {
initializePEIPass(*PassRegistry::getPassRegistry());
}
void getAnalysisUsage(AnalysisUsage &AU) const override;
/// runOnMachineFunction - Insert prolog/epilog code and replace abstract
/// frame indexes with appropriate references.
bool runOnMachineFunction(MachineFunction &MF) override;
private:
RegScavenger *RS;
// MinCSFrameIndex, MaxCSFrameIndex - Keeps the range of callee saved
// stack frame indexes.
unsigned MinCSFrameIndex = std::numeric_limits<unsigned>::max();
unsigned MaxCSFrameIndex = 0;
// Save and Restore blocks of the current function. Typically there is a
// single save block, unless Windows EH funclets are involved.
MBBVector SaveBlocks;
MBBVector RestoreBlocks;
// Flag to control whether to use the register scavenger to resolve
// frame index materialization registers. Set according to
// TRI->requiresFrameIndexScavenging() for the current function.
bool FrameIndexVirtualScavenging;
// Flag to control whether the scavenger should be passed even though
// FrameIndexVirtualScavenging is used.
bool FrameIndexEliminationScavenging;
// Emit remarks.
MachineOptimizationRemarkEmitter *ORE = nullptr;
void calculateCallFrameInfo(MachineFunction &MF);
void calculateSaveRestoreBlocks(MachineFunction &MF);
void spillCalleeSavedRegs(MachineFunction &MF);
void calculateFrameObjectOffsets(MachineFunction &MF);
void replaceFrameIndices(MachineFunction &MF);
void replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &MF,
int &SPAdj);
void insertPrologEpilogCode(MachineFunction &MF);
void insertZeroCallUsedRegs(MachineFunction &MF);
};
} // end anonymous namespace
char PEI::ID = 0;
char &llvm::PrologEpilogCodeInserterID = PEI::ID;
INITIALIZE_PASS_BEGIN(PEI, DEBUG_TYPE, "Prologue/Epilogue Insertion", false,
false)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_DEPENDENCY(MachineOptimizationRemarkEmitterPass)
INITIALIZE_PASS_END(PEI, DEBUG_TYPE,
"Prologue/Epilogue Insertion & Frame Finalization", false,
false)
MachineFunctionPass *llvm::createPrologEpilogInserterPass() {
return new PEI();
}
STATISTIC(NumBytesStackSpace,
"Number of bytes used for stack in all functions");
void PEI::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
AU.addPreserved<MachineLoopInfo>();
AU.addPreserved<MachineDominatorTree>();
AU.addRequired<MachineOptimizationRemarkEmitterPass>();
MachineFunctionPass::getAnalysisUsage(AU);
}
/// StackObjSet - A set of stack object indexes
using StackObjSet = SmallSetVector<int, 8>;
using SavedDbgValuesMap =
SmallDenseMap<MachineBasicBlock *, SmallVector<MachineInstr *, 4>, 4>;
/// Stash DBG_VALUEs that describe parameters and which are placed at the start
/// of the block. Later on, after the prologue code has been emitted, the
/// stashed DBG_VALUEs will be reinserted at the start of the block.
static void stashEntryDbgValues(MachineBasicBlock &MBB,
SavedDbgValuesMap &EntryDbgValues) {
SmallVector<const MachineInstr *, 4> FrameIndexValues;
for (auto &MI : MBB) {
if (!MI.isDebugInstr())
break;
if (!MI.isDebugValue() || !MI.getDebugVariable()->isParameter())
continue;
if (any_of(MI.debug_operands(),
[](const MachineOperand &MO) { return MO.isFI(); })) {
// We can only emit valid locations for frame indices after the frame
// setup, so do not stash away them.
FrameIndexValues.push_back(&MI);
continue;
}
const DILocalVariable *Var = MI.getDebugVariable();
const DIExpression *Expr = MI.getDebugExpression();
auto Overlaps = [Var, Expr](const MachineInstr *DV) {
return Var == DV->getDebugVariable() &&
Expr->fragmentsOverlap(DV->getDebugExpression());
};
// See if the debug value overlaps with any preceding debug value that will
// not be stashed. If that is the case, then we can't stash this value, as
// we would then reorder the values at reinsertion.
if (llvm::none_of(FrameIndexValues, Overlaps))
EntryDbgValues[&MBB].push_back(&MI);
}
// Remove stashed debug values from the block.
if (EntryDbgValues.count(&MBB))
for (auto *MI : EntryDbgValues[&MBB])
MI->removeFromParent();
}
/// runOnMachineFunction - Insert prolog/epilog code and replace abstract
/// frame indexes with appropriate references.
bool PEI::runOnMachineFunction(MachineFunction &MF) {
NumFuncSeen++;
const Function &F = MF.getFunction();
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
RS = TRI->requiresRegisterScavenging(MF) ? new RegScavenger() : nullptr;
FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(MF);
ORE = &getAnalysis<MachineOptimizationRemarkEmitterPass>().getORE();
// Calculate the MaxCallFrameSize and AdjustsStack variables for the
// function's frame information. Also eliminates call frame pseudo
// instructions.
calculateCallFrameInfo(MF);
// Determine placement of CSR spill/restore code and prolog/epilog code:
// place all spills in the entry block, all restores in return blocks.
calculateSaveRestoreBlocks(MF);
// Stash away DBG_VALUEs that should not be moved by insertion of prolog code.
SavedDbgValuesMap EntryDbgValues;
for (MachineBasicBlock *SaveBlock : SaveBlocks)
stashEntryDbgValues(*SaveBlock, EntryDbgValues);
// Handle CSR spilling and restoring, for targets that need it.
if (MF.getTarget().usesPhysRegsForValues())
spillCalleeSavedRegs(MF);
// Allow the target machine to make final modifications to the function
// before the frame layout is finalized.
TFI->processFunctionBeforeFrameFinalized(MF, RS);
// Calculate actual frame offsets for all abstract stack objects...
calculateFrameObjectOffsets(MF);
// Add prolog and epilog code to the function. This function is required
// to align the stack frame as necessary for any stack variables or
// called functions. Because of this, calculateCalleeSavedRegisters()
// must be called before this function in order to set the AdjustsStack
// and MaxCallFrameSize variables.
if (!F.hasFnAttribute(Attribute::Naked))
insertPrologEpilogCode(MF);
// Reinsert stashed debug values at the start of the entry blocks.
for (auto &I : EntryDbgValues)
I.first->insert(I.first->begin(), I.second.begin(), I.second.end());
// Allow the target machine to make final modifications to the function
// before the frame layout is finalized.
TFI->processFunctionBeforeFrameIndicesReplaced(MF, RS);
// Replace all MO_FrameIndex operands with physical register references
// and actual offsets.
//
replaceFrameIndices(MF);
// If register scavenging is needed, as we've enabled doing it as a
// post-pass, scavenge the virtual registers that frame index elimination
// inserted.
if (TRI->requiresRegisterScavenging(MF) && FrameIndexVirtualScavenging)
scavengeFrameVirtualRegs(MF, *RS);
// Warn on stack size when we exceeds the given limit.
MachineFrameInfo &MFI = MF.getFrameInfo();
uint64_t StackSize = MFI.getStackSize();
unsigned Threshold = UINT_MAX;
if (MF.getFunction().hasFnAttribute("warn-stack-size")) {
bool Failed = MF.getFunction()
.getFnAttribute("warn-stack-size")
.getValueAsString()
.getAsInteger(10, Threshold);
// Verifier should have caught this.
assert(!Failed && "Invalid warn-stack-size fn attr value");
(void)Failed;
}
if (MF.getFunction().hasFnAttribute(Attribute::SafeStack)) {
StackSize += MFI.getUnsafeStackSize();
}
if (StackSize > Threshold) {
DiagnosticInfoStackSize DiagStackSize(F, StackSize, Threshold, DS_Warning);
F.getContext().diagnose(DiagStackSize);
}
ORE->emit([&]() {
return MachineOptimizationRemarkAnalysis(DEBUG_TYPE, "StackSize",
MF.getFunction().getSubprogram(),
&MF.front())
<< ore::NV("NumStackBytes", StackSize) << " stack bytes in function";
});
delete RS;
SaveBlocks.clear();
RestoreBlocks.clear();
MFI.setSavePoint(nullptr);
MFI.setRestorePoint(nullptr);
return true;
}
/// Calculate the MaxCallFrameSize and AdjustsStack
/// variables for the function's frame information and eliminate call frame
/// pseudo instructions.
void PEI::calculateCallFrameInfo(MachineFunction &MF) {
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned MaxCallFrameSize = 0;
bool AdjustsStack = MFI.adjustsStack();
// Get the function call frame set-up and tear-down instruction opcode
unsigned FrameSetupOpcode = TII.getCallFrameSetupOpcode();
unsigned FrameDestroyOpcode = TII.getCallFrameDestroyOpcode();
// Early exit for targets which have no call frame setup/destroy pseudo
// instructions.
if (FrameSetupOpcode == ~0u && FrameDestroyOpcode == ~0u)
return;
std::vector<MachineBasicBlock::iterator> FrameSDOps;
for (MachineBasicBlock &BB : MF)
for (MachineBasicBlock::iterator I = BB.begin(); I != BB.end(); ++I)
if (TII.isFrameInstr(*I)) {
unsigned Size = TII.getFrameSize(*I);
if (Size > MaxCallFrameSize) MaxCallFrameSize = Size;
AdjustsStack = true;
FrameSDOps.push_back(I);
} else if (I->isInlineAsm()) {
// Some inline asm's need a stack frame, as indicated by operand 1.
unsigned ExtraInfo = I->getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
if (ExtraInfo & InlineAsm::Extra_IsAlignStack)
AdjustsStack = true;
}
assert(!MFI.isMaxCallFrameSizeComputed() ||
(MFI.getMaxCallFrameSize() == MaxCallFrameSize &&
MFI.adjustsStack() == AdjustsStack));
MFI.setAdjustsStack(AdjustsStack);
MFI.setMaxCallFrameSize(MaxCallFrameSize);
for (MachineBasicBlock::iterator I : FrameSDOps) {
// If call frames are not being included as part of the stack frame, and
// the target doesn't indicate otherwise, remove the call frame pseudos
// here. The sub/add sp instruction pairs are still inserted, but we don't
// need to track the SP adjustment for frame index elimination.
if (TFI->canSimplifyCallFramePseudos(MF))
TFI->eliminateCallFramePseudoInstr(MF, *I->getParent(), I);
}
}
/// Compute the sets of entry and return blocks for saving and restoring
/// callee-saved registers, and placing prolog and epilog code.
void PEI::calculateSaveRestoreBlocks(MachineFunction &MF) {
const MachineFrameInfo &MFI = MF.getFrameInfo();
// Even when we do not change any CSR, we still want to insert the
// prologue and epilogue of the function.
// So set the save points for those.
// Use the points found by shrink-wrapping, if any.
if (MFI.getSavePoint()) {
SaveBlocks.push_back(MFI.getSavePoint());
assert(MFI.getRestorePoint() && "Both restore and save must be set");
MachineBasicBlock *RestoreBlock = MFI.getRestorePoint();
// If RestoreBlock does not have any successor and is not a return block
// then the end point is unreachable and we do not need to insert any
// epilogue.
if (!RestoreBlock->succ_empty() || RestoreBlock->isReturnBlock())
RestoreBlocks.push_back(RestoreBlock);
return;
}
// Save refs to entry and return blocks.
SaveBlocks.push_back(&MF.front());
for (MachineBasicBlock &MBB : MF) {
if (MBB.isEHFuncletEntry())
SaveBlocks.push_back(&MBB);
if (MBB.isReturnBlock())
RestoreBlocks.push_back(&MBB);
}
}
static void assignCalleeSavedSpillSlots(MachineFunction &F,
const BitVector &SavedRegs,
unsigned &MinCSFrameIndex,
unsigned &MaxCSFrameIndex) {
if (SavedRegs.empty())
return;
const TargetRegisterInfo *RegInfo = F.getSubtarget().getRegisterInfo();
const MCPhysReg *CSRegs = F.getRegInfo().getCalleeSavedRegs();
BitVector CSMask(SavedRegs.size());
for (unsigned i = 0; CSRegs[i]; ++i)
CSMask.set(CSRegs[i]);
std::vector<CalleeSavedInfo> CSI;
for (unsigned i = 0; CSRegs[i]; ++i) {
unsigned Reg = CSRegs[i];
if (SavedRegs.test(Reg)) {
bool SavedSuper = false;
for (const MCPhysReg &SuperReg : RegInfo->superregs(Reg)) {
// Some backends set all aliases for some registers as saved, such as
// Mips's $fp, so they appear in SavedRegs but not CSRegs.
if (SavedRegs.test(SuperReg) && CSMask.test(SuperReg)) {
SavedSuper = true;
break;
}
}
if (!SavedSuper)
CSI.push_back(CalleeSavedInfo(Reg));
}
}
const TargetFrameLowering *TFI = F.getSubtarget().getFrameLowering();
MachineFrameInfo &MFI = F.getFrameInfo();
if (!TFI->assignCalleeSavedSpillSlots(F, RegInfo, CSI, MinCSFrameIndex,
MaxCSFrameIndex)) {
// If target doesn't implement this, use generic code.
if (CSI.empty())
return; // Early exit if no callee saved registers are modified!
unsigned NumFixedSpillSlots;
const TargetFrameLowering::SpillSlot *FixedSpillSlots =
TFI->getCalleeSavedSpillSlots(NumFixedSpillSlots);
// Now that we know which registers need to be saved and restored, allocate
// stack slots for them.
for (auto &CS : CSI) {
// If the target has spilled this register to another register, we don't
// need to allocate a stack slot.
if (CS.isSpilledToReg())
continue;
unsigned Reg = CS.getReg();
const TargetRegisterClass *RC = RegInfo->getMinimalPhysRegClass(Reg);
int FrameIdx;
if (RegInfo->hasReservedSpillSlot(F, Reg, FrameIdx)) {
CS.setFrameIdx(FrameIdx);
continue;
}
// Check to see if this physreg must be spilled to a particular stack slot
// on this target.
const TargetFrameLowering::SpillSlot *FixedSlot = FixedSpillSlots;
while (FixedSlot != FixedSpillSlots + NumFixedSpillSlots &&
FixedSlot->Reg != Reg)
++FixedSlot;
unsigned Size = RegInfo->getSpillSize(*RC);
if (FixedSlot == FixedSpillSlots + NumFixedSpillSlots) {
// Nope, just spill it anywhere convenient.
Align Alignment = RegInfo->getSpillAlign(*RC);
// We may not be able to satisfy the desired alignment specification of
// the TargetRegisterClass if the stack alignment is smaller. Use the
// min.
Alignment = std::min(Alignment, TFI->getStackAlign());
FrameIdx = MFI.CreateStackObject(Size, Alignment, true);
if ((unsigned)FrameIdx < MinCSFrameIndex) MinCSFrameIndex = FrameIdx;
if ((unsigned)FrameIdx > MaxCSFrameIndex) MaxCSFrameIndex = FrameIdx;
} else {
// Spill it to the stack where we must.
FrameIdx = MFI.CreateFixedSpillStackObject(Size, FixedSlot->Offset);
}
CS.setFrameIdx(FrameIdx);
}
}
MFI.setCalleeSavedInfo(CSI);
}
/// Helper function to update the liveness information for the callee-saved
/// registers.
static void updateLiveness(MachineFunction &MF) {
MachineFrameInfo &MFI = MF.getFrameInfo();
// Visited will contain all the basic blocks that are in the region
// where the callee saved registers are alive:
// - Anything that is not Save or Restore -> LiveThrough.
// - Save -> LiveIn.
// - Restore -> LiveOut.
// The live-out is not attached to the block, so no need to keep
// Restore in this set.
SmallPtrSet<MachineBasicBlock *, 8> Visited;
SmallVector<MachineBasicBlock *, 8> WorkList;
MachineBasicBlock *Entry = &MF.front();
MachineBasicBlock *Save = MFI.getSavePoint();
if (!Save)
Save = Entry;
if (Entry != Save) {
WorkList.push_back(Entry);
Visited.insert(Entry);
}
Visited.insert(Save);
MachineBasicBlock *Restore = MFI.getRestorePoint();
if (Restore)
// By construction Restore cannot be visited, otherwise it
// means there exists a path to Restore that does not go
// through Save.
WorkList.push_back(Restore);
while (!WorkList.empty()) {
const MachineBasicBlock *CurBB = WorkList.pop_back_val();
// By construction, the region that is after the save point is
// dominated by the Save and post-dominated by the Restore.
if (CurBB == Save && Save != Restore)
continue;
// Enqueue all the successors not already visited.
// Those are by construction either before Save or after Restore.
for (MachineBasicBlock *SuccBB : CurBB->successors())
if (Visited.insert(SuccBB).second)
WorkList.push_back(SuccBB);
}
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
MachineRegisterInfo &MRI = MF.getRegInfo();
for (const CalleeSavedInfo &I : CSI) {
for (MachineBasicBlock *MBB : Visited) {
MCPhysReg Reg = I.getReg();
// Add the callee-saved register as live-in.
// It's killed at the spill.
if (!MRI.isReserved(Reg) && !MBB->isLiveIn(Reg))
MBB->addLiveIn(Reg);
}
// If callee-saved register is spilled to another register rather than
// spilling to stack, the destination register has to be marked as live for
// each MBB between the prologue and epilogue so that it is not clobbered
// before it is reloaded in the epilogue. The Visited set contains all
// blocks outside of the region delimited by prologue/epilogue.
if (I.isSpilledToReg()) {
for (MachineBasicBlock &MBB : MF) {
if (Visited.count(&MBB))
continue;
MCPhysReg DstReg = I.getDstReg();
if (!MBB.isLiveIn(DstReg))
MBB.addLiveIn(DstReg);
}
}
}
}
/// Insert spill code for the callee-saved registers used in the function.
static void insertCSRSaves(MachineBasicBlock &SaveBlock,
ArrayRef<CalleeSavedInfo> CSI) {
MachineFunction &MF = *SaveBlock.getParent();
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
MachineBasicBlock::iterator I = SaveBlock.begin();
if (!TFI->spillCalleeSavedRegisters(SaveBlock, I, CSI, TRI)) {
for (const CalleeSavedInfo &CS : CSI) {
// Insert the spill to the stack frame.
unsigned Reg = CS.getReg();
if (CS.isSpilledToReg()) {
BuildMI(SaveBlock, I, DebugLoc(),
TII.get(TargetOpcode::COPY), CS.getDstReg())
.addReg(Reg, getKillRegState(true));
} else {
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.storeRegToStackSlot(SaveBlock, I, Reg, true, CS.getFrameIdx(), RC,
TRI);
}
}
}
}
/// Insert restore code for the callee-saved registers used in the function.
static void insertCSRRestores(MachineBasicBlock &RestoreBlock,
std::vector<CalleeSavedInfo> &CSI) {
MachineFunction &MF = *RestoreBlock.getParent();
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
// Restore all registers immediately before the return and any
// terminators that precede it.
MachineBasicBlock::iterator I = RestoreBlock.getFirstTerminator();
if (!TFI->restoreCalleeSavedRegisters(RestoreBlock, I, CSI, TRI)) {
for (const CalleeSavedInfo &CI : reverse(CSI)) {
unsigned Reg = CI.getReg();
if (CI.isSpilledToReg()) {
BuildMI(RestoreBlock, I, DebugLoc(), TII.get(TargetOpcode::COPY), Reg)
.addReg(CI.getDstReg(), getKillRegState(true));
} else {
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.loadRegFromStackSlot(RestoreBlock, I, Reg, CI.getFrameIdx(), RC, TRI);
assert(I != RestoreBlock.begin() &&
"loadRegFromStackSlot didn't insert any code!");
// Insert in reverse order. loadRegFromStackSlot can insert
// multiple instructions.
}
}
}
}
void PEI::spillCalleeSavedRegs(MachineFunction &MF) {
// We can't list this requirement in getRequiredProperties because some
// targets (WebAssembly) use virtual registers past this point, and the pass
// pipeline is set up without giving the passes a chance to look at the
// TargetMachine.
// FIXME: Find a way to express this in getRequiredProperties.
assert(MF.getProperties().hasProperty(
MachineFunctionProperties::Property::NoVRegs));
const Function &F = MF.getFunction();
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
MachineFrameInfo &MFI = MF.getFrameInfo();
MinCSFrameIndex = std::numeric_limits<unsigned>::max();
MaxCSFrameIndex = 0;
// Determine which of the registers in the callee save list should be saved.
BitVector SavedRegs;
TFI->determineCalleeSaves(MF, SavedRegs, RS);
// Assign stack slots for any callee-saved registers that must be spilled.
assignCalleeSavedSpillSlots(MF, SavedRegs, MinCSFrameIndex, MaxCSFrameIndex);
// Add the code to save and restore the callee saved registers.
if (!F.hasFnAttribute(Attribute::Naked)) {
MFI.setCalleeSavedInfoValid(true);
std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
if (!CSI.empty()) {
if (!MFI.hasCalls())
NumLeafFuncWithSpills++;
for (MachineBasicBlock *SaveBlock : SaveBlocks)
insertCSRSaves(*SaveBlock, CSI);
// Update the live-in information of all the blocks up to the save point.
updateLiveness(MF);
for (MachineBasicBlock *RestoreBlock : RestoreBlocks)
insertCSRRestores(*RestoreBlock, CSI);
}
}
}
/// AdjustStackOffset - Helper function used to adjust the stack frame offset.
static inline void AdjustStackOffset(MachineFrameInfo &MFI, int FrameIdx,
bool StackGrowsDown, int64_t &Offset,
Align &MaxAlign, unsigned Skew) {
// If the stack grows down, add the object size to find the lowest address.
if (StackGrowsDown)
Offset += MFI.getObjectSize(FrameIdx);
Align Alignment = MFI.getObjectAlign(FrameIdx);
// If the alignment of this object is greater than that of the stack, then
// increase the stack alignment to match.
MaxAlign = std::max(MaxAlign, Alignment);
// Adjust to alignment boundary.
Offset = alignTo(Offset, Alignment, Skew);
if (StackGrowsDown) {
LLVM_DEBUG(dbgs() << "alloc FI(" << FrameIdx << ") at SP[" << -Offset
<< "]\n");
MFI.setObjectOffset(FrameIdx, -Offset); // Set the computed offset
} else {
LLVM_DEBUG(dbgs() << "alloc FI(" << FrameIdx << ") at SP[" << Offset
<< "]\n");
MFI.setObjectOffset(FrameIdx, Offset);
Offset += MFI.getObjectSize(FrameIdx);
}
}
/// Compute which bytes of fixed and callee-save stack area are unused and keep
/// track of them in StackBytesFree.
static inline void
computeFreeStackSlots(MachineFrameInfo &MFI, bool StackGrowsDown,
unsigned MinCSFrameIndex, unsigned MaxCSFrameIndex,
int64_t FixedCSEnd, BitVector &StackBytesFree) {
// Avoid undefined int64_t -> int conversion below in extreme case.
if (FixedCSEnd > std::numeric_limits<int>::max())
return;
StackBytesFree.resize(FixedCSEnd, true);
SmallVector<int, 16> AllocatedFrameSlots;
// Add fixed objects.
for (int i = MFI.getObjectIndexBegin(); i != 0; ++i)
// StackSlot scavenging is only implemented for the default stack.
if (MFI.getStackID(i) == TargetStackID::Default)
AllocatedFrameSlots.push_back(i);
// Add callee-save objects if there are any.
if (MinCSFrameIndex <= MaxCSFrameIndex) {
for (int i = MinCSFrameIndex; i <= (int)MaxCSFrameIndex; ++i)
if (MFI.getStackID(i) == TargetStackID::Default)
AllocatedFrameSlots.push_back(i);
}
for (int i : AllocatedFrameSlots) {
// These are converted from int64_t, but they should always fit in int
// because of the FixedCSEnd check above.
int ObjOffset = MFI.getObjectOffset(i);
int ObjSize = MFI.getObjectSize(i);
int ObjStart, ObjEnd;
if (StackGrowsDown) {
// ObjOffset is negative when StackGrowsDown is true.
ObjStart = -ObjOffset - ObjSize;
ObjEnd = -ObjOffset;
} else {
ObjStart = ObjOffset;
ObjEnd = ObjOffset + ObjSize;
}
// Ignore fixed holes that are in the previous stack frame.
if (ObjEnd > 0)
StackBytesFree.reset(ObjStart, ObjEnd);
}
}
/// Assign frame object to an unused portion of the stack in the fixed stack
/// object range. Return true if the allocation was successful.
static inline bool scavengeStackSlot(MachineFrameInfo &MFI, int FrameIdx,
bool StackGrowsDown, Align MaxAlign,
BitVector &StackBytesFree) {
if (MFI.isVariableSizedObjectIndex(FrameIdx))
return false;
if (StackBytesFree.none()) {
// clear it to speed up later scavengeStackSlot calls to
// StackBytesFree.none()
StackBytesFree.clear();
return false;
}
Align ObjAlign = MFI.getObjectAlign(FrameIdx);
if (ObjAlign > MaxAlign)
return false;
int64_t ObjSize = MFI.getObjectSize(FrameIdx);
int FreeStart;
for (FreeStart = StackBytesFree.find_first(); FreeStart != -1;
FreeStart = StackBytesFree.find_next(FreeStart)) {
// Check that free space has suitable alignment.
unsigned ObjStart = StackGrowsDown ? FreeStart + ObjSize : FreeStart;
if (alignTo(ObjStart, ObjAlign) != ObjStart)
continue;
if (FreeStart + ObjSize > StackBytesFree.size())
return false;
bool AllBytesFree = true;
for (unsigned Byte = 0; Byte < ObjSize; ++Byte)
if (!StackBytesFree.test(FreeStart + Byte)) {
AllBytesFree = false;
break;
}
if (AllBytesFree)
break;
}
if (FreeStart == -1)
return false;
if (StackGrowsDown) {
int ObjStart = -(FreeStart + ObjSize);
LLVM_DEBUG(dbgs() << "alloc FI(" << FrameIdx << ") scavenged at SP["
<< ObjStart << "]\n");
MFI.setObjectOffset(FrameIdx, ObjStart);
} else {
LLVM_DEBUG(dbgs() << "alloc FI(" << FrameIdx << ") scavenged at SP["
<< FreeStart << "]\n");
MFI.setObjectOffset(FrameIdx, FreeStart);
}
StackBytesFree.reset(FreeStart, FreeStart + ObjSize);
return true;
}
/// AssignProtectedObjSet - Helper function to assign large stack objects (i.e.,
/// those required to be close to the Stack Protector) to stack offsets.
static void AssignProtectedObjSet(const StackObjSet &UnassignedObjs,
SmallSet<int, 16> &ProtectedObjs,
MachineFrameInfo &MFI, bool StackGrowsDown,
int64_t &Offset, Align &MaxAlign,
unsigned Skew) {
for (int i : UnassignedObjs) {
AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign, Skew);
ProtectedObjs.insert(i);
}
}
/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the
/// abstract stack objects.
void PEI::calculateFrameObjectOffsets(MachineFunction &MF) {
const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering();
bool StackGrowsDown =
TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown;
// Loop over all of the stack objects, assigning sequential addresses...
MachineFrameInfo &MFI = MF.getFrameInfo();
// Start at the beginning of the local area.
// The Offset is the distance from the stack top in the direction
// of stack growth -- so it's always nonnegative.
int LocalAreaOffset = TFI.getOffsetOfLocalArea();
if (StackGrowsDown)
LocalAreaOffset = -LocalAreaOffset;
assert(LocalAreaOffset >= 0
&& "Local area offset should be in direction of stack growth");
int64_t Offset = LocalAreaOffset;
// Skew to be applied to alignment.
unsigned Skew = TFI.getStackAlignmentSkew(MF);
#ifdef EXPENSIVE_CHECKS
for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i)
if (!MFI.isDeadObjectIndex(i) &&
MFI.getStackID(i) == TargetStackID::Default)
assert(MFI.getObjectAlign(i) <= MFI.getMaxAlign() &&
"MaxAlignment is invalid");
#endif
// If there are fixed sized objects that are preallocated in the local area,
// non-fixed objects can't be allocated right at the start of local area.
// Adjust 'Offset' to point to the end of last fixed sized preallocated
// object.
for (int i = MFI.getObjectIndexBegin(); i != 0; ++i) {
// Only allocate objects on the default stack.
if (MFI.getStackID(i) != TargetStackID::Default)
continue;
int64_t FixedOff;
if (StackGrowsDown) {
// The maximum distance from the stack pointer is at lower address of
// the object -- which is given by offset. For down growing stack
// the offset is negative, so we negate the offset to get the distance.
FixedOff = -MFI.getObjectOffset(i);
} else {
// The maximum distance from the start pointer is at the upper
// address of the object.
FixedOff = MFI.getObjectOffset(i) + MFI.getObjectSize(i);
}
if (FixedOff > Offset) Offset = FixedOff;
}
Align MaxAlign = MFI.getMaxAlign();
// First assign frame offsets to stack objects that are used to spill
// callee saved registers.
if (MaxCSFrameIndex >= MinCSFrameIndex) {
for (unsigned i = 0; i <= MaxCSFrameIndex - MinCSFrameIndex; ++i) {
unsigned FrameIndex =
StackGrowsDown ? MinCSFrameIndex + i : MaxCSFrameIndex - i;
// Only allocate objects on the default stack.
if (MFI.getStackID(FrameIndex) != TargetStackID::Default)
continue;
// TODO: should this just be if (MFI.isDeadObjectIndex(FrameIndex))
if (!StackGrowsDown && MFI.isDeadObjectIndex(FrameIndex))
continue;
AdjustStackOffset(MFI, FrameIndex, StackGrowsDown, Offset, MaxAlign,
Skew);
}
}
assert(MaxAlign == MFI.getMaxAlign() &&
"MFI.getMaxAlign should already account for all callee-saved "
"registers without a fixed stack slot");
// FixedCSEnd is the stack offset to the end of the fixed and callee-save
// stack area.
int64_t FixedCSEnd = Offset;
// Make sure the special register scavenging spill slot is closest to the
// incoming stack pointer if a frame pointer is required and is closer
// to the incoming rather than the final stack pointer.
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
bool EarlyScavengingSlots = TFI.allocateScavengingFrameIndexesNearIncomingSP(MF);
if (RS && EarlyScavengingSlots) {
SmallVector<int, 2> SFIs;
RS->getScavengingFrameIndices(SFIs);
for (int SFI : SFIs)
AdjustStackOffset(MFI, SFI, StackGrowsDown, Offset, MaxAlign, Skew);
}
// FIXME: Once this is working, then enable flag will change to a target
// check for whether the frame is large enough to want to use virtual
// frame index registers. Functions which don't want/need this optimization
// will continue to use the existing code path.
if (MFI.getUseLocalStackAllocationBlock()) {
Align Alignment = MFI.getLocalFrameMaxAlign();
// Adjust to alignment boundary.
Offset = alignTo(Offset, Alignment, Skew);
LLVM_DEBUG(dbgs() << "Local frame base offset: " << Offset << "\n");
// Resolve offsets for objects in the local block.
for (unsigned i = 0, e = MFI.getLocalFrameObjectCount(); i != e; ++i) {
std::pair<int, int64_t> Entry = MFI.getLocalFrameObjectMap(i);
int64_t FIOffset = (StackGrowsDown ? -Offset : Offset) + Entry.second;
LLVM_DEBUG(dbgs() << "alloc FI(" << Entry.first << ") at SP[" << FIOffset
<< "]\n");
MFI.setObjectOffset(Entry.first, FIOffset);
}
// Allocate the local block
Offset += MFI.getLocalFrameSize();
MaxAlign = std::max(Alignment, MaxAlign);
}
// Retrieve the Exception Handler registration node.
int EHRegNodeFrameIndex = std::numeric_limits<int>::max();
if (const WinEHFuncInfo *FuncInfo = MF.getWinEHFuncInfo())
EHRegNodeFrameIndex = FuncInfo->EHRegNodeFrameIndex;
// Make sure that the stack protector comes before the local variables on the
// stack.
SmallSet<int, 16> ProtectedObjs;
if (MFI.hasStackProtectorIndex()) {
int StackProtectorFI = MFI.getStackProtectorIndex();
StackObjSet LargeArrayObjs;
StackObjSet SmallArrayObjs;
StackObjSet AddrOfObjs;
// If we need a stack protector, we need to make sure that
// LocalStackSlotPass didn't already allocate a slot for it.
// If we are told to use the LocalStackAllocationBlock, the stack protector
// is expected to be already pre-allocated.
if (MFI.getStackID(StackProtectorFI) != TargetStackID::Default) {
// If the stack protector isn't on the default stack then it's up to the
// target to set the stack offset.
assert(MFI.getObjectOffset(StackProtectorFI) != 0 &&
"Offset of stack protector on non-default stack expected to be "
"already set.");
assert(!MFI.isObjectPreAllocated(MFI.getStackProtectorIndex()) &&
"Stack protector on non-default stack expected to not be "
"pre-allocated by LocalStackSlotPass.");
} else if (!MFI.getUseLocalStackAllocationBlock()) {
AdjustStackOffset(MFI, StackProtectorFI, StackGrowsDown, Offset, MaxAlign,
Skew);
} else if (!MFI.isObjectPreAllocated(MFI.getStackProtectorIndex())) {
llvm_unreachable(
"Stack protector not pre-allocated by LocalStackSlotPass.");
}
// Assign large stack objects first.
for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
if (MFI.isObjectPreAllocated(i) && MFI.getUseLocalStackAllocationBlock())
continue;
if (i >= MinCSFrameIndex && i <= MaxCSFrameIndex)
continue;
if (RS && RS->isScavengingFrameIndex((int)i))
continue;
if (MFI.isDeadObjectIndex(i))
continue;
if (StackProtectorFI == (int)i || EHRegNodeFrameIndex == (int)i)
continue;
// Only allocate objects on the default stack.
if (MFI.getStackID(i) != TargetStackID::Default)
continue;
switch (MFI.getObjectSSPLayout(i)) {
case MachineFrameInfo::SSPLK_None:
continue;
case MachineFrameInfo::SSPLK_SmallArray:
SmallArrayObjs.insert(i);
continue;
case MachineFrameInfo::SSPLK_AddrOf:
AddrOfObjs.insert(i);
continue;
case MachineFrameInfo::SSPLK_LargeArray:
LargeArrayObjs.insert(i);
continue;
}
llvm_unreachable("Unexpected SSPLayoutKind.");
}
// We expect **all** the protected stack objects to be pre-allocated by
// LocalStackSlotPass. If it turns out that PEI still has to allocate some
// of them, we may end up messing up the expected order of the objects.
if (MFI.getUseLocalStackAllocationBlock() &&
!(LargeArrayObjs.empty() && SmallArrayObjs.empty() &&
AddrOfObjs.empty()))
llvm_unreachable("Found protected stack objects not pre-allocated by "
"LocalStackSlotPass.");
AssignProtectedObjSet(LargeArrayObjs, ProtectedObjs, MFI, StackGrowsDown,
Offset, MaxAlign, Skew);
AssignProtectedObjSet(SmallArrayObjs, ProtectedObjs, MFI, StackGrowsDown,
Offset, MaxAlign, Skew);
AssignProtectedObjSet(AddrOfObjs, ProtectedObjs, MFI, StackGrowsDown,
Offset, MaxAlign, Skew);
}
SmallVector<int, 8> ObjectsToAllocate;
// Then prepare to assign frame offsets to stack objects that are not used to
// spill callee saved registers.
for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
if (MFI.isObjectPreAllocated(i) && MFI.getUseLocalStackAllocationBlock())
continue;
if (i >= MinCSFrameIndex && i <= MaxCSFrameIndex)
continue;
if (RS && RS->isScavengingFrameIndex((int)i))
continue;
if (MFI.isDeadObjectIndex(i))
continue;
if (MFI.getStackProtectorIndex() == (int)i || EHRegNodeFrameIndex == (int)i)
continue;
if (ProtectedObjs.count(i))
continue;
// Only allocate objects on the default stack.
if (MFI.getStackID(i) != TargetStackID::Default)
continue;
// Add the objects that we need to allocate to our working set.
ObjectsToAllocate.push_back(i);
}
// Allocate the EH registration node first if one is present.
if (EHRegNodeFrameIndex != std::numeric_limits<int>::max())
AdjustStackOffset(MFI, EHRegNodeFrameIndex, StackGrowsDown, Offset,
MaxAlign, Skew);
// Give the targets a chance to order the objects the way they like it.
if (MF.getTarget().getOptLevel() != CodeGenOpt::None &&
MF.getTarget().Options.StackSymbolOrdering)
TFI.orderFrameObjects(MF, ObjectsToAllocate);
// Keep track of which bytes in the fixed and callee-save range are used so we
// can use the holes when allocating later stack objects. Only do this if
// stack protector isn't being used and the target requests it and we're
// optimizing.
BitVector StackBytesFree;
if (!ObjectsToAllocate.empty() &&
MF.getTarget().getOptLevel() != CodeGenOpt::None &&
MFI.getStackProtectorIndex() < 0 && TFI.enableStackSlotScavenging(MF))
computeFreeStackSlots(MFI, StackGrowsDown, MinCSFrameIndex, MaxCSFrameIndex,
FixedCSEnd, StackBytesFree);
// Now walk the objects and actually assign base offsets to them.
for (auto &Object : ObjectsToAllocate)
if (!scavengeStackSlot(MFI, Object, StackGrowsDown, MaxAlign,
StackBytesFree))
AdjustStackOffset(MFI, Object, StackGrowsDown, Offset, MaxAlign, Skew);
// Make sure the special register scavenging spill slot is closest to the
// stack pointer.
if (RS && !EarlyScavengingSlots) {
SmallVector<int, 2> SFIs;
RS->getScavengingFrameIndices(SFIs);
for (int SFI : SFIs)
AdjustStackOffset(MFI, SFI, StackGrowsDown, Offset, MaxAlign, Skew);
}
if (!TFI.targetHandlesStackFrameRounding()) {
// If we have reserved argument space for call sites in the function
// immediately on entry to the current function, count it as part of the
// overall stack size.
if (MFI.adjustsStack() && TFI.hasReservedCallFrame(MF))
Offset += MFI.getMaxCallFrameSize();
// Round up the size to a multiple of the alignment. If the function has
// any calls or alloca's, align to the target's StackAlignment value to
// ensure that the callee's frame or the alloca data is suitably aligned;
// otherwise, for leaf functions, align to the TransientStackAlignment
// value.
Align StackAlign;
if (MFI.adjustsStack() || MFI.hasVarSizedObjects() ||
(RegInfo->hasStackRealignment(MF) && MFI.getObjectIndexEnd() != 0))
StackAlign = TFI.getStackAlign();
else
StackAlign = TFI.getTransientStackAlign();
// If the frame pointer is eliminated, all frame offsets will be relative to
// SP not FP. Align to MaxAlign so this works.
StackAlign = std::max(StackAlign, MaxAlign);
int64_t OffsetBeforeAlignment = Offset;
Offset = alignTo(Offset, StackAlign, Skew);
// If we have increased the offset to fulfill the alignment constrants,
// then the scavenging spill slots may become harder to reach from the
// stack pointer, float them so they stay close.
if (StackGrowsDown && OffsetBeforeAlignment != Offset && RS &&
!EarlyScavengingSlots) {
SmallVector<int, 2> SFIs;
RS->getScavengingFrameIndices(SFIs);
LLVM_DEBUG(if (!SFIs.empty()) llvm::dbgs()
<< "Adjusting emergency spill slots!\n";);
int64_t Delta = Offset - OffsetBeforeAlignment;
for (int SFI : SFIs) {
LLVM_DEBUG(llvm::dbgs()
<< "Adjusting offset of emergency spill slot #" << SFI
<< " from " << MFI.getObjectOffset(SFI););
MFI.setObjectOffset(SFI, MFI.getObjectOffset(SFI) - Delta);
LLVM_DEBUG(llvm::dbgs() << " to " << MFI.getObjectOffset(SFI) << "\n";);
}
}
}
// Update frame info to pretend that this is part of the stack...
int64_t StackSize = Offset - LocalAreaOffset;
MFI.setStackSize(StackSize);
NumBytesStackSpace += StackSize;
}
/// insertPrologEpilogCode - Scan the function for modified callee saved
/// registers, insert spill code for these callee saved registers, then add
/// prolog and epilog code to the function.
void PEI::insertPrologEpilogCode(MachineFunction &MF) {
const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering();
// Add prologue to the function...
for (MachineBasicBlock *SaveBlock : SaveBlocks)
TFI.emitPrologue(MF, *SaveBlock);
// Add epilogue to restore the callee-save registers in each exiting block.
for (MachineBasicBlock *RestoreBlock : RestoreBlocks)
TFI.emitEpilogue(MF, *RestoreBlock);
// Zero call used registers before restoring callee-saved registers.
insertZeroCallUsedRegs(MF);
for (MachineBasicBlock *SaveBlock : SaveBlocks)
TFI.inlineStackProbe(MF, *SaveBlock);
// Emit additional code that is required to support segmented stacks, if
// we've been asked for it. This, when linked with a runtime with support
// for segmented stacks (libgcc is one), will result in allocating stack
// space in small chunks instead of one large contiguous block.
if (MF.shouldSplitStack()) {
for (MachineBasicBlock *SaveBlock : SaveBlocks)
TFI.adjustForSegmentedStacks(MF, *SaveBlock);
}
// Emit additional code that is required to explicitly handle the stack in
// HiPE native code (if needed) when loaded in the Erlang/OTP runtime. The
// approach is rather similar to that of Segmented Stacks, but it uses a
// different conditional check and another BIF for allocating more stack
// space.
if (MF.getFunction().getCallingConv() == CallingConv::HiPE)
for (MachineBasicBlock *SaveBlock : SaveBlocks)
TFI.adjustForHiPEPrologue(MF, *SaveBlock);
}
/// insertZeroCallUsedRegs - Zero out call used registers.
void PEI::insertZeroCallUsedRegs(MachineFunction &MF) {
const Function &F = MF.getFunction();
if (!F.hasFnAttribute("zero-call-used-regs"))
return;
using namespace ZeroCallUsedRegs;
ZeroCallUsedRegsKind ZeroRegsKind =
StringSwitch<ZeroCallUsedRegsKind>(
F.getFnAttribute("zero-call-used-regs").getValueAsString())
.Case("skip", ZeroCallUsedRegsKind::Skip)
.Case("used-gpr-arg", ZeroCallUsedRegsKind::UsedGPRArg)
.Case("used-gpr", ZeroCallUsedRegsKind::UsedGPR)
.Case("used-arg", ZeroCallUsedRegsKind::UsedArg)
.Case("used", ZeroCallUsedRegsKind::Used)
.Case("all-gpr-arg", ZeroCallUsedRegsKind::AllGPRArg)
.Case("all-gpr", ZeroCallUsedRegsKind::AllGPR)
.Case("all-arg", ZeroCallUsedRegsKind::AllArg)
.Case("all", ZeroCallUsedRegsKind::All);
if (ZeroRegsKind == ZeroCallUsedRegsKind::Skip)
return;
const bool OnlyGPR = static_cast<unsigned>(ZeroRegsKind) & ONLY_GPR;
const bool OnlyUsed = static_cast<unsigned>(ZeroRegsKind) & ONLY_USED;
const bool OnlyArg = static_cast<unsigned>(ZeroRegsKind) & ONLY_ARG;
const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
const BitVector AllocatableSet(TRI.getAllocatableSet(MF));
// Mark all used registers.
BitVector UsedRegs(TRI.getNumRegs());
if (OnlyUsed)
for (const MachineBasicBlock &MBB : MF)
for (const MachineInstr &MI : MBB)
for (const MachineOperand &MO : MI.operands()) {
if (!MO.isReg())
continue;
MCRegister Reg = MO.getReg();
if (AllocatableSet[Reg] && !MO.isImplicit() &&
(MO.isDef() || MO.isUse()))
UsedRegs.set(Reg);
}
BitVector RegsToZero(TRI.getNumRegs());
for (MCRegister Reg : AllocatableSet.set_bits()) {
// Skip over fixed registers.
if (TRI.isFixedRegister(MF, Reg))
continue;
// Want only general purpose registers.
if (OnlyGPR && !TRI.isGeneralPurposeRegister(MF, Reg))
continue;
// Want only used registers.
if (OnlyUsed && !UsedRegs[Reg])
continue;
// Want only registers used for arguments.
if (OnlyArg && !TRI.isArgumentRegister(MF, Reg))
continue;
RegsToZero.set(Reg);
}
// Don't clear registers that are live when leaving the function.
for (const MachineBasicBlock &MBB : MF)
for (const MachineInstr &MI : MBB.terminators()) {
if (!MI.isReturn())
continue;
for (const auto &MO : MI.operands()) {
if (!MO.isReg())
continue;
for (MCPhysReg SReg : TRI.sub_and_superregs_inclusive(MO.getReg()))
RegsToZero.reset(SReg);
}
}
// Don't need to clear registers that are used/clobbered by terminating
// instructions.
for (const MachineBasicBlock &MBB : MF) {
if (!MBB.isReturnBlock())
continue;
MachineBasicBlock::const_iterator MBBI = MBB.getFirstTerminator();
for (MachineBasicBlock::const_iterator I = MBBI, E = MBB.end(); I != E;
++I) {
for (const MachineOperand &MO : I->operands()) {
if (!MO.isReg())
continue;
for (const MCPhysReg &Reg :
TRI.sub_and_superregs_inclusive(MO.getReg()))
RegsToZero.reset(Reg);
}
}
}
- // Don't clear registers that are reset before exiting.
- for (const CalleeSavedInfo &CSI : MF.getFrameInfo().getCalleeSavedInfo())
- for (MCRegister Reg : TRI.sub_and_superregs_inclusive(CSI.getReg()))
+ // Don't clear registers that must be preserved.
+ for (const MCPhysReg *CSRegs = TRI.getCalleeSavedRegs(&MF);
+ MCPhysReg CSReg = *CSRegs; ++CSRegs)
+ for (MCRegister Reg : TRI.sub_and_superregs_inclusive(CSReg))
RegsToZero.reset(Reg);
const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering();
for (MachineBasicBlock &MBB : MF)
if (MBB.isReturnBlock())
TFI.emitZeroCallUsedRegs(RegsToZero, MBB);
}
/// replaceFrameIndices - Replace all MO_FrameIndex operands with physical
/// register references and actual offsets.
void PEI::replaceFrameIndices(MachineFunction &MF) {
const auto &ST = MF.getSubtarget();
const TargetFrameLowering &TFI = *ST.getFrameLowering();
if (!TFI.needsFrameIndexResolution(MF))
return;
const TargetRegisterInfo *TRI = ST.getRegisterInfo();
// Allow the target to determine this after knowing the frame size.
FrameIndexEliminationScavenging = (RS && !FrameIndexVirtualScavenging) ||
TRI->requiresFrameIndexReplacementScavenging(MF);
// Store SPAdj at exit of a basic block.
SmallVector<int, 8> SPState;
SPState.resize(MF.getNumBlockIDs());
df_iterator_default_set<MachineBasicBlock*> Reachable;
// Iterate over the reachable blocks in DFS order.
for (auto DFI = df_ext_begin(&MF, Reachable), DFE = df_ext_end(&MF, Reachable);
DFI != DFE; ++DFI) {
int SPAdj = 0;
// Check the exit state of the DFS stack predecessor.
if (DFI.getPathLength() >= 2) {
MachineBasicBlock *StackPred = DFI.getPath(DFI.getPathLength() - 2);
assert(Reachable.count(StackPred) &&
"DFS stack predecessor is already visited.\n");
SPAdj = SPState[StackPred->getNumber()];
}
MachineBasicBlock *BB = *DFI;
replaceFrameIndices(BB, MF, SPAdj);
SPState[BB->getNumber()] = SPAdj;
}
// Handle the unreachable blocks.
for (auto &BB : MF) {
if (Reachable.count(&BB))
// Already handled in DFS traversal.
continue;
int SPAdj = 0;
replaceFrameIndices(&BB, MF, SPAdj);
}
}
void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &MF,
int &SPAdj) {
assert(MF.getSubtarget().getRegisterInfo() &&
"getRegisterInfo() must be implemented!");
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
if (RS && FrameIndexEliminationScavenging)
RS->enterBasicBlock(*BB);
bool InsideCallSequence = false;
for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) {
if (TII.isFrameInstr(*I)) {
InsideCallSequence = TII.isFrameSetup(*I);
SPAdj += TII.getSPAdjust(*I);
I = TFI->eliminateCallFramePseudoInstr(MF, *BB, I);
continue;
}
MachineInstr &MI = *I;
bool DoIncr = true;
bool DidFinishLoop = true;
for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
if (!MI.getOperand(i).isFI())
continue;
// Frame indices in debug values are encoded in a target independent
// way with simply the frame index and offset rather than any
// target-specific addressing mode.
if (MI.isDebugValue()) {
MachineOperand &Op = MI.getOperand(i);
assert(
MI.isDebugOperand(&Op) &&
"Frame indices can only appear as a debug operand in a DBG_VALUE*"
" machine instruction");
Register Reg;
unsigned FrameIdx = Op.getIndex();
unsigned Size = MF.getFrameInfo().getObjectSize(FrameIdx);
StackOffset Offset =
TFI->getFrameIndexReference(MF, FrameIdx, Reg);
Op.ChangeToRegister(Reg, false /*isDef*/);
const DIExpression *DIExpr = MI.getDebugExpression();
// If we have a direct DBG_VALUE, and its location expression isn't
// currently complex, then adding an offset will morph it into a
// complex location that is interpreted as being a memory address.
// This changes a pointer-valued variable to dereference that pointer,
// which is incorrect. Fix by adding DW_OP_stack_value.
if (MI.isNonListDebugValue()) {
unsigned PrependFlags = DIExpression::ApplyOffset;
if (!MI.isIndirectDebugValue() && !DIExpr->isComplex())
PrependFlags |= DIExpression::StackValue;
// If we have DBG_VALUE that is indirect and has a Implicit location
// expression need to insert a deref before prepending a Memory
// location expression. Also after doing this we change the DBG_VALUE
// to be direct.
if (MI.isIndirectDebugValue() && DIExpr->isImplicit()) {
SmallVector<uint64_t, 2> Ops = {dwarf::DW_OP_deref_size, Size};
bool WithStackValue = true;
DIExpr = DIExpression::prependOpcodes(DIExpr, Ops, WithStackValue);
// Make the DBG_VALUE direct.
MI.getDebugOffset().ChangeToRegister(0, false);
}
DIExpr = TRI.prependOffsetExpression(DIExpr, PrependFlags, Offset);
} else {
// The debug operand at DebugOpIndex was a frame index at offset
// `Offset`; now the operand has been replaced with the frame
// register, we must add Offset with `register x, plus Offset`.
unsigned DebugOpIndex = MI.getDebugOperandIndex(&Op);
SmallVector<uint64_t, 3> Ops;
TRI.getOffsetOpcodes(Offset, Ops);
DIExpr = DIExpression::appendOpsToArg(DIExpr, Ops, DebugOpIndex);
}
MI.getDebugExpressionOp().setMetadata(DIExpr);
continue;
} else if (MI.isDebugPHI()) {
// Allow stack ref to continue onwards.
continue;
}
// TODO: This code should be commoned with the code for
// PATCHPOINT. There's no good reason for the difference in
// implementation other than historical accident. The only
// remaining difference is the unconditional use of the stack
// pointer as the base register.
if (MI.getOpcode() == TargetOpcode::STATEPOINT) {
assert((!MI.isDebugValue() || i == 0) &&
"Frame indicies can only appear as the first operand of a "
"DBG_VALUE machine instruction");
Register Reg;
MachineOperand &Offset = MI.getOperand(i + 1);
StackOffset refOffset = TFI->getFrameIndexReferencePreferSP(
MF, MI.getOperand(i).getIndex(), Reg, /*IgnoreSPUpdates*/ false);
assert(!refOffset.getScalable() &&
"Frame offsets with a scalable component are not supported");
Offset.setImm(Offset.getImm() + refOffset.getFixed() + SPAdj);
MI.getOperand(i).ChangeToRegister(Reg, false /*isDef*/);
continue;
}
// Some instructions (e.g. inline asm instructions) can have
// multiple frame indices and/or cause eliminateFrameIndex
// to insert more than one instruction. We need the register
// scavenger to go through all of these instructions so that
// it can update its register information. We keep the
// iterator at the point before insertion so that we can
// revisit them in full.
bool AtBeginning = (I == BB->begin());
if (!AtBeginning) --I;
// If this instruction has a FrameIndex operand, we need to
// use that target machine register info object to eliminate
// it.
TRI.eliminateFrameIndex(MI, SPAdj, i,
FrameIndexEliminationScavenging ? RS : nullptr);
// Reset the iterator if we were at the beginning of the BB.
if (AtBeginning) {
I = BB->begin();
DoIncr = false;
}
DidFinishLoop = false;
break;
}
// If we are looking at a call sequence, we need to keep track of
// the SP adjustment made by each instruction in the sequence.
// This includes both the frame setup/destroy pseudos (handled above),
// as well as other instructions that have side effects w.r.t the SP.
// Note that this must come after eliminateFrameIndex, because
// if I itself referred to a frame index, we shouldn't count its own
// adjustment.
if (DidFinishLoop && InsideCallSequence)
SPAdj += TII.getSPAdjust(MI);
if (DoIncr && I != BB->end()) ++I;
// Update register states.
if (RS && FrameIndexEliminationScavenging && DidFinishLoop)
RS->forward(MI);
}
}
diff --git a/contrib/llvm-project/llvm/lib/Support/X86TargetParser.cpp b/contrib/llvm-project/llvm/lib/Support/X86TargetParser.cpp
index 2567f3ed8034..0daaa6d815bf 100644
--- a/contrib/llvm-project/llvm/lib/Support/X86TargetParser.cpp
+++ b/contrib/llvm-project/llvm/lib/Support/X86TargetParser.cpp
@@ -1,711 +1,711 @@
//===-- X86TargetParser - Parser for X86 features ---------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements a target parser to recognise X86 hardware features.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/X86TargetParser.h"
#include "llvm/ADT/StringSwitch.h"
#include <numeric>
using namespace llvm;
using namespace llvm::X86;
namespace {
/// Container class for CPU features.
/// This is a constexpr reimplementation of a subset of std::bitset. It would be
/// nice to use std::bitset directly, but it doesn't support constant
/// initialization.
class FeatureBitset {
static constexpr unsigned NUM_FEATURE_WORDS =
(X86::CPU_FEATURE_MAX + 31) / 32;
// This cannot be a std::array, operator[] is not constexpr until C++17.
uint32_t Bits[NUM_FEATURE_WORDS] = {};
public:
constexpr FeatureBitset() = default;
constexpr FeatureBitset(std::initializer_list<unsigned> Init) {
for (auto I : Init)
set(I);
}
bool any() const {
return llvm::any_of(Bits, [](uint64_t V) { return V != 0; });
}
constexpr FeatureBitset &set(unsigned I) {
// GCC <6.2 crashes if this is written in a single statement.
uint32_t NewBits = Bits[I / 32] | (uint32_t(1) << (I % 32));
Bits[I / 32] = NewBits;
return *this;
}
constexpr bool operator[](unsigned I) const {
uint32_t Mask = uint32_t(1) << (I % 32);
return (Bits[I / 32] & Mask) != 0;
}
constexpr FeatureBitset &operator&=(const FeatureBitset &RHS) {
for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) {
// GCC <6.2 crashes if this is written in a single statement.
uint32_t NewBits = Bits[I] & RHS.Bits[I];
Bits[I] = NewBits;
}
return *this;
}
constexpr FeatureBitset &operator|=(const FeatureBitset &RHS) {
for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) {
// GCC <6.2 crashes if this is written in a single statement.
uint32_t NewBits = Bits[I] | RHS.Bits[I];
Bits[I] = NewBits;
}
return *this;
}
// gcc 5.3 miscompiles this if we try to write this using operator&=.
constexpr FeatureBitset operator&(const FeatureBitset &RHS) const {
FeatureBitset Result;
for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I)
Result.Bits[I] = Bits[I] & RHS.Bits[I];
return Result;
}
// gcc 5.3 miscompiles this if we try to write this using operator&=.
constexpr FeatureBitset operator|(const FeatureBitset &RHS) const {
FeatureBitset Result;
for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I)
Result.Bits[I] = Bits[I] | RHS.Bits[I];
return Result;
}
constexpr FeatureBitset operator~() const {
FeatureBitset Result;
for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I)
Result.Bits[I] = ~Bits[I];
return Result;
}
constexpr bool operator!=(const FeatureBitset &RHS) const {
for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I)
if (Bits[I] != RHS.Bits[I])
return true;
return false;
}
};
struct ProcInfo {
StringLiteral Name;
X86::CPUKind Kind;
unsigned KeyFeature;
FeatureBitset Features;
};
struct FeatureInfo {
StringLiteral Name;
FeatureBitset ImpliedFeatures;
};
} // end anonymous namespace
#define X86_FEATURE(ENUM, STRING) \
constexpr FeatureBitset Feature##ENUM = {X86::FEATURE_##ENUM};
#include "llvm/Support/X86TargetParser.def"
// Pentium with MMX.
constexpr FeatureBitset FeaturesPentiumMMX =
FeatureX87 | FeatureCMPXCHG8B | FeatureMMX;
// Pentium 2 and 3.
constexpr FeatureBitset FeaturesPentium2 =
FeatureX87 | FeatureCMPXCHG8B | FeatureMMX | FeatureFXSR;
constexpr FeatureBitset FeaturesPentium3 = FeaturesPentium2 | FeatureSSE;
// Pentium 4 CPUs
constexpr FeatureBitset FeaturesPentium4 = FeaturesPentium3 | FeatureSSE2;
constexpr FeatureBitset FeaturesPrescott = FeaturesPentium4 | FeatureSSE3;
constexpr FeatureBitset FeaturesNocona =
FeaturesPrescott | Feature64BIT | FeatureCMPXCHG16B;
// Basic 64-bit capable CPU.
constexpr FeatureBitset FeaturesX86_64 = FeaturesPentium4 | Feature64BIT;
constexpr FeatureBitset FeaturesX86_64_V2 = FeaturesX86_64 | FeatureSAHF |
FeaturePOPCNT | FeatureCRC32 |
FeatureSSE4_2 | FeatureCMPXCHG16B;
constexpr FeatureBitset FeaturesX86_64_V3 =
FeaturesX86_64_V2 | FeatureAVX2 | FeatureBMI | FeatureBMI2 | FeatureF16C |
FeatureFMA | FeatureLZCNT | FeatureMOVBE | FeatureXSAVE;
constexpr FeatureBitset FeaturesX86_64_V4 = FeaturesX86_64_V3 |
FeatureAVX512BW | FeatureAVX512CD |
FeatureAVX512DQ | FeatureAVX512VL;
// Intel Core CPUs
constexpr FeatureBitset FeaturesCore2 =
FeaturesNocona | FeatureSAHF | FeatureSSSE3;
constexpr FeatureBitset FeaturesPenryn = FeaturesCore2 | FeatureSSE4_1;
constexpr FeatureBitset FeaturesNehalem =
FeaturesPenryn | FeaturePOPCNT | FeatureCRC32 | FeatureSSE4_2;
constexpr FeatureBitset FeaturesWestmere = FeaturesNehalem | FeaturePCLMUL;
constexpr FeatureBitset FeaturesSandyBridge =
FeaturesWestmere | FeatureAVX | FeatureXSAVE | FeatureXSAVEOPT;
constexpr FeatureBitset FeaturesIvyBridge =
FeaturesSandyBridge | FeatureF16C | FeatureFSGSBASE | FeatureRDRND;
constexpr FeatureBitset FeaturesHaswell =
FeaturesIvyBridge | FeatureAVX2 | FeatureBMI | FeatureBMI2 | FeatureFMA |
FeatureINVPCID | FeatureLZCNT | FeatureMOVBE;
constexpr FeatureBitset FeaturesBroadwell =
FeaturesHaswell | FeatureADX | FeaturePRFCHW | FeatureRDSEED;
// Intel Knights Landing and Knights Mill
// Knights Landing has feature parity with Broadwell.
constexpr FeatureBitset FeaturesKNL =
FeaturesBroadwell | FeatureAES | FeatureAVX512F | FeatureAVX512CD |
FeatureAVX512ER | FeatureAVX512PF | FeaturePREFETCHWT1;
constexpr FeatureBitset FeaturesKNM = FeaturesKNL | FeatureAVX512VPOPCNTDQ;
// Intel Skylake processors.
constexpr FeatureBitset FeaturesSkylakeClient =
FeaturesBroadwell | FeatureAES | FeatureCLFLUSHOPT | FeatureXSAVEC |
FeatureXSAVES | FeatureSGX;
// SkylakeServer inherits all SkylakeClient features except SGX.
// FIXME: That doesn't match gcc.
constexpr FeatureBitset FeaturesSkylakeServer =
(FeaturesSkylakeClient & ~FeatureSGX) | FeatureAVX512F | FeatureAVX512CD |
FeatureAVX512DQ | FeatureAVX512BW | FeatureAVX512VL | FeatureCLWB |
FeaturePKU;
constexpr FeatureBitset FeaturesCascadeLake =
FeaturesSkylakeServer | FeatureAVX512VNNI;
constexpr FeatureBitset FeaturesCooperLake =
FeaturesCascadeLake | FeatureAVX512BF16;
// Intel 10nm processors.
constexpr FeatureBitset FeaturesCannonlake =
FeaturesSkylakeClient | FeatureAVX512F | FeatureAVX512CD | FeatureAVX512DQ |
FeatureAVX512BW | FeatureAVX512VL | FeatureAVX512IFMA | FeatureAVX512VBMI |
FeaturePKU | FeatureSHA;
constexpr FeatureBitset FeaturesICLClient =
FeaturesCannonlake | FeatureAVX512BITALG | FeatureAVX512VBMI2 |
FeatureAVX512VNNI | FeatureAVX512VPOPCNTDQ | FeatureGFNI | FeatureRDPID |
FeatureVAES | FeatureVPCLMULQDQ;
constexpr FeatureBitset FeaturesRocketlake = FeaturesICLClient & ~FeatureSGX;
constexpr FeatureBitset FeaturesICLServer =
FeaturesICLClient | FeatureCLWB | FeaturePCONFIG | FeatureWBNOINVD;
constexpr FeatureBitset FeaturesTigerlake =
FeaturesICLClient | FeatureAVX512VP2INTERSECT | FeatureMOVDIR64B |
FeatureCLWB | FeatureMOVDIRI | FeatureSHSTK | FeatureKL | FeatureWIDEKL;
constexpr FeatureBitset FeaturesSapphireRapids =
FeaturesICLServer | FeatureAMX_BF16 | FeatureAMX_INT8 | FeatureAMX_TILE |
- FeatureAVX512BF16 | FeatureAVX512FP16 | FeatureAVX512VP2INTERSECT |
- FeatureAVXVNNI | FeatureCLDEMOTE | FeatureENQCMD | FeatureMOVDIR64B |
- FeatureMOVDIRI | FeaturePTWRITE | FeatureSERIALIZE | FeatureSHSTK |
- FeatureTSXLDTRK | FeatureUINTR | FeatureWAITPKG;
+ FeatureAVX512BF16 | FeatureAVX512FP16 | FeatureAVXVNNI | FeatureCLDEMOTE |
+ FeatureENQCMD | FeatureMOVDIR64B | FeatureMOVDIRI | FeaturePTWRITE |
+ FeatureSERIALIZE | FeatureSHSTK | FeatureTSXLDTRK | FeatureUINTR |
+ FeatureWAITPKG;
// Intel Atom processors.
// Bonnell has feature parity with Core2 and adds MOVBE.
constexpr FeatureBitset FeaturesBonnell = FeaturesCore2 | FeatureMOVBE;
// Silvermont has parity with Westmere and Bonnell plus PRFCHW and RDRND.
constexpr FeatureBitset FeaturesSilvermont =
FeaturesBonnell | FeaturesWestmere | FeaturePRFCHW | FeatureRDRND;
constexpr FeatureBitset FeaturesGoldmont =
FeaturesSilvermont | FeatureAES | FeatureCLFLUSHOPT | FeatureFSGSBASE |
FeatureRDSEED | FeatureSHA | FeatureXSAVE | FeatureXSAVEC |
FeatureXSAVEOPT | FeatureXSAVES;
constexpr FeatureBitset FeaturesGoldmontPlus =
FeaturesGoldmont | FeaturePTWRITE | FeatureRDPID | FeatureSGX;
constexpr FeatureBitset FeaturesTremont =
FeaturesGoldmontPlus | FeatureCLWB | FeatureGFNI;
constexpr FeatureBitset FeaturesAlderlake =
FeaturesTremont | FeatureADX | FeatureBMI | FeatureBMI2 | FeatureF16C |
FeatureFMA | FeatureINVPCID | FeatureLZCNT | FeaturePCONFIG | FeaturePKU |
FeatureSERIALIZE | FeatureSHSTK | FeatureVAES | FeatureVPCLMULQDQ |
FeatureCLDEMOTE | FeatureMOVDIR64B | FeatureMOVDIRI | FeatureWAITPKG |
FeatureAVXVNNI | FeatureHRESET | FeatureWIDEKL;
// Geode Processor.
constexpr FeatureBitset FeaturesGeode =
FeatureX87 | FeatureCMPXCHG8B | FeatureMMX | Feature3DNOW | Feature3DNOWA;
// K6 processor.
constexpr FeatureBitset FeaturesK6 = FeatureX87 | FeatureCMPXCHG8B | FeatureMMX;
// K7 and K8 architecture processors.
constexpr FeatureBitset FeaturesAthlon =
FeatureX87 | FeatureCMPXCHG8B | FeatureMMX | Feature3DNOW | Feature3DNOWA;
constexpr FeatureBitset FeaturesAthlonXP =
FeaturesAthlon | FeatureFXSR | FeatureSSE;
constexpr FeatureBitset FeaturesK8 =
FeaturesAthlonXP | FeatureSSE2 | Feature64BIT;
constexpr FeatureBitset FeaturesK8SSE3 = FeaturesK8 | FeatureSSE3;
constexpr FeatureBitset FeaturesAMDFAM10 =
FeaturesK8SSE3 | FeatureCMPXCHG16B | FeatureLZCNT | FeaturePOPCNT |
FeaturePRFCHW | FeatureSAHF | FeatureSSE4_A;
// Bobcat architecture processors.
constexpr FeatureBitset FeaturesBTVER1 =
FeatureX87 | FeatureCMPXCHG8B | FeatureCMPXCHG16B | Feature64BIT |
FeatureFXSR | FeatureLZCNT | FeatureMMX | FeaturePOPCNT | FeaturePRFCHW |
FeatureSSE | FeatureSSE2 | FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_A |
FeatureSAHF;
constexpr FeatureBitset FeaturesBTVER2 =
FeaturesBTVER1 | FeatureAES | FeatureAVX | FeatureBMI | FeatureCRC32 |
FeatureF16C | FeatureMOVBE | FeaturePCLMUL | FeatureXSAVE | FeatureXSAVEOPT;
// AMD Bulldozer architecture processors.
constexpr FeatureBitset FeaturesBDVER1 =
FeatureX87 | FeatureAES | FeatureAVX | FeatureCMPXCHG8B |
FeatureCMPXCHG16B | FeatureCRC32 | Feature64BIT | FeatureFMA4 |
FeatureFXSR | FeatureLWP | FeatureLZCNT | FeatureMMX | FeaturePCLMUL |
FeaturePOPCNT | FeaturePRFCHW | FeatureSAHF | FeatureSSE | FeatureSSE2 |
FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_1 | FeatureSSE4_2 | FeatureSSE4_A |
FeatureXOP | FeatureXSAVE;
constexpr FeatureBitset FeaturesBDVER2 =
FeaturesBDVER1 | FeatureBMI | FeatureFMA | FeatureF16C | FeatureTBM;
constexpr FeatureBitset FeaturesBDVER3 =
FeaturesBDVER2 | FeatureFSGSBASE | FeatureXSAVEOPT;
constexpr FeatureBitset FeaturesBDVER4 = FeaturesBDVER3 | FeatureAVX2 |
FeatureBMI2 | FeatureMOVBE |
FeatureMWAITX | FeatureRDRND;
// AMD Zen architecture processors.
constexpr FeatureBitset FeaturesZNVER1 =
FeatureX87 | FeatureADX | FeatureAES | FeatureAVX | FeatureAVX2 |
FeatureBMI | FeatureBMI2 | FeatureCLFLUSHOPT | FeatureCLZERO |
FeatureCMPXCHG8B | FeatureCMPXCHG16B | FeatureCRC32 | Feature64BIT |
FeatureF16C | FeatureFMA | FeatureFSGSBASE | FeatureFXSR | FeatureLZCNT |
FeatureMMX | FeatureMOVBE | FeatureMWAITX | FeaturePCLMUL | FeaturePOPCNT |
FeaturePRFCHW | FeatureRDRND | FeatureRDSEED | FeatureSAHF | FeatureSHA |
FeatureSSE | FeatureSSE2 | FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_1 |
FeatureSSE4_2 | FeatureSSE4_A | FeatureXSAVE | FeatureXSAVEC |
FeatureXSAVEOPT | FeatureXSAVES;
constexpr FeatureBitset FeaturesZNVER2 = FeaturesZNVER1 | FeatureCLWB |
FeatureRDPID | FeatureRDPRU |
FeatureWBNOINVD;
static constexpr FeatureBitset FeaturesZNVER3 = FeaturesZNVER2 |
FeatureINVPCID | FeaturePKU |
FeatureVAES | FeatureVPCLMULQDQ;
constexpr ProcInfo Processors[] = {
// Empty processor. Include X87 and CMPXCHG8 for backwards compatibility.
{ {""}, CK_None, ~0U, FeatureX87 | FeatureCMPXCHG8B },
// i386-generation processors.
{ {"i386"}, CK_i386, ~0U, FeatureX87 },
// i486-generation processors.
{ {"i486"}, CK_i486, ~0U, FeatureX87 },
{ {"winchip-c6"}, CK_WinChipC6, ~0U, FeaturesPentiumMMX },
{ {"winchip2"}, CK_WinChip2, ~0U, FeaturesPentiumMMX | Feature3DNOW },
{ {"c3"}, CK_C3, ~0U, FeaturesPentiumMMX | Feature3DNOW },
// i586-generation processors, P5 microarchitecture based.
{ {"i586"}, CK_i586, ~0U, FeatureX87 | FeatureCMPXCHG8B },
{ {"pentium"}, CK_Pentium, ~0U, FeatureX87 | FeatureCMPXCHG8B },
{ {"pentium-mmx"}, CK_PentiumMMX, ~0U, FeaturesPentiumMMX },
// i686-generation processors, P6 / Pentium M microarchitecture based.
{ {"pentiumpro"}, CK_PentiumPro, ~0U, FeatureX87 | FeatureCMPXCHG8B },
{ {"i686"}, CK_i686, ~0U, FeatureX87 | FeatureCMPXCHG8B },
{ {"pentium2"}, CK_Pentium2, ~0U, FeaturesPentium2 },
{ {"pentium3"}, CK_Pentium3, ~0U, FeaturesPentium3 },
{ {"pentium3m"}, CK_Pentium3, ~0U, FeaturesPentium3 },
{ {"pentium-m"}, CK_PentiumM, ~0U, FeaturesPentium4 },
{ {"c3-2"}, CK_C3_2, ~0U, FeaturesPentium3 },
{ {"yonah"}, CK_Yonah, ~0U, FeaturesPrescott },
// Netburst microarchitecture based processors.
{ {"pentium4"}, CK_Pentium4, ~0U, FeaturesPentium4 },
{ {"pentium4m"}, CK_Pentium4, ~0U, FeaturesPentium4 },
{ {"prescott"}, CK_Prescott, ~0U, FeaturesPrescott },
{ {"nocona"}, CK_Nocona, ~0U, FeaturesNocona },
// Core microarchitecture based processors.
{ {"core2"}, CK_Core2, ~0U, FeaturesCore2 },
{ {"penryn"}, CK_Penryn, ~0U, FeaturesPenryn },
// Atom processors
{ {"bonnell"}, CK_Bonnell, FEATURE_SSSE3, FeaturesBonnell },
{ {"atom"}, CK_Bonnell, FEATURE_SSSE3, FeaturesBonnell },
{ {"silvermont"}, CK_Silvermont, FEATURE_SSE4_2, FeaturesSilvermont },
{ {"slm"}, CK_Silvermont, FEATURE_SSE4_2, FeaturesSilvermont },
{ {"goldmont"}, CK_Goldmont, FEATURE_SSE4_2, FeaturesGoldmont },
{ {"goldmont-plus"}, CK_GoldmontPlus, FEATURE_SSE4_2, FeaturesGoldmontPlus },
{ {"tremont"}, CK_Tremont, FEATURE_SSE4_2, FeaturesTremont },
// Nehalem microarchitecture based processors.
{ {"nehalem"}, CK_Nehalem, FEATURE_SSE4_2, FeaturesNehalem },
{ {"corei7"}, CK_Nehalem, FEATURE_SSE4_2, FeaturesNehalem },
// Westmere microarchitecture based processors.
{ {"westmere"}, CK_Westmere, FEATURE_PCLMUL, FeaturesWestmere },
// Sandy Bridge microarchitecture based processors.
{ {"sandybridge"}, CK_SandyBridge, FEATURE_AVX, FeaturesSandyBridge },
{ {"corei7-avx"}, CK_SandyBridge, FEATURE_AVX, FeaturesSandyBridge },
// Ivy Bridge microarchitecture based processors.
{ {"ivybridge"}, CK_IvyBridge, FEATURE_AVX, FeaturesIvyBridge },
{ {"core-avx-i"}, CK_IvyBridge, FEATURE_AVX, FeaturesIvyBridge },
// Haswell microarchitecture based processors.
{ {"haswell"}, CK_Haswell, FEATURE_AVX2, FeaturesHaswell },
{ {"core-avx2"}, CK_Haswell, FEATURE_AVX2, FeaturesHaswell },
// Broadwell microarchitecture based processors.
{ {"broadwell"}, CK_Broadwell, FEATURE_AVX2, FeaturesBroadwell },
// Skylake client microarchitecture based processors.
{ {"skylake"}, CK_SkylakeClient, FEATURE_AVX2, FeaturesSkylakeClient },
// Skylake server microarchitecture based processors.
{ {"skylake-avx512"}, CK_SkylakeServer, FEATURE_AVX512F, FeaturesSkylakeServer },
{ {"skx"}, CK_SkylakeServer, FEATURE_AVX512F, FeaturesSkylakeServer },
// Cascadelake Server microarchitecture based processors.
{ {"cascadelake"}, CK_Cascadelake, FEATURE_AVX512VNNI, FeaturesCascadeLake },
// Cooperlake Server microarchitecture based processors.
{ {"cooperlake"}, CK_Cooperlake, FEATURE_AVX512BF16, FeaturesCooperLake },
// Cannonlake client microarchitecture based processors.
{ {"cannonlake"}, CK_Cannonlake, FEATURE_AVX512VBMI, FeaturesCannonlake },
// Icelake client microarchitecture based processors.
{ {"icelake-client"}, CK_IcelakeClient, FEATURE_AVX512VBMI2, FeaturesICLClient },
// Rocketlake microarchitecture based processors.
{ {"rocketlake"}, CK_Rocketlake, FEATURE_AVX512VBMI2, FeaturesRocketlake },
// Icelake server microarchitecture based processors.
{ {"icelake-server"}, CK_IcelakeServer, FEATURE_AVX512VBMI2, FeaturesICLServer },
// Tigerlake microarchitecture based processors.
{ {"tigerlake"}, CK_Tigerlake, FEATURE_AVX512VP2INTERSECT, FeaturesTigerlake },
// Sapphire Rapids microarchitecture based processors.
- { {"sapphirerapids"}, CK_SapphireRapids, FEATURE_AVX512VP2INTERSECT, FeaturesSapphireRapids },
+ { {"sapphirerapids"}, CK_SapphireRapids, FEATURE_AVX512BF16, FeaturesSapphireRapids },
// Alderlake microarchitecture based processors.
{ {"alderlake"}, CK_Alderlake, FEATURE_AVX2, FeaturesAlderlake },
// Knights Landing processor.
{ {"knl"}, CK_KNL, FEATURE_AVX512F, FeaturesKNL },
// Knights Mill processor.
{ {"knm"}, CK_KNM, FEATURE_AVX5124FMAPS, FeaturesKNM },
// Lakemont microarchitecture based processors.
{ {"lakemont"}, CK_Lakemont, ~0U, FeatureCMPXCHG8B },
// K6 architecture processors.
{ {"k6"}, CK_K6, ~0U, FeaturesK6 },
{ {"k6-2"}, CK_K6_2, ~0U, FeaturesK6 | Feature3DNOW },
{ {"k6-3"}, CK_K6_3, ~0U, FeaturesK6 | Feature3DNOW },
// K7 architecture processors.
{ {"athlon"}, CK_Athlon, ~0U, FeaturesAthlon },
{ {"athlon-tbird"}, CK_Athlon, ~0U, FeaturesAthlon },
{ {"athlon-xp"}, CK_AthlonXP, ~0U, FeaturesAthlonXP },
{ {"athlon-mp"}, CK_AthlonXP, ~0U, FeaturesAthlonXP },
{ {"athlon-4"}, CK_AthlonXP, ~0U, FeaturesAthlonXP },
// K8 architecture processors.
{ {"k8"}, CK_K8, ~0U, FeaturesK8 },
{ {"athlon64"}, CK_K8, ~0U, FeaturesK8 },
{ {"athlon-fx"}, CK_K8, ~0U, FeaturesK8 },
{ {"opteron"}, CK_K8, ~0U, FeaturesK8 },
{ {"k8-sse3"}, CK_K8SSE3, ~0U, FeaturesK8SSE3 },
{ {"athlon64-sse3"}, CK_K8SSE3, ~0U, FeaturesK8SSE3 },
{ {"opteron-sse3"}, CK_K8SSE3, ~0U, FeaturesK8SSE3 },
{ {"amdfam10"}, CK_AMDFAM10, FEATURE_SSE4_A, FeaturesAMDFAM10 },
{ {"barcelona"}, CK_AMDFAM10, FEATURE_SSE4_A, FeaturesAMDFAM10 },
// Bobcat architecture processors.
{ {"btver1"}, CK_BTVER1, FEATURE_SSE4_A, FeaturesBTVER1 },
{ {"btver2"}, CK_BTVER2, FEATURE_BMI, FeaturesBTVER2 },
// Bulldozer architecture processors.
{ {"bdver1"}, CK_BDVER1, FEATURE_XOP, FeaturesBDVER1 },
{ {"bdver2"}, CK_BDVER2, FEATURE_FMA, FeaturesBDVER2 },
{ {"bdver3"}, CK_BDVER3, FEATURE_FMA, FeaturesBDVER3 },
{ {"bdver4"}, CK_BDVER4, FEATURE_AVX2, FeaturesBDVER4 },
// Zen architecture processors.
{ {"znver1"}, CK_ZNVER1, FEATURE_AVX2, FeaturesZNVER1 },
{ {"znver2"}, CK_ZNVER2, FEATURE_AVX2, FeaturesZNVER2 },
{ {"znver3"}, CK_ZNVER3, FEATURE_AVX2, FeaturesZNVER3 },
// Generic 64-bit processor.
{ {"x86-64"}, CK_x86_64, ~0U, FeaturesX86_64 },
{ {"x86-64-v2"}, CK_x86_64_v2, ~0U, FeaturesX86_64_V2 },
{ {"x86-64-v3"}, CK_x86_64_v3, ~0U, FeaturesX86_64_V3 },
{ {"x86-64-v4"}, CK_x86_64_v4, ~0U, FeaturesX86_64_V4 },
// Geode processors.
{ {"geode"}, CK_Geode, ~0U, FeaturesGeode },
};
constexpr const char *NoTuneList[] = {"x86-64-v2", "x86-64-v3", "x86-64-v4"};
X86::CPUKind llvm::X86::parseArchX86(StringRef CPU, bool Only64Bit) {
for (const auto &P : Processors)
if (P.Name == CPU && (P.Features[FEATURE_64BIT] || !Only64Bit))
return P.Kind;
return CK_None;
}
X86::CPUKind llvm::X86::parseTuneCPU(StringRef CPU, bool Only64Bit) {
if (llvm::is_contained(NoTuneList, CPU))
return CK_None;
return parseArchX86(CPU, Only64Bit);
}
void llvm::X86::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values,
bool Only64Bit) {
for (const auto &P : Processors)
if (!P.Name.empty() && (P.Features[FEATURE_64BIT] || !Only64Bit))
Values.emplace_back(P.Name);
}
void llvm::X86::fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values,
bool Only64Bit) {
for (const ProcInfo &P : Processors)
if (!P.Name.empty() && (P.Features[FEATURE_64BIT] || !Only64Bit) &&
!llvm::is_contained(NoTuneList, P.Name))
Values.emplace_back(P.Name);
}
ProcessorFeatures llvm::X86::getKeyFeature(X86::CPUKind Kind) {
// FIXME: Can we avoid a linear search here? The table might be sorted by
// CPUKind so we could binary search?
for (const auto &P : Processors) {
if (P.Kind == Kind) {
assert(P.KeyFeature != ~0U && "Processor does not have a key feature.");
return static_cast<ProcessorFeatures>(P.KeyFeature);
}
}
llvm_unreachable("Unable to find CPU kind!");
}
// Features with no dependencies.
constexpr FeatureBitset ImpliedFeatures64BIT = {};
constexpr FeatureBitset ImpliedFeaturesADX = {};
constexpr FeatureBitset ImpliedFeaturesBMI = {};
constexpr FeatureBitset ImpliedFeaturesBMI2 = {};
constexpr FeatureBitset ImpliedFeaturesCLDEMOTE = {};
constexpr FeatureBitset ImpliedFeaturesCLFLUSHOPT = {};
constexpr FeatureBitset ImpliedFeaturesCLWB = {};
constexpr FeatureBitset ImpliedFeaturesCLZERO = {};
constexpr FeatureBitset ImpliedFeaturesCMOV = {};
constexpr FeatureBitset ImpliedFeaturesCMPXCHG16B = {};
constexpr FeatureBitset ImpliedFeaturesCMPXCHG8B = {};
constexpr FeatureBitset ImpliedFeaturesCRC32 = {};
constexpr FeatureBitset ImpliedFeaturesENQCMD = {};
constexpr FeatureBitset ImpliedFeaturesFSGSBASE = {};
constexpr FeatureBitset ImpliedFeaturesFXSR = {};
constexpr FeatureBitset ImpliedFeaturesINVPCID = {};
constexpr FeatureBitset ImpliedFeaturesLWP = {};
constexpr FeatureBitset ImpliedFeaturesLZCNT = {};
constexpr FeatureBitset ImpliedFeaturesMWAITX = {};
constexpr FeatureBitset ImpliedFeaturesMOVBE = {};
constexpr FeatureBitset ImpliedFeaturesMOVDIR64B = {};
constexpr FeatureBitset ImpliedFeaturesMOVDIRI = {};
constexpr FeatureBitset ImpliedFeaturesPCONFIG = {};
constexpr FeatureBitset ImpliedFeaturesPOPCNT = {};
constexpr FeatureBitset ImpliedFeaturesPKU = {};
constexpr FeatureBitset ImpliedFeaturesPREFETCHWT1 = {};
constexpr FeatureBitset ImpliedFeaturesPRFCHW = {};
constexpr FeatureBitset ImpliedFeaturesPTWRITE = {};
constexpr FeatureBitset ImpliedFeaturesRDPID = {};
constexpr FeatureBitset ImpliedFeaturesRDPRU = {};
constexpr FeatureBitset ImpliedFeaturesRDRND = {};
constexpr FeatureBitset ImpliedFeaturesRDSEED = {};
constexpr FeatureBitset ImpliedFeaturesRTM = {};
constexpr FeatureBitset ImpliedFeaturesSAHF = {};
constexpr FeatureBitset ImpliedFeaturesSERIALIZE = {};
constexpr FeatureBitset ImpliedFeaturesSGX = {};
constexpr FeatureBitset ImpliedFeaturesSHSTK = {};
constexpr FeatureBitset ImpliedFeaturesTBM = {};
constexpr FeatureBitset ImpliedFeaturesTSXLDTRK = {};
constexpr FeatureBitset ImpliedFeaturesUINTR = {};
constexpr FeatureBitset ImpliedFeaturesWAITPKG = {};
constexpr FeatureBitset ImpliedFeaturesWBNOINVD = {};
constexpr FeatureBitset ImpliedFeaturesVZEROUPPER = {};
constexpr FeatureBitset ImpliedFeaturesX87 = {};
constexpr FeatureBitset ImpliedFeaturesXSAVE = {};
// Not really CPU features, but need to be in the table because clang uses
// target features to communicate them to the backend.
constexpr FeatureBitset ImpliedFeaturesRETPOLINE_EXTERNAL_THUNK = {};
constexpr FeatureBitset ImpliedFeaturesRETPOLINE_INDIRECT_BRANCHES = {};
constexpr FeatureBitset ImpliedFeaturesRETPOLINE_INDIRECT_CALLS = {};
constexpr FeatureBitset ImpliedFeaturesLVI_CFI = {};
constexpr FeatureBitset ImpliedFeaturesLVI_LOAD_HARDENING = {};
// XSAVE features are dependent on basic XSAVE.
constexpr FeatureBitset ImpliedFeaturesXSAVEC = FeatureXSAVE;
constexpr FeatureBitset ImpliedFeaturesXSAVEOPT = FeatureXSAVE;
constexpr FeatureBitset ImpliedFeaturesXSAVES = FeatureXSAVE;
// MMX->3DNOW->3DNOWA chain.
constexpr FeatureBitset ImpliedFeaturesMMX = {};
constexpr FeatureBitset ImpliedFeatures3DNOW = FeatureMMX;
constexpr FeatureBitset ImpliedFeatures3DNOWA = Feature3DNOW;
// SSE/AVX/AVX512F chain.
constexpr FeatureBitset ImpliedFeaturesSSE = {};
constexpr FeatureBitset ImpliedFeaturesSSE2 = FeatureSSE;
constexpr FeatureBitset ImpliedFeaturesSSE3 = FeatureSSE2;
constexpr FeatureBitset ImpliedFeaturesSSSE3 = FeatureSSE3;
constexpr FeatureBitset ImpliedFeaturesSSE4_1 = FeatureSSSE3;
constexpr FeatureBitset ImpliedFeaturesSSE4_2 = FeatureSSE4_1;
constexpr FeatureBitset ImpliedFeaturesAVX = FeatureSSE4_2;
constexpr FeatureBitset ImpliedFeaturesAVX2 = FeatureAVX;
constexpr FeatureBitset ImpliedFeaturesAVX512F =
FeatureAVX2 | FeatureF16C | FeatureFMA;
// Vector extensions that build on SSE or AVX.
constexpr FeatureBitset ImpliedFeaturesAES = FeatureSSE2;
constexpr FeatureBitset ImpliedFeaturesF16C = FeatureAVX;
constexpr FeatureBitset ImpliedFeaturesFMA = FeatureAVX;
constexpr FeatureBitset ImpliedFeaturesGFNI = FeatureSSE2;
constexpr FeatureBitset ImpliedFeaturesPCLMUL = FeatureSSE2;
constexpr FeatureBitset ImpliedFeaturesSHA = FeatureSSE2;
constexpr FeatureBitset ImpliedFeaturesVAES = FeatureAES | FeatureAVX;
constexpr FeatureBitset ImpliedFeaturesVPCLMULQDQ = FeatureAVX | FeaturePCLMUL;
// AVX512 features.
constexpr FeatureBitset ImpliedFeaturesAVX512CD = FeatureAVX512F;
constexpr FeatureBitset ImpliedFeaturesAVX512BW = FeatureAVX512F;
constexpr FeatureBitset ImpliedFeaturesAVX512DQ = FeatureAVX512F;
constexpr FeatureBitset ImpliedFeaturesAVX512ER = FeatureAVX512F;
constexpr FeatureBitset ImpliedFeaturesAVX512PF = FeatureAVX512F;
constexpr FeatureBitset ImpliedFeaturesAVX512VL = FeatureAVX512F;
constexpr FeatureBitset ImpliedFeaturesAVX512BF16 = FeatureAVX512BW;
constexpr FeatureBitset ImpliedFeaturesAVX512BITALG = FeatureAVX512BW;
constexpr FeatureBitset ImpliedFeaturesAVX512IFMA = FeatureAVX512F;
constexpr FeatureBitset ImpliedFeaturesAVX512VNNI = FeatureAVX512F;
constexpr FeatureBitset ImpliedFeaturesAVX512VPOPCNTDQ = FeatureAVX512F;
constexpr FeatureBitset ImpliedFeaturesAVX512VBMI = FeatureAVX512BW;
constexpr FeatureBitset ImpliedFeaturesAVX512VBMI2 = FeatureAVX512BW;
constexpr FeatureBitset ImpliedFeaturesAVX512VP2INTERSECT = FeatureAVX512F;
// FIXME: These two aren't really implemented and just exist in the feature
// list for __builtin_cpu_supports. So omit their dependencies.
constexpr FeatureBitset ImpliedFeaturesAVX5124FMAPS = {};
constexpr FeatureBitset ImpliedFeaturesAVX5124VNNIW = {};
// SSE4_A->FMA4->XOP chain.
constexpr FeatureBitset ImpliedFeaturesSSE4_A = FeatureSSE3;
constexpr FeatureBitset ImpliedFeaturesFMA4 = FeatureAVX | FeatureSSE4_A;
constexpr FeatureBitset ImpliedFeaturesXOP = FeatureFMA4;
// AMX Features
constexpr FeatureBitset ImpliedFeaturesAMX_TILE = {};
constexpr FeatureBitset ImpliedFeaturesAMX_BF16 = FeatureAMX_TILE;
constexpr FeatureBitset ImpliedFeaturesAMX_INT8 = FeatureAMX_TILE;
constexpr FeatureBitset ImpliedFeaturesHRESET = {};
static constexpr FeatureBitset ImpliedFeaturesAVX512FP16 =
FeatureAVX512BW | FeatureAVX512DQ | FeatureAVX512VL;
// Key Locker Features
constexpr FeatureBitset ImpliedFeaturesKL = FeatureSSE2;
constexpr FeatureBitset ImpliedFeaturesWIDEKL = FeatureKL;
// AVXVNNI Features
constexpr FeatureBitset ImpliedFeaturesAVXVNNI = FeatureAVX2;
constexpr FeatureInfo FeatureInfos[X86::CPU_FEATURE_MAX] = {
#define X86_FEATURE(ENUM, STR) {{STR}, ImpliedFeatures##ENUM},
#include "llvm/Support/X86TargetParser.def"
};
void llvm::X86::getFeaturesForCPU(StringRef CPU,
SmallVectorImpl<StringRef> &EnabledFeatures) {
auto I = llvm::find_if(Processors,
[&](const ProcInfo &P) { return P.Name == CPU; });
assert(I != std::end(Processors) && "Processor not found!");
FeatureBitset Bits = I->Features;
// Remove the 64-bit feature which we only use to validate if a CPU can
// be used with 64-bit mode.
Bits &= ~Feature64BIT;
// Add the string version of all set bits.
for (unsigned i = 0; i != CPU_FEATURE_MAX; ++i)
if (Bits[i] && !FeatureInfos[i].Name.empty())
EnabledFeatures.push_back(FeatureInfos[i].Name);
}
// For each feature that is (transitively) implied by this feature, set it.
static void getImpliedEnabledFeatures(FeatureBitset &Bits,
const FeatureBitset &Implies) {
// Fast path: Implies is often empty.
if (!Implies.any())
return;
FeatureBitset Prev;
Bits |= Implies;
do {
Prev = Bits;
for (unsigned i = CPU_FEATURE_MAX; i;)
if (Bits[--i])
Bits |= FeatureInfos[i].ImpliedFeatures;
} while (Prev != Bits);
}
/// Create bit vector of features that are implied disabled if the feature
/// passed in Value is disabled.
static void getImpliedDisabledFeatures(FeatureBitset &Bits, unsigned Value) {
// Check all features looking for any dependent on this feature. If we find
// one, mark it and recursively find any feature that depend on it.
FeatureBitset Prev;
Bits.set(Value);
do {
Prev = Bits;
for (unsigned i = 0; i != CPU_FEATURE_MAX; ++i)
if ((FeatureInfos[i].ImpliedFeatures & Bits).any())
Bits.set(i);
} while (Prev != Bits);
}
void llvm::X86::updateImpliedFeatures(
StringRef Feature, bool Enabled,
StringMap<bool> &Features) {
auto I = llvm::find_if(
FeatureInfos, [&](const FeatureInfo &FI) { return FI.Name == Feature; });
if (I == std::end(FeatureInfos)) {
// FIXME: This shouldn't happen, but may not have all features in the table
// yet.
return;
}
FeatureBitset ImpliedBits;
if (Enabled)
getImpliedEnabledFeatures(ImpliedBits, I->ImpliedFeatures);
else
getImpliedDisabledFeatures(ImpliedBits,
std::distance(std::begin(FeatureInfos), I));
// Update the map entry for all implied features.
for (unsigned i = 0; i != CPU_FEATURE_MAX; ++i)
if (ImpliedBits[i] && !FeatureInfos[i].Name.empty())
Features[FeatureInfos[i].Name] = Enabled;
}
uint64_t llvm::X86::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) {
// Processor features and mapping to processor feature value.
uint64_t FeaturesMask = 0;
for (const StringRef &FeatureStr : FeatureStrs) {
unsigned Feature = StringSwitch<unsigned>(FeatureStr)
#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) \
.Case(STR, llvm::X86::FEATURE_##ENUM)
#include "llvm/Support/X86TargetParser.def"
;
FeaturesMask |= (1ULL << Feature);
}
return FeaturesMask;
}
unsigned llvm::X86::getFeaturePriority(ProcessorFeatures Feat) {
#ifndef NDEBUG
// Check that priorities are set properly in the .def file. We expect that
// "compat" features are assigned non-duplicate consecutive priorities
// starting from zero (0, 1, ..., num_features - 1).
#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) PRIORITY,
unsigned Priorities[] = {
#include "llvm/Support/X86TargetParser.def"
std::numeric_limits<unsigned>::max() // Need to consume last comma.
};
std::array<unsigned, array_lengthof(Priorities) - 1> HelperList;
std::iota(HelperList.begin(), HelperList.end(), 0);
assert(std::is_permutation(HelperList.begin(), HelperList.end(),
std::begin(Priorities),
std::prev(std::end(Priorities))) &&
"Priorities don't form consecutive range!");
#endif
switch (Feat) {
#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) \
case X86::FEATURE_##ENUM: \
return PRIORITY;
#include "llvm/Support/X86TargetParser.def"
default:
llvm_unreachable("No Feature Priority for non-CPUSupports Features");
}
}
diff --git a/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonVectorCombine.cpp b/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonVectorCombine.cpp
index bd0232c71d48..f37c50900adb 100644
--- a/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonVectorCombine.cpp
+++ b/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonVectorCombine.cpp
@@ -1,1530 +1,1533 @@
//===-- HexagonVectorCombine.cpp ------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// HexagonVectorCombine is a utility class implementing a variety of functions
// that assist in vector-based optimizations.
//
// AlignVectors: replace unaligned vector loads and stores with aligned ones.
//===----------------------------------------------------------------------===//
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsHexagon.h"
#include "llvm/IR/Metadata.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/KnownBits.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "HexagonSubtarget.h"
#include "HexagonTargetMachine.h"
#include <algorithm>
#include <deque>
#include <map>
#include <set>
#include <utility>
#include <vector>
#define DEBUG_TYPE "hexagon-vc"
using namespace llvm;
namespace {
class HexagonVectorCombine {
public:
HexagonVectorCombine(Function &F_, AliasAnalysis &AA_, AssumptionCache &AC_,
DominatorTree &DT_, TargetLibraryInfo &TLI_,
const TargetMachine &TM_)
: F(F_), DL(F.getParent()->getDataLayout()), AA(AA_), AC(AC_), DT(DT_),
TLI(TLI_),
HST(static_cast<const HexagonSubtarget &>(*TM_.getSubtargetImpl(F))) {}
bool run();
// Common integer type.
IntegerType *getIntTy() const;
// Byte type: either scalar (when Length = 0), or vector with given
// element count.
Type *getByteTy(int ElemCount = 0) const;
// Boolean type: either scalar (when Length = 0), or vector with given
// element count.
Type *getBoolTy(int ElemCount = 0) const;
// Create a ConstantInt of type returned by getIntTy with the value Val.
ConstantInt *getConstInt(int Val) const;
// Get the integer value of V, if it exists.
Optional<APInt> getIntValue(const Value *Val) const;
// Is V a constant 0, or a vector of 0s?
bool isZero(const Value *Val) const;
// Is V an undef value?
bool isUndef(const Value *Val) const;
int getSizeOf(const Value *Val) const;
int getSizeOf(const Type *Ty) const;
int getAllocSizeOf(const Type *Ty) const;
int getTypeAlignment(Type *Ty) const;
Constant *getNullValue(Type *Ty) const;
Constant *getFullValue(Type *Ty) const;
Value *insertb(IRBuilder<> &Builder, Value *Dest, Value *Src, int Start,
int Length, int Where) const;
Value *vlalignb(IRBuilder<> &Builder, Value *Lo, Value *Hi, Value *Amt) const;
Value *vralignb(IRBuilder<> &Builder, Value *Lo, Value *Hi, Value *Amt) const;
Value *concat(IRBuilder<> &Builder, ArrayRef<Value *> Vecs) const;
Value *vresize(IRBuilder<> &Builder, Value *Val, int NewSize,
Value *Pad) const;
Value *rescale(IRBuilder<> &Builder, Value *Mask, Type *FromTy,
Type *ToTy) const;
Value *vlsb(IRBuilder<> &Builder, Value *Val) const;
Value *vbytes(IRBuilder<> &Builder, Value *Val) const;
Value *createHvxIntrinsic(IRBuilder<> &Builder, Intrinsic::ID IntID,
Type *RetTy, ArrayRef<Value *> Args) const;
Optional<int> calculatePointerDifference(Value *Ptr0, Value *Ptr1) const;
template <typename T = std::vector<Instruction *>>
bool isSafeToMoveBeforeInBB(const Instruction &In,
BasicBlock::const_iterator To,
const T &Ignore = {}) const;
Function &F;
const DataLayout &DL;
AliasAnalysis &AA;
AssumptionCache &AC;
DominatorTree &DT;
TargetLibraryInfo &TLI;
const HexagonSubtarget &HST;
private:
#ifndef NDEBUG
// These two functions are only used for assertions at the moment.
bool isByteVecTy(Type *Ty) const;
bool isSectorTy(Type *Ty) const;
#endif
Value *getElementRange(IRBuilder<> &Builder, Value *Lo, Value *Hi, int Start,
int Length) const;
};
class AlignVectors {
public:
AlignVectors(HexagonVectorCombine &HVC_) : HVC(HVC_) {}
bool run();
private:
using InstList = std::vector<Instruction *>;
struct Segment {
void *Data;
int Start;
int Size;
};
struct AddrInfo {
AddrInfo(const AddrInfo &) = default;
AddrInfo(const HexagonVectorCombine &HVC, Instruction *I, Value *A, Type *T,
Align H)
: Inst(I), Addr(A), ValTy(T), HaveAlign(H),
NeedAlign(HVC.getTypeAlignment(ValTy)) {}
+ AddrInfo &operator=(const AddrInfo &) = default;
// XXX: add Size member?
Instruction *Inst;
Value *Addr;
Type *ValTy;
Align HaveAlign;
Align NeedAlign;
int Offset = 0; // Offset (in bytes) from the first member of the
// containing AddrList.
};
using AddrList = std::vector<AddrInfo>;
struct InstrLess {
bool operator()(const Instruction *A, const Instruction *B) const {
return A->comesBefore(B);
}
};
using DepList = std::set<Instruction *, InstrLess>;
struct MoveGroup {
MoveGroup(const AddrInfo &AI, Instruction *B, bool Hvx, bool Load)
: Base(B), Main{AI.Inst}, IsHvx(Hvx), IsLoad(Load) {}
Instruction *Base; // Base instruction of the parent address group.
InstList Main; // Main group of instructions.
InstList Deps; // List of dependencies.
bool IsHvx; // Is this group of HVX instructions?
bool IsLoad; // Is this a load group?
};
using MoveList = std::vector<MoveGroup>;
struct ByteSpan {
struct Segment {
// Segment of a Value: 'Len' bytes starting at byte 'Begin'.
Segment(Value *Val, int Begin, int Len)
: Val(Val), Start(Begin), Size(Len) {}
Segment(const Segment &Seg) = default;
+ Segment &operator=(const Segment &Seg) = default;
Value *Val; // Value representable as a sequence of bytes.
int Start; // First byte of the value that belongs to the segment.
int Size; // Number of bytes in the segment.
};
struct Block {
Block(Value *Val, int Len, int Pos) : Seg(Val, 0, Len), Pos(Pos) {}
Block(Value *Val, int Off, int Len, int Pos)
: Seg(Val, Off, Len), Pos(Pos) {}
Block(const Block &Blk) = default;
+ Block &operator=(const Block &Blk) = default;
Segment Seg; // Value segment.
int Pos; // Position (offset) of the segment in the Block.
};
int extent() const;
ByteSpan section(int Start, int Length) const;
ByteSpan &shift(int Offset);
SmallVector<Value *, 8> values() const;
int size() const { return Blocks.size(); }
Block &operator[](int i) { return Blocks[i]; }
std::vector<Block> Blocks;
using iterator = decltype(Blocks)::iterator;
iterator begin() { return Blocks.begin(); }
iterator end() { return Blocks.end(); }
using const_iterator = decltype(Blocks)::const_iterator;
const_iterator begin() const { return Blocks.begin(); }
const_iterator end() const { return Blocks.end(); }
};
Align getAlignFromValue(const Value *V) const;
Optional<MemoryLocation> getLocation(const Instruction &In) const;
Optional<AddrInfo> getAddrInfo(Instruction &In) const;
bool isHvx(const AddrInfo &AI) const;
Value *getPayload(Value *Val) const;
Value *getMask(Value *Val) const;
Value *getPassThrough(Value *Val) const;
Value *createAdjustedPointer(IRBuilder<> &Builder, Value *Ptr, Type *ValTy,
int Adjust) const;
Value *createAlignedPointer(IRBuilder<> &Builder, Value *Ptr, Type *ValTy,
int Alignment) const;
Value *createAlignedLoad(IRBuilder<> &Builder, Type *ValTy, Value *Ptr,
int Alignment, Value *Mask, Value *PassThru) const;
Value *createAlignedStore(IRBuilder<> &Builder, Value *Val, Value *Ptr,
int Alignment, Value *Mask) const;
bool createAddressGroups();
MoveList createLoadGroups(const AddrList &Group) const;
MoveList createStoreGroups(const AddrList &Group) const;
bool move(const MoveGroup &Move) const;
bool realignGroup(const MoveGroup &Move) const;
friend raw_ostream &operator<<(raw_ostream &OS, const AddrInfo &AI);
friend raw_ostream &operator<<(raw_ostream &OS, const MoveGroup &MG);
friend raw_ostream &operator<<(raw_ostream &OS, const ByteSpan &BS);
std::map<Instruction *, AddrList> AddrGroups;
HexagonVectorCombine &HVC;
};
LLVM_ATTRIBUTE_UNUSED
raw_ostream &operator<<(raw_ostream &OS, const AlignVectors::AddrInfo &AI) {
OS << "Inst: " << AI.Inst << " " << *AI.Inst << '\n';
OS << "Addr: " << *AI.Addr << '\n';
OS << "Type: " << *AI.ValTy << '\n';
OS << "HaveAlign: " << AI.HaveAlign.value() << '\n';
OS << "NeedAlign: " << AI.NeedAlign.value() << '\n';
OS << "Offset: " << AI.Offset;
return OS;
}
LLVM_ATTRIBUTE_UNUSED
raw_ostream &operator<<(raw_ostream &OS, const AlignVectors::MoveGroup &MG) {
OS << "Main\n";
for (Instruction *I : MG.Main)
OS << " " << *I << '\n';
OS << "Deps\n";
for (Instruction *I : MG.Deps)
OS << " " << *I << '\n';
return OS;
}
LLVM_ATTRIBUTE_UNUSED
raw_ostream &operator<<(raw_ostream &OS, const AlignVectors::ByteSpan &BS) {
OS << "ByteSpan[size=" << BS.size() << ", extent=" << BS.extent() << '\n';
for (const AlignVectors::ByteSpan::Block &B : BS) {
OS << " @" << B.Pos << " [" << B.Seg.Start << ',' << B.Seg.Size << "] "
<< *B.Seg.Val << '\n';
}
OS << ']';
return OS;
}
} // namespace
namespace {
template <typename T> T *getIfUnordered(T *MaybeT) {
return MaybeT && MaybeT->isUnordered() ? MaybeT : nullptr;
}
template <typename T> T *isCandidate(Instruction *In) {
return dyn_cast<T>(In);
}
template <> LoadInst *isCandidate<LoadInst>(Instruction *In) {
return getIfUnordered(dyn_cast<LoadInst>(In));
}
template <> StoreInst *isCandidate<StoreInst>(Instruction *In) {
return getIfUnordered(dyn_cast<StoreInst>(In));
}
#if !defined(_MSC_VER) || _MSC_VER >= 1926
// VS2017 and some versions of VS2019 have trouble compiling this:
// error C2976: 'std::map': too few template arguments
// VS 2019 16.x is known to work, except for 16.4/16.5 (MSC_VER 1924/1925)
template <typename Pred, typename... Ts>
void erase_if(std::map<Ts...> &map, Pred p)
#else
template <typename Pred, typename T, typename U>
void erase_if(std::map<T, U> &map, Pred p)
#endif
{
for (auto i = map.begin(), e = map.end(); i != e;) {
if (p(*i))
i = map.erase(i);
else
i = std::next(i);
}
}
// Forward other erase_ifs to the LLVM implementations.
template <typename Pred, typename T> void erase_if(T &&container, Pred p) {
llvm::erase_if(std::forward<T>(container), p);
}
} // namespace
// --- Begin AlignVectors
auto AlignVectors::ByteSpan::extent() const -> int {
if (size() == 0)
return 0;
int Min = Blocks[0].Pos;
int Max = Blocks[0].Pos + Blocks[0].Seg.Size;
for (int i = 1, e = size(); i != e; ++i) {
Min = std::min(Min, Blocks[i].Pos);
Max = std::max(Max, Blocks[i].Pos + Blocks[i].Seg.Size);
}
return Max - Min;
}
auto AlignVectors::ByteSpan::section(int Start, int Length) const -> ByteSpan {
ByteSpan Section;
for (const ByteSpan::Block &B : Blocks) {
int L = std::max(B.Pos, Start); // Left end.
int R = std::min(B.Pos + B.Seg.Size, Start + Length); // Right end+1.
if (L < R) {
// How much to chop off the beginning of the segment:
int Off = L > B.Pos ? L - B.Pos : 0;
Section.Blocks.emplace_back(B.Seg.Val, B.Seg.Start + Off, R - L, L);
}
}
return Section;
}
auto AlignVectors::ByteSpan::shift(int Offset) -> ByteSpan & {
for (Block &B : Blocks)
B.Pos += Offset;
return *this;
}
auto AlignVectors::ByteSpan::values() const -> SmallVector<Value *, 8> {
SmallVector<Value *, 8> Values(Blocks.size());
for (int i = 0, e = Blocks.size(); i != e; ++i)
Values[i] = Blocks[i].Seg.Val;
return Values;
}
auto AlignVectors::getAlignFromValue(const Value *V) const -> Align {
const auto *C = dyn_cast<ConstantInt>(V);
assert(C && "Alignment must be a compile-time constant integer");
return C->getAlignValue();
}
auto AlignVectors::getAddrInfo(Instruction &In) const -> Optional<AddrInfo> {
if (auto *L = isCandidate<LoadInst>(&In))
return AddrInfo(HVC, L, L->getPointerOperand(), L->getType(),
L->getAlign());
if (auto *S = isCandidate<StoreInst>(&In))
return AddrInfo(HVC, S, S->getPointerOperand(),
S->getValueOperand()->getType(), S->getAlign());
if (auto *II = isCandidate<IntrinsicInst>(&In)) {
Intrinsic::ID ID = II->getIntrinsicID();
switch (ID) {
case Intrinsic::masked_load:
return AddrInfo(HVC, II, II->getArgOperand(0), II->getType(),
getAlignFromValue(II->getArgOperand(1)));
case Intrinsic::masked_store:
return AddrInfo(HVC, II, II->getArgOperand(1),
II->getArgOperand(0)->getType(),
getAlignFromValue(II->getArgOperand(2)));
}
}
return Optional<AddrInfo>();
}
auto AlignVectors::isHvx(const AddrInfo &AI) const -> bool {
return HVC.HST.isTypeForHVX(AI.ValTy);
}
auto AlignVectors::getPayload(Value *Val) const -> Value * {
if (auto *In = dyn_cast<Instruction>(Val)) {
Intrinsic::ID ID = 0;
if (auto *II = dyn_cast<IntrinsicInst>(In))
ID = II->getIntrinsicID();
if (isa<StoreInst>(In) || ID == Intrinsic::masked_store)
return In->getOperand(0);
}
return Val;
}
auto AlignVectors::getMask(Value *Val) const -> Value * {
if (auto *II = dyn_cast<IntrinsicInst>(Val)) {
switch (II->getIntrinsicID()) {
case Intrinsic::masked_load:
return II->getArgOperand(2);
case Intrinsic::masked_store:
return II->getArgOperand(3);
}
}
Type *ValTy = getPayload(Val)->getType();
if (auto *VecTy = dyn_cast<VectorType>(ValTy)) {
int ElemCount = VecTy->getElementCount().getFixedValue();
return HVC.getFullValue(HVC.getBoolTy(ElemCount));
}
return HVC.getFullValue(HVC.getBoolTy());
}
auto AlignVectors::getPassThrough(Value *Val) const -> Value * {
if (auto *II = dyn_cast<IntrinsicInst>(Val)) {
if (II->getIntrinsicID() == Intrinsic::masked_load)
return II->getArgOperand(3);
}
return UndefValue::get(getPayload(Val)->getType());
}
auto AlignVectors::createAdjustedPointer(IRBuilder<> &Builder, Value *Ptr,
Type *ValTy, int Adjust) const
-> Value * {
// The adjustment is in bytes, but if it's a multiple of the type size,
// we don't need to do pointer casts.
auto *PtrTy = cast<PointerType>(Ptr->getType());
if (!PtrTy->isOpaque()) {
Type *ElemTy = PtrTy->getNonOpaquePointerElementType();
int ElemSize = HVC.getAllocSizeOf(ElemTy);
if (Adjust % ElemSize == 0 && Adjust != 0) {
Value *Tmp0 =
Builder.CreateGEP(ElemTy, Ptr, HVC.getConstInt(Adjust / ElemSize));
return Builder.CreatePointerCast(Tmp0, ValTy->getPointerTo());
}
}
PointerType *CharPtrTy = Type::getInt8PtrTy(HVC.F.getContext());
Value *Tmp0 = Builder.CreatePointerCast(Ptr, CharPtrTy);
Value *Tmp1 = Builder.CreateGEP(Type::getInt8Ty(HVC.F.getContext()), Tmp0,
HVC.getConstInt(Adjust));
return Builder.CreatePointerCast(Tmp1, ValTy->getPointerTo());
}
auto AlignVectors::createAlignedPointer(IRBuilder<> &Builder, Value *Ptr,
Type *ValTy, int Alignment) const
-> Value * {
Value *AsInt = Builder.CreatePtrToInt(Ptr, HVC.getIntTy());
Value *Mask = HVC.getConstInt(-Alignment);
Value *And = Builder.CreateAnd(AsInt, Mask);
return Builder.CreateIntToPtr(And, ValTy->getPointerTo());
}
auto AlignVectors::createAlignedLoad(IRBuilder<> &Builder, Type *ValTy,
Value *Ptr, int Alignment, Value *Mask,
Value *PassThru) const -> Value * {
assert(!HVC.isUndef(Mask)); // Should this be allowed?
if (HVC.isZero(Mask))
return PassThru;
if (Mask == ConstantInt::getTrue(Mask->getType()))
return Builder.CreateAlignedLoad(ValTy, Ptr, Align(Alignment));
return Builder.CreateMaskedLoad(ValTy, Ptr, Align(Alignment), Mask, PassThru);
}
auto AlignVectors::createAlignedStore(IRBuilder<> &Builder, Value *Val,
Value *Ptr, int Alignment,
Value *Mask) const -> Value * {
if (HVC.isZero(Mask) || HVC.isUndef(Val) || HVC.isUndef(Mask))
return UndefValue::get(Val->getType());
if (Mask == ConstantInt::getTrue(Mask->getType()))
return Builder.CreateAlignedStore(Val, Ptr, Align(Alignment));
return Builder.CreateMaskedStore(Val, Ptr, Align(Alignment), Mask);
}
auto AlignVectors::createAddressGroups() -> bool {
// An address group created here may contain instructions spanning
// multiple basic blocks.
AddrList WorkStack;
auto findBaseAndOffset = [&](AddrInfo &AI) -> std::pair<Instruction *, int> {
for (AddrInfo &W : WorkStack) {
if (auto D = HVC.calculatePointerDifference(AI.Addr, W.Addr))
return std::make_pair(W.Inst, *D);
}
return std::make_pair(nullptr, 0);
};
auto traverseBlock = [&](DomTreeNode *DomN, auto Visit) -> void {
BasicBlock &Block = *DomN->getBlock();
for (Instruction &I : Block) {
auto AI = this->getAddrInfo(I); // Use this-> for gcc6.
if (!AI)
continue;
auto F = findBaseAndOffset(*AI);
Instruction *GroupInst;
if (Instruction *BI = F.first) {
AI->Offset = F.second;
GroupInst = BI;
} else {
WorkStack.push_back(*AI);
GroupInst = AI->Inst;
}
AddrGroups[GroupInst].push_back(*AI);
}
for (DomTreeNode *C : DomN->children())
Visit(C, Visit);
while (!WorkStack.empty() && WorkStack.back().Inst->getParent() == &Block)
WorkStack.pop_back();
};
traverseBlock(HVC.DT.getRootNode(), traverseBlock);
assert(WorkStack.empty());
// AddrGroups are formed.
// Remove groups of size 1.
erase_if(AddrGroups, [](auto &G) { return G.second.size() == 1; });
// Remove groups that don't use HVX types.
erase_if(AddrGroups, [&](auto &G) {
return llvm::none_of(
G.second, [&](auto &I) { return HVC.HST.isTypeForHVX(I.ValTy); });
});
return !AddrGroups.empty();
}
auto AlignVectors::createLoadGroups(const AddrList &Group) const -> MoveList {
// Form load groups.
// To avoid complications with moving code across basic blocks, only form
// groups that are contained within a single basic block.
auto getUpwardDeps = [](Instruction *In, Instruction *Base) {
BasicBlock *Parent = Base->getParent();
assert(In->getParent() == Parent &&
"Base and In should be in the same block");
assert(Base->comesBefore(In) && "Base should come before In");
DepList Deps;
std::deque<Instruction *> WorkQ = {In};
while (!WorkQ.empty()) {
Instruction *D = WorkQ.front();
WorkQ.pop_front();
Deps.insert(D);
for (Value *Op : D->operands()) {
if (auto *I = dyn_cast<Instruction>(Op)) {
if (I->getParent() == Parent && Base->comesBefore(I))
WorkQ.push_back(I);
}
}
}
return Deps;
};
auto tryAddTo = [&](const AddrInfo &Info, MoveGroup &Move) {
assert(!Move.Main.empty() && "Move group should have non-empty Main");
// Don't mix HVX and non-HVX instructions.
if (Move.IsHvx != isHvx(Info))
return false;
// Leading instruction in the load group.
Instruction *Base = Move.Main.front();
if (Base->getParent() != Info.Inst->getParent())
return false;
auto isSafeToMoveToBase = [&](const Instruction *I) {
return HVC.isSafeToMoveBeforeInBB(*I, Base->getIterator());
};
DepList Deps = getUpwardDeps(Info.Inst, Base);
if (!llvm::all_of(Deps, isSafeToMoveToBase))
return false;
// The dependencies will be moved together with the load, so make sure
// that none of them could be moved independently in another group.
Deps.erase(Info.Inst);
auto inAddrMap = [&](Instruction *I) { return AddrGroups.count(I) > 0; };
if (llvm::any_of(Deps, inAddrMap))
return false;
Move.Main.push_back(Info.Inst);
llvm::append_range(Move.Deps, Deps);
return true;
};
MoveList LoadGroups;
for (const AddrInfo &Info : Group) {
if (!Info.Inst->mayReadFromMemory())
continue;
if (LoadGroups.empty() || !tryAddTo(Info, LoadGroups.back()))
LoadGroups.emplace_back(Info, Group.front().Inst, isHvx(Info), true);
}
// Erase singleton groups.
erase_if(LoadGroups, [](const MoveGroup &G) { return G.Main.size() <= 1; });
return LoadGroups;
}
auto AlignVectors::createStoreGroups(const AddrList &Group) const -> MoveList {
// Form store groups.
// To avoid complications with moving code across basic blocks, only form
// groups that are contained within a single basic block.
auto tryAddTo = [&](const AddrInfo &Info, MoveGroup &Move) {
assert(!Move.Main.empty() && "Move group should have non-empty Main");
// For stores with return values we'd have to collect downward depenencies.
// There are no such stores that we handle at the moment, so omit that.
assert(Info.Inst->getType()->isVoidTy() &&
"Not handling stores with return values");
// Don't mix HVX and non-HVX instructions.
if (Move.IsHvx != isHvx(Info))
return false;
// For stores we need to be careful whether it's safe to move them.
// Stores that are otherwise safe to move together may not appear safe
// to move over one another (i.e. isSafeToMoveBefore may return false).
Instruction *Base = Move.Main.front();
if (Base->getParent() != Info.Inst->getParent())
return false;
if (!HVC.isSafeToMoveBeforeInBB(*Info.Inst, Base->getIterator(), Move.Main))
return false;
Move.Main.push_back(Info.Inst);
return true;
};
MoveList StoreGroups;
for (auto I = Group.rbegin(), E = Group.rend(); I != E; ++I) {
const AddrInfo &Info = *I;
if (!Info.Inst->mayWriteToMemory())
continue;
if (StoreGroups.empty() || !tryAddTo(Info, StoreGroups.back()))
StoreGroups.emplace_back(Info, Group.front().Inst, isHvx(Info), false);
}
// Erase singleton groups.
erase_if(StoreGroups, [](const MoveGroup &G) { return G.Main.size() <= 1; });
return StoreGroups;
}
auto AlignVectors::move(const MoveGroup &Move) const -> bool {
assert(!Move.Main.empty() && "Move group should have non-empty Main");
Instruction *Where = Move.Main.front();
if (Move.IsLoad) {
// Move all deps to before Where, keeping order.
for (Instruction *D : Move.Deps)
D->moveBefore(Where);
// Move all main instructions to after Where, keeping order.
ArrayRef<Instruction *> Main(Move.Main);
for (Instruction *M : Main.drop_front(1)) {
M->moveAfter(Where);
Where = M;
}
} else {
// NOTE: Deps are empty for "store" groups. If they need to be
// non-empty, decide on the order.
assert(Move.Deps.empty());
// Move all main instructions to before Where, inverting order.
ArrayRef<Instruction *> Main(Move.Main);
for (Instruction *M : Main.drop_front(1)) {
M->moveBefore(Where);
Where = M;
}
}
return Move.Main.size() + Move.Deps.size() > 1;
}
auto AlignVectors::realignGroup(const MoveGroup &Move) const -> bool {
// TODO: Needs support for masked loads/stores of "scalar" vectors.
if (!Move.IsHvx)
return false;
// Return the element with the maximum alignment from Range,
// where GetValue obtains the value to compare from an element.
auto getMaxOf = [](auto Range, auto GetValue) {
return *std::max_element(
Range.begin(), Range.end(),
[&GetValue](auto &A, auto &B) { return GetValue(A) < GetValue(B); });
};
const AddrList &BaseInfos = AddrGroups.at(Move.Base);
// Conceptually, there is a vector of N bytes covering the addresses
// starting from the minimum offset (i.e. Base.Addr+Start). This vector
// represents a contiguous memory region that spans all accessed memory
// locations.
// The correspondence between loaded or stored values will be expressed
// in terms of this vector. For example, the 0th element of the vector
// from the Base address info will start at byte Start from the beginning
// of this conceptual vector.
//
// This vector will be loaded/stored starting at the nearest down-aligned
// address and the amount od the down-alignment will be AlignVal:
// valign(load_vector(align_down(Base+Start)), AlignVal)
std::set<Instruction *> TestSet(Move.Main.begin(), Move.Main.end());
AddrList MoveInfos;
llvm::copy_if(
BaseInfos, std::back_inserter(MoveInfos),
[&TestSet](const AddrInfo &AI) { return TestSet.count(AI.Inst); });
// Maximum alignment present in the whole address group.
const AddrInfo &WithMaxAlign =
getMaxOf(MoveInfos, [](const AddrInfo &AI) { return AI.HaveAlign; });
Align MaxGiven = WithMaxAlign.HaveAlign;
// Minimum alignment present in the move address group.
const AddrInfo &WithMinOffset =
getMaxOf(MoveInfos, [](const AddrInfo &AI) { return -AI.Offset; });
const AddrInfo &WithMaxNeeded =
getMaxOf(MoveInfos, [](const AddrInfo &AI) { return AI.NeedAlign; });
Align MinNeeded = WithMaxNeeded.NeedAlign;
// Set the builder at the top instruction in the move group.
Instruction *TopIn = Move.IsLoad ? Move.Main.front() : Move.Main.back();
IRBuilder<> Builder(TopIn);
Value *AlignAddr = nullptr; // Actual aligned address.
Value *AlignVal = nullptr; // Right-shift amount (for valign).
if (MinNeeded <= MaxGiven) {
int Start = WithMinOffset.Offset;
int OffAtMax = WithMaxAlign.Offset;
// Shift the offset of the maximally aligned instruction (OffAtMax)
// back by just enough multiples of the required alignment to cover the
// distance from Start to OffAtMax.
// Calculate the address adjustment amount based on the address with the
// maximum alignment. This is to allow a simple gep instruction instead
// of potential bitcasts to i8*.
int Adjust = -alignTo(OffAtMax - Start, MinNeeded.value());
AlignAddr = createAdjustedPointer(Builder, WithMaxAlign.Addr,
WithMaxAlign.ValTy, Adjust);
int Diff = Start - (OffAtMax + Adjust);
AlignVal = HVC.getConstInt(Diff);
assert(Diff >= 0);
assert(static_cast<decltype(MinNeeded.value())>(Diff) < MinNeeded.value());
} else {
// WithMinOffset is the lowest address in the group,
// WithMinOffset.Addr = Base+Start.
// Align instructions for both HVX (V6_valign) and scalar (S2_valignrb)
// mask off unnecessary bits, so it's ok to just the original pointer as
// the alignment amount.
// Do an explicit down-alignment of the address to avoid creating an
// aligned instruction with an address that is not really aligned.
AlignAddr = createAlignedPointer(Builder, WithMinOffset.Addr,
WithMinOffset.ValTy, MinNeeded.value());
AlignVal = Builder.CreatePtrToInt(WithMinOffset.Addr, HVC.getIntTy());
}
ByteSpan VSpan;
for (const AddrInfo &AI : MoveInfos) {
VSpan.Blocks.emplace_back(AI.Inst, HVC.getSizeOf(AI.ValTy),
AI.Offset - WithMinOffset.Offset);
}
// The aligned loads/stores will use blocks that are either scalars,
// or HVX vectors. Let "sector" be the unified term for such a block.
// blend(scalar, vector) -> sector...
int ScLen = Move.IsHvx ? HVC.HST.getVectorLength()
: std::max<int>(MinNeeded.value(), 4);
assert(!Move.IsHvx || ScLen == 64 || ScLen == 128);
assert(Move.IsHvx || ScLen == 4 || ScLen == 8);
Type *SecTy = HVC.getByteTy(ScLen);
int NumSectors = (VSpan.extent() + ScLen - 1) / ScLen;
bool DoAlign = !HVC.isZero(AlignVal);
if (Move.IsLoad) {
ByteSpan ASpan;
auto *True = HVC.getFullValue(HVC.getBoolTy(ScLen));
auto *Undef = UndefValue::get(SecTy);
for (int i = 0; i != NumSectors + DoAlign; ++i) {
Value *Ptr = createAdjustedPointer(Builder, AlignAddr, SecTy, i * ScLen);
// FIXME: generate a predicated load?
Value *Load = createAlignedLoad(Builder, SecTy, Ptr, ScLen, True, Undef);
// If vector shifting is potentially needed, accumulate metadata
// from source sections of twice the load width.
int Start = (i - DoAlign) * ScLen;
int Width = (1 + DoAlign) * ScLen;
propagateMetadata(cast<Instruction>(Load),
VSpan.section(Start, Width).values());
ASpan.Blocks.emplace_back(Load, ScLen, i * ScLen);
}
if (DoAlign) {
for (int j = 0; j != NumSectors; ++j) {
ASpan[j].Seg.Val = HVC.vralignb(Builder, ASpan[j].Seg.Val,
ASpan[j + 1].Seg.Val, AlignVal);
}
}
for (ByteSpan::Block &B : VSpan) {
ByteSpan ASection = ASpan.section(B.Pos, B.Seg.Size).shift(-B.Pos);
Value *Accum = UndefValue::get(HVC.getByteTy(B.Seg.Size));
for (ByteSpan::Block &S : ASection) {
Value *Pay = HVC.vbytes(Builder, getPayload(S.Seg.Val));
Accum =
HVC.insertb(Builder, Accum, Pay, S.Seg.Start, S.Seg.Size, S.Pos);
}
// Instead of casting everything to bytes for the vselect, cast to the
// original value type. This will avoid complications with casting masks.
// For example, in cases when the original mask applied to i32, it could
// be converted to a mask applicable to i8 via pred_typecast intrinsic,
// but if the mask is not exactly of HVX length, extra handling would be
// needed to make it work.
Type *ValTy = getPayload(B.Seg.Val)->getType();
Value *Cast = Builder.CreateBitCast(Accum, ValTy);
Value *Sel = Builder.CreateSelect(getMask(B.Seg.Val), Cast,
getPassThrough(B.Seg.Val));
B.Seg.Val->replaceAllUsesWith(Sel);
}
} else {
// Stores.
ByteSpan ASpanV, ASpanM;
// Return a vector value corresponding to the input value Val:
// either <1 x Val> for scalar Val, or Val itself for vector Val.
auto MakeVec = [](IRBuilder<> &Builder, Value *Val) -> Value * {
Type *Ty = Val->getType();
if (Ty->isVectorTy())
return Val;
auto *VecTy = VectorType::get(Ty, 1, /*Scalable*/ false);
return Builder.CreateBitCast(Val, VecTy);
};
// Create an extra "undef" sector at the beginning and at the end.
// They will be used as the left/right filler in the vlalign step.
for (int i = (DoAlign ? -1 : 0); i != NumSectors + DoAlign; ++i) {
// For stores, the size of each section is an aligned vector length.
// Adjust the store offsets relative to the section start offset.
ByteSpan VSection = VSpan.section(i * ScLen, ScLen).shift(-i * ScLen);
Value *AccumV = UndefValue::get(SecTy);
Value *AccumM = HVC.getNullValue(SecTy);
for (ByteSpan::Block &S : VSection) {
Value *Pay = getPayload(S.Seg.Val);
Value *Mask = HVC.rescale(Builder, MakeVec(Builder, getMask(S.Seg.Val)),
Pay->getType(), HVC.getByteTy());
AccumM = HVC.insertb(Builder, AccumM, HVC.vbytes(Builder, Mask),
S.Seg.Start, S.Seg.Size, S.Pos);
AccumV = HVC.insertb(Builder, AccumV, HVC.vbytes(Builder, Pay),
S.Seg.Start, S.Seg.Size, S.Pos);
}
ASpanV.Blocks.emplace_back(AccumV, ScLen, i * ScLen);
ASpanM.Blocks.emplace_back(AccumM, ScLen, i * ScLen);
}
// vlalign
if (DoAlign) {
for (int j = 1; j != NumSectors + 2; ++j) {
ASpanV[j - 1].Seg.Val = HVC.vlalignb(Builder, ASpanV[j - 1].Seg.Val,
ASpanV[j].Seg.Val, AlignVal);
ASpanM[j - 1].Seg.Val = HVC.vlalignb(Builder, ASpanM[j - 1].Seg.Val,
ASpanM[j].Seg.Val, AlignVal);
}
}
for (int i = 0; i != NumSectors + DoAlign; ++i) {
Value *Ptr = createAdjustedPointer(Builder, AlignAddr, SecTy, i * ScLen);
Value *Val = ASpanV[i].Seg.Val;
Value *Mask = ASpanM[i].Seg.Val; // bytes
if (!HVC.isUndef(Val) && !HVC.isZero(Mask)) {
Value *Store = createAlignedStore(Builder, Val, Ptr, ScLen,
HVC.vlsb(Builder, Mask));
// If vector shifting is potentially needed, accumulate metadata
// from source sections of twice the store width.
int Start = (i - DoAlign) * ScLen;
int Width = (1 + DoAlign) * ScLen;
propagateMetadata(cast<Instruction>(Store),
VSpan.section(Start, Width).values());
}
}
}
for (auto *Inst : Move.Main)
Inst->eraseFromParent();
return true;
}
auto AlignVectors::run() -> bool {
if (!createAddressGroups())
return false;
bool Changed = false;
MoveList LoadGroups, StoreGroups;
for (auto &G : AddrGroups) {
llvm::append_range(LoadGroups, createLoadGroups(G.second));
llvm::append_range(StoreGroups, createStoreGroups(G.second));
}
for (auto &M : LoadGroups)
Changed |= move(M);
for (auto &M : StoreGroups)
Changed |= move(M);
for (auto &M : LoadGroups)
Changed |= realignGroup(M);
for (auto &M : StoreGroups)
Changed |= realignGroup(M);
return Changed;
}
// --- End AlignVectors
auto HexagonVectorCombine::run() -> bool {
if (!HST.useHVXOps())
return false;
bool Changed = AlignVectors(*this).run();
return Changed;
}
auto HexagonVectorCombine::getIntTy() const -> IntegerType * {
return Type::getInt32Ty(F.getContext());
}
auto HexagonVectorCombine::getByteTy(int ElemCount) const -> Type * {
assert(ElemCount >= 0);
IntegerType *ByteTy = Type::getInt8Ty(F.getContext());
if (ElemCount == 0)
return ByteTy;
return VectorType::get(ByteTy, ElemCount, /*Scalable*/ false);
}
auto HexagonVectorCombine::getBoolTy(int ElemCount) const -> Type * {
assert(ElemCount >= 0);
IntegerType *BoolTy = Type::getInt1Ty(F.getContext());
if (ElemCount == 0)
return BoolTy;
return VectorType::get(BoolTy, ElemCount, /*Scalable*/ false);
}
auto HexagonVectorCombine::getConstInt(int Val) const -> ConstantInt * {
return ConstantInt::getSigned(getIntTy(), Val);
}
auto HexagonVectorCombine::isZero(const Value *Val) const -> bool {
if (auto *C = dyn_cast<Constant>(Val))
return C->isZeroValue();
return false;
}
auto HexagonVectorCombine::getIntValue(const Value *Val) const
-> Optional<APInt> {
if (auto *CI = dyn_cast<ConstantInt>(Val))
return CI->getValue();
return None;
}
auto HexagonVectorCombine::isUndef(const Value *Val) const -> bool {
return isa<UndefValue>(Val);
}
auto HexagonVectorCombine::getSizeOf(const Value *Val) const -> int {
return getSizeOf(Val->getType());
}
auto HexagonVectorCombine::getSizeOf(const Type *Ty) const -> int {
return DL.getTypeStoreSize(const_cast<Type *>(Ty)).getFixedValue();
}
auto HexagonVectorCombine::getAllocSizeOf(const Type *Ty) const -> int {
return DL.getTypeAllocSize(const_cast<Type *>(Ty)).getFixedValue();
}
auto HexagonVectorCombine::getTypeAlignment(Type *Ty) const -> int {
// The actual type may be shorter than the HVX vector, so determine
// the alignment based on subtarget info.
if (HST.isTypeForHVX(Ty))
return HST.getVectorLength();
return DL.getABITypeAlign(Ty).value();
}
auto HexagonVectorCombine::getNullValue(Type *Ty) const -> Constant * {
assert(Ty->isIntOrIntVectorTy());
auto Zero = ConstantInt::get(Ty->getScalarType(), 0);
if (auto *VecTy = dyn_cast<VectorType>(Ty))
return ConstantVector::getSplat(VecTy->getElementCount(), Zero);
return Zero;
}
auto HexagonVectorCombine::getFullValue(Type *Ty) const -> Constant * {
assert(Ty->isIntOrIntVectorTy());
auto Minus1 = ConstantInt::get(Ty->getScalarType(), -1);
if (auto *VecTy = dyn_cast<VectorType>(Ty))
return ConstantVector::getSplat(VecTy->getElementCount(), Minus1);
return Minus1;
}
// Insert bytes [Start..Start+Length) of Src into Dst at byte Where.
auto HexagonVectorCombine::insertb(IRBuilder<> &Builder, Value *Dst, Value *Src,
int Start, int Length, int Where) const
-> Value * {
assert(isByteVecTy(Dst->getType()) && isByteVecTy(Src->getType()));
int SrcLen = getSizeOf(Src);
int DstLen = getSizeOf(Dst);
assert(0 <= Start && Start + Length <= SrcLen);
assert(0 <= Where && Where + Length <= DstLen);
int P2Len = PowerOf2Ceil(SrcLen | DstLen);
auto *Undef = UndefValue::get(getByteTy());
Value *P2Src = vresize(Builder, Src, P2Len, Undef);
Value *P2Dst = vresize(Builder, Dst, P2Len, Undef);
SmallVector<int, 256> SMask(P2Len);
for (int i = 0; i != P2Len; ++i) {
// If i is in [Where, Where+Length), pick Src[Start+(i-Where)].
// Otherwise, pick Dst[i];
SMask[i] =
(Where <= i && i < Where + Length) ? P2Len + Start + (i - Where) : i;
}
Value *P2Insert = Builder.CreateShuffleVector(P2Dst, P2Src, SMask);
return vresize(Builder, P2Insert, DstLen, Undef);
}
auto HexagonVectorCombine::vlalignb(IRBuilder<> &Builder, Value *Lo, Value *Hi,
Value *Amt) const -> Value * {
assert(Lo->getType() == Hi->getType() && "Argument type mismatch");
assert(isSectorTy(Hi->getType()));
if (isZero(Amt))
return Hi;
int VecLen = getSizeOf(Hi);
if (auto IntAmt = getIntValue(Amt))
return getElementRange(Builder, Lo, Hi, VecLen - IntAmt->getSExtValue(),
VecLen);
if (HST.isTypeForHVX(Hi->getType())) {
int HwLen = HST.getVectorLength();
assert(VecLen == HwLen && "Expecting an exact HVX type");
Intrinsic::ID V6_vlalignb = HwLen == 64
? Intrinsic::hexagon_V6_vlalignb
: Intrinsic::hexagon_V6_vlalignb_128B;
return createHvxIntrinsic(Builder, V6_vlalignb, Hi->getType(),
{Hi, Lo, Amt});
}
if (VecLen == 4) {
Value *Pair = concat(Builder, {Lo, Hi});
Value *Shift = Builder.CreateLShr(Builder.CreateShl(Pair, Amt), 32);
Value *Trunc = Builder.CreateTrunc(Shift, Type::getInt32Ty(F.getContext()));
return Builder.CreateBitCast(Trunc, Hi->getType());
}
if (VecLen == 8) {
Value *Sub = Builder.CreateSub(getConstInt(VecLen), Amt);
return vralignb(Builder, Lo, Hi, Sub);
}
llvm_unreachable("Unexpected vector length");
}
auto HexagonVectorCombine::vralignb(IRBuilder<> &Builder, Value *Lo, Value *Hi,
Value *Amt) const -> Value * {
assert(Lo->getType() == Hi->getType() && "Argument type mismatch");
assert(isSectorTy(Lo->getType()));
if (isZero(Amt))
return Lo;
int VecLen = getSizeOf(Lo);
if (auto IntAmt = getIntValue(Amt))
return getElementRange(Builder, Lo, Hi, IntAmt->getSExtValue(), VecLen);
if (HST.isTypeForHVX(Lo->getType())) {
int HwLen = HST.getVectorLength();
assert(VecLen == HwLen && "Expecting an exact HVX type");
Intrinsic::ID V6_valignb = HwLen == 64 ? Intrinsic::hexagon_V6_valignb
: Intrinsic::hexagon_V6_valignb_128B;
return createHvxIntrinsic(Builder, V6_valignb, Lo->getType(),
{Hi, Lo, Amt});
}
if (VecLen == 4) {
Value *Pair = concat(Builder, {Lo, Hi});
Value *Shift = Builder.CreateLShr(Pair, Amt);
Value *Trunc = Builder.CreateTrunc(Shift, Type::getInt32Ty(F.getContext()));
return Builder.CreateBitCast(Trunc, Lo->getType());
}
if (VecLen == 8) {
Type *Int64Ty = Type::getInt64Ty(F.getContext());
Value *Lo64 = Builder.CreateBitCast(Lo, Int64Ty);
Value *Hi64 = Builder.CreateBitCast(Hi, Int64Ty);
Function *FI = Intrinsic::getDeclaration(F.getParent(),
Intrinsic::hexagon_S2_valignrb);
Value *Call = Builder.CreateCall(FI, {Hi64, Lo64, Amt});
return Builder.CreateBitCast(Call, Lo->getType());
}
llvm_unreachable("Unexpected vector length");
}
// Concatenates a sequence of vectors of the same type.
auto HexagonVectorCombine::concat(IRBuilder<> &Builder,
ArrayRef<Value *> Vecs) const -> Value * {
assert(!Vecs.empty());
SmallVector<int, 256> SMask;
std::vector<Value *> Work[2];
int ThisW = 0, OtherW = 1;
Work[ThisW].assign(Vecs.begin(), Vecs.end());
while (Work[ThisW].size() > 1) {
auto *Ty = cast<VectorType>(Work[ThisW].front()->getType());
int ElemCount = Ty->getElementCount().getFixedValue();
SMask.resize(ElemCount * 2);
std::iota(SMask.begin(), SMask.end(), 0);
Work[OtherW].clear();
if (Work[ThisW].size() % 2 != 0)
Work[ThisW].push_back(UndefValue::get(Ty));
for (int i = 0, e = Work[ThisW].size(); i < e; i += 2) {
Value *Joined = Builder.CreateShuffleVector(Work[ThisW][i],
Work[ThisW][i + 1], SMask);
Work[OtherW].push_back(Joined);
}
std::swap(ThisW, OtherW);
}
// Since there may have been some undefs appended to make shuffle operands
// have the same type, perform the last shuffle to only pick the original
// elements.
SMask.resize(Vecs.size() * getSizeOf(Vecs.front()->getType()));
std::iota(SMask.begin(), SMask.end(), 0);
Value *Total = Work[OtherW].front();
return Builder.CreateShuffleVector(Total, SMask);
}
auto HexagonVectorCombine::vresize(IRBuilder<> &Builder, Value *Val,
int NewSize, Value *Pad) const -> Value * {
assert(isa<VectorType>(Val->getType()));
auto *ValTy = cast<VectorType>(Val->getType());
assert(ValTy->getElementType() == Pad->getType());
int CurSize = ValTy->getElementCount().getFixedValue();
if (CurSize == NewSize)
return Val;
// Truncate?
if (CurSize > NewSize)
return getElementRange(Builder, Val, /*Unused*/ Val, 0, NewSize);
// Extend.
SmallVector<int, 128> SMask(NewSize);
std::iota(SMask.begin(), SMask.begin() + CurSize, 0);
std::fill(SMask.begin() + CurSize, SMask.end(), CurSize);
Value *PadVec = Builder.CreateVectorSplat(CurSize, Pad);
return Builder.CreateShuffleVector(Val, PadVec, SMask);
}
auto HexagonVectorCombine::rescale(IRBuilder<> &Builder, Value *Mask,
Type *FromTy, Type *ToTy) const -> Value * {
// Mask is a vector <N x i1>, where each element corresponds to an
// element of FromTy. Remap it so that each element will correspond
// to an element of ToTy.
assert(isa<VectorType>(Mask->getType()));
Type *FromSTy = FromTy->getScalarType();
Type *ToSTy = ToTy->getScalarType();
if (FromSTy == ToSTy)
return Mask;
int FromSize = getSizeOf(FromSTy);
int ToSize = getSizeOf(ToSTy);
assert(FromSize % ToSize == 0 || ToSize % FromSize == 0);
auto *MaskTy = cast<VectorType>(Mask->getType());
int FromCount = MaskTy->getElementCount().getFixedValue();
int ToCount = (FromCount * FromSize) / ToSize;
assert((FromCount * FromSize) % ToSize == 0);
auto *FromITy = IntegerType::get(F.getContext(), FromSize * 8);
auto *ToITy = IntegerType::get(F.getContext(), ToSize * 8);
// Mask <N x i1> -> sext to <N x FromTy> -> bitcast to <M x ToTy> ->
// -> trunc to <M x i1>.
Value *Ext = Builder.CreateSExt(
Mask, VectorType::get(FromITy, FromCount, /*Scalable*/ false));
Value *Cast = Builder.CreateBitCast(
Ext, VectorType::get(ToITy, ToCount, /*Scalable*/ false));
return Builder.CreateTrunc(
Cast, VectorType::get(getBoolTy(), ToCount, /*Scalable*/ false));
}
// Bitcast to bytes, and return least significant bits.
auto HexagonVectorCombine::vlsb(IRBuilder<> &Builder, Value *Val) const
-> Value * {
Type *ScalarTy = Val->getType()->getScalarType();
if (ScalarTy == getBoolTy())
return Val;
Value *Bytes = vbytes(Builder, Val);
if (auto *VecTy = dyn_cast<VectorType>(Bytes->getType()))
return Builder.CreateTrunc(Bytes, getBoolTy(getSizeOf(VecTy)));
// If Bytes is a scalar (i.e. Val was a scalar byte), return i1, not
// <1 x i1>.
return Builder.CreateTrunc(Bytes, getBoolTy());
}
// Bitcast to bytes for non-bool. For bool, convert i1 -> i8.
auto HexagonVectorCombine::vbytes(IRBuilder<> &Builder, Value *Val) const
-> Value * {
Type *ScalarTy = Val->getType()->getScalarType();
if (ScalarTy == getByteTy())
return Val;
if (ScalarTy != getBoolTy())
return Builder.CreateBitCast(Val, getByteTy(getSizeOf(Val)));
// For bool, return a sext from i1 to i8.
if (auto *VecTy = dyn_cast<VectorType>(Val->getType()))
return Builder.CreateSExt(Val, VectorType::get(getByteTy(), VecTy));
return Builder.CreateSExt(Val, getByteTy());
}
auto HexagonVectorCombine::createHvxIntrinsic(IRBuilder<> &Builder,
Intrinsic::ID IntID, Type *RetTy,
ArrayRef<Value *> Args) const
-> Value * {
int HwLen = HST.getVectorLength();
Type *BoolTy = Type::getInt1Ty(F.getContext());
Type *Int32Ty = Type::getInt32Ty(F.getContext());
// HVX vector -> v16i32/v32i32
// HVX vector predicate -> v512i1/v1024i1
auto getTypeForIntrin = [&](Type *Ty) -> Type * {
if (HST.isTypeForHVX(Ty, /*IncludeBool*/ true)) {
Type *ElemTy = cast<VectorType>(Ty)->getElementType();
if (ElemTy == Int32Ty)
return Ty;
if (ElemTy == BoolTy)
return VectorType::get(BoolTy, 8 * HwLen, /*Scalable*/ false);
return VectorType::get(Int32Ty, HwLen / 4, /*Scalable*/ false);
}
// Non-HVX type. It should be a scalar.
assert(Ty == Int32Ty || Ty->isIntegerTy(64));
return Ty;
};
auto getCast = [&](IRBuilder<> &Builder, Value *Val,
Type *DestTy) -> Value * {
Type *SrcTy = Val->getType();
if (SrcTy == DestTy)
return Val;
if (HST.isTypeForHVX(SrcTy, /*IncludeBool*/ true)) {
if (cast<VectorType>(SrcTy)->getElementType() == BoolTy) {
// This should take care of casts the other way too, for example
// v1024i1 -> v32i1.
Intrinsic::ID TC = HwLen == 64
? Intrinsic::hexagon_V6_pred_typecast
: Intrinsic::hexagon_V6_pred_typecast_128B;
Function *FI = Intrinsic::getDeclaration(F.getParent(), TC,
{DestTy, Val->getType()});
return Builder.CreateCall(FI, {Val});
}
// Non-predicate HVX vector.
return Builder.CreateBitCast(Val, DestTy);
}
// Non-HVX type. It should be a scalar, and it should already have
// a valid type.
llvm_unreachable("Unexpected type");
};
SmallVector<Value *, 4> IntOps;
for (Value *A : Args)
IntOps.push_back(getCast(Builder, A, getTypeForIntrin(A->getType())));
Function *FI = Intrinsic::getDeclaration(F.getParent(), IntID);
Value *Call = Builder.CreateCall(FI, IntOps);
Type *CallTy = Call->getType();
if (CallTy == RetTy)
return Call;
// Scalar types should have RetTy matching the call return type.
assert(HST.isTypeForHVX(CallTy, /*IncludeBool*/ true));
if (cast<VectorType>(CallTy)->getElementType() == BoolTy)
return getCast(Builder, Call, RetTy);
return Builder.CreateBitCast(Call, RetTy);
}
auto HexagonVectorCombine::calculatePointerDifference(Value *Ptr0,
Value *Ptr1) const
-> Optional<int> {
struct Builder : IRBuilder<> {
Builder(BasicBlock *B) : IRBuilder<>(B) {}
~Builder() {
for (Instruction *I : llvm::reverse(ToErase))
I->eraseFromParent();
}
SmallVector<Instruction *, 8> ToErase;
};
#define CallBuilder(B, F) \
[&](auto &B_) { \
Value *V = B_.F; \
if (auto *I = dyn_cast<Instruction>(V)) \
B_.ToErase.push_back(I); \
return V; \
}(B)
auto Simplify = [&](Value *V) {
if (auto *I = dyn_cast<Instruction>(V)) {
SimplifyQuery Q(DL, &TLI, &DT, &AC, I);
if (Value *S = simplifyInstruction(I, Q))
return S;
}
return V;
};
auto StripBitCast = [](Value *V) {
while (auto *C = dyn_cast<BitCastInst>(V))
V = C->getOperand(0);
return V;
};
Ptr0 = StripBitCast(Ptr0);
Ptr1 = StripBitCast(Ptr1);
if (!isa<GetElementPtrInst>(Ptr0) || !isa<GetElementPtrInst>(Ptr1))
return None;
auto *Gep0 = cast<GetElementPtrInst>(Ptr0);
auto *Gep1 = cast<GetElementPtrInst>(Ptr1);
if (Gep0->getPointerOperand() != Gep1->getPointerOperand())
return None;
Builder B(Gep0->getParent());
int Scale = getAllocSizeOf(Gep0->getSourceElementType());
// FIXME: for now only check GEPs with a single index.
if (Gep0->getNumOperands() != 2 || Gep1->getNumOperands() != 2)
return None;
Value *Idx0 = Gep0->getOperand(1);
Value *Idx1 = Gep1->getOperand(1);
// First, try to simplify the subtraction directly.
if (auto *Diff = dyn_cast<ConstantInt>(
Simplify(CallBuilder(B, CreateSub(Idx0, Idx1)))))
return Diff->getSExtValue() * Scale;
KnownBits Known0 = computeKnownBits(Idx0, DL, 0, &AC, Gep0, &DT);
KnownBits Known1 = computeKnownBits(Idx1, DL, 0, &AC, Gep1, &DT);
APInt Unknown = ~(Known0.Zero | Known0.One) | ~(Known1.Zero | Known1.One);
if (Unknown.isAllOnes())
return None;
Value *MaskU = ConstantInt::get(Idx0->getType(), Unknown);
Value *AndU0 = Simplify(CallBuilder(B, CreateAnd(Idx0, MaskU)));
Value *AndU1 = Simplify(CallBuilder(B, CreateAnd(Idx1, MaskU)));
Value *SubU = Simplify(CallBuilder(B, CreateSub(AndU0, AndU1)));
int Diff0 = 0;
if (auto *C = dyn_cast<ConstantInt>(SubU)) {
Diff0 = C->getSExtValue();
} else {
return None;
}
Value *MaskK = ConstantInt::get(MaskU->getType(), ~Unknown);
Value *AndK0 = Simplify(CallBuilder(B, CreateAnd(Idx0, MaskK)));
Value *AndK1 = Simplify(CallBuilder(B, CreateAnd(Idx1, MaskK)));
Value *SubK = Simplify(CallBuilder(B, CreateSub(AndK0, AndK1)));
int Diff1 = 0;
if (auto *C = dyn_cast<ConstantInt>(SubK)) {
Diff1 = C->getSExtValue();
} else {
return None;
}
return (Diff0 + Diff1) * Scale;
#undef CallBuilder
}
template <typename T>
auto HexagonVectorCombine::isSafeToMoveBeforeInBB(const Instruction &In,
BasicBlock::const_iterator To,
const T &Ignore) const
-> bool {
auto getLocOrNone = [this](const Instruction &I) -> Optional<MemoryLocation> {
if (const auto *II = dyn_cast<IntrinsicInst>(&I)) {
switch (II->getIntrinsicID()) {
case Intrinsic::masked_load:
return MemoryLocation::getForArgument(II, 0, TLI);
case Intrinsic::masked_store:
return MemoryLocation::getForArgument(II, 1, TLI);
}
}
return MemoryLocation::getOrNone(&I);
};
// The source and the destination must be in the same basic block.
const BasicBlock &Block = *In.getParent();
assert(Block.begin() == To || Block.end() == To || To->getParent() == &Block);
// No PHIs.
if (isa<PHINode>(In) || (To != Block.end() && isa<PHINode>(*To)))
return false;
if (!mayHaveNonDefUseDependency(In))
return true;
bool MayWrite = In.mayWriteToMemory();
auto MaybeLoc = getLocOrNone(In);
auto From = In.getIterator();
if (From == To)
return true;
bool MoveUp = (To != Block.end() && To->comesBefore(&In));
auto Range =
MoveUp ? std::make_pair(To, From) : std::make_pair(std::next(From), To);
for (auto It = Range.first; It != Range.second; ++It) {
const Instruction &I = *It;
if (llvm::is_contained(Ignore, &I))
continue;
// assume intrinsic can be ignored
if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
if (II->getIntrinsicID() == Intrinsic::assume)
continue;
}
// Parts based on isSafeToMoveBefore from CoveMoverUtils.cpp.
if (I.mayThrow())
return false;
if (auto *CB = dyn_cast<CallBase>(&I)) {
if (!CB->hasFnAttr(Attribute::WillReturn))
return false;
if (!CB->hasFnAttr(Attribute::NoSync))
return false;
}
if (I.mayReadOrWriteMemory()) {
auto MaybeLocI = getLocOrNone(I);
if (MayWrite || I.mayWriteToMemory()) {
if (!MaybeLoc || !MaybeLocI)
return false;
if (!AA.isNoAlias(*MaybeLoc, *MaybeLocI))
return false;
}
}
}
return true;
}
#ifndef NDEBUG
auto HexagonVectorCombine::isByteVecTy(Type *Ty) const -> bool {
if (auto *VecTy = dyn_cast<VectorType>(Ty))
return VecTy->getElementType() == getByteTy();
return false;
}
auto HexagonVectorCombine::isSectorTy(Type *Ty) const -> bool {
if (!isByteVecTy(Ty))
return false;
int Size = getSizeOf(Ty);
if (HST.isTypeForHVX(Ty))
return Size == static_cast<int>(HST.getVectorLength());
return Size == 4 || Size == 8;
}
#endif
auto HexagonVectorCombine::getElementRange(IRBuilder<> &Builder, Value *Lo,
Value *Hi, int Start,
int Length) const -> Value * {
assert(0 <= Start && Start < Length);
SmallVector<int, 128> SMask(Length);
std::iota(SMask.begin(), SMask.end(), Start);
return Builder.CreateShuffleVector(Lo, Hi, SMask);
}
// Pass management.
namespace llvm {
void initializeHexagonVectorCombineLegacyPass(PassRegistry &);
FunctionPass *createHexagonVectorCombineLegacyPass();
} // namespace llvm
namespace {
class HexagonVectorCombineLegacy : public FunctionPass {
public:
static char ID;
HexagonVectorCombineLegacy() : FunctionPass(ID) {}
StringRef getPassName() const override { return "Hexagon Vector Combine"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
AU.addRequired<AAResultsWrapperPass>();
AU.addRequired<AssumptionCacheTracker>();
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<TargetLibraryInfoWrapperPass>();
AU.addRequired<TargetPassConfig>();
FunctionPass::getAnalysisUsage(AU);
}
bool runOnFunction(Function &F) override {
if (skipFunction(F))
return false;
AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
AssumptionCache &AC =
getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
TargetLibraryInfo &TLI =
getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
auto &TM = getAnalysis<TargetPassConfig>().getTM<HexagonTargetMachine>();
HexagonVectorCombine HVC(F, AA, AC, DT, TLI, TM);
return HVC.run();
}
};
} // namespace
char HexagonVectorCombineLegacy::ID = 0;
INITIALIZE_PASS_BEGIN(HexagonVectorCombineLegacy, DEBUG_TYPE,
"Hexagon Vector Combine", false, false)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_END(HexagonVectorCombineLegacy, DEBUG_TYPE,
"Hexagon Vector Combine", false, false)
FunctionPass *llvm::createHexagonVectorCombineLegacyPass() {
return new HexagonVectorCombineLegacy();
}
diff --git a/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVDuplicatesTracker.cpp b/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVDuplicatesTracker.cpp
index 1926977ea66e..2e426bb79cae 100644
--- a/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVDuplicatesTracker.cpp
+++ b/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVDuplicatesTracker.cpp
@@ -1,95 +1,97 @@
//===-- SPIRVDuplicatesTracker.cpp - SPIR-V Duplicates Tracker --*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// General infrastructure for keeping track of the values that according to
// the SPIR-V binary layout should be global to the whole module.
//
//===----------------------------------------------------------------------===//
#include "SPIRVDuplicatesTracker.h"
using namespace llvm;
template <typename T>
void SPIRVGeneralDuplicatesTracker::prebuildReg2Entry(
SPIRVDuplicatesTracker<T> &DT, SPIRVReg2EntryTy &Reg2Entry) {
for (auto &TPair : DT.getAllUses()) {
for (auto &RegPair : TPair.second) {
const MachineFunction *MF = RegPair.first;
Register R = RegPair.second;
MachineInstr *MI = MF->getRegInfo().getUniqueVRegDef(R);
if (!MI)
continue;
Reg2Entry[&MI->getOperand(0)] = &TPair.second;
}
}
}
void SPIRVGeneralDuplicatesTracker::buildDepsGraph(
std::vector<SPIRV::DTSortableEntry *> &Graph,
MachineModuleInfo *MMI = nullptr) {
SPIRVReg2EntryTy Reg2Entry;
prebuildReg2Entry(TT, Reg2Entry);
prebuildReg2Entry(CT, Reg2Entry);
prebuildReg2Entry(GT, Reg2Entry);
prebuildReg2Entry(FT, Reg2Entry);
prebuildReg2Entry(AT, Reg2Entry);
for (auto &Op2E : Reg2Entry) {
SPIRV::DTSortableEntry *E = Op2E.second;
Graph.push_back(E);
for (auto &U : *E) {
const MachineRegisterInfo &MRI = U.first->getRegInfo();
MachineInstr *MI = MRI.getUniqueVRegDef(U.second);
if (!MI)
continue;
assert(MI && MI->getParent() && "No MachineInstr created yet");
for (auto i = MI->getNumDefs(); i < MI->getNumOperands(); i++) {
MachineOperand &Op = MI->getOperand(i);
if (!Op.isReg())
continue;
MachineOperand *RegOp = &MRI.getVRegDef(Op.getReg())->getOperand(0);
assert((MI->getOpcode() == SPIRV::OpVariable && i == 3) ||
Reg2Entry.count(RegOp));
if (Reg2Entry.count(RegOp))
E->addDep(Reg2Entry[RegOp]);
}
if (E->getIsFunc()) {
MachineInstr *Next = MI->getNextNode();
if (Next && (Next->getOpcode() == SPIRV::OpFunction ||
Next->getOpcode() == SPIRV::OpFunctionParameter)) {
E->addDep(Reg2Entry[&Next->getOperand(0)]);
}
}
}
}
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
if (MMI) {
const Module *M = MMI->getModule();
for (auto F = M->begin(), E = M->end(); F != E; ++F) {
const MachineFunction *MF = MMI->getMachineFunction(*F);
if (!MF)
continue;
for (const MachineBasicBlock &MBB : *MF) {
for (const MachineInstr &CMI : MBB) {
MachineInstr &MI = const_cast<MachineInstr &>(CMI);
MI.dump();
if (MI.getNumExplicitDefs() > 0 &&
Reg2Entry.count(&MI.getOperand(0))) {
dbgs() << "\t[";
for (SPIRV::DTSortableEntry *D :
Reg2Entry.lookup(&MI.getOperand(0))->getDeps())
dbgs() << Register::virtReg2Index(D->lookup(MF)) << ", ";
dbgs() << "]\n";
}
}
}
}
}
+#endif
}
diff --git a/contrib/llvm-project/llvm/lib/Target/X86/X86.td b/contrib/llvm-project/llvm/lib/Target/X86/X86.td
index fa0a6bd415dc..f98916e81cee 100644
--- a/contrib/llvm-project/llvm/lib/Target/X86/X86.td
+++ b/contrib/llvm-project/llvm/lib/Target/X86/X86.td
@@ -1,1659 +1,1658 @@
//===-- X86.td - Target definition file for the Intel X86 --*- tablegen -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is a target description file for the Intel i386 architecture, referred
// to here as the "X86" architecture.
//
//===----------------------------------------------------------------------===//
// Get the target-independent interfaces which we are implementing...
//
include "llvm/Target/Target.td"
//===----------------------------------------------------------------------===//
// X86 Subtarget state
//
// disregarding specific ABI / programming model
def Is64Bit : SubtargetFeature<"64bit-mode", "Is64Bit", "true",
"64-bit mode (x86_64)">;
def Is32Bit : SubtargetFeature<"32bit-mode", "Is32Bit", "true",
"32-bit mode (80386)">;
def Is16Bit : SubtargetFeature<"16bit-mode", "Is16Bit", "true",
"16-bit mode (i8086)">;
//===----------------------------------------------------------------------===//
// X86 Subtarget ISA features
//===----------------------------------------------------------------------===//
def FeatureX87 : SubtargetFeature<"x87","HasX87", "true",
"Enable X87 float instructions">;
def FeatureNOPL : SubtargetFeature<"nopl", "HasNOPL", "true",
"Enable NOPL instruction (generally pentium pro+)">;
def FeatureCMOV : SubtargetFeature<"cmov","HasCMOV", "true",
"Enable conditional move instructions">;
def FeatureCX8 : SubtargetFeature<"cx8", "HasCX8", "true",
"Support CMPXCHG8B instructions">;
def FeatureCRC32 : SubtargetFeature<"crc32", "HasCRC32", "true",
"Enable SSE 4.2 CRC32 instruction (used when SSE4.2 is supported but function is GPR only)">;
def FeaturePOPCNT : SubtargetFeature<"popcnt", "HasPOPCNT", "true",
"Support POPCNT instruction">;
def FeatureFXSR : SubtargetFeature<"fxsr", "HasFXSR", "true",
"Support fxsave/fxrestore instructions">;
def FeatureXSAVE : SubtargetFeature<"xsave", "HasXSAVE", "true",
"Support xsave instructions">;
def FeatureXSAVEOPT: SubtargetFeature<"xsaveopt", "HasXSAVEOPT", "true",
"Support xsaveopt instructions",
[FeatureXSAVE]>;
def FeatureXSAVEC : SubtargetFeature<"xsavec", "HasXSAVEC", "true",
"Support xsavec instructions",
[FeatureXSAVE]>;
def FeatureXSAVES : SubtargetFeature<"xsaves", "HasXSAVES", "true",
"Support xsaves instructions",
[FeatureXSAVE]>;
def FeatureSSE1 : SubtargetFeature<"sse", "X86SSELevel", "SSE1",
"Enable SSE instructions">;
def FeatureSSE2 : SubtargetFeature<"sse2", "X86SSELevel", "SSE2",
"Enable SSE2 instructions",
[FeatureSSE1]>;
def FeatureSSE3 : SubtargetFeature<"sse3", "X86SSELevel", "SSE3",
"Enable SSE3 instructions",
[FeatureSSE2]>;
def FeatureSSSE3 : SubtargetFeature<"ssse3", "X86SSELevel", "SSSE3",
"Enable SSSE3 instructions",
[FeatureSSE3]>;
def FeatureSSE41 : SubtargetFeature<"sse4.1", "X86SSELevel", "SSE41",
"Enable SSE 4.1 instructions",
[FeatureSSSE3]>;
def FeatureSSE42 : SubtargetFeature<"sse4.2", "X86SSELevel", "SSE42",
"Enable SSE 4.2 instructions",
[FeatureSSE41]>;
// The MMX subtarget feature is separate from the rest of the SSE features
// because it's important (for odd compatibility reasons) to be able to
// turn it off explicitly while allowing SSE+ to be on.
def FeatureMMX : SubtargetFeature<"mmx","X863DNowLevel", "MMX",
"Enable MMX instructions">;
def Feature3DNow : SubtargetFeature<"3dnow", "X863DNowLevel", "ThreeDNow",
"Enable 3DNow! instructions",
[FeatureMMX]>;
def Feature3DNowA : SubtargetFeature<"3dnowa", "X863DNowLevel", "ThreeDNowA",
"Enable 3DNow! Athlon instructions",
[Feature3DNow]>;
// All x86-64 hardware has SSE2, but we don't mark SSE2 as an implied
// feature, because SSE2 can be disabled (e.g. for compiling OS kernels)
// without disabling 64-bit mode. Nothing should imply this feature bit. It
// is used to enforce that only 64-bit capable CPUs are used in 64-bit mode.
def FeatureX86_64 : SubtargetFeature<"64bit", "HasX86_64", "true",
"Support 64-bit instructions">;
def FeatureCX16 : SubtargetFeature<"cx16", "HasCX16", "true",
"64-bit with cmpxchg16b (this is true for most x86-64 chips, but not the first AMD chips)",
[FeatureCX8]>;
def FeatureSSE4A : SubtargetFeature<"sse4a", "HasSSE4A", "true",
"Support SSE 4a instructions",
[FeatureSSE3]>;
def FeatureAVX : SubtargetFeature<"avx", "X86SSELevel", "AVX",
"Enable AVX instructions",
[FeatureSSE42]>;
def FeatureAVX2 : SubtargetFeature<"avx2", "X86SSELevel", "AVX2",
"Enable AVX2 instructions",
[FeatureAVX]>;
def FeatureFMA : SubtargetFeature<"fma", "HasFMA", "true",
"Enable three-operand fused multiple-add",
[FeatureAVX]>;
def FeatureF16C : SubtargetFeature<"f16c", "HasF16C", "true",
"Support 16-bit floating point conversion instructions",
[FeatureAVX]>;
def FeatureAVX512 : SubtargetFeature<"avx512f", "X86SSELevel", "AVX512",
"Enable AVX-512 instructions",
[FeatureAVX2, FeatureFMA, FeatureF16C]>;
def FeatureERI : SubtargetFeature<"avx512er", "HasERI", "true",
"Enable AVX-512 Exponential and Reciprocal Instructions",
[FeatureAVX512]>;
def FeatureCDI : SubtargetFeature<"avx512cd", "HasCDI", "true",
"Enable AVX-512 Conflict Detection Instructions",
[FeatureAVX512]>;
def FeatureVPOPCNTDQ : SubtargetFeature<"avx512vpopcntdq", "HasVPOPCNTDQ",
"true", "Enable AVX-512 Population Count Instructions",
[FeatureAVX512]>;
def FeaturePFI : SubtargetFeature<"avx512pf", "HasPFI", "true",
"Enable AVX-512 PreFetch Instructions",
[FeatureAVX512]>;
def FeaturePREFETCHWT1 : SubtargetFeature<"prefetchwt1", "HasPREFETCHWT1",
"true",
"Prefetch with Intent to Write and T1 Hint">;
def FeatureDQI : SubtargetFeature<"avx512dq", "HasDQI", "true",
"Enable AVX-512 Doubleword and Quadword Instructions",
[FeatureAVX512]>;
def FeatureBWI : SubtargetFeature<"avx512bw", "HasBWI", "true",
"Enable AVX-512 Byte and Word Instructions",
[FeatureAVX512]>;
def FeatureVLX : SubtargetFeature<"avx512vl", "HasVLX", "true",
"Enable AVX-512 Vector Length eXtensions",
[FeatureAVX512]>;
def FeatureVBMI : SubtargetFeature<"avx512vbmi", "HasVBMI", "true",
"Enable AVX-512 Vector Byte Manipulation Instructions",
[FeatureBWI]>;
def FeatureVBMI2 : SubtargetFeature<"avx512vbmi2", "HasVBMI2", "true",
"Enable AVX-512 further Vector Byte Manipulation Instructions",
[FeatureBWI]>;
def FeatureIFMA : SubtargetFeature<"avx512ifma", "HasIFMA", "true",
"Enable AVX-512 Integer Fused Multiple-Add",
[FeatureAVX512]>;
def FeaturePKU : SubtargetFeature<"pku", "HasPKU", "true",
"Enable protection keys">;
def FeatureVNNI : SubtargetFeature<"avx512vnni", "HasVNNI", "true",
"Enable AVX-512 Vector Neural Network Instructions",
[FeatureAVX512]>;
def FeatureAVXVNNI : SubtargetFeature<"avxvnni", "HasAVXVNNI", "true",
"Support AVX_VNNI encoding",
[FeatureAVX2]>;
def FeatureBF16 : SubtargetFeature<"avx512bf16", "HasBF16", "true",
"Support bfloat16 floating point",
[FeatureBWI]>;
def FeatureBITALG : SubtargetFeature<"avx512bitalg", "HasBITALG", "true",
"Enable AVX-512 Bit Algorithms",
[FeatureBWI]>;
def FeatureVP2INTERSECT : SubtargetFeature<"avx512vp2intersect",
"HasVP2INTERSECT", "true",
"Enable AVX-512 vp2intersect",
[FeatureAVX512]>;
// FIXME: FP16 scalar intrinsics use the type v8f16, which is supposed to be
// guarded under condition hasVLX. So we imply it in FeatureFP16 currently.
// FIXME: FP16 conversion between f16 and i64 customize type v8i64, which is
// supposed to be guarded under condition hasDQI. So we imply it in FeatureFP16
// currently.
def FeatureFP16 : SubtargetFeature<"avx512fp16", "HasFP16", "true",
"Support 16-bit floating point",
[FeatureBWI, FeatureVLX, FeatureDQI]>;
def FeaturePCLMUL : SubtargetFeature<"pclmul", "HasPCLMUL", "true",
"Enable packed carry-less multiplication instructions",
[FeatureSSE2]>;
def FeatureGFNI : SubtargetFeature<"gfni", "HasGFNI", "true",
"Enable Galois Field Arithmetic Instructions",
[FeatureSSE2]>;
def FeatureVPCLMULQDQ : SubtargetFeature<"vpclmulqdq", "HasVPCLMULQDQ", "true",
"Enable vpclmulqdq instructions",
[FeatureAVX, FeaturePCLMUL]>;
def FeatureFMA4 : SubtargetFeature<"fma4", "HasFMA4", "true",
"Enable four-operand fused multiple-add",
[FeatureAVX, FeatureSSE4A]>;
def FeatureXOP : SubtargetFeature<"xop", "HasXOP", "true",
"Enable XOP instructions",
[FeatureFMA4]>;
def FeatureSSEUnalignedMem : SubtargetFeature<"sse-unaligned-mem",
"HasSSEUnalignedMem", "true",
"Allow unaligned memory operands with SSE instructions (this may require setting a configuration bit in the processor)">;
def FeatureAES : SubtargetFeature<"aes", "HasAES", "true",
"Enable AES instructions",
[FeatureSSE2]>;
def FeatureVAES : SubtargetFeature<"vaes", "HasVAES", "true",
"Promote selected AES instructions to AVX512/AVX registers",
[FeatureAVX, FeatureAES]>;
def FeatureTBM : SubtargetFeature<"tbm", "HasTBM", "true",
"Enable TBM instructions">;
def FeatureLWP : SubtargetFeature<"lwp", "HasLWP", "true",
"Enable LWP instructions">;
def FeatureMOVBE : SubtargetFeature<"movbe", "HasMOVBE", "true",
"Support MOVBE instruction">;
def FeatureRDRAND : SubtargetFeature<"rdrnd", "HasRDRAND", "true",
"Support RDRAND instruction">;
def FeatureFSGSBase : SubtargetFeature<"fsgsbase", "HasFSGSBase", "true",
"Support FS/GS Base instructions">;
def FeatureLZCNT : SubtargetFeature<"lzcnt", "HasLZCNT", "true",
"Support LZCNT instruction">;
def FeatureBMI : SubtargetFeature<"bmi", "HasBMI", "true",
"Support BMI instructions">;
def FeatureBMI2 : SubtargetFeature<"bmi2", "HasBMI2", "true",
"Support BMI2 instructions">;
def FeatureRTM : SubtargetFeature<"rtm", "HasRTM", "true",
"Support RTM instructions">;
def FeatureADX : SubtargetFeature<"adx", "HasADX", "true",
"Support ADX instructions">;
def FeatureSHA : SubtargetFeature<"sha", "HasSHA", "true",
"Enable SHA instructions",
[FeatureSSE2]>;
// Processor supports CET SHSTK - Control-Flow Enforcement Technology
// using Shadow Stack
def FeatureSHSTK : SubtargetFeature<"shstk", "HasSHSTK", "true",
"Support CET Shadow-Stack instructions">;
def FeaturePRFCHW : SubtargetFeature<"prfchw", "HasPRFCHW", "true",
"Support PRFCHW instructions">;
def FeatureRDSEED : SubtargetFeature<"rdseed", "HasRDSEED", "true",
"Support RDSEED instruction">;
def FeatureLAHFSAHF64 : SubtargetFeature<"sahf", "HasLAHFSAHF64", "true",
"Support LAHF and SAHF instructions in 64-bit mode">;
def FeatureMWAITX : SubtargetFeature<"mwaitx", "HasMWAITX", "true",
"Enable MONITORX/MWAITX timer functionality">;
def FeatureCLZERO : SubtargetFeature<"clzero", "HasCLZERO", "true",
"Enable Cache Line Zero">;
def FeatureCLDEMOTE : SubtargetFeature<"cldemote", "HasCLDEMOTE", "true",
"Enable Cache Line Demote">;
def FeaturePTWRITE : SubtargetFeature<"ptwrite", "HasPTWRITE", "true",
"Support ptwrite instruction">;
def FeatureAMXTILE : SubtargetFeature<"amx-tile", "HasAMXTILE", "true",
"Support AMX-TILE instructions">;
def FeatureAMXINT8 : SubtargetFeature<"amx-int8", "HasAMXINT8", "true",
"Support AMX-INT8 instructions",
[FeatureAMXTILE]>;
def FeatureAMXBF16 : SubtargetFeature<"amx-bf16", "HasAMXBF16", "true",
"Support AMX-BF16 instructions",
[FeatureAMXTILE]>;
def FeatureINVPCID : SubtargetFeature<"invpcid", "HasINVPCID", "true",
"Invalidate Process-Context Identifier">;
def FeatureSGX : SubtargetFeature<"sgx", "HasSGX", "true",
"Enable Software Guard Extensions">;
def FeatureCLFLUSHOPT : SubtargetFeature<"clflushopt", "HasCLFLUSHOPT", "true",
"Flush A Cache Line Optimized">;
def FeatureCLWB : SubtargetFeature<"clwb", "HasCLWB", "true",
"Cache Line Write Back">;
def FeatureWBNOINVD : SubtargetFeature<"wbnoinvd", "HasWBNOINVD", "true",
"Write Back No Invalidate">;
def FeatureRDPID : SubtargetFeature<"rdpid", "HasRDPID", "true",
"Support RDPID instructions">;
def FeatureRDPRU : SubtargetFeature<"rdpru", "HasRDPRU", "true",
"Support RDPRU instructions">;
def FeatureWAITPKG : SubtargetFeature<"waitpkg", "HasWAITPKG", "true",
"Wait and pause enhancements">;
def FeatureENQCMD : SubtargetFeature<"enqcmd", "HasENQCMD", "true",
"Has ENQCMD instructions">;
def FeatureKL : SubtargetFeature<"kl", "HasKL", "true",
"Support Key Locker kl Instructions",
[FeatureSSE2]>;
def FeatureWIDEKL : SubtargetFeature<"widekl", "HasWIDEKL", "true",
"Support Key Locker wide Instructions",
[FeatureKL]>;
def FeatureHRESET : SubtargetFeature<"hreset", "HasHRESET", "true",
"Has hreset instruction">;
def FeatureSERIALIZE : SubtargetFeature<"serialize", "HasSERIALIZE", "true",
"Has serialize instruction">;
def FeatureTSXLDTRK : SubtargetFeature<"tsxldtrk", "HasTSXLDTRK", "true",
"Support TSXLDTRK instructions">;
def FeatureUINTR : SubtargetFeature<"uintr", "HasUINTR", "true",
"Has UINTR Instructions">;
def FeaturePCONFIG : SubtargetFeature<"pconfig", "HasPCONFIG", "true",
"platform configuration instruction">;
def FeatureMOVDIRI : SubtargetFeature<"movdiri", "HasMOVDIRI", "true",
"Support movdiri instruction (direct store integer)">;
def FeatureMOVDIR64B : SubtargetFeature<"movdir64b", "HasMOVDIR64B", "true",
"Support movdir64b instruction (direct store 64 bytes)">;
// Ivy Bridge and newer processors have enhanced REP MOVSB and STOSB (aka
// "string operations"). See "REP String Enhancement" in the Intel Software
// Development Manual. This feature essentially means that REP MOVSB will copy
// using the largest available size instead of copying bytes one by one, making
// it at least as fast as REPMOVS{W,D,Q}.
def FeatureERMSB
: SubtargetFeature<
"ermsb", "HasERMSB", "true",
"REP MOVS/STOS are fast">;
// Icelake and newer processors have Fast Short REP MOV.
def FeatureFSRM
: SubtargetFeature<
"fsrm", "HasFSRM", "true",
"REP MOVSB of short lengths is faster">;
def FeatureSoftFloat
: SubtargetFeature<"soft-float", "UseSoftFloat", "true",
"Use software floating point features">;
//===----------------------------------------------------------------------===//
// X86 Subtarget Security Mitigation features
//===----------------------------------------------------------------------===//
// Lower indirect calls using a special construct called a `retpoline` to
// mitigate potential Spectre v2 attacks against them.
def FeatureRetpolineIndirectCalls
: SubtargetFeature<
"retpoline-indirect-calls", "UseRetpolineIndirectCalls", "true",
"Remove speculation of indirect calls from the generated code">;
// Lower indirect branches and switches either using conditional branch trees
// or using a special construct called a `retpoline` to mitigate potential
// Spectre v2 attacks against them.
def FeatureRetpolineIndirectBranches
: SubtargetFeature<
"retpoline-indirect-branches", "UseRetpolineIndirectBranches", "true",
"Remove speculation of indirect branches from the generated code">;
// Deprecated umbrella feature for enabling both `retpoline-indirect-calls` and
// `retpoline-indirect-branches` above.
def FeatureRetpoline
: SubtargetFeature<"retpoline", "DeprecatedUseRetpoline", "true",
"Remove speculation of indirect branches from the "
"generated code, either by avoiding them entirely or "
"lowering them with a speculation blocking construct",
[FeatureRetpolineIndirectCalls,
FeatureRetpolineIndirectBranches]>;
// Rely on external thunks for the emitted retpoline calls. This allows users
// to provide their own custom thunk definitions in highly specialized
// environments such as a kernel that does boot-time hot patching.
def FeatureRetpolineExternalThunk
: SubtargetFeature<
"retpoline-external-thunk", "UseRetpolineExternalThunk", "true",
"When lowering an indirect call or branch using a `retpoline`, rely "
"on the specified user provided thunk rather than emitting one "
"ourselves. Only has effect when combined with some other retpoline "
"feature", [FeatureRetpolineIndirectCalls]>;
// Mitigate LVI attacks against indirect calls/branches and call returns
def FeatureLVIControlFlowIntegrity
: SubtargetFeature<
"lvi-cfi", "UseLVIControlFlowIntegrity", "true",
"Prevent indirect calls/branches from using a memory operand, and "
"precede all indirect calls/branches from a register with an "
"LFENCE instruction to serialize control flow. Also decompose RET "
"instructions into a POP+LFENCE+JMP sequence.">;
// Enable SESES to mitigate speculative execution attacks
def FeatureSpeculativeExecutionSideEffectSuppression
: SubtargetFeature<
"seses", "UseSpeculativeExecutionSideEffectSuppression", "true",
"Prevent speculative execution side channel timing attacks by "
"inserting a speculation barrier before memory reads, memory writes, "
"and conditional branches. Implies LVI Control Flow integrity.",
[FeatureLVIControlFlowIntegrity]>;
// Mitigate LVI attacks against data loads
def FeatureLVILoadHardening
: SubtargetFeature<
"lvi-load-hardening", "UseLVILoadHardening", "true",
"Insert LFENCE instructions to prevent data speculatively injected "
"into loads from being used maliciously.">;
def FeatureTaggedGlobals
: SubtargetFeature<
"tagged-globals", "AllowTaggedGlobals", "true",
"Use an instruction sequence for taking the address of a global "
"that allows a memory tag in the upper address bits.">;
// Control codegen mitigation against Straight Line Speculation vulnerability.
def FeatureHardenSlsRet
: SubtargetFeature<
"harden-sls-ret", "HardenSlsRet", "true",
"Harden against straight line speculation across RET instructions.">;
def FeatureHardenSlsIJmp
: SubtargetFeature<
"harden-sls-ijmp", "HardenSlsIJmp", "true",
"Harden against straight line speculation across indirect JMP instructions.">;
//===----------------------------------------------------------------------===//
// X86 Subtarget Tuning features
//===----------------------------------------------------------------------===//
def TuningSlowSHLD : SubtargetFeature<"slow-shld", "IsSHLDSlow", "true",
"SHLD instruction is slow">;
def TuningSlowPMULLD : SubtargetFeature<"slow-pmulld", "IsPMULLDSlow", "true",
"PMULLD instruction is slow (compared to PMULLW/PMULHW and PMULUDQ)">;
def TuningSlowPMADDWD : SubtargetFeature<"slow-pmaddwd", "IsPMADDWDSlow",
"true",
"PMADDWD is slower than PMULLD">;
// FIXME: This should not apply to CPUs that do not have SSE.
def TuningSlowUAMem16 : SubtargetFeature<"slow-unaligned-mem-16",
"IsUnalignedMem16Slow", "true",
"Slow unaligned 16-byte memory access">;
def TuningSlowUAMem32 : SubtargetFeature<"slow-unaligned-mem-32",
"IsUnalignedMem32Slow", "true",
"Slow unaligned 32-byte memory access">;
def TuningLEAForSP : SubtargetFeature<"lea-sp", "UseLeaForSP", "true",
"Use LEA for adjusting the stack pointer (this is an optimization for Intel Atom processors)">;
// True if 8-bit divisions are significantly faster than
// 32-bit divisions and should be used when possible.
def TuningSlowDivide32 : SubtargetFeature<"idivl-to-divb",
"HasSlowDivide32", "true",
"Use 8-bit divide for positive values less than 256">;
// True if 32-bit divides are significantly faster than
// 64-bit divisions and should be used when possible.
def TuningSlowDivide64 : SubtargetFeature<"idivq-to-divl",
"HasSlowDivide64", "true",
"Use 32-bit divide for positive values less than 2^32">;
def TuningPadShortFunctions : SubtargetFeature<"pad-short-functions",
"PadShortFunctions", "true",
"Pad short functions (to prevent a stall when returning too early)">;
// On some processors, instructions that implicitly take two memory operands are
// slow. In practice, this means that CALL, PUSH, and POP with memory operands
// should be avoided in favor of a MOV + register CALL/PUSH/POP.
def TuningSlowTwoMemOps : SubtargetFeature<"slow-two-mem-ops",
"SlowTwoMemOps", "true",
"Two memory operand instructions are slow">;
// True if the LEA instruction inputs have to be ready at address generation
// (AG) time.
def TuningLEAUsesAG : SubtargetFeature<"lea-uses-ag", "LeaUsesAG", "true",
"LEA instruction needs inputs at AG stage">;
def TuningSlowLEA : SubtargetFeature<"slow-lea", "SlowLEA", "true",
"LEA instruction with certain arguments is slow">;
// True if the LEA instruction has all three source operands: base, index,
// and offset or if the LEA instruction uses base and index registers where
// the base is EBP, RBP,or R13
def TuningSlow3OpsLEA : SubtargetFeature<"slow-3ops-lea", "Slow3OpsLEA", "true",
"LEA instruction with 3 ops or certain registers is slow">;
// True if INC and DEC instructions are slow when writing to flags
def TuningSlowIncDec : SubtargetFeature<"slow-incdec", "SlowIncDec", "true",
"INC and DEC instructions are slower than ADD and SUB">;
def TuningPOPCNTFalseDeps : SubtargetFeature<"false-deps-popcnt",
"HasPOPCNTFalseDeps", "true",
"POPCNT has a false dependency on dest register">;
def TuningLZCNTFalseDeps : SubtargetFeature<"false-deps-lzcnt-tzcnt",
"HasLZCNTFalseDeps", "true",
"LZCNT/TZCNT have a false dependency on dest register">;
def TuningMULCFalseDeps : SubtargetFeature<"false-deps-mulc",
"HasMULCFalseDeps", "true",
"VF[C]MULCPH/SH has a false dependency on dest register">;
def TuningPERMFalseDeps : SubtargetFeature<"false-deps-perm",
"HasPERMFalseDeps", "true",
"VPERMD/Q/PS/PD has a false dependency on dest register">;
def TuningRANGEFalseDeps : SubtargetFeature<"false-deps-range",
"HasRANGEFalseDeps", "true",
"VRANGEPD/PS/SD/SS has a false dependency on dest register">;
def TuningGETMANTFalseDeps : SubtargetFeature<"false-deps-getmant",
"HasGETMANTFalseDeps", "true",
"VGETMANTSS/SD/SH and VGETMANDPS/PD(memory version) has a"
" false dependency on dest register">;
def TuningMULLQFalseDeps : SubtargetFeature<"false-deps-mullq",
"HasMULLQFalseDeps", "true",
"VPMULLQ has a false dependency on dest register">;
def TuningSBBDepBreaking : SubtargetFeature<"sbb-dep-breaking",
"HasSBBDepBreaking", "true",
"SBB with same register has no source dependency">;
// On recent X86 (port bound) processors, its preferable to combine to a single shuffle
// using a variable mask over multiple fixed shuffles.
def TuningFastVariableCrossLaneShuffle
: SubtargetFeature<"fast-variable-crosslane-shuffle",
"HasFastVariableCrossLaneShuffle",
"true", "Cross-lane shuffles with variable masks are fast">;
def TuningFastVariablePerLaneShuffle
: SubtargetFeature<"fast-variable-perlane-shuffle",
"HasFastVariablePerLaneShuffle",
"true", "Per-lane shuffles with variable masks are fast">;
// On some X86 processors, a vzeroupper instruction should be inserted after
// using ymm/zmm registers before executing code that may use SSE instructions.
def TuningInsertVZEROUPPER
: SubtargetFeature<"vzeroupper",
"InsertVZEROUPPER",
"true", "Should insert vzeroupper instructions">;
// TuningFastScalarFSQRT should be enabled if scalar FSQRT has shorter latency
// than the corresponding NR code. TuningFastVectorFSQRT should be enabled if
// vector FSQRT has higher throughput than the corresponding NR code.
// The idea is that throughput bound code is likely to be vectorized, so for
// vectorized code we should care about the throughput of SQRT operations.
// But if the code is scalar that probably means that the code has some kind of
// dependency and we should care more about reducing the latency.
// True if hardware SQRTSS instruction is at least as fast (latency) as
// RSQRTSS followed by a Newton-Raphson iteration.
def TuningFastScalarFSQRT
: SubtargetFeature<"fast-scalar-fsqrt", "HasFastScalarFSQRT",
"true", "Scalar SQRT is fast (disable Newton-Raphson)">;
// True if hardware SQRTPS/VSQRTPS instructions are at least as fast
// (throughput) as RSQRTPS/VRSQRTPS followed by a Newton-Raphson iteration.
def TuningFastVectorFSQRT
: SubtargetFeature<"fast-vector-fsqrt", "HasFastVectorFSQRT",
"true", "Vector SQRT is fast (disable Newton-Raphson)">;
// If lzcnt has equivalent latency/throughput to most simple integer ops, it can
// be used to replace test/set sequences.
def TuningFastLZCNT
: SubtargetFeature<
"fast-lzcnt", "HasFastLZCNT", "true",
"LZCNT instructions are as fast as most simple integer ops">;
// If the target can efficiently decode NOPs upto 7-bytes in length.
def TuningFast7ByteNOP
: SubtargetFeature<
"fast-7bytenop", "HasFast7ByteNOP", "true",
"Target can quickly decode up to 7 byte NOPs">;
// If the target can efficiently decode NOPs upto 11-bytes in length.
def TuningFast11ByteNOP
: SubtargetFeature<
"fast-11bytenop", "HasFast11ByteNOP", "true",
"Target can quickly decode up to 11 byte NOPs">;
// If the target can efficiently decode NOPs upto 15-bytes in length.
def TuningFast15ByteNOP
: SubtargetFeature<
"fast-15bytenop", "HasFast15ByteNOP", "true",
"Target can quickly decode up to 15 byte NOPs">;
// Sandy Bridge and newer processors can use SHLD with the same source on both
// inputs to implement rotate to avoid the partial flag update of the normal
// rotate instructions.
def TuningFastSHLDRotate
: SubtargetFeature<
"fast-shld-rotate", "HasFastSHLDRotate", "true",
"SHLD can be used as a faster rotate">;
// Bulldozer and newer processors can merge CMP/TEST (but not other
// instructions) with conditional branches.
def TuningBranchFusion
: SubtargetFeature<"branchfusion", "HasBranchFusion", "true",
"CMP/TEST can be fused with conditional branches">;
// Sandy Bridge and newer processors have many instructions that can be
// fused with conditional branches and pass through the CPU as a single
// operation.
def TuningMacroFusion
: SubtargetFeature<"macrofusion", "HasMacroFusion", "true",
"Various instructions can be fused with conditional branches">;
// Gather is available since Haswell (AVX2 set). So technically, we can
// generate Gathers on all AVX2 processors. But the overhead on HSW is high.
// Skylake Client processor has faster Gathers than HSW and performance is
// similar to Skylake Server (AVX-512).
def TuningFastGather
: SubtargetFeature<"fast-gather", "HasFastGather", "true",
"Indicates if gather is reasonably fast (this is true for Skylake client and all AVX-512 CPUs)">;
def TuningPrefer128Bit
: SubtargetFeature<"prefer-128-bit", "Prefer128Bit", "true",
"Prefer 128-bit AVX instructions">;
def TuningPrefer256Bit
: SubtargetFeature<"prefer-256-bit", "Prefer256Bit", "true",
"Prefer 256-bit AVX instructions">;
def TuningPreferMaskRegisters
: SubtargetFeature<"prefer-mask-registers", "PreferMaskRegisters", "true",
"Prefer AVX512 mask registers over PTEST/MOVMSK">;
def TuningFastBEXTR : SubtargetFeature<"fast-bextr", "HasFastBEXTR", "true",
"Indicates that the BEXTR instruction is implemented as a single uop "
"with good throughput">;
// Combine vector math operations with shuffles into horizontal math
// instructions if a CPU implements horizontal operations (introduced with
// SSE3) with better latency/throughput than the alternative sequence.
def TuningFastHorizontalOps
: SubtargetFeature<
"fast-hops", "HasFastHorizontalOps", "true",
"Prefer horizontal vector math instructions (haddp, phsub, etc.) over "
"normal vector instructions with shuffles">;
def TuningFastScalarShiftMasks
: SubtargetFeature<
"fast-scalar-shift-masks", "HasFastScalarShiftMasks", "true",
"Prefer a left/right scalar logical shift pair over a shift+and pair">;
def TuningFastVectorShiftMasks
: SubtargetFeature<
"fast-vector-shift-masks", "HasFastVectorShiftMasks", "true",
"Prefer a left/right vector logical shift pair over a shift+and pair">;
def TuningFastMOVBE
: SubtargetFeature<"fast-movbe", "HasFastMOVBE", "true",
"Prefer a movbe over a single-use load + bswap / single-use bswap + store">;
def TuningUseSLMArithCosts
: SubtargetFeature<"use-slm-arith-costs", "UseSLMArithCosts", "true",
"Use Silvermont specific arithmetic costs">;
def TuningUseGLMDivSqrtCosts
: SubtargetFeature<"use-glm-div-sqrt-costs", "UseGLMDivSqrtCosts", "true",
"Use Goldmont specific floating point div/sqrt costs">;
//===----------------------------------------------------------------------===//
// X86 CPU Families
// TODO: Remove these - use general tuning features to determine codegen.
//===----------------------------------------------------------------------===//
// Bonnell
def ProcIntelAtom : SubtargetFeature<"", "IsAtom", "true", "Is Intel Atom processor">;
//===----------------------------------------------------------------------===//
// Register File Description
//===----------------------------------------------------------------------===//
include "X86RegisterInfo.td"
include "X86RegisterBanks.td"
//===----------------------------------------------------------------------===//
// Instruction Descriptions
//===----------------------------------------------------------------------===//
include "X86Schedule.td"
include "X86InstrInfo.td"
include "X86SchedPredicates.td"
def X86InstrInfo : InstrInfo;
//===----------------------------------------------------------------------===//
// X86 Scheduler Models
//===----------------------------------------------------------------------===//
include "X86ScheduleAtom.td"
include "X86SchedSandyBridge.td"
include "X86SchedHaswell.td"
include "X86SchedBroadwell.td"
include "X86ScheduleSLM.td"
include "X86ScheduleZnver1.td"
include "X86ScheduleZnver2.td"
include "X86ScheduleZnver3.td"
include "X86ScheduleBdVer2.td"
include "X86ScheduleBtVer2.td"
include "X86SchedSkylakeClient.td"
include "X86SchedSkylakeServer.td"
include "X86SchedIceLake.td"
//===----------------------------------------------------------------------===//
// X86 Processor Feature Lists
//===----------------------------------------------------------------------===//
def ProcessorFeatures {
// x86-64 and x86-64-v[234]
list<SubtargetFeature> X86_64V1Features = [
FeatureX87, FeatureCX8, FeatureCMOV, FeatureMMX, FeatureSSE2,
FeatureFXSR, FeatureNOPL, FeatureX86_64,
];
list<SubtargetFeature> X86_64V2Features = !listconcat(X86_64V1Features, [
FeatureCX16, FeatureLAHFSAHF64, FeatureCRC32, FeaturePOPCNT,
FeatureSSE42
]);
list<SubtargetFeature> X86_64V3Features = !listconcat(X86_64V2Features, [
FeatureAVX2, FeatureBMI, FeatureBMI2, FeatureF16C, FeatureFMA, FeatureLZCNT,
FeatureMOVBE, FeatureXSAVE
]);
list<SubtargetFeature> X86_64V4Features = !listconcat(X86_64V3Features, [
FeatureBWI,
FeatureCDI,
FeatureDQI,
FeatureVLX,
]);
// Nehalem
list<SubtargetFeature> NHMFeatures = X86_64V2Features;
list<SubtargetFeature> NHMTuning = [TuningMacroFusion,
TuningInsertVZEROUPPER];
// Westmere
list<SubtargetFeature> WSMAdditionalFeatures = [FeaturePCLMUL];
list<SubtargetFeature> WSMTuning = NHMTuning;
list<SubtargetFeature> WSMFeatures =
!listconcat(NHMFeatures, WSMAdditionalFeatures);
// Sandybridge
list<SubtargetFeature> SNBAdditionalFeatures = [FeatureAVX,
FeatureXSAVE,
FeatureXSAVEOPT];
list<SubtargetFeature> SNBTuning = [TuningMacroFusion,
TuningSlow3OpsLEA,
TuningSlowDivide64,
TuningSlowUAMem32,
TuningFastScalarFSQRT,
TuningFastSHLDRotate,
TuningFast15ByteNOP,
TuningPOPCNTFalseDeps,
TuningInsertVZEROUPPER];
list<SubtargetFeature> SNBFeatures =
!listconcat(WSMFeatures, SNBAdditionalFeatures);
// Ivybridge
list<SubtargetFeature> IVBAdditionalFeatures = [FeatureRDRAND,
FeatureF16C,
FeatureFSGSBase];
list<SubtargetFeature> IVBTuning = SNBTuning;
list<SubtargetFeature> IVBFeatures =
!listconcat(SNBFeatures, IVBAdditionalFeatures);
// Haswell
list<SubtargetFeature> HSWAdditionalFeatures = [FeatureAVX2,
FeatureBMI,
FeatureBMI2,
FeatureERMSB,
FeatureFMA,
FeatureINVPCID,
FeatureLZCNT,
FeatureMOVBE];
list<SubtargetFeature> HSWTuning = [TuningMacroFusion,
TuningSlow3OpsLEA,
TuningSlowDivide64,
TuningFastScalarFSQRT,
TuningFastSHLDRotate,
TuningFast15ByteNOP,
TuningFastVariableCrossLaneShuffle,
TuningFastVariablePerLaneShuffle,
TuningPOPCNTFalseDeps,
TuningLZCNTFalseDeps,
TuningInsertVZEROUPPER];
list<SubtargetFeature> HSWFeatures =
!listconcat(IVBFeatures, HSWAdditionalFeatures);
// Broadwell
list<SubtargetFeature> BDWAdditionalFeatures = [FeatureADX,
FeatureRDSEED,
FeaturePRFCHW];
list<SubtargetFeature> BDWTuning = HSWTuning;
list<SubtargetFeature> BDWFeatures =
!listconcat(HSWFeatures, BDWAdditionalFeatures);
// Skylake
list<SubtargetFeature> SKLAdditionalFeatures = [FeatureAES,
FeatureXSAVEC,
FeatureXSAVES,
FeatureCLFLUSHOPT];
list<SubtargetFeature> SKLTuning = [TuningFastGather,
TuningMacroFusion,
TuningSlow3OpsLEA,
TuningSlowDivide64,
TuningFastScalarFSQRT,
TuningFastVectorFSQRT,
TuningFastSHLDRotate,
TuningFast15ByteNOP,
TuningFastVariableCrossLaneShuffle,
TuningFastVariablePerLaneShuffle,
TuningPOPCNTFalseDeps,
TuningInsertVZEROUPPER];
list<SubtargetFeature> SKLFeatures =
!listconcat(BDWFeatures, SKLAdditionalFeatures);
// Skylake-AVX512
list<SubtargetFeature> SKXAdditionalFeatures = [FeatureAES,
FeatureXSAVEC,
FeatureXSAVES,
FeatureCLFLUSHOPT,
FeatureAVX512,
FeatureCDI,
FeatureDQI,
FeatureBWI,
FeatureVLX,
FeaturePKU,
FeatureCLWB];
list<SubtargetFeature> SKXTuning = [TuningFastGather,
TuningMacroFusion,
TuningSlow3OpsLEA,
TuningSlowDivide64,
TuningFastScalarFSQRT,
TuningFastVectorFSQRT,
TuningFastSHLDRotate,
TuningFast15ByteNOP,
TuningFastVariableCrossLaneShuffle,
TuningFastVariablePerLaneShuffle,
TuningPrefer256Bit,
TuningPOPCNTFalseDeps,
TuningInsertVZEROUPPER];
list<SubtargetFeature> SKXFeatures =
!listconcat(BDWFeatures, SKXAdditionalFeatures);
// Cascadelake
list<SubtargetFeature> CLXAdditionalFeatures = [FeatureVNNI];
list<SubtargetFeature> CLXTuning = SKXTuning;
list<SubtargetFeature> CLXFeatures =
!listconcat(SKXFeatures, CLXAdditionalFeatures);
// Cooperlake
list<SubtargetFeature> CPXAdditionalFeatures = [FeatureBF16];
list<SubtargetFeature> CPXTuning = SKXTuning;
list<SubtargetFeature> CPXFeatures =
!listconcat(CLXFeatures, CPXAdditionalFeatures);
// Cannonlake
list<SubtargetFeature> CNLAdditionalFeatures = [FeatureAVX512,
FeatureCDI,
FeatureDQI,
FeatureBWI,
FeatureVLX,
FeaturePKU,
FeatureVBMI,
FeatureIFMA,
FeatureSHA];
list<SubtargetFeature> CNLTuning = [TuningFastGather,
TuningMacroFusion,
TuningSlow3OpsLEA,
TuningSlowDivide64,
TuningFastScalarFSQRT,
TuningFastVectorFSQRT,
TuningFastSHLDRotate,
TuningFast15ByteNOP,
TuningFastVariableCrossLaneShuffle,
TuningFastVariablePerLaneShuffle,
TuningPrefer256Bit,
TuningInsertVZEROUPPER];
list<SubtargetFeature> CNLFeatures =
!listconcat(SKLFeatures, CNLAdditionalFeatures);
// Icelake
list<SubtargetFeature> ICLAdditionalFeatures = [FeatureBITALG,
FeatureVAES,
FeatureVBMI2,
FeatureVNNI,
FeatureVPCLMULQDQ,
FeatureVPOPCNTDQ,
FeatureGFNI,
FeatureRDPID,
FeatureFSRM];
list<SubtargetFeature> ICLTuning = [TuningFastGather,
TuningMacroFusion,
TuningSlow3OpsLEA,
TuningSlowDivide64,
TuningFastScalarFSQRT,
TuningFastVectorFSQRT,
TuningFastSHLDRotate,
TuningFast15ByteNOP,
TuningFastVariableCrossLaneShuffle,
TuningFastVariablePerLaneShuffle,
TuningPrefer256Bit,
TuningInsertVZEROUPPER];
list<SubtargetFeature> ICLFeatures =
!listconcat(CNLFeatures, ICLAdditionalFeatures);
// Icelake Server
list<SubtargetFeature> ICXAdditionalFeatures = [FeaturePCONFIG,
FeatureCLWB,
FeatureWBNOINVD];
list<SubtargetFeature> ICXTuning = ICLTuning;
list<SubtargetFeature> ICXFeatures =
!listconcat(ICLFeatures, ICXAdditionalFeatures);
// Tigerlake
list<SubtargetFeature> TGLAdditionalFeatures = [FeatureVP2INTERSECT,
FeatureCLWB,
FeatureMOVDIRI,
FeatureMOVDIR64B,
FeatureSHSTK];
list<SubtargetFeature> TGLTuning = ICLTuning;
list<SubtargetFeature> TGLFeatures =
!listconcat(ICLFeatures, TGLAdditionalFeatures );
// Sapphirerapids
list<SubtargetFeature> SPRAdditionalFeatures = [FeatureAMXTILE,
FeatureAMXINT8,
FeatureAMXBF16,
FeatureBF16,
FeatureSERIALIZE,
FeatureCLDEMOTE,
FeatureWAITPKG,
FeaturePTWRITE,
FeatureFP16,
FeatureAVXVNNI,
FeatureTSXLDTRK,
FeatureENQCMD,
FeatureSHSTK,
- FeatureVP2INTERSECT,
FeatureMOVDIRI,
FeatureMOVDIR64B,
FeatureUINTR];
list<SubtargetFeature> SPRAdditionalTuning = [TuningMULCFalseDeps,
TuningPERMFalseDeps,
TuningRANGEFalseDeps,
TuningGETMANTFalseDeps,
TuningMULLQFalseDeps];
list<SubtargetFeature> SPRTuning = !listconcat(ICXTuning, SPRAdditionalTuning);
list<SubtargetFeature> SPRFeatures =
!listconcat(ICXFeatures, SPRAdditionalFeatures);
// Atom
list<SubtargetFeature> AtomFeatures = [FeatureX87,
FeatureCX8,
FeatureCMOV,
FeatureMMX,
FeatureSSSE3,
FeatureFXSR,
FeatureNOPL,
FeatureX86_64,
FeatureCX16,
FeatureMOVBE,
FeatureLAHFSAHF64];
list<SubtargetFeature> AtomTuning = [ProcIntelAtom,
TuningSlowUAMem16,
TuningLEAForSP,
TuningSlowDivide32,
TuningSlowDivide64,
TuningSlowTwoMemOps,
TuningLEAUsesAG,
TuningPadShortFunctions,
TuningInsertVZEROUPPER];
// Silvermont
list<SubtargetFeature> SLMAdditionalFeatures = [FeatureSSE42,
FeatureCRC32,
FeaturePOPCNT,
FeaturePCLMUL,
FeaturePRFCHW,
FeatureRDRAND];
list<SubtargetFeature> SLMTuning = [TuningUseSLMArithCosts,
TuningSlowTwoMemOps,
TuningSlowLEA,
TuningSlowIncDec,
TuningSlowDivide64,
TuningSlowPMULLD,
TuningFast7ByteNOP,
TuningFastMOVBE,
TuningPOPCNTFalseDeps,
TuningInsertVZEROUPPER];
list<SubtargetFeature> SLMFeatures =
!listconcat(AtomFeatures, SLMAdditionalFeatures);
// Goldmont
list<SubtargetFeature> GLMAdditionalFeatures = [FeatureAES,
FeatureSHA,
FeatureRDSEED,
FeatureXSAVE,
FeatureXSAVEOPT,
FeatureXSAVEC,
FeatureXSAVES,
FeatureCLFLUSHOPT,
FeatureFSGSBase];
list<SubtargetFeature> GLMTuning = [TuningUseGLMDivSqrtCosts,
TuningSlowTwoMemOps,
TuningSlowLEA,
TuningSlowIncDec,
TuningFastMOVBE,
TuningPOPCNTFalseDeps,
TuningInsertVZEROUPPER];
list<SubtargetFeature> GLMFeatures =
!listconcat(SLMFeatures, GLMAdditionalFeatures);
// Goldmont Plus
list<SubtargetFeature> GLPAdditionalFeatures = [FeaturePTWRITE,
FeatureRDPID];
list<SubtargetFeature> GLPTuning = [TuningUseGLMDivSqrtCosts,
TuningSlowTwoMemOps,
TuningSlowLEA,
TuningSlowIncDec,
TuningFastMOVBE,
TuningInsertVZEROUPPER];
list<SubtargetFeature> GLPFeatures =
!listconcat(GLMFeatures, GLPAdditionalFeatures);
// Tremont
list<SubtargetFeature> TRMAdditionalFeatures = [FeatureCLWB,
FeatureGFNI];
list<SubtargetFeature> TRMTuning = GLPTuning;
list<SubtargetFeature> TRMFeatures =
!listconcat(GLPFeatures, TRMAdditionalFeatures);
// Alderlake
list<SubtargetFeature> ADLAdditionalFeatures = [FeatureSERIALIZE,
FeaturePCONFIG,
FeatureSHSTK,
FeatureWIDEKL,
FeatureINVPCID,
FeatureADX,
FeatureFMA,
FeatureVAES,
FeatureVPCLMULQDQ,
FeatureF16C,
FeatureBMI,
FeatureBMI2,
FeatureLZCNT,
FeatureAVXVNNI,
FeaturePKU,
FeatureHRESET,
FeatureCLDEMOTE,
FeatureMOVDIRI,
FeatureMOVDIR64B,
FeatureWAITPKG];
list<SubtargetFeature> ADLAdditionalTuning = [TuningPERMFalseDeps];
list<SubtargetFeature> ADLTuning = !listconcat(SKLTuning, ADLAdditionalTuning);
list<SubtargetFeature> ADLFeatures =
!listconcat(TRMFeatures, ADLAdditionalFeatures);
// Knights Landing
list<SubtargetFeature> KNLFeatures = [FeatureX87,
FeatureCX8,
FeatureCMOV,
FeatureMMX,
FeatureFXSR,
FeatureNOPL,
FeatureX86_64,
FeatureCX16,
FeatureCRC32,
FeaturePOPCNT,
FeaturePCLMUL,
FeatureXSAVE,
FeatureXSAVEOPT,
FeatureLAHFSAHF64,
FeatureAES,
FeatureRDRAND,
FeatureF16C,
FeatureFSGSBase,
FeatureAVX512,
FeatureERI,
FeatureCDI,
FeaturePFI,
FeaturePREFETCHWT1,
FeatureADX,
FeatureRDSEED,
FeatureMOVBE,
FeatureLZCNT,
FeatureBMI,
FeatureBMI2,
FeatureFMA,
FeaturePRFCHW];
list<SubtargetFeature> KNLTuning = [TuningSlowDivide64,
TuningSlow3OpsLEA,
TuningSlowIncDec,
TuningSlowTwoMemOps,
TuningPreferMaskRegisters,
TuningFastGather,
TuningFastMOVBE,
TuningSlowPMADDWD];
// TODO Add AVX5124FMAPS/AVX5124VNNIW features
list<SubtargetFeature> KNMFeatures =
!listconcat(KNLFeatures, [FeatureVPOPCNTDQ]);
// Barcelona
list<SubtargetFeature> BarcelonaFeatures = [FeatureX87,
FeatureCX8,
FeatureSSE4A,
Feature3DNowA,
FeatureFXSR,
FeatureNOPL,
FeatureCX16,
FeaturePRFCHW,
FeatureLZCNT,
FeaturePOPCNT,
FeatureLAHFSAHF64,
FeatureCMOV,
FeatureX86_64];
list<SubtargetFeature> BarcelonaTuning = [TuningFastScalarShiftMasks,
TuningSlowSHLD,
TuningSBBDepBreaking,
TuningInsertVZEROUPPER];
// Bobcat
list<SubtargetFeature> BtVer1Features = [FeatureX87,
FeatureCX8,
FeatureCMOV,
FeatureMMX,
FeatureSSSE3,
FeatureSSE4A,
FeatureFXSR,
FeatureNOPL,
FeatureX86_64,
FeatureCX16,
FeaturePRFCHW,
FeatureLZCNT,
FeaturePOPCNT,
FeatureLAHFSAHF64];
list<SubtargetFeature> BtVer1Tuning = [TuningFast15ByteNOP,
TuningFastScalarShiftMasks,
TuningFastVectorShiftMasks,
TuningSlowSHLD,
TuningSBBDepBreaking,
TuningInsertVZEROUPPER];
// Jaguar
list<SubtargetFeature> BtVer2AdditionalFeatures = [FeatureAVX,
FeatureAES,
FeatureCRC32,
FeaturePCLMUL,
FeatureBMI,
FeatureF16C,
FeatureMOVBE,
FeatureXSAVE,
FeatureXSAVEOPT];
list<SubtargetFeature> BtVer2Tuning = [TuningFastLZCNT,
TuningFastBEXTR,
TuningFastHorizontalOps,
TuningFast15ByteNOP,
TuningFastScalarShiftMasks,
TuningFastVectorShiftMasks,
TuningFastMOVBE,
TuningSBBDepBreaking,
TuningSlowSHLD];
list<SubtargetFeature> BtVer2Features =
!listconcat(BtVer1Features, BtVer2AdditionalFeatures);
// Bulldozer
list<SubtargetFeature> BdVer1Features = [FeatureX87,
FeatureCX8,
FeatureCMOV,
FeatureXOP,
FeatureX86_64,
FeatureCX16,
FeatureAES,
FeatureCRC32,
FeaturePRFCHW,
FeaturePCLMUL,
FeatureMMX,
FeatureFXSR,
FeatureNOPL,
FeatureLZCNT,
FeaturePOPCNT,
FeatureXSAVE,
FeatureLWP,
FeatureLAHFSAHF64];
list<SubtargetFeature> BdVer1Tuning = [TuningSlowSHLD,
TuningFast11ByteNOP,
TuningFastScalarShiftMasks,
TuningBranchFusion,
TuningSBBDepBreaking,
TuningInsertVZEROUPPER];
// PileDriver
list<SubtargetFeature> BdVer2AdditionalFeatures = [FeatureF16C,
FeatureBMI,
FeatureTBM,
FeatureFMA];
list<SubtargetFeature> BdVer2AdditionalTuning = [TuningFastBEXTR,
TuningFastMOVBE];
list<SubtargetFeature> BdVer2Tuning =
!listconcat(BdVer1Tuning, BdVer2AdditionalTuning);
list<SubtargetFeature> BdVer2Features =
!listconcat(BdVer1Features, BdVer2AdditionalFeatures);
// Steamroller
list<SubtargetFeature> BdVer3AdditionalFeatures = [FeatureXSAVEOPT,
FeatureFSGSBase];
list<SubtargetFeature> BdVer3Tuning = BdVer2Tuning;
list<SubtargetFeature> BdVer3Features =
!listconcat(BdVer2Features, BdVer3AdditionalFeatures);
// Excavator
list<SubtargetFeature> BdVer4AdditionalFeatures = [FeatureAVX2,
FeatureBMI2,
FeatureMOVBE,
FeatureRDRAND,
FeatureMWAITX];
list<SubtargetFeature> BdVer4Tuning = BdVer3Tuning;
list<SubtargetFeature> BdVer4Features =
!listconcat(BdVer3Features, BdVer4AdditionalFeatures);
// AMD Zen Processors common ISAs
list<SubtargetFeature> ZNFeatures = [FeatureADX,
FeatureAES,
FeatureAVX2,
FeatureBMI,
FeatureBMI2,
FeatureCLFLUSHOPT,
FeatureCLZERO,
FeatureCMOV,
FeatureX86_64,
FeatureCX16,
FeatureCRC32,
FeatureF16C,
FeatureFMA,
FeatureFSGSBase,
FeatureFXSR,
FeatureNOPL,
FeatureLAHFSAHF64,
FeatureLZCNT,
FeatureMMX,
FeatureMOVBE,
FeatureMWAITX,
FeaturePCLMUL,
FeaturePOPCNT,
FeaturePRFCHW,
FeatureRDRAND,
FeatureRDSEED,
FeatureSHA,
FeatureSSE4A,
FeatureX87,
FeatureXSAVE,
FeatureXSAVEC,
FeatureXSAVEOPT,
FeatureXSAVES];
list<SubtargetFeature> ZNTuning = [TuningFastLZCNT,
TuningFastBEXTR,
TuningFast15ByteNOP,
TuningBranchFusion,
TuningFastScalarFSQRT,
TuningFastVectorFSQRT,
TuningFastScalarShiftMasks,
TuningFastVariablePerLaneShuffle,
TuningFastMOVBE,
TuningSlowSHLD,
TuningSBBDepBreaking,
TuningInsertVZEROUPPER];
list<SubtargetFeature> ZN2AdditionalFeatures = [FeatureCLWB,
FeatureRDPID,
FeatureRDPRU,
FeatureWBNOINVD];
list<SubtargetFeature> ZN2Tuning = ZNTuning;
list<SubtargetFeature> ZN2Features =
!listconcat(ZNFeatures, ZN2AdditionalFeatures);
list<SubtargetFeature> ZN3AdditionalFeatures = [FeatureFSRM,
FeatureINVPCID,
FeaturePKU,
FeatureVAES,
FeatureVPCLMULQDQ];
list<SubtargetFeature> ZN3AdditionalTuning = [TuningMacroFusion];
list<SubtargetFeature> ZN3Tuning =
!listconcat(ZN2Tuning, ZN3AdditionalTuning);
list<SubtargetFeature> ZN3Features =
!listconcat(ZN2Features, ZN3AdditionalFeatures);
}
//===----------------------------------------------------------------------===//
// X86 processors supported.
//===----------------------------------------------------------------------===//
class Proc<string Name, list<SubtargetFeature> Features,
list<SubtargetFeature> TuneFeatures>
: ProcessorModel<Name, GenericModel, Features, TuneFeatures>;
class ProcModel<string Name, SchedMachineModel Model,
list<SubtargetFeature> Features,
list<SubtargetFeature> TuneFeatures>
: ProcessorModel<Name, Model, Features, TuneFeatures>;
// NOTE: CMPXCHG8B is here for legacy compatibility so that it is only disabled
// if i386/i486 is specifically requested.
// NOTE: 64Bit is here as "generic" is the default llc CPU. The X86Subtarget
// constructor checks that any CPU used in 64-bit mode has FeatureX86_64
// enabled. It has no effect on code generation.
// NOTE: As a default tuning, "generic" aims to produce code optimized for the
// most common X86 processors. The tunings might be changed over time. It is
// recommended to use "tune-cpu"="x86-64" in function attribute for consistency.
def : ProcModel<"generic", SandyBridgeModel,
[FeatureX87, FeatureCX8, FeatureX86_64],
[TuningSlow3OpsLEA,
TuningSlowDivide64,
TuningMacroFusion,
TuningFastScalarFSQRT,
TuningFast15ByteNOP,
TuningInsertVZEROUPPER]>;
def : Proc<"i386", [FeatureX87],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"i486", [FeatureX87],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"i586", [FeatureX87, FeatureCX8],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"pentium", [FeatureX87, FeatureCX8],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"pentium-mmx", [FeatureX87, FeatureCX8, FeatureMMX],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"i686", [FeatureX87, FeatureCX8, FeatureCMOV],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"pentiumpro", [FeatureX87, FeatureCX8, FeatureCMOV,
FeatureNOPL],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"pentium2", [FeatureX87, FeatureCX8, FeatureMMX, FeatureCMOV,
FeatureFXSR, FeatureNOPL],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
foreach P = ["pentium3", "pentium3m"] in {
def : Proc<P, [FeatureX87, FeatureCX8, FeatureMMX,
FeatureSSE1, FeatureFXSR, FeatureNOPL, FeatureCMOV],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
}
// Enable the PostRAScheduler for SSE2 and SSE3 class cpus.
// The intent is to enable it for pentium4 which is the current default
// processor in a vanilla 32-bit clang compilation when no specific
// architecture is specified. This generally gives a nice performance
// increase on silvermont, with largely neutral behavior on other
// contemporary large core processors.
// pentium-m, pentium4m, prescott and nocona are included as a preventative
// measure to avoid performance surprises, in case clang's default cpu
// changes slightly.
def : ProcModel<"pentium-m", GenericPostRAModel,
[FeatureX87, FeatureCX8, FeatureMMX, FeatureSSE2,
FeatureFXSR, FeatureNOPL, FeatureCMOV],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
foreach P = ["pentium4", "pentium4m"] in {
def : ProcModel<P, GenericPostRAModel,
[FeatureX87, FeatureCX8, FeatureMMX, FeatureSSE2,
FeatureFXSR, FeatureNOPL, FeatureCMOV],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
}
// Intel Quark.
def : Proc<"lakemont", [FeatureCX8],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
// Intel Core Duo.
def : ProcModel<"yonah", SandyBridgeModel,
[FeatureX87, FeatureCX8, FeatureMMX, FeatureSSE3,
FeatureFXSR, FeatureNOPL, FeatureCMOV],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
// NetBurst.
def : ProcModel<"prescott", GenericPostRAModel,
[FeatureX87, FeatureCX8, FeatureMMX, FeatureSSE3,
FeatureFXSR, FeatureNOPL, FeatureCMOV],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : ProcModel<"nocona", GenericPostRAModel, [
FeatureX87,
FeatureCX8,
FeatureCMOV,
FeatureMMX,
FeatureSSE3,
FeatureFXSR,
FeatureNOPL,
FeatureX86_64,
FeatureCX16,
],
[
TuningSlowUAMem16,
TuningInsertVZEROUPPER
]>;
// Intel Core 2 Solo/Duo.
def : ProcModel<"core2", SandyBridgeModel, [
FeatureX87,
FeatureCX8,
FeatureCMOV,
FeatureMMX,
FeatureSSSE3,
FeatureFXSR,
FeatureNOPL,
FeatureX86_64,
FeatureCX16,
FeatureLAHFSAHF64
],
[
TuningMacroFusion,
TuningSlowUAMem16,
TuningInsertVZEROUPPER
]>;
def : ProcModel<"penryn", SandyBridgeModel, [
FeatureX87,
FeatureCX8,
FeatureCMOV,
FeatureMMX,
FeatureSSE41,
FeatureFXSR,
FeatureNOPL,
FeatureX86_64,
FeatureCX16,
FeatureLAHFSAHF64
],
[
TuningMacroFusion,
TuningSlowUAMem16,
TuningInsertVZEROUPPER
]>;
// Atom CPUs.
foreach P = ["bonnell", "atom"] in {
def : ProcModel<P, AtomModel, ProcessorFeatures.AtomFeatures,
ProcessorFeatures.AtomTuning>;
}
foreach P = ["silvermont", "slm"] in {
def : ProcModel<P, SLMModel, ProcessorFeatures.SLMFeatures,
ProcessorFeatures.SLMTuning>;
}
def : ProcModel<"goldmont", SLMModel, ProcessorFeatures.GLMFeatures,
ProcessorFeatures.GLMTuning>;
def : ProcModel<"goldmont-plus", SLMModel, ProcessorFeatures.GLPFeatures,
ProcessorFeatures.GLPTuning>;
def : ProcModel<"tremont", SLMModel, ProcessorFeatures.TRMFeatures,
ProcessorFeatures.TRMTuning>;
// "Arrandale" along with corei3 and corei5
foreach P = ["nehalem", "corei7"] in {
def : ProcModel<P, SandyBridgeModel, ProcessorFeatures.NHMFeatures,
ProcessorFeatures.NHMTuning>;
}
// Westmere is the corei3/i5/i7 path from nehalem to sandybridge
def : ProcModel<"westmere", SandyBridgeModel, ProcessorFeatures.WSMFeatures,
ProcessorFeatures.WSMTuning>;
foreach P = ["sandybridge", "corei7-avx"] in {
def : ProcModel<P, SandyBridgeModel, ProcessorFeatures.SNBFeatures,
ProcessorFeatures.SNBTuning>;
}
foreach P = ["ivybridge", "core-avx-i"] in {
def : ProcModel<P, SandyBridgeModel, ProcessorFeatures.IVBFeatures,
ProcessorFeatures.IVBTuning>;
}
foreach P = ["haswell", "core-avx2"] in {
def : ProcModel<P, HaswellModel, ProcessorFeatures.HSWFeatures,
ProcessorFeatures.HSWTuning>;
}
def : ProcModel<"broadwell", BroadwellModel, ProcessorFeatures.BDWFeatures,
ProcessorFeatures.BDWTuning>;
def : ProcModel<"skylake", SkylakeClientModel, ProcessorFeatures.SKLFeatures,
ProcessorFeatures.SKLTuning>;
// FIXME: define KNL scheduler model
def : ProcModel<"knl", HaswellModel, ProcessorFeatures.KNLFeatures,
ProcessorFeatures.KNLTuning>;
def : ProcModel<"knm", HaswellModel, ProcessorFeatures.KNMFeatures,
ProcessorFeatures.KNLTuning>;
foreach P = ["skylake-avx512", "skx"] in {
def : ProcModel<P, SkylakeServerModel, ProcessorFeatures.SKXFeatures,
ProcessorFeatures.SKXTuning>;
}
def : ProcModel<"cascadelake", SkylakeServerModel,
ProcessorFeatures.CLXFeatures, ProcessorFeatures.CLXTuning>;
def : ProcModel<"cooperlake", SkylakeServerModel,
ProcessorFeatures.CPXFeatures, ProcessorFeatures.CPXTuning>;
def : ProcModel<"cannonlake", SkylakeServerModel,
ProcessorFeatures.CNLFeatures, ProcessorFeatures.CNLTuning>;
def : ProcModel<"icelake-client", IceLakeModel,
ProcessorFeatures.ICLFeatures, ProcessorFeatures.ICLTuning>;
def : ProcModel<"rocketlake", IceLakeModel,
ProcessorFeatures.ICLFeatures, ProcessorFeatures.ICLTuning>;
def : ProcModel<"icelake-server", IceLakeModel,
ProcessorFeatures.ICXFeatures, ProcessorFeatures.ICXTuning>;
def : ProcModel<"tigerlake", IceLakeModel,
ProcessorFeatures.TGLFeatures, ProcessorFeatures.TGLTuning>;
def : ProcModel<"sapphirerapids", SkylakeServerModel,
ProcessorFeatures.SPRFeatures, ProcessorFeatures.SPRTuning>;
def : ProcModel<"alderlake", SkylakeClientModel,
ProcessorFeatures.ADLFeatures, ProcessorFeatures.ADLTuning>;
// AMD CPUs.
def : Proc<"k6", [FeatureX87, FeatureCX8, FeatureMMX],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"k6-2", [FeatureX87, FeatureCX8, Feature3DNow],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"k6-3", [FeatureX87, FeatureCX8, Feature3DNow],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
foreach P = ["athlon", "athlon-tbird"] in {
def : Proc<P, [FeatureX87, FeatureCX8, FeatureCMOV, Feature3DNowA,
FeatureNOPL],
[TuningSlowSHLD, TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
}
foreach P = ["athlon-4", "athlon-xp", "athlon-mp"] in {
def : Proc<P, [FeatureX87, FeatureCX8, FeatureCMOV,
FeatureSSE1, Feature3DNowA, FeatureFXSR, FeatureNOPL],
[TuningSlowSHLD, TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
}
foreach P = ["k8", "opteron", "athlon64", "athlon-fx"] in {
def : Proc<P, [FeatureX87, FeatureCX8, FeatureSSE2, Feature3DNowA,
FeatureFXSR, FeatureNOPL, FeatureX86_64, FeatureCMOV],
[TuningFastScalarShiftMasks, TuningSlowSHLD, TuningSlowUAMem16,
TuningSBBDepBreaking, TuningInsertVZEROUPPER]>;
}
foreach P = ["k8-sse3", "opteron-sse3", "athlon64-sse3"] in {
def : Proc<P, [FeatureX87, FeatureCX8, FeatureSSE3, Feature3DNowA,
FeatureFXSR, FeatureNOPL, FeatureCX16, FeatureCMOV,
FeatureX86_64],
[TuningFastScalarShiftMasks, TuningSlowSHLD, TuningSlowUAMem16,
TuningSBBDepBreaking, TuningInsertVZEROUPPER]>;
}
foreach P = ["amdfam10", "barcelona"] in {
def : Proc<P, ProcessorFeatures.BarcelonaFeatures,
ProcessorFeatures.BarcelonaTuning>;
}
// Bobcat
def : Proc<"btver1", ProcessorFeatures.BtVer1Features,
ProcessorFeatures.BtVer1Tuning>;
// Jaguar
def : ProcModel<"btver2", BtVer2Model, ProcessorFeatures.BtVer2Features,
ProcessorFeatures.BtVer2Tuning>;
// Bulldozer
def : ProcModel<"bdver1", BdVer2Model, ProcessorFeatures.BdVer1Features,
ProcessorFeatures.BdVer1Tuning>;
// Piledriver
def : ProcModel<"bdver2", BdVer2Model, ProcessorFeatures.BdVer2Features,
ProcessorFeatures.BdVer2Tuning>;
// Steamroller
def : Proc<"bdver3", ProcessorFeatures.BdVer3Features,
ProcessorFeatures.BdVer3Tuning>;
// Excavator
def : Proc<"bdver4", ProcessorFeatures.BdVer4Features,
ProcessorFeatures.BdVer4Tuning>;
def : ProcModel<"znver1", Znver1Model, ProcessorFeatures.ZNFeatures,
ProcessorFeatures.ZNTuning>;
def : ProcModel<"znver2", Znver2Model, ProcessorFeatures.ZN2Features,
ProcessorFeatures.ZN2Tuning>;
def : ProcModel<"znver3", Znver3Model, ProcessorFeatures.ZN3Features,
ProcessorFeatures.ZN3Tuning>;
def : Proc<"geode", [FeatureX87, FeatureCX8, Feature3DNowA],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"winchip-c6", [FeatureX87, FeatureMMX],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"winchip2", [FeatureX87, Feature3DNow],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"c3", [FeatureX87, Feature3DNow],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
def : Proc<"c3-2", [FeatureX87, FeatureCX8, FeatureMMX,
FeatureSSE1, FeatureFXSR, FeatureCMOV],
[TuningSlowUAMem16, TuningInsertVZEROUPPER]>;
// We also provide a generic 64-bit specific x86 processor model which tries to
// be good for modern chips without enabling instruction set encodings past the
// basic SSE2 and 64-bit ones. It disables slow things from any mainstream and
// modern 64-bit x86 chip, and enables features that are generally beneficial.
//
// We currently use the Sandy Bridge model as the default scheduling model as
// we use it across Nehalem, Westmere, Sandy Bridge, and Ivy Bridge which
// covers a huge swath of x86 processors. If there are specific scheduling
// knobs which need to be tuned differently for AMD chips, we might consider
// forming a common base for them.
def : ProcModel<"x86-64", SandyBridgeModel, ProcessorFeatures.X86_64V1Features,
[
TuningSlow3OpsLEA,
TuningSlowDivide64,
TuningSlowIncDec,
TuningMacroFusion,
TuningInsertVZEROUPPER
]>;
// x86-64 micro-architecture levels.
def : ProcModel<"x86-64-v2", SandyBridgeModel, ProcessorFeatures.X86_64V2Features,
ProcessorFeatures.SNBTuning>;
// Close to Haswell.
def : ProcModel<"x86-64-v3", HaswellModel, ProcessorFeatures.X86_64V3Features,
ProcessorFeatures.HSWTuning>;
// Close to the AVX-512 level implemented by Xeon Scalable Processors.
def : ProcModel<"x86-64-v4", SkylakeServerModel, ProcessorFeatures.X86_64V4Features,
ProcessorFeatures.SKXTuning>;
//===----------------------------------------------------------------------===//
// Calling Conventions
//===----------------------------------------------------------------------===//
include "X86CallingConv.td"
//===----------------------------------------------------------------------===//
// Assembly Parser
//===----------------------------------------------------------------------===//
def ATTAsmParserVariant : AsmParserVariant {
int Variant = 0;
// Variant name.
string Name = "att";
// Discard comments in assembly strings.
string CommentDelimiter = "#";
// Recognize hard coded registers.
string RegisterPrefix = "%";
}
def IntelAsmParserVariant : AsmParserVariant {
int Variant = 1;
// Variant name.
string Name = "intel";
// Discard comments in assembly strings.
string CommentDelimiter = ";";
// Recognize hard coded registers.
string RegisterPrefix = "";
}
//===----------------------------------------------------------------------===//
// Assembly Printers
//===----------------------------------------------------------------------===//
// The X86 target supports two different syntaxes for emitting machine code.
// This is controlled by the -x86-asm-syntax={att|intel}
def ATTAsmWriter : AsmWriter {
string AsmWriterClassName = "ATTInstPrinter";
int Variant = 0;
}
def IntelAsmWriter : AsmWriter {
string AsmWriterClassName = "IntelInstPrinter";
int Variant = 1;
}
def X86 : Target {
// Information about the instructions...
let InstructionSet = X86InstrInfo;
let AssemblyParserVariants = [ATTAsmParserVariant, IntelAsmParserVariant];
let AssemblyWriters = [ATTAsmWriter, IntelAsmWriter];
let AllowRegisterRenaming = 1;
}
//===----------------------------------------------------------------------===//
// Pfm Counters
//===----------------------------------------------------------------------===//
include "X86PfmCounters.td"
diff --git a/contrib/llvm-project/llvm/lib/Transforms/Utils/LoopVersioning.cpp b/contrib/llvm-project/llvm/lib/Transforms/Utils/LoopVersioning.cpp
index 97f29527bb95..6309eed7963d 100644
--- a/contrib/llvm-project/llvm/lib/Transforms/Utils/LoopVersioning.cpp
+++ b/contrib/llvm-project/llvm/lib/Transforms/Utils/LoopVersioning.cpp
@@ -1,366 +1,368 @@
//===- LoopVersioning.cpp - Utility to version a loop ---------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines a utility class to perform loop versioning. The versioned
// loop speculates that otherwise may-aliasing memory accesses don't overlap and
// emits checks to prove this.
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Utils/LoopVersioning.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/InstSimplifyFolder.h"
#include "llvm/Analysis/LoopAccessAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/PassManager.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h"
using namespace llvm;
static cl::opt<bool>
AnnotateNoAlias("loop-version-annotate-no-alias", cl::init(true),
cl::Hidden,
cl::desc("Add no-alias annotation for instructions that "
"are disambiguated by memchecks"));
LoopVersioning::LoopVersioning(const LoopAccessInfo &LAI,
ArrayRef<RuntimePointerCheck> Checks, Loop *L,
LoopInfo *LI, DominatorTree *DT,
ScalarEvolution *SE)
: VersionedLoop(L), AliasChecks(Checks.begin(), Checks.end()),
Preds(LAI.getPSE().getPredicate()), LAI(LAI), LI(LI), DT(DT),
SE(SE) {
}
void LoopVersioning::versionLoop(
const SmallVectorImpl<Instruction *> &DefsUsedOutside) {
assert(VersionedLoop->getUniqueExitBlock() && "No single exit block");
assert(VersionedLoop->isLoopSimplifyForm() &&
"Loop is not in loop-simplify form");
Value *MemRuntimeCheck;
Value *SCEVRuntimeCheck;
Value *RuntimeCheck = nullptr;
// Add the memcheck in the original preheader (this is empty initially).
BasicBlock *RuntimeCheckBB = VersionedLoop->getLoopPreheader();
const auto &RtPtrChecking = *LAI.getRuntimePointerChecking();
SCEVExpander Exp2(*RtPtrChecking.getSE(),
VersionedLoop->getHeader()->getModule()->getDataLayout(),
"induction");
MemRuntimeCheck = addRuntimeChecks(RuntimeCheckBB->getTerminator(),
VersionedLoop, AliasChecks, Exp2);
SCEVExpander Exp(*SE, RuntimeCheckBB->getModule()->getDataLayout(),
"scev.check");
SCEVRuntimeCheck =
Exp.expandCodeForPredicate(&Preds, RuntimeCheckBB->getTerminator());
IRBuilder<InstSimplifyFolder> Builder(
RuntimeCheckBB->getContext(),
InstSimplifyFolder(RuntimeCheckBB->getModule()->getDataLayout()));
if (MemRuntimeCheck && SCEVRuntimeCheck) {
Builder.SetInsertPoint(RuntimeCheckBB->getTerminator());
RuntimeCheck =
Builder.CreateOr(MemRuntimeCheck, SCEVRuntimeCheck, "lver.safe");
} else
RuntimeCheck = MemRuntimeCheck ? MemRuntimeCheck : SCEVRuntimeCheck;
assert(RuntimeCheck && "called even though we don't need "
"any runtime checks");
// Rename the block to make the IR more readable.
RuntimeCheckBB->setName(VersionedLoop->getHeader()->getName() +
".lver.check");
// Create empty preheader for the loop (and after cloning for the
// non-versioned loop).
BasicBlock *PH =
SplitBlock(RuntimeCheckBB, RuntimeCheckBB->getTerminator(), DT, LI,
nullptr, VersionedLoop->getHeader()->getName() + ".ph");
// Clone the loop including the preheader.
//
// FIXME: This does not currently preserve SimplifyLoop because the exit
// block is a join between the two loops.
SmallVector<BasicBlock *, 8> NonVersionedLoopBlocks;
NonVersionedLoop =
cloneLoopWithPreheader(PH, RuntimeCheckBB, VersionedLoop, VMap,
".lver.orig", LI, DT, NonVersionedLoopBlocks);
remapInstructionsInBlocks(NonVersionedLoopBlocks, VMap);
// Insert the conditional branch based on the result of the memchecks.
Instruction *OrigTerm = RuntimeCheckBB->getTerminator();
Builder.SetInsertPoint(OrigTerm);
Builder.CreateCondBr(RuntimeCheck, NonVersionedLoop->getLoopPreheader(),
VersionedLoop->getLoopPreheader());
OrigTerm->eraseFromParent();
// The loops merge in the original exit block. This is now dominated by the
// memchecking block.
DT->changeImmediateDominator(VersionedLoop->getExitBlock(), RuntimeCheckBB);
// Adds the necessary PHI nodes for the versioned loops based on the
// loop-defined values used outside of the loop.
addPHINodes(DefsUsedOutside);
formDedicatedExitBlocks(NonVersionedLoop, DT, LI, nullptr, true);
formDedicatedExitBlocks(VersionedLoop, DT, LI, nullptr, true);
assert(NonVersionedLoop->isLoopSimplifyForm() &&
VersionedLoop->isLoopSimplifyForm() &&
"The versioned loops should be in simplify form.");
}
void LoopVersioning::addPHINodes(
const SmallVectorImpl<Instruction *> &DefsUsedOutside) {
BasicBlock *PHIBlock = VersionedLoop->getExitBlock();
assert(PHIBlock && "No single successor to loop exit block");
PHINode *PN;
// First add a single-operand PHI for each DefsUsedOutside if one does not
// exists yet.
for (auto *Inst : DefsUsedOutside) {
// See if we have a single-operand PHI with the value defined by the
// original loop.
for (auto I = PHIBlock->begin(); (PN = dyn_cast<PHINode>(I)); ++I) {
- if (PN->getIncomingValue(0) == Inst)
+ if (PN->getIncomingValue(0) == Inst) {
+ SE->forgetValue(PN);
break;
+ }
}
// If not create it.
if (!PN) {
PN = PHINode::Create(Inst->getType(), 2, Inst->getName() + ".lver",
&PHIBlock->front());
SmallVector<User*, 8> UsersToUpdate;
for (User *U : Inst->users())
if (!VersionedLoop->contains(cast<Instruction>(U)->getParent()))
UsersToUpdate.push_back(U);
for (User *U : UsersToUpdate)
U->replaceUsesOfWith(Inst, PN);
PN->addIncoming(Inst, VersionedLoop->getExitingBlock());
}
}
// Then for each PHI add the operand for the edge from the cloned loop.
for (auto I = PHIBlock->begin(); (PN = dyn_cast<PHINode>(I)); ++I) {
assert(PN->getNumOperands() == 1 &&
"Exit block should only have on predecessor");
// If the definition was cloned used that otherwise use the same value.
Value *ClonedValue = PN->getIncomingValue(0);
auto Mapped = VMap.find(ClonedValue);
if (Mapped != VMap.end())
ClonedValue = Mapped->second;
PN->addIncoming(ClonedValue, NonVersionedLoop->getExitingBlock());
}
}
void LoopVersioning::prepareNoAliasMetadata() {
// We need to turn the no-alias relation between pointer checking groups into
// no-aliasing annotations between instructions.
//
// We accomplish this by mapping each pointer checking group (a set of
// pointers memchecked together) to an alias scope and then also mapping each
// group to the list of scopes it can't alias.
const RuntimePointerChecking *RtPtrChecking = LAI.getRuntimePointerChecking();
LLVMContext &Context = VersionedLoop->getHeader()->getContext();
// First allocate an aliasing scope for each pointer checking group.
//
// While traversing through the checking groups in the loop, also create a
// reverse map from pointers to the pointer checking group they were assigned
// to.
MDBuilder MDB(Context);
MDNode *Domain = MDB.createAnonymousAliasScopeDomain("LVerDomain");
for (const auto &Group : RtPtrChecking->CheckingGroups) {
GroupToScope[&Group] = MDB.createAnonymousAliasScope(Domain);
for (unsigned PtrIdx : Group.Members)
PtrToGroup[RtPtrChecking->getPointerInfo(PtrIdx).PointerValue] = &Group;
}
// Go through the checks and for each pointer group, collect the scopes for
// each non-aliasing pointer group.
DenseMap<const RuntimeCheckingPtrGroup *, SmallVector<Metadata *, 4>>
GroupToNonAliasingScopes;
for (const auto &Check : AliasChecks)
GroupToNonAliasingScopes[Check.first].push_back(GroupToScope[Check.second]);
// Finally, transform the above to actually map to scope list which is what
// the metadata uses.
for (auto Pair : GroupToNonAliasingScopes)
GroupToNonAliasingScopeList[Pair.first] = MDNode::get(Context, Pair.second);
}
void LoopVersioning::annotateLoopWithNoAlias() {
if (!AnnotateNoAlias)
return;
// First prepare the maps.
prepareNoAliasMetadata();
// Add the scope and no-alias metadata to the instructions.
for (Instruction *I : LAI.getDepChecker().getMemoryInstructions()) {
annotateInstWithNoAlias(I);
}
}
void LoopVersioning::annotateInstWithNoAlias(Instruction *VersionedInst,
const Instruction *OrigInst) {
if (!AnnotateNoAlias)
return;
LLVMContext &Context = VersionedLoop->getHeader()->getContext();
const Value *Ptr = isa<LoadInst>(OrigInst)
? cast<LoadInst>(OrigInst)->getPointerOperand()
: cast<StoreInst>(OrigInst)->getPointerOperand();
// Find the group for the pointer and then add the scope metadata.
auto Group = PtrToGroup.find(Ptr);
if (Group != PtrToGroup.end()) {
VersionedInst->setMetadata(
LLVMContext::MD_alias_scope,
MDNode::concatenate(
VersionedInst->getMetadata(LLVMContext::MD_alias_scope),
MDNode::get(Context, GroupToScope[Group->second])));
// Add the no-alias metadata.
auto NonAliasingScopeList = GroupToNonAliasingScopeList.find(Group->second);
if (NonAliasingScopeList != GroupToNonAliasingScopeList.end())
VersionedInst->setMetadata(
LLVMContext::MD_noalias,
MDNode::concatenate(
VersionedInst->getMetadata(LLVMContext::MD_noalias),
NonAliasingScopeList->second));
}
}
namespace {
bool runImpl(LoopInfo *LI, function_ref<const LoopAccessInfo &(Loop &)> GetLAA,
DominatorTree *DT, ScalarEvolution *SE) {
// Build up a worklist of inner-loops to version. This is necessary as the
// act of versioning a loop creates new loops and can invalidate iterators
// across the loops.
SmallVector<Loop *, 8> Worklist;
for (Loop *TopLevelLoop : *LI)
for (Loop *L : depth_first(TopLevelLoop))
// We only handle inner-most loops.
if (L->isInnermost())
Worklist.push_back(L);
// Now walk the identified inner loops.
bool Changed = false;
for (Loop *L : Worklist) {
if (!L->isLoopSimplifyForm() || !L->isRotatedForm() ||
!L->getExitingBlock())
continue;
const LoopAccessInfo &LAI = GetLAA(*L);
if (!LAI.hasConvergentOp() &&
(LAI.getNumRuntimePointerChecks() ||
!LAI.getPSE().getPredicate().isAlwaysTrue())) {
LoopVersioning LVer(LAI, LAI.getRuntimePointerChecking()->getChecks(), L,
LI, DT, SE);
LVer.versionLoop();
LVer.annotateLoopWithNoAlias();
Changed = true;
}
}
return Changed;
}
/// Also expose this is a pass. Currently this is only used for
/// unit-testing. It adds all memchecks necessary to remove all may-aliasing
/// array accesses from the loop.
class LoopVersioningLegacyPass : public FunctionPass {
public:
LoopVersioningLegacyPass() : FunctionPass(ID) {
initializeLoopVersioningLegacyPassPass(*PassRegistry::getPassRegistry());
}
bool runOnFunction(Function &F) override {
auto *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
auto GetLAA = [&](Loop &L) -> const LoopAccessInfo & {
return getAnalysis<LoopAccessLegacyAnalysis>().getInfo(&L);
};
auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
auto *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
return runImpl(LI, GetLAA, DT, SE);
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<LoopInfoWrapperPass>();
AU.addPreserved<LoopInfoWrapperPass>();
AU.addRequired<LoopAccessLegacyAnalysis>();
AU.addRequired<DominatorTreeWrapperPass>();
AU.addPreserved<DominatorTreeWrapperPass>();
AU.addRequired<ScalarEvolutionWrapperPass>();
}
static char ID;
};
}
#define LVER_OPTION "loop-versioning"
#define DEBUG_TYPE LVER_OPTION
char LoopVersioningLegacyPass::ID;
static const char LVer_name[] = "Loop Versioning";
INITIALIZE_PASS_BEGIN(LoopVersioningLegacyPass, LVER_OPTION, LVer_name, false,
false)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LoopAccessLegacyAnalysis)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
INITIALIZE_PASS_END(LoopVersioningLegacyPass, LVER_OPTION, LVer_name, false,
false)
namespace llvm {
FunctionPass *createLoopVersioningLegacyPass() {
return new LoopVersioningLegacyPass();
}
PreservedAnalyses LoopVersioningPass::run(Function &F,
FunctionAnalysisManager &AM) {
auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F);
auto &LI = AM.getResult<LoopAnalysis>(F);
auto &TTI = AM.getResult<TargetIRAnalysis>(F);
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
auto &AA = AM.getResult<AAManager>(F);
auto &AC = AM.getResult<AssumptionAnalysis>(F);
auto &LAM = AM.getResult<LoopAnalysisManagerFunctionProxy>(F).getManager();
auto GetLAA = [&](Loop &L) -> const LoopAccessInfo & {
LoopStandardAnalysisResults AR = {AA, AC, DT, LI, SE,
TLI, TTI, nullptr, nullptr, nullptr};
return LAM.getResult<LoopAccessAnalysis>(L, AR);
};
if (runImpl(&LI, GetLAA, &DT, &SE))
return PreservedAnalyses::none();
return PreservedAnalyses::all();
}
} // namespace llvm
diff --git a/contrib/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/contrib/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 91bc7dbad1d0..5fd4e45d80fb 100644
--- a/contrib/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/contrib/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -1,10568 +1,10574 @@
//===- LoopVectorize.cpp - A Loop Vectorizer ------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is the LLVM loop vectorizer. This pass modifies 'vectorizable' loops
// and generates target-independent LLVM-IR.
// The vectorizer uses the TargetTransformInfo analysis to estimate the costs
// of instructions in order to estimate the profitability of vectorization.
//
// The loop vectorizer combines consecutive loop iterations into a single
// 'wide' iteration. After this transformation the index is incremented
// by the SIMD vector width, and not by one.
//
// This pass has three parts:
// 1. The main loop pass that drives the different parts.
// 2. LoopVectorizationLegality - A unit that checks for the legality
// of the vectorization.
// 3. InnerLoopVectorizer - A unit that performs the actual
// widening of instructions.
// 4. LoopVectorizationCostModel - A unit that checks for the profitability
// of vectorization. It decides on the optimal vector width, which
// can be one, if vectorization is not profitable.
//
// There is a development effort going on to migrate loop vectorizer to the
// VPlan infrastructure and to introduce outer loop vectorization support (see
// docs/Proposal/VectorizationPlan.rst and
// http://lists.llvm.org/pipermail/llvm-dev/2017-December/119523.html). For this
// purpose, we temporarily introduced the VPlan-native vectorization path: an
// alternative vectorization path that is natively implemented on top of the
// VPlan infrastructure. See EnableVPlanNativePath for enabling.
//
//===----------------------------------------------------------------------===//
//
// The reduction-variable vectorization is based on the paper:
// D. Nuzman and R. Henderson. Multi-platform Auto-vectorization.
//
// Variable uniformity checks are inspired by:
// Karrenberg, R. and Hack, S. Whole Function Vectorization.
//
// The interleaved access vectorization is based on the paper:
// Dorit Nuzman, Ira Rosen and Ayal Zaks. Auto-Vectorization of Interleaved
// Data for SIMD
//
// Other ideas/concepts are from:
// A. Zaks and D. Nuzman. Autovectorization in GCC-two years later.
//
// S. Maleki, Y. Gao, M. Garzaran, T. Wong and D. Padua. An Evaluation of
// Vectorizing Compilers.
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Vectorize/LoopVectorize.h"
#include "LoopVectorizationPlanner.h"
#include "VPRecipeBuilder.h"
#include "VPlan.h"
#include "VPlanHCFGBuilder.h"
#include "VPlanTransforms.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/CodeMetrics.h"
#include "llvm/Analysis/DemandedBits.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/LoopAccessAnalysis.h"
#include "llvm/Analysis/LoopAnalysisManager.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/LoopIterator.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/IR/Verifier.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/InstructionCost.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/InjectTLIMappings.h"
#include "llvm/Transforms/Utils/LoopSimplify.h"
#include "llvm/Transforms/Utils/LoopUtils.h"
#include "llvm/Transforms/Utils/LoopVersioning.h"
#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h"
#include "llvm/Transforms/Utils/SizeOpts.h"
#include "llvm/Transforms/Vectorize/LoopVectorizationLegality.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <functional>
#include <iterator>
#include <limits>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
using namespace llvm;
#define LV_NAME "loop-vectorize"
#define DEBUG_TYPE LV_NAME
#ifndef NDEBUG
const char VerboseDebug[] = DEBUG_TYPE "-verbose";
#endif
/// @{
/// Metadata attribute names
const char LLVMLoopVectorizeFollowupAll[] = "llvm.loop.vectorize.followup_all";
const char LLVMLoopVectorizeFollowupVectorized[] =
"llvm.loop.vectorize.followup_vectorized";
const char LLVMLoopVectorizeFollowupEpilogue[] =
"llvm.loop.vectorize.followup_epilogue";
/// @}
STATISTIC(LoopsVectorized, "Number of loops vectorized");
STATISTIC(LoopsAnalyzed, "Number of loops analyzed for vectorization");
STATISTIC(LoopsEpilogueVectorized, "Number of epilogues vectorized");
static cl::opt<bool> EnableEpilogueVectorization(
"enable-epilogue-vectorization", cl::init(true), cl::Hidden,
cl::desc("Enable vectorization of epilogue loops."));
static cl::opt<unsigned> EpilogueVectorizationForceVF(
"epilogue-vectorization-force-VF", cl::init(1), cl::Hidden,
cl::desc("When epilogue vectorization is enabled, and a value greater than "
"1 is specified, forces the given VF for all applicable epilogue "
"loops."));
static cl::opt<unsigned> EpilogueVectorizationMinVF(
"epilogue-vectorization-minimum-VF", cl::init(16), cl::Hidden,
cl::desc("Only loops with vectorization factor equal to or larger than "
"the specified value are considered for epilogue vectorization."));
/// Loops with a known constant trip count below this number are vectorized only
/// if no scalar iteration overheads are incurred.
static cl::opt<unsigned> TinyTripCountVectorThreshold(
"vectorizer-min-trip-count", cl::init(16), cl::Hidden,
cl::desc("Loops with a constant trip count that is smaller than this "
"value are vectorized only if no scalar iteration overheads "
"are incurred."));
static cl::opt<unsigned> VectorizeMemoryCheckThreshold(
"vectorize-memory-check-threshold", cl::init(128), cl::Hidden,
cl::desc("The maximum allowed number of runtime memory checks"));
// Option prefer-predicate-over-epilogue indicates that an epilogue is undesired,
// that predication is preferred, and this lists all options. I.e., the
// vectorizer will try to fold the tail-loop (epilogue) into the vector body
// and predicate the instructions accordingly. If tail-folding fails, there are
// different fallback strategies depending on these values:
namespace PreferPredicateTy {
enum Option {
ScalarEpilogue = 0,
PredicateElseScalarEpilogue,
PredicateOrDontVectorize
};
} // namespace PreferPredicateTy
static cl::opt<PreferPredicateTy::Option> PreferPredicateOverEpilogue(
"prefer-predicate-over-epilogue",
cl::init(PreferPredicateTy::ScalarEpilogue),
cl::Hidden,
cl::desc("Tail-folding and predication preferences over creating a scalar "
"epilogue loop."),
cl::values(clEnumValN(PreferPredicateTy::ScalarEpilogue,
"scalar-epilogue",
"Don't tail-predicate loops, create scalar epilogue"),
clEnumValN(PreferPredicateTy::PredicateElseScalarEpilogue,
"predicate-else-scalar-epilogue",
"prefer tail-folding, create scalar epilogue if tail "
"folding fails."),
clEnumValN(PreferPredicateTy::PredicateOrDontVectorize,
"predicate-dont-vectorize",
"prefers tail-folding, don't attempt vectorization if "
"tail-folding fails.")));
static cl::opt<bool> MaximizeBandwidth(
"vectorizer-maximize-bandwidth", cl::init(false), cl::Hidden,
cl::desc("Maximize bandwidth when selecting vectorization factor which "
"will be determined by the smallest type in loop."));
static cl::opt<bool> EnableInterleavedMemAccesses(
"enable-interleaved-mem-accesses", cl::init(false), cl::Hidden,
cl::desc("Enable vectorization on interleaved memory accesses in a loop"));
/// An interleave-group may need masking if it resides in a block that needs
/// predication, or in order to mask away gaps.
static cl::opt<bool> EnableMaskedInterleavedMemAccesses(
"enable-masked-interleaved-mem-accesses", cl::init(false), cl::Hidden,
cl::desc("Enable vectorization on masked interleaved memory accesses in a loop"));
static cl::opt<unsigned> TinyTripCountInterleaveThreshold(
"tiny-trip-count-interleave-threshold", cl::init(128), cl::Hidden,
cl::desc("We don't interleave loops with a estimated constant trip count "
"below this number"));
static cl::opt<unsigned> ForceTargetNumScalarRegs(
"force-target-num-scalar-regs", cl::init(0), cl::Hidden,
cl::desc("A flag that overrides the target's number of scalar registers."));
static cl::opt<unsigned> ForceTargetNumVectorRegs(
"force-target-num-vector-regs", cl::init(0), cl::Hidden,
cl::desc("A flag that overrides the target's number of vector registers."));
static cl::opt<unsigned> ForceTargetMaxScalarInterleaveFactor(
"force-target-max-scalar-interleave", cl::init(0), cl::Hidden,
cl::desc("A flag that overrides the target's max interleave factor for "
"scalar loops."));
static cl::opt<unsigned> ForceTargetMaxVectorInterleaveFactor(
"force-target-max-vector-interleave", cl::init(0), cl::Hidden,
cl::desc("A flag that overrides the target's max interleave factor for "
"vectorized loops."));
static cl::opt<unsigned> ForceTargetInstructionCost(
"force-target-instruction-cost", cl::init(0), cl::Hidden,
cl::desc("A flag that overrides the target's expected cost for "
"an instruction to a single constant value. Mostly "
"useful for getting consistent testing."));
static cl::opt<bool> ForceTargetSupportsScalableVectors(
"force-target-supports-scalable-vectors", cl::init(false), cl::Hidden,
cl::desc(
"Pretend that scalable vectors are supported, even if the target does "
"not support them. This flag should only be used for testing."));
static cl::opt<unsigned> SmallLoopCost(
"small-loop-cost", cl::init(20), cl::Hidden,
cl::desc(
"The cost of a loop that is considered 'small' by the interleaver."));
static cl::opt<bool> LoopVectorizeWithBlockFrequency(
"loop-vectorize-with-block-frequency", cl::init(true), cl::Hidden,
cl::desc("Enable the use of the block frequency analysis to access PGO "
"heuristics minimizing code growth in cold regions and being more "
"aggressive in hot regions."));
// Runtime interleave loops for load/store throughput.
static cl::opt<bool> EnableLoadStoreRuntimeInterleave(
"enable-loadstore-runtime-interleave", cl::init(true), cl::Hidden,
cl::desc(
"Enable runtime interleaving until load/store ports are saturated"));
/// Interleave small loops with scalar reductions.
static cl::opt<bool> InterleaveSmallLoopScalarReduction(
"interleave-small-loop-scalar-reduction", cl::init(false), cl::Hidden,
cl::desc("Enable interleaving for loops with small iteration counts that "
"contain scalar reductions to expose ILP."));
/// The number of stores in a loop that are allowed to need predication.
static cl::opt<unsigned> NumberOfStoresToPredicate(
"vectorize-num-stores-pred", cl::init(1), cl::Hidden,
cl::desc("Max number of stores to be predicated behind an if."));
static cl::opt<bool> EnableIndVarRegisterHeur(
"enable-ind-var-reg-heur", cl::init(true), cl::Hidden,
cl::desc("Count the induction variable only once when interleaving"));
static cl::opt<bool> EnableCondStoresVectorization(
"enable-cond-stores-vec", cl::init(true), cl::Hidden,
cl::desc("Enable if predication of stores during vectorization."));
static cl::opt<unsigned> MaxNestedScalarReductionIC(
"max-nested-scalar-reduction-interleave", cl::init(2), cl::Hidden,
cl::desc("The maximum interleave count to use when interleaving a scalar "
"reduction in a nested loop."));
static cl::opt<bool>
PreferInLoopReductions("prefer-inloop-reductions", cl::init(false),
cl::Hidden,
cl::desc("Prefer in-loop vector reductions, "
"overriding the targets preference."));
static cl::opt<bool> ForceOrderedReductions(
"force-ordered-reductions", cl::init(false), cl::Hidden,
cl::desc("Enable the vectorisation of loops with in-order (strict) "
"FP reductions"));
static cl::opt<bool> PreferPredicatedReductionSelect(
"prefer-predicated-reduction-select", cl::init(false), cl::Hidden,
cl::desc(
"Prefer predicating a reduction operation over an after loop select."));
cl::opt<bool> EnableVPlanNativePath(
"enable-vplan-native-path", cl::init(false), cl::Hidden,
cl::desc("Enable VPlan-native vectorization path with "
"support for outer loop vectorization."));
// This flag enables the stress testing of the VPlan H-CFG construction in the
// VPlan-native vectorization path. It must be used in conjuction with
// -enable-vplan-native-path. -vplan-verify-hcfg can also be used to enable the
// verification of the H-CFGs built.
static cl::opt<bool> VPlanBuildStressTest(
"vplan-build-stress-test", cl::init(false), cl::Hidden,
cl::desc(
"Build VPlan for every supported loop nest in the function and bail "
"out right after the build (stress test the VPlan H-CFG construction "
"in the VPlan-native vectorization path)."));
cl::opt<bool> llvm::EnableLoopInterleaving(
"interleave-loops", cl::init(true), cl::Hidden,
cl::desc("Enable loop interleaving in Loop vectorization passes"));
cl::opt<bool> llvm::EnableLoopVectorization(
"vectorize-loops", cl::init(true), cl::Hidden,
cl::desc("Run the Loop vectorization passes"));
cl::opt<bool> PrintVPlansInDotFormat(
"vplan-print-in-dot-format", cl::init(false), cl::Hidden,
cl::desc("Use dot format instead of plain text when dumping VPlans"));
/// A helper function that returns true if the given type is irregular. The
/// type is irregular if its allocated size doesn't equal the store size of an
/// element of the corresponding vector type.
static bool hasIrregularType(Type *Ty, const DataLayout &DL) {
// Determine if an array of N elements of type Ty is "bitcast compatible"
// with a <N x Ty> vector.
// This is only true if there is no padding between the array elements.
return DL.getTypeAllocSizeInBits(Ty) != DL.getTypeSizeInBits(Ty);
}
/// A helper function that returns the reciprocal of the block probability of
/// predicated blocks. If we return X, we are assuming the predicated block
/// will execute once for every X iterations of the loop header.
///
/// TODO: We should use actual block probability here, if available. Currently,
/// we always assume predicated blocks have a 50% chance of executing.
static unsigned getReciprocalPredBlockProb() { return 2; }
/// A helper function that returns an integer or floating-point constant with
/// value C.
static Constant *getSignedIntOrFpConstant(Type *Ty, int64_t C) {
return Ty->isIntegerTy() ? ConstantInt::getSigned(Ty, C)
: ConstantFP::get(Ty, C);
}
/// Returns "best known" trip count for the specified loop \p L as defined by
/// the following procedure:
/// 1) Returns exact trip count if it is known.
/// 2) Returns expected trip count according to profile data if any.
/// 3) Returns upper bound estimate if it is known.
/// 4) Returns None if all of the above failed.
static Optional<unsigned> getSmallBestKnownTC(ScalarEvolution &SE, Loop *L) {
// Check if exact trip count is known.
if (unsigned ExpectedTC = SE.getSmallConstantTripCount(L))
return ExpectedTC;
// Check if there is an expected trip count available from profile data.
if (LoopVectorizeWithBlockFrequency)
if (auto EstimatedTC = getLoopEstimatedTripCount(L))
return EstimatedTC;
// Check if upper bound estimate is known.
if (unsigned ExpectedTC = SE.getSmallConstantMaxTripCount(L))
return ExpectedTC;
return None;
}
// Forward declare GeneratedRTChecks.
class GeneratedRTChecks;
namespace llvm {
AnalysisKey ShouldRunExtraVectorPasses::Key;
/// InnerLoopVectorizer vectorizes loops which contain only one basic
/// block to a specified vectorization factor (VF).
/// This class performs the widening of scalars into vectors, or multiple
/// scalars. This class also implements the following features:
/// * It inserts an epilogue loop for handling loops that don't have iteration
/// counts that are known to be a multiple of the vectorization factor.
/// * It handles the code generation for reduction variables.
/// * Scalarization (implementation using scalars) of un-vectorizable
/// instructions.
/// InnerLoopVectorizer does not perform any vectorization-legality
/// checks, and relies on the caller to check for the different legality
/// aspects. The InnerLoopVectorizer relies on the
/// LoopVectorizationLegality class to provide information about the induction
/// and reduction variables that were found to a given vectorization factor.
class InnerLoopVectorizer {
public:
InnerLoopVectorizer(Loop *OrigLoop, PredicatedScalarEvolution &PSE,
LoopInfo *LI, DominatorTree *DT,
const TargetLibraryInfo *TLI,
const TargetTransformInfo *TTI, AssumptionCache *AC,
OptimizationRemarkEmitter *ORE, ElementCount VecWidth,
ElementCount MinProfitableTripCount,
unsigned UnrollFactor, LoopVectorizationLegality *LVL,
LoopVectorizationCostModel *CM, BlockFrequencyInfo *BFI,
ProfileSummaryInfo *PSI, GeneratedRTChecks &RTChecks)
: OrigLoop(OrigLoop), PSE(PSE), LI(LI), DT(DT), TLI(TLI), TTI(TTI),
AC(AC), ORE(ORE), VF(VecWidth), UF(UnrollFactor),
Builder(PSE.getSE()->getContext()), Legal(LVL), Cost(CM), BFI(BFI),
PSI(PSI), RTChecks(RTChecks) {
// Query this against the original loop and save it here because the profile
// of the original loop header may change as the transformation happens.
OptForSizeBasedOnProfile = llvm::shouldOptimizeForSize(
OrigLoop->getHeader(), PSI, BFI, PGSOQueryType::IRPass);
if (MinProfitableTripCount.isZero())
this->MinProfitableTripCount = VecWidth;
else
this->MinProfitableTripCount = MinProfitableTripCount;
}
virtual ~InnerLoopVectorizer() = default;
/// Create a new empty loop that will contain vectorized instructions later
/// on, while the old loop will be used as the scalar remainder. Control flow
/// is generated around the vectorized (and scalar epilogue) loops consisting
/// of various checks and bypasses. Return the pre-header block of the new
/// loop and the start value for the canonical induction, if it is != 0. The
/// latter is the case when vectorizing the epilogue loop. In the case of
/// epilogue vectorization, this function is overriden to handle the more
/// complex control flow around the loops.
virtual std::pair<BasicBlock *, Value *> createVectorizedLoopSkeleton();
/// Widen a single call instruction within the innermost loop.
void widenCallInstruction(CallInst &CI, VPValue *Def, VPUser &ArgOperands,
VPTransformState &State);
/// Fix the vectorized code, taking care of header phi's, live-outs, and more.
void fixVectorizedLoop(VPTransformState &State, VPlan &Plan);
// Return true if any runtime check is added.
bool areSafetyChecksAdded() { return AddedSafetyChecks; }
/// A type for vectorized values in the new loop. Each value from the
/// original loop, when vectorized, is represented by UF vector values in the
/// new unrolled loop, where UF is the unroll factor.
using VectorParts = SmallVector<Value *, 2>;
/// A helper function to scalarize a single Instruction in the innermost loop.
/// Generates a sequence of scalar instances for each lane between \p MinLane
/// and \p MaxLane, times each part between \p MinPart and \p MaxPart,
/// inclusive. Uses the VPValue operands from \p RepRecipe instead of \p
/// Instr's operands.
void scalarizeInstruction(Instruction *Instr, VPReplicateRecipe *RepRecipe,
const VPIteration &Instance, bool IfPredicateInstr,
VPTransformState &State);
/// Construct the vector value of a scalarized value \p V one lane at a time.
void packScalarIntoVectorValue(VPValue *Def, const VPIteration &Instance,
VPTransformState &State);
/// Try to vectorize interleaved access group \p Group with the base address
/// given in \p Addr, optionally masking the vector operations if \p
/// BlockInMask is non-null. Use \p State to translate given VPValues to IR
/// values in the vectorized loop.
void vectorizeInterleaveGroup(const InterleaveGroup<Instruction> *Group,
ArrayRef<VPValue *> VPDefs,
VPTransformState &State, VPValue *Addr,
ArrayRef<VPValue *> StoredValues,
VPValue *BlockInMask = nullptr);
/// Fix the non-induction PHIs in \p Plan.
void fixNonInductionPHIs(VPlan &Plan, VPTransformState &State);
/// Returns true if the reordering of FP operations is not allowed, but we are
/// able to vectorize with strict in-order reductions for the given RdxDesc.
bool useOrderedReductions(const RecurrenceDescriptor &RdxDesc);
/// Create a broadcast instruction. This method generates a broadcast
/// instruction (shuffle) for loop invariant values and for the induction
/// value. If this is the induction variable then we extend it to N, N+1, ...
/// this is needed because each iteration in the loop corresponds to a SIMD
/// element.
virtual Value *getBroadcastInstrs(Value *V);
// Returns the resume value (bc.merge.rdx) for a reduction as
// generated by fixReduction.
PHINode *getReductionResumeValue(const RecurrenceDescriptor &RdxDesc);
protected:
friend class LoopVectorizationPlanner;
/// A small list of PHINodes.
using PhiVector = SmallVector<PHINode *, 4>;
/// A type for scalarized values in the new loop. Each value from the
/// original loop, when scalarized, is represented by UF x VF scalar values
/// in the new unrolled loop, where UF is the unroll factor and VF is the
/// vectorization factor.
using ScalarParts = SmallVector<SmallVector<Value *, 4>, 2>;
/// Set up the values of the IVs correctly when exiting the vector loop.
void fixupIVUsers(PHINode *OrigPhi, const InductionDescriptor &II,
Value *VectorTripCount, Value *EndValue,
BasicBlock *MiddleBlock, BasicBlock *VectorHeader,
VPlan &Plan);
/// Handle all cross-iteration phis in the header.
void fixCrossIterationPHIs(VPTransformState &State);
/// Create the exit value of first order recurrences in the middle block and
/// update their users.
void fixFirstOrderRecurrence(VPFirstOrderRecurrencePHIRecipe *PhiR,
VPTransformState &State);
/// Create code for the loop exit value of the reduction.
void fixReduction(VPReductionPHIRecipe *Phi, VPTransformState &State);
/// Clear NSW/NUW flags from reduction instructions if necessary.
void clearReductionWrapFlags(VPReductionPHIRecipe *PhiR,
VPTransformState &State);
/// Iteratively sink the scalarized operands of a predicated instruction into
/// the block that was created for it.
void sinkScalarOperands(Instruction *PredInst);
/// Shrinks vector element sizes to the smallest bitwidth they can be legally
/// represented as.
void truncateToMinimalBitwidths(VPTransformState &State);
/// Returns (and creates if needed) the original loop trip count.
Value *getOrCreateTripCount(BasicBlock *InsertBlock);
/// Returns (and creates if needed) the trip count of the widened loop.
Value *getOrCreateVectorTripCount(BasicBlock *InsertBlock);
/// Returns a bitcasted value to the requested vector type.
/// Also handles bitcasts of vector<float> <-> vector<pointer> types.
Value *createBitOrPointerCast(Value *V, VectorType *DstVTy,
const DataLayout &DL);
/// Emit a bypass check to see if the vector trip count is zero, including if
/// it overflows.
void emitIterationCountCheck(BasicBlock *Bypass);
/// Emit a bypass check to see if all of the SCEV assumptions we've
/// had to make are correct. Returns the block containing the checks or
/// nullptr if no checks have been added.
BasicBlock *emitSCEVChecks(BasicBlock *Bypass);
/// Emit bypass checks to check any memory assumptions we may have made.
/// Returns the block containing the checks or nullptr if no checks have been
/// added.
BasicBlock *emitMemRuntimeChecks(BasicBlock *Bypass);
/// Emit basic blocks (prefixed with \p Prefix) for the iteration check,
/// vector loop preheader, middle block and scalar preheader.
void createVectorLoopSkeleton(StringRef Prefix);
/// Create new phi nodes for the induction variables to resume iteration count
/// in the scalar epilogue, from where the vectorized loop left off.
/// In cases where the loop skeleton is more complicated (eg. epilogue
/// vectorization) and the resume values can come from an additional bypass
/// block, the \p AdditionalBypass pair provides information about the bypass
/// block and the end value on the edge from bypass to this loop.
void createInductionResumeValues(
std::pair<BasicBlock *, Value *> AdditionalBypass = {nullptr, nullptr});
/// Complete the loop skeleton by adding debug MDs, creating appropriate
/// conditional branches in the middle block, preparing the builder and
/// running the verifier. Return the preheader of the completed vector loop.
BasicBlock *completeLoopSkeleton(MDNode *OrigLoopID);
/// Collect poison-generating recipes that may generate a poison value that is
/// used after vectorization, even when their operands are not poison. Those
/// recipes meet the following conditions:
/// * Contribute to the address computation of a recipe generating a widen
/// memory load/store (VPWidenMemoryInstructionRecipe or
/// VPInterleaveRecipe).
/// * Such a widen memory load/store has at least one underlying Instruction
/// that is in a basic block that needs predication and after vectorization
/// the generated instruction won't be predicated.
void collectPoisonGeneratingRecipes(VPTransformState &State);
/// Allow subclasses to override and print debug traces before/after vplan
/// execution, when trace information is requested.
virtual void printDebugTracesAtStart(){};
virtual void printDebugTracesAtEnd(){};
/// The original loop.
Loop *OrigLoop;
/// A wrapper around ScalarEvolution used to add runtime SCEV checks. Applies
/// dynamic knowledge to simplify SCEV expressions and converts them to a
/// more usable form.
PredicatedScalarEvolution &PSE;
/// Loop Info.
LoopInfo *LI;
/// Dominator Tree.
DominatorTree *DT;
/// Alias Analysis.
AAResults *AA;
/// Target Library Info.
const TargetLibraryInfo *TLI;
/// Target Transform Info.
const TargetTransformInfo *TTI;
/// Assumption Cache.
AssumptionCache *AC;
/// Interface to emit optimization remarks.
OptimizationRemarkEmitter *ORE;
/// The vectorization SIMD factor to use. Each vector will have this many
/// vector elements.
ElementCount VF;
ElementCount MinProfitableTripCount;
/// The vectorization unroll factor to use. Each scalar is vectorized to this
/// many different vector instructions.
unsigned UF;
/// The builder that we use
IRBuilder<> Builder;
// --- Vectorization state ---
/// The vector-loop preheader.
BasicBlock *LoopVectorPreHeader;
/// The scalar-loop preheader.
BasicBlock *LoopScalarPreHeader;
/// Middle Block between the vector and the scalar.
BasicBlock *LoopMiddleBlock;
/// The unique ExitBlock of the scalar loop if one exists. Note that
/// there can be multiple exiting edges reaching this block.
BasicBlock *LoopExitBlock;
/// The scalar loop body.
BasicBlock *LoopScalarBody;
/// A list of all bypass blocks. The first block is the entry of the loop.
SmallVector<BasicBlock *, 4> LoopBypassBlocks;
/// Store instructions that were predicated.
SmallVector<Instruction *, 4> PredicatedInstructions;
/// Trip count of the original loop.
Value *TripCount = nullptr;
/// Trip count of the widened loop (TripCount - TripCount % (VF*UF))
Value *VectorTripCount = nullptr;
/// The legality analysis.
LoopVectorizationLegality *Legal;
/// The profitablity analysis.
LoopVectorizationCostModel *Cost;
// Record whether runtime checks are added.
bool AddedSafetyChecks = false;
// Holds the end values for each induction variable. We save the end values
// so we can later fix-up the external users of the induction variables.
DenseMap<PHINode *, Value *> IVEndValues;
/// BFI and PSI are used to check for profile guided size optimizations.
BlockFrequencyInfo *BFI;
ProfileSummaryInfo *PSI;
// Whether this loop should be optimized for size based on profile guided size
// optimizatios.
bool OptForSizeBasedOnProfile;
/// Structure to hold information about generated runtime checks, responsible
/// for cleaning the checks, if vectorization turns out unprofitable.
GeneratedRTChecks &RTChecks;
// Holds the resume values for reductions in the loops, used to set the
// correct start value of reduction PHIs when vectorizing the epilogue.
SmallMapVector<const RecurrenceDescriptor *, PHINode *, 4>
ReductionResumeValues;
};
class InnerLoopUnroller : public InnerLoopVectorizer {
public:
InnerLoopUnroller(Loop *OrigLoop, PredicatedScalarEvolution &PSE,
LoopInfo *LI, DominatorTree *DT,
const TargetLibraryInfo *TLI,
const TargetTransformInfo *TTI, AssumptionCache *AC,
OptimizationRemarkEmitter *ORE, unsigned UnrollFactor,
LoopVectorizationLegality *LVL,
LoopVectorizationCostModel *CM, BlockFrequencyInfo *BFI,
ProfileSummaryInfo *PSI, GeneratedRTChecks &Check)
: InnerLoopVectorizer(OrigLoop, PSE, LI, DT, TLI, TTI, AC, ORE,
ElementCount::getFixed(1),
ElementCount::getFixed(1), UnrollFactor, LVL, CM,
BFI, PSI, Check) {}
private:
Value *getBroadcastInstrs(Value *V) override;
};
/// Encapsulate information regarding vectorization of a loop and its epilogue.
/// This information is meant to be updated and used across two stages of
/// epilogue vectorization.
struct EpilogueLoopVectorizationInfo {
ElementCount MainLoopVF = ElementCount::getFixed(0);
unsigned MainLoopUF = 0;
ElementCount EpilogueVF = ElementCount::getFixed(0);
unsigned EpilogueUF = 0;
BasicBlock *MainLoopIterationCountCheck = nullptr;
BasicBlock *EpilogueIterationCountCheck = nullptr;
BasicBlock *SCEVSafetyCheck = nullptr;
BasicBlock *MemSafetyCheck = nullptr;
Value *TripCount = nullptr;
Value *VectorTripCount = nullptr;
EpilogueLoopVectorizationInfo(ElementCount MVF, unsigned MUF,
ElementCount EVF, unsigned EUF)
: MainLoopVF(MVF), MainLoopUF(MUF), EpilogueVF(EVF), EpilogueUF(EUF) {
assert(EUF == 1 &&
"A high UF for the epilogue loop is likely not beneficial.");
}
};
/// An extension of the inner loop vectorizer that creates a skeleton for a
/// vectorized loop that has its epilogue (residual) also vectorized.
/// The idea is to run the vplan on a given loop twice, firstly to setup the
/// skeleton and vectorize the main loop, and secondly to complete the skeleton
/// from the first step and vectorize the epilogue. This is achieved by
/// deriving two concrete strategy classes from this base class and invoking
/// them in succession from the loop vectorizer planner.
class InnerLoopAndEpilogueVectorizer : public InnerLoopVectorizer {
public:
InnerLoopAndEpilogueVectorizer(
Loop *OrigLoop, PredicatedScalarEvolution &PSE, LoopInfo *LI,
DominatorTree *DT, const TargetLibraryInfo *TLI,
const TargetTransformInfo *TTI, AssumptionCache *AC,
OptimizationRemarkEmitter *ORE, EpilogueLoopVectorizationInfo &EPI,
LoopVectorizationLegality *LVL, llvm::LoopVectorizationCostModel *CM,
BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI,
GeneratedRTChecks &Checks)
: InnerLoopVectorizer(OrigLoop, PSE, LI, DT, TLI, TTI, AC, ORE,
EPI.MainLoopVF, EPI.MainLoopVF, EPI.MainLoopUF, LVL,
CM, BFI, PSI, Checks),
EPI(EPI) {}
// Override this function to handle the more complex control flow around the
// three loops.
std::pair<BasicBlock *, Value *> createVectorizedLoopSkeleton() final {
return createEpilogueVectorizedLoopSkeleton();
}
/// The interface for creating a vectorized skeleton using one of two
/// different strategies, each corresponding to one execution of the vplan
/// as described above.
virtual std::pair<BasicBlock *, Value *>
createEpilogueVectorizedLoopSkeleton() = 0;
/// Holds and updates state information required to vectorize the main loop
/// and its epilogue in two separate passes. This setup helps us avoid
/// regenerating and recomputing runtime safety checks. It also helps us to
/// shorten the iteration-count-check path length for the cases where the
/// iteration count of the loop is so small that the main vector loop is
/// completely skipped.
EpilogueLoopVectorizationInfo &EPI;
};
/// A specialized derived class of inner loop vectorizer that performs
/// vectorization of *main* loops in the process of vectorizing loops and their
/// epilogues.
class EpilogueVectorizerMainLoop : public InnerLoopAndEpilogueVectorizer {
public:
EpilogueVectorizerMainLoop(
Loop *OrigLoop, PredicatedScalarEvolution &PSE, LoopInfo *LI,
DominatorTree *DT, const TargetLibraryInfo *TLI,
const TargetTransformInfo *TTI, AssumptionCache *AC,
OptimizationRemarkEmitter *ORE, EpilogueLoopVectorizationInfo &EPI,
LoopVectorizationLegality *LVL, llvm::LoopVectorizationCostModel *CM,
BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI,
GeneratedRTChecks &Check)
: InnerLoopAndEpilogueVectorizer(OrigLoop, PSE, LI, DT, TLI, TTI, AC, ORE,
EPI, LVL, CM, BFI, PSI, Check) {}
/// Implements the interface for creating a vectorized skeleton using the
/// *main loop* strategy (ie the first pass of vplan execution).
std::pair<BasicBlock *, Value *> createEpilogueVectorizedLoopSkeleton() final;
protected:
/// Emits an iteration count bypass check once for the main loop (when \p
/// ForEpilogue is false) and once for the epilogue loop (when \p
/// ForEpilogue is true).
BasicBlock *emitIterationCountCheck(BasicBlock *Bypass, bool ForEpilogue);
void printDebugTracesAtStart() override;
void printDebugTracesAtEnd() override;
};
// A specialized derived class of inner loop vectorizer that performs
// vectorization of *epilogue* loops in the process of vectorizing loops and
// their epilogues.
class EpilogueVectorizerEpilogueLoop : public InnerLoopAndEpilogueVectorizer {
public:
EpilogueVectorizerEpilogueLoop(
Loop *OrigLoop, PredicatedScalarEvolution &PSE, LoopInfo *LI,
DominatorTree *DT, const TargetLibraryInfo *TLI,
const TargetTransformInfo *TTI, AssumptionCache *AC,
OptimizationRemarkEmitter *ORE, EpilogueLoopVectorizationInfo &EPI,
LoopVectorizationLegality *LVL, llvm::LoopVectorizationCostModel *CM,
BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI,
GeneratedRTChecks &Checks)
: InnerLoopAndEpilogueVectorizer(OrigLoop, PSE, LI, DT, TLI, TTI, AC, ORE,
EPI, LVL, CM, BFI, PSI, Checks) {
TripCount = EPI.TripCount;
}
/// Implements the interface for creating a vectorized skeleton using the
/// *epilogue loop* strategy (ie the second pass of vplan execution).
std::pair<BasicBlock *, Value *> createEpilogueVectorizedLoopSkeleton() final;
protected:
/// Emits an iteration count bypass check after the main vector loop has
/// finished to see if there are any iterations left to execute by either
/// the vector epilogue or the scalar epilogue.
BasicBlock *emitMinimumVectorEpilogueIterCountCheck(
BasicBlock *Bypass,
BasicBlock *Insert);
void printDebugTracesAtStart() override;
void printDebugTracesAtEnd() override;
};
} // end namespace llvm
/// Look for a meaningful debug location on the instruction or it's
/// operands.
static Instruction *getDebugLocFromInstOrOperands(Instruction *I) {
if (!I)
return I;
DebugLoc Empty;
if (I->getDebugLoc() != Empty)
return I;
for (Use &Op : I->operands()) {
if (Instruction *OpInst = dyn_cast<Instruction>(Op))
if (OpInst->getDebugLoc() != Empty)
return OpInst;
}
return I;
}
/// Write a \p DebugMsg about vectorization to the debug output stream. If \p I
/// is passed, the message relates to that particular instruction.
#ifndef NDEBUG
static void debugVectorizationMessage(const StringRef Prefix,
const StringRef DebugMsg,
Instruction *I) {
dbgs() << "LV: " << Prefix << DebugMsg;
if (I != nullptr)
dbgs() << " " << *I;
else
dbgs() << '.';
dbgs() << '\n';
}
#endif
/// Create an analysis remark that explains why vectorization failed
///
/// \p PassName is the name of the pass (e.g. can be AlwaysPrint). \p
/// RemarkName is the identifier for the remark. If \p I is passed it is an
/// instruction that prevents vectorization. Otherwise \p TheLoop is used for
/// the location of the remark. \return the remark object that can be
/// streamed to.
static OptimizationRemarkAnalysis createLVAnalysis(const char *PassName,
StringRef RemarkName, Loop *TheLoop, Instruction *I) {
Value *CodeRegion = TheLoop->getHeader();
DebugLoc DL = TheLoop->getStartLoc();
if (I) {
CodeRegion = I->getParent();
// If there is no debug location attached to the instruction, revert back to
// using the loop's.
if (I->getDebugLoc())
DL = I->getDebugLoc();
}
return OptimizationRemarkAnalysis(PassName, RemarkName, DL, CodeRegion);
}
namespace llvm {
/// Return a value for Step multiplied by VF.
Value *createStepForVF(IRBuilderBase &B, Type *Ty, ElementCount VF,
int64_t Step) {
assert(Ty->isIntegerTy() && "Expected an integer step");
Constant *StepVal = ConstantInt::get(Ty, Step * VF.getKnownMinValue());
return VF.isScalable() ? B.CreateVScale(StepVal) : StepVal;
}
/// Return the runtime value for VF.
Value *getRuntimeVF(IRBuilderBase &B, Type *Ty, ElementCount VF) {
Constant *EC = ConstantInt::get(Ty, VF.getKnownMinValue());
return VF.isScalable() ? B.CreateVScale(EC) : EC;
}
static Value *getRuntimeVFAsFloat(IRBuilderBase &B, Type *FTy,
ElementCount VF) {
assert(FTy->isFloatingPointTy() && "Expected floating point type!");
Type *IntTy = IntegerType::get(FTy->getContext(), FTy->getScalarSizeInBits());
Value *RuntimeVF = getRuntimeVF(B, IntTy, VF);
return B.CreateUIToFP(RuntimeVF, FTy);
}
void reportVectorizationFailure(const StringRef DebugMsg,
const StringRef OREMsg, const StringRef ORETag,
OptimizationRemarkEmitter *ORE, Loop *TheLoop,
Instruction *I) {
LLVM_DEBUG(debugVectorizationMessage("Not vectorizing: ", DebugMsg, I));
LoopVectorizeHints Hints(TheLoop, true /* doesn't matter */, *ORE);
ORE->emit(
createLVAnalysis(Hints.vectorizeAnalysisPassName(), ORETag, TheLoop, I)
<< "loop not vectorized: " << OREMsg);
}
void reportVectorizationInfo(const StringRef Msg, const StringRef ORETag,
OptimizationRemarkEmitter *ORE, Loop *TheLoop,
Instruction *I) {
LLVM_DEBUG(debugVectorizationMessage("", Msg, I));
LoopVectorizeHints Hints(TheLoop, true /* doesn't matter */, *ORE);
ORE->emit(
createLVAnalysis(Hints.vectorizeAnalysisPassName(), ORETag, TheLoop, I)
<< Msg);
}
} // end namespace llvm
#ifndef NDEBUG
/// \return string containing a file name and a line # for the given loop.
static std::string getDebugLocString(const Loop *L) {
std::string Result;
if (L) {
raw_string_ostream OS(Result);
if (const DebugLoc LoopDbgLoc = L->getStartLoc())
LoopDbgLoc.print(OS);
else
// Just print the module name.
OS << L->getHeader()->getParent()->getParent()->getModuleIdentifier();
OS.flush();
}
return Result;
}
#endif
void InnerLoopVectorizer::collectPoisonGeneratingRecipes(
VPTransformState &State) {
// Collect recipes in the backward slice of `Root` that may generate a poison
// value that is used after vectorization.
SmallPtrSet<VPRecipeBase *, 16> Visited;
auto collectPoisonGeneratingInstrsInBackwardSlice([&](VPRecipeBase *Root) {
SmallVector<VPRecipeBase *, 16> Worklist;
Worklist.push_back(Root);
// Traverse the backward slice of Root through its use-def chain.
while (!Worklist.empty()) {
VPRecipeBase *CurRec = Worklist.back();
Worklist.pop_back();
if (!Visited.insert(CurRec).second)
continue;
// Prune search if we find another recipe generating a widen memory
// instruction. Widen memory instructions involved in address computation
// will lead to gather/scatter instructions, which don't need to be
// handled.
if (isa<VPWidenMemoryInstructionRecipe>(CurRec) ||
isa<VPInterleaveRecipe>(CurRec) ||
isa<VPScalarIVStepsRecipe>(CurRec) ||
isa<VPCanonicalIVPHIRecipe>(CurRec) ||
isa<VPActiveLaneMaskPHIRecipe>(CurRec))
continue;
// This recipe contributes to the address computation of a widen
// load/store. Collect recipe if its underlying instruction has
// poison-generating flags.
Instruction *Instr = CurRec->getUnderlyingInstr();
if (Instr && Instr->hasPoisonGeneratingFlags())
State.MayGeneratePoisonRecipes.insert(CurRec);
// Add new definitions to the worklist.
for (VPValue *operand : CurRec->operands())
if (VPDef *OpDef = operand->getDef())
Worklist.push_back(cast<VPRecipeBase>(OpDef));
}
});
// Traverse all the recipes in the VPlan and collect the poison-generating
// recipes in the backward slice starting at the address of a VPWidenRecipe or
// VPInterleaveRecipe.
auto Iter = depth_first(
VPBlockRecursiveTraversalWrapper<VPBlockBase *>(State.Plan->getEntry()));
for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(Iter)) {
for (VPRecipeBase &Recipe : *VPBB) {
if (auto *WidenRec = dyn_cast<VPWidenMemoryInstructionRecipe>(&Recipe)) {
Instruction &UnderlyingInstr = WidenRec->getIngredient();
VPDef *AddrDef = WidenRec->getAddr()->getDef();
if (AddrDef && WidenRec->isConsecutive() &&
Legal->blockNeedsPredication(UnderlyingInstr.getParent()))
collectPoisonGeneratingInstrsInBackwardSlice(
cast<VPRecipeBase>(AddrDef));
} else if (auto *InterleaveRec = dyn_cast<VPInterleaveRecipe>(&Recipe)) {
VPDef *AddrDef = InterleaveRec->getAddr()->getDef();
if (AddrDef) {
// Check if any member of the interleave group needs predication.
const InterleaveGroup<Instruction> *InterGroup =
InterleaveRec->getInterleaveGroup();
bool NeedPredication = false;
for (int I = 0, NumMembers = InterGroup->getNumMembers();
I < NumMembers; ++I) {
Instruction *Member = InterGroup->getMember(I);
if (Member)
NeedPredication |=
Legal->blockNeedsPredication(Member->getParent());
}
if (NeedPredication)
collectPoisonGeneratingInstrsInBackwardSlice(
cast<VPRecipeBase>(AddrDef));
}
}
}
}
}
PHINode *InnerLoopVectorizer::getReductionResumeValue(
const RecurrenceDescriptor &RdxDesc) {
auto It = ReductionResumeValues.find(&RdxDesc);
assert(It != ReductionResumeValues.end() &&
"Expected to find a resume value for the reduction.");
return It->second;
}
namespace llvm {
// Loop vectorization cost-model hints how the scalar epilogue loop should be
// lowered.
enum ScalarEpilogueLowering {
// The default: allowing scalar epilogues.
CM_ScalarEpilogueAllowed,
// Vectorization with OptForSize: don't allow epilogues.
CM_ScalarEpilogueNotAllowedOptSize,
// A special case of vectorisation with OptForSize: loops with a very small
// trip count are considered for vectorization under OptForSize, thereby
// making sure the cost of their loop body is dominant, free of runtime
// guards and scalar iteration overheads.
CM_ScalarEpilogueNotAllowedLowTripLoop,
// Loop hint predicate indicating an epilogue is undesired.
CM_ScalarEpilogueNotNeededUsePredicate,
// Directive indicating we must either tail fold or not vectorize
CM_ScalarEpilogueNotAllowedUsePredicate
};
/// ElementCountComparator creates a total ordering for ElementCount
/// for the purposes of using it in a set structure.
struct ElementCountComparator {
bool operator()(const ElementCount &LHS, const ElementCount &RHS) const {
return std::make_tuple(LHS.isScalable(), LHS.getKnownMinValue()) <
std::make_tuple(RHS.isScalable(), RHS.getKnownMinValue());
}
};
using ElementCountSet = SmallSet<ElementCount, 16, ElementCountComparator>;
/// LoopVectorizationCostModel - estimates the expected speedups due to
/// vectorization.
/// In many cases vectorization is not profitable. This can happen because of
/// a number of reasons. In this class we mainly attempt to predict the
/// expected speedup/slowdowns due to the supported instruction set. We use the
/// TargetTransformInfo to query the different backends for the cost of
/// different operations.
class LoopVectorizationCostModel {
public:
LoopVectorizationCostModel(ScalarEpilogueLowering SEL, Loop *L,
PredicatedScalarEvolution &PSE, LoopInfo *LI,
LoopVectorizationLegality *Legal,
const TargetTransformInfo &TTI,
const TargetLibraryInfo *TLI, DemandedBits *DB,
AssumptionCache *AC,
OptimizationRemarkEmitter *ORE, const Function *F,
const LoopVectorizeHints *Hints,
InterleavedAccessInfo &IAI)
: ScalarEpilogueStatus(SEL), TheLoop(L), PSE(PSE), LI(LI), Legal(Legal),
TTI(TTI), TLI(TLI), DB(DB), AC(AC), ORE(ORE), TheFunction(F),
Hints(Hints), InterleaveInfo(IAI) {}
/// \return An upper bound for the vectorization factors (both fixed and
/// scalable). If the factors are 0, vectorization and interleaving should be
/// avoided up front.
FixedScalableVFPair computeMaxVF(ElementCount UserVF, unsigned UserIC);
/// \return True if runtime checks are required for vectorization, and false
/// otherwise.
bool runtimeChecksRequired();
/// \return The most profitable vectorization factor and the cost of that VF.
/// This method checks every VF in \p CandidateVFs. If UserVF is not ZERO
/// then this vectorization factor will be selected if vectorization is
/// possible.
VectorizationFactor
selectVectorizationFactor(const ElementCountSet &CandidateVFs);
VectorizationFactor
selectEpilogueVectorizationFactor(const ElementCount MaxVF,
const LoopVectorizationPlanner &LVP);
/// Setup cost-based decisions for user vectorization factor.
/// \return true if the UserVF is a feasible VF to be chosen.
bool selectUserVectorizationFactor(ElementCount UserVF) {
collectUniformsAndScalars(UserVF);
collectInstsToScalarize(UserVF);
return expectedCost(UserVF).first.isValid();
}
/// \return The size (in bits) of the smallest and widest types in the code
/// that needs to be vectorized. We ignore values that remain scalar such as
/// 64 bit loop indices.
std::pair<unsigned, unsigned> getSmallestAndWidestTypes();
/// \return The desired interleave count.
/// If interleave count has been specified by metadata it will be returned.
/// Otherwise, the interleave count is computed and returned. VF and LoopCost
/// are the selected vectorization factor and the cost of the selected VF.
unsigned selectInterleaveCount(ElementCount VF, unsigned LoopCost);
/// Memory access instruction may be vectorized in more than one way.
/// Form of instruction after vectorization depends on cost.
/// This function takes cost-based decisions for Load/Store instructions
/// and collects them in a map. This decisions map is used for building
/// the lists of loop-uniform and loop-scalar instructions.
/// The calculated cost is saved with widening decision in order to
/// avoid redundant calculations.
void setCostBasedWideningDecision(ElementCount VF);
/// A struct that represents some properties of the register usage
/// of a loop.
struct RegisterUsage {
/// Holds the number of loop invariant values that are used in the loop.
/// The key is ClassID of target-provided register class.
SmallMapVector<unsigned, unsigned, 4> LoopInvariantRegs;
/// Holds the maximum number of concurrent live intervals in the loop.
/// The key is ClassID of target-provided register class.
SmallMapVector<unsigned, unsigned, 4> MaxLocalUsers;
};
/// \return Returns information about the register usages of the loop for the
/// given vectorization factors.
SmallVector<RegisterUsage, 8>
calculateRegisterUsage(ArrayRef<ElementCount> VFs);
/// Collect values we want to ignore in the cost model.
void collectValuesToIgnore();
/// Collect all element types in the loop for which widening is needed.
void collectElementTypesForWidening();
/// Split reductions into those that happen in the loop, and those that happen
/// outside. In loop reductions are collected into InLoopReductionChains.
void collectInLoopReductions();
/// Returns true if we should use strict in-order reductions for the given
/// RdxDesc. This is true if the -enable-strict-reductions flag is passed,
/// the IsOrdered flag of RdxDesc is set and we do not allow reordering
/// of FP operations.
bool useOrderedReductions(const RecurrenceDescriptor &RdxDesc) const {
return !Hints->allowReordering() && RdxDesc.isOrdered();
}
/// \returns The smallest bitwidth each instruction can be represented with.
/// The vector equivalents of these instructions should be truncated to this
/// type.
const MapVector<Instruction *, uint64_t> &getMinimalBitwidths() const {
return MinBWs;
}
/// \returns True if it is more profitable to scalarize instruction \p I for
/// vectorization factor \p VF.
bool isProfitableToScalarize(Instruction *I, ElementCount VF) const {
assert(VF.isVector() &&
"Profitable to scalarize relevant only for VF > 1.");
// Cost model is not run in the VPlan-native path - return conservative
// result until this changes.
if (EnableVPlanNativePath)
return false;
auto Scalars = InstsToScalarize.find(VF);
assert(Scalars != InstsToScalarize.end() &&
"VF not yet analyzed for scalarization profitability");
return Scalars->second.find(I) != Scalars->second.end();
}
/// Returns true if \p I is known to be uniform after vectorization.
bool isUniformAfterVectorization(Instruction *I, ElementCount VF) const {
if (VF.isScalar())
return true;
// Cost model is not run in the VPlan-native path - return conservative
// result until this changes.
if (EnableVPlanNativePath)
return false;
auto UniformsPerVF = Uniforms.find(VF);
assert(UniformsPerVF != Uniforms.end() &&
"VF not yet analyzed for uniformity");
return UniformsPerVF->second.count(I);
}
/// Returns true if \p I is known to be scalar after vectorization.
bool isScalarAfterVectorization(Instruction *I, ElementCount VF) const {
if (VF.isScalar())
return true;
// Cost model is not run in the VPlan-native path - return conservative
// result until this changes.
if (EnableVPlanNativePath)
return false;
auto ScalarsPerVF = Scalars.find(VF);
assert(ScalarsPerVF != Scalars.end() &&
"Scalar values are not calculated for VF");
return ScalarsPerVF->second.count(I);
}
/// \returns True if instruction \p I can be truncated to a smaller bitwidth
/// for vectorization factor \p VF.
bool canTruncateToMinimalBitwidth(Instruction *I, ElementCount VF) const {
return VF.isVector() && MinBWs.find(I) != MinBWs.end() &&
!isProfitableToScalarize(I, VF) &&
!isScalarAfterVectorization(I, VF);
}
/// Decision that was taken during cost calculation for memory instruction.
enum InstWidening {
CM_Unknown,
CM_Widen, // For consecutive accesses with stride +1.
CM_Widen_Reverse, // For consecutive accesses with stride -1.
CM_Interleave,
CM_GatherScatter,
CM_Scalarize
};
/// Save vectorization decision \p W and \p Cost taken by the cost model for
/// instruction \p I and vector width \p VF.
void setWideningDecision(Instruction *I, ElementCount VF, InstWidening W,
InstructionCost Cost) {
assert(VF.isVector() && "Expected VF >=2");
WideningDecisions[std::make_pair(I, VF)] = std::make_pair(W, Cost);
}
/// Save vectorization decision \p W and \p Cost taken by the cost model for
/// interleaving group \p Grp and vector width \p VF.
void setWideningDecision(const InterleaveGroup<Instruction> *Grp,
ElementCount VF, InstWidening W,
InstructionCost Cost) {
assert(VF.isVector() && "Expected VF >=2");
/// Broadcast this decicion to all instructions inside the group.
/// But the cost will be assigned to one instruction only.
for (unsigned i = 0; i < Grp->getFactor(); ++i) {
if (auto *I = Grp->getMember(i)) {
if (Grp->getInsertPos() == I)
WideningDecisions[std::make_pair(I, VF)] = std::make_pair(W, Cost);
else
WideningDecisions[std::make_pair(I, VF)] = std::make_pair(W, 0);
}
}
}
/// Return the cost model decision for the given instruction \p I and vector
/// width \p VF. Return CM_Unknown if this instruction did not pass
/// through the cost modeling.
InstWidening getWideningDecision(Instruction *I, ElementCount VF) const {
assert(VF.isVector() && "Expected VF to be a vector VF");
// Cost model is not run in the VPlan-native path - return conservative
// result until this changes.
if (EnableVPlanNativePath)
return CM_GatherScatter;
std::pair<Instruction *, ElementCount> InstOnVF = std::make_pair(I, VF);
auto Itr = WideningDecisions.find(InstOnVF);
if (Itr == WideningDecisions.end())
return CM_Unknown;
return Itr->second.first;
}
/// Return the vectorization cost for the given instruction \p I and vector
/// width \p VF.
InstructionCost getWideningCost(Instruction *I, ElementCount VF) {
assert(VF.isVector() && "Expected VF >=2");
std::pair<Instruction *, ElementCount> InstOnVF = std::make_pair(I, VF);
assert(WideningDecisions.find(InstOnVF) != WideningDecisions.end() &&
"The cost is not calculated");
return WideningDecisions[InstOnVF].second;
}
/// Return True if instruction \p I is an optimizable truncate whose operand
/// is an induction variable. Such a truncate will be removed by adding a new
/// induction variable with the destination type.
bool isOptimizableIVTruncate(Instruction *I, ElementCount VF) {
// If the instruction is not a truncate, return false.
auto *Trunc = dyn_cast<TruncInst>(I);
if (!Trunc)
return false;
// Get the source and destination types of the truncate.
Type *SrcTy = ToVectorTy(cast<CastInst>(I)->getSrcTy(), VF);
Type *DestTy = ToVectorTy(cast<CastInst>(I)->getDestTy(), VF);
// If the truncate is free for the given types, return false. Replacing a
// free truncate with an induction variable would add an induction variable
// update instruction to each iteration of the loop. We exclude from this
// check the primary induction variable since it will need an update
// instruction regardless.
Value *Op = Trunc->getOperand(0);
if (Op != Legal->getPrimaryInduction() && TTI.isTruncateFree(SrcTy, DestTy))
return false;
// If the truncated value is not an induction variable, return false.
return Legal->isInductionPhi(Op);
}
/// Collects the instructions to scalarize for each predicated instruction in
/// the loop.
void collectInstsToScalarize(ElementCount VF);
/// Collect Uniform and Scalar values for the given \p VF.
/// The sets depend on CM decision for Load/Store instructions
/// that may be vectorized as interleave, gather-scatter or scalarized.
void collectUniformsAndScalars(ElementCount VF) {
// Do the analysis once.
if (VF.isScalar() || Uniforms.find(VF) != Uniforms.end())
return;
setCostBasedWideningDecision(VF);
collectLoopUniforms(VF);
collectLoopScalars(VF);
}
/// Returns true if the target machine supports masked store operation
/// for the given \p DataType and kind of access to \p Ptr.
bool isLegalMaskedStore(Type *DataType, Value *Ptr, Align Alignment) const {
return Legal->isConsecutivePtr(DataType, Ptr) &&
TTI.isLegalMaskedStore(DataType, Alignment);
}
/// Returns true if the target machine supports masked load operation
/// for the given \p DataType and kind of access to \p Ptr.
bool isLegalMaskedLoad(Type *DataType, Value *Ptr, Align Alignment) const {
return Legal->isConsecutivePtr(DataType, Ptr) &&
TTI.isLegalMaskedLoad(DataType, Alignment);
}
/// Returns true if the target machine can represent \p V as a masked gather
/// or scatter operation.
bool isLegalGatherOrScatter(Value *V,
ElementCount VF = ElementCount::getFixed(1)) {
bool LI = isa<LoadInst>(V);
bool SI = isa<StoreInst>(V);
if (!LI && !SI)
return false;
auto *Ty = getLoadStoreType(V);
Align Align = getLoadStoreAlignment(V);
if (VF.isVector())
Ty = VectorType::get(Ty, VF);
return (LI && TTI.isLegalMaskedGather(Ty, Align)) ||
(SI && TTI.isLegalMaskedScatter(Ty, Align));
}
/// Returns true if the target machine supports all of the reduction
/// variables found for the given VF.
bool canVectorizeReductions(ElementCount VF) const {
return (all_of(Legal->getReductionVars(), [&](auto &Reduction) -> bool {
const RecurrenceDescriptor &RdxDesc = Reduction.second;
return TTI.isLegalToVectorizeReduction(RdxDesc, VF);
}));
}
/// Returns true if \p I is an instruction that will be scalarized with
/// predication when vectorizing \p I with vectorization factor \p VF. Such
/// instructions include conditional stores and instructions that may divide
/// by zero.
bool isScalarWithPredication(Instruction *I, ElementCount VF) const;
// Returns true if \p I is an instruction that will be predicated either
// through scalar predication or masked load/store or masked gather/scatter.
// \p VF is the vectorization factor that will be used to vectorize \p I.
// Superset of instructions that return true for isScalarWithPredication.
bool isPredicatedInst(Instruction *I, ElementCount VF) {
// When we know the load's address is loop invariant and the instruction
// in the original scalar loop was unconditionally executed then we
// don't need to mark it as a predicated instruction. Tail folding may
// introduce additional predication, but we're guaranteed to always have
// at least one active lane. We call Legal->blockNeedsPredication here
// because it doesn't query tail-folding.
if (Legal->isUniformMemOp(*I) && isa<LoadInst>(I) &&
!Legal->blockNeedsPredication(I->getParent()))
return false;
if (!blockNeedsPredicationForAnyReason(I->getParent()))
return false;
// Loads and stores that need some form of masked operation are predicated
// instructions.
if (isa<LoadInst>(I) || isa<StoreInst>(I))
return Legal->isMaskRequired(I);
return isScalarWithPredication(I, VF);
}
/// Returns true if \p I is a memory instruction with consecutive memory
/// access that can be widened.
bool
memoryInstructionCanBeWidened(Instruction *I,
ElementCount VF = ElementCount::getFixed(1));
/// Returns true if \p I is a memory instruction in an interleaved-group
/// of memory accesses that can be vectorized with wide vector loads/stores
/// and shuffles.
bool
interleavedAccessCanBeWidened(Instruction *I,
ElementCount VF = ElementCount::getFixed(1));
/// Check if \p Instr belongs to any interleaved access group.
bool isAccessInterleaved(Instruction *Instr) {
return InterleaveInfo.isInterleaved(Instr);
}
/// Get the interleaved access group that \p Instr belongs to.
const InterleaveGroup<Instruction> *
getInterleavedAccessGroup(Instruction *Instr) {
return InterleaveInfo.getInterleaveGroup(Instr);
}
/// Returns true if we're required to use a scalar epilogue for at least
/// the final iteration of the original loop.
bool requiresScalarEpilogue(ElementCount VF) const {
if (!isScalarEpilogueAllowed())
return false;
// If we might exit from anywhere but the latch, must run the exiting
// iteration in scalar form.
if (TheLoop->getExitingBlock() != TheLoop->getLoopLatch())
return true;
return VF.isVector() && InterleaveInfo.requiresScalarEpilogue();
}
/// Returns true if a scalar epilogue is not allowed due to optsize or a
/// loop hint annotation.
bool isScalarEpilogueAllowed() const {
return ScalarEpilogueStatus == CM_ScalarEpilogueAllowed;
}
/// Returns true if all loop blocks should be masked to fold tail loop.
bool foldTailByMasking() const { return FoldTailByMasking; }
/// Returns true if were tail-folding and want to use the active lane mask
/// for vector loop control flow.
bool useActiveLaneMaskForControlFlow() const {
return FoldTailByMasking &&
TTI.emitGetActiveLaneMask() == PredicationStyle::DataAndControlFlow;
}
/// Returns true if the instructions in this block requires predication
/// for any reason, e.g. because tail folding now requires a predicate
/// or because the block in the original loop was predicated.
bool blockNeedsPredicationForAnyReason(BasicBlock *BB) const {
return foldTailByMasking() || Legal->blockNeedsPredication(BB);
}
/// A SmallMapVector to store the InLoop reduction op chains, mapping phi
/// nodes to the chain of instructions representing the reductions. Uses a
/// MapVector to ensure deterministic iteration order.
using ReductionChainMap =
SmallMapVector<PHINode *, SmallVector<Instruction *, 4>, 4>;
/// Return the chain of instructions representing an inloop reduction.
const ReductionChainMap &getInLoopReductionChains() const {
return InLoopReductionChains;
}
/// Returns true if the Phi is part of an inloop reduction.
bool isInLoopReduction(PHINode *Phi) const {
return InLoopReductionChains.count(Phi);
}
/// Estimate cost of an intrinsic call instruction CI if it were vectorized
/// with factor VF. Return the cost of the instruction, including
/// scalarization overhead if it's needed.
InstructionCost getVectorIntrinsicCost(CallInst *CI, ElementCount VF) const;
/// Estimate cost of a call instruction CI if it were vectorized with factor
/// VF. Return the cost of the instruction, including scalarization overhead
/// if it's needed. The flag NeedToScalarize shows if the call needs to be
/// scalarized -
/// i.e. either vector version isn't available, or is too expensive.
InstructionCost getVectorCallCost(CallInst *CI, ElementCount VF,
bool &NeedToScalarize) const;
/// Returns true if the per-lane cost of VectorizationFactor A is lower than
/// that of B.
bool isMoreProfitable(const VectorizationFactor &A,
const VectorizationFactor &B) const;
/// Invalidates decisions already taken by the cost model.
void invalidateCostModelingDecisions() {
WideningDecisions.clear();
Uniforms.clear();
Scalars.clear();
}
/// Convenience function that returns the value of vscale_range iff
/// vscale_range.min == vscale_range.max or otherwise returns the value
/// returned by the corresponding TLI method.
Optional<unsigned> getVScaleForTuning() const;
private:
unsigned NumPredStores = 0;
/// \return An upper bound for the vectorization factors for both
/// fixed and scalable vectorization, where the minimum-known number of
/// elements is a power-of-2 larger than zero. If scalable vectorization is
/// disabled or unsupported, then the scalable part will be equal to
/// ElementCount::getScalable(0).
FixedScalableVFPair computeFeasibleMaxVF(unsigned ConstTripCount,
ElementCount UserVF,
bool FoldTailByMasking);
/// \return the maximized element count based on the targets vector
/// registers and the loop trip-count, but limited to a maximum safe VF.
/// This is a helper function of computeFeasibleMaxVF.
ElementCount getMaximizedVFForTarget(unsigned ConstTripCount,
unsigned SmallestType,
unsigned WidestType,
ElementCount MaxSafeVF,
bool FoldTailByMasking);
/// \return the maximum legal scalable VF, based on the safe max number
/// of elements.
ElementCount getMaxLegalScalableVF(unsigned MaxSafeElements);
/// The vectorization cost is a combination of the cost itself and a boolean
/// indicating whether any of the contributing operations will actually
/// operate on vector values after type legalization in the backend. If this
/// latter value is false, then all operations will be scalarized (i.e. no
/// vectorization has actually taken place).
using VectorizationCostTy = std::pair<InstructionCost, bool>;
/// Returns the expected execution cost. The unit of the cost does
/// not matter because we use the 'cost' units to compare different
/// vector widths. The cost that is returned is *not* normalized by
/// the factor width. If \p Invalid is not nullptr, this function
/// will add a pair(Instruction*, ElementCount) to \p Invalid for
/// each instruction that has an Invalid cost for the given VF.
using InstructionVFPair = std::pair<Instruction *, ElementCount>;
VectorizationCostTy
expectedCost(ElementCount VF,
SmallVectorImpl<InstructionVFPair> *Invalid = nullptr);
/// Returns the execution time cost of an instruction for a given vector
/// width. Vector width of one means scalar.
VectorizationCostTy getInstructionCost(Instruction *I, ElementCount VF);
/// The cost-computation logic from getInstructionCost which provides
/// the vector type as an output parameter.
InstructionCost getInstructionCost(Instruction *I, ElementCount VF,
Type *&VectorTy);
/// Return the cost of instructions in an inloop reduction pattern, if I is
/// part of that pattern.
Optional<InstructionCost>
getReductionPatternCost(Instruction *I, ElementCount VF, Type *VectorTy,
TTI::TargetCostKind CostKind);
/// Calculate vectorization cost of memory instruction \p I.
InstructionCost getMemoryInstructionCost(Instruction *I, ElementCount VF);
/// The cost computation for scalarized memory instruction.
InstructionCost getMemInstScalarizationCost(Instruction *I, ElementCount VF);
/// The cost computation for interleaving group of memory instructions.
InstructionCost getInterleaveGroupCost(Instruction *I, ElementCount VF);
/// The cost computation for Gather/Scatter instruction.
InstructionCost getGatherScatterCost(Instruction *I, ElementCount VF);
/// The cost computation for widening instruction \p I with consecutive
/// memory access.
InstructionCost getConsecutiveMemOpCost(Instruction *I, ElementCount VF);
/// The cost calculation for Load/Store instruction \p I with uniform pointer -
/// Load: scalar load + broadcast.
/// Store: scalar store + (loop invariant value stored? 0 : extract of last
/// element)
InstructionCost getUniformMemOpCost(Instruction *I, ElementCount VF);
/// Estimate the overhead of scalarizing an instruction. This is a
/// convenience wrapper for the type-based getScalarizationOverhead API.
InstructionCost getScalarizationOverhead(Instruction *I,
ElementCount VF) const;
/// Returns true if an artificially high cost for emulated masked memrefs
/// should be used.
bool useEmulatedMaskMemRefHack(Instruction *I, ElementCount VF);
/// Map of scalar integer values to the smallest bitwidth they can be legally
/// represented as. The vector equivalents of these values should be truncated
/// to this type.
MapVector<Instruction *, uint64_t> MinBWs;
/// A type representing the costs for instructions if they were to be
/// scalarized rather than vectorized. The entries are Instruction-Cost
/// pairs.
using ScalarCostsTy = DenseMap<Instruction *, InstructionCost>;
/// A set containing all BasicBlocks that are known to present after
/// vectorization as a predicated block.
DenseMap<ElementCount, SmallPtrSet<BasicBlock *, 4>>
PredicatedBBsAfterVectorization;
/// Records whether it is allowed to have the original scalar loop execute at
/// least once. This may be needed as a fallback loop in case runtime
/// aliasing/dependence checks fail, or to handle the tail/remainder
/// iterations when the trip count is unknown or doesn't divide by the VF,
/// or as a peel-loop to handle gaps in interleave-groups.
/// Under optsize and when the trip count is very small we don't allow any
/// iterations to execute in the scalar loop.
ScalarEpilogueLowering ScalarEpilogueStatus = CM_ScalarEpilogueAllowed;
/// All blocks of loop are to be masked to fold tail of scalar iterations.
bool FoldTailByMasking = false;
/// A map holding scalar costs for different vectorization factors. The
/// presence of a cost for an instruction in the mapping indicates that the
/// instruction will be scalarized when vectorizing with the associated
/// vectorization factor. The entries are VF-ScalarCostTy pairs.
DenseMap<ElementCount, ScalarCostsTy> InstsToScalarize;
/// Holds the instructions known to be uniform after vectorization.
/// The data is collected per VF.
DenseMap<ElementCount, SmallPtrSet<Instruction *, 4>> Uniforms;
/// Holds the instructions known to be scalar after vectorization.
/// The data is collected per VF.
DenseMap<ElementCount, SmallPtrSet<Instruction *, 4>> Scalars;
/// Holds the instructions (address computations) that are forced to be
/// scalarized.
DenseMap<ElementCount, SmallPtrSet<Instruction *, 4>> ForcedScalars;
/// PHINodes of the reductions that should be expanded in-loop along with
/// their associated chains of reduction operations, in program order from top
/// (PHI) to bottom
ReductionChainMap InLoopReductionChains;
/// A Map of inloop reduction operations and their immediate chain operand.
/// FIXME: This can be removed once reductions can be costed correctly in
/// vplan. This was added to allow quick lookup to the inloop operations,
/// without having to loop through InLoopReductionChains.
DenseMap<Instruction *, Instruction *> InLoopReductionImmediateChains;
/// Returns the expected difference in cost from scalarizing the expression
/// feeding a predicated instruction \p PredInst. The instructions to
/// scalarize and their scalar costs are collected in \p ScalarCosts. A
/// non-negative return value implies the expression will be scalarized.
/// Currently, only single-use chains are considered for scalarization.
int computePredInstDiscount(Instruction *PredInst, ScalarCostsTy &ScalarCosts,
ElementCount VF);
/// Collect the instructions that are uniform after vectorization. An
/// instruction is uniform if we represent it with a single scalar value in
/// the vectorized loop corresponding to each vector iteration. Examples of
/// uniform instructions include pointer operands of consecutive or
/// interleaved memory accesses. Note that although uniformity implies an
/// instruction will be scalar, the reverse is not true. In general, a
/// scalarized instruction will be represented by VF scalar values in the
/// vectorized loop, each corresponding to an iteration of the original
/// scalar loop.
void collectLoopUniforms(ElementCount VF);
/// Collect the instructions that are scalar after vectorization. An
/// instruction is scalar if it is known to be uniform or will be scalarized
/// during vectorization. collectLoopScalars should only add non-uniform nodes
/// to the list if they are used by a load/store instruction that is marked as
/// CM_Scalarize. Non-uniform scalarized instructions will be represented by
/// VF values in the vectorized loop, each corresponding to an iteration of
/// the original scalar loop.
void collectLoopScalars(ElementCount VF);
/// Keeps cost model vectorization decision and cost for instructions.
/// Right now it is used for memory instructions only.
using DecisionList = DenseMap<std::pair<Instruction *, ElementCount>,
std::pair<InstWidening, InstructionCost>>;
DecisionList WideningDecisions;
/// Returns true if \p V is expected to be vectorized and it needs to be
/// extracted.
bool needsExtract(Value *V, ElementCount VF) const {
Instruction *I = dyn_cast<Instruction>(V);
if (VF.isScalar() || !I || !TheLoop->contains(I) ||
TheLoop->isLoopInvariant(I))
return false;
// Assume we can vectorize V (and hence we need extraction) if the
// scalars are not computed yet. This can happen, because it is called
// via getScalarizationOverhead from setCostBasedWideningDecision, before
// the scalars are collected. That should be a safe assumption in most
// cases, because we check if the operands have vectorizable types
// beforehand in LoopVectorizationLegality.
return Scalars.find(VF) == Scalars.end() ||
!isScalarAfterVectorization(I, VF);
};
/// Returns a range containing only operands needing to be extracted.
SmallVector<Value *, 4> filterExtractingOperands(Instruction::op_range Ops,
ElementCount VF) const {
return SmallVector<Value *, 4>(make_filter_range(
Ops, [this, VF](Value *V) { return this->needsExtract(V, VF); }));
}
/// Determines if we have the infrastructure to vectorize loop \p L and its
/// epilogue, assuming the main loop is vectorized by \p VF.
bool isCandidateForEpilogueVectorization(const Loop &L,
const ElementCount VF) const;
/// Returns true if epilogue vectorization is considered profitable, and
/// false otherwise.
/// \p VF is the vectorization factor chosen for the original loop.
bool isEpilogueVectorizationProfitable(const ElementCount VF) const;
public:
/// The loop that we evaluate.
Loop *TheLoop;
/// Predicated scalar evolution analysis.
PredicatedScalarEvolution &PSE;
/// Loop Info analysis.
LoopInfo *LI;
/// Vectorization legality.
LoopVectorizationLegality *Legal;
/// Vector target information.
const TargetTransformInfo &TTI;
/// Target Library Info.
const TargetLibraryInfo *TLI;
/// Demanded bits analysis.
DemandedBits *DB;
/// Assumption cache.
AssumptionCache *AC;
/// Interface to emit optimization remarks.
OptimizationRemarkEmitter *ORE;
const Function *TheFunction;
/// Loop Vectorize Hint.
const LoopVectorizeHints *Hints;
/// The interleave access information contains groups of interleaved accesses
/// with the same stride and close to each other.
InterleavedAccessInfo &InterleaveInfo;
/// Values to ignore in the cost model.
SmallPtrSet<const Value *, 16> ValuesToIgnore;
/// Values to ignore in the cost model when VF > 1.
SmallPtrSet<const Value *, 16> VecValuesToIgnore;
/// All element types found in the loop.
SmallPtrSet<Type *, 16> ElementTypesInLoop;
/// Profitable vector factors.
SmallVector<VectorizationFactor, 8> ProfitableVFs;
};
} // end namespace llvm
/// Helper struct to manage generating runtime checks for vectorization.
///
/// The runtime checks are created up-front in temporary blocks to allow better
/// estimating the cost and un-linked from the existing IR. After deciding to
/// vectorize, the checks are moved back. If deciding not to vectorize, the
/// temporary blocks are completely removed.
class GeneratedRTChecks {
/// Basic block which contains the generated SCEV checks, if any.
BasicBlock *SCEVCheckBlock = nullptr;
/// The value representing the result of the generated SCEV checks. If it is
/// nullptr, either no SCEV checks have been generated or they have been used.
Value *SCEVCheckCond = nullptr;
/// Basic block which contains the generated memory runtime checks, if any.
BasicBlock *MemCheckBlock = nullptr;
/// The value representing the result of the generated memory runtime checks.
/// If it is nullptr, either no memory runtime checks have been generated or
/// they have been used.
Value *MemRuntimeCheckCond = nullptr;
DominatorTree *DT;
LoopInfo *LI;
TargetTransformInfo *TTI;
SCEVExpander SCEVExp;
SCEVExpander MemCheckExp;
bool CostTooHigh = false;
public:
GeneratedRTChecks(ScalarEvolution &SE, DominatorTree *DT, LoopInfo *LI,
TargetTransformInfo *TTI, const DataLayout &DL)
: DT(DT), LI(LI), TTI(TTI), SCEVExp(SE, DL, "scev.check"),
MemCheckExp(SE, DL, "scev.check") {}
/// Generate runtime checks in SCEVCheckBlock and MemCheckBlock, so we can
/// accurately estimate the cost of the runtime checks. The blocks are
/// un-linked from the IR and is added back during vector code generation. If
/// there is no vector code generation, the check blocks are removed
/// completely.
void Create(Loop *L, const LoopAccessInfo &LAI,
const SCEVPredicate &UnionPred, ElementCount VF, unsigned IC) {
// Hard cutoff to limit compile-time increase in case a very large number of
// runtime checks needs to be generated.
// TODO: Skip cutoff if the loop is guaranteed to execute, e.g. due to
// profile info.
CostTooHigh =
LAI.getNumRuntimePointerChecks() > VectorizeMemoryCheckThreshold;
if (CostTooHigh)
return;
BasicBlock *LoopHeader = L->getHeader();
BasicBlock *Preheader = L->getLoopPreheader();
// Use SplitBlock to create blocks for SCEV & memory runtime checks to
// ensure the blocks are properly added to LoopInfo & DominatorTree. Those
// may be used by SCEVExpander. The blocks will be un-linked from their
// predecessors and removed from LI & DT at the end of the function.
if (!UnionPred.isAlwaysTrue()) {
SCEVCheckBlock = SplitBlock(Preheader, Preheader->getTerminator(), DT, LI,
nullptr, "vector.scevcheck");
SCEVCheckCond = SCEVExp.expandCodeForPredicate(
&UnionPred, SCEVCheckBlock->getTerminator());
}
const auto &RtPtrChecking = *LAI.getRuntimePointerChecking();
if (RtPtrChecking.Need) {
auto *Pred = SCEVCheckBlock ? SCEVCheckBlock : Preheader;
MemCheckBlock = SplitBlock(Pred, Pred->getTerminator(), DT, LI, nullptr,
"vector.memcheck");
auto DiffChecks = RtPtrChecking.getDiffChecks();
if (DiffChecks) {
Value *RuntimeVF = nullptr;
MemRuntimeCheckCond = addDiffRuntimeChecks(
MemCheckBlock->getTerminator(), L, *DiffChecks, MemCheckExp,
[VF, &RuntimeVF](IRBuilderBase &B, unsigned Bits) {
if (!RuntimeVF)
RuntimeVF = getRuntimeVF(B, B.getIntNTy(Bits), VF);
return RuntimeVF;
},
IC);
} else {
MemRuntimeCheckCond =
addRuntimeChecks(MemCheckBlock->getTerminator(), L,
RtPtrChecking.getChecks(), MemCheckExp);
}
assert(MemRuntimeCheckCond &&
"no RT checks generated although RtPtrChecking "
"claimed checks are required");
}
if (!MemCheckBlock && !SCEVCheckBlock)
return;
// Unhook the temporary block with the checks, update various places
// accordingly.
if (SCEVCheckBlock)
SCEVCheckBlock->replaceAllUsesWith(Preheader);
if (MemCheckBlock)
MemCheckBlock->replaceAllUsesWith(Preheader);
if (SCEVCheckBlock) {
SCEVCheckBlock->getTerminator()->moveBefore(Preheader->getTerminator());
new UnreachableInst(Preheader->getContext(), SCEVCheckBlock);
Preheader->getTerminator()->eraseFromParent();
}
if (MemCheckBlock) {
MemCheckBlock->getTerminator()->moveBefore(Preheader->getTerminator());
new UnreachableInst(Preheader->getContext(), MemCheckBlock);
Preheader->getTerminator()->eraseFromParent();
}
DT->changeImmediateDominator(LoopHeader, Preheader);
if (MemCheckBlock) {
DT->eraseNode(MemCheckBlock);
LI->removeBlock(MemCheckBlock);
}
if (SCEVCheckBlock) {
DT->eraseNode(SCEVCheckBlock);
LI->removeBlock(SCEVCheckBlock);
}
}
InstructionCost getCost() {
if (SCEVCheckBlock || MemCheckBlock)
LLVM_DEBUG(dbgs() << "Calculating cost of runtime checks:\n");
if (CostTooHigh) {
InstructionCost Cost;
Cost.setInvalid();
LLVM_DEBUG(dbgs() << " number of checks exceeded threshold\n");
return Cost;
}
InstructionCost RTCheckCost = 0;
if (SCEVCheckBlock)
for (Instruction &I : *SCEVCheckBlock) {
if (SCEVCheckBlock->getTerminator() == &I)
continue;
InstructionCost C =
TTI->getInstructionCost(&I, TTI::TCK_RecipThroughput);
LLVM_DEBUG(dbgs() << " " << C << " for " << I << "\n");
RTCheckCost += C;
}
if (MemCheckBlock)
for (Instruction &I : *MemCheckBlock) {
if (MemCheckBlock->getTerminator() == &I)
continue;
InstructionCost C =
TTI->getInstructionCost(&I, TTI::TCK_RecipThroughput);
LLVM_DEBUG(dbgs() << " " << C << " for " << I << "\n");
RTCheckCost += C;
}
if (SCEVCheckBlock || MemCheckBlock)
LLVM_DEBUG(dbgs() << "Total cost of runtime checks: " << RTCheckCost
<< "\n");
return RTCheckCost;
}
/// Remove the created SCEV & memory runtime check blocks & instructions, if
/// unused.
~GeneratedRTChecks() {
SCEVExpanderCleaner SCEVCleaner(SCEVExp);
SCEVExpanderCleaner MemCheckCleaner(MemCheckExp);
if (!SCEVCheckCond)
SCEVCleaner.markResultUsed();
if (!MemRuntimeCheckCond)
MemCheckCleaner.markResultUsed();
if (MemRuntimeCheckCond) {
auto &SE = *MemCheckExp.getSE();
// Memory runtime check generation creates compares that use expanded
// values. Remove them before running the SCEVExpanderCleaners.
for (auto &I : make_early_inc_range(reverse(*MemCheckBlock))) {
if (MemCheckExp.isInsertedInstruction(&I))
continue;
SE.forgetValue(&I);
I.eraseFromParent();
}
}
MemCheckCleaner.cleanup();
SCEVCleaner.cleanup();
if (SCEVCheckCond)
SCEVCheckBlock->eraseFromParent();
if (MemRuntimeCheckCond)
MemCheckBlock->eraseFromParent();
}
/// Adds the generated SCEVCheckBlock before \p LoopVectorPreHeader and
/// adjusts the branches to branch to the vector preheader or \p Bypass,
/// depending on the generated condition.
BasicBlock *emitSCEVChecks(BasicBlock *Bypass,
BasicBlock *LoopVectorPreHeader,
BasicBlock *LoopExitBlock) {
if (!SCEVCheckCond)
return nullptr;
Value *Cond = SCEVCheckCond;
// Mark the check as used, to prevent it from being removed during cleanup.
SCEVCheckCond = nullptr;
if (auto *C = dyn_cast<ConstantInt>(Cond))
if (C->isZero())
return nullptr;
auto *Pred = LoopVectorPreHeader->getSinglePredecessor();
BranchInst::Create(LoopVectorPreHeader, SCEVCheckBlock);
// Create new preheader for vector loop.
if (auto *PL = LI->getLoopFor(LoopVectorPreHeader))
PL->addBasicBlockToLoop(SCEVCheckBlock, *LI);
SCEVCheckBlock->getTerminator()->eraseFromParent();
SCEVCheckBlock->moveBefore(LoopVectorPreHeader);
Pred->getTerminator()->replaceSuccessorWith(LoopVectorPreHeader,
SCEVCheckBlock);
DT->addNewBlock(SCEVCheckBlock, Pred);
DT->changeImmediateDominator(LoopVectorPreHeader, SCEVCheckBlock);
ReplaceInstWithInst(SCEVCheckBlock->getTerminator(),
BranchInst::Create(Bypass, LoopVectorPreHeader, Cond));
return SCEVCheckBlock;
}
/// Adds the generated MemCheckBlock before \p LoopVectorPreHeader and adjusts
/// the branches to branch to the vector preheader or \p Bypass, depending on
/// the generated condition.
BasicBlock *emitMemRuntimeChecks(BasicBlock *Bypass,
BasicBlock *LoopVectorPreHeader) {
// Check if we generated code that checks in runtime if arrays overlap.
if (!MemRuntimeCheckCond)
return nullptr;
auto *Pred = LoopVectorPreHeader->getSinglePredecessor();
Pred->getTerminator()->replaceSuccessorWith(LoopVectorPreHeader,
MemCheckBlock);
DT->addNewBlock(MemCheckBlock, Pred);
DT->changeImmediateDominator(LoopVectorPreHeader, MemCheckBlock);
MemCheckBlock->moveBefore(LoopVectorPreHeader);
if (auto *PL = LI->getLoopFor(LoopVectorPreHeader))
PL->addBasicBlockToLoop(MemCheckBlock, *LI);
ReplaceInstWithInst(
MemCheckBlock->getTerminator(),
BranchInst::Create(Bypass, LoopVectorPreHeader, MemRuntimeCheckCond));
MemCheckBlock->getTerminator()->setDebugLoc(
Pred->getTerminator()->getDebugLoc());
// Mark the check as used, to prevent it from being removed during cleanup.
MemRuntimeCheckCond = nullptr;
return MemCheckBlock;
}
};
// Return true if \p OuterLp is an outer loop annotated with hints for explicit
// vectorization. The loop needs to be annotated with #pragma omp simd
// simdlen(#) or #pragma clang vectorize(enable) vectorize_width(#). If the
// vector length information is not provided, vectorization is not considered
// explicit. Interleave hints are not allowed either. These limitations will be
// relaxed in the future.
// Please, note that we are currently forced to abuse the pragma 'clang
// vectorize' semantics. This pragma provides *auto-vectorization hints*
// (i.e., LV must check that vectorization is legal) whereas pragma 'omp simd'
// provides *explicit vectorization hints* (LV can bypass legal checks and
// assume that vectorization is legal). However, both hints are implemented
// using the same metadata (llvm.loop.vectorize, processed by
// LoopVectorizeHints). This will be fixed in the future when the native IR
// representation for pragma 'omp simd' is introduced.
static bool isExplicitVecOuterLoop(Loop *OuterLp,
OptimizationRemarkEmitter *ORE) {
assert(!OuterLp->isInnermost() && "This is not an outer loop");
LoopVectorizeHints Hints(OuterLp, true /*DisableInterleaving*/, *ORE);
// Only outer loops with an explicit vectorization hint are supported.
// Unannotated outer loops are ignored.
if (Hints.getForce() == LoopVectorizeHints::FK_Undefined)
return false;
Function *Fn = OuterLp->getHeader()->getParent();
if (!Hints.allowVectorization(Fn, OuterLp,
true /*VectorizeOnlyWhenForced*/)) {
LLVM_DEBUG(dbgs() << "LV: Loop hints prevent outer loop vectorization.\n");
return false;
}
if (Hints.getInterleave() > 1) {
// TODO: Interleave support is future work.
LLVM_DEBUG(dbgs() << "LV: Not vectorizing: Interleave is not supported for "
"outer loops.\n");
Hints.emitRemarkWithHints();
return false;
}
return true;
}
static void collectSupportedLoops(Loop &L, LoopInfo *LI,
OptimizationRemarkEmitter *ORE,
SmallVectorImpl<Loop *> &V) {
// Collect inner loops and outer loops without irreducible control flow. For
// now, only collect outer loops that have explicit vectorization hints. If we
// are stress testing the VPlan H-CFG construction, we collect the outermost
// loop of every loop nest.
if (L.isInnermost() || VPlanBuildStressTest ||
(EnableVPlanNativePath && isExplicitVecOuterLoop(&L, ORE))) {
LoopBlocksRPO RPOT(&L);
RPOT.perform(LI);
if (!containsIrreducibleCFG<const BasicBlock *>(RPOT, *LI)) {
V.push_back(&L);
// TODO: Collect inner loops inside marked outer loops in case
// vectorization fails for the outer loop. Do not invoke
// 'containsIrreducibleCFG' again for inner loops when the outer loop is
// already known to be reducible. We can use an inherited attribute for
// that.
return;
}
}
for (Loop *InnerL : L)
collectSupportedLoops(*InnerL, LI, ORE, V);
}
namespace {
/// The LoopVectorize Pass.
struct LoopVectorize : public FunctionPass {
/// Pass identification, replacement for typeid
static char ID;
LoopVectorizePass Impl;
explicit LoopVectorize(bool InterleaveOnlyWhenForced = false,
bool VectorizeOnlyWhenForced = false)
: FunctionPass(ID),
Impl({InterleaveOnlyWhenForced, VectorizeOnlyWhenForced}) {
initializeLoopVectorizePass(*PassRegistry::getPassRegistry());
}
bool runOnFunction(Function &F) override {
if (skipFunction(F))
return false;
auto *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
auto *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
auto *TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>();
auto *TLI = TLIP ? &TLIP->getTLI(F) : nullptr;
auto *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
auto *AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
auto *LAA = &getAnalysis<LoopAccessLegacyAnalysis>();
auto *DB = &getAnalysis<DemandedBitsWrapperPass>().getDemandedBits();
auto *ORE = &getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
auto *PSI = &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
std::function<const LoopAccessInfo &(Loop &)> GetLAA =
[&](Loop &L) -> const LoopAccessInfo & { return LAA->getInfo(&L); };
return Impl.runImpl(F, *SE, *LI, *TTI, *DT, *BFI, TLI, *DB, *AA, *AC,
GetLAA, *ORE, PSI).MadeAnyChange;
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<AssumptionCacheTracker>();
AU.addRequired<BlockFrequencyInfoWrapperPass>();
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<LoopInfoWrapperPass>();
AU.addRequired<ScalarEvolutionWrapperPass>();
AU.addRequired<TargetTransformInfoWrapperPass>();
AU.addRequired<AAResultsWrapperPass>();
AU.addRequired<LoopAccessLegacyAnalysis>();
AU.addRequired<DemandedBitsWrapperPass>();
AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
AU.addRequired<InjectTLIMappingsLegacy>();
// We currently do not preserve loopinfo/dominator analyses with outer loop
// vectorization. Until this is addressed, mark these analyses as preserved
// only for non-VPlan-native path.
// TODO: Preserve Loop and Dominator analyses for VPlan-native path.
if (!EnableVPlanNativePath) {
AU.addPreserved<LoopInfoWrapperPass>();
AU.addPreserved<DominatorTreeWrapperPass>();
}
AU.addPreserved<BasicAAWrapperPass>();
AU.addPreserved<GlobalsAAWrapperPass>();
AU.addRequired<ProfileSummaryInfoWrapperPass>();
}
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// Implementation of LoopVectorizationLegality, InnerLoopVectorizer and
// LoopVectorizationCostModel and LoopVectorizationPlanner.
//===----------------------------------------------------------------------===//
Value *InnerLoopVectorizer::getBroadcastInstrs(Value *V) {
// We need to place the broadcast of invariant variables outside the loop,
// but only if it's proven safe to do so. Else, broadcast will be inside
// vector loop body.
Instruction *Instr = dyn_cast<Instruction>(V);
bool SafeToHoist = OrigLoop->isLoopInvariant(V) &&
(!Instr ||
DT->dominates(Instr->getParent(), LoopVectorPreHeader));
// Place the code for broadcasting invariant variables in the new preheader.
IRBuilder<>::InsertPointGuard Guard(Builder);
if (SafeToHoist)
Builder.SetInsertPoint(LoopVectorPreHeader->getTerminator());
// Broadcast the scalar into all locations in the vector.
Value *Shuf = Builder.CreateVectorSplat(VF, V, "broadcast");
return Shuf;
}
/// This function adds
/// (StartIdx * Step, (StartIdx + 1) * Step, (StartIdx + 2) * Step, ...)
/// to each vector element of Val. The sequence starts at StartIndex.
/// \p Opcode is relevant for FP induction variable.
static Value *getStepVector(Value *Val, Value *StartIdx, Value *Step,
Instruction::BinaryOps BinOp, ElementCount VF,
IRBuilderBase &Builder) {
assert(VF.isVector() && "only vector VFs are supported");
// Create and check the types.
auto *ValVTy = cast<VectorType>(Val->getType());
ElementCount VLen = ValVTy->getElementCount();
Type *STy = Val->getType()->getScalarType();
assert((STy->isIntegerTy() || STy->isFloatingPointTy()) &&
"Induction Step must be an integer or FP");
assert(Step->getType() == STy && "Step has wrong type");
SmallVector<Constant *, 8> Indices;
// Create a vector of consecutive numbers from zero to VF.
VectorType *InitVecValVTy = ValVTy;
if (STy->isFloatingPointTy()) {
Type *InitVecValSTy =
IntegerType::get(STy->getContext(), STy->getScalarSizeInBits());
InitVecValVTy = VectorType::get(InitVecValSTy, VLen);
}
Value *InitVec = Builder.CreateStepVector(InitVecValVTy);
// Splat the StartIdx
Value *StartIdxSplat = Builder.CreateVectorSplat(VLen, StartIdx);
if (STy->isIntegerTy()) {
InitVec = Builder.CreateAdd(InitVec, StartIdxSplat);
Step = Builder.CreateVectorSplat(VLen, Step);
assert(Step->getType() == Val->getType() && "Invalid step vec");
// FIXME: The newly created binary instructions should contain nsw/nuw
// flags, which can be found from the original scalar operations.
Step = Builder.CreateMul(InitVec, Step);
return Builder.CreateAdd(Val, Step, "induction");
}
// Floating point induction.
assert((BinOp == Instruction::FAdd || BinOp == Instruction::FSub) &&
"Binary Opcode should be specified for FP induction");
InitVec = Builder.CreateUIToFP(InitVec, ValVTy);
InitVec = Builder.CreateFAdd(InitVec, StartIdxSplat);
Step = Builder.CreateVectorSplat(VLen, Step);
Value *MulOp = Builder.CreateFMul(InitVec, Step);
return Builder.CreateBinOp(BinOp, Val, MulOp, "induction");
}
/// Compute scalar induction steps. \p ScalarIV is the scalar induction
/// variable on which to base the steps, \p Step is the size of the step.
static void buildScalarSteps(Value *ScalarIV, Value *Step,
const InductionDescriptor &ID, VPValue *Def,
VPTransformState &State) {
IRBuilderBase &Builder = State.Builder;
// We shouldn't have to build scalar steps if we aren't vectorizing.
assert(State.VF.isVector() && "VF should be greater than one");
// Get the value type and ensure it and the step have the same integer type.
Type *ScalarIVTy = ScalarIV->getType()->getScalarType();
assert(ScalarIVTy == Step->getType() &&
"Val and Step should have the same type");
// We build scalar steps for both integer and floating-point induction
// variables. Here, we determine the kind of arithmetic we will perform.
Instruction::BinaryOps AddOp;
Instruction::BinaryOps MulOp;
if (ScalarIVTy->isIntegerTy()) {
AddOp = Instruction::Add;
MulOp = Instruction::Mul;
} else {
AddOp = ID.getInductionOpcode();
MulOp = Instruction::FMul;
}
// Determine the number of scalars we need to generate for each unroll
// iteration.
bool FirstLaneOnly = vputils::onlyFirstLaneUsed(Def);
unsigned Lanes = FirstLaneOnly ? 1 : State.VF.getKnownMinValue();
// Compute the scalar steps and save the results in State.
Type *IntStepTy = IntegerType::get(ScalarIVTy->getContext(),
ScalarIVTy->getScalarSizeInBits());
Type *VecIVTy = nullptr;
Value *UnitStepVec = nullptr, *SplatStep = nullptr, *SplatIV = nullptr;
if (!FirstLaneOnly && State.VF.isScalable()) {
VecIVTy = VectorType::get(ScalarIVTy, State.VF);
UnitStepVec =
Builder.CreateStepVector(VectorType::get(IntStepTy, State.VF));
SplatStep = Builder.CreateVectorSplat(State.VF, Step);
SplatIV = Builder.CreateVectorSplat(State.VF, ScalarIV);
}
for (unsigned Part = 0; Part < State.UF; ++Part) {
Value *StartIdx0 = createStepForVF(Builder, IntStepTy, State.VF, Part);
if (!FirstLaneOnly && State.VF.isScalable()) {
auto *SplatStartIdx = Builder.CreateVectorSplat(State.VF, StartIdx0);
auto *InitVec = Builder.CreateAdd(SplatStartIdx, UnitStepVec);
if (ScalarIVTy->isFloatingPointTy())
InitVec = Builder.CreateSIToFP(InitVec, VecIVTy);
auto *Mul = Builder.CreateBinOp(MulOp, InitVec, SplatStep);
auto *Add = Builder.CreateBinOp(AddOp, SplatIV, Mul);
State.set(Def, Add, Part);
// It's useful to record the lane values too for the known minimum number
// of elements so we do those below. This improves the code quality when
// trying to extract the first element, for example.
}
if (ScalarIVTy->isFloatingPointTy())
StartIdx0 = Builder.CreateSIToFP(StartIdx0, ScalarIVTy);
for (unsigned Lane = 0; Lane < Lanes; ++Lane) {
Value *StartIdx = Builder.CreateBinOp(
AddOp, StartIdx0, getSignedIntOrFpConstant(ScalarIVTy, Lane));
// The step returned by `createStepForVF` is a runtime-evaluated value
// when VF is scalable. Otherwise, it should be folded into a Constant.
assert((State.VF.isScalable() || isa<Constant>(StartIdx)) &&
"Expected StartIdx to be folded to a constant when VF is not "
"scalable");
auto *Mul = Builder.CreateBinOp(MulOp, StartIdx, Step);
auto *Add = Builder.CreateBinOp(AddOp, ScalarIV, Mul);
State.set(Def, Add, VPIteration(Part, Lane));
}
}
}
// Generate code for the induction step. Note that induction steps are
// required to be loop-invariant
static Value *CreateStepValue(const SCEV *Step, ScalarEvolution &SE,
Instruction *InsertBefore,
Loop *OrigLoop = nullptr) {
const DataLayout &DL = SE.getDataLayout();
assert((!OrigLoop || SE.isLoopInvariant(Step, OrigLoop)) &&
"Induction step should be loop invariant");
if (auto *E = dyn_cast<SCEVUnknown>(Step))
return E->getValue();
SCEVExpander Exp(SE, DL, "induction");
return Exp.expandCodeFor(Step, Step->getType(), InsertBefore);
}
/// Compute the transformed value of Index at offset StartValue using step
/// StepValue.
/// For integer induction, returns StartValue + Index * StepValue.
/// For pointer induction, returns StartValue[Index * StepValue].
/// FIXME: The newly created binary instructions should contain nsw/nuw
/// flags, which can be found from the original scalar operations.
static Value *emitTransformedIndex(IRBuilderBase &B, Value *Index,
Value *StartValue, Value *Step,
const InductionDescriptor &ID) {
assert(Index->getType()->getScalarType() == Step->getType() &&
"Index scalar type does not match StepValue type");
// Note: the IR at this point is broken. We cannot use SE to create any new
// SCEV and then expand it, hoping that SCEV's simplification will give us
// a more optimal code. Unfortunately, attempt of doing so on invalid IR may
// lead to various SCEV crashes. So all we can do is to use builder and rely
// on InstCombine for future simplifications. Here we handle some trivial
// cases only.
auto CreateAdd = [&B](Value *X, Value *Y) {
assert(X->getType() == Y->getType() && "Types don't match!");
if (auto *CX = dyn_cast<ConstantInt>(X))
if (CX->isZero())
return Y;
if (auto *CY = dyn_cast<ConstantInt>(Y))
if (CY->isZero())
return X;
return B.CreateAdd(X, Y);
};
// We allow X to be a vector type, in which case Y will potentially be
// splatted into a vector with the same element count.
auto CreateMul = [&B](Value *X, Value *Y) {
assert(X->getType()->getScalarType() == Y->getType() &&
"Types don't match!");
if (auto *CX = dyn_cast<ConstantInt>(X))
if (CX->isOne())
return Y;
if (auto *CY = dyn_cast<ConstantInt>(Y))
if (CY->isOne())
return X;
VectorType *XVTy = dyn_cast<VectorType>(X->getType());
if (XVTy && !isa<VectorType>(Y->getType()))
Y = B.CreateVectorSplat(XVTy->getElementCount(), Y);
return B.CreateMul(X, Y);
};
switch (ID.getKind()) {
case InductionDescriptor::IK_IntInduction: {
assert(!isa<VectorType>(Index->getType()) &&
"Vector indices not supported for integer inductions yet");
assert(Index->getType() == StartValue->getType() &&
"Index type does not match StartValue type");
if (isa<ConstantInt>(Step) && cast<ConstantInt>(Step)->isMinusOne())
return B.CreateSub(StartValue, Index);
auto *Offset = CreateMul(Index, Step);
return CreateAdd(StartValue, Offset);
}
case InductionDescriptor::IK_PtrInduction: {
assert(isa<Constant>(Step) &&
"Expected constant step for pointer induction");
return B.CreateGEP(ID.getElementType(), StartValue, CreateMul(Index, Step));
}
case InductionDescriptor::IK_FpInduction: {
assert(!isa<VectorType>(Index->getType()) &&
"Vector indices not supported for FP inductions yet");
assert(Step->getType()->isFloatingPointTy() && "Expected FP Step value");
auto InductionBinOp = ID.getInductionBinOp();
assert(InductionBinOp &&
(InductionBinOp->getOpcode() == Instruction::FAdd ||
InductionBinOp->getOpcode() == Instruction::FSub) &&
"Original bin op should be defined for FP induction");
Value *MulExp = B.CreateFMul(Step, Index);
return B.CreateBinOp(InductionBinOp->getOpcode(), StartValue, MulExp,
"induction");
}
case InductionDescriptor::IK_NoInduction:
return nullptr;
}
llvm_unreachable("invalid enum");
}
void InnerLoopVectorizer::packScalarIntoVectorValue(VPValue *Def,
const VPIteration &Instance,
VPTransformState &State) {
Value *ScalarInst = State.get(Def, Instance);
Value *VectorValue = State.get(Def, Instance.Part);
VectorValue = Builder.CreateInsertElement(
VectorValue, ScalarInst,
Instance.Lane.getAsRuntimeExpr(State.Builder, VF));
State.set(Def, VectorValue, Instance.Part);
}
// Return whether we allow using masked interleave-groups (for dealing with
// strided loads/stores that reside in predicated blocks, or for dealing
// with gaps).
static bool useMaskedInterleavedAccesses(const TargetTransformInfo &TTI) {
// If an override option has been passed in for interleaved accesses, use it.
if (EnableMaskedInterleavedMemAccesses.getNumOccurrences() > 0)
return EnableMaskedInterleavedMemAccesses;
return TTI.enableMaskedInterleavedAccessVectorization();
}
// Try to vectorize the interleave group that \p Instr belongs to.
//
// E.g. Translate following interleaved load group (factor = 3):
// for (i = 0; i < N; i+=3) {
// R = Pic[i]; // Member of index 0
// G = Pic[i+1]; // Member of index 1
// B = Pic[i+2]; // Member of index 2
// ... // do something to R, G, B
// }
// To:
// %wide.vec = load <12 x i32> ; Read 4 tuples of R,G,B
// %R.vec = shuffle %wide.vec, poison, <0, 3, 6, 9> ; R elements
// %G.vec = shuffle %wide.vec, poison, <1, 4, 7, 10> ; G elements
// %B.vec = shuffle %wide.vec, poison, <2, 5, 8, 11> ; B elements
//
// Or translate following interleaved store group (factor = 3):
// for (i = 0; i < N; i+=3) {
// ... do something to R, G, B
// Pic[i] = R; // Member of index 0
// Pic[i+1] = G; // Member of index 1
// Pic[i+2] = B; // Member of index 2
// }
// To:
// %R_G.vec = shuffle %R.vec, %G.vec, <0, 1, 2, ..., 7>
// %B_U.vec = shuffle %B.vec, poison, <0, 1, 2, 3, u, u, u, u>
// %interleaved.vec = shuffle %R_G.vec, %B_U.vec,
// <0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11> ; Interleave R,G,B elements
// store <12 x i32> %interleaved.vec ; Write 4 tuples of R,G,B
void InnerLoopVectorizer::vectorizeInterleaveGroup(
const InterleaveGroup<Instruction> *Group, ArrayRef<VPValue *> VPDefs,
VPTransformState &State, VPValue *Addr, ArrayRef<VPValue *> StoredValues,
VPValue *BlockInMask) {
Instruction *Instr = Group->getInsertPos();
const DataLayout &DL = Instr->getModule()->getDataLayout();
// Prepare for the vector type of the interleaved load/store.
Type *ScalarTy = getLoadStoreType(Instr);
unsigned InterleaveFactor = Group->getFactor();
assert(!VF.isScalable() && "scalable vectors not yet supported.");
auto *VecTy = VectorType::get(ScalarTy, VF * InterleaveFactor);
// Prepare for the new pointers.
SmallVector<Value *, 2> AddrParts;
unsigned Index = Group->getIndex(Instr);
// TODO: extend the masked interleaved-group support to reversed access.
assert((!BlockInMask || !Group->isReverse()) &&
"Reversed masked interleave-group not supported.");
// If the group is reverse, adjust the index to refer to the last vector lane
// instead of the first. We adjust the index from the first vector lane,
// rather than directly getting the pointer for lane VF - 1, because the
// pointer operand of the interleaved access is supposed to be uniform. For
// uniform instructions, we're only required to generate a value for the
// first vector lane in each unroll iteration.
if (Group->isReverse())
Index += (VF.getKnownMinValue() - 1) * Group->getFactor();
for (unsigned Part = 0; Part < UF; Part++) {
Value *AddrPart = State.get(Addr, VPIteration(Part, 0));
State.setDebugLocFromInst(AddrPart);
// Notice current instruction could be any index. Need to adjust the address
// to the member of index 0.
//
// E.g. a = A[i+1]; // Member of index 1 (Current instruction)
// b = A[i]; // Member of index 0
// Current pointer is pointed to A[i+1], adjust it to A[i].
//
// E.g. A[i+1] = a; // Member of index 1
// A[i] = b; // Member of index 0
// A[i+2] = c; // Member of index 2 (Current instruction)
// Current pointer is pointed to A[i+2], adjust it to A[i].
bool InBounds = false;
if (auto *gep = dyn_cast<GetElementPtrInst>(AddrPart->stripPointerCasts()))
InBounds = gep->isInBounds();
AddrPart = Builder.CreateGEP(ScalarTy, AddrPart, Builder.getInt32(-Index));
cast<GetElementPtrInst>(AddrPart)->setIsInBounds(InBounds);
// Cast to the vector pointer type.
unsigned AddressSpace = AddrPart->getType()->getPointerAddressSpace();
Type *PtrTy = VecTy->getPointerTo(AddressSpace);
AddrParts.push_back(Builder.CreateBitCast(AddrPart, PtrTy));
}
State.setDebugLocFromInst(Instr);
Value *PoisonVec = PoisonValue::get(VecTy);
Value *MaskForGaps = nullptr;
if (Group->requiresScalarEpilogue() && !Cost->isScalarEpilogueAllowed()) {
MaskForGaps = createBitMaskForGaps(Builder, VF.getKnownMinValue(), *Group);
assert(MaskForGaps && "Mask for Gaps is required but it is null");
}
// Vectorize the interleaved load group.
if (isa<LoadInst>(Instr)) {
// For each unroll part, create a wide load for the group.
SmallVector<Value *, 2> NewLoads;
for (unsigned Part = 0; Part < UF; Part++) {
Instruction *NewLoad;
if (BlockInMask || MaskForGaps) {
assert(useMaskedInterleavedAccesses(*TTI) &&
"masked interleaved groups are not allowed.");
Value *GroupMask = MaskForGaps;
if (BlockInMask) {
Value *BlockInMaskPart = State.get(BlockInMask, Part);
Value *ShuffledMask = Builder.CreateShuffleVector(
BlockInMaskPart,
createReplicatedMask(InterleaveFactor, VF.getKnownMinValue()),
"interleaved.mask");
GroupMask = MaskForGaps
? Builder.CreateBinOp(Instruction::And, ShuffledMask,
MaskForGaps)
: ShuffledMask;
}
NewLoad =
Builder.CreateMaskedLoad(VecTy, AddrParts[Part], Group->getAlign(),
GroupMask, PoisonVec, "wide.masked.vec");
}
else
NewLoad = Builder.CreateAlignedLoad(VecTy, AddrParts[Part],
Group->getAlign(), "wide.vec");
Group->addMetadata(NewLoad);
NewLoads.push_back(NewLoad);
}
// For each member in the group, shuffle out the appropriate data from the
// wide loads.
unsigned J = 0;
for (unsigned I = 0; I < InterleaveFactor; ++I) {
Instruction *Member = Group->getMember(I);
// Skip the gaps in the group.
if (!Member)
continue;
auto StrideMask =
createStrideMask(I, InterleaveFactor, VF.getKnownMinValue());
for (unsigned Part = 0; Part < UF; Part++) {
Value *StridedVec = Builder.CreateShuffleVector(
NewLoads[Part], StrideMask, "strided.vec");
// If this member has different type, cast the result type.
if (Member->getType() != ScalarTy) {
assert(!VF.isScalable() && "VF is assumed to be non scalable.");
VectorType *OtherVTy = VectorType::get(Member->getType(), VF);
StridedVec = createBitOrPointerCast(StridedVec, OtherVTy, DL);
}
if (Group->isReverse())
StridedVec = Builder.CreateVectorReverse(StridedVec, "reverse");
State.set(VPDefs[J], StridedVec, Part);
}
++J;
}
return;
}
// The sub vector type for current instruction.
auto *SubVT = VectorType::get(ScalarTy, VF);
// Vectorize the interleaved store group.
MaskForGaps = createBitMaskForGaps(Builder, VF.getKnownMinValue(), *Group);
assert((!MaskForGaps || useMaskedInterleavedAccesses(*TTI)) &&
"masked interleaved groups are not allowed.");
assert((!MaskForGaps || !VF.isScalable()) &&
"masking gaps for scalable vectors is not yet supported.");
for (unsigned Part = 0; Part < UF; Part++) {
// Collect the stored vector from each member.
SmallVector<Value *, 4> StoredVecs;
for (unsigned i = 0; i < InterleaveFactor; i++) {
assert((Group->getMember(i) || MaskForGaps) &&
"Fail to get a member from an interleaved store group");
Instruction *Member = Group->getMember(i);
// Skip the gaps in the group.
if (!Member) {
Value *Undef = PoisonValue::get(SubVT);
StoredVecs.push_back(Undef);
continue;
}
Value *StoredVec = State.get(StoredValues[i], Part);
if (Group->isReverse())
StoredVec = Builder.CreateVectorReverse(StoredVec, "reverse");
// If this member has different type, cast it to a unified type.
if (StoredVec->getType() != SubVT)
StoredVec = createBitOrPointerCast(StoredVec, SubVT, DL);
StoredVecs.push_back(StoredVec);
}
// Concatenate all vectors into a wide vector.
Value *WideVec = concatenateVectors(Builder, StoredVecs);
// Interleave the elements in the wide vector.
Value *IVec = Builder.CreateShuffleVector(
WideVec, createInterleaveMask(VF.getKnownMinValue(), InterleaveFactor),
"interleaved.vec");
Instruction *NewStoreInstr;
if (BlockInMask || MaskForGaps) {
Value *GroupMask = MaskForGaps;
if (BlockInMask) {
Value *BlockInMaskPart = State.get(BlockInMask, Part);
Value *ShuffledMask = Builder.CreateShuffleVector(
BlockInMaskPart,
createReplicatedMask(InterleaveFactor, VF.getKnownMinValue()),
"interleaved.mask");
GroupMask = MaskForGaps ? Builder.CreateBinOp(Instruction::And,
ShuffledMask, MaskForGaps)
: ShuffledMask;
}
NewStoreInstr = Builder.CreateMaskedStore(IVec, AddrParts[Part],
Group->getAlign(), GroupMask);
} else
NewStoreInstr =
Builder.CreateAlignedStore(IVec, AddrParts[Part], Group->getAlign());
Group->addMetadata(NewStoreInstr);
}
}
void InnerLoopVectorizer::scalarizeInstruction(Instruction *Instr,
VPReplicateRecipe *RepRecipe,
const VPIteration &Instance,
bool IfPredicateInstr,
VPTransformState &State) {
assert(!Instr->getType()->isAggregateType() && "Can't handle vectors");
// llvm.experimental.noalias.scope.decl intrinsics must only be duplicated for
// the first lane and part.
if (isa<NoAliasScopeDeclInst>(Instr))
if (!Instance.isFirstIteration())
return;
// Does this instruction return a value ?
bool IsVoidRetTy = Instr->getType()->isVoidTy();
Instruction *Cloned = Instr->clone();
if (!IsVoidRetTy)
Cloned->setName(Instr->getName() + ".cloned");
// If the scalarized instruction contributes to the address computation of a
// widen masked load/store which was in a basic block that needed predication
// and is not predicated after vectorization, we can't propagate
// poison-generating flags (nuw/nsw, exact, inbounds, etc.). The scalarized
// instruction could feed a poison value to the base address of the widen
// load/store.
if (State.MayGeneratePoisonRecipes.contains(RepRecipe))
Cloned->dropPoisonGeneratingFlags();
if (Instr->getDebugLoc())
State.setDebugLocFromInst(Instr);
// Replace the operands of the cloned instructions with their scalar
// equivalents in the new loop.
for (auto &I : enumerate(RepRecipe->operands())) {
auto InputInstance = Instance;
VPValue *Operand = I.value();
VPReplicateRecipe *OperandR = dyn_cast<VPReplicateRecipe>(Operand);
if (OperandR && OperandR->isUniform())
InputInstance.Lane = VPLane::getFirstLane();
Cloned->setOperand(I.index(), State.get(Operand, InputInstance));
}
State.addNewMetadata(Cloned, Instr);
// Place the cloned scalar in the new loop.
State.Builder.Insert(Cloned);
State.set(RepRecipe, Cloned, Instance);
// If we just cloned a new assumption, add it the assumption cache.
if (auto *II = dyn_cast<AssumeInst>(Cloned))
AC->registerAssumption(II);
// End if-block.
if (IfPredicateInstr)
PredicatedInstructions.push_back(Cloned);
}
Value *InnerLoopVectorizer::getOrCreateTripCount(BasicBlock *InsertBlock) {
if (TripCount)
return TripCount;
assert(InsertBlock);
IRBuilder<> Builder(InsertBlock->getTerminator());
// Find the loop boundaries.
ScalarEvolution *SE = PSE.getSE();
const SCEV *BackedgeTakenCount = PSE.getBackedgeTakenCount();
assert(!isa<SCEVCouldNotCompute>(BackedgeTakenCount) &&
"Invalid loop count");
Type *IdxTy = Legal->getWidestInductionType();
assert(IdxTy && "No type for induction");
// The exit count might have the type of i64 while the phi is i32. This can
// happen if we have an induction variable that is sign extended before the
// compare. The only way that we get a backedge taken count is that the
// induction variable was signed and as such will not overflow. In such a case
// truncation is legal.
if (SE->getTypeSizeInBits(BackedgeTakenCount->getType()) >
IdxTy->getPrimitiveSizeInBits())
BackedgeTakenCount = SE->getTruncateOrNoop(BackedgeTakenCount, IdxTy);
BackedgeTakenCount = SE->getNoopOrZeroExtend(BackedgeTakenCount, IdxTy);
// Get the total trip count from the count by adding 1.
const SCEV *ExitCount = SE->getAddExpr(
BackedgeTakenCount, SE->getOne(BackedgeTakenCount->getType()));
const DataLayout &DL = InsertBlock->getModule()->getDataLayout();
// Expand the trip count and place the new instructions in the preheader.
// Notice that the pre-header does not change, only the loop body.
SCEVExpander Exp(*SE, DL, "induction");
// Count holds the overall loop count (N).
TripCount = Exp.expandCodeFor(ExitCount, ExitCount->getType(),
InsertBlock->getTerminator());
if (TripCount->getType()->isPointerTy())
TripCount =
CastInst::CreatePointerCast(TripCount, IdxTy, "exitcount.ptrcnt.to.int",
InsertBlock->getTerminator());
return TripCount;
}
Value *
InnerLoopVectorizer::getOrCreateVectorTripCount(BasicBlock *InsertBlock) {
if (VectorTripCount)
return VectorTripCount;
Value *TC = getOrCreateTripCount(InsertBlock);
IRBuilder<> Builder(InsertBlock->getTerminator());
Type *Ty = TC->getType();
// This is where we can make the step a runtime constant.
Value *Step = createStepForVF(Builder, Ty, VF, UF);
// If the tail is to be folded by masking, round the number of iterations N
// up to a multiple of Step instead of rounding down. This is done by first
// adding Step-1 and then rounding down. Note that it's ok if this addition
// overflows: the vector induction variable will eventually wrap to zero given
// that it starts at zero and its Step is a power of two; the loop will then
// exit, with the last early-exit vector comparison also producing all-true.
// For scalable vectors the VF is not guaranteed to be a power of 2, but this
// is accounted for in emitIterationCountCheck that adds an overflow check.
if (Cost->foldTailByMasking()) {
assert(isPowerOf2_32(VF.getKnownMinValue() * UF) &&
"VF*UF must be a power of 2 when folding tail by masking");
Value *NumLanes = getRuntimeVF(Builder, Ty, VF * UF);
TC = Builder.CreateAdd(
TC, Builder.CreateSub(NumLanes, ConstantInt::get(Ty, 1)), "n.rnd.up");
}
// Now we need to generate the expression for the part of the loop that the
// vectorized body will execute. This is equal to N - (N % Step) if scalar
// iterations are not required for correctness, or N - Step, otherwise. Step
// is equal to the vectorization factor (number of SIMD elements) times the
// unroll factor (number of SIMD instructions).
Value *R = Builder.CreateURem(TC, Step, "n.mod.vf");
// There are cases where we *must* run at least one iteration in the remainder
// loop. See the cost model for when this can happen. If the step evenly
// divides the trip count, we set the remainder to be equal to the step. If
// the step does not evenly divide the trip count, no adjustment is necessary
// since there will already be scalar iterations. Note that the minimum
// iterations check ensures that N >= Step.
if (Cost->requiresScalarEpilogue(VF)) {
auto *IsZero = Builder.CreateICmpEQ(R, ConstantInt::get(R->getType(), 0));
R = Builder.CreateSelect(IsZero, Step, R);
}
VectorTripCount = Builder.CreateSub(TC, R, "n.vec");
return VectorTripCount;
}
Value *InnerLoopVectorizer::createBitOrPointerCast(Value *V, VectorType *DstVTy,
const DataLayout &DL) {
// Verify that V is a vector type with same number of elements as DstVTy.
auto *DstFVTy = cast<FixedVectorType>(DstVTy);
unsigned VF = DstFVTy->getNumElements();
auto *SrcVecTy = cast<FixedVectorType>(V->getType());
assert((VF == SrcVecTy->getNumElements()) && "Vector dimensions do not match");
Type *SrcElemTy = SrcVecTy->getElementType();
Type *DstElemTy = DstFVTy->getElementType();
assert((DL.getTypeSizeInBits(SrcElemTy) == DL.getTypeSizeInBits(DstElemTy)) &&
"Vector elements must have same size");
// Do a direct cast if element types are castable.
if (CastInst::isBitOrNoopPointerCastable(SrcElemTy, DstElemTy, DL)) {
return Builder.CreateBitOrPointerCast(V, DstFVTy);
}
// V cannot be directly casted to desired vector type.
// May happen when V is a floating point vector but DstVTy is a vector of
// pointers or vice-versa. Handle this using a two-step bitcast using an
// intermediate Integer type for the bitcast i.e. Ptr <-> Int <-> Float.
assert((DstElemTy->isPointerTy() != SrcElemTy->isPointerTy()) &&
"Only one type should be a pointer type");
assert((DstElemTy->isFloatingPointTy() != SrcElemTy->isFloatingPointTy()) &&
"Only one type should be a floating point type");
Type *IntTy =
IntegerType::getIntNTy(V->getContext(), DL.getTypeSizeInBits(SrcElemTy));
auto *VecIntTy = FixedVectorType::get(IntTy, VF);
Value *CastVal = Builder.CreateBitOrPointerCast(V, VecIntTy);
return Builder.CreateBitOrPointerCast(CastVal, DstFVTy);
}
void InnerLoopVectorizer::emitIterationCountCheck(BasicBlock *Bypass) {
Value *Count = getOrCreateTripCount(LoopVectorPreHeader);
// Reuse existing vector loop preheader for TC checks.
// Note that new preheader block is generated for vector loop.
BasicBlock *const TCCheckBlock = LoopVectorPreHeader;
IRBuilder<> Builder(TCCheckBlock->getTerminator());
// Generate code to check if the loop's trip count is less than VF * UF, or
// equal to it in case a scalar epilogue is required; this implies that the
// vector trip count is zero. This check also covers the case where adding one
// to the backedge-taken count overflowed leading to an incorrect trip count
// of zero. In this case we will also jump to the scalar loop.
auto P = Cost->requiresScalarEpilogue(VF) ? ICmpInst::ICMP_ULE
: ICmpInst::ICMP_ULT;
// If tail is to be folded, vector loop takes care of all iterations.
Type *CountTy = Count->getType();
Value *CheckMinIters = Builder.getFalse();
auto CreateStep = [&]() -> Value * {
// Create step with max(MinProTripCount, UF * VF).
if (UF * VF.getKnownMinValue() >= MinProfitableTripCount.getKnownMinValue())
return createStepForVF(Builder, CountTy, VF, UF);
Value *MinProfTC =
createStepForVF(Builder, CountTy, MinProfitableTripCount, 1);
if (!VF.isScalable())
return MinProfTC;
return Builder.CreateBinaryIntrinsic(
Intrinsic::umax, MinProfTC, createStepForVF(Builder, CountTy, VF, UF));
};
if (!Cost->foldTailByMasking())
CheckMinIters =
Builder.CreateICmp(P, Count, CreateStep(), "min.iters.check");
else if (VF.isScalable()) {
// vscale is not necessarily a power-of-2, which means we cannot guarantee
// an overflow to zero when updating induction variables and so an
// additional overflow check is required before entering the vector loop.
// Get the maximum unsigned value for the type.
Value *MaxUIntTripCount =
ConstantInt::get(CountTy, cast<IntegerType>(CountTy)->getMask());
Value *LHS = Builder.CreateSub(MaxUIntTripCount, Count);
// Don't execute the vector loop if (UMax - n) < (VF * UF).
CheckMinIters = Builder.CreateICmp(ICmpInst::ICMP_ULT, LHS, CreateStep());
}
// Create new preheader for vector loop.
LoopVectorPreHeader =
SplitBlock(TCCheckBlock, TCCheckBlock->getTerminator(), DT, LI, nullptr,
"vector.ph");
assert(DT->properlyDominates(DT->getNode(TCCheckBlock),
DT->getNode(Bypass)->getIDom()) &&
"TC check is expected to dominate Bypass");
// Update dominator for Bypass & LoopExit (if needed).
DT->changeImmediateDominator(Bypass, TCCheckBlock);
if (!Cost->requiresScalarEpilogue(VF))
// If there is an epilogue which must run, there's no edge from the
// middle block to exit blocks and thus no need to update the immediate
// dominator of the exit blocks.
DT->changeImmediateDominator(LoopExitBlock, TCCheckBlock);
ReplaceInstWithInst(
TCCheckBlock->getTerminator(),
BranchInst::Create(Bypass, LoopVectorPreHeader, CheckMinIters));
LoopBypassBlocks.push_back(TCCheckBlock);
}
BasicBlock *InnerLoopVectorizer::emitSCEVChecks(BasicBlock *Bypass) {
BasicBlock *const SCEVCheckBlock =
RTChecks.emitSCEVChecks(Bypass, LoopVectorPreHeader, LoopExitBlock);
if (!SCEVCheckBlock)
return nullptr;
assert(!(SCEVCheckBlock->getParent()->hasOptSize() ||
(OptForSizeBasedOnProfile &&
Cost->Hints->getForce() != LoopVectorizeHints::FK_Enabled)) &&
"Cannot SCEV check stride or overflow when optimizing for size");
// Update dominator only if this is first RT check.
if (LoopBypassBlocks.empty()) {
DT->changeImmediateDominator(Bypass, SCEVCheckBlock);
if (!Cost->requiresScalarEpilogue(VF))
// If there is an epilogue which must run, there's no edge from the
// middle block to exit blocks and thus no need to update the immediate
// dominator of the exit blocks.
DT->changeImmediateDominator(LoopExitBlock, SCEVCheckBlock);
}
LoopBypassBlocks.push_back(SCEVCheckBlock);
AddedSafetyChecks = true;
return SCEVCheckBlock;
}
BasicBlock *InnerLoopVectorizer::emitMemRuntimeChecks(BasicBlock *Bypass) {
// VPlan-native path does not do any analysis for runtime checks currently.
if (EnableVPlanNativePath)
return nullptr;
BasicBlock *const MemCheckBlock =
RTChecks.emitMemRuntimeChecks(Bypass, LoopVectorPreHeader);
// Check if we generated code that checks in runtime if arrays overlap. We put
// the checks into a separate block to make the more common case of few
// elements faster.
if (!MemCheckBlock)
return nullptr;
if (MemCheckBlock->getParent()->hasOptSize() || OptForSizeBasedOnProfile) {
assert(Cost->Hints->getForce() == LoopVectorizeHints::FK_Enabled &&
"Cannot emit memory checks when optimizing for size, unless forced "
"to vectorize.");
ORE->emit([&]() {
return OptimizationRemarkAnalysis(DEBUG_TYPE, "VectorizationCodeSize",
OrigLoop->getStartLoc(),
OrigLoop->getHeader())
<< "Code-size may be reduced by not forcing "
"vectorization, or by source-code modifications "
"eliminating the need for runtime checks "
"(e.g., adding 'restrict').";
});
}
LoopBypassBlocks.push_back(MemCheckBlock);
AddedSafetyChecks = true;
return MemCheckBlock;
}
void InnerLoopVectorizer::createVectorLoopSkeleton(StringRef Prefix) {
LoopScalarBody = OrigLoop->getHeader();
LoopVectorPreHeader = OrigLoop->getLoopPreheader();
assert(LoopVectorPreHeader && "Invalid loop structure");
LoopExitBlock = OrigLoop->getUniqueExitBlock(); // may be nullptr
assert((LoopExitBlock || Cost->requiresScalarEpilogue(VF)) &&
"multiple exit loop without required epilogue?");
LoopMiddleBlock =
SplitBlock(LoopVectorPreHeader, LoopVectorPreHeader->getTerminator(), DT,
LI, nullptr, Twine(Prefix) + "middle.block");
LoopScalarPreHeader =
SplitBlock(LoopMiddleBlock, LoopMiddleBlock->getTerminator(), DT, LI,
nullptr, Twine(Prefix) + "scalar.ph");
auto *ScalarLatchTerm = OrigLoop->getLoopLatch()->getTerminator();
// Set up the middle block terminator. Two cases:
// 1) If we know that we must execute the scalar epilogue, emit an
// unconditional branch.
// 2) Otherwise, we must have a single unique exit block (due to how we
// implement the multiple exit case). In this case, set up a conditonal
// branch from the middle block to the loop scalar preheader, and the
// exit block. completeLoopSkeleton will update the condition to use an
// iteration check, if required to decide whether to execute the remainder.
BranchInst *BrInst = Cost->requiresScalarEpilogue(VF) ?
BranchInst::Create(LoopScalarPreHeader) :
BranchInst::Create(LoopExitBlock, LoopScalarPreHeader,
Builder.getTrue());
BrInst->setDebugLoc(ScalarLatchTerm->getDebugLoc());
ReplaceInstWithInst(LoopMiddleBlock->getTerminator(), BrInst);
// Update dominator for loop exit. During skeleton creation, only the vector
// pre-header and the middle block are created. The vector loop is entirely
// created during VPlan exection.
if (!Cost->requiresScalarEpilogue(VF))
// If there is an epilogue which must run, there's no edge from the
// middle block to exit blocks and thus no need to update the immediate
// dominator of the exit blocks.
DT->changeImmediateDominator(LoopExitBlock, LoopMiddleBlock);
}
void InnerLoopVectorizer::createInductionResumeValues(
std::pair<BasicBlock *, Value *> AdditionalBypass) {
assert(((AdditionalBypass.first && AdditionalBypass.second) ||
(!AdditionalBypass.first && !AdditionalBypass.second)) &&
"Inconsistent information about additional bypass.");
Value *VectorTripCount = getOrCreateVectorTripCount(LoopVectorPreHeader);
assert(VectorTripCount && "Expected valid arguments");
// We are going to resume the execution of the scalar loop.
// Go over all of the induction variables that we found and fix the
// PHIs that are left in the scalar version of the loop.
// The starting values of PHI nodes depend on the counter of the last
// iteration in the vectorized loop.
// If we come from a bypass edge then we need to start from the original
// start value.
Instruction *OldInduction = Legal->getPrimaryInduction();
for (auto &InductionEntry : Legal->getInductionVars()) {
PHINode *OrigPhi = InductionEntry.first;
InductionDescriptor II = InductionEntry.second;
Value *&EndValue = IVEndValues[OrigPhi];
Value *EndValueFromAdditionalBypass = AdditionalBypass.second;
if (OrigPhi == OldInduction) {
// We know what the end value is.
EndValue = VectorTripCount;
} else {
IRBuilder<> B(LoopVectorPreHeader->getTerminator());
// Fast-math-flags propagate from the original induction instruction.
if (II.getInductionBinOp() && isa<FPMathOperator>(II.getInductionBinOp()))
B.setFastMathFlags(II.getInductionBinOp()->getFastMathFlags());
Type *StepType = II.getStep()->getType();
Instruction::CastOps CastOp =
CastInst::getCastOpcode(VectorTripCount, true, StepType, true);
Value *VTC = B.CreateCast(CastOp, VectorTripCount, StepType, "cast.vtc");
Value *Step =
CreateStepValue(II.getStep(), *PSE.getSE(), &*B.GetInsertPoint());
EndValue = emitTransformedIndex(B, VTC, II.getStartValue(), Step, II);
EndValue->setName("ind.end");
// Compute the end value for the additional bypass (if applicable).
if (AdditionalBypass.first) {
B.SetInsertPoint(&(*AdditionalBypass.first->getFirstInsertionPt()));
CastOp = CastInst::getCastOpcode(AdditionalBypass.second, true,
StepType, true);
Value *Step =
CreateStepValue(II.getStep(), *PSE.getSE(), &*B.GetInsertPoint());
VTC =
B.CreateCast(CastOp, AdditionalBypass.second, StepType, "cast.vtc");
EndValueFromAdditionalBypass =
emitTransformedIndex(B, VTC, II.getStartValue(), Step, II);
EndValueFromAdditionalBypass->setName("ind.end");
}
}
// Create phi nodes to merge from the backedge-taken check block.
PHINode *BCResumeVal =
PHINode::Create(OrigPhi->getType(), 3, "bc.resume.val",
LoopScalarPreHeader->getTerminator());
// Copy original phi DL over to the new one.
BCResumeVal->setDebugLoc(OrigPhi->getDebugLoc());
// The new PHI merges the original incoming value, in case of a bypass,
// or the value at the end of the vectorized loop.
BCResumeVal->addIncoming(EndValue, LoopMiddleBlock);
// Fix the scalar body counter (PHI node).
// The old induction's phi node in the scalar body needs the truncated
// value.
for (BasicBlock *BB : LoopBypassBlocks)
BCResumeVal->addIncoming(II.getStartValue(), BB);
if (AdditionalBypass.first)
BCResumeVal->setIncomingValueForBlock(AdditionalBypass.first,
EndValueFromAdditionalBypass);
OrigPhi->setIncomingValueForBlock(LoopScalarPreHeader, BCResumeVal);
}
}
BasicBlock *InnerLoopVectorizer::completeLoopSkeleton(MDNode *OrigLoopID) {
// The trip counts should be cached by now.
Value *Count = getOrCreateTripCount(LoopVectorPreHeader);
Value *VectorTripCount = getOrCreateVectorTripCount(LoopVectorPreHeader);
auto *ScalarLatchTerm = OrigLoop->getLoopLatch()->getTerminator();
// Add a check in the middle block to see if we have completed
// all of the iterations in the first vector loop. Three cases:
// 1) If we require a scalar epilogue, there is no conditional branch as
// we unconditionally branch to the scalar preheader. Do nothing.
// 2) If (N - N%VF) == N, then we *don't* need to run the remainder.
// Thus if tail is to be folded, we know we don't need to run the
// remainder and we can use the previous value for the condition (true).
// 3) Otherwise, construct a runtime check.
if (!Cost->requiresScalarEpilogue(VF) && !Cost->foldTailByMasking()) {
Instruction *CmpN = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ,
Count, VectorTripCount, "cmp.n",
LoopMiddleBlock->getTerminator());
// Here we use the same DebugLoc as the scalar loop latch terminator instead
// of the corresponding compare because they may have ended up with
// different line numbers and we want to avoid awkward line stepping while
// debugging. Eg. if the compare has got a line number inside the loop.
CmpN->setDebugLoc(ScalarLatchTerm->getDebugLoc());
cast<BranchInst>(LoopMiddleBlock->getTerminator())->setCondition(CmpN);
}
#ifdef EXPENSIVE_CHECKS
assert(DT->verify(DominatorTree::VerificationLevel::Fast));
#endif
return LoopVectorPreHeader;
}
std::pair<BasicBlock *, Value *>
InnerLoopVectorizer::createVectorizedLoopSkeleton() {
/*
In this function we generate a new loop. The new loop will contain
the vectorized instructions while the old loop will continue to run the
scalar remainder.
[ ] <-- loop iteration number check.
/ |
/ v
| [ ] <-- vector loop bypass (may consist of multiple blocks).
| / |
| / v
|| [ ] <-- vector pre header.
|/ |
| v
| [ ] \
| [ ]_| <-- vector loop (created during VPlan execution).
| |
| v
\ -[ ] <--- middle-block.
\/ |
/\ v
| ->[ ] <--- new preheader.
| |
(opt) v <-- edge from middle to exit iff epilogue is not required.
| [ ] \
| [ ]_| <-- old scalar loop to handle remainder (scalar epilogue).
\ |
\ v
>[ ] <-- exit block(s).
...
*/
// Get the metadata of the original loop before it gets modified.
MDNode *OrigLoopID = OrigLoop->getLoopID();
// Workaround! Compute the trip count of the original loop and cache it
// before we start modifying the CFG. This code has a systemic problem
// wherein it tries to run analysis over partially constructed IR; this is
// wrong, and not simply for SCEV. The trip count of the original loop
// simply happens to be prone to hitting this in practice. In theory, we
// can hit the same issue for any SCEV, or ValueTracking query done during
// mutation. See PR49900.
getOrCreateTripCount(OrigLoop->getLoopPreheader());
// Create an empty vector loop, and prepare basic blocks for the runtime
// checks.
createVectorLoopSkeleton("");
// Now, compare the new count to zero. If it is zero skip the vector loop and
// jump to the scalar loop. This check also covers the case where the
// backedge-taken count is uint##_max: adding one to it will overflow leading
// to an incorrect trip count of zero. In this (rare) case we will also jump
// to the scalar loop.
emitIterationCountCheck(LoopScalarPreHeader);
// Generate the code to check any assumptions that we've made for SCEV
// expressions.
emitSCEVChecks(LoopScalarPreHeader);
// Generate the code that checks in runtime if arrays overlap. We put the
// checks into a separate block to make the more common case of few elements
// faster.
emitMemRuntimeChecks(LoopScalarPreHeader);
// Emit phis for the new starting index of the scalar loop.
createInductionResumeValues();
return {completeLoopSkeleton(OrigLoopID), nullptr};
}
// Fix up external users of the induction variable. At this point, we are
// in LCSSA form, with all external PHIs that use the IV having one input value,
// coming from the remainder loop. We need those PHIs to also have a correct
// value for the IV when arriving directly from the middle block.
void InnerLoopVectorizer::fixupIVUsers(PHINode *OrigPhi,
const InductionDescriptor &II,
Value *VectorTripCount, Value *EndValue,
BasicBlock *MiddleBlock,
BasicBlock *VectorHeader, VPlan &Plan) {
// There are two kinds of external IV usages - those that use the value
// computed in the last iteration (the PHI) and those that use the penultimate
// value (the value that feeds into the phi from the loop latch).
// We allow both, but they, obviously, have different values.
assert(OrigLoop->getUniqueExitBlock() && "Expected a single exit block");
DenseMap<Value *, Value *> MissingVals;
// An external user of the last iteration's value should see the value that
// the remainder loop uses to initialize its own IV.
Value *PostInc = OrigPhi->getIncomingValueForBlock(OrigLoop->getLoopLatch());
for (User *U : PostInc->users()) {
Instruction *UI = cast<Instruction>(U);
if (!OrigLoop->contains(UI)) {
assert(isa<PHINode>(UI) && "Expected LCSSA form");
MissingVals[UI] = EndValue;
}
}
// An external user of the penultimate value need to see EndValue - Step.
// The simplest way to get this is to recompute it from the constituent SCEVs,
// that is Start + (Step * (CRD - 1)).
for (User *U : OrigPhi->users()) {
auto *UI = cast<Instruction>(U);
if (!OrigLoop->contains(UI)) {
assert(isa<PHINode>(UI) && "Expected LCSSA form");
IRBuilder<> B(MiddleBlock->getTerminator());
// Fast-math-flags propagate from the original induction instruction.
if (II.getInductionBinOp() && isa<FPMathOperator>(II.getInductionBinOp()))
B.setFastMathFlags(II.getInductionBinOp()->getFastMathFlags());
Value *CountMinusOne = B.CreateSub(
VectorTripCount, ConstantInt::get(VectorTripCount->getType(), 1));
Value *CMO =
!II.getStep()->getType()->isIntegerTy()
? B.CreateCast(Instruction::SIToFP, CountMinusOne,
II.getStep()->getType())
: B.CreateSExtOrTrunc(CountMinusOne, II.getStep()->getType());
CMO->setName("cast.cmo");
Value *Step = CreateStepValue(II.getStep(), *PSE.getSE(),
VectorHeader->getTerminator());
Value *Escape =
emitTransformedIndex(B, CMO, II.getStartValue(), Step, II);
Escape->setName("ind.escape");
MissingVals[UI] = Escape;
}
}
for (auto &I : MissingVals) {
PHINode *PHI = cast<PHINode>(I.first);
// One corner case we have to handle is two IVs "chasing" each-other,
// that is %IV2 = phi [...], [ %IV1, %latch ]
// In this case, if IV1 has an external use, we need to avoid adding both
// "last value of IV1" and "penultimate value of IV2". So, verify that we
// don't already have an incoming value for the middle block.
if (PHI->getBasicBlockIndex(MiddleBlock) == -1) {
PHI->addIncoming(I.second, MiddleBlock);
Plan.removeLiveOut(PHI);
}
}
}
namespace {
struct CSEDenseMapInfo {
static bool canHandle(const Instruction *I) {
return isa<InsertElementInst>(I) || isa<ExtractElementInst>(I) ||
isa<ShuffleVectorInst>(I) || isa<GetElementPtrInst>(I);
}
static inline Instruction *getEmptyKey() {
return DenseMapInfo<Instruction *>::getEmptyKey();
}
static inline Instruction *getTombstoneKey() {
return DenseMapInfo<Instruction *>::getTombstoneKey();
}
static unsigned getHashValue(const Instruction *I) {
assert(canHandle(I) && "Unknown instruction!");
return hash_combine(I->getOpcode(), hash_combine_range(I->value_op_begin(),
I->value_op_end()));
}
static bool isEqual(const Instruction *LHS, const Instruction *RHS) {
if (LHS == getEmptyKey() || RHS == getEmptyKey() ||
LHS == getTombstoneKey() || RHS == getTombstoneKey())
return LHS == RHS;
return LHS->isIdenticalTo(RHS);
}
};
} // end anonymous namespace
///Perform cse of induction variable instructions.
static void cse(BasicBlock *BB) {
// Perform simple cse.
SmallDenseMap<Instruction *, Instruction *, 4, CSEDenseMapInfo> CSEMap;
for (Instruction &In : llvm::make_early_inc_range(*BB)) {
if (!CSEDenseMapInfo::canHandle(&In))
continue;
// Check if we can replace this instruction with any of the
// visited instructions.
if (Instruction *V = CSEMap.lookup(&In)) {
In.replaceAllUsesWith(V);
In.eraseFromParent();
continue;
}
CSEMap[&In] = &In;
}
}
InstructionCost
LoopVectorizationCostModel::getVectorCallCost(CallInst *CI, ElementCount VF,
bool &NeedToScalarize) const {
Function *F = CI->getCalledFunction();
Type *ScalarRetTy = CI->getType();
SmallVector<Type *, 4> Tys, ScalarTys;
for (auto &ArgOp : CI->args())
ScalarTys.push_back(ArgOp->getType());
// Estimate cost of scalarized vector call. The source operands are assumed
// to be vectors, so we need to extract individual elements from there,
// execute VF scalar calls, and then gather the result into the vector return
// value.
InstructionCost ScalarCallCost =
TTI.getCallInstrCost(F, ScalarRetTy, ScalarTys, TTI::TCK_RecipThroughput);
if (VF.isScalar())
return ScalarCallCost;
// Compute corresponding vector type for return value and arguments.
Type *RetTy = ToVectorTy(ScalarRetTy, VF);
for (Type *ScalarTy : ScalarTys)
Tys.push_back(ToVectorTy(ScalarTy, VF));
// Compute costs of unpacking argument values for the scalar calls and
// packing the return values to a vector.
InstructionCost ScalarizationCost = getScalarizationOverhead(CI, VF);
InstructionCost Cost =
ScalarCallCost * VF.getKnownMinValue() + ScalarizationCost;
// If we can't emit a vector call for this function, then the currently found
// cost is the cost we need to return.
NeedToScalarize = true;
VFShape Shape = VFShape::get(*CI, VF, false /*HasGlobalPred*/);
Function *VecFunc = VFDatabase(*CI).getVectorizedFunction(Shape);
if (!TLI || CI->isNoBuiltin() || !VecFunc)
return Cost;
// If the corresponding vector cost is cheaper, return its cost.
InstructionCost VectorCallCost =
TTI.getCallInstrCost(nullptr, RetTy, Tys, TTI::TCK_RecipThroughput);
if (VectorCallCost < Cost) {
NeedToScalarize = false;
Cost = VectorCallCost;
}
return Cost;
}
static Type *MaybeVectorizeType(Type *Elt, ElementCount VF) {
if (VF.isScalar() || (!Elt->isIntOrPtrTy() && !Elt->isFloatingPointTy()))
return Elt;
return VectorType::get(Elt, VF);
}
InstructionCost
LoopVectorizationCostModel::getVectorIntrinsicCost(CallInst *CI,
ElementCount VF) const {
Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI);
assert(ID && "Expected intrinsic call!");
Type *RetTy = MaybeVectorizeType(CI->getType(), VF);
FastMathFlags FMF;
if (auto *FPMO = dyn_cast<FPMathOperator>(CI))
FMF = FPMO->getFastMathFlags();
SmallVector<const Value *> Arguments(CI->args());
FunctionType *FTy = CI->getCalledFunction()->getFunctionType();
SmallVector<Type *> ParamTys;
std::transform(FTy->param_begin(), FTy->param_end(),
std::back_inserter(ParamTys),
[&](Type *Ty) { return MaybeVectorizeType(Ty, VF); });
IntrinsicCostAttributes CostAttrs(ID, RetTy, Arguments, ParamTys, FMF,
dyn_cast<IntrinsicInst>(CI));
return TTI.getIntrinsicInstrCost(CostAttrs,
TargetTransformInfo::TCK_RecipThroughput);
}
static Type *smallestIntegerVectorType(Type *T1, Type *T2) {
auto *I1 = cast<IntegerType>(cast<VectorType>(T1)->getElementType());
auto *I2 = cast<IntegerType>(cast<VectorType>(T2)->getElementType());
return I1->getBitWidth() < I2->getBitWidth() ? T1 : T2;
}
static Type *largestIntegerVectorType(Type *T1, Type *T2) {
auto *I1 = cast<IntegerType>(cast<VectorType>(T1)->getElementType());
auto *I2 = cast<IntegerType>(cast<VectorType>(T2)->getElementType());
return I1->getBitWidth() > I2->getBitWidth() ? T1 : T2;
}
void InnerLoopVectorizer::truncateToMinimalBitwidths(VPTransformState &State) {
// For every instruction `I` in MinBWs, truncate the operands, create a
// truncated version of `I` and reextend its result. InstCombine runs
// later and will remove any ext/trunc pairs.
SmallPtrSet<Value *, 4> Erased;
for (const auto &KV : Cost->getMinimalBitwidths()) {
// If the value wasn't vectorized, we must maintain the original scalar
// type. The absence of the value from State indicates that it
// wasn't vectorized.
// FIXME: Should not rely on getVPValue at this point.
VPValue *Def = State.Plan->getVPValue(KV.first, true);
if (!State.hasAnyVectorValue(Def))
continue;
for (unsigned Part = 0; Part < UF; ++Part) {
Value *I = State.get(Def, Part);
if (Erased.count(I) || I->use_empty() || !isa<Instruction>(I))
continue;
Type *OriginalTy = I->getType();
Type *ScalarTruncatedTy =
IntegerType::get(OriginalTy->getContext(), KV.second);
auto *TruncatedTy = VectorType::get(
ScalarTruncatedTy, cast<VectorType>(OriginalTy)->getElementCount());
if (TruncatedTy == OriginalTy)
continue;
IRBuilder<> B(cast<Instruction>(I));
auto ShrinkOperand = [&](Value *V) -> Value * {
if (auto *ZI = dyn_cast<ZExtInst>(V))
if (ZI->getSrcTy() == TruncatedTy)
return ZI->getOperand(0);
return B.CreateZExtOrTrunc(V, TruncatedTy);
};
// The actual instruction modification depends on the instruction type,
// unfortunately.
Value *NewI = nullptr;
if (auto *BO = dyn_cast<BinaryOperator>(I)) {
NewI = B.CreateBinOp(BO->getOpcode(), ShrinkOperand(BO->getOperand(0)),
ShrinkOperand(BO->getOperand(1)));
// Any wrapping introduced by shrinking this operation shouldn't be
// considered undefined behavior. So, we can't unconditionally copy
// arithmetic wrapping flags to NewI.
cast<BinaryOperator>(NewI)->copyIRFlags(I, /*IncludeWrapFlags=*/false);
} else if (auto *CI = dyn_cast<ICmpInst>(I)) {
NewI =
B.CreateICmp(CI->getPredicate(), ShrinkOperand(CI->getOperand(0)),
ShrinkOperand(CI->getOperand(1)));
} else if (auto *SI = dyn_cast<SelectInst>(I)) {
NewI = B.CreateSelect(SI->getCondition(),
ShrinkOperand(SI->getTrueValue()),
ShrinkOperand(SI->getFalseValue()));
} else if (auto *CI = dyn_cast<CastInst>(I)) {
switch (CI->getOpcode()) {
default:
llvm_unreachable("Unhandled cast!");
case Instruction::Trunc:
NewI = ShrinkOperand(CI->getOperand(0));
break;
case Instruction::SExt:
NewI = B.CreateSExtOrTrunc(
CI->getOperand(0),
smallestIntegerVectorType(OriginalTy, TruncatedTy));
break;
case Instruction::ZExt:
NewI = B.CreateZExtOrTrunc(
CI->getOperand(0),
smallestIntegerVectorType(OriginalTy, TruncatedTy));
break;
}
} else if (auto *SI = dyn_cast<ShuffleVectorInst>(I)) {
auto Elements0 =
cast<VectorType>(SI->getOperand(0)->getType())->getElementCount();
auto *O0 = B.CreateZExtOrTrunc(
SI->getOperand(0), VectorType::get(ScalarTruncatedTy, Elements0));
auto Elements1 =
cast<VectorType>(SI->getOperand(1)->getType())->getElementCount();
auto *O1 = B.CreateZExtOrTrunc(
SI->getOperand(1), VectorType::get(ScalarTruncatedTy, Elements1));
NewI = B.CreateShuffleVector(O0, O1, SI->getShuffleMask());
} else if (isa<LoadInst>(I) || isa<PHINode>(I)) {
// Don't do anything with the operands, just extend the result.
continue;
} else if (auto *IE = dyn_cast<InsertElementInst>(I)) {
auto Elements =
cast<VectorType>(IE->getOperand(0)->getType())->getElementCount();
auto *O0 = B.CreateZExtOrTrunc(
IE->getOperand(0), VectorType::get(ScalarTruncatedTy, Elements));
auto *O1 = B.CreateZExtOrTrunc(IE->getOperand(1), ScalarTruncatedTy);
NewI = B.CreateInsertElement(O0, O1, IE->getOperand(2));
} else if (auto *EE = dyn_cast<ExtractElementInst>(I)) {
auto Elements =
cast<VectorType>(EE->getOperand(0)->getType())->getElementCount();
auto *O0 = B.CreateZExtOrTrunc(
EE->getOperand(0), VectorType::get(ScalarTruncatedTy, Elements));
NewI = B.CreateExtractElement(O0, EE->getOperand(2));
} else {
// If we don't know what to do, be conservative and don't do anything.
continue;
}
// Lastly, extend the result.
NewI->takeName(cast<Instruction>(I));
Value *Res = B.CreateZExtOrTrunc(NewI, OriginalTy);
I->replaceAllUsesWith(Res);
cast<Instruction>(I)->eraseFromParent();
Erased.insert(I);
State.reset(Def, Res, Part);
}
}
// We'll have created a bunch of ZExts that are now parentless. Clean up.
for (const auto &KV : Cost->getMinimalBitwidths()) {
// If the value wasn't vectorized, we must maintain the original scalar
// type. The absence of the value from State indicates that it
// wasn't vectorized.
// FIXME: Should not rely on getVPValue at this point.
VPValue *Def = State.Plan->getVPValue(KV.first, true);
if (!State.hasAnyVectorValue(Def))
continue;
for (unsigned Part = 0; Part < UF; ++Part) {
Value *I = State.get(Def, Part);
ZExtInst *Inst = dyn_cast<ZExtInst>(I);
if (Inst && Inst->use_empty()) {
Value *NewI = Inst->getOperand(0);
Inst->eraseFromParent();
State.reset(Def, NewI, Part);
}
}
}
}
void InnerLoopVectorizer::fixVectorizedLoop(VPTransformState &State,
VPlan &Plan) {
// Insert truncates and extends for any truncated instructions as hints to
// InstCombine.
if (VF.isVector())
truncateToMinimalBitwidths(State);
// Fix widened non-induction PHIs by setting up the PHI operands.
if (EnableVPlanNativePath)
fixNonInductionPHIs(Plan, State);
// At this point every instruction in the original loop is widened to a
// vector form. Now we need to fix the recurrences in the loop. These PHI
// nodes are currently empty because we did not want to introduce cycles.
// This is the second stage of vectorizing recurrences.
fixCrossIterationPHIs(State);
// Forget the original basic block.
PSE.getSE()->forgetLoop(OrigLoop);
VPBasicBlock *LatchVPBB = Plan.getVectorLoopRegion()->getExitingBasicBlock();
Loop *VectorLoop = LI->getLoopFor(State.CFG.VPBB2IRBB[LatchVPBB]);
if (Cost->requiresScalarEpilogue(VF)) {
// No edge from the middle block to the unique exit block has been inserted
// and there is nothing to fix from vector loop; phis should have incoming
// from scalar loop only.
Plan.clearLiveOuts();
} else {
// If we inserted an edge from the middle block to the unique exit block,
// update uses outside the loop (phis) to account for the newly inserted
// edge.
// Fix-up external users of the induction variables.
for (auto &Entry : Legal->getInductionVars())
fixupIVUsers(Entry.first, Entry.second,
getOrCreateVectorTripCount(VectorLoop->getLoopPreheader()),
IVEndValues[Entry.first], LoopMiddleBlock,
VectorLoop->getHeader(), Plan);
}
// Fix LCSSA phis not already fixed earlier. Extracts may need to be generated
// in the exit block, so update the builder.
State.Builder.SetInsertPoint(State.CFG.ExitBB->getFirstNonPHI());
for (auto &KV : Plan.getLiveOuts())
KV.second->fixPhi(Plan, State);
for (Instruction *PI : PredicatedInstructions)
sinkScalarOperands(&*PI);
// Remove redundant induction instructions.
cse(VectorLoop->getHeader());
// Set/update profile weights for the vector and remainder loops as original
// loop iterations are now distributed among them. Note that original loop
// represented by LoopScalarBody becomes remainder loop after vectorization.
//
// For cases like foldTailByMasking() and requiresScalarEpiloque() we may
// end up getting slightly roughened result but that should be OK since
// profile is not inherently precise anyway. Note also possible bypass of
// vector code caused by legality checks is ignored, assigning all the weight
// to the vector loop, optimistically.
//
// For scalable vectorization we can't know at compile time how many iterations
// of the loop are handled in one vector iteration, so instead assume a pessimistic
// vscale of '1'.
setProfileInfoAfterUnrolling(LI->getLoopFor(LoopScalarBody), VectorLoop,
LI->getLoopFor(LoopScalarBody),
VF.getKnownMinValue() * UF);
}
void InnerLoopVectorizer::fixCrossIterationPHIs(VPTransformState &State) {
// In order to support recurrences we need to be able to vectorize Phi nodes.
// Phi nodes have cycles, so we need to vectorize them in two stages. This is
// stage #2: We now need to fix the recurrences by adding incoming edges to
// the currently empty PHI nodes. At this point every instruction in the
// original loop is widened to a vector form so we can use them to construct
// the incoming edges.
VPBasicBlock *Header =
State.Plan->getVectorLoopRegion()->getEntryBasicBlock();
for (VPRecipeBase &R : Header->phis()) {
if (auto *ReductionPhi = dyn_cast<VPReductionPHIRecipe>(&R))
fixReduction(ReductionPhi, State);
else if (auto *FOR = dyn_cast<VPFirstOrderRecurrencePHIRecipe>(&R))
fixFirstOrderRecurrence(FOR, State);
}
}
void InnerLoopVectorizer::fixFirstOrderRecurrence(
VPFirstOrderRecurrencePHIRecipe *PhiR, VPTransformState &State) {
// This is the second phase of vectorizing first-order recurrences. An
// overview of the transformation is described below. Suppose we have the
// following loop.
//
// for (int i = 0; i < n; ++i)
// b[i] = a[i] - a[i - 1];
//
// There is a first-order recurrence on "a". For this loop, the shorthand
// scalar IR looks like:
//
// scalar.ph:
// s_init = a[-1]
// br scalar.body
//
// scalar.body:
// i = phi [0, scalar.ph], [i+1, scalar.body]
// s1 = phi [s_init, scalar.ph], [s2, scalar.body]
// s2 = a[i]
// b[i] = s2 - s1
// br cond, scalar.body, ...
//
// In this example, s1 is a recurrence because it's value depends on the
// previous iteration. In the first phase of vectorization, we created a
// vector phi v1 for s1. We now complete the vectorization and produce the
// shorthand vector IR shown below (for VF = 4, UF = 1).
//
// vector.ph:
// v_init = vector(..., ..., ..., a[-1])
// br vector.body
//
// vector.body
// i = phi [0, vector.ph], [i+4, vector.body]
// v1 = phi [v_init, vector.ph], [v2, vector.body]
// v2 = a[i, i+1, i+2, i+3];
// v3 = vector(v1(3), v2(0, 1, 2))
// b[i, i+1, i+2, i+3] = v2 - v3
// br cond, vector.body, middle.block
//
// middle.block:
// x = v2(3)
// br scalar.ph
//
// scalar.ph:
// s_init = phi [x, middle.block], [a[-1], otherwise]
// br scalar.body
//
// After execution completes the vector loop, we extract the next value of
// the recurrence (x) to use as the initial value in the scalar loop.
// Extract the last vector element in the middle block. This will be the
// initial value for the recurrence when jumping to the scalar loop.
VPValue *PreviousDef = PhiR->getBackedgeValue();
Value *Incoming = State.get(PreviousDef, UF - 1);
auto *ExtractForScalar = Incoming;
auto *IdxTy = Builder.getInt32Ty();
if (VF.isVector()) {
auto *One = ConstantInt::get(IdxTy, 1);
Builder.SetInsertPoint(LoopMiddleBlock->getTerminator());
auto *RuntimeVF = getRuntimeVF(Builder, IdxTy, VF);
auto *LastIdx = Builder.CreateSub(RuntimeVF, One);
ExtractForScalar = Builder.CreateExtractElement(ExtractForScalar, LastIdx,
"vector.recur.extract");
}
// Extract the second last element in the middle block if the
// Phi is used outside the loop. We need to extract the phi itself
// and not the last element (the phi update in the current iteration). This
// will be the value when jumping to the exit block from the LoopMiddleBlock,
// when the scalar loop is not run at all.
Value *ExtractForPhiUsedOutsideLoop = nullptr;
if (VF.isVector()) {
auto *RuntimeVF = getRuntimeVF(Builder, IdxTy, VF);
auto *Idx = Builder.CreateSub(RuntimeVF, ConstantInt::get(IdxTy, 2));
ExtractForPhiUsedOutsideLoop = Builder.CreateExtractElement(
Incoming, Idx, "vector.recur.extract.for.phi");
} else if (UF > 1)
// When loop is unrolled without vectorizing, initialize
// ExtractForPhiUsedOutsideLoop with the value just prior to unrolled value
// of `Incoming`. This is analogous to the vectorized case above: extracting
// the second last element when VF > 1.
ExtractForPhiUsedOutsideLoop = State.get(PreviousDef, UF - 2);
// Fix the initial value of the original recurrence in the scalar loop.
Builder.SetInsertPoint(&*LoopScalarPreHeader->begin());
PHINode *Phi = cast<PHINode>(PhiR->getUnderlyingValue());
auto *Start = Builder.CreatePHI(Phi->getType(), 2, "scalar.recur.init");
auto *ScalarInit = PhiR->getStartValue()->getLiveInIRValue();
for (auto *BB : predecessors(LoopScalarPreHeader)) {
auto *Incoming = BB == LoopMiddleBlock ? ExtractForScalar : ScalarInit;
Start->addIncoming(Incoming, BB);
}
Phi->setIncomingValueForBlock(LoopScalarPreHeader, Start);
Phi->setName("scalar.recur");
// Finally, fix users of the recurrence outside the loop. The users will need
// either the last value of the scalar recurrence or the last value of the
// vector recurrence we extracted in the middle block. Since the loop is in
// LCSSA form, we just need to find all the phi nodes for the original scalar
// recurrence in the exit block, and then add an edge for the middle block.
// Note that LCSSA does not imply single entry when the original scalar loop
// had multiple exiting edges (as we always run the last iteration in the
// scalar epilogue); in that case, there is no edge from middle to exit and
// and thus no phis which needed updated.
if (!Cost->requiresScalarEpilogue(VF))
for (PHINode &LCSSAPhi : LoopExitBlock->phis())
if (llvm::is_contained(LCSSAPhi.incoming_values(), Phi)) {
LCSSAPhi.addIncoming(ExtractForPhiUsedOutsideLoop, LoopMiddleBlock);
State.Plan->removeLiveOut(&LCSSAPhi);
}
}
void InnerLoopVectorizer::fixReduction(VPReductionPHIRecipe *PhiR,
VPTransformState &State) {
PHINode *OrigPhi = cast<PHINode>(PhiR->getUnderlyingValue());
// Get it's reduction variable descriptor.
assert(Legal->isReductionVariable(OrigPhi) &&
"Unable to find the reduction variable");
const RecurrenceDescriptor &RdxDesc = PhiR->getRecurrenceDescriptor();
RecurKind RK = RdxDesc.getRecurrenceKind();
TrackingVH<Value> ReductionStartValue = RdxDesc.getRecurrenceStartValue();
Instruction *LoopExitInst = RdxDesc.getLoopExitInstr();
State.setDebugLocFromInst(ReductionStartValue);
VPValue *LoopExitInstDef = PhiR->getBackedgeValue();
// This is the vector-clone of the value that leaves the loop.
Type *VecTy = State.get(LoopExitInstDef, 0)->getType();
// Wrap flags are in general invalid after vectorization, clear them.
clearReductionWrapFlags(PhiR, State);
// Before each round, move the insertion point right between
// the PHIs and the values we are going to write.
// This allows us to write both PHINodes and the extractelement
// instructions.
Builder.SetInsertPoint(&*LoopMiddleBlock->getFirstInsertionPt());
State.setDebugLocFromInst(LoopExitInst);
Type *PhiTy = OrigPhi->getType();
VPBasicBlock *LatchVPBB =
PhiR->getParent()->getEnclosingLoopRegion()->getExitingBasicBlock();
BasicBlock *VectorLoopLatch = State.CFG.VPBB2IRBB[LatchVPBB];
// If tail is folded by masking, the vector value to leave the loop should be
// a Select choosing between the vectorized LoopExitInst and vectorized Phi,
// instead of the former. For an inloop reduction the reduction will already
// be predicated, and does not need to be handled here.
if (Cost->foldTailByMasking() && !PhiR->isInLoop()) {
for (unsigned Part = 0; Part < UF; ++Part) {
Value *VecLoopExitInst = State.get(LoopExitInstDef, Part);
SelectInst *Sel = nullptr;
for (User *U : VecLoopExitInst->users()) {
if (isa<SelectInst>(U)) {
assert(!Sel && "Reduction exit feeding two selects");
Sel = cast<SelectInst>(U);
} else
assert(isa<PHINode>(U) && "Reduction exit must feed Phi's or select");
}
assert(Sel && "Reduction exit feeds no select");
State.reset(LoopExitInstDef, Sel, Part);
if (isa<FPMathOperator>(Sel))
Sel->setFastMathFlags(RdxDesc.getFastMathFlags());
// If the target can create a predicated operator for the reduction at no
// extra cost in the loop (for example a predicated vadd), it can be
// cheaper for the select to remain in the loop than be sunk out of it,
// and so use the select value for the phi instead of the old
// LoopExitValue.
if (PreferPredicatedReductionSelect ||
TTI->preferPredicatedReductionSelect(
RdxDesc.getOpcode(), PhiTy,
TargetTransformInfo::ReductionFlags())) {
auto *VecRdxPhi =
cast<PHINode>(State.get(PhiR, Part));
VecRdxPhi->setIncomingValueForBlock(VectorLoopLatch, Sel);
}
}
}
// If the vector reduction can be performed in a smaller type, we truncate
// then extend the loop exit value to enable InstCombine to evaluate the
// entire expression in the smaller type.
if (VF.isVector() && PhiTy != RdxDesc.getRecurrenceType()) {
assert(!PhiR->isInLoop() && "Unexpected truncated inloop reduction!");
Type *RdxVecTy = VectorType::get(RdxDesc.getRecurrenceType(), VF);
Builder.SetInsertPoint(VectorLoopLatch->getTerminator());
VectorParts RdxParts(UF);
for (unsigned Part = 0; Part < UF; ++Part) {
RdxParts[Part] = State.get(LoopExitInstDef, Part);
Value *Trunc = Builder.CreateTrunc(RdxParts[Part], RdxVecTy);
Value *Extnd = RdxDesc.isSigned() ? Builder.CreateSExt(Trunc, VecTy)
: Builder.CreateZExt(Trunc, VecTy);
for (User *U : llvm::make_early_inc_range(RdxParts[Part]->users()))
if (U != Trunc) {
U->replaceUsesOfWith(RdxParts[Part], Extnd);
RdxParts[Part] = Extnd;
}
}
Builder.SetInsertPoint(&*LoopMiddleBlock->getFirstInsertionPt());
for (unsigned Part = 0; Part < UF; ++Part) {
RdxParts[Part] = Builder.CreateTrunc(RdxParts[Part], RdxVecTy);
State.reset(LoopExitInstDef, RdxParts[Part], Part);
}
}
// Reduce all of the unrolled parts into a single vector.
Value *ReducedPartRdx = State.get(LoopExitInstDef, 0);
unsigned Op = RecurrenceDescriptor::getOpcode(RK);
// The middle block terminator has already been assigned a DebugLoc here (the
// OrigLoop's single latch terminator). We want the whole middle block to
// appear to execute on this line because: (a) it is all compiler generated,
// (b) these instructions are always executed after evaluating the latch
// conditional branch, and (c) other passes may add new predecessors which
// terminate on this line. This is the easiest way to ensure we don't
// accidentally cause an extra step back into the loop while debugging.
State.setDebugLocFromInst(LoopMiddleBlock->getTerminator());
if (PhiR->isOrdered())
ReducedPartRdx = State.get(LoopExitInstDef, UF - 1);
else {
// Floating-point operations should have some FMF to enable the reduction.
IRBuilderBase::FastMathFlagGuard FMFG(Builder);
Builder.setFastMathFlags(RdxDesc.getFastMathFlags());
for (unsigned Part = 1; Part < UF; ++Part) {
Value *RdxPart = State.get(LoopExitInstDef, Part);
if (Op != Instruction::ICmp && Op != Instruction::FCmp) {
ReducedPartRdx = Builder.CreateBinOp(
(Instruction::BinaryOps)Op, RdxPart, ReducedPartRdx, "bin.rdx");
} else if (RecurrenceDescriptor::isSelectCmpRecurrenceKind(RK))
ReducedPartRdx = createSelectCmpOp(Builder, ReductionStartValue, RK,
ReducedPartRdx, RdxPart);
else
ReducedPartRdx = createMinMaxOp(Builder, RK, ReducedPartRdx, RdxPart);
}
}
// Create the reduction after the loop. Note that inloop reductions create the
// target reduction in the loop using a Reduction recipe.
if (VF.isVector() && !PhiR->isInLoop()) {
ReducedPartRdx =
createTargetReduction(Builder, TTI, RdxDesc, ReducedPartRdx, OrigPhi);
// If the reduction can be performed in a smaller type, we need to extend
// the reduction to the wider type before we branch to the original loop.
if (PhiTy != RdxDesc.getRecurrenceType())
ReducedPartRdx = RdxDesc.isSigned()
? Builder.CreateSExt(ReducedPartRdx, PhiTy)
: Builder.CreateZExt(ReducedPartRdx, PhiTy);
}
PHINode *ResumePhi =
dyn_cast<PHINode>(PhiR->getStartValue()->getUnderlyingValue());
// Create a phi node that merges control-flow from the backedge-taken check
// block and the middle block.
PHINode *BCBlockPhi = PHINode::Create(PhiTy, 2, "bc.merge.rdx",
LoopScalarPreHeader->getTerminator());
// If we are fixing reductions in the epilogue loop then we should already
// have created a bc.merge.rdx Phi after the main vector body. Ensure that
// we carry over the incoming values correctly.
for (auto *Incoming : predecessors(LoopScalarPreHeader)) {
if (Incoming == LoopMiddleBlock)
BCBlockPhi->addIncoming(ReducedPartRdx, Incoming);
else if (ResumePhi && llvm::is_contained(ResumePhi->blocks(), Incoming))
BCBlockPhi->addIncoming(ResumePhi->getIncomingValueForBlock(Incoming),
Incoming);
else
BCBlockPhi->addIncoming(ReductionStartValue, Incoming);
}
// Set the resume value for this reduction
ReductionResumeValues.insert({&RdxDesc, BCBlockPhi});
// If there were stores of the reduction value to a uniform memory address
// inside the loop, create the final store here.
if (StoreInst *SI = RdxDesc.IntermediateStore) {
StoreInst *NewSI =
Builder.CreateStore(ReducedPartRdx, SI->getPointerOperand());
propagateMetadata(NewSI, SI);
// If the reduction value is used in other places,
// then let the code below create PHI's for that.
}
// Now, we need to fix the users of the reduction variable
// inside and outside of the scalar remainder loop.
// We know that the loop is in LCSSA form. We need to update the PHI nodes
// in the exit blocks. See comment on analogous loop in
// fixFirstOrderRecurrence for a more complete explaination of the logic.
if (!Cost->requiresScalarEpilogue(VF))
for (PHINode &LCSSAPhi : LoopExitBlock->phis())
if (llvm::is_contained(LCSSAPhi.incoming_values(), LoopExitInst)) {
LCSSAPhi.addIncoming(ReducedPartRdx, LoopMiddleBlock);
State.Plan->removeLiveOut(&LCSSAPhi);
}
// Fix the scalar loop reduction variable with the incoming reduction sum
// from the vector body and from the backedge value.
int IncomingEdgeBlockIdx =
OrigPhi->getBasicBlockIndex(OrigLoop->getLoopLatch());
assert(IncomingEdgeBlockIdx >= 0 && "Invalid block index");
// Pick the other block.
int SelfEdgeBlockIdx = (IncomingEdgeBlockIdx ? 0 : 1);
OrigPhi->setIncomingValue(SelfEdgeBlockIdx, BCBlockPhi);
OrigPhi->setIncomingValue(IncomingEdgeBlockIdx, LoopExitInst);
}
void InnerLoopVectorizer::clearReductionWrapFlags(VPReductionPHIRecipe *PhiR,
VPTransformState &State) {
const RecurrenceDescriptor &RdxDesc = PhiR->getRecurrenceDescriptor();
RecurKind RK = RdxDesc.getRecurrenceKind();
if (RK != RecurKind::Add && RK != RecurKind::Mul)
return;
SmallVector<VPValue *, 8> Worklist;
SmallPtrSet<VPValue *, 8> Visited;
Worklist.push_back(PhiR);
Visited.insert(PhiR);
while (!Worklist.empty()) {
VPValue *Cur = Worklist.pop_back_val();
for (unsigned Part = 0; Part < UF; ++Part) {
Value *V = State.get(Cur, Part);
if (!isa<OverflowingBinaryOperator>(V))
break;
cast<Instruction>(V)->dropPoisonGeneratingFlags();
}
for (VPUser *U : Cur->users()) {
auto *UserRecipe = dyn_cast<VPRecipeBase>(U);
if (!UserRecipe)
continue;
for (VPValue *V : UserRecipe->definedValues())
if (Visited.insert(V).second)
Worklist.push_back(V);
}
}
}
void InnerLoopVectorizer::sinkScalarOperands(Instruction *PredInst) {
// The basic block and loop containing the predicated instruction.
auto *PredBB = PredInst->getParent();
auto *VectorLoop = LI->getLoopFor(PredBB);
// Initialize a worklist with the operands of the predicated instruction.
SetVector<Value *> Worklist(PredInst->op_begin(), PredInst->op_end());
// Holds instructions that we need to analyze again. An instruction may be
// reanalyzed if we don't yet know if we can sink it or not.
SmallVector<Instruction *, 8> InstsToReanalyze;
// Returns true if a given use occurs in the predicated block. Phi nodes use
// their operands in their corresponding predecessor blocks.
auto isBlockOfUsePredicated = [&](Use &U) -> bool {
auto *I = cast<Instruction>(U.getUser());
BasicBlock *BB = I->getParent();
if (auto *Phi = dyn_cast<PHINode>(I))
BB = Phi->getIncomingBlock(
PHINode::getIncomingValueNumForOperand(U.getOperandNo()));
return BB == PredBB;
};
// Iteratively sink the scalarized operands of the predicated instruction
// into the block we created for it. When an instruction is sunk, it's
// operands are then added to the worklist. The algorithm ends after one pass
// through the worklist doesn't sink a single instruction.
bool Changed;
do {
// Add the instructions that need to be reanalyzed to the worklist, and
// reset the changed indicator.
Worklist.insert(InstsToReanalyze.begin(), InstsToReanalyze.end());
InstsToReanalyze.clear();
Changed = false;
while (!Worklist.empty()) {
auto *I = dyn_cast<Instruction>(Worklist.pop_back_val());
// We can't sink an instruction if it is a phi node, is not in the loop,
// or may have side effects.
if (!I || isa<PHINode>(I) || !VectorLoop->contains(I) ||
I->mayHaveSideEffects())
continue;
// If the instruction is already in PredBB, check if we can sink its
// operands. In that case, VPlan's sinkScalarOperands() succeeded in
// sinking the scalar instruction I, hence it appears in PredBB; but it
// may have failed to sink I's operands (recursively), which we try
// (again) here.
if (I->getParent() == PredBB) {
Worklist.insert(I->op_begin(), I->op_end());
continue;
}
// It's legal to sink the instruction if all its uses occur in the
// predicated block. Otherwise, there's nothing to do yet, and we may
// need to reanalyze the instruction.
if (!llvm::all_of(I->uses(), isBlockOfUsePredicated)) {
InstsToReanalyze.push_back(I);
continue;
}
// Move the instruction to the beginning of the predicated block, and add
// it's operands to the worklist.
I->moveBefore(&*PredBB->getFirstInsertionPt());
Worklist.insert(I->op_begin(), I->op_end());
// The sinking may have enabled other instructions to be sunk, so we will
// need to iterate.
Changed = true;
}
} while (Changed);
}
void InnerLoopVectorizer::fixNonInductionPHIs(VPlan &Plan,
VPTransformState &State) {
auto Iter = depth_first(
VPBlockRecursiveTraversalWrapper<VPBlockBase *>(Plan.getEntry()));
for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(Iter)) {
for (VPRecipeBase &P : VPBB->phis()) {
VPWidenPHIRecipe *VPPhi = dyn_cast<VPWidenPHIRecipe>(&P);
if (!VPPhi)
continue;
PHINode *NewPhi = cast<PHINode>(State.get(VPPhi, 0));
// Make sure the builder has a valid insert point.
Builder.SetInsertPoint(NewPhi);
for (unsigned i = 0; i < VPPhi->getNumOperands(); ++i) {
VPValue *Inc = VPPhi->getIncomingValue(i);
VPBasicBlock *VPBB = VPPhi->getIncomingBlock(i);
NewPhi->addIncoming(State.get(Inc, 0), State.CFG.VPBB2IRBB[VPBB]);
}
}
}
}
bool InnerLoopVectorizer::useOrderedReductions(
const RecurrenceDescriptor &RdxDesc) {
return Cost->useOrderedReductions(RdxDesc);
}
void InnerLoopVectorizer::widenCallInstruction(CallInst &CI, VPValue *Def,
VPUser &ArgOperands,
VPTransformState &State) {
assert(!isa<DbgInfoIntrinsic>(CI) &&
"DbgInfoIntrinsic should have been dropped during VPlan construction");
State.setDebugLocFromInst(&CI);
SmallVector<Type *, 4> Tys;
for (Value *ArgOperand : CI.args())
Tys.push_back(ToVectorTy(ArgOperand->getType(), VF.getKnownMinValue()));
Intrinsic::ID ID = getVectorIntrinsicIDForCall(&CI, TLI);
// The flag shows whether we use Intrinsic or a usual Call for vectorized
// version of the instruction.
// Is it beneficial to perform intrinsic call compared to lib call?
bool NeedToScalarize = false;
InstructionCost CallCost = Cost->getVectorCallCost(&CI, VF, NeedToScalarize);
InstructionCost IntrinsicCost =
ID ? Cost->getVectorIntrinsicCost(&CI, VF) : 0;
bool UseVectorIntrinsic = ID && IntrinsicCost <= CallCost;
assert((UseVectorIntrinsic || !NeedToScalarize) &&
"Instruction should be scalarized elsewhere.");
assert((IntrinsicCost.isValid() || CallCost.isValid()) &&
"Either the intrinsic cost or vector call cost must be valid");
for (unsigned Part = 0; Part < UF; ++Part) {
SmallVector<Type *, 2> TysForDecl = {CI.getType()};
SmallVector<Value *, 4> Args;
for (auto &I : enumerate(ArgOperands.operands())) {
// Some intrinsics have a scalar argument - don't replace it with a
// vector.
Value *Arg;
if (!UseVectorIntrinsic ||
!isVectorIntrinsicWithScalarOpAtArg(ID, I.index()))
Arg = State.get(I.value(), Part);
else
Arg = State.get(I.value(), VPIteration(0, 0));
if (isVectorIntrinsicWithOverloadTypeAtArg(ID, I.index()))
TysForDecl.push_back(Arg->getType());
Args.push_back(Arg);
}
Function *VectorF;
if (UseVectorIntrinsic) {
// Use vector version of the intrinsic.
if (VF.isVector())
TysForDecl[0] = VectorType::get(CI.getType()->getScalarType(), VF);
Module *M = State.Builder.GetInsertBlock()->getModule();
VectorF = Intrinsic::getDeclaration(M, ID, TysForDecl);
assert(VectorF && "Can't retrieve vector intrinsic.");
} else {
// Use vector version of the function call.
const VFShape Shape = VFShape::get(CI, VF, false /*HasGlobalPred*/);
#ifndef NDEBUG
assert(VFDatabase(CI).getVectorizedFunction(Shape) != nullptr &&
"Can't create vector function.");
#endif
VectorF = VFDatabase(CI).getVectorizedFunction(Shape);
}
SmallVector<OperandBundleDef, 1> OpBundles;
CI.getOperandBundlesAsDefs(OpBundles);
CallInst *V = Builder.CreateCall(VectorF, Args, OpBundles);
if (isa<FPMathOperator>(V))
V->copyFastMathFlags(&CI);
State.set(Def, V, Part);
State.addMetadata(V, &CI);
}
}
void LoopVectorizationCostModel::collectLoopScalars(ElementCount VF) {
// We should not collect Scalars more than once per VF. Right now, this
// function is called from collectUniformsAndScalars(), which already does
// this check. Collecting Scalars for VF=1 does not make any sense.
assert(VF.isVector() && Scalars.find(VF) == Scalars.end() &&
"This function should not be visited twice for the same VF");
// This avoids any chances of creating a REPLICATE recipe during planning
// since that would result in generation of scalarized code during execution,
// which is not supported for scalable vectors.
if (VF.isScalable()) {
Scalars[VF].insert(Uniforms[VF].begin(), Uniforms[VF].end());
return;
}
SmallSetVector<Instruction *, 8> Worklist;
// These sets are used to seed the analysis with pointers used by memory
// accesses that will remain scalar.
SmallSetVector<Instruction *, 8> ScalarPtrs;
SmallPtrSet<Instruction *, 8> PossibleNonScalarPtrs;
auto *Latch = TheLoop->getLoopLatch();
// A helper that returns true if the use of Ptr by MemAccess will be scalar.
// The pointer operands of loads and stores will be scalar as long as the
// memory access is not a gather or scatter operation. The value operand of a
// store will remain scalar if the store is scalarized.
auto isScalarUse = [&](Instruction *MemAccess, Value *Ptr) {
InstWidening WideningDecision = getWideningDecision(MemAccess, VF);
assert(WideningDecision != CM_Unknown &&
"Widening decision should be ready at this moment");
if (auto *Store = dyn_cast<StoreInst>(MemAccess))
if (Ptr == Store->getValueOperand())
return WideningDecision == CM_Scalarize;
assert(Ptr == getLoadStorePointerOperand(MemAccess) &&
"Ptr is neither a value or pointer operand");
return WideningDecision != CM_GatherScatter;
};
// A helper that returns true if the given value is a bitcast or
// getelementptr instruction contained in the loop.
auto isLoopVaryingBitCastOrGEP = [&](Value *V) {
return ((isa<BitCastInst>(V) && V->getType()->isPointerTy()) ||
isa<GetElementPtrInst>(V)) &&
!TheLoop->isLoopInvariant(V);
};
// A helper that evaluates a memory access's use of a pointer. If the use will
// be a scalar use and the pointer is only used by memory accesses, we place
// the pointer in ScalarPtrs. Otherwise, the pointer is placed in
// PossibleNonScalarPtrs.
auto evaluatePtrUse = [&](Instruction *MemAccess, Value *Ptr) {
// We only care about bitcast and getelementptr instructions contained in
// the loop.
if (!isLoopVaryingBitCastOrGEP(Ptr))
return;
// If the pointer has already been identified as scalar (e.g., if it was
// also identified as uniform), there's nothing to do.
auto *I = cast<Instruction>(Ptr);
if (Worklist.count(I))
return;
// If the use of the pointer will be a scalar use, and all users of the
// pointer are memory accesses, place the pointer in ScalarPtrs. Otherwise,
// place the pointer in PossibleNonScalarPtrs.
if (isScalarUse(MemAccess, Ptr) && llvm::all_of(I->users(), [&](User *U) {
return isa<LoadInst>(U) || isa<StoreInst>(U);
}))
ScalarPtrs.insert(I);
else
PossibleNonScalarPtrs.insert(I);
};
// We seed the scalars analysis with three classes of instructions: (1)
// instructions marked uniform-after-vectorization and (2) bitcast,
// getelementptr and (pointer) phi instructions used by memory accesses
// requiring a scalar use.
//
// (1) Add to the worklist all instructions that have been identified as
// uniform-after-vectorization.
Worklist.insert(Uniforms[VF].begin(), Uniforms[VF].end());
// (2) Add to the worklist all bitcast and getelementptr instructions used by
// memory accesses requiring a scalar use. The pointer operands of loads and
// stores will be scalar as long as the memory accesses is not a gather or
// scatter operation. The value operand of a store will remain scalar if the
// store is scalarized.
for (auto *BB : TheLoop->blocks())
for (auto &I : *BB) {
if (auto *Load = dyn_cast<LoadInst>(&I)) {
evaluatePtrUse(Load, Load->getPointerOperand());
} else if (auto *Store = dyn_cast<StoreInst>(&I)) {
evaluatePtrUse(Store, Store->getPointerOperand());
evaluatePtrUse(Store, Store->getValueOperand());
}
}
for (auto *I : ScalarPtrs)
if (!PossibleNonScalarPtrs.count(I)) {
LLVM_DEBUG(dbgs() << "LV: Found scalar instruction: " << *I << "\n");
Worklist.insert(I);
}
// Insert the forced scalars.
// FIXME: Currently VPWidenPHIRecipe() often creates a dead vector
// induction variable when the PHI user is scalarized.
auto ForcedScalar = ForcedScalars.find(VF);
if (ForcedScalar != ForcedScalars.end())
for (auto *I : ForcedScalar->second)
Worklist.insert(I);
// Expand the worklist by looking through any bitcasts and getelementptr
// instructions we've already identified as scalar. This is similar to the
// expansion step in collectLoopUniforms(); however, here we're only
// expanding to include additional bitcasts and getelementptr instructions.
unsigned Idx = 0;
while (Idx != Worklist.size()) {
Instruction *Dst = Worklist[Idx++];
if (!isLoopVaryingBitCastOrGEP(Dst->getOperand(0)))
continue;
auto *Src = cast<Instruction>(Dst->getOperand(0));
if (llvm::all_of(Src->users(), [&](User *U) -> bool {
auto *J = cast<Instruction>(U);
return !TheLoop->contains(J) || Worklist.count(J) ||
((isa<LoadInst>(J) || isa<StoreInst>(J)) &&
isScalarUse(J, Src));
})) {
Worklist.insert(Src);
LLVM_DEBUG(dbgs() << "LV: Found scalar instruction: " << *Src << "\n");
}
}
// An induction variable will remain scalar if all users of the induction
// variable and induction variable update remain scalar.
for (auto &Induction : Legal->getInductionVars()) {
auto *Ind = Induction.first;
auto *IndUpdate = cast<Instruction>(Ind->getIncomingValueForBlock(Latch));
// If tail-folding is applied, the primary induction variable will be used
// to feed a vector compare.
if (Ind == Legal->getPrimaryInduction() && foldTailByMasking())
continue;
// Returns true if \p Indvar is a pointer induction that is used directly by
// load/store instruction \p I.
auto IsDirectLoadStoreFromPtrIndvar = [&](Instruction *Indvar,
Instruction *I) {
return Induction.second.getKind() ==
InductionDescriptor::IK_PtrInduction &&
(isa<LoadInst>(I) || isa<StoreInst>(I)) &&
Indvar == getLoadStorePointerOperand(I) && isScalarUse(I, Indvar);
};
// Determine if all users of the induction variable are scalar after
// vectorization.
auto ScalarInd = llvm::all_of(Ind->users(), [&](User *U) -> bool {
auto *I = cast<Instruction>(U);
return I == IndUpdate || !TheLoop->contains(I) || Worklist.count(I) ||
IsDirectLoadStoreFromPtrIndvar(Ind, I);
});
if (!ScalarInd)
continue;
// Determine if all users of the induction variable update instruction are
// scalar after vectorization.
auto ScalarIndUpdate =
llvm::all_of(IndUpdate->users(), [&](User *U) -> bool {
auto *I = cast<Instruction>(U);
return I == Ind || !TheLoop->contains(I) || Worklist.count(I) ||
IsDirectLoadStoreFromPtrIndvar(IndUpdate, I);
});
if (!ScalarIndUpdate)
continue;
// The induction variable and its update instruction will remain scalar.
Worklist.insert(Ind);
Worklist.insert(IndUpdate);
LLVM_DEBUG(dbgs() << "LV: Found scalar instruction: " << *Ind << "\n");
LLVM_DEBUG(dbgs() << "LV: Found scalar instruction: " << *IndUpdate
<< "\n");
}
Scalars[VF].insert(Worklist.begin(), Worklist.end());
}
bool LoopVectorizationCostModel::isScalarWithPredication(
Instruction *I, ElementCount VF) const {
if (!blockNeedsPredicationForAnyReason(I->getParent()))
return false;
switch(I->getOpcode()) {
default:
break;
case Instruction::Load:
case Instruction::Store: {
if (!Legal->isMaskRequired(I))
return false;
auto *Ptr = getLoadStorePointerOperand(I);
auto *Ty = getLoadStoreType(I);
Type *VTy = Ty;
if (VF.isVector())
VTy = VectorType::get(Ty, VF);
const Align Alignment = getLoadStoreAlignment(I);
return isa<LoadInst>(I) ? !(isLegalMaskedLoad(Ty, Ptr, Alignment) ||
TTI.isLegalMaskedGather(VTy, Alignment))
: !(isLegalMaskedStore(Ty, Ptr, Alignment) ||
TTI.isLegalMaskedScatter(VTy, Alignment));
}
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::SRem:
case Instruction::URem:
// TODO: We can use the loop-preheader as context point here and get
// context sensitive reasoning
return !isSafeToSpeculativelyExecute(I);
}
return false;
}
bool LoopVectorizationCostModel::interleavedAccessCanBeWidened(
Instruction *I, ElementCount VF) {
assert(isAccessInterleaved(I) && "Expecting interleaved access.");
assert(getWideningDecision(I, VF) == CM_Unknown &&
"Decision should not be set yet.");
auto *Group = getInterleavedAccessGroup(I);
assert(Group && "Must have a group.");
// If the instruction's allocated size doesn't equal it's type size, it
// requires padding and will be scalarized.
auto &DL = I->getModule()->getDataLayout();
auto *ScalarTy = getLoadStoreType(I);
if (hasIrregularType(ScalarTy, DL))
return false;
// If the group involves a non-integral pointer, we may not be able to
// losslessly cast all values to a common type.
unsigned InterleaveFactor = Group->getFactor();
bool ScalarNI = DL.isNonIntegralPointerType(ScalarTy);
for (unsigned i = 0; i < InterleaveFactor; i++) {
Instruction *Member = Group->getMember(i);
if (!Member)
continue;
auto *MemberTy = getLoadStoreType(Member);
bool MemberNI = DL.isNonIntegralPointerType(MemberTy);
// Don't coerce non-integral pointers to integers or vice versa.
if (MemberNI != ScalarNI) {
// TODO: Consider adding special nullptr value case here
return false;
} else if (MemberNI && ScalarNI &&
ScalarTy->getPointerAddressSpace() !=
MemberTy->getPointerAddressSpace()) {
return false;
}
}
// Check if masking is required.
// A Group may need masking for one of two reasons: it resides in a block that
// needs predication, or it was decided to use masking to deal with gaps
// (either a gap at the end of a load-access that may result in a speculative
// load, or any gaps in a store-access).
bool PredicatedAccessRequiresMasking =
blockNeedsPredicationForAnyReason(I->getParent()) &&
Legal->isMaskRequired(I);
bool LoadAccessWithGapsRequiresEpilogMasking =
isa<LoadInst>(I) && Group->requiresScalarEpilogue() &&
!isScalarEpilogueAllowed();
bool StoreAccessWithGapsRequiresMasking =
isa<StoreInst>(I) && (Group->getNumMembers() < Group->getFactor());
if (!PredicatedAccessRequiresMasking &&
!LoadAccessWithGapsRequiresEpilogMasking &&
!StoreAccessWithGapsRequiresMasking)
return true;
// If masked interleaving is required, we expect that the user/target had
// enabled it, because otherwise it either wouldn't have been created or
// it should have been invalidated by the CostModel.
assert(useMaskedInterleavedAccesses(TTI) &&
"Masked interleave-groups for predicated accesses are not enabled.");
if (Group->isReverse())
return false;
auto *Ty = getLoadStoreType(I);
const Align Alignment = getLoadStoreAlignment(I);
return isa<LoadInst>(I) ? TTI.isLegalMaskedLoad(Ty, Alignment)
: TTI.isLegalMaskedStore(Ty, Alignment);
}
bool LoopVectorizationCostModel::memoryInstructionCanBeWidened(
Instruction *I, ElementCount VF) {
// Get and ensure we have a valid memory instruction.
assert((isa<LoadInst, StoreInst>(I)) && "Invalid memory instruction");
auto *Ptr = getLoadStorePointerOperand(I);
auto *ScalarTy = getLoadStoreType(I);
// In order to be widened, the pointer should be consecutive, first of all.
if (!Legal->isConsecutivePtr(ScalarTy, Ptr))
return false;
// If the instruction is a store located in a predicated block, it will be
// scalarized.
if (isScalarWithPredication(I, VF))
return false;
// If the instruction's allocated size doesn't equal it's type size, it
// requires padding and will be scalarized.
auto &DL = I->getModule()->getDataLayout();
if (hasIrregularType(ScalarTy, DL))
return false;
return true;
}
void LoopVectorizationCostModel::collectLoopUniforms(ElementCount VF) {
// We should not collect Uniforms more than once per VF. Right now,
// this function is called from collectUniformsAndScalars(), which
// already does this check. Collecting Uniforms for VF=1 does not make any
// sense.
assert(VF.isVector() && Uniforms.find(VF) == Uniforms.end() &&
"This function should not be visited twice for the same VF");
// Visit the list of Uniforms. If we'll not find any uniform value, we'll
// not analyze again. Uniforms.count(VF) will return 1.
Uniforms[VF].clear();
// We now know that the loop is vectorizable!
// Collect instructions inside the loop that will remain uniform after
// vectorization.
// Global values, params and instructions outside of current loop are out of
// scope.
auto isOutOfScope = [&](Value *V) -> bool {
Instruction *I = dyn_cast<Instruction>(V);
return (!I || !TheLoop->contains(I));
};
// Worklist containing uniform instructions demanding lane 0.
SetVector<Instruction *> Worklist;
BasicBlock *Latch = TheLoop->getLoopLatch();
// Add uniform instructions demanding lane 0 to the worklist. Instructions
// that are scalar with predication must not be considered uniform after
// vectorization, because that would create an erroneous replicating region
// where only a single instance out of VF should be formed.
// TODO: optimize such seldom cases if found important, see PR40816.
auto addToWorklistIfAllowed = [&](Instruction *I) -> void {
if (isOutOfScope(I)) {
LLVM_DEBUG(dbgs() << "LV: Found not uniform due to scope: "
<< *I << "\n");
return;
}
if (isScalarWithPredication(I, VF)) {
LLVM_DEBUG(dbgs() << "LV: Found not uniform being ScalarWithPredication: "
<< *I << "\n");
return;
}
LLVM_DEBUG(dbgs() << "LV: Found uniform instruction: " << *I << "\n");
Worklist.insert(I);
};
// Start with the conditional branch. If the branch condition is an
// instruction contained in the loop that is only used by the branch, it is
// uniform.
auto *Cmp = dyn_cast<Instruction>(Latch->getTerminator()->getOperand(0));
if (Cmp && TheLoop->contains(Cmp) && Cmp->hasOneUse())
addToWorklistIfAllowed(Cmp);
auto isUniformDecision = [&](Instruction *I, ElementCount VF) {
InstWidening WideningDecision = getWideningDecision(I, VF);
assert(WideningDecision != CM_Unknown &&
"Widening decision should be ready at this moment");
// A uniform memory op is itself uniform. We exclude uniform stores
// here as they demand the last lane, not the first one.
if (isa<LoadInst>(I) && Legal->isUniformMemOp(*I)) {
assert(WideningDecision == CM_Scalarize);
return true;
}
return (WideningDecision == CM_Widen ||
WideningDecision == CM_Widen_Reverse ||
WideningDecision == CM_Interleave);
};
// Returns true if Ptr is the pointer operand of a memory access instruction
// I, and I is known to not require scalarization.
auto isVectorizedMemAccessUse = [&](Instruction *I, Value *Ptr) -> bool {
return getLoadStorePointerOperand(I) == Ptr && isUniformDecision(I, VF);
};
// Holds a list of values which are known to have at least one uniform use.
// Note that there may be other uses which aren't uniform. A "uniform use"
// here is something which only demands lane 0 of the unrolled iterations;
// it does not imply that all lanes produce the same value (e.g. this is not
// the usual meaning of uniform)
SetVector<Value *> HasUniformUse;
// Scan the loop for instructions which are either a) known to have only
// lane 0 demanded or b) are uses which demand only lane 0 of their operand.
for (auto *BB : TheLoop->blocks())
for (auto &I : *BB) {
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I)) {
switch (II->getIntrinsicID()) {
case Intrinsic::sideeffect:
case Intrinsic::experimental_noalias_scope_decl:
case Intrinsic::assume:
case Intrinsic::lifetime_start:
case Intrinsic::lifetime_end:
if (TheLoop->hasLoopInvariantOperands(&I))
addToWorklistIfAllowed(&I);
break;
default:
break;
}
}
// ExtractValue instructions must be uniform, because the operands are
// known to be loop-invariant.
if (auto *EVI = dyn_cast<ExtractValueInst>(&I)) {
assert(isOutOfScope(EVI->getAggregateOperand()) &&
"Expected aggregate value to be loop invariant");
addToWorklistIfAllowed(EVI);
continue;
}
// If there's no pointer operand, there's nothing to do.
auto *Ptr = getLoadStorePointerOperand(&I);
if (!Ptr)
continue;
// A uniform memory op is itself uniform. We exclude uniform stores
// here as they demand the last lane, not the first one.
if (isa<LoadInst>(I) && Legal->isUniformMemOp(I))
addToWorklistIfAllowed(&I);
if (isUniformDecision(&I, VF)) {
assert(isVectorizedMemAccessUse(&I, Ptr) && "consistency check");
HasUniformUse.insert(Ptr);
}
}
// Add to the worklist any operands which have *only* uniform (e.g. lane 0
// demanding) users. Since loops are assumed to be in LCSSA form, this
// disallows uses outside the loop as well.
for (auto *V : HasUniformUse) {
if (isOutOfScope(V))
continue;
auto *I = cast<Instruction>(V);
auto UsersAreMemAccesses =
llvm::all_of(I->users(), [&](User *U) -> bool {
return isVectorizedMemAccessUse(cast<Instruction>(U), V);
});
if (UsersAreMemAccesses)
addToWorklistIfAllowed(I);
}
// Expand Worklist in topological order: whenever a new instruction
// is added , its users should be already inside Worklist. It ensures
// a uniform instruction will only be used by uniform instructions.
unsigned idx = 0;
while (idx != Worklist.size()) {
Instruction *I = Worklist[idx++];
for (auto OV : I->operand_values()) {
// isOutOfScope operands cannot be uniform instructions.
if (isOutOfScope(OV))
continue;
// First order recurrence Phi's should typically be considered
// non-uniform.
auto *OP = dyn_cast<PHINode>(OV);
if (OP && Legal->isFirstOrderRecurrence(OP))
continue;
// If all the users of the operand are uniform, then add the
// operand into the uniform worklist.
auto *OI = cast<Instruction>(OV);
if (llvm::all_of(OI->users(), [&](User *U) -> bool {
auto *J = cast<Instruction>(U);
return Worklist.count(J) || isVectorizedMemAccessUse(J, OI);
}))
addToWorklistIfAllowed(OI);
}
}
// For an instruction to be added into Worklist above, all its users inside
// the loop should also be in Worklist. However, this condition cannot be
// true for phi nodes that form a cyclic dependence. We must process phi
// nodes separately. An induction variable will remain uniform if all users
// of the induction variable and induction variable update remain uniform.
// The code below handles both pointer and non-pointer induction variables.
for (auto &Induction : Legal->getInductionVars()) {
auto *Ind = Induction.first;
auto *IndUpdate = cast<Instruction>(Ind->getIncomingValueForBlock(Latch));
// Determine if all users of the induction variable are uniform after
// vectorization.
auto UniformInd = llvm::all_of(Ind->users(), [&](User *U) -> bool {
auto *I = cast<Instruction>(U);
return I == IndUpdate || !TheLoop->contains(I) || Worklist.count(I) ||
isVectorizedMemAccessUse(I, Ind);
});
if (!UniformInd)
continue;
// Determine if all users of the induction variable update instruction are
// uniform after vectorization.
auto UniformIndUpdate =
llvm::all_of(IndUpdate->users(), [&](User *U) -> bool {
auto *I = cast<Instruction>(U);
return I == Ind || !TheLoop->contains(I) || Worklist.count(I) ||
isVectorizedMemAccessUse(I, IndUpdate);
});
if (!UniformIndUpdate)
continue;
// The induction variable and its update instruction will remain uniform.
addToWorklistIfAllowed(Ind);
addToWorklistIfAllowed(IndUpdate);
}
Uniforms[VF].insert(Worklist.begin(), Worklist.end());
}
bool LoopVectorizationCostModel::runtimeChecksRequired() {
LLVM_DEBUG(dbgs() << "LV: Performing code size checks.\n");
if (Legal->getRuntimePointerChecking()->Need) {
reportVectorizationFailure("Runtime ptr check is required with -Os/-Oz",
"runtime pointer checks needed. Enable vectorization of this "
"loop with '#pragma clang loop vectorize(enable)' when "
"compiling with -Os/-Oz",
"CantVersionLoopWithOptForSize", ORE, TheLoop);
return true;
}
if (!PSE.getPredicate().isAlwaysTrue()) {
reportVectorizationFailure("Runtime SCEV check is required with -Os/-Oz",
"runtime SCEV checks needed. Enable vectorization of this "
"loop with '#pragma clang loop vectorize(enable)' when "
"compiling with -Os/-Oz",
"CantVersionLoopWithOptForSize", ORE, TheLoop);
return true;
}
// FIXME: Avoid specializing for stride==1 instead of bailing out.
if (!Legal->getLAI()->getSymbolicStrides().empty()) {
reportVectorizationFailure("Runtime stride check for small trip count",
"runtime stride == 1 checks needed. Enable vectorization of "
"this loop without such check by compiling with -Os/-Oz",
"CantVersionLoopWithOptForSize", ORE, TheLoop);
return true;
}
return false;
}
ElementCount
LoopVectorizationCostModel::getMaxLegalScalableVF(unsigned MaxSafeElements) {
if (!TTI.supportsScalableVectors() && !ForceTargetSupportsScalableVectors)
return ElementCount::getScalable(0);
if (Hints->isScalableVectorizationDisabled()) {
reportVectorizationInfo("Scalable vectorization is explicitly disabled",
"ScalableVectorizationDisabled", ORE, TheLoop);
return ElementCount::getScalable(0);
}
LLVM_DEBUG(dbgs() << "LV: Scalable vectorization is available\n");
auto MaxScalableVF = ElementCount::getScalable(
std::numeric_limits<ElementCount::ScalarTy>::max());
// Test that the loop-vectorizer can legalize all operations for this MaxVF.
// FIXME: While for scalable vectors this is currently sufficient, this should
// be replaced by a more detailed mechanism that filters out specific VFs,
// instead of invalidating vectorization for a whole set of VFs based on the
// MaxVF.
// Disable scalable vectorization if the loop contains unsupported reductions.
if (!canVectorizeReductions(MaxScalableVF)) {
reportVectorizationInfo(
"Scalable vectorization not supported for the reduction "
"operations found in this loop.",
"ScalableVFUnfeasible", ORE, TheLoop);
return ElementCount::getScalable(0);
}
// Disable scalable vectorization if the loop contains any instructions
// with element types not supported for scalable vectors.
if (any_of(ElementTypesInLoop, [&](Type *Ty) {
return !Ty->isVoidTy() &&
!this->TTI.isElementTypeLegalForScalableVector(Ty);
})) {
reportVectorizationInfo("Scalable vectorization is not supported "
"for all element types found in this loop.",
"ScalableVFUnfeasible", ORE, TheLoop);
return ElementCount::getScalable(0);
}
if (Legal->isSafeForAnyVectorWidth())
return MaxScalableVF;
// Limit MaxScalableVF by the maximum safe dependence distance.
Optional<unsigned> MaxVScale = TTI.getMaxVScale();
if (!MaxVScale && TheFunction->hasFnAttribute(Attribute::VScaleRange))
MaxVScale =
TheFunction->getFnAttribute(Attribute::VScaleRange).getVScaleRangeMax();
MaxScalableVF = ElementCount::getScalable(
MaxVScale ? (MaxSafeElements / MaxVScale.value()) : 0);
if (!MaxScalableVF)
reportVectorizationInfo(
"Max legal vector width too small, scalable vectorization "
"unfeasible.",
"ScalableVFUnfeasible", ORE, TheLoop);
return MaxScalableVF;
}
FixedScalableVFPair LoopVectorizationCostModel::computeFeasibleMaxVF(
unsigned ConstTripCount, ElementCount UserVF, bool FoldTailByMasking) {
MinBWs = computeMinimumValueSizes(TheLoop->getBlocks(), *DB, &TTI);
unsigned SmallestType, WidestType;
std::tie(SmallestType, WidestType) = getSmallestAndWidestTypes();
// Get the maximum safe dependence distance in bits computed by LAA.
// It is computed by MaxVF * sizeOf(type) * 8, where type is taken from
// the memory accesses that is most restrictive (involved in the smallest
// dependence distance).
unsigned MaxSafeElements =
PowerOf2Floor(Legal->getMaxSafeVectorWidthInBits() / WidestType);
auto MaxSafeFixedVF = ElementCount::getFixed(MaxSafeElements);
auto MaxSafeScalableVF = getMaxLegalScalableVF(MaxSafeElements);
LLVM_DEBUG(dbgs() << "LV: The max safe fixed VF is: " << MaxSafeFixedVF
<< ".\n");
LLVM_DEBUG(dbgs() << "LV: The max safe scalable VF is: " << MaxSafeScalableVF
<< ".\n");
// First analyze the UserVF, fall back if the UserVF should be ignored.
if (UserVF) {
auto MaxSafeUserVF =
UserVF.isScalable() ? MaxSafeScalableVF : MaxSafeFixedVF;
if (ElementCount::isKnownLE(UserVF, MaxSafeUserVF)) {
// If `VF=vscale x N` is safe, then so is `VF=N`
if (UserVF.isScalable())
return FixedScalableVFPair(
ElementCount::getFixed(UserVF.getKnownMinValue()), UserVF);
else
return UserVF;
}
assert(ElementCount::isKnownGT(UserVF, MaxSafeUserVF));
// Only clamp if the UserVF is not scalable. If the UserVF is scalable, it
// is better to ignore the hint and let the compiler choose a suitable VF.
if (!UserVF.isScalable()) {
LLVM_DEBUG(dbgs() << "LV: User VF=" << UserVF
<< " is unsafe, clamping to max safe VF="
<< MaxSafeFixedVF << ".\n");
ORE->emit([&]() {
return OptimizationRemarkAnalysis(DEBUG_TYPE, "VectorizationFactor",
TheLoop->getStartLoc(),
TheLoop->getHeader())
<< "User-specified vectorization factor "
<< ore::NV("UserVectorizationFactor", UserVF)
<< " is unsafe, clamping to maximum safe vectorization factor "
<< ore::NV("VectorizationFactor", MaxSafeFixedVF);
});
return MaxSafeFixedVF;
}
if (!TTI.supportsScalableVectors() && !ForceTargetSupportsScalableVectors) {
LLVM_DEBUG(dbgs() << "LV: User VF=" << UserVF
<< " is ignored because scalable vectors are not "
"available.\n");
ORE->emit([&]() {
return OptimizationRemarkAnalysis(DEBUG_TYPE, "VectorizationFactor",
TheLoop->getStartLoc(),
TheLoop->getHeader())
<< "User-specified vectorization factor "
<< ore::NV("UserVectorizationFactor", UserVF)
<< " is ignored because the target does not support scalable "
"vectors. The compiler will pick a more suitable value.";
});
} else {
LLVM_DEBUG(dbgs() << "LV: User VF=" << UserVF
<< " is unsafe. Ignoring scalable UserVF.\n");
ORE->emit([&]() {
return OptimizationRemarkAnalysis(DEBUG_TYPE, "VectorizationFactor",
TheLoop->getStartLoc(),
TheLoop->getHeader())
<< "User-specified vectorization factor "
<< ore::NV("UserVectorizationFactor", UserVF)
<< " is unsafe. Ignoring the hint to let the compiler pick a "
"more suitable value.";
});
}
}
LLVM_DEBUG(dbgs() << "LV: The Smallest and Widest types: " << SmallestType
<< " / " << WidestType << " bits.\n");
FixedScalableVFPair Result(ElementCount::getFixed(1),
ElementCount::getScalable(0));
if (auto MaxVF =
getMaximizedVFForTarget(ConstTripCount, SmallestType, WidestType,
MaxSafeFixedVF, FoldTailByMasking))
Result.FixedVF = MaxVF;
if (auto MaxVF =
getMaximizedVFForTarget(ConstTripCount, SmallestType, WidestType,
MaxSafeScalableVF, FoldTailByMasking))
if (MaxVF.isScalable()) {
Result.ScalableVF = MaxVF;
LLVM_DEBUG(dbgs() << "LV: Found feasible scalable VF = " << MaxVF
<< "\n");
}
return Result;
}
FixedScalableVFPair
LoopVectorizationCostModel::computeMaxVF(ElementCount UserVF, unsigned UserIC) {
if (Legal->getRuntimePointerChecking()->Need && TTI.hasBranchDivergence()) {
// TODO: It may by useful to do since it's still likely to be dynamically
// uniform if the target can skip.
reportVectorizationFailure(
"Not inserting runtime ptr check for divergent target",
"runtime pointer checks needed. Not enabled for divergent target",
"CantVersionLoopWithDivergentTarget", ORE, TheLoop);
return FixedScalableVFPair::getNone();
}
unsigned TC = PSE.getSE()->getSmallConstantTripCount(TheLoop);
LLVM_DEBUG(dbgs() << "LV: Found trip count: " << TC << '\n');
if (TC == 1) {
reportVectorizationFailure("Single iteration (non) loop",
"loop trip count is one, irrelevant for vectorization",
"SingleIterationLoop", ORE, TheLoop);
return FixedScalableVFPair::getNone();
}
switch (ScalarEpilogueStatus) {
case CM_ScalarEpilogueAllowed:
return computeFeasibleMaxVF(TC, UserVF, false);
case CM_ScalarEpilogueNotAllowedUsePredicate:
LLVM_FALLTHROUGH;
case CM_ScalarEpilogueNotNeededUsePredicate:
LLVM_DEBUG(
dbgs() << "LV: vector predicate hint/switch found.\n"
<< "LV: Not allowing scalar epilogue, creating predicated "
<< "vector loop.\n");
break;
case CM_ScalarEpilogueNotAllowedLowTripLoop:
// fallthrough as a special case of OptForSize
case CM_ScalarEpilogueNotAllowedOptSize:
if (ScalarEpilogueStatus == CM_ScalarEpilogueNotAllowedOptSize)
LLVM_DEBUG(
dbgs() << "LV: Not allowing scalar epilogue due to -Os/-Oz.\n");
else
LLVM_DEBUG(dbgs() << "LV: Not allowing scalar epilogue due to low trip "
<< "count.\n");
// Bail if runtime checks are required, which are not good when optimising
// for size.
if (runtimeChecksRequired())
return FixedScalableVFPair::getNone();
break;
}
// The only loops we can vectorize without a scalar epilogue, are loops with
// a bottom-test and a single exiting block. We'd have to handle the fact
// that not every instruction executes on the last iteration. This will
// require a lane mask which varies through the vector loop body. (TODO)
if (TheLoop->getExitingBlock() != TheLoop->getLoopLatch()) {
// If there was a tail-folding hint/switch, but we can't fold the tail by
// masking, fallback to a vectorization with a scalar epilogue.
if (ScalarEpilogueStatus == CM_ScalarEpilogueNotNeededUsePredicate) {
LLVM_DEBUG(dbgs() << "LV: Cannot fold tail by masking: vectorize with a "
"scalar epilogue instead.\n");
ScalarEpilogueStatus = CM_ScalarEpilogueAllowed;
return computeFeasibleMaxVF(TC, UserVF, false);
}
return FixedScalableVFPair::getNone();
}
// Now try the tail folding
// Invalidate interleave groups that require an epilogue if we can't mask
// the interleave-group.
if (!useMaskedInterleavedAccesses(TTI)) {
assert(WideningDecisions.empty() && Uniforms.empty() && Scalars.empty() &&
"No decisions should have been taken at this point");
// Note: There is no need to invalidate any cost modeling decisions here, as
// non where taken so far.
InterleaveInfo.invalidateGroupsRequiringScalarEpilogue();
}
FixedScalableVFPair MaxFactors = computeFeasibleMaxVF(TC, UserVF, true);
// Avoid tail folding if the trip count is known to be a multiple of any VF
// we chose.
// FIXME: The condition below pessimises the case for fixed-width vectors,
// when scalable VFs are also candidates for vectorization.
if (MaxFactors.FixedVF.isVector() && !MaxFactors.ScalableVF) {
ElementCount MaxFixedVF = MaxFactors.FixedVF;
assert((UserVF.isNonZero() || isPowerOf2_32(MaxFixedVF.getFixedValue())) &&
"MaxFixedVF must be a power of 2");
unsigned MaxVFtimesIC = UserIC ? MaxFixedVF.getFixedValue() * UserIC
: MaxFixedVF.getFixedValue();
ScalarEvolution *SE = PSE.getSE();
const SCEV *BackedgeTakenCount = PSE.getBackedgeTakenCount();
const SCEV *ExitCount = SE->getAddExpr(
BackedgeTakenCount, SE->getOne(BackedgeTakenCount->getType()));
const SCEV *Rem = SE->getURemExpr(
SE->applyLoopGuards(ExitCount, TheLoop),
SE->getConstant(BackedgeTakenCount->getType(), MaxVFtimesIC));
if (Rem->isZero()) {
// Accept MaxFixedVF if we do not have a tail.
LLVM_DEBUG(dbgs() << "LV: No tail will remain for any chosen VF.\n");
return MaxFactors;
}
}
// If we don't know the precise trip count, or if the trip count that we
// found modulo the vectorization factor is not zero, try to fold the tail
// by masking.
// FIXME: look for a smaller MaxVF that does divide TC rather than masking.
if (Legal->prepareToFoldTailByMasking()) {
FoldTailByMasking = true;
return MaxFactors;
}
// If there was a tail-folding hint/switch, but we can't fold the tail by
// masking, fallback to a vectorization with a scalar epilogue.
if (ScalarEpilogueStatus == CM_ScalarEpilogueNotNeededUsePredicate) {
LLVM_DEBUG(dbgs() << "LV: Cannot fold tail by masking: vectorize with a "
"scalar epilogue instead.\n");
ScalarEpilogueStatus = CM_ScalarEpilogueAllowed;
return MaxFactors;
}
if (ScalarEpilogueStatus == CM_ScalarEpilogueNotAllowedUsePredicate) {
LLVM_DEBUG(dbgs() << "LV: Can't fold tail by masking: don't vectorize\n");
return FixedScalableVFPair::getNone();
}
if (TC == 0) {
reportVectorizationFailure(
"Unable to calculate the loop count due to complex control flow",
"unable to calculate the loop count due to complex control flow",
"UnknownLoopCountComplexCFG", ORE, TheLoop);
return FixedScalableVFPair::getNone();
}
reportVectorizationFailure(
"Cannot optimize for size and vectorize at the same time.",
"cannot optimize for size and vectorize at the same time. "
"Enable vectorization of this loop with '#pragma clang loop "
"vectorize(enable)' when compiling with -Os/-Oz",
"NoTailLoopWithOptForSize", ORE, TheLoop);
return FixedScalableVFPair::getNone();
}
ElementCount LoopVectorizationCostModel::getMaximizedVFForTarget(
unsigned ConstTripCount, unsigned SmallestType, unsigned WidestType,
ElementCount MaxSafeVF, bool FoldTailByMasking) {
bool ComputeScalableMaxVF = MaxSafeVF.isScalable();
TypeSize WidestRegister = TTI.getRegisterBitWidth(
ComputeScalableMaxVF ? TargetTransformInfo::RGK_ScalableVector
: TargetTransformInfo::RGK_FixedWidthVector);
// Convenience function to return the minimum of two ElementCounts.
auto MinVF = [](const ElementCount &LHS, const ElementCount &RHS) {
assert((LHS.isScalable() == RHS.isScalable()) &&
"Scalable flags must match");
return ElementCount::isKnownLT(LHS, RHS) ? LHS : RHS;
};
// Ensure MaxVF is a power of 2; the dependence distance bound may not be.
// Note that both WidestRegister and WidestType may not be a powers of 2.
auto MaxVectorElementCount = ElementCount::get(
PowerOf2Floor(WidestRegister.getKnownMinSize() / WidestType),
ComputeScalableMaxVF);
MaxVectorElementCount = MinVF(MaxVectorElementCount, MaxSafeVF);
LLVM_DEBUG(dbgs() << "LV: The Widest register safe to use is: "
<< (MaxVectorElementCount * WidestType) << " bits.\n");
if (!MaxVectorElementCount) {
LLVM_DEBUG(dbgs() << "LV: The target has no "
<< (ComputeScalableMaxVF ? "scalable" : "fixed")
<< " vector registers.\n");
return ElementCount::getFixed(1);
}
const auto TripCountEC = ElementCount::getFixed(ConstTripCount);
if (ConstTripCount &&
ElementCount::isKnownLE(TripCountEC, MaxVectorElementCount) &&
(!FoldTailByMasking || isPowerOf2_32(ConstTripCount))) {
// If loop trip count (TC) is known at compile time there is no point in
// choosing VF greater than TC (as done in the loop below). Select maximum
// power of two which doesn't exceed TC.
// If MaxVectorElementCount is scalable, we only fall back on a fixed VF
// when the TC is less than or equal to the known number of lanes.
auto ClampedConstTripCount = PowerOf2Floor(ConstTripCount);
LLVM_DEBUG(dbgs() << "LV: Clamping the MaxVF to maximum power of two not "
"exceeding the constant trip count: "
<< ClampedConstTripCount << "\n");
return ElementCount::getFixed(ClampedConstTripCount);
}
TargetTransformInfo::RegisterKind RegKind =
ComputeScalableMaxVF ? TargetTransformInfo::RGK_ScalableVector
: TargetTransformInfo::RGK_FixedWidthVector;
ElementCount MaxVF = MaxVectorElementCount;
if (MaximizeBandwidth || (MaximizeBandwidth.getNumOccurrences() == 0 &&
TTI.shouldMaximizeVectorBandwidth(RegKind))) {
auto MaxVectorElementCountMaxBW = ElementCount::get(
PowerOf2Floor(WidestRegister.getKnownMinSize() / SmallestType),
ComputeScalableMaxVF);
MaxVectorElementCountMaxBW = MinVF(MaxVectorElementCountMaxBW, MaxSafeVF);
// Collect all viable vectorization factors larger than the default MaxVF
// (i.e. MaxVectorElementCount).
SmallVector<ElementCount, 8> VFs;
for (ElementCount VS = MaxVectorElementCount * 2;
ElementCount::isKnownLE(VS, MaxVectorElementCountMaxBW); VS *= 2)
VFs.push_back(VS);
// For each VF calculate its register usage.
auto RUs = calculateRegisterUsage(VFs);
// Select the largest VF which doesn't require more registers than existing
// ones.
for (int i = RUs.size() - 1; i >= 0; --i) {
bool Selected = true;
for (auto &pair : RUs[i].MaxLocalUsers) {
unsigned TargetNumRegisters = TTI.getNumberOfRegisters(pair.first);
if (pair.second > TargetNumRegisters)
Selected = false;
}
if (Selected) {
MaxVF = VFs[i];
break;
}
}
if (ElementCount MinVF =
TTI.getMinimumVF(SmallestType, ComputeScalableMaxVF)) {
if (ElementCount::isKnownLT(MaxVF, MinVF)) {
LLVM_DEBUG(dbgs() << "LV: Overriding calculated MaxVF(" << MaxVF
<< ") with target's minimum: " << MinVF << '\n');
MaxVF = MinVF;
}
}
// Invalidate any widening decisions we might have made, in case the loop
// requires prediction (decided later), but we have already made some
// load/store widening decisions.
invalidateCostModelingDecisions();
}
return MaxVF;
}
Optional<unsigned> LoopVectorizationCostModel::getVScaleForTuning() const {
if (TheFunction->hasFnAttribute(Attribute::VScaleRange)) {
auto Attr = TheFunction->getFnAttribute(Attribute::VScaleRange);
auto Min = Attr.getVScaleRangeMin();
auto Max = Attr.getVScaleRangeMax();
if (Max && Min == Max)
return Max;
}
return TTI.getVScaleForTuning();
}
bool LoopVectorizationCostModel::isMoreProfitable(
const VectorizationFactor &A, const VectorizationFactor &B) const {
InstructionCost CostA = A.Cost;
InstructionCost CostB = B.Cost;
unsigned MaxTripCount = PSE.getSE()->getSmallConstantMaxTripCount(TheLoop);
if (!A.Width.isScalable() && !B.Width.isScalable() && FoldTailByMasking &&
MaxTripCount) {
// If we are folding the tail and the trip count is a known (possibly small)
// constant, the trip count will be rounded up to an integer number of
// iterations. The total cost will be PerIterationCost*ceil(TripCount/VF),
// which we compare directly. When not folding the tail, the total cost will
// be PerIterationCost*floor(TC/VF) + Scalar remainder cost, and so is
// approximated with the per-lane cost below instead of using the tripcount
// as here.
auto RTCostA = CostA * divideCeil(MaxTripCount, A.Width.getFixedValue());
auto RTCostB = CostB * divideCeil(MaxTripCount, B.Width.getFixedValue());
return RTCostA < RTCostB;
}
// Improve estimate for the vector width if it is scalable.
unsigned EstimatedWidthA = A.Width.getKnownMinValue();
unsigned EstimatedWidthB = B.Width.getKnownMinValue();
if (Optional<unsigned> VScale = getVScaleForTuning()) {
if (A.Width.isScalable())
EstimatedWidthA *= VScale.value();
if (B.Width.isScalable())
EstimatedWidthB *= VScale.value();
}
// Assume vscale may be larger than 1 (or the value being tuned for),
// so that scalable vectorization is slightly favorable over fixed-width
// vectorization.
if (A.Width.isScalable() && !B.Width.isScalable())
return (CostA * B.Width.getFixedValue()) <= (CostB * EstimatedWidthA);
// To avoid the need for FP division:
// (CostA / A.Width) < (CostB / B.Width)
// <=> (CostA * B.Width) < (CostB * A.Width)
return (CostA * EstimatedWidthB) < (CostB * EstimatedWidthA);
}
VectorizationFactor LoopVectorizationCostModel::selectVectorizationFactor(
const ElementCountSet &VFCandidates) {
InstructionCost ExpectedCost = expectedCost(ElementCount::getFixed(1)).first;
LLVM_DEBUG(dbgs() << "LV: Scalar loop costs: " << ExpectedCost << ".\n");
assert(ExpectedCost.isValid() && "Unexpected invalid cost for scalar loop");
assert(VFCandidates.count(ElementCount::getFixed(1)) &&
"Expected Scalar VF to be a candidate");
const VectorizationFactor ScalarCost(ElementCount::getFixed(1), ExpectedCost,
ExpectedCost);
VectorizationFactor ChosenFactor = ScalarCost;
bool ForceVectorization = Hints->getForce() == LoopVectorizeHints::FK_Enabled;
if (ForceVectorization && VFCandidates.size() > 1) {
// Ignore scalar width, because the user explicitly wants vectorization.
// Initialize cost to max so that VF = 2 is, at least, chosen during cost
// evaluation.
ChosenFactor.Cost = InstructionCost::getMax();
}
SmallVector<InstructionVFPair> InvalidCosts;
for (const auto &i : VFCandidates) {
// The cost for scalar VF=1 is already calculated, so ignore it.
if (i.isScalar())
continue;
VectorizationCostTy C = expectedCost(i, &InvalidCosts);
VectorizationFactor Candidate(i, C.first, ScalarCost.ScalarCost);
#ifndef NDEBUG
unsigned AssumedMinimumVscale = 1;
if (Optional<unsigned> VScale = getVScaleForTuning())
AssumedMinimumVscale = *VScale;
unsigned Width =
Candidate.Width.isScalable()
? Candidate.Width.getKnownMinValue() * AssumedMinimumVscale
: Candidate.Width.getFixedValue();
LLVM_DEBUG(dbgs() << "LV: Vector loop of width " << i
<< " costs: " << (Candidate.Cost / Width));
if (i.isScalable())
LLVM_DEBUG(dbgs() << " (assuming a minimum vscale of "
<< AssumedMinimumVscale << ")");
LLVM_DEBUG(dbgs() << ".\n");
#endif
if (!C.second && !ForceVectorization) {
LLVM_DEBUG(
dbgs() << "LV: Not considering vector loop of width " << i
<< " because it will not generate any vector instructions.\n");
continue;
}
// If profitable add it to ProfitableVF list.
if (isMoreProfitable(Candidate, ScalarCost))
ProfitableVFs.push_back(Candidate);
if (isMoreProfitable(Candidate, ChosenFactor))
ChosenFactor = Candidate;
}
// Emit a report of VFs with invalid costs in the loop.
if (!InvalidCosts.empty()) {
// Group the remarks per instruction, keeping the instruction order from
// InvalidCosts.
std::map<Instruction *, unsigned> Numbering;
unsigned I = 0;
for (auto &Pair : InvalidCosts)
if (!Numbering.count(Pair.first))
Numbering[Pair.first] = I++;
// Sort the list, first on instruction(number) then on VF.
llvm::sort(InvalidCosts,
[&Numbering](InstructionVFPair &A, InstructionVFPair &B) {
if (Numbering[A.first] != Numbering[B.first])
return Numbering[A.first] < Numbering[B.first];
ElementCountComparator ECC;
return ECC(A.second, B.second);
});
// For a list of ordered instruction-vf pairs:
// [(load, vf1), (load, vf2), (store, vf1)]
// Group the instructions together to emit separate remarks for:
// load (vf1, vf2)
// store (vf1)
auto Tail = ArrayRef<InstructionVFPair>(InvalidCosts);
auto Subset = ArrayRef<InstructionVFPair>();
do {
if (Subset.empty())
Subset = Tail.take_front(1);
Instruction *I = Subset.front().first;
// If the next instruction is different, or if there are no other pairs,
// emit a remark for the collated subset. e.g.
// [(load, vf1), (load, vf2))]
// to emit:
// remark: invalid costs for 'load' at VF=(vf, vf2)
if (Subset == Tail || Tail[Subset.size()].first != I) {
std::string OutString;
raw_string_ostream OS(OutString);
assert(!Subset.empty() && "Unexpected empty range");
OS << "Instruction with invalid costs prevented vectorization at VF=(";
for (auto &Pair : Subset)
OS << (Pair.second == Subset.front().second ? "" : ", ")
<< Pair.second;
OS << "):";
if (auto *CI = dyn_cast<CallInst>(I))
OS << " call to " << CI->getCalledFunction()->getName();
else
OS << " " << I->getOpcodeName();
OS.flush();
reportVectorizationInfo(OutString, "InvalidCost", ORE, TheLoop, I);
Tail = Tail.drop_front(Subset.size());
Subset = {};
} else
// Grow the subset by one element
Subset = Tail.take_front(Subset.size() + 1);
} while (!Tail.empty());
}
if (!EnableCondStoresVectorization && NumPredStores) {
reportVectorizationFailure("There are conditional stores.",
"store that is conditionally executed prevents vectorization",
"ConditionalStore", ORE, TheLoop);
ChosenFactor = ScalarCost;
}
LLVM_DEBUG(if (ForceVectorization && !ChosenFactor.Width.isScalar() &&
!isMoreProfitable(ChosenFactor, ScalarCost)) dbgs()
<< "LV: Vectorization seems to be not beneficial, "
<< "but was forced by a user.\n");
LLVM_DEBUG(dbgs() << "LV: Selecting VF: " << ChosenFactor.Width << ".\n");
return ChosenFactor;
}
bool LoopVectorizationCostModel::isCandidateForEpilogueVectorization(
const Loop &L, ElementCount VF) const {
// Cross iteration phis such as reductions need special handling and are
// currently unsupported.
if (any_of(L.getHeader()->phis(),
[&](PHINode &Phi) { return Legal->isFirstOrderRecurrence(&Phi); }))
return false;
// Phis with uses outside of the loop require special handling and are
// currently unsupported.
for (auto &Entry : Legal->getInductionVars()) {
// Look for uses of the value of the induction at the last iteration.
Value *PostInc = Entry.first->getIncomingValueForBlock(L.getLoopLatch());
for (User *U : PostInc->users())
if (!L.contains(cast<Instruction>(U)))
return false;
// Look for uses of penultimate value of the induction.
for (User *U : Entry.first->users())
if (!L.contains(cast<Instruction>(U)))
return false;
}
// Induction variables that are widened require special handling that is
// currently not supported.
if (any_of(Legal->getInductionVars(), [&](auto &Entry) {
return !(this->isScalarAfterVectorization(Entry.first, VF) ||
this->isProfitableToScalarize(Entry.first, VF));
}))
return false;
// Epilogue vectorization code has not been auditted to ensure it handles
// non-latch exits properly. It may be fine, but it needs auditted and
// tested.
if (L.getExitingBlock() != L.getLoopLatch())
return false;
return true;
}
bool LoopVectorizationCostModel::isEpilogueVectorizationProfitable(
const ElementCount VF) const {
// FIXME: We need a much better cost-model to take different parameters such
// as register pressure, code size increase and cost of extra branches into
// account. For now we apply a very crude heuristic and only consider loops
// with vectorization factors larger than a certain value.
// We also consider epilogue vectorization unprofitable for targets that don't
// consider interleaving beneficial (eg. MVE).
if (TTI.getMaxInterleaveFactor(VF.getKnownMinValue()) <= 1)
return false;
// FIXME: We should consider changing the threshold for scalable
// vectors to take VScaleForTuning into account.
if (VF.getKnownMinValue() >= EpilogueVectorizationMinVF)
return true;
return false;
}
VectorizationFactor
LoopVectorizationCostModel::selectEpilogueVectorizationFactor(
const ElementCount MainLoopVF, const LoopVectorizationPlanner &LVP) {
VectorizationFactor Result = VectorizationFactor::Disabled();
if (!EnableEpilogueVectorization) {
LLVM_DEBUG(dbgs() << "LEV: Epilogue vectorization is disabled.\n";);
return Result;
}
if (!isScalarEpilogueAllowed()) {
LLVM_DEBUG(
dbgs() << "LEV: Unable to vectorize epilogue because no epilogue is "
"allowed.\n";);
return Result;
}
// Not really a cost consideration, but check for unsupported cases here to
// simplify the logic.
if (!isCandidateForEpilogueVectorization(*TheLoop, MainLoopVF)) {
LLVM_DEBUG(
dbgs() << "LEV: Unable to vectorize epilogue because the loop is "
"not a supported candidate.\n";);
return Result;
}
if (EpilogueVectorizationForceVF > 1) {
LLVM_DEBUG(dbgs() << "LEV: Epilogue vectorization factor is forced.\n";);
ElementCount ForcedEC = ElementCount::getFixed(EpilogueVectorizationForceVF);
if (LVP.hasPlanWithVF(ForcedEC))
return {ForcedEC, 0, 0};
else {
LLVM_DEBUG(
dbgs()
<< "LEV: Epilogue vectorization forced factor is not viable.\n";);
return Result;
}
}
if (TheLoop->getHeader()->getParent()->hasOptSize() ||
TheLoop->getHeader()->getParent()->hasMinSize()) {
LLVM_DEBUG(
dbgs()
<< "LEV: Epilogue vectorization skipped due to opt for size.\n";);
return Result;
}
if (!isEpilogueVectorizationProfitable(MainLoopVF)) {
LLVM_DEBUG(dbgs() << "LEV: Epilogue vectorization is not profitable for "
"this loop\n");
return Result;
}
// If MainLoopVF = vscale x 2, and vscale is expected to be 4, then we know
// the main loop handles 8 lanes per iteration. We could still benefit from
// vectorizing the epilogue loop with VF=4.
ElementCount EstimatedRuntimeVF = MainLoopVF;
if (MainLoopVF.isScalable()) {
EstimatedRuntimeVF = ElementCount::getFixed(MainLoopVF.getKnownMinValue());
if (Optional<unsigned> VScale = getVScaleForTuning())
EstimatedRuntimeVF *= *VScale;
}
for (auto &NextVF : ProfitableVFs)
if (((!NextVF.Width.isScalable() && MainLoopVF.isScalable() &&
ElementCount::isKnownLT(NextVF.Width, EstimatedRuntimeVF)) ||
ElementCount::isKnownLT(NextVF.Width, MainLoopVF)) &&
(Result.Width.isScalar() || isMoreProfitable(NextVF, Result)) &&
LVP.hasPlanWithVF(NextVF.Width))
Result = NextVF;
if (Result != VectorizationFactor::Disabled())
LLVM_DEBUG(dbgs() << "LEV: Vectorizing epilogue loop with VF = "
<< Result.Width << "\n";);
return Result;
}
std::pair<unsigned, unsigned>
LoopVectorizationCostModel::getSmallestAndWidestTypes() {
unsigned MinWidth = -1U;
unsigned MaxWidth = 8;
const DataLayout &DL = TheFunction->getParent()->getDataLayout();
// For in-loop reductions, no element types are added to ElementTypesInLoop
// if there are no loads/stores in the loop. In this case, check through the
// reduction variables to determine the maximum width.
if (ElementTypesInLoop.empty() && !Legal->getReductionVars().empty()) {
// Reset MaxWidth so that we can find the smallest type used by recurrences
// in the loop.
MaxWidth = -1U;
for (auto &PhiDescriptorPair : Legal->getReductionVars()) {
const RecurrenceDescriptor &RdxDesc = PhiDescriptorPair.second;
// When finding the min width used by the recurrence we need to account
// for casts on the input operands of the recurrence.
MaxWidth = std::min<unsigned>(
MaxWidth, std::min<unsigned>(
RdxDesc.getMinWidthCastToRecurrenceTypeInBits(),
RdxDesc.getRecurrenceType()->getScalarSizeInBits()));
}
} else {
for (Type *T : ElementTypesInLoop) {
MinWidth = std::min<unsigned>(
MinWidth, DL.getTypeSizeInBits(T->getScalarType()).getFixedSize());
MaxWidth = std::max<unsigned>(
MaxWidth, DL.getTypeSizeInBits(T->getScalarType()).getFixedSize());
}
}
return {MinWidth, MaxWidth};
}
void LoopVectorizationCostModel::collectElementTypesForWidening() {
ElementTypesInLoop.clear();
// For each block.
for (BasicBlock *BB : TheLoop->blocks()) {
// For each instruction in the loop.
for (Instruction &I : BB->instructionsWithoutDebug()) {
Type *T = I.getType();
// Skip ignored values.
if (ValuesToIgnore.count(&I))
continue;
// Only examine Loads, Stores and PHINodes.
if (!isa<LoadInst>(I) && !isa<StoreInst>(I) && !isa<PHINode>(I))
continue;
// Examine PHI nodes that are reduction variables. Update the type to
// account for the recurrence type.
if (auto *PN = dyn_cast<PHINode>(&I)) {
if (!Legal->isReductionVariable(PN))
continue;
const RecurrenceDescriptor &RdxDesc =
Legal->getReductionVars().find(PN)->second;
if (PreferInLoopReductions || useOrderedReductions(RdxDesc) ||
TTI.preferInLoopReduction(RdxDesc.getOpcode(),
RdxDesc.getRecurrenceType(),
TargetTransformInfo::ReductionFlags()))
continue;
T = RdxDesc.getRecurrenceType();
}
// Examine the stored values.
if (auto *ST = dyn_cast<StoreInst>(&I))
T = ST->getValueOperand()->getType();
assert(T->isSized() &&
"Expected the load/store/recurrence type to be sized");
ElementTypesInLoop.insert(T);
}
}
}
unsigned LoopVectorizationCostModel::selectInterleaveCount(ElementCount VF,
unsigned LoopCost) {
// -- The interleave heuristics --
// We interleave the loop in order to expose ILP and reduce the loop overhead.
// There are many micro-architectural considerations that we can't predict
// at this level. For example, frontend pressure (on decode or fetch) due to
// code size, or the number and capabilities of the execution ports.
//
// We use the following heuristics to select the interleave count:
// 1. If the code has reductions, then we interleave to break the cross
// iteration dependency.
// 2. If the loop is really small, then we interleave to reduce the loop
// overhead.
// 3. We don't interleave if we think that we will spill registers to memory
// due to the increased register pressure.
if (!isScalarEpilogueAllowed())
return 1;
// We used the distance for the interleave count.
if (Legal->getMaxSafeDepDistBytes() != -1U)
return 1;
auto BestKnownTC = getSmallBestKnownTC(*PSE.getSE(), TheLoop);
const bool HasReductions = !Legal->getReductionVars().empty();
// Do not interleave loops with a relatively small known or estimated trip
// count. But we will interleave when InterleaveSmallLoopScalarReduction is
// enabled, and the code has scalar reductions(HasReductions && VF = 1),
// because with the above conditions interleaving can expose ILP and break
// cross iteration dependences for reductions.
if (BestKnownTC && (*BestKnownTC < TinyTripCountInterleaveThreshold) &&
!(InterleaveSmallLoopScalarReduction && HasReductions && VF.isScalar()))
return 1;
// If we did not calculate the cost for VF (because the user selected the VF)
// then we calculate the cost of VF here.
if (LoopCost == 0) {
InstructionCost C = expectedCost(VF).first;
assert(C.isValid() && "Expected to have chosen a VF with valid cost");
LoopCost = *C.getValue();
// Loop body is free and there is no need for interleaving.
if (LoopCost == 0)
return 1;
}
RegisterUsage R = calculateRegisterUsage({VF})[0];
// We divide by these constants so assume that we have at least one
// instruction that uses at least one register.
for (auto& pair : R.MaxLocalUsers) {
pair.second = std::max(pair.second, 1U);
}
// We calculate the interleave count using the following formula.
// Subtract the number of loop invariants from the number of available
// registers. These registers are used by all of the interleaved instances.
// Next, divide the remaining registers by the number of registers that is
// required by the loop, in order to estimate how many parallel instances
// fit without causing spills. All of this is rounded down if necessary to be
// a power of two. We want power of two interleave count to simplify any
// addressing operations or alignment considerations.
// We also want power of two interleave counts to ensure that the induction
// variable of the vector loop wraps to zero, when tail is folded by masking;
// this currently happens when OptForSize, in which case IC is set to 1 above.
unsigned IC = UINT_MAX;
for (auto& pair : R.MaxLocalUsers) {
unsigned TargetNumRegisters = TTI.getNumberOfRegisters(pair.first);
LLVM_DEBUG(dbgs() << "LV: The target has " << TargetNumRegisters
<< " registers of "
<< TTI.getRegisterClassName(pair.first) << " register class\n");
if (VF.isScalar()) {
if (ForceTargetNumScalarRegs.getNumOccurrences() > 0)
TargetNumRegisters = ForceTargetNumScalarRegs;
} else {
if (ForceTargetNumVectorRegs.getNumOccurrences() > 0)
TargetNumRegisters = ForceTargetNumVectorRegs;
}
unsigned MaxLocalUsers = pair.second;
unsigned LoopInvariantRegs = 0;
if (R.LoopInvariantRegs.find(pair.first) != R.LoopInvariantRegs.end())
LoopInvariantRegs = R.LoopInvariantRegs[pair.first];
unsigned TmpIC = PowerOf2Floor((TargetNumRegisters - LoopInvariantRegs) / MaxLocalUsers);
// Don't count the induction variable as interleaved.
if (EnableIndVarRegisterHeur) {
TmpIC =
PowerOf2Floor((TargetNumRegisters - LoopInvariantRegs - 1) /
std::max(1U, (MaxLocalUsers - 1)));
}
IC = std::min(IC, TmpIC);
}
// Clamp the interleave ranges to reasonable counts.
unsigned MaxInterleaveCount =
TTI.getMaxInterleaveFactor(VF.getKnownMinValue());
// Check if the user has overridden the max.
if (VF.isScalar()) {
if (ForceTargetMaxScalarInterleaveFactor.getNumOccurrences() > 0)
MaxInterleaveCount = ForceTargetMaxScalarInterleaveFactor;
} else {
if (ForceTargetMaxVectorInterleaveFactor.getNumOccurrences() > 0)
MaxInterleaveCount = ForceTargetMaxVectorInterleaveFactor;
}
// If trip count is known or estimated compile time constant, limit the
// interleave count to be less than the trip count divided by VF, provided it
// is at least 1.
//
// For scalable vectors we can't know if interleaving is beneficial. It may
// not be beneficial for small loops if none of the lanes in the second vector
// iterations is enabled. However, for larger loops, there is likely to be a
// similar benefit as for fixed-width vectors. For now, we choose to leave
// the InterleaveCount as if vscale is '1', although if some information about
// the vector is known (e.g. min vector size), we can make a better decision.
if (BestKnownTC) {
MaxInterleaveCount =
std::min(*BestKnownTC / VF.getKnownMinValue(), MaxInterleaveCount);
// Make sure MaxInterleaveCount is greater than 0.
MaxInterleaveCount = std::max(1u, MaxInterleaveCount);
}
assert(MaxInterleaveCount > 0 &&
"Maximum interleave count must be greater than 0");
// Clamp the calculated IC to be between the 1 and the max interleave count
// that the target and trip count allows.
if (IC > MaxInterleaveCount)
IC = MaxInterleaveCount;
else
// Make sure IC is greater than 0.
IC = std::max(1u, IC);
assert(IC > 0 && "Interleave count must be greater than 0.");
// Interleave if we vectorized this loop and there is a reduction that could
// benefit from interleaving.
if (VF.isVector() && HasReductions) {
LLVM_DEBUG(dbgs() << "LV: Interleaving because of reductions.\n");
return IC;
}
// For any scalar loop that either requires runtime checks or predication we
// are better off leaving this to the unroller. Note that if we've already
// vectorized the loop we will have done the runtime check and so interleaving
// won't require further checks.
bool ScalarInterleavingRequiresPredication =
(VF.isScalar() && any_of(TheLoop->blocks(), [this](BasicBlock *BB) {
return Legal->blockNeedsPredication(BB);
}));
bool ScalarInterleavingRequiresRuntimePointerCheck =
(VF.isScalar() && Legal->getRuntimePointerChecking()->Need);
// We want to interleave small loops in order to reduce the loop overhead and
// potentially expose ILP opportunities.
LLVM_DEBUG(dbgs() << "LV: Loop cost is " << LoopCost << '\n'
<< "LV: IC is " << IC << '\n'
<< "LV: VF is " << VF << '\n');
const bool AggressivelyInterleaveReductions =
TTI.enableAggressiveInterleaving(HasReductions);
if (!ScalarInterleavingRequiresRuntimePointerCheck &&
!ScalarInterleavingRequiresPredication && LoopCost < SmallLoopCost) {
// We assume that the cost overhead is 1 and we use the cost model
// to estimate the cost of the loop and interleave until the cost of the
// loop overhead is about 5% of the cost of the loop.
unsigned SmallIC =
std::min(IC, (unsigned)PowerOf2Floor(SmallLoopCost / LoopCost));
// Interleave until store/load ports (estimated by max interleave count) are
// saturated.
unsigned NumStores = Legal->getNumStores();
unsigned NumLoads = Legal->getNumLoads();
unsigned StoresIC = IC / (NumStores ? NumStores : 1);
unsigned LoadsIC = IC / (NumLoads ? NumLoads : 1);
// There is little point in interleaving for reductions containing selects
// and compares when VF=1 since it may just create more overhead than it's
// worth for loops with small trip counts. This is because we still have to
// do the final reduction after the loop.
bool HasSelectCmpReductions =
HasReductions &&
any_of(Legal->getReductionVars(), [&](auto &Reduction) -> bool {
const RecurrenceDescriptor &RdxDesc = Reduction.second;
return RecurrenceDescriptor::isSelectCmpRecurrenceKind(
RdxDesc.getRecurrenceKind());
});
if (HasSelectCmpReductions) {
LLVM_DEBUG(dbgs() << "LV: Not interleaving select-cmp reductions.\n");
return 1;
}
// If we have a scalar reduction (vector reductions are already dealt with
// by this point), we can increase the critical path length if the loop
// we're interleaving is inside another loop. For tree-wise reductions
// set the limit to 2, and for ordered reductions it's best to disable
// interleaving entirely.
if (HasReductions && TheLoop->getLoopDepth() > 1) {
bool HasOrderedReductions =
any_of(Legal->getReductionVars(), [&](auto &Reduction) -> bool {
const RecurrenceDescriptor &RdxDesc = Reduction.second;
return RdxDesc.isOrdered();
});
if (HasOrderedReductions) {
LLVM_DEBUG(
dbgs() << "LV: Not interleaving scalar ordered reductions.\n");
return 1;
}
unsigned F = static_cast<unsigned>(MaxNestedScalarReductionIC);
SmallIC = std::min(SmallIC, F);
StoresIC = std::min(StoresIC, F);
LoadsIC = std::min(LoadsIC, F);
}
if (EnableLoadStoreRuntimeInterleave &&
std::max(StoresIC, LoadsIC) > SmallIC) {
LLVM_DEBUG(
dbgs() << "LV: Interleaving to saturate store or load ports.\n");
return std::max(StoresIC, LoadsIC);
}
// If there are scalar reductions and TTI has enabled aggressive
// interleaving for reductions, we will interleave to expose ILP.
if (InterleaveSmallLoopScalarReduction && VF.isScalar() &&
AggressivelyInterleaveReductions) {
LLVM_DEBUG(dbgs() << "LV: Interleaving to expose ILP.\n");
// Interleave no less than SmallIC but not as aggressive as the normal IC
// to satisfy the rare situation when resources are too limited.
return std::max(IC / 2, SmallIC);
} else {
LLVM_DEBUG(dbgs() << "LV: Interleaving to reduce branch cost.\n");
return SmallIC;
}
}
// Interleave if this is a large loop (small loops are already dealt with by
// this point) that could benefit from interleaving.
if (AggressivelyInterleaveReductions) {
LLVM_DEBUG(dbgs() << "LV: Interleaving to expose ILP.\n");
return IC;
}
LLVM_DEBUG(dbgs() << "LV: Not Interleaving.\n");
return 1;
}
SmallVector<LoopVectorizationCostModel::RegisterUsage, 8>
LoopVectorizationCostModel::calculateRegisterUsage(ArrayRef<ElementCount> VFs) {
// This function calculates the register usage by measuring the highest number
// of values that are alive at a single location. Obviously, this is a very
// rough estimation. We scan the loop in a topological order in order and
// assign a number to each instruction. We use RPO to ensure that defs are
// met before their users. We assume that each instruction that has in-loop
// users starts an interval. We record every time that an in-loop value is
// used, so we have a list of the first and last occurrences of each
// instruction. Next, we transpose this data structure into a multi map that
// holds the list of intervals that *end* at a specific location. This multi
// map allows us to perform a linear search. We scan the instructions linearly
// and record each time that a new interval starts, by placing it in a set.
// If we find this value in the multi-map then we remove it from the set.
// The max register usage is the maximum size of the set.
// We also search for instructions that are defined outside the loop, but are
// used inside the loop. We need this number separately from the max-interval
// usage number because when we unroll, loop-invariant values do not take
// more register.
LoopBlocksDFS DFS(TheLoop);
DFS.perform(LI);
RegisterUsage RU;
// Each 'key' in the map opens a new interval. The values
// of the map are the index of the 'last seen' usage of the
// instruction that is the key.
using IntervalMap = DenseMap<Instruction *, unsigned>;
// Maps instruction to its index.
SmallVector<Instruction *, 64> IdxToInstr;
// Marks the end of each interval.
IntervalMap EndPoint;
// Saves the list of instruction indices that are used in the loop.
SmallPtrSet<Instruction *, 8> Ends;
// Saves the list of values that are used in the loop but are
// defined outside the loop, such as arguments and constants.
SmallPtrSet<Value *, 8> LoopInvariants;
for (BasicBlock *BB : make_range(DFS.beginRPO(), DFS.endRPO())) {
for (Instruction &I : BB->instructionsWithoutDebug()) {
IdxToInstr.push_back(&I);
// Save the end location of each USE.
for (Value *U : I.operands()) {
auto *Instr = dyn_cast<Instruction>(U);
// Ignore non-instruction values such as arguments, constants, etc.
if (!Instr)
continue;
// If this instruction is outside the loop then record it and continue.
if (!TheLoop->contains(Instr)) {
LoopInvariants.insert(Instr);
continue;
}
// Overwrite previous end points.
EndPoint[Instr] = IdxToInstr.size();
Ends.insert(Instr);
}
}
}
// Saves the list of intervals that end with the index in 'key'.
using InstrList = SmallVector<Instruction *, 2>;
DenseMap<unsigned, InstrList> TransposeEnds;
// Transpose the EndPoints to a list of values that end at each index.
for (auto &Interval : EndPoint)
TransposeEnds[Interval.second].push_back(Interval.first);
SmallPtrSet<Instruction *, 8> OpenIntervals;
SmallVector<RegisterUsage, 8> RUs(VFs.size());
SmallVector<SmallMapVector<unsigned, unsigned, 4>, 8> MaxUsages(VFs.size());
LLVM_DEBUG(dbgs() << "LV(REG): Calculating max register usage:\n");
const auto &TTICapture = TTI;
auto GetRegUsage = [&TTICapture](Type *Ty, ElementCount VF) -> unsigned {
if (Ty->isTokenTy() || !VectorType::isValidElementType(Ty))
return 0;
return TTICapture.getRegUsageForType(VectorType::get(Ty, VF));
};
for (unsigned int i = 0, s = IdxToInstr.size(); i < s; ++i) {
Instruction *I = IdxToInstr[i];
// Remove all of the instructions that end at this location.
InstrList &List = TransposeEnds[i];
for (Instruction *ToRemove : List)
OpenIntervals.erase(ToRemove);
// Ignore instructions that are never used within the loop.
if (!Ends.count(I))
continue;
// Skip ignored values.
if (ValuesToIgnore.count(I))
continue;
// For each VF find the maximum usage of registers.
for (unsigned j = 0, e = VFs.size(); j < e; ++j) {
// Count the number of live intervals.
SmallMapVector<unsigned, unsigned, 4> RegUsage;
if (VFs[j].isScalar()) {
for (auto Inst : OpenIntervals) {
unsigned ClassID = TTI.getRegisterClassForType(false, Inst->getType());
if (RegUsage.find(ClassID) == RegUsage.end())
RegUsage[ClassID] = 1;
else
RegUsage[ClassID] += 1;
}
} else {
collectUniformsAndScalars(VFs[j]);
for (auto Inst : OpenIntervals) {
// Skip ignored values for VF > 1.
if (VecValuesToIgnore.count(Inst))
continue;
if (isScalarAfterVectorization(Inst, VFs[j])) {
unsigned ClassID = TTI.getRegisterClassForType(false, Inst->getType());
if (RegUsage.find(ClassID) == RegUsage.end())
RegUsage[ClassID] = 1;
else
RegUsage[ClassID] += 1;
} else {
unsigned ClassID = TTI.getRegisterClassForType(true, Inst->getType());
if (RegUsage.find(ClassID) == RegUsage.end())
RegUsage[ClassID] = GetRegUsage(Inst->getType(), VFs[j]);
else
RegUsage[ClassID] += GetRegUsage(Inst->getType(), VFs[j]);
}
}
}
for (auto& pair : RegUsage) {
if (MaxUsages[j].find(pair.first) != MaxUsages[j].end())
MaxUsages[j][pair.first] = std::max(MaxUsages[j][pair.first], pair.second);
else
MaxUsages[j][pair.first] = pair.second;
}
}
LLVM_DEBUG(dbgs() << "LV(REG): At #" << i << " Interval # "
<< OpenIntervals.size() << '\n');
// Add the current instruction to the list of open intervals.
OpenIntervals.insert(I);
}
for (unsigned i = 0, e = VFs.size(); i < e; ++i) {
SmallMapVector<unsigned, unsigned, 4> Invariant;
for (auto Inst : LoopInvariants) {
unsigned Usage =
VFs[i].isScalar() ? 1 : GetRegUsage(Inst->getType(), VFs[i]);
unsigned ClassID =
TTI.getRegisterClassForType(VFs[i].isVector(), Inst->getType());
if (Invariant.find(ClassID) == Invariant.end())
Invariant[ClassID] = Usage;
else
Invariant[ClassID] += Usage;
}
LLVM_DEBUG({
dbgs() << "LV(REG): VF = " << VFs[i] << '\n';
dbgs() << "LV(REG): Found max usage: " << MaxUsages[i].size()
<< " item\n";
for (const auto &pair : MaxUsages[i]) {
dbgs() << "LV(REG): RegisterClass: "
<< TTI.getRegisterClassName(pair.first) << ", " << pair.second
<< " registers\n";
}
dbgs() << "LV(REG): Found invariant usage: " << Invariant.size()
<< " item\n";
for (const auto &pair : Invariant) {
dbgs() << "LV(REG): RegisterClass: "
<< TTI.getRegisterClassName(pair.first) << ", " << pair.second
<< " registers\n";
}
});
RU.LoopInvariantRegs = Invariant;
RU.MaxLocalUsers = MaxUsages[i];
RUs[i] = RU;
}
return RUs;
}
bool LoopVectorizationCostModel::useEmulatedMaskMemRefHack(Instruction *I,
ElementCount VF) {
// TODO: Cost model for emulated masked load/store is completely
// broken. This hack guides the cost model to use an artificially
// high enough value to practically disable vectorization with such
// operations, except where previously deployed legality hack allowed
// using very low cost values. This is to avoid regressions coming simply
// from moving "masked load/store" check from legality to cost model.
// Masked Load/Gather emulation was previously never allowed.
// Limited number of Masked Store/Scatter emulation was allowed.
assert((isPredicatedInst(I, VF) || Legal->isUniformMemOp(*I)) &&
"Expecting a scalar emulated instruction");
return isa<LoadInst>(I) ||
(isa<StoreInst>(I) &&
NumPredStores > NumberOfStoresToPredicate);
}
void LoopVectorizationCostModel::collectInstsToScalarize(ElementCount VF) {
// If we aren't vectorizing the loop, or if we've already collected the
// instructions to scalarize, there's nothing to do. Collection may already
// have occurred if we have a user-selected VF and are now computing the
// expected cost for interleaving.
if (VF.isScalar() || VF.isZero() ||
InstsToScalarize.find(VF) != InstsToScalarize.end())
return;
// Initialize a mapping for VF in InstsToScalalarize. If we find that it's
// not profitable to scalarize any instructions, the presence of VF in the
// map will indicate that we've analyzed it already.
ScalarCostsTy &ScalarCostsVF = InstsToScalarize[VF];
PredicatedBBsAfterVectorization[VF].clear();
// Find all the instructions that are scalar with predication in the loop and
// determine if it would be better to not if-convert the blocks they are in.
// If so, we also record the instructions to scalarize.
for (BasicBlock *BB : TheLoop->blocks()) {
if (!blockNeedsPredicationForAnyReason(BB))
continue;
for (Instruction &I : *BB)
if (isScalarWithPredication(&I, VF)) {
ScalarCostsTy ScalarCosts;
// Do not apply discount if scalable, because that would lead to
// invalid scalarization costs.
// Do not apply discount logic if hacked cost is needed
// for emulated masked memrefs.
if (!VF.isScalable() && !useEmulatedMaskMemRefHack(&I, VF) &&
computePredInstDiscount(&I, ScalarCosts, VF) >= 0)
ScalarCostsVF.insert(ScalarCosts.begin(), ScalarCosts.end());
// Remember that BB will remain after vectorization.
PredicatedBBsAfterVectorization[VF].insert(BB);
}
}
}
int LoopVectorizationCostModel::computePredInstDiscount(
Instruction *PredInst, ScalarCostsTy &ScalarCosts, ElementCount VF) {
assert(!isUniformAfterVectorization(PredInst, VF) &&
"Instruction marked uniform-after-vectorization will be predicated");
// Initialize the discount to zero, meaning that the scalar version and the
// vector version cost the same.
InstructionCost Discount = 0;
// Holds instructions to analyze. The instructions we visit are mapped in
// ScalarCosts. Those instructions are the ones that would be scalarized if
// we find that the scalar version costs less.
SmallVector<Instruction *, 8> Worklist;
// Returns true if the given instruction can be scalarized.
auto canBeScalarized = [&](Instruction *I) -> bool {
// We only attempt to scalarize instructions forming a single-use chain
// from the original predicated block that would otherwise be vectorized.
// Although not strictly necessary, we give up on instructions we know will
// already be scalar to avoid traversing chains that are unlikely to be
// beneficial.
if (!I->hasOneUse() || PredInst->getParent() != I->getParent() ||
isScalarAfterVectorization(I, VF))
return false;
// If the instruction is scalar with predication, it will be analyzed
// separately. We ignore it within the context of PredInst.
if (isScalarWithPredication(I, VF))
return false;
// If any of the instruction's operands are uniform after vectorization,
// the instruction cannot be scalarized. This prevents, for example, a
// masked load from being scalarized.
//
// We assume we will only emit a value for lane zero of an instruction
// marked uniform after vectorization, rather than VF identical values.
// Thus, if we scalarize an instruction that uses a uniform, we would
// create uses of values corresponding to the lanes we aren't emitting code
// for. This behavior can be changed by allowing getScalarValue to clone
// the lane zero values for uniforms rather than asserting.
for (Use &U : I->operands())
if (auto *J = dyn_cast<Instruction>(U.get()))
if (isUniformAfterVectorization(J, VF))
return false;
// Otherwise, we can scalarize the instruction.
return true;
};
// Compute the expected cost discount from scalarizing the entire expression
// feeding the predicated instruction. We currently only consider expressions
// that are single-use instruction chains.
Worklist.push_back(PredInst);
while (!Worklist.empty()) {
Instruction *I = Worklist.pop_back_val();
// If we've already analyzed the instruction, there's nothing to do.
if (ScalarCosts.find(I) != ScalarCosts.end())
continue;
// Compute the cost of the vector instruction. Note that this cost already
// includes the scalarization overhead of the predicated instruction.
InstructionCost VectorCost = getInstructionCost(I, VF).first;
// Compute the cost of the scalarized instruction. This cost is the cost of
// the instruction as if it wasn't if-converted and instead remained in the
// predicated block. We will scale this cost by block probability after
// computing the scalarization overhead.
InstructionCost ScalarCost =
VF.getFixedValue() *
getInstructionCost(I, ElementCount::getFixed(1)).first;
// Compute the scalarization overhead of needed insertelement instructions
// and phi nodes.
if (isScalarWithPredication(I, VF) && !I->getType()->isVoidTy()) {
ScalarCost += TTI.getScalarizationOverhead(
cast<VectorType>(ToVectorTy(I->getType(), VF)),
APInt::getAllOnes(VF.getFixedValue()), true, false);
ScalarCost +=
VF.getFixedValue() *
TTI.getCFInstrCost(Instruction::PHI, TTI::TCK_RecipThroughput);
}
// Compute the scalarization overhead of needed extractelement
// instructions. For each of the instruction's operands, if the operand can
// be scalarized, add it to the worklist; otherwise, account for the
// overhead.
for (Use &U : I->operands())
if (auto *J = dyn_cast<Instruction>(U.get())) {
assert(VectorType::isValidElementType(J->getType()) &&
"Instruction has non-scalar type");
if (canBeScalarized(J))
Worklist.push_back(J);
else if (needsExtract(J, VF)) {
ScalarCost += TTI.getScalarizationOverhead(
cast<VectorType>(ToVectorTy(J->getType(), VF)),
APInt::getAllOnes(VF.getFixedValue()), false, true);
}
}
// Scale the total scalar cost by block probability.
ScalarCost /= getReciprocalPredBlockProb();
// Compute the discount. A non-negative discount means the vector version
// of the instruction costs more, and scalarizing would be beneficial.
Discount += VectorCost - ScalarCost;
ScalarCosts[I] = ScalarCost;
}
return *Discount.getValue();
}
LoopVectorizationCostModel::VectorizationCostTy
LoopVectorizationCostModel::expectedCost(
ElementCount VF, SmallVectorImpl<InstructionVFPair> *Invalid) {
VectorizationCostTy Cost;
// For each block.
for (BasicBlock *BB : TheLoop->blocks()) {
VectorizationCostTy BlockCost;
// For each instruction in the old loop.
for (Instruction &I : BB->instructionsWithoutDebug()) {
// Skip ignored values.
if (ValuesToIgnore.count(&I) ||
(VF.isVector() && VecValuesToIgnore.count(&I)))
continue;
VectorizationCostTy C = getInstructionCost(&I, VF);
// Check if we should override the cost.
if (C.first.isValid() &&
ForceTargetInstructionCost.getNumOccurrences() > 0)
C.first = InstructionCost(ForceTargetInstructionCost);
// Keep a list of instructions with invalid costs.
if (Invalid && !C.first.isValid())
Invalid->emplace_back(&I, VF);
BlockCost.first += C.first;
BlockCost.second |= C.second;
LLVM_DEBUG(dbgs() << "LV: Found an estimated cost of " << C.first
<< " for VF " << VF << " For instruction: " << I
<< '\n');
}
// If we are vectorizing a predicated block, it will have been
// if-converted. This means that the block's instructions (aside from
// stores and instructions that may divide by zero) will now be
// unconditionally executed. For the scalar case, we may not always execute
// the predicated block, if it is an if-else block. Thus, scale the block's
// cost by the probability of executing it. blockNeedsPredication from
// Legal is used so as to not include all blocks in tail folded loops.
if (VF.isScalar() && Legal->blockNeedsPredication(BB))
BlockCost.first /= getReciprocalPredBlockProb();
Cost.first += BlockCost.first;
Cost.second |= BlockCost.second;
}
return Cost;
}
/// Gets Address Access SCEV after verifying that the access pattern
/// is loop invariant except the induction variable dependence.
///
/// This SCEV can be sent to the Target in order to estimate the address
/// calculation cost.
static const SCEV *getAddressAccessSCEV(
Value *Ptr,
LoopVectorizationLegality *Legal,
PredicatedScalarEvolution &PSE,
const Loop *TheLoop) {
auto *Gep = dyn_cast<GetElementPtrInst>(Ptr);
if (!Gep)
return nullptr;
// We are looking for a gep with all loop invariant indices except for one
// which should be an induction variable.
auto SE = PSE.getSE();
unsigned NumOperands = Gep->getNumOperands();
for (unsigned i = 1; i < NumOperands; ++i) {
Value *Opd = Gep->getOperand(i);
if (!SE->isLoopInvariant(SE->getSCEV(Opd), TheLoop) &&
!Legal->isInductionVariable(Opd))
return nullptr;
}
// Now we know we have a GEP ptr, %inv, %ind, %inv. return the Ptr SCEV.
return PSE.getSCEV(Ptr);
}
static bool isStrideMul(Instruction *I, LoopVectorizationLegality *Legal) {
return Legal->hasStride(I->getOperand(0)) ||
Legal->hasStride(I->getOperand(1));
}
InstructionCost
LoopVectorizationCostModel::getMemInstScalarizationCost(Instruction *I,
ElementCount VF) {
assert(VF.isVector() &&
"Scalarization cost of instruction implies vectorization.");
if (VF.isScalable())
return InstructionCost::getInvalid();
Type *ValTy = getLoadStoreType(I);
auto SE = PSE.getSE();
unsigned AS = getLoadStoreAddressSpace(I);
Value *Ptr = getLoadStorePointerOperand(I);
Type *PtrTy = ToVectorTy(Ptr->getType(), VF);
// NOTE: PtrTy is a vector to signal `TTI::getAddressComputationCost`
// that it is being called from this specific place.
// Figure out whether the access is strided and get the stride value
// if it's known in compile time
const SCEV *PtrSCEV = getAddressAccessSCEV(Ptr, Legal, PSE, TheLoop);
// Get the cost of the scalar memory instruction and address computation.
InstructionCost Cost =
VF.getKnownMinValue() * TTI.getAddressComputationCost(PtrTy, SE, PtrSCEV);
// Don't pass *I here, since it is scalar but will actually be part of a
// vectorized loop where the user of it is a vectorized instruction.
const Align Alignment = getLoadStoreAlignment(I);
Cost += VF.getKnownMinValue() *
TTI.getMemoryOpCost(I->getOpcode(), ValTy->getScalarType(), Alignment,
AS, TTI::TCK_RecipThroughput);
// Get the overhead of the extractelement and insertelement instructions
// we might create due to scalarization.
Cost += getScalarizationOverhead(I, VF);
// If we have a predicated load/store, it will need extra i1 extracts and
// conditional branches, but may not be executed for each vector lane. Scale
// the cost by the probability of executing the predicated block.
if (isPredicatedInst(I, VF)) {
Cost /= getReciprocalPredBlockProb();
// Add the cost of an i1 extract and a branch
auto *Vec_i1Ty =
VectorType::get(IntegerType::getInt1Ty(ValTy->getContext()), VF);
Cost += TTI.getScalarizationOverhead(
Vec_i1Ty, APInt::getAllOnes(VF.getKnownMinValue()),
/*Insert=*/false, /*Extract=*/true);
Cost += TTI.getCFInstrCost(Instruction::Br, TTI::TCK_RecipThroughput);
if (useEmulatedMaskMemRefHack(I, VF))
// Artificially setting to a high enough value to practically disable
// vectorization with such operations.
Cost = 3000000;
}
return Cost;
}
InstructionCost
LoopVectorizationCostModel::getConsecutiveMemOpCost(Instruction *I,
ElementCount VF) {
Type *ValTy = getLoadStoreType(I);
auto *VectorTy = cast<VectorType>(ToVectorTy(ValTy, VF));
Value *Ptr = getLoadStorePointerOperand(I);
unsigned AS = getLoadStoreAddressSpace(I);
int ConsecutiveStride = Legal->isConsecutivePtr(ValTy, Ptr);
enum TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
assert((ConsecutiveStride == 1 || ConsecutiveStride == -1) &&
"Stride should be 1 or -1 for consecutive memory access");
const Align Alignment = getLoadStoreAlignment(I);
InstructionCost Cost = 0;
if (Legal->isMaskRequired(I))
Cost += TTI.getMaskedMemoryOpCost(I->getOpcode(), VectorTy, Alignment, AS,
CostKind);
else
Cost += TTI.getMemoryOpCost(I->getOpcode(), VectorTy, Alignment, AS,
CostKind, I);
bool Reverse = ConsecutiveStride < 0;
if (Reverse)
Cost +=
TTI.getShuffleCost(TargetTransformInfo::SK_Reverse, VectorTy, None, 0);
return Cost;
}
InstructionCost
LoopVectorizationCostModel::getUniformMemOpCost(Instruction *I,
ElementCount VF) {
assert(Legal->isUniformMemOp(*I));
Type *ValTy = getLoadStoreType(I);
auto *VectorTy = cast<VectorType>(ToVectorTy(ValTy, VF));
const Align Alignment = getLoadStoreAlignment(I);
unsigned AS = getLoadStoreAddressSpace(I);
enum TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
if (isa<LoadInst>(I)) {
return TTI.getAddressComputationCost(ValTy) +
TTI.getMemoryOpCost(Instruction::Load, ValTy, Alignment, AS,
CostKind) +
TTI.getShuffleCost(TargetTransformInfo::SK_Broadcast, VectorTy);
}
StoreInst *SI = cast<StoreInst>(I);
bool isLoopInvariantStoreValue = Legal->isUniform(SI->getValueOperand());
return TTI.getAddressComputationCost(ValTy) +
TTI.getMemoryOpCost(Instruction::Store, ValTy, Alignment, AS,
CostKind) +
(isLoopInvariantStoreValue
? 0
: TTI.getVectorInstrCost(Instruction::ExtractElement, VectorTy,
VF.getKnownMinValue() - 1));
}
InstructionCost
LoopVectorizationCostModel::getGatherScatterCost(Instruction *I,
ElementCount VF) {
Type *ValTy = getLoadStoreType(I);
auto *VectorTy = cast<VectorType>(ToVectorTy(ValTy, VF));
const Align Alignment = getLoadStoreAlignment(I);
const Value *Ptr = getLoadStorePointerOperand(I);
return TTI.getAddressComputationCost(VectorTy) +
TTI.getGatherScatterOpCost(
I->getOpcode(), VectorTy, Ptr, Legal->isMaskRequired(I), Alignment,
TargetTransformInfo::TCK_RecipThroughput, I);
}
InstructionCost
LoopVectorizationCostModel::getInterleaveGroupCost(Instruction *I,
ElementCount VF) {
// TODO: Once we have support for interleaving with scalable vectors
// we can calculate the cost properly here.
if (VF.isScalable())
return InstructionCost::getInvalid();
Type *ValTy = getLoadStoreType(I);
auto *VectorTy = cast<VectorType>(ToVectorTy(ValTy, VF));
unsigned AS = getLoadStoreAddressSpace(I);
auto Group = getInterleavedAccessGroup(I);
assert(Group && "Fail to get an interleaved access group.");
unsigned InterleaveFactor = Group->getFactor();
auto *WideVecTy = VectorType::get(ValTy, VF * InterleaveFactor);
// Holds the indices of existing members in the interleaved group.
SmallVector<unsigned, 4> Indices;
for (unsigned IF = 0; IF < InterleaveFactor; IF++)
if (Group->getMember(IF))
Indices.push_back(IF);
// Calculate the cost of the whole interleaved group.
bool UseMaskForGaps =
(Group->requiresScalarEpilogue() && !isScalarEpilogueAllowed()) ||
(isa<StoreInst>(I) && (Group->getNumMembers() < Group->getFactor()));
InstructionCost Cost = TTI.getInterleavedMemoryOpCost(
I->getOpcode(), WideVecTy, Group->getFactor(), Indices, Group->getAlign(),
AS, TTI::TCK_RecipThroughput, Legal->isMaskRequired(I), UseMaskForGaps);
if (Group->isReverse()) {
// TODO: Add support for reversed masked interleaved access.
assert(!Legal->isMaskRequired(I) &&
"Reverse masked interleaved access not supported.");
Cost +=
Group->getNumMembers() *
TTI.getShuffleCost(TargetTransformInfo::SK_Reverse, VectorTy, None, 0);
}
return Cost;
}
Optional<InstructionCost> LoopVectorizationCostModel::getReductionPatternCost(
Instruction *I, ElementCount VF, Type *Ty, TTI::TargetCostKind CostKind) {
using namespace llvm::PatternMatch;
// Early exit for no inloop reductions
if (InLoopReductionChains.empty() || VF.isScalar() || !isa<VectorType>(Ty))
return None;
auto *VectorTy = cast<VectorType>(Ty);
// We are looking for a pattern of, and finding the minimal acceptable cost:
// reduce(mul(ext(A), ext(B))) or
// reduce(mul(A, B)) or
// reduce(ext(A)) or
// reduce(A).
// The basic idea is that we walk down the tree to do that, finding the root
// reduction instruction in InLoopReductionImmediateChains. From there we find
// the pattern of mul/ext and test the cost of the entire pattern vs the cost
// of the components. If the reduction cost is lower then we return it for the
// reduction instruction and 0 for the other instructions in the pattern. If
// it is not we return an invalid cost specifying the orignal cost method
// should be used.
Instruction *RetI = I;
if (match(RetI, m_ZExtOrSExt(m_Value()))) {
if (!RetI->hasOneUser())
return None;
RetI = RetI->user_back();
}
if (match(RetI, m_Mul(m_Value(), m_Value())) &&
RetI->user_back()->getOpcode() == Instruction::Add) {
if (!RetI->hasOneUser())
return None;
RetI = RetI->user_back();
}
// Test if the found instruction is a reduction, and if not return an invalid
// cost specifying the parent to use the original cost modelling.
if (!InLoopReductionImmediateChains.count(RetI))
return None;
// Find the reduction this chain is a part of and calculate the basic cost of
// the reduction on its own.
Instruction *LastChain = InLoopReductionImmediateChains[RetI];
Instruction *ReductionPhi = LastChain;
while (!isa<PHINode>(ReductionPhi))
ReductionPhi = InLoopReductionImmediateChains[ReductionPhi];
const RecurrenceDescriptor &RdxDesc =
Legal->getReductionVars().find(cast<PHINode>(ReductionPhi))->second;
InstructionCost BaseCost = TTI.getArithmeticReductionCost(
RdxDesc.getOpcode(), VectorTy, RdxDesc.getFastMathFlags(), CostKind);
// For a call to the llvm.fmuladd intrinsic we need to add the cost of a
// normal fmul instruction to the cost of the fadd reduction.
if (RdxDesc.getRecurrenceKind() == RecurKind::FMulAdd)
BaseCost +=
TTI.getArithmeticInstrCost(Instruction::FMul, VectorTy, CostKind);
// If we're using ordered reductions then we can just return the base cost
// here, since getArithmeticReductionCost calculates the full ordered
// reduction cost when FP reassociation is not allowed.
if (useOrderedReductions(RdxDesc))
return BaseCost;
// Get the operand that was not the reduction chain and match it to one of the
// patterns, returning the better cost if it is found.
Instruction *RedOp = RetI->getOperand(1) == LastChain
? dyn_cast<Instruction>(RetI->getOperand(0))
: dyn_cast<Instruction>(RetI->getOperand(1));
VectorTy = VectorType::get(I->getOperand(0)->getType(), VectorTy);
Instruction *Op0, *Op1;
if (RedOp &&
match(RedOp,
m_ZExtOrSExt(m_Mul(m_Instruction(Op0), m_Instruction(Op1)))) &&
match(Op0, m_ZExtOrSExt(m_Value())) &&
Op0->getOpcode() == Op1->getOpcode() &&
Op0->getOperand(0)->getType() == Op1->getOperand(0)->getType() &&
!TheLoop->isLoopInvariant(Op0) && !TheLoop->isLoopInvariant(Op1) &&
(Op0->getOpcode() == RedOp->getOpcode() || Op0 == Op1)) {
// Matched reduce(ext(mul(ext(A), ext(B)))
// Note that the extend opcodes need to all match, or if A==B they will have
// been converted to zext(mul(sext(A), sext(A))) as it is known positive,
// which is equally fine.
bool IsUnsigned = isa<ZExtInst>(Op0);
auto *ExtType = VectorType::get(Op0->getOperand(0)->getType(), VectorTy);
auto *MulType = VectorType::get(Op0->getType(), VectorTy);
InstructionCost ExtCost =
TTI.getCastInstrCost(Op0->getOpcode(), MulType, ExtType,
TTI::CastContextHint::None, CostKind, Op0);
InstructionCost MulCost =
TTI.getArithmeticInstrCost(Instruction::Mul, MulType, CostKind);
InstructionCost Ext2Cost =
TTI.getCastInstrCost(RedOp->getOpcode(), VectorTy, MulType,
TTI::CastContextHint::None, CostKind, RedOp);
InstructionCost RedCost = TTI.getExtendedAddReductionCost(
/*IsMLA=*/true, IsUnsigned, RdxDesc.getRecurrenceType(), ExtType,
CostKind);
if (RedCost.isValid() &&
RedCost < ExtCost * 2 + MulCost + Ext2Cost + BaseCost)
return I == RetI ? RedCost : 0;
} else if (RedOp && match(RedOp, m_ZExtOrSExt(m_Value())) &&
!TheLoop->isLoopInvariant(RedOp)) {
// Matched reduce(ext(A))
bool IsUnsigned = isa<ZExtInst>(RedOp);
auto *ExtType = VectorType::get(RedOp->getOperand(0)->getType(), VectorTy);
InstructionCost RedCost = TTI.getExtendedAddReductionCost(
/*IsMLA=*/false, IsUnsigned, RdxDesc.getRecurrenceType(), ExtType,
CostKind);
InstructionCost ExtCost =
TTI.getCastInstrCost(RedOp->getOpcode(), VectorTy, ExtType,
TTI::CastContextHint::None, CostKind, RedOp);
if (RedCost.isValid() && RedCost < BaseCost + ExtCost)
return I == RetI ? RedCost : 0;
} else if (RedOp &&
match(RedOp, m_Mul(m_Instruction(Op0), m_Instruction(Op1)))) {
if (match(Op0, m_ZExtOrSExt(m_Value())) &&
Op0->getOpcode() == Op1->getOpcode() &&
!TheLoop->isLoopInvariant(Op0) && !TheLoop->isLoopInvariant(Op1)) {
bool IsUnsigned = isa<ZExtInst>(Op0);
Type *Op0Ty = Op0->getOperand(0)->getType();
Type *Op1Ty = Op1->getOperand(0)->getType();
Type *LargestOpTy =
Op0Ty->getIntegerBitWidth() < Op1Ty->getIntegerBitWidth() ? Op1Ty
: Op0Ty;
auto *ExtType = VectorType::get(LargestOpTy, VectorTy);
// Matched reduce(mul(ext(A), ext(B))), where the two ext may be of
// different sizes. We take the largest type as the ext to reduce, and add
// the remaining cost as, for example reduce(mul(ext(ext(A)), ext(B))).
InstructionCost ExtCost0 = TTI.getCastInstrCost(
Op0->getOpcode(), VectorTy, VectorType::get(Op0Ty, VectorTy),
TTI::CastContextHint::None, CostKind, Op0);
InstructionCost ExtCost1 = TTI.getCastInstrCost(
Op1->getOpcode(), VectorTy, VectorType::get(Op1Ty, VectorTy),
TTI::CastContextHint::None, CostKind, Op1);
InstructionCost MulCost =
TTI.getArithmeticInstrCost(Instruction::Mul, VectorTy, CostKind);
InstructionCost RedCost = TTI.getExtendedAddReductionCost(
/*IsMLA=*/true, IsUnsigned, RdxDesc.getRecurrenceType(), ExtType,
CostKind);
InstructionCost ExtraExtCost = 0;
if (Op0Ty != LargestOpTy || Op1Ty != LargestOpTy) {
Instruction *ExtraExtOp = (Op0Ty != LargestOpTy) ? Op0 : Op1;
ExtraExtCost = TTI.getCastInstrCost(
ExtraExtOp->getOpcode(), ExtType,
VectorType::get(ExtraExtOp->getOperand(0)->getType(), VectorTy),
TTI::CastContextHint::None, CostKind, ExtraExtOp);
}
if (RedCost.isValid() &&
(RedCost + ExtraExtCost) < (ExtCost0 + ExtCost1 + MulCost + BaseCost))
return I == RetI ? RedCost : 0;
} else if (!match(I, m_ZExtOrSExt(m_Value()))) {
// Matched reduce(mul())
InstructionCost MulCost =
TTI.getArithmeticInstrCost(Instruction::Mul, VectorTy, CostKind);
InstructionCost RedCost = TTI.getExtendedAddReductionCost(
/*IsMLA=*/true, true, RdxDesc.getRecurrenceType(), VectorTy,
CostKind);
if (RedCost.isValid() && RedCost < MulCost + BaseCost)
return I == RetI ? RedCost : 0;
}
}
return I == RetI ? Optional<InstructionCost>(BaseCost) : None;
}
InstructionCost
LoopVectorizationCostModel::getMemoryInstructionCost(Instruction *I,
ElementCount VF) {
// Calculate scalar cost only. Vectorization cost should be ready at this
// moment.
if (VF.isScalar()) {
Type *ValTy = getLoadStoreType(I);
const Align Alignment = getLoadStoreAlignment(I);
unsigned AS = getLoadStoreAddressSpace(I);
return TTI.getAddressComputationCost(ValTy) +
TTI.getMemoryOpCost(I->getOpcode(), ValTy, Alignment, AS,
TTI::TCK_RecipThroughput, I);
}
return getWideningCost(I, VF);
}
LoopVectorizationCostModel::VectorizationCostTy
LoopVectorizationCostModel::getInstructionCost(Instruction *I,
ElementCount VF) {
// If we know that this instruction will remain uniform, check the cost of
// the scalar version.
if (isUniformAfterVectorization(I, VF))
VF = ElementCount::getFixed(1);
if (VF.isVector() && isProfitableToScalarize(I, VF))
return VectorizationCostTy(InstsToScalarize[VF][I], false);
// Forced scalars do not have any scalarization overhead.
auto ForcedScalar = ForcedScalars.find(VF);
if (VF.isVector() && ForcedScalar != ForcedScalars.end()) {
auto InstSet = ForcedScalar->second;
if (InstSet.count(I))
return VectorizationCostTy(
(getInstructionCost(I, ElementCount::getFixed(1)).first *
VF.getKnownMinValue()),
false);
}
Type *VectorTy;
InstructionCost C = getInstructionCost(I, VF, VectorTy);
bool TypeNotScalarized = false;
if (VF.isVector() && VectorTy->isVectorTy()) {
if (unsigned NumParts = TTI.getNumberOfParts(VectorTy)) {
if (VF.isScalable())
// <vscale x 1 x iN> is assumed to be profitable over iN because
// scalable registers are a distinct register class from scalar ones.
// If we ever find a target which wants to lower scalable vectors
// back to scalars, we'll need to update this code to explicitly
// ask TTI about the register class uses for each part.
TypeNotScalarized = NumParts <= VF.getKnownMinValue();
else
TypeNotScalarized = NumParts < VF.getKnownMinValue();
} else
C = InstructionCost::getInvalid();
}
return VectorizationCostTy(C, TypeNotScalarized);
}
InstructionCost
LoopVectorizationCostModel::getScalarizationOverhead(Instruction *I,
ElementCount VF) const {
// There is no mechanism yet to create a scalable scalarization loop,
// so this is currently Invalid.
if (VF.isScalable())
return InstructionCost::getInvalid();
if (VF.isScalar())
return 0;
InstructionCost Cost = 0;
Type *RetTy = ToVectorTy(I->getType(), VF);
if (!RetTy->isVoidTy() &&
(!isa<LoadInst>(I) || !TTI.supportsEfficientVectorElementLoadStore()))
Cost += TTI.getScalarizationOverhead(
cast<VectorType>(RetTy), APInt::getAllOnes(VF.getKnownMinValue()), true,
false);
// Some targets keep addresses scalar.
if (isa<LoadInst>(I) && !TTI.prefersVectorizedAddressing())
return Cost;
// Some targets support efficient element stores.
if (isa<StoreInst>(I) && TTI.supportsEfficientVectorElementLoadStore())
return Cost;
// Collect operands to consider.
CallInst *CI = dyn_cast<CallInst>(I);
Instruction::op_range Ops = CI ? CI->args() : I->operands();
// Skip operands that do not require extraction/scalarization and do not incur
// any overhead.
SmallVector<Type *> Tys;
for (auto *V : filterExtractingOperands(Ops, VF))
Tys.push_back(MaybeVectorizeType(V->getType(), VF));
return Cost + TTI.getOperandsScalarizationOverhead(
filterExtractingOperands(Ops, VF), Tys);
}
void LoopVectorizationCostModel::setCostBasedWideningDecision(ElementCount VF) {
if (VF.isScalar())
return;
NumPredStores = 0;
for (BasicBlock *BB : TheLoop->blocks()) {
// For each instruction in the old loop.
for (Instruction &I : *BB) {
Value *Ptr = getLoadStorePointerOperand(&I);
if (!Ptr)
continue;
// TODO: We should generate better code and update the cost model for
// predicated uniform stores. Today they are treated as any other
// predicated store (see added test cases in
// invariant-store-vectorization.ll).
if (isa<StoreInst>(&I) && isScalarWithPredication(&I, VF))
NumPredStores++;
if (Legal->isUniformMemOp(I)) {
// Lowering story for uniform memory ops is currently a bit complicated.
// Scalarization works for everything which isn't a store with scalable
// VF. Fixed len VFs just scalarize and then DCE later; scalarization
// knows how to handle uniform-per-part values (i.e. the first lane
// in each unrolled VF) and can thus handle scalable loads too. For
// scalable stores, we use a scatter if legal. If not, we have no way
// to lower (currently) and thus have to abort vectorization.
if (isa<StoreInst>(&I) && VF.isScalable()) {
if (isLegalGatherOrScatter(&I, VF))
setWideningDecision(&I, VF, CM_GatherScatter,
getGatherScatterCost(&I, VF));
else
// Error case, abort vectorization
setWideningDecision(&I, VF, CM_Scalarize,
InstructionCost::getInvalid());
continue;
}
// Load: Scalar load + broadcast
// Store: Scalar store + isLoopInvariantStoreValue ? 0 : extract
// TODO: Avoid replicating loads and stores instead of relying on
// instcombine to remove them.
setWideningDecision(&I, VF, CM_Scalarize,
getUniformMemOpCost(&I, VF));
continue;
}
// We assume that widening is the best solution when possible.
if (memoryInstructionCanBeWidened(&I, VF)) {
InstructionCost Cost = getConsecutiveMemOpCost(&I, VF);
int ConsecutiveStride = Legal->isConsecutivePtr(
getLoadStoreType(&I), getLoadStorePointerOperand(&I));
assert((ConsecutiveStride == 1 || ConsecutiveStride == -1) &&
"Expected consecutive stride.");
InstWidening Decision =
ConsecutiveStride == 1 ? CM_Widen : CM_Widen_Reverse;
setWideningDecision(&I, VF, Decision, Cost);
continue;
}
// Choose between Interleaving, Gather/Scatter or Scalarization.
InstructionCost InterleaveCost = InstructionCost::getInvalid();
unsigned NumAccesses = 1;
if (isAccessInterleaved(&I)) {
auto Group = getInterleavedAccessGroup(&I);
assert(Group && "Fail to get an interleaved access group.");
// Make one decision for the whole group.
if (getWideningDecision(&I, VF) != CM_Unknown)
continue;
NumAccesses = Group->getNumMembers();
if (interleavedAccessCanBeWidened(&I, VF))
InterleaveCost = getInterleaveGroupCost(&I, VF);
}
InstructionCost GatherScatterCost =
isLegalGatherOrScatter(&I, VF)
? getGatherScatterCost(&I, VF) * NumAccesses
: InstructionCost::getInvalid();
InstructionCost ScalarizationCost =
getMemInstScalarizationCost(&I, VF) * NumAccesses;
// Choose better solution for the current VF,
// write down this decision and use it during vectorization.
InstructionCost Cost;
InstWidening Decision;
if (InterleaveCost <= GatherScatterCost &&
InterleaveCost < ScalarizationCost) {
Decision = CM_Interleave;
Cost = InterleaveCost;
} else if (GatherScatterCost < ScalarizationCost) {
Decision = CM_GatherScatter;
Cost = GatherScatterCost;
} else {
Decision = CM_Scalarize;
Cost = ScalarizationCost;
}
// If the instructions belongs to an interleave group, the whole group
// receives the same decision. The whole group receives the cost, but
// the cost will actually be assigned to one instruction.
if (auto Group = getInterleavedAccessGroup(&I))
setWideningDecision(Group, VF, Decision, Cost);
else
setWideningDecision(&I, VF, Decision, Cost);
}
}
// Make sure that any load of address and any other address computation
// remains scalar unless there is gather/scatter support. This avoids
// inevitable extracts into address registers, and also has the benefit of
// activating LSR more, since that pass can't optimize vectorized
// addresses.
if (TTI.prefersVectorizedAddressing())
return;
// Start with all scalar pointer uses.
SmallPtrSet<Instruction *, 8> AddrDefs;
for (BasicBlock *BB : TheLoop->blocks())
for (Instruction &I : *BB) {
Instruction *PtrDef =
dyn_cast_or_null<Instruction>(getLoadStorePointerOperand(&I));
if (PtrDef && TheLoop->contains(PtrDef) &&
getWideningDecision(&I, VF) != CM_GatherScatter)
AddrDefs.insert(PtrDef);
}
// Add all instructions used to generate the addresses.
SmallVector<Instruction *, 4> Worklist;
append_range(Worklist, AddrDefs);
while (!Worklist.empty()) {
Instruction *I = Worklist.pop_back_val();
for (auto &Op : I->operands())
if (auto *InstOp = dyn_cast<Instruction>(Op))
if ((InstOp->getParent() == I->getParent()) && !isa<PHINode>(InstOp) &&
AddrDefs.insert(InstOp).second)
Worklist.push_back(InstOp);
}
for (auto *I : AddrDefs) {
if (isa<LoadInst>(I)) {
// Setting the desired widening decision should ideally be handled in
// by cost functions, but since this involves the task of finding out
// if the loaded register is involved in an address computation, it is
// instead changed here when we know this is the case.
InstWidening Decision = getWideningDecision(I, VF);
if (Decision == CM_Widen || Decision == CM_Widen_Reverse)
// Scalarize a widened load of address.
setWideningDecision(
I, VF, CM_Scalarize,
(VF.getKnownMinValue() *
getMemoryInstructionCost(I, ElementCount::getFixed(1))));
else if (auto Group = getInterleavedAccessGroup(I)) {
// Scalarize an interleave group of address loads.
for (unsigned I = 0; I < Group->getFactor(); ++I) {
if (Instruction *Member = Group->getMember(I))
setWideningDecision(
Member, VF, CM_Scalarize,
(VF.getKnownMinValue() *
getMemoryInstructionCost(Member, ElementCount::getFixed(1))));
}
}
} else
// Make sure I gets scalarized and a cost estimate without
// scalarization overhead.
ForcedScalars[VF].insert(I);
}
}
InstructionCost
LoopVectorizationCostModel::getInstructionCost(Instruction *I, ElementCount VF,
Type *&VectorTy) {
Type *RetTy = I->getType();
if (canTruncateToMinimalBitwidth(I, VF))
RetTy = IntegerType::get(RetTy->getContext(), MinBWs[I]);
auto SE = PSE.getSE();
TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
auto hasSingleCopyAfterVectorization = [this](Instruction *I,
ElementCount VF) -> bool {
if (VF.isScalar())
return true;
auto Scalarized = InstsToScalarize.find(VF);
assert(Scalarized != InstsToScalarize.end() &&
"VF not yet analyzed for scalarization profitability");
return !Scalarized->second.count(I) &&
llvm::all_of(I->users(), [&](User *U) {
auto *UI = cast<Instruction>(U);
return !Scalarized->second.count(UI);
});
};
(void) hasSingleCopyAfterVectorization;
if (isScalarAfterVectorization(I, VF)) {
// With the exception of GEPs and PHIs, after scalarization there should
// only be one copy of the instruction generated in the loop. This is
// because the VF is either 1, or any instructions that need scalarizing
// have already been dealt with by the the time we get here. As a result,
// it means we don't have to multiply the instruction cost by VF.
assert(I->getOpcode() == Instruction::GetElementPtr ||
I->getOpcode() == Instruction::PHI ||
(I->getOpcode() == Instruction::BitCast &&
I->getType()->isPointerTy()) ||
hasSingleCopyAfterVectorization(I, VF));
VectorTy = RetTy;
} else
VectorTy = ToVectorTy(RetTy, VF);
// TODO: We need to estimate the cost of intrinsic calls.
switch (I->getOpcode()) {
case Instruction::GetElementPtr:
// We mark this instruction as zero-cost because the cost of GEPs in
// vectorized code depends on whether the corresponding memory instruction
// is scalarized or not. Therefore, we handle GEPs with the memory
// instruction cost.
return 0;
case Instruction::Br: {
// In cases of scalarized and predicated instructions, there will be VF
// predicated blocks in the vectorized loop. Each branch around these
// blocks requires also an extract of its vector compare i1 element.
bool ScalarPredicatedBB = false;
BranchInst *BI = cast<BranchInst>(I);
if (VF.isVector() && BI->isConditional() &&
(PredicatedBBsAfterVectorization[VF].count(BI->getSuccessor(0)) ||
PredicatedBBsAfterVectorization[VF].count(BI->getSuccessor(1))))
ScalarPredicatedBB = true;
if (ScalarPredicatedBB) {
// Not possible to scalarize scalable vector with predicated instructions.
if (VF.isScalable())
return InstructionCost::getInvalid();
// Return cost for branches around scalarized and predicated blocks.
auto *Vec_i1Ty =
VectorType::get(IntegerType::getInt1Ty(RetTy->getContext()), VF);
return (
TTI.getScalarizationOverhead(
Vec_i1Ty, APInt::getAllOnes(VF.getFixedValue()), false, true) +
(TTI.getCFInstrCost(Instruction::Br, CostKind) * VF.getFixedValue()));
} else if (I->getParent() == TheLoop->getLoopLatch() || VF.isScalar())
// The back-edge branch will remain, as will all scalar branches.
return TTI.getCFInstrCost(Instruction::Br, CostKind);
else
// This branch will be eliminated by if-conversion.
return 0;
// Note: We currently assume zero cost for an unconditional branch inside
// a predicated block since it will become a fall-through, although we
// may decide in the future to call TTI for all branches.
}
case Instruction::PHI: {
auto *Phi = cast<PHINode>(I);
// First-order recurrences are replaced by vector shuffles inside the loop.
// NOTE: Don't use ToVectorTy as SK_ExtractSubvector expects a vector type.
if (VF.isVector() && Legal->isFirstOrderRecurrence(Phi))
return TTI.getShuffleCost(
TargetTransformInfo::SK_ExtractSubvector, cast<VectorType>(VectorTy),
None, VF.getKnownMinValue() - 1, FixedVectorType::get(RetTy, 1));
// Phi nodes in non-header blocks (not inductions, reductions, etc.) are
// converted into select instructions. We require N - 1 selects per phi
// node, where N is the number of incoming values.
if (VF.isVector() && Phi->getParent() != TheLoop->getHeader())
return (Phi->getNumIncomingValues() - 1) *
TTI.getCmpSelInstrCost(
Instruction::Select, ToVectorTy(Phi->getType(), VF),
ToVectorTy(Type::getInt1Ty(Phi->getContext()), VF),
CmpInst::BAD_ICMP_PREDICATE, CostKind);
return TTI.getCFInstrCost(Instruction::PHI, CostKind);
}
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::URem:
case Instruction::SRem:
// If we have a predicated instruction, it may not be executed for each
// vector lane. Get the scalarization cost and scale this amount by the
// probability of executing the predicated block. If the instruction is not
// predicated, we fall through to the next case.
if (VF.isVector() && isScalarWithPredication(I, VF)) {
InstructionCost Cost = 0;
// These instructions have a non-void type, so account for the phi nodes
// that we will create. This cost is likely to be zero. The phi node
// cost, if any, should be scaled by the block probability because it
// models a copy at the end of each predicated block.
Cost += VF.getKnownMinValue() *
TTI.getCFInstrCost(Instruction::PHI, CostKind);
// The cost of the non-predicated instruction.
Cost += VF.getKnownMinValue() *
TTI.getArithmeticInstrCost(I->getOpcode(), RetTy, CostKind);
// The cost of insertelement and extractelement instructions needed for
// scalarization.
Cost += getScalarizationOverhead(I, VF);
// Scale the cost by the probability of executing the predicated blocks.
// This assumes the predicated block for each vector lane is equally
// likely.
return Cost / getReciprocalPredBlockProb();
}
LLVM_FALLTHROUGH;
case Instruction::Add:
case Instruction::FAdd:
case Instruction::Sub:
case Instruction::FSub:
case Instruction::Mul:
case Instruction::FMul:
case Instruction::FDiv:
case Instruction::FRem:
case Instruction::Shl:
case Instruction::LShr:
case Instruction::AShr:
case Instruction::And:
case Instruction::Or:
case Instruction::Xor: {
// Since we will replace the stride by 1 the multiplication should go away.
if (I->getOpcode() == Instruction::Mul && isStrideMul(I, Legal))
return 0;
// Detect reduction patterns
if (auto RedCost = getReductionPatternCost(I, VF, VectorTy, CostKind))
return *RedCost;
// Certain instructions can be cheaper to vectorize if they have a constant
// second vector operand. One example of this are shifts on x86.
Value *Op2 = I->getOperand(1);
TargetTransformInfo::OperandValueProperties Op2VP;
TargetTransformInfo::OperandValueKind Op2VK =
TTI.getOperandInfo(Op2, Op2VP);
if (Op2VK == TargetTransformInfo::OK_AnyValue && Legal->isUniform(Op2))
Op2VK = TargetTransformInfo::OK_UniformValue;
SmallVector<const Value *, 4> Operands(I->operand_values());
return TTI.getArithmeticInstrCost(
I->getOpcode(), VectorTy, CostKind, TargetTransformInfo::OK_AnyValue,
Op2VK, TargetTransformInfo::OP_None, Op2VP, Operands, I);
}
case Instruction::FNeg: {
return TTI.getArithmeticInstrCost(
I->getOpcode(), VectorTy, CostKind, TargetTransformInfo::OK_AnyValue,
TargetTransformInfo::OK_AnyValue, TargetTransformInfo::OP_None,
TargetTransformInfo::OP_None, I->getOperand(0), I);
}
case Instruction::Select: {
SelectInst *SI = cast<SelectInst>(I);
const SCEV *CondSCEV = SE->getSCEV(SI->getCondition());
bool ScalarCond = (SE->isLoopInvariant(CondSCEV, TheLoop));
const Value *Op0, *Op1;
using namespace llvm::PatternMatch;
if (!ScalarCond && (match(I, m_LogicalAnd(m_Value(Op0), m_Value(Op1))) ||
match(I, m_LogicalOr(m_Value(Op0), m_Value(Op1))))) {
// select x, y, false --> x & y
// select x, true, y --> x | y
TTI::OperandValueProperties Op1VP = TTI::OP_None;
TTI::OperandValueProperties Op2VP = TTI::OP_None;
TTI::OperandValueKind Op1VK = TTI::getOperandInfo(Op0, Op1VP);
TTI::OperandValueKind Op2VK = TTI::getOperandInfo(Op1, Op2VP);
assert(Op0->getType()->getScalarSizeInBits() == 1 &&
Op1->getType()->getScalarSizeInBits() == 1);
SmallVector<const Value *, 2> Operands{Op0, Op1};
return TTI.getArithmeticInstrCost(
match(I, m_LogicalOr()) ? Instruction::Or : Instruction::And, VectorTy,
CostKind, Op1VK, Op2VK, Op1VP, Op2VP, Operands, I);
}
Type *CondTy = SI->getCondition()->getType();
if (!ScalarCond)
CondTy = VectorType::get(CondTy, VF);
CmpInst::Predicate Pred = CmpInst::BAD_ICMP_PREDICATE;
if (auto *Cmp = dyn_cast<CmpInst>(SI->getCondition()))
Pred = Cmp->getPredicate();
return TTI.getCmpSelInstrCost(I->getOpcode(), VectorTy, CondTy, Pred,
CostKind, I);
}
case Instruction::ICmp:
case Instruction::FCmp: {
Type *ValTy = I->getOperand(0)->getType();
Instruction *Op0AsInstruction = dyn_cast<Instruction>(I->getOperand(0));
if (canTruncateToMinimalBitwidth(Op0AsInstruction, VF))
ValTy = IntegerType::get(ValTy->getContext(), MinBWs[Op0AsInstruction]);
VectorTy = ToVectorTy(ValTy, VF);
return TTI.getCmpSelInstrCost(I->getOpcode(), VectorTy, nullptr,
cast<CmpInst>(I)->getPredicate(), CostKind,
I);
}
case Instruction::Store:
case Instruction::Load: {
ElementCount Width = VF;
if (Width.isVector()) {
InstWidening Decision = getWideningDecision(I, Width);
assert(Decision != CM_Unknown &&
"CM decision should be taken at this point");
if (getWideningCost(I, VF) == InstructionCost::getInvalid())
return InstructionCost::getInvalid();
if (Decision == CM_Scalarize)
Width = ElementCount::getFixed(1);
}
VectorTy = ToVectorTy(getLoadStoreType(I), Width);
return getMemoryInstructionCost(I, VF);
}
case Instruction::BitCast:
if (I->getType()->isPointerTy())
return 0;
LLVM_FALLTHROUGH;
case Instruction::ZExt:
case Instruction::SExt:
case Instruction::FPToUI:
case Instruction::FPToSI:
case Instruction::FPExt:
case Instruction::PtrToInt:
case Instruction::IntToPtr:
case Instruction::SIToFP:
case Instruction::UIToFP:
case Instruction::Trunc:
case Instruction::FPTrunc: {
// Computes the CastContextHint from a Load/Store instruction.
auto ComputeCCH = [&](Instruction *I) -> TTI::CastContextHint {
assert((isa<LoadInst>(I) || isa<StoreInst>(I)) &&
"Expected a load or a store!");
if (VF.isScalar() || !TheLoop->contains(I))
return TTI::CastContextHint::Normal;
switch (getWideningDecision(I, VF)) {
case LoopVectorizationCostModel::CM_GatherScatter:
return TTI::CastContextHint::GatherScatter;
case LoopVectorizationCostModel::CM_Interleave:
return TTI::CastContextHint::Interleave;
case LoopVectorizationCostModel::CM_Scalarize:
case LoopVectorizationCostModel::CM_Widen:
return Legal->isMaskRequired(I) ? TTI::CastContextHint::Masked
: TTI::CastContextHint::Normal;
case LoopVectorizationCostModel::CM_Widen_Reverse:
return TTI::CastContextHint::Reversed;
case LoopVectorizationCostModel::CM_Unknown:
llvm_unreachable("Instr did not go through cost modelling?");
}
llvm_unreachable("Unhandled case!");
};
unsigned Opcode = I->getOpcode();
TTI::CastContextHint CCH = TTI::CastContextHint::None;
// For Trunc, the context is the only user, which must be a StoreInst.
if (Opcode == Instruction::Trunc || Opcode == Instruction::FPTrunc) {
if (I->hasOneUse())
if (StoreInst *Store = dyn_cast<StoreInst>(*I->user_begin()))
CCH = ComputeCCH(Store);
}
// For Z/Sext, the context is the operand, which must be a LoadInst.
else if (Opcode == Instruction::ZExt || Opcode == Instruction::SExt ||
Opcode == Instruction::FPExt) {
if (LoadInst *Load = dyn_cast<LoadInst>(I->getOperand(0)))
CCH = ComputeCCH(Load);
}
// We optimize the truncation of induction variables having constant
// integer steps. The cost of these truncations is the same as the scalar
// operation.
if (isOptimizableIVTruncate(I, VF)) {
auto *Trunc = cast<TruncInst>(I);
return TTI.getCastInstrCost(Instruction::Trunc, Trunc->getDestTy(),
Trunc->getSrcTy(), CCH, CostKind, Trunc);
}
// Detect reduction patterns
if (auto RedCost = getReductionPatternCost(I, VF, VectorTy, CostKind))
return *RedCost;
Type *SrcScalarTy = I->getOperand(0)->getType();
Type *SrcVecTy =
VectorTy->isVectorTy() ? ToVectorTy(SrcScalarTy, VF) : SrcScalarTy;
if (canTruncateToMinimalBitwidth(I, VF)) {
// This cast is going to be shrunk. This may remove the cast or it might
// turn it into slightly different cast. For example, if MinBW == 16,
// "zext i8 %1 to i32" becomes "zext i8 %1 to i16".
//
// Calculate the modified src and dest types.
Type *MinVecTy = VectorTy;
if (Opcode == Instruction::Trunc) {
SrcVecTy = smallestIntegerVectorType(SrcVecTy, MinVecTy);
VectorTy =
largestIntegerVectorType(ToVectorTy(I->getType(), VF), MinVecTy);
} else if (Opcode == Instruction::ZExt || Opcode == Instruction::SExt) {
SrcVecTy = largestIntegerVectorType(SrcVecTy, MinVecTy);
VectorTy =
smallestIntegerVectorType(ToVectorTy(I->getType(), VF), MinVecTy);
}
}
return TTI.getCastInstrCost(Opcode, VectorTy, SrcVecTy, CCH, CostKind, I);
}
case Instruction::Call: {
if (RecurrenceDescriptor::isFMulAddIntrinsic(I))
if (auto RedCost = getReductionPatternCost(I, VF, VectorTy, CostKind))
return *RedCost;
bool NeedToScalarize;
CallInst *CI = cast<CallInst>(I);
InstructionCost CallCost = getVectorCallCost(CI, VF, NeedToScalarize);
if (getVectorIntrinsicIDForCall(CI, TLI)) {
InstructionCost IntrinsicCost = getVectorIntrinsicCost(CI, VF);
return std::min(CallCost, IntrinsicCost);
}
return CallCost;
}
case Instruction::ExtractValue:
return TTI.getInstructionCost(I, TTI::TCK_RecipThroughput);
case Instruction::Alloca:
// We cannot easily widen alloca to a scalable alloca, as
// the result would need to be a vector of pointers.
if (VF.isScalable())
return InstructionCost::getInvalid();
LLVM_FALLTHROUGH;
default:
// This opcode is unknown. Assume that it is the same as 'mul'.
return TTI.getArithmeticInstrCost(Instruction::Mul, VectorTy, CostKind);
} // end of switch.
}
char LoopVectorize::ID = 0;
static const char lv_name[] = "Loop Vectorization";
INITIALIZE_PASS_BEGIN(LoopVectorize, LV_NAME, lv_name, false, false)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(BasicAAWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LoopAccessLegacyAnalysis)
INITIALIZE_PASS_DEPENDENCY(DemandedBitsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass)
INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(InjectTLIMappingsLegacy)
INITIALIZE_PASS_END(LoopVectorize, LV_NAME, lv_name, false, false)
namespace llvm {
Pass *createLoopVectorizePass() { return new LoopVectorize(); }
Pass *createLoopVectorizePass(bool InterleaveOnlyWhenForced,
bool VectorizeOnlyWhenForced) {
return new LoopVectorize(InterleaveOnlyWhenForced, VectorizeOnlyWhenForced);
}
} // end namespace llvm
void LoopVectorizationCostModel::collectValuesToIgnore() {
// Ignore ephemeral values.
CodeMetrics::collectEphemeralValues(TheLoop, AC, ValuesToIgnore);
// Find all stores to invariant variables. Since they are going to sink
// outside the loop we do not need calculate cost for them.
for (BasicBlock *BB : TheLoop->blocks())
for (Instruction &I : *BB) {
StoreInst *SI;
if ((SI = dyn_cast<StoreInst>(&I)) &&
Legal->isInvariantAddressOfReduction(SI->getPointerOperand()))
ValuesToIgnore.insert(&I);
}
// Ignore type-promoting instructions we identified during reduction
// detection.
for (auto &Reduction : Legal->getReductionVars()) {
const RecurrenceDescriptor &RedDes = Reduction.second;
const SmallPtrSetImpl<Instruction *> &Casts = RedDes.getCastInsts();
VecValuesToIgnore.insert(Casts.begin(), Casts.end());
}
// Ignore type-casting instructions we identified during induction
// detection.
for (auto &Induction : Legal->getInductionVars()) {
const InductionDescriptor &IndDes = Induction.second;
const SmallVectorImpl<Instruction *> &Casts = IndDes.getCastInsts();
VecValuesToIgnore.insert(Casts.begin(), Casts.end());
}
}
void LoopVectorizationCostModel::collectInLoopReductions() {
for (auto &Reduction : Legal->getReductionVars()) {
PHINode *Phi = Reduction.first;
const RecurrenceDescriptor &RdxDesc = Reduction.second;
// We don't collect reductions that are type promoted (yet).
if (RdxDesc.getRecurrenceType() != Phi->getType())
continue;
// If the target would prefer this reduction to happen "in-loop", then we
// want to record it as such.
unsigned Opcode = RdxDesc.getOpcode();
if (!PreferInLoopReductions && !useOrderedReductions(RdxDesc) &&
!TTI.preferInLoopReduction(Opcode, Phi->getType(),
TargetTransformInfo::ReductionFlags()))
continue;
// Check that we can correctly put the reductions into the loop, by
// finding the chain of operations that leads from the phi to the loop
// exit value.
SmallVector<Instruction *, 4> ReductionOperations =
RdxDesc.getReductionOpChain(Phi, TheLoop);
bool InLoop = !ReductionOperations.empty();
if (InLoop) {
InLoopReductionChains[Phi] = ReductionOperations;
// Add the elements to InLoopReductionImmediateChains for cost modelling.
Instruction *LastChain = Phi;
for (auto *I : ReductionOperations) {
InLoopReductionImmediateChains[I] = LastChain;
LastChain = I;
}
}
LLVM_DEBUG(dbgs() << "LV: Using " << (InLoop ? "inloop" : "out of loop")
<< " reduction for phi: " << *Phi << "\n");
}
}
// TODO: we could return a pair of values that specify the max VF and
// min VF, to be used in `buildVPlans(MinVF, MaxVF)` instead of
// `buildVPlans(VF, VF)`. We cannot do it because VPLAN at the moment
// doesn't have a cost model that can choose which plan to execute if
// more than one is generated.
static unsigned determineVPlanVF(const unsigned WidestVectorRegBits,
LoopVectorizationCostModel &CM) {
unsigned WidestType;
std::tie(std::ignore, WidestType) = CM.getSmallestAndWidestTypes();
return WidestVectorRegBits / WidestType;
}
VectorizationFactor
LoopVectorizationPlanner::planInVPlanNativePath(ElementCount UserVF) {
assert(!UserVF.isScalable() && "scalable vectors not yet supported");
ElementCount VF = UserVF;
// Outer loop handling: They may require CFG and instruction level
// transformations before even evaluating whether vectorization is profitable.
// Since we cannot modify the incoming IR, we need to build VPlan upfront in
// the vectorization pipeline.
if (!OrigLoop->isInnermost()) {
// If the user doesn't provide a vectorization factor, determine a
// reasonable one.
if (UserVF.isZero()) {
VF = ElementCount::getFixed(determineVPlanVF(
TTI->getRegisterBitWidth(TargetTransformInfo::RGK_FixedWidthVector)
.getFixedSize(),
CM));
LLVM_DEBUG(dbgs() << "LV: VPlan computed VF " << VF << ".\n");
// Make sure we have a VF > 1 for stress testing.
if (VPlanBuildStressTest && (VF.isScalar() || VF.isZero())) {
LLVM_DEBUG(dbgs() << "LV: VPlan stress testing: "
<< "overriding computed VF.\n");
VF = ElementCount::getFixed(4);
}
}
assert(EnableVPlanNativePath && "VPlan-native path is not enabled.");
assert(isPowerOf2_32(VF.getKnownMinValue()) &&
"VF needs to be a power of two");
LLVM_DEBUG(dbgs() << "LV: Using " << (!UserVF.isZero() ? "user " : "")
<< "VF " << VF << " to build VPlans.\n");
buildVPlans(VF, VF);
// For VPlan build stress testing, we bail out after VPlan construction.
if (VPlanBuildStressTest)
return VectorizationFactor::Disabled();
return {VF, 0 /*Cost*/, 0 /* ScalarCost */};
}
LLVM_DEBUG(
dbgs() << "LV: Not vectorizing. Inner loops aren't supported in the "
"VPlan-native path.\n");
return VectorizationFactor::Disabled();
}
Optional<VectorizationFactor>
LoopVectorizationPlanner::plan(ElementCount UserVF, unsigned UserIC) {
assert(OrigLoop->isInnermost() && "Inner loop expected.");
FixedScalableVFPair MaxFactors = CM.computeMaxVF(UserVF, UserIC);
if (!MaxFactors) // Cases that should not to be vectorized nor interleaved.
return None;
// Invalidate interleave groups if all blocks of loop will be predicated.
if (CM.blockNeedsPredicationForAnyReason(OrigLoop->getHeader()) &&
!useMaskedInterleavedAccesses(*TTI)) {
LLVM_DEBUG(
dbgs()
<< "LV: Invalidate all interleaved groups due to fold-tail by masking "
"which requires masked-interleaved support.\n");
if (CM.InterleaveInfo.invalidateGroups())
// Invalidating interleave groups also requires invalidating all decisions
// based on them, which includes widening decisions and uniform and scalar
// values.
CM.invalidateCostModelingDecisions();
}
ElementCount MaxUserVF =
UserVF.isScalable() ? MaxFactors.ScalableVF : MaxFactors.FixedVF;
bool UserVFIsLegal = ElementCount::isKnownLE(UserVF, MaxUserVF);
if (!UserVF.isZero() && UserVFIsLegal) {
assert(isPowerOf2_32(UserVF.getKnownMinValue()) &&
"VF needs to be a power of two");
// Collect the instructions (and their associated costs) that will be more
// profitable to scalarize.
if (CM.selectUserVectorizationFactor(UserVF)) {
LLVM_DEBUG(dbgs() << "LV: Using user VF " << UserVF << ".\n");
CM.collectInLoopReductions();
buildVPlansWithVPRecipes(UserVF, UserVF);
LLVM_DEBUG(printPlans(dbgs()));
return {{UserVF, 0, 0}};
} else
reportVectorizationInfo("UserVF ignored because of invalid costs.",
"InvalidCost", ORE, OrigLoop);
}
// Populate the set of Vectorization Factor Candidates.
ElementCountSet VFCandidates;
for (auto VF = ElementCount::getFixed(1);
ElementCount::isKnownLE(VF, MaxFactors.FixedVF); VF *= 2)
VFCandidates.insert(VF);
for (auto VF = ElementCount::getScalable(1);
ElementCount::isKnownLE(VF, MaxFactors.ScalableVF); VF *= 2)
VFCandidates.insert(VF);
for (const auto &VF : VFCandidates) {
// Collect Uniform and Scalar instructions after vectorization with VF.
CM.collectUniformsAndScalars(VF);
// Collect the instructions (and their associated costs) that will be more
// profitable to scalarize.
if (VF.isVector())
CM.collectInstsToScalarize(VF);
}
CM.collectInLoopReductions();
buildVPlansWithVPRecipes(ElementCount::getFixed(1), MaxFactors.FixedVF);
buildVPlansWithVPRecipes(ElementCount::getScalable(1), MaxFactors.ScalableVF);
LLVM_DEBUG(printPlans(dbgs()));
if (!MaxFactors.hasVector())
return VectorizationFactor::Disabled();
// Select the optimal vectorization factor.
VectorizationFactor VF = CM.selectVectorizationFactor(VFCandidates);
assert((VF.Width.isScalar() || VF.ScalarCost > 0) && "when vectorizing, the scalar cost must be non-zero.");
return VF;
}
VPlan &LoopVectorizationPlanner::getBestPlanFor(ElementCount VF) const {
assert(count_if(VPlans,
[VF](const VPlanPtr &Plan) { return Plan->hasVF(VF); }) ==
1 &&
"Best VF has not a single VPlan.");
for (const VPlanPtr &Plan : VPlans) {
if (Plan->hasVF(VF))
return *Plan.get();
}
llvm_unreachable("No plan found!");
}
static void AddRuntimeUnrollDisableMetaData(Loop *L) {
SmallVector<Metadata *, 4> MDs;
// Reserve first location for self reference to the LoopID metadata node.
MDs.push_back(nullptr);
bool IsUnrollMetadata = false;
MDNode *LoopID = L->getLoopID();
if (LoopID) {
// First find existing loop unrolling disable metadata.
for (unsigned i = 1, ie = LoopID->getNumOperands(); i < ie; ++i) {
auto *MD = dyn_cast<MDNode>(LoopID->getOperand(i));
if (MD) {
const auto *S = dyn_cast<MDString>(MD->getOperand(0));
IsUnrollMetadata =
S && S->getString().startswith("llvm.loop.unroll.disable");
}
MDs.push_back(LoopID->getOperand(i));
}
}
if (!IsUnrollMetadata) {
// Add runtime unroll disable metadata.
LLVMContext &Context = L->getHeader()->getContext();
SmallVector<Metadata *, 1> DisableOperands;
DisableOperands.push_back(
MDString::get(Context, "llvm.loop.unroll.runtime.disable"));
MDNode *DisableNode = MDNode::get(Context, DisableOperands);
MDs.push_back(DisableNode);
MDNode *NewLoopID = MDNode::get(Context, MDs);
// Set operand 0 to refer to the loop id itself.
NewLoopID->replaceOperandWith(0, NewLoopID);
L->setLoopID(NewLoopID);
}
}
void LoopVectorizationPlanner::executePlan(ElementCount BestVF, unsigned BestUF,
VPlan &BestVPlan,
InnerLoopVectorizer &ILV,
DominatorTree *DT,
bool IsEpilogueVectorization) {
LLVM_DEBUG(dbgs() << "Executing best plan with VF=" << BestVF << ", UF=" << BestUF
<< '\n');
// Perform the actual loop transformation.
// 1. Set up the skeleton for vectorization, including vector pre-header and
// middle block. The vector loop is created during VPlan execution.
VPTransformState State{BestVF, BestUF, LI, DT, ILV.Builder, &ILV, &BestVPlan};
Value *CanonicalIVStartValue;
std::tie(State.CFG.PrevBB, CanonicalIVStartValue) =
ILV.createVectorizedLoopSkeleton();
// Only use noalias metadata when using memory checks guaranteeing no overlap
// across all iterations.
const LoopAccessInfo *LAI = ILV.Legal->getLAI();
if (LAI && !LAI->getRuntimePointerChecking()->getChecks().empty() &&
!LAI->getRuntimePointerChecking()->getDiffChecks()) {
// We currently don't use LoopVersioning for the actual loop cloning but we
// still use it to add the noalias metadata.
// TODO: Find a better way to re-use LoopVersioning functionality to add
// metadata.
State.LVer = std::make_unique<LoopVersioning>(
*LAI, LAI->getRuntimePointerChecking()->getChecks(), OrigLoop, LI, DT,
PSE.getSE());
State.LVer->prepareNoAliasMetadata();
}
ILV.collectPoisonGeneratingRecipes(State);
ILV.printDebugTracesAtStart();
//===------------------------------------------------===//
//
// Notice: any optimization or new instruction that go
// into the code below should also be implemented in
// the cost-model.
//
//===------------------------------------------------===//
// 2. Copy and widen instructions from the old loop into the new loop.
BestVPlan.prepareToExecute(ILV.getOrCreateTripCount(nullptr),
ILV.getOrCreateVectorTripCount(nullptr),
CanonicalIVStartValue, State,
IsEpilogueVectorization);
BestVPlan.execute(&State);
// Keep all loop hints from the original loop on the vector loop (we'll
// replace the vectorizer-specific hints below).
MDNode *OrigLoopID = OrigLoop->getLoopID();
Optional<MDNode *> VectorizedLoopID =
makeFollowupLoopID(OrigLoopID, {LLVMLoopVectorizeFollowupAll,
LLVMLoopVectorizeFollowupVectorized});
VPBasicBlock *HeaderVPBB =
BestVPlan.getVectorLoopRegion()->getEntryBasicBlock();
Loop *L = LI->getLoopFor(State.CFG.VPBB2IRBB[HeaderVPBB]);
if (VectorizedLoopID)
L->setLoopID(VectorizedLoopID.value());
else {
// Keep all loop hints from the original loop on the vector loop (we'll
// replace the vectorizer-specific hints below).
if (MDNode *LID = OrigLoop->getLoopID())
L->setLoopID(LID);
LoopVectorizeHints Hints(L, true, *ORE);
Hints.setAlreadyVectorized();
}
// Disable runtime unrolling when vectorizing the epilogue loop.
if (CanonicalIVStartValue)
AddRuntimeUnrollDisableMetaData(L);
// 3. Fix the vectorized code: take care of header phi's, live-outs,
// predication, updating analyses.
ILV.fixVectorizedLoop(State, BestVPlan);
ILV.printDebugTracesAtEnd();
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void LoopVectorizationPlanner::printPlans(raw_ostream &O) {
for (const auto &Plan : VPlans)
if (PrintVPlansInDotFormat)
Plan->printDOT(O);
else
Plan->print(O);
}
#endif
Value *InnerLoopUnroller::getBroadcastInstrs(Value *V) { return V; }
//===--------------------------------------------------------------------===//
// EpilogueVectorizerMainLoop
//===--------------------------------------------------------------------===//
/// This function is partially responsible for generating the control flow
/// depicted in https://llvm.org/docs/Vectorizers.html#epilogue-vectorization.
std::pair<BasicBlock *, Value *>
EpilogueVectorizerMainLoop::createEpilogueVectorizedLoopSkeleton() {
MDNode *OrigLoopID = OrigLoop->getLoopID();
// Workaround! Compute the trip count of the original loop and cache it
// before we start modifying the CFG. This code has a systemic problem
// wherein it tries to run analysis over partially constructed IR; this is
// wrong, and not simply for SCEV. The trip count of the original loop
// simply happens to be prone to hitting this in practice. In theory, we
// can hit the same issue for any SCEV, or ValueTracking query done during
// mutation. See PR49900.
getOrCreateTripCount(OrigLoop->getLoopPreheader());
createVectorLoopSkeleton("");
// Generate the code to check the minimum iteration count of the vector
// epilogue (see below).
EPI.EpilogueIterationCountCheck =
emitIterationCountCheck(LoopScalarPreHeader, true);
EPI.EpilogueIterationCountCheck->setName("iter.check");
// Generate the code to check any assumptions that we've made for SCEV
// expressions.
EPI.SCEVSafetyCheck = emitSCEVChecks(LoopScalarPreHeader);
// Generate the code that checks at runtime if arrays overlap. We put the
// checks into a separate block to make the more common case of few elements
// faster.
EPI.MemSafetyCheck = emitMemRuntimeChecks(LoopScalarPreHeader);
// Generate the iteration count check for the main loop, *after* the check
// for the epilogue loop, so that the path-length is shorter for the case
// that goes directly through the vector epilogue. The longer-path length for
// the main loop is compensated for, by the gain from vectorizing the larger
// trip count. Note: the branch will get updated later on when we vectorize
// the epilogue.
EPI.MainLoopIterationCountCheck =
emitIterationCountCheck(LoopScalarPreHeader, false);
// Generate the induction variable.
EPI.VectorTripCount = getOrCreateVectorTripCount(LoopVectorPreHeader);
// Skip induction resume value creation here because they will be created in
// the second pass. If we created them here, they wouldn't be used anyway,
// because the vplan in the second pass still contains the inductions from the
// original loop.
return {completeLoopSkeleton(OrigLoopID), nullptr};
}
void EpilogueVectorizerMainLoop::printDebugTracesAtStart() {
LLVM_DEBUG({
dbgs() << "Create Skeleton for epilogue vectorized loop (first pass)\n"
<< "Main Loop VF:" << EPI.MainLoopVF
<< ", Main Loop UF:" << EPI.MainLoopUF
<< ", Epilogue Loop VF:" << EPI.EpilogueVF
<< ", Epilogue Loop UF:" << EPI.EpilogueUF << "\n";
});
}
void EpilogueVectorizerMainLoop::printDebugTracesAtEnd() {
DEBUG_WITH_TYPE(VerboseDebug, {
dbgs() << "intermediate fn:\n"
<< *OrigLoop->getHeader()->getParent() << "\n";
});
}
BasicBlock *
EpilogueVectorizerMainLoop::emitIterationCountCheck(BasicBlock *Bypass,
bool ForEpilogue) {
assert(Bypass && "Expected valid bypass basic block.");
ElementCount VFactor = ForEpilogue ? EPI.EpilogueVF : VF;
unsigned UFactor = ForEpilogue ? EPI.EpilogueUF : UF;
Value *Count = getOrCreateTripCount(LoopVectorPreHeader);
// Reuse existing vector loop preheader for TC checks.
// Note that new preheader block is generated for vector loop.
BasicBlock *const TCCheckBlock = LoopVectorPreHeader;
IRBuilder<> Builder(TCCheckBlock->getTerminator());
// Generate code to check if the loop's trip count is less than VF * UF of the
// main vector loop.
auto P = Cost->requiresScalarEpilogue(ForEpilogue ? EPI.EpilogueVF : VF) ?
ICmpInst::ICMP_ULE : ICmpInst::ICMP_ULT;
Value *CheckMinIters = Builder.CreateICmp(
P, Count, createStepForVF(Builder, Count->getType(), VFactor, UFactor),
"min.iters.check");
if (!ForEpilogue)
TCCheckBlock->setName("vector.main.loop.iter.check");
// Create new preheader for vector loop.
LoopVectorPreHeader = SplitBlock(TCCheckBlock, TCCheckBlock->getTerminator(),
DT, LI, nullptr, "vector.ph");
if (ForEpilogue) {
assert(DT->properlyDominates(DT->getNode(TCCheckBlock),
DT->getNode(Bypass)->getIDom()) &&
"TC check is expected to dominate Bypass");
// Update dominator for Bypass & LoopExit.
DT->changeImmediateDominator(Bypass, TCCheckBlock);
if (!Cost->requiresScalarEpilogue(EPI.EpilogueVF))
// For loops with multiple exits, there's no edge from the middle block
// to exit blocks (as the epilogue must run) and thus no need to update
// the immediate dominator of the exit blocks.
DT->changeImmediateDominator(LoopExitBlock, TCCheckBlock);
LoopBypassBlocks.push_back(TCCheckBlock);
// Save the trip count so we don't have to regenerate it in the
// vec.epilog.iter.check. This is safe to do because the trip count
// generated here dominates the vector epilog iter check.
EPI.TripCount = Count;
}
ReplaceInstWithInst(
TCCheckBlock->getTerminator(),
BranchInst::Create(Bypass, LoopVectorPreHeader, CheckMinIters));
return TCCheckBlock;
}
//===--------------------------------------------------------------------===//
// EpilogueVectorizerEpilogueLoop
//===--------------------------------------------------------------------===//
/// This function is partially responsible for generating the control flow
/// depicted in https://llvm.org/docs/Vectorizers.html#epilogue-vectorization.
std::pair<BasicBlock *, Value *>
EpilogueVectorizerEpilogueLoop::createEpilogueVectorizedLoopSkeleton() {
MDNode *OrigLoopID = OrigLoop->getLoopID();
createVectorLoopSkeleton("vec.epilog.");
// Now, compare the remaining count and if there aren't enough iterations to
// execute the vectorized epilogue skip to the scalar part.
BasicBlock *VecEpilogueIterationCountCheck = LoopVectorPreHeader;
VecEpilogueIterationCountCheck->setName("vec.epilog.iter.check");
LoopVectorPreHeader =
SplitBlock(LoopVectorPreHeader, LoopVectorPreHeader->getTerminator(), DT,
LI, nullptr, "vec.epilog.ph");
emitMinimumVectorEpilogueIterCountCheck(LoopScalarPreHeader,
VecEpilogueIterationCountCheck);
// Adjust the control flow taking the state info from the main loop
// vectorization into account.
assert(EPI.MainLoopIterationCountCheck && EPI.EpilogueIterationCountCheck &&
"expected this to be saved from the previous pass.");
EPI.MainLoopIterationCountCheck->getTerminator()->replaceUsesOfWith(
VecEpilogueIterationCountCheck, LoopVectorPreHeader);
DT->changeImmediateDominator(LoopVectorPreHeader,
EPI.MainLoopIterationCountCheck);
EPI.EpilogueIterationCountCheck->getTerminator()->replaceUsesOfWith(
VecEpilogueIterationCountCheck, LoopScalarPreHeader);
if (EPI.SCEVSafetyCheck)
EPI.SCEVSafetyCheck->getTerminator()->replaceUsesOfWith(
VecEpilogueIterationCountCheck, LoopScalarPreHeader);
if (EPI.MemSafetyCheck)
EPI.MemSafetyCheck->getTerminator()->replaceUsesOfWith(
VecEpilogueIterationCountCheck, LoopScalarPreHeader);
DT->changeImmediateDominator(
VecEpilogueIterationCountCheck,
VecEpilogueIterationCountCheck->getSinglePredecessor());
DT->changeImmediateDominator(LoopScalarPreHeader,
EPI.EpilogueIterationCountCheck);
if (!Cost->requiresScalarEpilogue(EPI.EpilogueVF))
// If there is an epilogue which must run, there's no edge from the
// middle block to exit blocks and thus no need to update the immediate
// dominator of the exit blocks.
DT->changeImmediateDominator(LoopExitBlock,
EPI.EpilogueIterationCountCheck);
// Keep track of bypass blocks, as they feed start values to the induction
// phis in the scalar loop preheader.
if (EPI.SCEVSafetyCheck)
LoopBypassBlocks.push_back(EPI.SCEVSafetyCheck);
if (EPI.MemSafetyCheck)
LoopBypassBlocks.push_back(EPI.MemSafetyCheck);
LoopBypassBlocks.push_back(EPI.EpilogueIterationCountCheck);
// The vec.epilog.iter.check block may contain Phi nodes from reductions which
// merge control-flow from the latch block and the middle block. Update the
// incoming values here and move the Phi into the preheader.
SmallVector<PHINode *, 4> PhisInBlock;
for (PHINode &Phi : VecEpilogueIterationCountCheck->phis())
PhisInBlock.push_back(&Phi);
for (PHINode *Phi : PhisInBlock) {
Phi->replaceIncomingBlockWith(
VecEpilogueIterationCountCheck->getSinglePredecessor(),
VecEpilogueIterationCountCheck);
Phi->removeIncomingValue(EPI.EpilogueIterationCountCheck);
if (EPI.SCEVSafetyCheck)
Phi->removeIncomingValue(EPI.SCEVSafetyCheck);
if (EPI.MemSafetyCheck)
Phi->removeIncomingValue(EPI.MemSafetyCheck);
Phi->moveBefore(LoopVectorPreHeader->getFirstNonPHI());
}
// Generate a resume induction for the vector epilogue and put it in the
// vector epilogue preheader
Type *IdxTy = Legal->getWidestInductionType();
PHINode *EPResumeVal = PHINode::Create(IdxTy, 2, "vec.epilog.resume.val",
LoopVectorPreHeader->getFirstNonPHI());
EPResumeVal->addIncoming(EPI.VectorTripCount, VecEpilogueIterationCountCheck);
EPResumeVal->addIncoming(ConstantInt::get(IdxTy, 0),
EPI.MainLoopIterationCountCheck);
// Generate induction resume values. These variables save the new starting
// indexes for the scalar loop. They are used to test if there are any tail
// iterations left once the vector loop has completed.
// Note that when the vectorized epilogue is skipped due to iteration count
// check, then the resume value for the induction variable comes from
// the trip count of the main vector loop, hence passing the AdditionalBypass
// argument.
createInductionResumeValues({VecEpilogueIterationCountCheck,
EPI.VectorTripCount} /* AdditionalBypass */);
return {completeLoopSkeleton(OrigLoopID), EPResumeVal};
}
BasicBlock *
EpilogueVectorizerEpilogueLoop::emitMinimumVectorEpilogueIterCountCheck(
BasicBlock *Bypass, BasicBlock *Insert) {
assert(EPI.TripCount &&
"Expected trip count to have been safed in the first pass.");
assert(
(!isa<Instruction>(EPI.TripCount) ||
DT->dominates(cast<Instruction>(EPI.TripCount)->getParent(), Insert)) &&
"saved trip count does not dominate insertion point.");
Value *TC = EPI.TripCount;
IRBuilder<> Builder(Insert->getTerminator());
Value *Count = Builder.CreateSub(TC, EPI.VectorTripCount, "n.vec.remaining");
// Generate code to check if the loop's trip count is less than VF * UF of the
// vector epilogue loop.
auto P = Cost->requiresScalarEpilogue(EPI.EpilogueVF) ?
ICmpInst::ICMP_ULE : ICmpInst::ICMP_ULT;
Value *CheckMinIters =
Builder.CreateICmp(P, Count,
createStepForVF(Builder, Count->getType(),
EPI.EpilogueVF, EPI.EpilogueUF),
"min.epilog.iters.check");
ReplaceInstWithInst(
Insert->getTerminator(),
BranchInst::Create(Bypass, LoopVectorPreHeader, CheckMinIters));
LoopBypassBlocks.push_back(Insert);
return Insert;
}
void EpilogueVectorizerEpilogueLoop::printDebugTracesAtStart() {
LLVM_DEBUG({
dbgs() << "Create Skeleton for epilogue vectorized loop (second pass)\n"
<< "Epilogue Loop VF:" << EPI.EpilogueVF
<< ", Epilogue Loop UF:" << EPI.EpilogueUF << "\n";
});
}
void EpilogueVectorizerEpilogueLoop::printDebugTracesAtEnd() {
DEBUG_WITH_TYPE(VerboseDebug, {
dbgs() << "final fn:\n" << *OrigLoop->getHeader()->getParent() << "\n";
});
}
bool LoopVectorizationPlanner::getDecisionAndClampRange(
const std::function<bool(ElementCount)> &Predicate, VFRange &Range) {
assert(!Range.isEmpty() && "Trying to test an empty VF range.");
bool PredicateAtRangeStart = Predicate(Range.Start);
for (ElementCount TmpVF = Range.Start * 2;
ElementCount::isKnownLT(TmpVF, Range.End); TmpVF *= 2)
if (Predicate(TmpVF) != PredicateAtRangeStart) {
Range.End = TmpVF;
break;
}
return PredicateAtRangeStart;
}
/// Build VPlans for the full range of feasible VF's = {\p MinVF, 2 * \p MinVF,
/// 4 * \p MinVF, ..., \p MaxVF} by repeatedly building a VPlan for a sub-range
/// of VF's starting at a given VF and extending it as much as possible. Each
/// vectorization decision can potentially shorten this sub-range during
/// buildVPlan().
void LoopVectorizationPlanner::buildVPlans(ElementCount MinVF,
ElementCount MaxVF) {
auto MaxVFPlusOne = MaxVF.getWithIncrement(1);
for (ElementCount VF = MinVF; ElementCount::isKnownLT(VF, MaxVFPlusOne);) {
VFRange SubRange = {VF, MaxVFPlusOne};
VPlans.push_back(buildVPlan(SubRange));
VF = SubRange.End;
}
}
VPValue *VPRecipeBuilder::createEdgeMask(BasicBlock *Src, BasicBlock *Dst,
VPlanPtr &Plan) {
assert(is_contained(predecessors(Dst), Src) && "Invalid edge");
// Look for cached value.
std::pair<BasicBlock *, BasicBlock *> Edge(Src, Dst);
EdgeMaskCacheTy::iterator ECEntryIt = EdgeMaskCache.find(Edge);
if (ECEntryIt != EdgeMaskCache.end())
return ECEntryIt->second;
VPValue *SrcMask = createBlockInMask(Src, Plan);
// The terminator has to be a branch inst!
BranchInst *BI = dyn_cast<BranchInst>(Src->getTerminator());
assert(BI && "Unexpected terminator found");
if (!BI->isConditional() || BI->getSuccessor(0) == BI->getSuccessor(1))
return EdgeMaskCache[Edge] = SrcMask;
// If source is an exiting block, we know the exit edge is dynamically dead
// in the vector loop, and thus we don't need to restrict the mask. Avoid
// adding uses of an otherwise potentially dead instruction.
if (OrigLoop->isLoopExiting(Src))
return EdgeMaskCache[Edge] = SrcMask;
VPValue *EdgeMask = Plan->getOrAddVPValue(BI->getCondition());
assert(EdgeMask && "No Edge Mask found for condition");
if (BI->getSuccessor(0) != Dst)
EdgeMask = Builder.createNot(EdgeMask, BI->getDebugLoc());
if (SrcMask) { // Otherwise block in-mask is all-one, no need to AND.
// The condition is 'SrcMask && EdgeMask', which is equivalent to
// 'select i1 SrcMask, i1 EdgeMask, i1 false'.
// The select version does not introduce new UB if SrcMask is false and
// EdgeMask is poison. Using 'and' here introduces undefined behavior.
VPValue *False = Plan->getOrAddVPValue(
ConstantInt::getFalse(BI->getCondition()->getType()));
EdgeMask =
Builder.createSelect(SrcMask, EdgeMask, False, BI->getDebugLoc());
}
return EdgeMaskCache[Edge] = EdgeMask;
}
VPValue *VPRecipeBuilder::createBlockInMask(BasicBlock *BB, VPlanPtr &Plan) {
assert(OrigLoop->contains(BB) && "Block is not a part of a loop");
// Look for cached value.
BlockMaskCacheTy::iterator BCEntryIt = BlockMaskCache.find(BB);
if (BCEntryIt != BlockMaskCache.end())
return BCEntryIt->second;
// All-one mask is modelled as no-mask following the convention for masked
// load/store/gather/scatter. Initialize BlockMask to no-mask.
VPValue *BlockMask = nullptr;
if (OrigLoop->getHeader() == BB) {
if (!CM.blockNeedsPredicationForAnyReason(BB))
return BlockMaskCache[BB] = BlockMask; // Loop incoming mask is all-one.
assert(CM.foldTailByMasking() && "must fold the tail");
// If we're using the active lane mask for control flow, then we get the
// mask from the active lane mask PHI that is cached in the VPlan.
PredicationStyle EmitGetActiveLaneMask = CM.TTI.emitGetActiveLaneMask();
if (EmitGetActiveLaneMask == PredicationStyle::DataAndControlFlow)
return BlockMaskCache[BB] = Plan->getActiveLaneMaskPhi();
// Introduce the early-exit compare IV <= BTC to form header block mask.
// This is used instead of IV < TC because TC may wrap, unlike BTC. Start by
// constructing the desired canonical IV in the header block as its first
// non-phi instructions.
VPBasicBlock *HeaderVPBB =
Plan->getVectorLoopRegion()->getEntryBasicBlock();
auto NewInsertionPoint = HeaderVPBB->getFirstNonPhi();
auto *IV = new VPWidenCanonicalIVRecipe(Plan->getCanonicalIV());
HeaderVPBB->insert(IV, HeaderVPBB->getFirstNonPhi());
VPBuilder::InsertPointGuard Guard(Builder);
Builder.setInsertPoint(HeaderVPBB, NewInsertionPoint);
if (EmitGetActiveLaneMask != PredicationStyle::None) {
VPValue *TC = Plan->getOrCreateTripCount();
BlockMask = Builder.createNaryOp(VPInstruction::ActiveLaneMask, {IV, TC},
nullptr, "active.lane.mask");
} else {
VPValue *BTC = Plan->getOrCreateBackedgeTakenCount();
BlockMask = Builder.createNaryOp(VPInstruction::ICmpULE, {IV, BTC});
}
return BlockMaskCache[BB] = BlockMask;
}
// This is the block mask. We OR all incoming edges.
for (auto *Predecessor : predecessors(BB)) {
VPValue *EdgeMask = createEdgeMask(Predecessor, BB, Plan);
if (!EdgeMask) // Mask of predecessor is all-one so mask of block is too.
return BlockMaskCache[BB] = EdgeMask;
if (!BlockMask) { // BlockMask has its initialized nullptr value.
BlockMask = EdgeMask;
continue;
}
BlockMask = Builder.createOr(BlockMask, EdgeMask, {});
}
return BlockMaskCache[BB] = BlockMask;
}
VPRecipeBase *VPRecipeBuilder::tryToWidenMemory(Instruction *I,
ArrayRef<VPValue *> Operands,
VFRange &Range,
VPlanPtr &Plan) {
assert((isa<LoadInst>(I) || isa<StoreInst>(I)) &&
"Must be called with either a load or store");
auto willWiden = [&](ElementCount VF) -> bool {
LoopVectorizationCostModel::InstWidening Decision =
CM.getWideningDecision(I, VF);
assert(Decision != LoopVectorizationCostModel::CM_Unknown &&
"CM decision should be taken at this point.");
if (Decision == LoopVectorizationCostModel::CM_Interleave)
return true;
if (CM.isScalarAfterVectorization(I, VF) ||
CM.isProfitableToScalarize(I, VF))
return false;
return Decision != LoopVectorizationCostModel::CM_Scalarize;
};
if (!LoopVectorizationPlanner::getDecisionAndClampRange(willWiden, Range))
return nullptr;
VPValue *Mask = nullptr;
if (Legal->isMaskRequired(I))
Mask = createBlockInMask(I->getParent(), Plan);
// Determine if the pointer operand of the access is either consecutive or
// reverse consecutive.
LoopVectorizationCostModel::InstWidening Decision =
CM.getWideningDecision(I, Range.Start);
bool Reverse = Decision == LoopVectorizationCostModel::CM_Widen_Reverse;
bool Consecutive =
Reverse || Decision == LoopVectorizationCostModel::CM_Widen;
if (LoadInst *Load = dyn_cast<LoadInst>(I))
return new VPWidenMemoryInstructionRecipe(*Load, Operands[0], Mask,
Consecutive, Reverse);
StoreInst *Store = cast<StoreInst>(I);
return new VPWidenMemoryInstructionRecipe(*Store, Operands[1], Operands[0],
Mask, Consecutive, Reverse);
}
/// Creates a VPWidenIntOrFpInductionRecpipe for \p Phi. If needed, it will also
/// insert a recipe to expand the step for the induction recipe.
static VPWidenIntOrFpInductionRecipe *createWidenInductionRecipes(
PHINode *Phi, Instruction *PhiOrTrunc, VPValue *Start,
const InductionDescriptor &IndDesc, LoopVectorizationCostModel &CM,
VPlan &Plan, ScalarEvolution &SE, Loop &OrigLoop, VFRange &Range) {
// Returns true if an instruction \p I should be scalarized instead of
// vectorized for the chosen vectorization factor.
auto ShouldScalarizeInstruction = [&CM](Instruction *I, ElementCount VF) {
return CM.isScalarAfterVectorization(I, VF) ||
CM.isProfitableToScalarize(I, VF);
};
bool NeedsScalarIVOnly = LoopVectorizationPlanner::getDecisionAndClampRange(
[&](ElementCount VF) {
return ShouldScalarizeInstruction(PhiOrTrunc, VF);
},
Range);
assert(IndDesc.getStartValue() ==
Phi->getIncomingValueForBlock(OrigLoop.getLoopPreheader()));
assert(SE.isLoopInvariant(IndDesc.getStep(), &OrigLoop) &&
"step must be loop invariant");
VPValue *Step =
vputils::getOrCreateVPValueForSCEVExpr(Plan, IndDesc.getStep(), SE);
if (auto *TruncI = dyn_cast<TruncInst>(PhiOrTrunc)) {
return new VPWidenIntOrFpInductionRecipe(Phi, Start, Step, IndDesc, TruncI,
!NeedsScalarIVOnly);
}
assert(isa<PHINode>(PhiOrTrunc) && "must be a phi node here");
return new VPWidenIntOrFpInductionRecipe(Phi, Start, Step, IndDesc,
!NeedsScalarIVOnly);
}
VPRecipeBase *VPRecipeBuilder::tryToOptimizeInductionPHI(
PHINode *Phi, ArrayRef<VPValue *> Operands, VPlan &Plan, VFRange &Range) {
// Check if this is an integer or fp induction. If so, build the recipe that
// produces its scalar and vector values.
if (auto *II = Legal->getIntOrFpInductionDescriptor(Phi))
return createWidenInductionRecipes(Phi, Phi, Operands[0], *II, CM, Plan,
*PSE.getSE(), *OrigLoop, Range);
// Check if this is pointer induction. If so, build the recipe for it.
- if (auto *II = Legal->getPointerInductionDescriptor(Phi))
- return new VPWidenPointerInductionRecipe(Phi, Operands[0], *II,
- *PSE.getSE());
+ if (auto *II = Legal->getPointerInductionDescriptor(Phi)) {
+ return new VPWidenPointerInductionRecipe(
+ Phi, Operands[0], *II, *PSE.getSE(),
+ LoopVectorizationPlanner::getDecisionAndClampRange(
+ [&](ElementCount VF) {
+ return CM.isScalarAfterVectorization(Phi, VF);
+ },
+ Range));
+ }
return nullptr;
}
VPWidenIntOrFpInductionRecipe *VPRecipeBuilder::tryToOptimizeInductionTruncate(
TruncInst *I, ArrayRef<VPValue *> Operands, VFRange &Range, VPlan &Plan) {
// Optimize the special case where the source is a constant integer
// induction variable. Notice that we can only optimize the 'trunc' case
// because (a) FP conversions lose precision, (b) sext/zext may wrap, and
// (c) other casts depend on pointer size.
// Determine whether \p K is a truncation based on an induction variable that
// can be optimized.
auto isOptimizableIVTruncate =
[&](Instruction *K) -> std::function<bool(ElementCount)> {
return [=](ElementCount VF) -> bool {
return CM.isOptimizableIVTruncate(K, VF);
};
};
if (LoopVectorizationPlanner::getDecisionAndClampRange(
isOptimizableIVTruncate(I), Range)) {
auto *Phi = cast<PHINode>(I->getOperand(0));
const InductionDescriptor &II = *Legal->getIntOrFpInductionDescriptor(Phi);
VPValue *Start = Plan.getOrAddVPValue(II.getStartValue());
return createWidenInductionRecipes(Phi, I, Start, II, CM, Plan,
*PSE.getSE(), *OrigLoop, Range);
}
return nullptr;
}
VPRecipeOrVPValueTy VPRecipeBuilder::tryToBlend(PHINode *Phi,
ArrayRef<VPValue *> Operands,
VPlanPtr &Plan) {
// If all incoming values are equal, the incoming VPValue can be used directly
// instead of creating a new VPBlendRecipe.
VPValue *FirstIncoming = Operands[0];
if (all_of(Operands, [FirstIncoming](const VPValue *Inc) {
return FirstIncoming == Inc;
})) {
return Operands[0];
}
unsigned NumIncoming = Phi->getNumIncomingValues();
// For in-loop reductions, we do not need to create an additional select.
VPValue *InLoopVal = nullptr;
for (unsigned In = 0; In < NumIncoming; In++) {
PHINode *PhiOp =
dyn_cast_or_null<PHINode>(Operands[In]->getUnderlyingValue());
if (PhiOp && CM.isInLoopReduction(PhiOp)) {
assert(!InLoopVal && "Found more than one in-loop reduction!");
InLoopVal = Operands[In];
}
}
assert((!InLoopVal || NumIncoming == 2) &&
"Found an in-loop reduction for PHI with unexpected number of "
"incoming values");
if (InLoopVal)
return Operands[Operands[0] == InLoopVal ? 1 : 0];
// We know that all PHIs in non-header blocks are converted into selects, so
// we don't have to worry about the insertion order and we can just use the
// builder. At this point we generate the predication tree. There may be
// duplications since this is a simple recursive scan, but future
// optimizations will clean it up.
SmallVector<VPValue *, 2> OperandsWithMask;
for (unsigned In = 0; In < NumIncoming; In++) {
VPValue *EdgeMask =
createEdgeMask(Phi->getIncomingBlock(In), Phi->getParent(), Plan);
assert((EdgeMask || NumIncoming == 1) &&
"Multiple predecessors with one having a full mask");
OperandsWithMask.push_back(Operands[In]);
if (EdgeMask)
OperandsWithMask.push_back(EdgeMask);
}
return toVPRecipeResult(new VPBlendRecipe(Phi, OperandsWithMask));
}
VPWidenCallRecipe *VPRecipeBuilder::tryToWidenCall(CallInst *CI,
ArrayRef<VPValue *> Operands,
VFRange &Range) const {
bool IsPredicated = LoopVectorizationPlanner::getDecisionAndClampRange(
[this, CI](ElementCount VF) {
return CM.isScalarWithPredication(CI, VF);
},
Range);
if (IsPredicated)
return nullptr;
Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI);
if (ID && (ID == Intrinsic::assume || ID == Intrinsic::lifetime_end ||
ID == Intrinsic::lifetime_start || ID == Intrinsic::sideeffect ||
ID == Intrinsic::pseudoprobe ||
ID == Intrinsic::experimental_noalias_scope_decl))
return nullptr;
auto willWiden = [&](ElementCount VF) -> bool {
Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI);
// The following case may be scalarized depending on the VF.
// The flag shows whether we use Intrinsic or a usual Call for vectorized
// version of the instruction.
// Is it beneficial to perform intrinsic call compared to lib call?
bool NeedToScalarize = false;
InstructionCost CallCost = CM.getVectorCallCost(CI, VF, NeedToScalarize);
InstructionCost IntrinsicCost = ID ? CM.getVectorIntrinsicCost(CI, VF) : 0;
bool UseVectorIntrinsic = ID && IntrinsicCost <= CallCost;
return UseVectorIntrinsic || !NeedToScalarize;
};
if (!LoopVectorizationPlanner::getDecisionAndClampRange(willWiden, Range))
return nullptr;
ArrayRef<VPValue *> Ops = Operands.take_front(CI->arg_size());
return new VPWidenCallRecipe(*CI, make_range(Ops.begin(), Ops.end()));
}
bool VPRecipeBuilder::shouldWiden(Instruction *I, VFRange &Range) const {
assert(!isa<BranchInst>(I) && !isa<PHINode>(I) && !isa<LoadInst>(I) &&
!isa<StoreInst>(I) && "Instruction should have been handled earlier");
// Instruction should be widened, unless it is scalar after vectorization,
// scalarization is profitable or it is predicated.
auto WillScalarize = [this, I](ElementCount VF) -> bool {
return CM.isScalarAfterVectorization(I, VF) ||
CM.isProfitableToScalarize(I, VF) ||
CM.isScalarWithPredication(I, VF);
};
return !LoopVectorizationPlanner::getDecisionAndClampRange(WillScalarize,
Range);
}
VPWidenRecipe *VPRecipeBuilder::tryToWiden(Instruction *I,
ArrayRef<VPValue *> Operands) const {
auto IsVectorizableOpcode = [](unsigned Opcode) {
switch (Opcode) {
case Instruction::Add:
case Instruction::And:
case Instruction::AShr:
case Instruction::BitCast:
case Instruction::FAdd:
case Instruction::FCmp:
case Instruction::FDiv:
case Instruction::FMul:
case Instruction::FNeg:
case Instruction::FPExt:
case Instruction::FPToSI:
case Instruction::FPToUI:
case Instruction::FPTrunc:
case Instruction::FRem:
case Instruction::FSub:
case Instruction::ICmp:
case Instruction::IntToPtr:
case Instruction::LShr:
case Instruction::Mul:
case Instruction::Or:
case Instruction::PtrToInt:
case Instruction::SDiv:
case Instruction::Select:
case Instruction::SExt:
case Instruction::Shl:
case Instruction::SIToFP:
case Instruction::SRem:
case Instruction::Sub:
case Instruction::Trunc:
case Instruction::UDiv:
case Instruction::UIToFP:
case Instruction::URem:
case Instruction::Xor:
case Instruction::ZExt:
case Instruction::Freeze:
return true;
}
return false;
};
if (!IsVectorizableOpcode(I->getOpcode()))
return nullptr;
// Success: widen this instruction.
return new VPWidenRecipe(*I, make_range(Operands.begin(), Operands.end()));
}
void VPRecipeBuilder::fixHeaderPhis() {
BasicBlock *OrigLatch = OrigLoop->getLoopLatch();
for (VPHeaderPHIRecipe *R : PhisToFix) {
auto *PN = cast<PHINode>(R->getUnderlyingValue());
VPRecipeBase *IncR =
getRecipe(cast<Instruction>(PN->getIncomingValueForBlock(OrigLatch)));
R->addOperand(IncR->getVPSingleValue());
}
}
VPBasicBlock *VPRecipeBuilder::handleReplication(
Instruction *I, VFRange &Range, VPBasicBlock *VPBB,
VPlanPtr &Plan) {
bool IsUniform = LoopVectorizationPlanner::getDecisionAndClampRange(
[&](ElementCount VF) { return CM.isUniformAfterVectorization(I, VF); },
Range);
bool IsPredicated = LoopVectorizationPlanner::getDecisionAndClampRange(
[&](ElementCount VF) { return CM.isPredicatedInst(I, VF); },
Range);
// Even if the instruction is not marked as uniform, there are certain
// intrinsic calls that can be effectively treated as such, so we check for
// them here. Conservatively, we only do this for scalable vectors, since
// for fixed-width VFs we can always fall back on full scalarization.
if (!IsUniform && Range.Start.isScalable() && isa<IntrinsicInst>(I)) {
switch (cast<IntrinsicInst>(I)->getIntrinsicID()) {
case Intrinsic::assume:
case Intrinsic::lifetime_start:
case Intrinsic::lifetime_end:
// For scalable vectors if one of the operands is variant then we still
// want to mark as uniform, which will generate one instruction for just
// the first lane of the vector. We can't scalarize the call in the same
// way as for fixed-width vectors because we don't know how many lanes
// there are.
//
// The reasons for doing it this way for scalable vectors are:
// 1. For the assume intrinsic generating the instruction for the first
// lane is still be better than not generating any at all. For
// example, the input may be a splat across all lanes.
// 2. For the lifetime start/end intrinsics the pointer operand only
// does anything useful when the input comes from a stack object,
// which suggests it should always be uniform. For non-stack objects
// the effect is to poison the object, which still allows us to
// remove the call.
IsUniform = true;
break;
default:
break;
}
}
auto *Recipe = new VPReplicateRecipe(I, Plan->mapToVPValues(I->operands()),
IsUniform, IsPredicated);
// Find if I uses a predicated instruction. If so, it will use its scalar
// value. Avoid hoisting the insert-element which packs the scalar value into
// a vector value, as that happens iff all users use the vector value.
for (VPValue *Op : Recipe->operands()) {
auto *PredR = dyn_cast_or_null<VPPredInstPHIRecipe>(Op->getDef());
if (!PredR)
continue;
auto *RepR =
cast_or_null<VPReplicateRecipe>(PredR->getOperand(0)->getDef());
assert(RepR->isPredicated() &&
"expected Replicate recipe to be predicated");
RepR->setAlsoPack(false);
}
// Finalize the recipe for Instr, first if it is not predicated.
if (!IsPredicated) {
LLVM_DEBUG(dbgs() << "LV: Scalarizing:" << *I << "\n");
setRecipe(I, Recipe);
Plan->addVPValue(I, Recipe);
VPBB->appendRecipe(Recipe);
return VPBB;
}
LLVM_DEBUG(dbgs() << "LV: Scalarizing and predicating:" << *I << "\n");
VPBlockBase *SingleSucc = VPBB->getSingleSuccessor();
assert(SingleSucc && "VPBB must have a single successor when handling "
"predicated replication.");
VPBlockUtils::disconnectBlocks(VPBB, SingleSucc);
// Record predicated instructions for above packing optimizations.
VPBlockBase *Region = createReplicateRegion(Recipe, Plan);
VPBlockUtils::insertBlockAfter(Region, VPBB);
auto *RegSucc = new VPBasicBlock();
VPBlockUtils::insertBlockAfter(RegSucc, Region);
VPBlockUtils::connectBlocks(RegSucc, SingleSucc);
return RegSucc;
}
VPRegionBlock *
VPRecipeBuilder::createReplicateRegion(VPReplicateRecipe *PredRecipe,
VPlanPtr &Plan) {
Instruction *Instr = PredRecipe->getUnderlyingInstr();
// Instructions marked for predication are replicated and placed under an
// if-then construct to prevent side-effects.
// Generate recipes to compute the block mask for this region.
VPValue *BlockInMask = createBlockInMask(Instr->getParent(), Plan);
// Build the triangular if-then region.
std::string RegionName = (Twine("pred.") + Instr->getOpcodeName()).str();
assert(Instr->getParent() && "Predicated instruction not in any basic block");
auto *BOMRecipe = new VPBranchOnMaskRecipe(BlockInMask);
auto *Entry = new VPBasicBlock(Twine(RegionName) + ".entry", BOMRecipe);
auto *PHIRecipe = Instr->getType()->isVoidTy()
? nullptr
: new VPPredInstPHIRecipe(PredRecipe);
if (PHIRecipe) {
setRecipe(Instr, PHIRecipe);
Plan->addVPValue(Instr, PHIRecipe);
} else {
setRecipe(Instr, PredRecipe);
Plan->addVPValue(Instr, PredRecipe);
}
auto *Exiting = new VPBasicBlock(Twine(RegionName) + ".continue", PHIRecipe);
auto *Pred = new VPBasicBlock(Twine(RegionName) + ".if", PredRecipe);
VPRegionBlock *Region = new VPRegionBlock(Entry, Exiting, RegionName, true);
// Note: first set Entry as region entry and then connect successors starting
// from it in order, to propagate the "parent" of each VPBasicBlock.
VPBlockUtils::insertTwoBlocksAfter(Pred, Exiting, Entry);
VPBlockUtils::connectBlocks(Pred, Exiting);
return Region;
}
VPRecipeOrVPValueTy
VPRecipeBuilder::tryToCreateWidenRecipe(Instruction *Instr,
ArrayRef<VPValue *> Operands,
VFRange &Range, VPlanPtr &Plan) {
// First, check for specific widening recipes that deal with inductions, Phi
// nodes, calls and memory operations.
VPRecipeBase *Recipe;
if (auto Phi = dyn_cast<PHINode>(Instr)) {
if (Phi->getParent() != OrigLoop->getHeader())
return tryToBlend(Phi, Operands, Plan);
if ((Recipe = tryToOptimizeInductionPHI(Phi, Operands, *Plan, Range)))
return toVPRecipeResult(Recipe);
VPHeaderPHIRecipe *PhiRecipe = nullptr;
assert((Legal->isReductionVariable(Phi) ||
Legal->isFirstOrderRecurrence(Phi)) &&
"can only widen reductions and first-order recurrences here");
VPValue *StartV = Operands[0];
if (Legal->isReductionVariable(Phi)) {
const RecurrenceDescriptor &RdxDesc =
Legal->getReductionVars().find(Phi)->second;
assert(RdxDesc.getRecurrenceStartValue() ==
Phi->getIncomingValueForBlock(OrigLoop->getLoopPreheader()));
PhiRecipe = new VPReductionPHIRecipe(Phi, RdxDesc, *StartV,
CM.isInLoopReduction(Phi),
CM.useOrderedReductions(RdxDesc));
} else {
PhiRecipe = new VPFirstOrderRecurrencePHIRecipe(Phi, *StartV);
}
// Record the incoming value from the backedge, so we can add the incoming
// value from the backedge after all recipes have been created.
recordRecipeOf(cast<Instruction>(
Phi->getIncomingValueForBlock(OrigLoop->getLoopLatch())));
PhisToFix.push_back(PhiRecipe);
return toVPRecipeResult(PhiRecipe);
}
if (isa<TruncInst>(Instr) &&
(Recipe = tryToOptimizeInductionTruncate(cast<TruncInst>(Instr), Operands,
Range, *Plan)))
return toVPRecipeResult(Recipe);
// All widen recipes below deal only with VF > 1.
if (LoopVectorizationPlanner::getDecisionAndClampRange(
[&](ElementCount VF) { return VF.isScalar(); }, Range))
return nullptr;
if (auto *CI = dyn_cast<CallInst>(Instr))
return toVPRecipeResult(tryToWidenCall(CI, Operands, Range));
if (isa<LoadInst>(Instr) || isa<StoreInst>(Instr))
return toVPRecipeResult(tryToWidenMemory(Instr, Operands, Range, Plan));
if (!shouldWiden(Instr, Range))
return nullptr;
if (auto GEP = dyn_cast<GetElementPtrInst>(Instr))
return toVPRecipeResult(new VPWidenGEPRecipe(
GEP, make_range(Operands.begin(), Operands.end()), OrigLoop));
if (auto *SI = dyn_cast<SelectInst>(Instr)) {
bool InvariantCond =
PSE.getSE()->isLoopInvariant(PSE.getSCEV(SI->getOperand(0)), OrigLoop);
return toVPRecipeResult(new VPWidenSelectRecipe(
*SI, make_range(Operands.begin(), Operands.end()), InvariantCond));
}
return toVPRecipeResult(tryToWiden(Instr, Operands));
}
void LoopVectorizationPlanner::buildVPlansWithVPRecipes(ElementCount MinVF,
ElementCount MaxVF) {
assert(OrigLoop->isInnermost() && "Inner loop expected.");
// Add assume instructions we need to drop to DeadInstructions, to prevent
// them from being added to the VPlan.
// TODO: We only need to drop assumes in blocks that get flattend. If the
// control flow is preserved, we should keep them.
SmallPtrSet<Instruction *, 4> DeadInstructions;
auto &ConditionalAssumes = Legal->getConditionalAssumes();
DeadInstructions.insert(ConditionalAssumes.begin(), ConditionalAssumes.end());
MapVector<Instruction *, Instruction *> &SinkAfter = Legal->getSinkAfter();
// Dead instructions do not need sinking. Remove them from SinkAfter.
for (Instruction *I : DeadInstructions)
SinkAfter.erase(I);
// Cannot sink instructions after dead instructions (there won't be any
// recipes for them). Instead, find the first non-dead previous instruction.
for (auto &P : Legal->getSinkAfter()) {
Instruction *SinkTarget = P.second;
Instruction *FirstInst = &*SinkTarget->getParent()->begin();
(void)FirstInst;
while (DeadInstructions.contains(SinkTarget)) {
assert(
SinkTarget != FirstInst &&
"Must find a live instruction (at least the one feeding the "
"first-order recurrence PHI) before reaching beginning of the block");
SinkTarget = SinkTarget->getPrevNode();
assert(SinkTarget != P.first &&
"sink source equals target, no sinking required");
}
P.second = SinkTarget;
}
auto MaxVFPlusOne = MaxVF.getWithIncrement(1);
for (ElementCount VF = MinVF; ElementCount::isKnownLT(VF, MaxVFPlusOne);) {
VFRange SubRange = {VF, MaxVFPlusOne};
VPlans.push_back(
buildVPlanWithVPRecipes(SubRange, DeadInstructions, SinkAfter));
VF = SubRange.End;
}
}
// Add the necessary canonical IV and branch recipes required to control the
// loop.
static void addCanonicalIVRecipes(VPlan &Plan, Type *IdxTy, DebugLoc DL,
bool HasNUW,
bool UseLaneMaskForLoopControlFlow) {
Value *StartIdx = ConstantInt::get(IdxTy, 0);
auto *StartV = Plan.getOrAddVPValue(StartIdx);
// Add a VPCanonicalIVPHIRecipe starting at 0 to the header.
auto *CanonicalIVPHI = new VPCanonicalIVPHIRecipe(StartV, DL);
VPRegionBlock *TopRegion = Plan.getVectorLoopRegion();
VPBasicBlock *Header = TopRegion->getEntryBasicBlock();
Header->insert(CanonicalIVPHI, Header->begin());
// Add a CanonicalIVIncrement{NUW} VPInstruction to increment the scalar
// IV by VF * UF.
auto *CanonicalIVIncrement =
new VPInstruction(HasNUW ? VPInstruction::CanonicalIVIncrementNUW
: VPInstruction::CanonicalIVIncrement,
{CanonicalIVPHI}, DL, "index.next");
CanonicalIVPHI->addOperand(CanonicalIVIncrement);
VPBasicBlock *EB = TopRegion->getExitingBasicBlock();
EB->appendRecipe(CanonicalIVIncrement);
if (UseLaneMaskForLoopControlFlow) {
// Create the active lane mask instruction in the vplan preheader.
VPBasicBlock *Preheader = Plan.getEntry()->getEntryBasicBlock();
// We can't use StartV directly in the ActiveLaneMask VPInstruction, since
// we have to take unrolling into account. Each part needs to start at
// Part * VF
auto *CanonicalIVIncrementParts =
new VPInstruction(HasNUW ? VPInstruction::CanonicalIVIncrementForPartNUW
: VPInstruction::CanonicalIVIncrementForPart,
{StartV}, DL, "index.part.next");
Preheader->appendRecipe(CanonicalIVIncrementParts);
// Create the ActiveLaneMask instruction using the correct start values.
VPValue *TC = Plan.getOrCreateTripCount();
auto *EntryALM = new VPInstruction(VPInstruction::ActiveLaneMask,
{CanonicalIVIncrementParts, TC}, DL,
"active.lane.mask.entry");
Preheader->appendRecipe(EntryALM);
// Now create the ActiveLaneMaskPhi recipe in the main loop using the
// preheader ActiveLaneMask instruction.
auto *LaneMaskPhi = new VPActiveLaneMaskPHIRecipe(EntryALM, DebugLoc());
Header->insert(LaneMaskPhi, Header->getFirstNonPhi());
// Create the active lane mask for the next iteration of the loop.
CanonicalIVIncrementParts =
new VPInstruction(HasNUW ? VPInstruction::CanonicalIVIncrementForPartNUW
: VPInstruction::CanonicalIVIncrementForPart,
{CanonicalIVIncrement}, DL);
EB->appendRecipe(CanonicalIVIncrementParts);
auto *ALM = new VPInstruction(VPInstruction::ActiveLaneMask,
{CanonicalIVIncrementParts, TC}, DL,
"active.lane.mask.next");
EB->appendRecipe(ALM);
LaneMaskPhi->addOperand(ALM);
// We have to invert the mask here because a true condition means jumping
// to the exit block.
auto *NotMask = new VPInstruction(VPInstruction::Not, ALM, DL);
EB->appendRecipe(NotMask);
VPInstruction *BranchBack =
new VPInstruction(VPInstruction::BranchOnCond, {NotMask}, DL);
EB->appendRecipe(BranchBack);
} else {
// Add the BranchOnCount VPInstruction to the latch.
VPInstruction *BranchBack = new VPInstruction(
VPInstruction::BranchOnCount,
{CanonicalIVIncrement, &Plan.getVectorTripCount()}, DL);
EB->appendRecipe(BranchBack);
}
}
// Add exit values to \p Plan. VPLiveOuts are added for each LCSSA phi in the
// original exit block.
static void addUsersInExitBlock(VPBasicBlock *HeaderVPBB,
VPBasicBlock *MiddleVPBB, Loop *OrigLoop,
VPlan &Plan) {
BasicBlock *ExitBB = OrigLoop->getUniqueExitBlock();
BasicBlock *ExitingBB = OrigLoop->getExitingBlock();
// Only handle single-exit loops with unique exit blocks for now.
if (!ExitBB || !ExitBB->getSinglePredecessor() || !ExitingBB)
return;
// Introduce VPUsers modeling the exit values.
for (PHINode &ExitPhi : ExitBB->phis()) {
Value *IncomingValue =
ExitPhi.getIncomingValueForBlock(ExitingBB);
VPValue *V = Plan.getOrAddVPValue(IncomingValue, true);
Plan.addLiveOut(&ExitPhi, V);
}
}
VPlanPtr LoopVectorizationPlanner::buildVPlanWithVPRecipes(
VFRange &Range, SmallPtrSetImpl<Instruction *> &DeadInstructions,
const MapVector<Instruction *, Instruction *> &SinkAfter) {
SmallPtrSet<const InterleaveGroup<Instruction> *, 1> InterleaveGroups;
VPRecipeBuilder RecipeBuilder(OrigLoop, TLI, Legal, CM, PSE, Builder);
// ---------------------------------------------------------------------------
// Pre-construction: record ingredients whose recipes we'll need to further
// process after constructing the initial VPlan.
// ---------------------------------------------------------------------------
// Mark instructions we'll need to sink later and their targets as
// ingredients whose recipe we'll need to record.
for (auto &Entry : SinkAfter) {
RecipeBuilder.recordRecipeOf(Entry.first);
RecipeBuilder.recordRecipeOf(Entry.second);
}
for (auto &Reduction : CM.getInLoopReductionChains()) {
PHINode *Phi = Reduction.first;
RecurKind Kind =
Legal->getReductionVars().find(Phi)->second.getRecurrenceKind();
const SmallVector<Instruction *, 4> &ReductionOperations = Reduction.second;
RecipeBuilder.recordRecipeOf(Phi);
for (auto &R : ReductionOperations) {
RecipeBuilder.recordRecipeOf(R);
// For min/max reductions, where we have a pair of icmp/select, we also
// need to record the ICmp recipe, so it can be removed later.
assert(!RecurrenceDescriptor::isSelectCmpRecurrenceKind(Kind) &&
"Only min/max recurrences allowed for inloop reductions");
if (RecurrenceDescriptor::isMinMaxRecurrenceKind(Kind))
RecipeBuilder.recordRecipeOf(cast<Instruction>(R->getOperand(0)));
}
}
// For each interleave group which is relevant for this (possibly trimmed)
// Range, add it to the set of groups to be later applied to the VPlan and add
// placeholders for its members' Recipes which we'll be replacing with a
// single VPInterleaveRecipe.
for (InterleaveGroup<Instruction> *IG : IAI.getInterleaveGroups()) {
auto applyIG = [IG, this](ElementCount VF) -> bool {
return (VF.isVector() && // Query is illegal for VF == 1
CM.getWideningDecision(IG->getInsertPos(), VF) ==
LoopVectorizationCostModel::CM_Interleave);
};
if (!getDecisionAndClampRange(applyIG, Range))
continue;
InterleaveGroups.insert(IG);
for (unsigned i = 0; i < IG->getFactor(); i++)
if (Instruction *Member = IG->getMember(i))
RecipeBuilder.recordRecipeOf(Member);
};
// ---------------------------------------------------------------------------
// Build initial VPlan: Scan the body of the loop in a topological order to
// visit each basic block after having visited its predecessor basic blocks.
// ---------------------------------------------------------------------------
// Create initial VPlan skeleton, starting with a block for the pre-header,
// followed by a region for the vector loop, followed by the middle block. The
// skeleton vector loop region contains a header and latch block.
VPBasicBlock *Preheader = new VPBasicBlock("vector.ph");
auto Plan = std::make_unique<VPlan>(Preheader);
VPBasicBlock *HeaderVPBB = new VPBasicBlock("vector.body");
VPBasicBlock *LatchVPBB = new VPBasicBlock("vector.latch");
VPBlockUtils::insertBlockAfter(LatchVPBB, HeaderVPBB);
auto *TopRegion = new VPRegionBlock(HeaderVPBB, LatchVPBB, "vector loop");
VPBlockUtils::insertBlockAfter(TopRegion, Preheader);
VPBasicBlock *MiddleVPBB = new VPBasicBlock("middle.block");
VPBlockUtils::insertBlockAfter(MiddleVPBB, TopRegion);
Instruction *DLInst =
getDebugLocFromInstOrOperands(Legal->getPrimaryInduction());
addCanonicalIVRecipes(*Plan, Legal->getWidestInductionType(),
DLInst ? DLInst->getDebugLoc() : DebugLoc(),
!CM.foldTailByMasking(),
CM.useActiveLaneMaskForControlFlow());
// Scan the body of the loop in a topological order to visit each basic block
// after having visited its predecessor basic blocks.
LoopBlocksDFS DFS(OrigLoop);
DFS.perform(LI);
VPBasicBlock *VPBB = HeaderVPBB;
SmallVector<VPWidenIntOrFpInductionRecipe *> InductionsToMove;
for (BasicBlock *BB : make_range(DFS.beginRPO(), DFS.endRPO())) {
// Relevant instructions from basic block BB will be grouped into VPRecipe
// ingredients and fill a new VPBasicBlock.
unsigned VPBBsForBB = 0;
if (VPBB != HeaderVPBB)
VPBB->setName(BB->getName());
Builder.setInsertPoint(VPBB);
// Introduce each ingredient into VPlan.
// TODO: Model and preserve debug intrinsics in VPlan.
for (Instruction &I : BB->instructionsWithoutDebug()) {
Instruction *Instr = &I;
// First filter out irrelevant instructions, to ensure no recipes are
// built for them.
if (isa<BranchInst>(Instr) || DeadInstructions.count(Instr))
continue;
SmallVector<VPValue *, 4> Operands;
auto *Phi = dyn_cast<PHINode>(Instr);
if (Phi && Phi->getParent() == OrigLoop->getHeader()) {
Operands.push_back(Plan->getOrAddVPValue(
Phi->getIncomingValueForBlock(OrigLoop->getLoopPreheader())));
} else {
auto OpRange = Plan->mapToVPValues(Instr->operands());
Operands = {OpRange.begin(), OpRange.end()};
}
// Invariant stores inside loop will be deleted and a single store
// with the final reduction value will be added to the exit block
StoreInst *SI;
if ((SI = dyn_cast<StoreInst>(&I)) &&
Legal->isInvariantAddressOfReduction(SI->getPointerOperand()))
continue;
if (auto RecipeOrValue = RecipeBuilder.tryToCreateWidenRecipe(
Instr, Operands, Range, Plan)) {
// If Instr can be simplified to an existing VPValue, use it.
if (RecipeOrValue.is<VPValue *>()) {
auto *VPV = RecipeOrValue.get<VPValue *>();
Plan->addVPValue(Instr, VPV);
// If the re-used value is a recipe, register the recipe for the
// instruction, in case the recipe for Instr needs to be recorded.
if (auto *R = dyn_cast_or_null<VPRecipeBase>(VPV->getDef()))
RecipeBuilder.setRecipe(Instr, R);
continue;
}
// Otherwise, add the new recipe.
VPRecipeBase *Recipe = RecipeOrValue.get<VPRecipeBase *>();
for (auto *Def : Recipe->definedValues()) {
auto *UV = Def->getUnderlyingValue();
Plan->addVPValue(UV, Def);
}
if (isa<VPWidenIntOrFpInductionRecipe>(Recipe) &&
HeaderVPBB->getFirstNonPhi() != VPBB->end()) {
// Keep track of VPWidenIntOrFpInductionRecipes not in the phi section
// of the header block. That can happen for truncates of induction
// variables. Those recipes are moved to the phi section of the header
// block after applying SinkAfter, which relies on the original
// position of the trunc.
assert(isa<TruncInst>(Instr));
InductionsToMove.push_back(
cast<VPWidenIntOrFpInductionRecipe>(Recipe));
}
RecipeBuilder.setRecipe(Instr, Recipe);
VPBB->appendRecipe(Recipe);
continue;
}
// Otherwise, if all widening options failed, Instruction is to be
// replicated. This may create a successor for VPBB.
VPBasicBlock *NextVPBB =
RecipeBuilder.handleReplication(Instr, Range, VPBB, Plan);
if (NextVPBB != VPBB) {
VPBB = NextVPBB;
VPBB->setName(BB->hasName() ? BB->getName() + "." + Twine(VPBBsForBB++)
: "");
}
}
VPBlockUtils::insertBlockAfter(new VPBasicBlock(), VPBB);
VPBB = cast<VPBasicBlock>(VPBB->getSingleSuccessor());
}
HeaderVPBB->setName("vector.body");
// Fold the last, empty block into its predecessor.
VPBB = VPBlockUtils::tryToMergeBlockIntoPredecessor(VPBB);
assert(VPBB && "expected to fold last (empty) block");
// After here, VPBB should not be used.
VPBB = nullptr;
addUsersInExitBlock(HeaderVPBB, MiddleVPBB, OrigLoop, *Plan);
assert(isa<VPRegionBlock>(Plan->getVectorLoopRegion()) &&
!Plan->getVectorLoopRegion()->getEntryBasicBlock()->empty() &&
"entry block must be set to a VPRegionBlock having a non-empty entry "
"VPBasicBlock");
RecipeBuilder.fixHeaderPhis();
// ---------------------------------------------------------------------------
// Transform initial VPlan: Apply previously taken decisions, in order, to
// bring the VPlan to its final state.
// ---------------------------------------------------------------------------
// Apply Sink-After legal constraints.
auto GetReplicateRegion = [](VPRecipeBase *R) -> VPRegionBlock * {
auto *Region = dyn_cast_or_null<VPRegionBlock>(R->getParent()->getParent());
if (Region && Region->isReplicator()) {
assert(Region->getNumSuccessors() == 1 &&
Region->getNumPredecessors() == 1 && "Expected SESE region!");
assert(R->getParent()->size() == 1 &&
"A recipe in an original replicator region must be the only "
"recipe in its block");
return Region;
}
return nullptr;
};
for (auto &Entry : SinkAfter) {
VPRecipeBase *Sink = RecipeBuilder.getRecipe(Entry.first);
VPRecipeBase *Target = RecipeBuilder.getRecipe(Entry.second);
auto *TargetRegion = GetReplicateRegion(Target);
auto *SinkRegion = GetReplicateRegion(Sink);
if (!SinkRegion) {
// If the sink source is not a replicate region, sink the recipe directly.
if (TargetRegion) {
// The target is in a replication region, make sure to move Sink to
// the block after it, not into the replication region itself.
VPBasicBlock *NextBlock =
cast<VPBasicBlock>(TargetRegion->getSuccessors().front());
Sink->moveBefore(*NextBlock, NextBlock->getFirstNonPhi());
} else
Sink->moveAfter(Target);
continue;
}
// The sink source is in a replicate region. Unhook the region from the CFG.
auto *SinkPred = SinkRegion->getSinglePredecessor();
auto *SinkSucc = SinkRegion->getSingleSuccessor();
VPBlockUtils::disconnectBlocks(SinkPred, SinkRegion);
VPBlockUtils::disconnectBlocks(SinkRegion, SinkSucc);
VPBlockUtils::connectBlocks(SinkPred, SinkSucc);
if (TargetRegion) {
// The target recipe is also in a replicate region, move the sink region
// after the target region.
auto *TargetSucc = TargetRegion->getSingleSuccessor();
VPBlockUtils::disconnectBlocks(TargetRegion, TargetSucc);
VPBlockUtils::connectBlocks(TargetRegion, SinkRegion);
VPBlockUtils::connectBlocks(SinkRegion, TargetSucc);
} else {
// The sink source is in a replicate region, we need to move the whole
// replicate region, which should only contain a single recipe in the
// main block.
auto *SplitBlock =
Target->getParent()->splitAt(std::next(Target->getIterator()));
auto *SplitPred = SplitBlock->getSinglePredecessor();
VPBlockUtils::disconnectBlocks(SplitPred, SplitBlock);
VPBlockUtils::connectBlocks(SplitPred, SinkRegion);
VPBlockUtils::connectBlocks(SinkRegion, SplitBlock);
}
}
VPlanTransforms::removeRedundantCanonicalIVs(*Plan);
VPlanTransforms::removeRedundantInductionCasts(*Plan);
// Now that sink-after is done, move induction recipes for optimized truncates
// to the phi section of the header block.
for (VPWidenIntOrFpInductionRecipe *Ind : InductionsToMove)
Ind->moveBefore(*HeaderVPBB, HeaderVPBB->getFirstNonPhi());
// Adjust the recipes for any inloop reductions.
adjustRecipesForReductions(cast<VPBasicBlock>(TopRegion->getExiting()), Plan,
RecipeBuilder, Range.Start);
// Introduce a recipe to combine the incoming and previous values of a
// first-order recurrence.
for (VPRecipeBase &R :
Plan->getVectorLoopRegion()->getEntryBasicBlock()->phis()) {
auto *RecurPhi = dyn_cast<VPFirstOrderRecurrencePHIRecipe>(&R);
if (!RecurPhi)
continue;
VPRecipeBase *PrevRecipe = RecurPhi->getBackedgeRecipe();
VPBasicBlock *InsertBlock = PrevRecipe->getParent();
auto *Region = GetReplicateRegion(PrevRecipe);
if (Region)
InsertBlock = dyn_cast<VPBasicBlock>(Region->getSingleSuccessor());
if (!InsertBlock) {
InsertBlock = new VPBasicBlock(Region->getName() + ".succ");
VPBlockUtils::insertBlockAfter(InsertBlock, Region);
}
if (Region || PrevRecipe->isPhi())
Builder.setInsertPoint(InsertBlock, InsertBlock->getFirstNonPhi());
else
Builder.setInsertPoint(InsertBlock, std::next(PrevRecipe->getIterator()));
auto *RecurSplice = cast<VPInstruction>(
Builder.createNaryOp(VPInstruction::FirstOrderRecurrenceSplice,
{RecurPhi, RecurPhi->getBackedgeValue()}));
RecurPhi->replaceAllUsesWith(RecurSplice);
// Set the first operand of RecurSplice to RecurPhi again, after replacing
// all users.
RecurSplice->setOperand(0, RecurPhi);
}
// Interleave memory: for each Interleave Group we marked earlier as relevant
// for this VPlan, replace the Recipes widening its memory instructions with a
// single VPInterleaveRecipe at its insertion point.
for (auto IG : InterleaveGroups) {
auto *Recipe = cast<VPWidenMemoryInstructionRecipe>(
RecipeBuilder.getRecipe(IG->getInsertPos()));
SmallVector<VPValue *, 4> StoredValues;
for (unsigned i = 0; i < IG->getFactor(); ++i)
if (auto *SI = dyn_cast_or_null<StoreInst>(IG->getMember(i))) {
auto *StoreR =
cast<VPWidenMemoryInstructionRecipe>(RecipeBuilder.getRecipe(SI));
StoredValues.push_back(StoreR->getStoredValue());
}
auto *VPIG = new VPInterleaveRecipe(IG, Recipe->getAddr(), StoredValues,
Recipe->getMask());
VPIG->insertBefore(Recipe);
unsigned J = 0;
for (unsigned i = 0; i < IG->getFactor(); ++i)
if (Instruction *Member = IG->getMember(i)) {
if (!Member->getType()->isVoidTy()) {
VPValue *OriginalV = Plan->getVPValue(Member);
Plan->removeVPValueFor(Member);
Plan->addVPValue(Member, VPIG->getVPValue(J));
OriginalV->replaceAllUsesWith(VPIG->getVPValue(J));
J++;
}
RecipeBuilder.getRecipe(Member)->eraseFromParent();
}
}
std::string PlanName;
raw_string_ostream RSO(PlanName);
ElementCount VF = Range.Start;
Plan->addVF(VF);
RSO << "Initial VPlan for VF={" << VF;
for (VF *= 2; ElementCount::isKnownLT(VF, Range.End); VF *= 2) {
Plan->addVF(VF);
RSO << "," << VF;
}
RSO << "},UF>=1";
RSO.flush();
Plan->setName(PlanName);
// From this point onwards, VPlan-to-VPlan transformations may change the plan
// in ways that accessing values using original IR values is incorrect.
Plan->disableValue2VPValue();
VPlanTransforms::optimizeInductions(*Plan, *PSE.getSE());
VPlanTransforms::sinkScalarOperands(*Plan);
VPlanTransforms::removeDeadRecipes(*Plan);
VPlanTransforms::mergeReplicateRegions(*Plan);
VPlanTransforms::removeRedundantExpandSCEVRecipes(*Plan);
// Fold Exit block into its predecessor if possible.
// TODO: Fold block earlier once all VPlan transforms properly maintain a
// VPBasicBlock as exit.
VPBlockUtils::tryToMergeBlockIntoPredecessor(TopRegion->getExiting());
assert(VPlanVerifier::verifyPlanIsValid(*Plan) && "VPlan is invalid");
return Plan;
}
VPlanPtr LoopVectorizationPlanner::buildVPlan(VFRange &Range) {
// Outer loop handling: They may require CFG and instruction level
// transformations before even evaluating whether vectorization is profitable.
// Since we cannot modify the incoming IR, we need to build VPlan upfront in
// the vectorization pipeline.
assert(!OrigLoop->isInnermost());
assert(EnableVPlanNativePath && "VPlan-native path is not enabled.");
// Create new empty VPlan
auto Plan = std::make_unique<VPlan>();
// Build hierarchical CFG
VPlanHCFGBuilder HCFGBuilder(OrigLoop, LI, *Plan);
HCFGBuilder.buildHierarchicalCFG();
for (ElementCount VF = Range.Start; ElementCount::isKnownLT(VF, Range.End);
VF *= 2)
Plan->addVF(VF);
SmallPtrSet<Instruction *, 1> DeadInstructions;
VPlanTransforms::VPInstructionsToVPRecipes(
OrigLoop, Plan,
[this](PHINode *P) { return Legal->getIntOrFpInductionDescriptor(P); },
DeadInstructions, *PSE.getSE());
// Remove the existing terminator of the exiting block of the top-most region.
// A BranchOnCount will be added instead when adding the canonical IV recipes.
auto *Term =
Plan->getVectorLoopRegion()->getExitingBasicBlock()->getTerminator();
Term->eraseFromParent();
addCanonicalIVRecipes(*Plan, Legal->getWidestInductionType(), DebugLoc(),
true, CM.useActiveLaneMaskForControlFlow());
return Plan;
}
// Adjust the recipes for reductions. For in-loop reductions the chain of
// instructions leading from the loop exit instr to the phi need to be converted
// to reductions, with one operand being vector and the other being the scalar
// reduction chain. For other reductions, a select is introduced between the phi
// and live-out recipes when folding the tail.
void LoopVectorizationPlanner::adjustRecipesForReductions(
VPBasicBlock *LatchVPBB, VPlanPtr &Plan, VPRecipeBuilder &RecipeBuilder,
ElementCount MinVF) {
for (auto &Reduction : CM.getInLoopReductionChains()) {
PHINode *Phi = Reduction.first;
const RecurrenceDescriptor &RdxDesc =
Legal->getReductionVars().find(Phi)->second;
const SmallVector<Instruction *, 4> &ReductionOperations = Reduction.second;
if (MinVF.isScalar() && !CM.useOrderedReductions(RdxDesc))
continue;
// ReductionOperations are orders top-down from the phi's use to the
// LoopExitValue. We keep a track of the previous item (the Chain) to tell
// which of the two operands will remain scalar and which will be reduced.
// For minmax the chain will be the select instructions.
Instruction *Chain = Phi;
for (Instruction *R : ReductionOperations) {
VPRecipeBase *WidenRecipe = RecipeBuilder.getRecipe(R);
RecurKind Kind = RdxDesc.getRecurrenceKind();
VPValue *ChainOp = Plan->getVPValue(Chain);
unsigned FirstOpId;
assert(!RecurrenceDescriptor::isSelectCmpRecurrenceKind(Kind) &&
"Only min/max recurrences allowed for inloop reductions");
// Recognize a call to the llvm.fmuladd intrinsic.
bool IsFMulAdd = (Kind == RecurKind::FMulAdd);
assert((!IsFMulAdd || RecurrenceDescriptor::isFMulAddIntrinsic(R)) &&
"Expected instruction to be a call to the llvm.fmuladd intrinsic");
if (RecurrenceDescriptor::isMinMaxRecurrenceKind(Kind)) {
assert(isa<VPWidenSelectRecipe>(WidenRecipe) &&
"Expected to replace a VPWidenSelectSC");
FirstOpId = 1;
} else {
assert((MinVF.isScalar() || isa<VPWidenRecipe>(WidenRecipe) ||
(IsFMulAdd && isa<VPWidenCallRecipe>(WidenRecipe))) &&
"Expected to replace a VPWidenSC");
FirstOpId = 0;
}
unsigned VecOpId =
R->getOperand(FirstOpId) == Chain ? FirstOpId + 1 : FirstOpId;
VPValue *VecOp = Plan->getVPValue(R->getOperand(VecOpId));
auto *CondOp = CM.blockNeedsPredicationForAnyReason(R->getParent())
? RecipeBuilder.createBlockInMask(R->getParent(), Plan)
: nullptr;
if (IsFMulAdd) {
// If the instruction is a call to the llvm.fmuladd intrinsic then we
// need to create an fmul recipe to use as the vector operand for the
// fadd reduction.
VPInstruction *FMulRecipe = new VPInstruction(
Instruction::FMul, {VecOp, Plan->getVPValue(R->getOperand(1))});
FMulRecipe->setFastMathFlags(R->getFastMathFlags());
WidenRecipe->getParent()->insert(FMulRecipe,
WidenRecipe->getIterator());
VecOp = FMulRecipe;
}
VPReductionRecipe *RedRecipe =
new VPReductionRecipe(&RdxDesc, R, ChainOp, VecOp, CondOp, TTI);
WidenRecipe->getVPSingleValue()->replaceAllUsesWith(RedRecipe);
Plan->removeVPValueFor(R);
Plan->addVPValue(R, RedRecipe);
// Append the recipe to the end of the VPBasicBlock because we need to
// ensure that it comes after all of it's inputs, including CondOp.
WidenRecipe->getParent()->appendRecipe(RedRecipe);
WidenRecipe->getVPSingleValue()->replaceAllUsesWith(RedRecipe);
WidenRecipe->eraseFromParent();
if (RecurrenceDescriptor::isMinMaxRecurrenceKind(Kind)) {
VPRecipeBase *CompareRecipe =
RecipeBuilder.getRecipe(cast<Instruction>(R->getOperand(0)));
assert(isa<VPWidenRecipe>(CompareRecipe) &&
"Expected to replace a VPWidenSC");
assert(cast<VPWidenRecipe>(CompareRecipe)->getNumUsers() == 0 &&
"Expected no remaining users");
CompareRecipe->eraseFromParent();
}
Chain = R;
}
}
// If tail is folded by masking, introduce selects between the phi
// and the live-out instruction of each reduction, at the beginning of the
// dedicated latch block.
if (CM.foldTailByMasking()) {
Builder.setInsertPoint(LatchVPBB, LatchVPBB->begin());
for (VPRecipeBase &R :
Plan->getVectorLoopRegion()->getEntryBasicBlock()->phis()) {
VPReductionPHIRecipe *PhiR = dyn_cast<VPReductionPHIRecipe>(&R);
if (!PhiR || PhiR->isInLoop())
continue;
VPValue *Cond =
RecipeBuilder.createBlockInMask(OrigLoop->getHeader(), Plan);
VPValue *Red = PhiR->getBackedgeValue();
assert(cast<VPRecipeBase>(Red->getDef())->getParent() != LatchVPBB &&
"reduction recipe must be defined before latch");
Builder.createNaryOp(Instruction::Select, {Cond, Red, PhiR});
}
}
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPInterleaveRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "INTERLEAVE-GROUP with factor " << IG->getFactor() << " at ";
IG->getInsertPos()->printAsOperand(O, false);
O << ", ";
getAddr()->printAsOperand(O, SlotTracker);
VPValue *Mask = getMask();
if (Mask) {
O << ", ";
Mask->printAsOperand(O, SlotTracker);
}
unsigned OpIdx = 0;
for (unsigned i = 0; i < IG->getFactor(); ++i) {
if (!IG->getMember(i))
continue;
if (getNumStoreOperands() > 0) {
O << "\n" << Indent << " store ";
getOperand(1 + OpIdx)->printAsOperand(O, SlotTracker);
O << " to index " << i;
} else {
O << "\n" << Indent << " ";
getVPValue(OpIdx)->printAsOperand(O, SlotTracker);
O << " = load from index " << i;
}
++OpIdx;
}
}
#endif
void VPWidenCallRecipe::execute(VPTransformState &State) {
State.ILV->widenCallInstruction(*cast<CallInst>(getUnderlyingInstr()), this,
*this, State);
}
void VPWidenIntOrFpInductionRecipe::execute(VPTransformState &State) {
assert(!State.Instance && "Int or FP induction being replicated.");
Value *Start = getStartValue()->getLiveInIRValue();
const InductionDescriptor &ID = getInductionDescriptor();
TruncInst *Trunc = getTruncInst();
IRBuilderBase &Builder = State.Builder;
assert(IV->getType() == ID.getStartValue()->getType() && "Types must match");
assert(State.VF.isVector() && "must have vector VF");
// The value from the original loop to which we are mapping the new induction
// variable.
Instruction *EntryVal = Trunc ? cast<Instruction>(Trunc) : IV;
// Fast-math-flags propagate from the original induction instruction.
IRBuilder<>::FastMathFlagGuard FMFG(Builder);
if (ID.getInductionBinOp() && isa<FPMathOperator>(ID.getInductionBinOp()))
Builder.setFastMathFlags(ID.getInductionBinOp()->getFastMathFlags());
// Now do the actual transformations, and start with fetching the step value.
Value *Step = State.get(getStepValue(), VPIteration(0, 0));
assert((isa<PHINode>(EntryVal) || isa<TruncInst>(EntryVal)) &&
"Expected either an induction phi-node or a truncate of it!");
// Construct the initial value of the vector IV in the vector loop preheader
auto CurrIP = Builder.saveIP();
BasicBlock *VectorPH = State.CFG.getPreheaderBBFor(this);
Builder.SetInsertPoint(VectorPH->getTerminator());
if (isa<TruncInst>(EntryVal)) {
assert(Start->getType()->isIntegerTy() &&
"Truncation requires an integer type");
auto *TruncType = cast<IntegerType>(EntryVal->getType());
Step = Builder.CreateTrunc(Step, TruncType);
Start = Builder.CreateCast(Instruction::Trunc, Start, TruncType);
}
Value *Zero = getSignedIntOrFpConstant(Start->getType(), 0);
Value *SplatStart = Builder.CreateVectorSplat(State.VF, Start);
Value *SteppedStart = getStepVector(
SplatStart, Zero, Step, ID.getInductionOpcode(), State.VF, State.Builder);
// We create vector phi nodes for both integer and floating-point induction
// variables. Here, we determine the kind of arithmetic we will perform.
Instruction::BinaryOps AddOp;
Instruction::BinaryOps MulOp;
if (Step->getType()->isIntegerTy()) {
AddOp = Instruction::Add;
MulOp = Instruction::Mul;
} else {
AddOp = ID.getInductionOpcode();
MulOp = Instruction::FMul;
}
// Multiply the vectorization factor by the step using integer or
// floating-point arithmetic as appropriate.
Type *StepType = Step->getType();
Value *RuntimeVF;
if (Step->getType()->isFloatingPointTy())
RuntimeVF = getRuntimeVFAsFloat(Builder, StepType, State.VF);
else
RuntimeVF = getRuntimeVF(Builder, StepType, State.VF);
Value *Mul = Builder.CreateBinOp(MulOp, Step, RuntimeVF);
// Create a vector splat to use in the induction update.
//
// FIXME: If the step is non-constant, we create the vector splat with
// IRBuilder. IRBuilder can constant-fold the multiply, but it doesn't
// handle a constant vector splat.
Value *SplatVF = isa<Constant>(Mul)
? ConstantVector::getSplat(State.VF, cast<Constant>(Mul))
: Builder.CreateVectorSplat(State.VF, Mul);
Builder.restoreIP(CurrIP);
// We may need to add the step a number of times, depending on the unroll
// factor. The last of those goes into the PHI.
PHINode *VecInd = PHINode::Create(SteppedStart->getType(), 2, "vec.ind",
&*State.CFG.PrevBB->getFirstInsertionPt());
VecInd->setDebugLoc(EntryVal->getDebugLoc());
Instruction *LastInduction = VecInd;
for (unsigned Part = 0; Part < State.UF; ++Part) {
State.set(this, LastInduction, Part);
if (isa<TruncInst>(EntryVal))
State.addMetadata(LastInduction, EntryVal);
LastInduction = cast<Instruction>(
Builder.CreateBinOp(AddOp, LastInduction, SplatVF, "step.add"));
LastInduction->setDebugLoc(EntryVal->getDebugLoc());
}
LastInduction->setName("vec.ind.next");
VecInd->addIncoming(SteppedStart, VectorPH);
// Add induction update using an incorrect block temporarily. The phi node
// will be fixed after VPlan execution. Note that at this point the latch
// block cannot be used, as it does not exist yet.
// TODO: Model increment value in VPlan, by turning the recipe into a
// multi-def and a subclass of VPHeaderPHIRecipe.
VecInd->addIncoming(LastInduction, VectorPH);
}
void VPWidenPointerInductionRecipe::execute(VPTransformState &State) {
assert(IndDesc.getKind() == InductionDescriptor::IK_PtrInduction &&
"Not a pointer induction according to InductionDescriptor!");
assert(cast<PHINode>(getUnderlyingInstr())->getType()->isPointerTy() &&
"Unexpected type.");
auto *IVR = getParent()->getPlan()->getCanonicalIV();
PHINode *CanonicalIV = cast<PHINode>(State.get(IVR, 0));
if (onlyScalarsGenerated(State.VF)) {
// This is the normalized GEP that starts counting at zero.
Value *PtrInd = State.Builder.CreateSExtOrTrunc(
CanonicalIV, IndDesc.getStep()->getType());
// Determine the number of scalars we need to generate for each unroll
// iteration. If the instruction is uniform, we only need to generate the
// first lane. Otherwise, we generate all VF values.
bool IsUniform = vputils::onlyFirstLaneUsed(this);
assert((IsUniform || !State.VF.isScalable()) &&
"Cannot scalarize a scalable VF");
unsigned Lanes = IsUniform ? 1 : State.VF.getFixedValue();
for (unsigned Part = 0; Part < State.UF; ++Part) {
Value *PartStart =
createStepForVF(State.Builder, PtrInd->getType(), State.VF, Part);
for (unsigned Lane = 0; Lane < Lanes; ++Lane) {
Value *Idx = State.Builder.CreateAdd(
PartStart, ConstantInt::get(PtrInd->getType(), Lane));
Value *GlobalIdx = State.Builder.CreateAdd(PtrInd, Idx);
Value *Step = CreateStepValue(IndDesc.getStep(), SE,
State.CFG.PrevBB->getTerminator());
Value *SclrGep = emitTransformedIndex(
State.Builder, GlobalIdx, IndDesc.getStartValue(), Step, IndDesc);
SclrGep->setName("next.gep");
State.set(this, SclrGep, VPIteration(Part, Lane));
}
}
return;
}
assert(isa<SCEVConstant>(IndDesc.getStep()) &&
"Induction step not a SCEV constant!");
Type *PhiType = IndDesc.getStep()->getType();
// Build a pointer phi
Value *ScalarStartValue = getStartValue()->getLiveInIRValue();
Type *ScStValueType = ScalarStartValue->getType();
PHINode *NewPointerPhi =
PHINode::Create(ScStValueType, 2, "pointer.phi", CanonicalIV);
BasicBlock *VectorPH = State.CFG.getPreheaderBBFor(this);
NewPointerPhi->addIncoming(ScalarStartValue, VectorPH);
// A pointer induction, performed by using a gep
const DataLayout &DL = NewPointerPhi->getModule()->getDataLayout();
Instruction *InductionLoc = &*State.Builder.GetInsertPoint();
const SCEV *ScalarStep = IndDesc.getStep();
SCEVExpander Exp(SE, DL, "induction");
Value *ScalarStepValue = Exp.expandCodeFor(ScalarStep, PhiType, InductionLoc);
Value *RuntimeVF = getRuntimeVF(State.Builder, PhiType, State.VF);
Value *NumUnrolledElems =
State.Builder.CreateMul(RuntimeVF, ConstantInt::get(PhiType, State.UF));
Value *InductionGEP = GetElementPtrInst::Create(
IndDesc.getElementType(), NewPointerPhi,
State.Builder.CreateMul(ScalarStepValue, NumUnrolledElems), "ptr.ind",
InductionLoc);
// Add induction update using an incorrect block temporarily. The phi node
// will be fixed after VPlan execution. Note that at this point the latch
// block cannot be used, as it does not exist yet.
// TODO: Model increment value in VPlan, by turning the recipe into a
// multi-def and a subclass of VPHeaderPHIRecipe.
NewPointerPhi->addIncoming(InductionGEP, VectorPH);
// Create UF many actual address geps that use the pointer
// phi as base and a vectorized version of the step value
// (<step*0, ..., step*N>) as offset.
for (unsigned Part = 0; Part < State.UF; ++Part) {
Type *VecPhiType = VectorType::get(PhiType, State.VF);
Value *StartOffsetScalar =
State.Builder.CreateMul(RuntimeVF, ConstantInt::get(PhiType, Part));
Value *StartOffset =
State.Builder.CreateVectorSplat(State.VF, StartOffsetScalar);
// Create a vector of consecutive numbers from zero to VF.
StartOffset = State.Builder.CreateAdd(
StartOffset, State.Builder.CreateStepVector(VecPhiType));
Value *GEP = State.Builder.CreateGEP(
IndDesc.getElementType(), NewPointerPhi,
State.Builder.CreateMul(
StartOffset,
State.Builder.CreateVectorSplat(State.VF, ScalarStepValue),
"vector.gep"));
State.set(this, GEP, Part);
}
}
void VPScalarIVStepsRecipe::execute(VPTransformState &State) {
assert(!State.Instance && "VPScalarIVStepsRecipe being replicated.");
// Fast-math-flags propagate from the original induction instruction.
IRBuilder<>::FastMathFlagGuard FMFG(State.Builder);
if (IndDesc.getInductionBinOp() &&
isa<FPMathOperator>(IndDesc.getInductionBinOp()))
State.Builder.setFastMathFlags(
IndDesc.getInductionBinOp()->getFastMathFlags());
Value *Step = State.get(getStepValue(), VPIteration(0, 0));
auto CreateScalarIV = [&](Value *&Step) -> Value * {
Value *ScalarIV = State.get(getCanonicalIV(), VPIteration(0, 0));
auto *CanonicalIV = State.get(getParent()->getPlan()->getCanonicalIV(), 0);
if (!isCanonical() || CanonicalIV->getType() != Ty) {
ScalarIV =
Ty->isIntegerTy()
? State.Builder.CreateSExtOrTrunc(ScalarIV, Ty)
: State.Builder.CreateCast(Instruction::SIToFP, ScalarIV, Ty);
ScalarIV = emitTransformedIndex(State.Builder, ScalarIV,
getStartValue()->getLiveInIRValue(), Step,
IndDesc);
ScalarIV->setName("offset.idx");
}
if (TruncToTy) {
assert(Step->getType()->isIntegerTy() &&
"Truncation requires an integer step");
ScalarIV = State.Builder.CreateTrunc(ScalarIV, TruncToTy);
Step = State.Builder.CreateTrunc(Step, TruncToTy);
}
return ScalarIV;
};
Value *ScalarIV = CreateScalarIV(Step);
if (State.VF.isVector()) {
buildScalarSteps(ScalarIV, Step, IndDesc, this, State);
return;
}
for (unsigned Part = 0; Part < State.UF; ++Part) {
assert(!State.VF.isScalable() && "scalable vectors not yet supported.");
Value *EntryPart;
if (Step->getType()->isFloatingPointTy()) {
Value *StartIdx =
getRuntimeVFAsFloat(State.Builder, Step->getType(), State.VF * Part);
// Floating-point operations inherit FMF via the builder's flags.
Value *MulOp = State.Builder.CreateFMul(StartIdx, Step);
EntryPart = State.Builder.CreateBinOp(IndDesc.getInductionOpcode(),
ScalarIV, MulOp);
} else {
Value *StartIdx =
getRuntimeVF(State.Builder, Step->getType(), State.VF * Part);
EntryPart = State.Builder.CreateAdd(
ScalarIV, State.Builder.CreateMul(StartIdx, Step), "induction");
}
State.set(this, EntryPart, Part);
}
}
void VPInterleaveRecipe::execute(VPTransformState &State) {
assert(!State.Instance && "Interleave group being replicated.");
State.ILV->vectorizeInterleaveGroup(IG, definedValues(), State, getAddr(),
getStoredValues(), getMask());
}
void VPReductionRecipe::execute(VPTransformState &State) {
assert(!State.Instance && "Reduction being replicated.");
Value *PrevInChain = State.get(getChainOp(), 0);
RecurKind Kind = RdxDesc->getRecurrenceKind();
bool IsOrdered = State.ILV->useOrderedReductions(*RdxDesc);
// Propagate the fast-math flags carried by the underlying instruction.
IRBuilderBase::FastMathFlagGuard FMFGuard(State.Builder);
State.Builder.setFastMathFlags(RdxDesc->getFastMathFlags());
for (unsigned Part = 0; Part < State.UF; ++Part) {
Value *NewVecOp = State.get(getVecOp(), Part);
if (VPValue *Cond = getCondOp()) {
Value *NewCond = State.get(Cond, Part);
VectorType *VecTy = cast<VectorType>(NewVecOp->getType());
Value *Iden = RdxDesc->getRecurrenceIdentity(
Kind, VecTy->getElementType(), RdxDesc->getFastMathFlags());
Value *IdenVec =
State.Builder.CreateVectorSplat(VecTy->getElementCount(), Iden);
Value *Select = State.Builder.CreateSelect(NewCond, NewVecOp, IdenVec);
NewVecOp = Select;
}
Value *NewRed;
Value *NextInChain;
if (IsOrdered) {
if (State.VF.isVector())
NewRed = createOrderedReduction(State.Builder, *RdxDesc, NewVecOp,
PrevInChain);
else
NewRed = State.Builder.CreateBinOp(
(Instruction::BinaryOps)RdxDesc->getOpcode(Kind), PrevInChain,
NewVecOp);
PrevInChain = NewRed;
} else {
PrevInChain = State.get(getChainOp(), Part);
NewRed = createTargetReduction(State.Builder, TTI, *RdxDesc, NewVecOp);
}
if (RecurrenceDescriptor::isMinMaxRecurrenceKind(Kind)) {
NextInChain =
createMinMaxOp(State.Builder, RdxDesc->getRecurrenceKind(),
NewRed, PrevInChain);
} else if (IsOrdered)
NextInChain = NewRed;
else
NextInChain = State.Builder.CreateBinOp(
(Instruction::BinaryOps)RdxDesc->getOpcode(Kind), NewRed,
PrevInChain);
State.set(this, NextInChain, Part);
}
}
void VPReplicateRecipe::execute(VPTransformState &State) {
if (State.Instance) { // Generate a single instance.
assert(!State.VF.isScalable() && "Can't scalarize a scalable vector");
State.ILV->scalarizeInstruction(getUnderlyingInstr(), this, *State.Instance,
IsPredicated, State);
// Insert scalar instance packing it into a vector.
if (AlsoPack && State.VF.isVector()) {
// If we're constructing lane 0, initialize to start from poison.
if (State.Instance->Lane.isFirstLane()) {
assert(!State.VF.isScalable() && "VF is assumed to be non scalable.");
Value *Poison = PoisonValue::get(
VectorType::get(getUnderlyingValue()->getType(), State.VF));
State.set(this, Poison, State.Instance->Part);
}
State.ILV->packScalarIntoVectorValue(this, *State.Instance, State);
}
return;
}
if (IsUniform) {
// Uniform within VL means we need to generate lane 0 only for each
// unrolled copy.
for (unsigned Part = 0; Part < State.UF; ++Part)
State.ILV->scalarizeInstruction(getUnderlyingInstr(), this,
VPIteration(Part, 0), IsPredicated,
State);
return;
}
// Generate scalar instances for all VF lanes of all UF parts.
assert(!State.VF.isScalable() && "Can't scalarize a scalable vector");
const unsigned EndLane = State.VF.getKnownMinValue();
for (unsigned Part = 0; Part < State.UF; ++Part)
for (unsigned Lane = 0; Lane < EndLane; ++Lane)
State.ILV->scalarizeInstruction(getUnderlyingInstr(), this,
VPIteration(Part, Lane), IsPredicated,
State);
}
void VPWidenMemoryInstructionRecipe::execute(VPTransformState &State) {
VPValue *StoredValue = isStore() ? getStoredValue() : nullptr;
// Attempt to issue a wide load.
LoadInst *LI = dyn_cast<LoadInst>(&Ingredient);
StoreInst *SI = dyn_cast<StoreInst>(&Ingredient);
assert((LI || SI) && "Invalid Load/Store instruction");
assert((!SI || StoredValue) && "No stored value provided for widened store");
assert((!LI || !StoredValue) && "Stored value provided for widened load");
Type *ScalarDataTy = getLoadStoreType(&Ingredient);
auto *DataTy = VectorType::get(ScalarDataTy, State.VF);
const Align Alignment = getLoadStoreAlignment(&Ingredient);
bool CreateGatherScatter = !Consecutive;
auto &Builder = State.Builder;
InnerLoopVectorizer::VectorParts BlockInMaskParts(State.UF);
bool isMaskRequired = getMask();
if (isMaskRequired)
for (unsigned Part = 0; Part < State.UF; ++Part)
BlockInMaskParts[Part] = State.get(getMask(), Part);
const auto CreateVecPtr = [&](unsigned Part, Value *Ptr) -> Value * {
// Calculate the pointer for the specific unroll-part.
GetElementPtrInst *PartPtr = nullptr;
bool InBounds = false;
if (auto *gep = dyn_cast<GetElementPtrInst>(Ptr->stripPointerCasts()))
InBounds = gep->isInBounds();
if (Reverse) {
// If the address is consecutive but reversed, then the
// wide store needs to start at the last vector element.
// RunTimeVF = VScale * VF.getKnownMinValue()
// For fixed-width VScale is 1, then RunTimeVF = VF.getKnownMinValue()
Value *RunTimeVF = getRuntimeVF(Builder, Builder.getInt32Ty(), State.VF);
// NumElt = -Part * RunTimeVF
Value *NumElt = Builder.CreateMul(Builder.getInt32(-Part), RunTimeVF);
// LastLane = 1 - RunTimeVF
Value *LastLane = Builder.CreateSub(Builder.getInt32(1), RunTimeVF);
PartPtr =
cast<GetElementPtrInst>(Builder.CreateGEP(ScalarDataTy, Ptr, NumElt));
PartPtr->setIsInBounds(InBounds);
PartPtr = cast<GetElementPtrInst>(
Builder.CreateGEP(ScalarDataTy, PartPtr, LastLane));
PartPtr->setIsInBounds(InBounds);
if (isMaskRequired) // Reverse of a null all-one mask is a null mask.
BlockInMaskParts[Part] =
Builder.CreateVectorReverse(BlockInMaskParts[Part], "reverse");
} else {
Value *Increment =
createStepForVF(Builder, Builder.getInt32Ty(), State.VF, Part);
PartPtr = cast<GetElementPtrInst>(
Builder.CreateGEP(ScalarDataTy, Ptr, Increment));
PartPtr->setIsInBounds(InBounds);
}
unsigned AddressSpace = Ptr->getType()->getPointerAddressSpace();
return Builder.CreateBitCast(PartPtr, DataTy->getPointerTo(AddressSpace));
};
// Handle Stores:
if (SI) {
State.setDebugLocFromInst(SI);
for (unsigned Part = 0; Part < State.UF; ++Part) {
Instruction *NewSI = nullptr;
Value *StoredVal = State.get(StoredValue, Part);
if (CreateGatherScatter) {
Value *MaskPart = isMaskRequired ? BlockInMaskParts[Part] : nullptr;
Value *VectorGep = State.get(getAddr(), Part);
NewSI = Builder.CreateMaskedScatter(StoredVal, VectorGep, Alignment,
MaskPart);
} else {
if (Reverse) {
// If we store to reverse consecutive memory locations, then we need
// to reverse the order of elements in the stored value.
StoredVal = Builder.CreateVectorReverse(StoredVal, "reverse");
// We don't want to update the value in the map as it might be used in
// another expression. So don't call resetVectorValue(StoredVal).
}
auto *VecPtr =
CreateVecPtr(Part, State.get(getAddr(), VPIteration(0, 0)));
if (isMaskRequired)
NewSI = Builder.CreateMaskedStore(StoredVal, VecPtr, Alignment,
BlockInMaskParts[Part]);
else
NewSI = Builder.CreateAlignedStore(StoredVal, VecPtr, Alignment);
}
State.addMetadata(NewSI, SI);
}
return;
}
// Handle loads.
assert(LI && "Must have a load instruction");
State.setDebugLocFromInst(LI);
for (unsigned Part = 0; Part < State.UF; ++Part) {
Value *NewLI;
if (CreateGatherScatter) {
Value *MaskPart = isMaskRequired ? BlockInMaskParts[Part] : nullptr;
Value *VectorGep = State.get(getAddr(), Part);
NewLI = Builder.CreateMaskedGather(DataTy, VectorGep, Alignment, MaskPart,
nullptr, "wide.masked.gather");
State.addMetadata(NewLI, LI);
} else {
auto *VecPtr =
CreateVecPtr(Part, State.get(getAddr(), VPIteration(0, 0)));
if (isMaskRequired)
NewLI = Builder.CreateMaskedLoad(
DataTy, VecPtr, Alignment, BlockInMaskParts[Part],
PoisonValue::get(DataTy), "wide.masked.load");
else
NewLI =
Builder.CreateAlignedLoad(DataTy, VecPtr, Alignment, "wide.load");
// Add metadata to the load, but setVectorValue to the reverse shuffle.
State.addMetadata(NewLI, LI);
if (Reverse)
NewLI = Builder.CreateVectorReverse(NewLI, "reverse");
}
State.set(getVPSingleValue(), NewLI, Part);
}
}
// Determine how to lower the scalar epilogue, which depends on 1) optimising
// for minimum code-size, 2) predicate compiler options, 3) loop hints forcing
// predication, and 4) a TTI hook that analyses whether the loop is suitable
// for predication.
static ScalarEpilogueLowering getScalarEpilogueLowering(
Function *F, Loop *L, LoopVectorizeHints &Hints, ProfileSummaryInfo *PSI,
BlockFrequencyInfo *BFI, TargetTransformInfo *TTI, TargetLibraryInfo *TLI,
AssumptionCache *AC, LoopInfo *LI, ScalarEvolution *SE, DominatorTree *DT,
LoopVectorizationLegality &LVL) {
// 1) OptSize takes precedence over all other options, i.e. if this is set,
// don't look at hints or options, and don't request a scalar epilogue.
// (For PGSO, as shouldOptimizeForSize isn't currently accessible from
// LoopAccessInfo (due to code dependency and not being able to reliably get
// PSI/BFI from a loop analysis under NPM), we cannot suppress the collection
// of strides in LoopAccessInfo::analyzeLoop() and vectorize without
// versioning when the vectorization is forced, unlike hasOptSize. So revert
// back to the old way and vectorize with versioning when forced. See D81345.)
if (F->hasOptSize() || (llvm::shouldOptimizeForSize(L->getHeader(), PSI, BFI,
PGSOQueryType::IRPass) &&
Hints.getForce() != LoopVectorizeHints::FK_Enabled))
return CM_ScalarEpilogueNotAllowedOptSize;
// 2) If set, obey the directives
if (PreferPredicateOverEpilogue.getNumOccurrences()) {
switch (PreferPredicateOverEpilogue) {
case PreferPredicateTy::ScalarEpilogue:
return CM_ScalarEpilogueAllowed;
case PreferPredicateTy::PredicateElseScalarEpilogue:
return CM_ScalarEpilogueNotNeededUsePredicate;
case PreferPredicateTy::PredicateOrDontVectorize:
return CM_ScalarEpilogueNotAllowedUsePredicate;
};
}
// 3) If set, obey the hints
switch (Hints.getPredicate()) {
case LoopVectorizeHints::FK_Enabled:
return CM_ScalarEpilogueNotNeededUsePredicate;
case LoopVectorizeHints::FK_Disabled:
return CM_ScalarEpilogueAllowed;
};
// 4) if the TTI hook indicates this is profitable, request predication.
if (TTI->preferPredicateOverEpilogue(L, LI, *SE, *AC, TLI, DT, &LVL))
return CM_ScalarEpilogueNotNeededUsePredicate;
return CM_ScalarEpilogueAllowed;
}
Value *VPTransformState::get(VPValue *Def, unsigned Part) {
// If Values have been set for this Def return the one relevant for \p Part.
if (hasVectorValue(Def, Part))
return Data.PerPartOutput[Def][Part];
if (!hasScalarValue(Def, {Part, 0})) {
Value *IRV = Def->getLiveInIRValue();
Value *B = ILV->getBroadcastInstrs(IRV);
set(Def, B, Part);
return B;
}
Value *ScalarValue = get(Def, {Part, 0});
// If we aren't vectorizing, we can just copy the scalar map values over
// to the vector map.
if (VF.isScalar()) {
set(Def, ScalarValue, Part);
return ScalarValue;
}
auto *RepR = dyn_cast<VPReplicateRecipe>(Def);
bool IsUniform = RepR && RepR->isUniform();
unsigned LastLane = IsUniform ? 0 : VF.getKnownMinValue() - 1;
// Check if there is a scalar value for the selected lane.
if (!hasScalarValue(Def, {Part, LastLane})) {
// At the moment, VPWidenIntOrFpInductionRecipes can also be uniform.
assert((isa<VPWidenIntOrFpInductionRecipe>(Def->getDef()) ||
isa<VPScalarIVStepsRecipe>(Def->getDef())) &&
"unexpected recipe found to be invariant");
IsUniform = true;
LastLane = 0;
}
auto *LastInst = cast<Instruction>(get(Def, {Part, LastLane}));
// Set the insert point after the last scalarized instruction or after the
// last PHI, if LastInst is a PHI. This ensures the insertelement sequence
// will directly follow the scalar definitions.
auto OldIP = Builder.saveIP();
auto NewIP =
isa<PHINode>(LastInst)
? BasicBlock::iterator(LastInst->getParent()->getFirstNonPHI())
: std::next(BasicBlock::iterator(LastInst));
Builder.SetInsertPoint(&*NewIP);
// However, if we are vectorizing, we need to construct the vector values.
// If the value is known to be uniform after vectorization, we can just
// broadcast the scalar value corresponding to lane zero for each unroll
// iteration. Otherwise, we construct the vector values using
// insertelement instructions. Since the resulting vectors are stored in
// State, we will only generate the insertelements once.
Value *VectorValue = nullptr;
if (IsUniform) {
VectorValue = ILV->getBroadcastInstrs(ScalarValue);
set(Def, VectorValue, Part);
} else {
// Initialize packing with insertelements to start from undef.
assert(!VF.isScalable() && "VF is assumed to be non scalable.");
Value *Undef = PoisonValue::get(VectorType::get(LastInst->getType(), VF));
set(Def, Undef, Part);
for (unsigned Lane = 0; Lane < VF.getKnownMinValue(); ++Lane)
ILV->packScalarIntoVectorValue(Def, {Part, Lane}, *this);
VectorValue = get(Def, Part);
}
Builder.restoreIP(OldIP);
return VectorValue;
}
// Process the loop in the VPlan-native vectorization path. This path builds
// VPlan upfront in the vectorization pipeline, which allows to apply
// VPlan-to-VPlan transformations from the very beginning without modifying the
// input LLVM IR.
static bool processLoopInVPlanNativePath(
Loop *L, PredicatedScalarEvolution &PSE, LoopInfo *LI, DominatorTree *DT,
LoopVectorizationLegality *LVL, TargetTransformInfo *TTI,
TargetLibraryInfo *TLI, DemandedBits *DB, AssumptionCache *AC,
OptimizationRemarkEmitter *ORE, BlockFrequencyInfo *BFI,
ProfileSummaryInfo *PSI, LoopVectorizeHints &Hints,
LoopVectorizationRequirements &Requirements) {
if (isa<SCEVCouldNotCompute>(PSE.getBackedgeTakenCount())) {
LLVM_DEBUG(dbgs() << "LV: cannot compute the outer-loop trip count\n");
return false;
}
assert(EnableVPlanNativePath && "VPlan-native path is disabled.");
Function *F = L->getHeader()->getParent();
InterleavedAccessInfo IAI(PSE, L, DT, LI, LVL->getLAI());
ScalarEpilogueLowering SEL = getScalarEpilogueLowering(
F, L, Hints, PSI, BFI, TTI, TLI, AC, LI, PSE.getSE(), DT, *LVL);
LoopVectorizationCostModel CM(SEL, L, PSE, LI, LVL, *TTI, TLI, DB, AC, ORE, F,
&Hints, IAI);
// Use the planner for outer loop vectorization.
// TODO: CM is not used at this point inside the planner. Turn CM into an
// optional argument if we don't need it in the future.
LoopVectorizationPlanner LVP(L, LI, TLI, TTI, LVL, CM, IAI, PSE, Hints, ORE);
// Get user vectorization factor.
ElementCount UserVF = Hints.getWidth();
CM.collectElementTypesForWidening();
// Plan how to best vectorize, return the best VF and its cost.
const VectorizationFactor VF = LVP.planInVPlanNativePath(UserVF);
// If we are stress testing VPlan builds, do not attempt to generate vector
// code. Masked vector code generation support will follow soon.
// Also, do not attempt to vectorize if no vector code will be produced.
if (VPlanBuildStressTest || VectorizationFactor::Disabled() == VF)
return false;
VPlan &BestPlan = LVP.getBestPlanFor(VF.Width);
{
GeneratedRTChecks Checks(*PSE.getSE(), DT, LI, TTI,
F->getParent()->getDataLayout());
InnerLoopVectorizer LB(L, PSE, LI, DT, TLI, TTI, AC, ORE, VF.Width,
VF.Width, 1, LVL, &CM, BFI, PSI, Checks);
LLVM_DEBUG(dbgs() << "Vectorizing outer loop in \""
<< L->getHeader()->getParent()->getName() << "\"\n");
LVP.executePlan(VF.Width, 1, BestPlan, LB, DT, false);
}
// Mark the loop as already vectorized to avoid vectorizing again.
Hints.setAlreadyVectorized();
assert(!verifyFunction(*L->getHeader()->getParent(), &dbgs()));
return true;
}
// Emit a remark if there are stores to floats that required a floating point
// extension. If the vectorized loop was generated with floating point there
// will be a performance penalty from the conversion overhead and the change in
// the vector width.
static void checkMixedPrecision(Loop *L, OptimizationRemarkEmitter *ORE) {
SmallVector<Instruction *, 4> Worklist;
for (BasicBlock *BB : L->getBlocks()) {
for (Instruction &Inst : *BB) {
if (auto *S = dyn_cast<StoreInst>(&Inst)) {
if (S->getValueOperand()->getType()->isFloatTy())
Worklist.push_back(S);
}
}
}
// Traverse the floating point stores upwards searching, for floating point
// conversions.
SmallPtrSet<const Instruction *, 4> Visited;
SmallPtrSet<const Instruction *, 4> EmittedRemark;
while (!Worklist.empty()) {
auto *I = Worklist.pop_back_val();
if (!L->contains(I))
continue;
if (!Visited.insert(I).second)
continue;
// Emit a remark if the floating point store required a floating
// point conversion.
// TODO: More work could be done to identify the root cause such as a
// constant or a function return type and point the user to it.
if (isa<FPExtInst>(I) && EmittedRemark.insert(I).second)
ORE->emit([&]() {
return OptimizationRemarkAnalysis(LV_NAME, "VectorMixedPrecision",
I->getDebugLoc(), L->getHeader())
<< "floating point conversion changes vector width. "
<< "Mixed floating point precision requires an up/down "
<< "cast that will negatively impact performance.";
});
for (Use &Op : I->operands())
if (auto *OpI = dyn_cast<Instruction>(Op))
Worklist.push_back(OpI);
}
}
static bool areRuntimeChecksProfitable(GeneratedRTChecks &Checks,
VectorizationFactor &VF,
Optional<unsigned> VScale, Loop *L,
ScalarEvolution &SE) {
InstructionCost CheckCost = Checks.getCost();
if (!CheckCost.isValid())
return false;
// When interleaving only scalar and vector cost will be equal, which in turn
// would lead to a divide by 0. Fall back to hard threshold.
if (VF.Width.isScalar()) {
if (CheckCost > VectorizeMemoryCheckThreshold) {
LLVM_DEBUG(
dbgs()
<< "LV: Interleaving only is not profitable due to runtime checks\n");
return false;
}
return true;
}
// The scalar cost should only be 0 when vectorizing with a user specified VF/IC. In those cases, runtime checks should always be generated.
double ScalarC = *VF.ScalarCost.getValue();
if (ScalarC == 0)
return true;
// First, compute the minimum iteration count required so that the vector
// loop outperforms the scalar loop.
// The total cost of the scalar loop is
// ScalarC * TC
// where
// * TC is the actual trip count of the loop.
// * ScalarC is the cost of a single scalar iteration.
//
// The total cost of the vector loop is
// RtC + VecC * (TC / VF) + EpiC
// where
// * RtC is the cost of the generated runtime checks
// * VecC is the cost of a single vector iteration.
// * TC is the actual trip count of the loop
// * VF is the vectorization factor
// * EpiCost is the cost of the generated epilogue, including the cost
// of the remaining scalar operations.
//
// Vectorization is profitable once the total vector cost is less than the
// total scalar cost:
// RtC + VecC * (TC / VF) + EpiC < ScalarC * TC
//
// Now we can compute the minimum required trip count TC as
// (RtC + EpiC) / (ScalarC - (VecC / VF)) < TC
//
// For now we assume the epilogue cost EpiC = 0 for simplicity. Note that
// the computations are performed on doubles, not integers and the result
// is rounded up, hence we get an upper estimate of the TC.
unsigned IntVF = VF.Width.getKnownMinValue();
if (VF.Width.isScalable()) {
unsigned AssumedMinimumVscale = 1;
if (VScale)
AssumedMinimumVscale = *VScale;
IntVF *= AssumedMinimumVscale;
}
double VecCOverVF = double(*VF.Cost.getValue()) / IntVF;
double RtC = *CheckCost.getValue();
double MinTC1 = RtC / (ScalarC - VecCOverVF);
// Second, compute a minimum iteration count so that the cost of the
// runtime checks is only a fraction of the total scalar loop cost. This
// adds a loop-dependent bound on the overhead incurred if the runtime
// checks fail. In case the runtime checks fail, the cost is RtC + ScalarC
// * TC. To bound the runtime check to be a fraction 1/X of the scalar
// cost, compute
// RtC < ScalarC * TC * (1 / X) ==> RtC * X / ScalarC < TC
double MinTC2 = RtC * 10 / ScalarC;
// Now pick the larger minimum. If it is not a multiple of VF, choose the
// next closest multiple of VF. This should partly compensate for ignoring
// the epilogue cost.
uint64_t MinTC = std::ceil(std::max(MinTC1, MinTC2));
VF.MinProfitableTripCount = ElementCount::getFixed(alignTo(MinTC, IntVF));
LLVM_DEBUG(
dbgs() << "LV: Minimum required TC for runtime checks to be profitable:"
<< VF.MinProfitableTripCount << "\n");
// Skip vectorization if the expected trip count is less than the minimum
// required trip count.
if (auto ExpectedTC = getSmallBestKnownTC(SE, L)) {
if (ElementCount::isKnownLT(ElementCount::getFixed(*ExpectedTC),
VF.MinProfitableTripCount)) {
LLVM_DEBUG(dbgs() << "LV: Vectorization is not beneficial: expected "
"trip count < minimum profitable VF ("
<< *ExpectedTC << " < " << VF.MinProfitableTripCount
<< ")\n");
return false;
}
}
return true;
}
LoopVectorizePass::LoopVectorizePass(LoopVectorizeOptions Opts)
: InterleaveOnlyWhenForced(Opts.InterleaveOnlyWhenForced ||
!EnableLoopInterleaving),
VectorizeOnlyWhenForced(Opts.VectorizeOnlyWhenForced ||
!EnableLoopVectorization) {}
bool LoopVectorizePass::processLoop(Loop *L) {
assert((EnableVPlanNativePath || L->isInnermost()) &&
"VPlan-native path is not enabled. Only process inner loops.");
#ifndef NDEBUG
const std::string DebugLocStr = getDebugLocString(L);
#endif /* NDEBUG */
LLVM_DEBUG(dbgs() << "\nLV: Checking a loop in '"
<< L->getHeader()->getParent()->getName() << "' from "
<< DebugLocStr << "\n");
LoopVectorizeHints Hints(L, InterleaveOnlyWhenForced, *ORE, TTI);
LLVM_DEBUG(
dbgs() << "LV: Loop hints:"
<< " force="
<< (Hints.getForce() == LoopVectorizeHints::FK_Disabled
? "disabled"
: (Hints.getForce() == LoopVectorizeHints::FK_Enabled
? "enabled"
: "?"))
<< " width=" << Hints.getWidth()
<< " interleave=" << Hints.getInterleave() << "\n");
// Function containing loop
Function *F = L->getHeader()->getParent();
// Looking at the diagnostic output is the only way to determine if a loop
// was vectorized (other than looking at the IR or machine code), so it
// is important to generate an optimization remark for each loop. Most of
// these messages are generated as OptimizationRemarkAnalysis. Remarks
// generated as OptimizationRemark and OptimizationRemarkMissed are
// less verbose reporting vectorized loops and unvectorized loops that may
// benefit from vectorization, respectively.
if (!Hints.allowVectorization(F, L, VectorizeOnlyWhenForced)) {
LLVM_DEBUG(dbgs() << "LV: Loop hints prevent vectorization.\n");
return false;
}
PredicatedScalarEvolution PSE(*SE, *L);
// Check if it is legal to vectorize the loop.
LoopVectorizationRequirements Requirements;
LoopVectorizationLegality LVL(L, PSE, DT, TTI, TLI, AA, F, GetLAA, LI, ORE,
&Requirements, &Hints, DB, AC, BFI, PSI);
if (!LVL.canVectorize(EnableVPlanNativePath)) {
LLVM_DEBUG(dbgs() << "LV: Not vectorizing: Cannot prove legality.\n");
Hints.emitRemarkWithHints();
return false;
}
// Check the function attributes and profiles to find out if this function
// should be optimized for size.
ScalarEpilogueLowering SEL = getScalarEpilogueLowering(
F, L, Hints, PSI, BFI, TTI, TLI, AC, LI, PSE.getSE(), DT, LVL);
// Entrance to the VPlan-native vectorization path. Outer loops are processed
// here. They may require CFG and instruction level transformations before
// even evaluating whether vectorization is profitable. Since we cannot modify
// the incoming IR, we need to build VPlan upfront in the vectorization
// pipeline.
if (!L->isInnermost())
return processLoopInVPlanNativePath(L, PSE, LI, DT, &LVL, TTI, TLI, DB, AC,
ORE, BFI, PSI, Hints, Requirements);
assert(L->isInnermost() && "Inner loop expected.");
// Check the loop for a trip count threshold: vectorize loops with a tiny trip
// count by optimizing for size, to minimize overheads.
auto ExpectedTC = getSmallBestKnownTC(*SE, L);
if (ExpectedTC && *ExpectedTC < TinyTripCountVectorThreshold) {
LLVM_DEBUG(dbgs() << "LV: Found a loop with a very small trip count. "
<< "This loop is worth vectorizing only if no scalar "
<< "iteration overheads are incurred.");
if (Hints.getForce() == LoopVectorizeHints::FK_Enabled)
LLVM_DEBUG(dbgs() << " But vectorizing was explicitly forced.\n");
else {
if (*ExpectedTC > TTI->getMinTripCountTailFoldingThreshold()) {
LLVM_DEBUG(dbgs() << "\n");
SEL = CM_ScalarEpilogueNotAllowedLowTripLoop;
} else {
LLVM_DEBUG(dbgs() << " But the target considers the trip count too "
"small to consider vectorizing.\n");
reportVectorizationFailure(
"The trip count is below the minial threshold value.",
"loop trip count is too low, avoiding vectorization",
"LowTripCount", ORE, L);
Hints.emitRemarkWithHints();
return false;
}
}
}
// Check the function attributes to see if implicit floats are allowed.
// FIXME: This check doesn't seem possibly correct -- what if the loop is
// an integer loop and the vector instructions selected are purely integer
// vector instructions?
if (F->hasFnAttribute(Attribute::NoImplicitFloat)) {
reportVectorizationFailure(
"Can't vectorize when the NoImplicitFloat attribute is used",
"loop not vectorized due to NoImplicitFloat attribute",
"NoImplicitFloat", ORE, L);
Hints.emitRemarkWithHints();
return false;
}
// Check if the target supports potentially unsafe FP vectorization.
// FIXME: Add a check for the type of safety issue (denormal, signaling)
// for the target we're vectorizing for, to make sure none of the
// additional fp-math flags can help.
if (Hints.isPotentiallyUnsafe() &&
TTI->isFPVectorizationPotentiallyUnsafe()) {
reportVectorizationFailure(
"Potentially unsafe FP op prevents vectorization",
"loop not vectorized due to unsafe FP support.",
"UnsafeFP", ORE, L);
Hints.emitRemarkWithHints();
return false;
}
bool AllowOrderedReductions;
// If the flag is set, use that instead and override the TTI behaviour.
if (ForceOrderedReductions.getNumOccurrences() > 0)
AllowOrderedReductions = ForceOrderedReductions;
else
AllowOrderedReductions = TTI->enableOrderedReductions();
if (!LVL.canVectorizeFPMath(AllowOrderedReductions)) {
ORE->emit([&]() {
auto *ExactFPMathInst = Requirements.getExactFPInst();
return OptimizationRemarkAnalysisFPCommute(DEBUG_TYPE, "CantReorderFPOps",
ExactFPMathInst->getDebugLoc(),
ExactFPMathInst->getParent())
<< "loop not vectorized: cannot prove it is safe to reorder "
"floating-point operations";
});
LLVM_DEBUG(dbgs() << "LV: loop not vectorized: cannot prove it is safe to "
"reorder floating-point operations\n");
Hints.emitRemarkWithHints();
return false;
}
bool UseInterleaved = TTI->enableInterleavedAccessVectorization();
InterleavedAccessInfo IAI(PSE, L, DT, LI, LVL.getLAI());
// If an override option has been passed in for interleaved accesses, use it.
if (EnableInterleavedMemAccesses.getNumOccurrences() > 0)
UseInterleaved = EnableInterleavedMemAccesses;
// Analyze interleaved memory accesses.
if (UseInterleaved) {
IAI.analyzeInterleaving(useMaskedInterleavedAccesses(*TTI));
}
// Use the cost model.
LoopVectorizationCostModel CM(SEL, L, PSE, LI, &LVL, *TTI, TLI, DB, AC, ORE,
F, &Hints, IAI);
CM.collectValuesToIgnore();
CM.collectElementTypesForWidening();
// Use the planner for vectorization.
LoopVectorizationPlanner LVP(L, LI, TLI, TTI, &LVL, CM, IAI, PSE, Hints, ORE);
// Get user vectorization factor and interleave count.
ElementCount UserVF = Hints.getWidth();
unsigned UserIC = Hints.getInterleave();
// Plan how to best vectorize, return the best VF and its cost.
Optional<VectorizationFactor> MaybeVF = LVP.plan(UserVF, UserIC);
VectorizationFactor VF = VectorizationFactor::Disabled();
unsigned IC = 1;
GeneratedRTChecks Checks(*PSE.getSE(), DT, LI, TTI,
F->getParent()->getDataLayout());
if (MaybeVF) {
VF = *MaybeVF;
// Select the interleave count.
IC = CM.selectInterleaveCount(VF.Width, *VF.Cost.getValue());
unsigned SelectedIC = std::max(IC, UserIC);
// Optimistically generate runtime checks if they are needed. Drop them if
// they turn out to not be profitable.
if (VF.Width.isVector() || SelectedIC > 1)
Checks.Create(L, *LVL.getLAI(), PSE.getPredicate(), VF.Width, SelectedIC);
// Check if it is profitable to vectorize with runtime checks.
bool ForceVectorization =
Hints.getForce() == LoopVectorizeHints::FK_Enabled;
if (!ForceVectorization &&
!areRuntimeChecksProfitable(Checks, VF, CM.getVScaleForTuning(), L,
*PSE.getSE())) {
ORE->emit([&]() {
return OptimizationRemarkAnalysisAliasing(
DEBUG_TYPE, "CantReorderMemOps", L->getStartLoc(),
L->getHeader())
<< "loop not vectorized: cannot prove it is safe to reorder "
"memory operations";
});
LLVM_DEBUG(dbgs() << "LV: Too many memory checks needed.\n");
Hints.emitRemarkWithHints();
return false;
}
}
// Identify the diagnostic messages that should be produced.
std::pair<StringRef, std::string> VecDiagMsg, IntDiagMsg;
bool VectorizeLoop = true, InterleaveLoop = true;
if (VF.Width.isScalar()) {
LLVM_DEBUG(dbgs() << "LV: Vectorization is possible but not beneficial.\n");
VecDiagMsg = std::make_pair(
"VectorizationNotBeneficial",
"the cost-model indicates that vectorization is not beneficial");
VectorizeLoop = false;
}
if (!MaybeVF && UserIC > 1) {
// Tell the user interleaving was avoided up-front, despite being explicitly
// requested.
LLVM_DEBUG(dbgs() << "LV: Ignoring UserIC, because vectorization and "
"interleaving should be avoided up front\n");
IntDiagMsg = std::make_pair(
"InterleavingAvoided",
"Ignoring UserIC, because interleaving was avoided up front");
InterleaveLoop = false;
} else if (IC == 1 && UserIC <= 1) {
// Tell the user interleaving is not beneficial.
LLVM_DEBUG(dbgs() << "LV: Interleaving is not beneficial.\n");
IntDiagMsg = std::make_pair(
"InterleavingNotBeneficial",
"the cost-model indicates that interleaving is not beneficial");
InterleaveLoop = false;
if (UserIC == 1) {
IntDiagMsg.first = "InterleavingNotBeneficialAndDisabled";
IntDiagMsg.second +=
" and is explicitly disabled or interleave count is set to 1";
}
} else if (IC > 1 && UserIC == 1) {
// Tell the user interleaving is beneficial, but it explicitly disabled.
LLVM_DEBUG(
dbgs() << "LV: Interleaving is beneficial but is explicitly disabled.");
IntDiagMsg = std::make_pair(
"InterleavingBeneficialButDisabled",
"the cost-model indicates that interleaving is beneficial "
"but is explicitly disabled or interleave count is set to 1");
InterleaveLoop = false;
}
// Override IC if user provided an interleave count.
IC = UserIC > 0 ? UserIC : IC;
// Emit diagnostic messages, if any.
const char *VAPassName = Hints.vectorizeAnalysisPassName();
if (!VectorizeLoop && !InterleaveLoop) {
// Do not vectorize or interleaving the loop.
ORE->emit([&]() {
return OptimizationRemarkMissed(VAPassName, VecDiagMsg.first,
L->getStartLoc(), L->getHeader())
<< VecDiagMsg.second;
});
ORE->emit([&]() {
return OptimizationRemarkMissed(LV_NAME, IntDiagMsg.first,
L->getStartLoc(), L->getHeader())
<< IntDiagMsg.second;
});
return false;
} else if (!VectorizeLoop && InterleaveLoop) {
LLVM_DEBUG(dbgs() << "LV: Interleave Count is " << IC << '\n');
ORE->emit([&]() {
return OptimizationRemarkAnalysis(VAPassName, VecDiagMsg.first,
L->getStartLoc(), L->getHeader())
<< VecDiagMsg.second;
});
} else if (VectorizeLoop && !InterleaveLoop) {
LLVM_DEBUG(dbgs() << "LV: Found a vectorizable loop (" << VF.Width
<< ") in " << DebugLocStr << '\n');
ORE->emit([&]() {
return OptimizationRemarkAnalysis(LV_NAME, IntDiagMsg.first,
L->getStartLoc(), L->getHeader())
<< IntDiagMsg.second;
});
} else if (VectorizeLoop && InterleaveLoop) {
LLVM_DEBUG(dbgs() << "LV: Found a vectorizable loop (" << VF.Width
<< ") in " << DebugLocStr << '\n');
LLVM_DEBUG(dbgs() << "LV: Interleave Count is " << IC << '\n');
}
bool DisableRuntimeUnroll = false;
MDNode *OrigLoopID = L->getLoopID();
{
using namespace ore;
if (!VectorizeLoop) {
assert(IC > 1 && "interleave count should not be 1 or 0");
// If we decided that it is not legal to vectorize the loop, then
// interleave it.
InnerLoopUnroller Unroller(L, PSE, LI, DT, TLI, TTI, AC, ORE, IC, &LVL,
&CM, BFI, PSI, Checks);
VPlan &BestPlan = LVP.getBestPlanFor(VF.Width);
LVP.executePlan(VF.Width, IC, BestPlan, Unroller, DT, false);
ORE->emit([&]() {
return OptimizationRemark(LV_NAME, "Interleaved", L->getStartLoc(),
L->getHeader())
<< "interleaved loop (interleaved count: "
<< NV("InterleaveCount", IC) << ")";
});
} else {
// If we decided that it is *legal* to vectorize the loop, then do it.
// Consider vectorizing the epilogue too if it's profitable.
VectorizationFactor EpilogueVF =
CM.selectEpilogueVectorizationFactor(VF.Width, LVP);
if (EpilogueVF.Width.isVector()) {
// The first pass vectorizes the main loop and creates a scalar epilogue
// to be vectorized by executing the plan (potentially with a different
// factor) again shortly afterwards.
EpilogueLoopVectorizationInfo EPI(VF.Width, IC, EpilogueVF.Width, 1);
EpilogueVectorizerMainLoop MainILV(L, PSE, LI, DT, TLI, TTI, AC, ORE,
EPI, &LVL, &CM, BFI, PSI, Checks);
VPlan &BestMainPlan = LVP.getBestPlanFor(EPI.MainLoopVF);
LVP.executePlan(EPI.MainLoopVF, EPI.MainLoopUF, BestMainPlan, MainILV,
DT, true);
++LoopsVectorized;
// Second pass vectorizes the epilogue and adjusts the control flow
// edges from the first pass.
EPI.MainLoopVF = EPI.EpilogueVF;
EPI.MainLoopUF = EPI.EpilogueUF;
EpilogueVectorizerEpilogueLoop EpilogILV(L, PSE, LI, DT, TLI, TTI, AC,
ORE, EPI, &LVL, &CM, BFI, PSI,
Checks);
VPlan &BestEpiPlan = LVP.getBestPlanFor(EPI.EpilogueVF);
VPRegionBlock *VectorLoop = BestEpiPlan.getVectorLoopRegion();
VPBasicBlock *Header = VectorLoop->getEntryBasicBlock();
Header->setName("vec.epilog.vector.body");
// Ensure that the start values for any VPReductionPHIRecipes are
// updated before vectorising the epilogue loop.
for (VPRecipeBase &R : Header->phis()) {
if (auto *ReductionPhi = dyn_cast<VPReductionPHIRecipe>(&R)) {
if (auto *Resume = MainILV.getReductionResumeValue(
ReductionPhi->getRecurrenceDescriptor())) {
VPValue *StartVal = BestEpiPlan.getOrAddExternalDef(Resume);
ReductionPhi->setOperand(0, StartVal);
}
}
}
LVP.executePlan(EPI.EpilogueVF, EPI.EpilogueUF, BestEpiPlan, EpilogILV,
DT, true);
++LoopsEpilogueVectorized;
if (!MainILV.areSafetyChecksAdded())
DisableRuntimeUnroll = true;
} else {
InnerLoopVectorizer LB(L, PSE, LI, DT, TLI, TTI, AC, ORE, VF.Width,
VF.MinProfitableTripCount, IC, &LVL, &CM, BFI,
PSI, Checks);
VPlan &BestPlan = LVP.getBestPlanFor(VF.Width);
LVP.executePlan(VF.Width, IC, BestPlan, LB, DT, false);
++LoopsVectorized;
// Add metadata to disable runtime unrolling a scalar loop when there
// are no runtime checks about strides and memory. A scalar loop that is
// rarely used is not worth unrolling.
if (!LB.areSafetyChecksAdded())
DisableRuntimeUnroll = true;
}
// Report the vectorization decision.
ORE->emit([&]() {
return OptimizationRemark(LV_NAME, "Vectorized", L->getStartLoc(),
L->getHeader())
<< "vectorized loop (vectorization width: "
<< NV("VectorizationFactor", VF.Width)
<< ", interleaved count: " << NV("InterleaveCount", IC) << ")";
});
}
if (ORE->allowExtraAnalysis(LV_NAME))
checkMixedPrecision(L, ORE);
}
Optional<MDNode *> RemainderLoopID =
makeFollowupLoopID(OrigLoopID, {LLVMLoopVectorizeFollowupAll,
LLVMLoopVectorizeFollowupEpilogue});
if (RemainderLoopID) {
L->setLoopID(RemainderLoopID.value());
} else {
if (DisableRuntimeUnroll)
AddRuntimeUnrollDisableMetaData(L);
// Mark the loop as already vectorized to avoid vectorizing again.
Hints.setAlreadyVectorized();
}
assert(!verifyFunction(*L->getHeader()->getParent(), &dbgs()));
return true;
}
LoopVectorizeResult LoopVectorizePass::runImpl(
Function &F, ScalarEvolution &SE_, LoopInfo &LI_, TargetTransformInfo &TTI_,
DominatorTree &DT_, BlockFrequencyInfo &BFI_, TargetLibraryInfo *TLI_,
DemandedBits &DB_, AAResults &AA_, AssumptionCache &AC_,
std::function<const LoopAccessInfo &(Loop &)> &GetLAA_,
OptimizationRemarkEmitter &ORE_, ProfileSummaryInfo *PSI_) {
SE = &SE_;
LI = &LI_;
TTI = &TTI_;
DT = &DT_;
BFI = &BFI_;
TLI = TLI_;
AA = &AA_;
AC = &AC_;
GetLAA = &GetLAA_;
DB = &DB_;
ORE = &ORE_;
PSI = PSI_;
// Don't attempt if
// 1. the target claims to have no vector registers, and
// 2. interleaving won't help ILP.
//
// The second condition is necessary because, even if the target has no
// vector registers, loop vectorization may still enable scalar
// interleaving.
if (!TTI->getNumberOfRegisters(TTI->getRegisterClassForType(true)) &&
TTI->getMaxInterleaveFactor(1) < 2)
return LoopVectorizeResult(false, false);
bool Changed = false, CFGChanged = false;
// The vectorizer requires loops to be in simplified form.
// Since simplification may add new inner loops, it has to run before the
// legality and profitability checks. This means running the loop vectorizer
// will simplify all loops, regardless of whether anything end up being
// vectorized.
for (auto &L : *LI)
Changed |= CFGChanged |=
simplifyLoop(L, DT, LI, SE, AC, nullptr, false /* PreserveLCSSA */);
// Build up a worklist of inner-loops to vectorize. This is necessary as
// the act of vectorizing or partially unrolling a loop creates new loops
// and can invalidate iterators across the loops.
SmallVector<Loop *, 8> Worklist;
for (Loop *L : *LI)
collectSupportedLoops(*L, LI, ORE, Worklist);
LoopsAnalyzed += Worklist.size();
// Now walk the identified inner loops.
while (!Worklist.empty()) {
Loop *L = Worklist.pop_back_val();
// For the inner loops we actually process, form LCSSA to simplify the
// transform.
Changed |= formLCSSARecursively(*L, *DT, LI, SE);
Changed |= CFGChanged |= processLoop(L);
}
// Process each loop nest in the function.
return LoopVectorizeResult(Changed, CFGChanged);
}
PreservedAnalyses LoopVectorizePass::run(Function &F,
FunctionAnalysisManager &AM) {
auto &LI = AM.getResult<LoopAnalysis>(F);
// There are no loops in the function. Return before computing other expensive
// analyses.
if (LI.empty())
return PreservedAnalyses::all();
auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F);
auto &TTI = AM.getResult<TargetIRAnalysis>(F);
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &BFI = AM.getResult<BlockFrequencyAnalysis>(F);
auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
auto &AA = AM.getResult<AAManager>(F);
auto &AC = AM.getResult<AssumptionAnalysis>(F);
auto &DB = AM.getResult<DemandedBitsAnalysis>(F);
auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
auto &LAM = AM.getResult<LoopAnalysisManagerFunctionProxy>(F).getManager();
std::function<const LoopAccessInfo &(Loop &)> GetLAA =
[&](Loop &L) -> const LoopAccessInfo & {
LoopStandardAnalysisResults AR = {AA, AC, DT, LI, SE,
TLI, TTI, nullptr, nullptr, nullptr};
return LAM.getResult<LoopAccessAnalysis>(L, AR);
};
auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
ProfileSummaryInfo *PSI =
MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
LoopVectorizeResult Result =
runImpl(F, SE, LI, TTI, DT, BFI, &TLI, DB, AA, AC, GetLAA, ORE, PSI);
if (!Result.MadeAnyChange)
return PreservedAnalyses::all();
PreservedAnalyses PA;
// We currently do not preserve loopinfo/dominator analyses with outer loop
// vectorization. Until this is addressed, mark these analyses as preserved
// only for non-VPlan-native path.
// TODO: Preserve Loop and Dominator analyses for VPlan-native path.
if (!EnableVPlanNativePath) {
PA.preserve<LoopAnalysis>();
PA.preserve<DominatorTreeAnalysis>();
}
if (Result.MadeCFGChange) {
// Making CFG changes likely means a loop got vectorized. Indicate that
// extra simplification passes should be run.
// TODO: MadeCFGChanges is not a prefect proxy. Extra passes should only
// be run if runtime checks have been added.
AM.getResult<ShouldRunExtraVectorPasses>(F);
PA.preserve<ShouldRunExtraVectorPasses>();
} else {
PA.preserveSet<CFGAnalyses>();
}
return PA;
}
void LoopVectorizePass::printPipeline(
raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
static_cast<PassInfoMixin<LoopVectorizePass> *>(this)->printPipeline(
OS, MapClassName2PassName);
OS << "<";
OS << (InterleaveOnlyWhenForced ? "" : "no-") << "interleave-forced-only;";
OS << (VectorizeOnlyWhenForced ? "" : "no-") << "vectorize-forced-only;";
OS << ">";
}
diff --git a/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlan.h b/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlan.h
index f009a7ee6b4b..7a6bc48e2aee 100644
--- a/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -1,3068 +1,3072 @@
//===- VPlan.h - Represent A Vectorizer Plan --------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
/// \file
/// This file contains the declarations of the Vectorization Plan base classes:
/// 1. VPBasicBlock and VPRegionBlock that inherit from a common pure virtual
/// VPBlockBase, together implementing a Hierarchical CFG;
/// 2. Specializations of GraphTraits that allow VPBlockBase graphs to be
/// treated as proper graphs for generic algorithms;
/// 3. Pure virtual VPRecipeBase serving as the base class for recipes contained
/// within VPBasicBlocks;
/// 4. VPInstruction, a concrete Recipe and VPUser modeling a single planned
/// instruction;
/// 5. The VPlan class holding a candidate for vectorization;
/// 6. The VPlanPrinter class providing a way to print a plan in dot format;
/// These are documented in docs/VectorizationPlan.rst.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TRANSFORMS_VECTORIZE_VPLAN_H
#define LLVM_TRANSFORMS_VECTORIZE_VPLAN_H
#include "VPlanValue.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/FMF.h"
#include "llvm/Transforms/Utils/LoopVersioning.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <string>
namespace llvm {
class BasicBlock;
class DominatorTree;
class InductionDescriptor;
class InnerLoopVectorizer;
class IRBuilderBase;
class LoopInfo;
class raw_ostream;
class RecurrenceDescriptor;
class Value;
class VPBasicBlock;
class VPRegionBlock;
class VPlan;
class VPReplicateRecipe;
class VPlanSlp;
/// Returns a calculation for the total number of elements for a given \p VF.
/// For fixed width vectors this value is a constant, whereas for scalable
/// vectors it is an expression determined at runtime.
Value *getRuntimeVF(IRBuilderBase &B, Type *Ty, ElementCount VF);
/// Return a value for Step multiplied by VF.
Value *createStepForVF(IRBuilderBase &B, Type *Ty, ElementCount VF,
int64_t Step);
/// A range of powers-of-2 vectorization factors with fixed start and
/// adjustable end. The range includes start and excludes end, e.g.,:
/// [1, 9) = {1, 2, 4, 8}
struct VFRange {
// A power of 2.
const ElementCount Start;
// Need not be a power of 2. If End <= Start range is empty.
ElementCount End;
bool isEmpty() const {
return End.getKnownMinValue() <= Start.getKnownMinValue();
}
VFRange(const ElementCount &Start, const ElementCount &End)
: Start(Start), End(End) {
assert(Start.isScalable() == End.isScalable() &&
"Both Start and End should have the same scalable flag");
assert(isPowerOf2_32(Start.getKnownMinValue()) &&
"Expected Start to be a power of 2");
}
};
using VPlanPtr = std::unique_ptr<VPlan>;
/// In what follows, the term "input IR" refers to code that is fed into the
/// vectorizer whereas the term "output IR" refers to code that is generated by
/// the vectorizer.
/// VPLane provides a way to access lanes in both fixed width and scalable
/// vectors, where for the latter the lane index sometimes needs calculating
/// as a runtime expression.
class VPLane {
public:
/// Kind describes how to interpret Lane.
enum class Kind : uint8_t {
/// For First, Lane is the index into the first N elements of a
/// fixed-vector <N x <ElTy>> or a scalable vector <vscale x N x <ElTy>>.
First,
/// For ScalableLast, Lane is the offset from the start of the last
/// N-element subvector in a scalable vector <vscale x N x <ElTy>>. For
/// example, a Lane of 0 corresponds to lane `(vscale - 1) * N`, a Lane of
/// 1 corresponds to `((vscale - 1) * N) + 1`, etc.
ScalableLast
};
private:
/// in [0..VF)
unsigned Lane;
/// Indicates how the Lane should be interpreted, as described above.
Kind LaneKind;
public:
VPLane(unsigned Lane, Kind LaneKind) : Lane(Lane), LaneKind(LaneKind) {}
static VPLane getFirstLane() { return VPLane(0, VPLane::Kind::First); }
static VPLane getLastLaneForVF(const ElementCount &VF) {
unsigned LaneOffset = VF.getKnownMinValue() - 1;
Kind LaneKind;
if (VF.isScalable())
// In this case 'LaneOffset' refers to the offset from the start of the
// last subvector with VF.getKnownMinValue() elements.
LaneKind = VPLane::Kind::ScalableLast;
else
LaneKind = VPLane::Kind::First;
return VPLane(LaneOffset, LaneKind);
}
/// Returns a compile-time known value for the lane index and asserts if the
/// lane can only be calculated at runtime.
unsigned getKnownLane() const {
assert(LaneKind == Kind::First);
return Lane;
}
/// Returns an expression describing the lane index that can be used at
/// runtime.
Value *getAsRuntimeExpr(IRBuilderBase &Builder, const ElementCount &VF) const;
/// Returns the Kind of lane offset.
Kind getKind() const { return LaneKind; }
/// Returns true if this is the first lane of the whole vector.
bool isFirstLane() const { return Lane == 0 && LaneKind == Kind::First; }
/// Maps the lane to a cache index based on \p VF.
unsigned mapToCacheIndex(const ElementCount &VF) const {
switch (LaneKind) {
case VPLane::Kind::ScalableLast:
assert(VF.isScalable() && Lane < VF.getKnownMinValue());
return VF.getKnownMinValue() + Lane;
default:
assert(Lane < VF.getKnownMinValue());
return Lane;
}
}
/// Returns the maxmimum number of lanes that we are able to consider
/// caching for \p VF.
static unsigned getNumCachedLanes(const ElementCount &VF) {
return VF.getKnownMinValue() * (VF.isScalable() ? 2 : 1);
}
};
/// VPIteration represents a single point in the iteration space of the output
/// (vectorized and/or unrolled) IR loop.
struct VPIteration {
/// in [0..UF)
unsigned Part;
VPLane Lane;
VPIteration(unsigned Part, unsigned Lane,
VPLane::Kind Kind = VPLane::Kind::First)
: Part(Part), Lane(Lane, Kind) {}
VPIteration(unsigned Part, const VPLane &Lane) : Part(Part), Lane(Lane) {}
bool isFirstIteration() const { return Part == 0 && Lane.isFirstLane(); }
};
/// VPTransformState holds information passed down when "executing" a VPlan,
/// needed for generating the output IR.
struct VPTransformState {
VPTransformState(ElementCount VF, unsigned UF, LoopInfo *LI,
DominatorTree *DT, IRBuilderBase &Builder,
InnerLoopVectorizer *ILV, VPlan *Plan)
: VF(VF), UF(UF), LI(LI), DT(DT), Builder(Builder), ILV(ILV), Plan(Plan),
LVer(nullptr) {}
/// The chosen Vectorization and Unroll Factors of the loop being vectorized.
ElementCount VF;
unsigned UF;
/// Hold the indices to generate specific scalar instructions. Null indicates
/// that all instances are to be generated, using either scalar or vector
/// instructions.
Optional<VPIteration> Instance;
struct DataState {
/// A type for vectorized values in the new loop. Each value from the
/// original loop, when vectorized, is represented by UF vector values in
/// the new unrolled loop, where UF is the unroll factor.
typedef SmallVector<Value *, 2> PerPartValuesTy;
DenseMap<VPValue *, PerPartValuesTy> PerPartOutput;
using ScalarsPerPartValuesTy = SmallVector<SmallVector<Value *, 4>, 2>;
DenseMap<VPValue *, ScalarsPerPartValuesTy> PerPartScalars;
} Data;
/// Get the generated Value for a given VPValue and a given Part. Note that
/// as some Defs are still created by ILV and managed in its ValueMap, this
/// method will delegate the call to ILV in such cases in order to provide
/// callers a consistent API.
/// \see set.
Value *get(VPValue *Def, unsigned Part);
/// Get the generated Value for a given VPValue and given Part and Lane.
Value *get(VPValue *Def, const VPIteration &Instance);
bool hasVectorValue(VPValue *Def, unsigned Part) {
auto I = Data.PerPartOutput.find(Def);
return I != Data.PerPartOutput.end() && Part < I->second.size() &&
I->second[Part];
}
bool hasAnyVectorValue(VPValue *Def) const {
return Data.PerPartOutput.find(Def) != Data.PerPartOutput.end();
}
bool hasScalarValue(VPValue *Def, VPIteration Instance) {
auto I = Data.PerPartScalars.find(Def);
if (I == Data.PerPartScalars.end())
return false;
unsigned CacheIdx = Instance.Lane.mapToCacheIndex(VF);
return Instance.Part < I->second.size() &&
CacheIdx < I->second[Instance.Part].size() &&
I->second[Instance.Part][CacheIdx];
}
/// Set the generated Value for a given VPValue and a given Part.
void set(VPValue *Def, Value *V, unsigned Part) {
if (!Data.PerPartOutput.count(Def)) {
DataState::PerPartValuesTy Entry(UF);
Data.PerPartOutput[Def] = Entry;
}
Data.PerPartOutput[Def][Part] = V;
}
/// Reset an existing vector value for \p Def and a given \p Part.
void reset(VPValue *Def, Value *V, unsigned Part) {
auto Iter = Data.PerPartOutput.find(Def);
assert(Iter != Data.PerPartOutput.end() &&
"need to overwrite existing value");
Iter->second[Part] = V;
}
/// Set the generated scalar \p V for \p Def and the given \p Instance.
void set(VPValue *Def, Value *V, const VPIteration &Instance) {
auto Iter = Data.PerPartScalars.insert({Def, {}});
auto &PerPartVec = Iter.first->second;
while (PerPartVec.size() <= Instance.Part)
PerPartVec.emplace_back();
auto &Scalars = PerPartVec[Instance.Part];
unsigned CacheIdx = Instance.Lane.mapToCacheIndex(VF);
while (Scalars.size() <= CacheIdx)
Scalars.push_back(nullptr);
assert(!Scalars[CacheIdx] && "should overwrite existing value");
Scalars[CacheIdx] = V;
}
/// Reset an existing scalar value for \p Def and a given \p Instance.
void reset(VPValue *Def, Value *V, const VPIteration &Instance) {
auto Iter = Data.PerPartScalars.find(Def);
assert(Iter != Data.PerPartScalars.end() &&
"need to overwrite existing value");
assert(Instance.Part < Iter->second.size() &&
"need to overwrite existing value");
unsigned CacheIdx = Instance.Lane.mapToCacheIndex(VF);
assert(CacheIdx < Iter->second[Instance.Part].size() &&
"need to overwrite existing value");
Iter->second[Instance.Part][CacheIdx] = V;
}
/// Add additional metadata to \p To that was not present on \p Orig.
///
/// Currently this is used to add the noalias annotations based on the
/// inserted memchecks. Use this for instructions that are *cloned* into the
/// vector loop.
void addNewMetadata(Instruction *To, const Instruction *Orig);
/// Add metadata from one instruction to another.
///
/// This includes both the original MDs from \p From and additional ones (\see
/// addNewMetadata). Use this for *newly created* instructions in the vector
/// loop.
void addMetadata(Instruction *To, Instruction *From);
/// Similar to the previous function but it adds the metadata to a
/// vector of instructions.
void addMetadata(ArrayRef<Value *> To, Instruction *From);
/// Set the debug location in the builder using the debug location in \p V.
void setDebugLocFromInst(const Value *V);
/// Hold state information used when constructing the CFG of the output IR,
/// traversing the VPBasicBlocks and generating corresponding IR BasicBlocks.
struct CFGState {
/// The previous VPBasicBlock visited. Initially set to null.
VPBasicBlock *PrevVPBB = nullptr;
/// The previous IR BasicBlock created or used. Initially set to the new
/// header BasicBlock.
BasicBlock *PrevBB = nullptr;
/// The last IR BasicBlock in the output IR. Set to the exit block of the
/// vector loop.
BasicBlock *ExitBB = nullptr;
/// A mapping of each VPBasicBlock to the corresponding BasicBlock. In case
/// of replication, maps the BasicBlock of the last replica created.
SmallDenseMap<VPBasicBlock *, BasicBlock *> VPBB2IRBB;
CFGState() = default;
/// Returns the BasicBlock* mapped to the pre-header of the loop region
/// containing \p R.
BasicBlock *getPreheaderBBFor(VPRecipeBase *R);
} CFG;
/// Hold a pointer to LoopInfo to register new basic blocks in the loop.
LoopInfo *LI;
/// Hold a pointer to Dominator Tree to register new basic blocks in the loop.
DominatorTree *DT;
/// Hold a reference to the IRBuilder used to generate output IR code.
IRBuilderBase &Builder;
VPValue2ValueTy VPValue2Value;
/// Hold the canonical scalar IV of the vector loop (start=0, step=VF*UF).
Value *CanonicalIV = nullptr;
/// Hold a pointer to InnerLoopVectorizer to reuse its IR generation methods.
InnerLoopVectorizer *ILV;
/// Pointer to the VPlan code is generated for.
VPlan *Plan;
/// Holds recipes that may generate a poison value that is used after
/// vectorization, even when their operands are not poison.
SmallPtrSet<VPRecipeBase *, 16> MayGeneratePoisonRecipes;
/// The loop object for the current parent region, or nullptr.
Loop *CurrentVectorLoop = nullptr;
/// LoopVersioning. It's only set up (non-null) if memchecks were
/// used.
///
/// This is currently only used to add no-alias metadata based on the
/// memchecks. The actually versioning is performed manually.
std::unique_ptr<LoopVersioning> LVer;
};
/// VPBlockBase is the building block of the Hierarchical Control-Flow Graph.
/// A VPBlockBase can be either a VPBasicBlock or a VPRegionBlock.
class VPBlockBase {
friend class VPBlockUtils;
const unsigned char SubclassID; ///< Subclass identifier (for isa/dyn_cast).
/// An optional name for the block.
std::string Name;
/// The immediate VPRegionBlock which this VPBlockBase belongs to, or null if
/// it is a topmost VPBlockBase.
VPRegionBlock *Parent = nullptr;
/// List of predecessor blocks.
SmallVector<VPBlockBase *, 1> Predecessors;
/// List of successor blocks.
SmallVector<VPBlockBase *, 1> Successors;
/// VPlan containing the block. Can only be set on the entry block of the
/// plan.
VPlan *Plan = nullptr;
/// Add \p Successor as the last successor to this block.
void appendSuccessor(VPBlockBase *Successor) {
assert(Successor && "Cannot add nullptr successor!");
Successors.push_back(Successor);
}
/// Add \p Predecessor as the last predecessor to this block.
void appendPredecessor(VPBlockBase *Predecessor) {
assert(Predecessor && "Cannot add nullptr predecessor!");
Predecessors.push_back(Predecessor);
}
/// Remove \p Predecessor from the predecessors of this block.
void removePredecessor(VPBlockBase *Predecessor) {
auto Pos = find(Predecessors, Predecessor);
assert(Pos && "Predecessor does not exist");
Predecessors.erase(Pos);
}
/// Remove \p Successor from the successors of this block.
void removeSuccessor(VPBlockBase *Successor) {
auto Pos = find(Successors, Successor);
assert(Pos && "Successor does not exist");
Successors.erase(Pos);
}
protected:
VPBlockBase(const unsigned char SC, const std::string &N)
: SubclassID(SC), Name(N) {}
public:
/// An enumeration for keeping track of the concrete subclass of VPBlockBase
/// that are actually instantiated. Values of this enumeration are kept in the
/// SubclassID field of the VPBlockBase objects. They are used for concrete
/// type identification.
using VPBlockTy = enum { VPBasicBlockSC, VPRegionBlockSC };
using VPBlocksTy = SmallVectorImpl<VPBlockBase *>;
virtual ~VPBlockBase() = default;
const std::string &getName() const { return Name; }
void setName(const Twine &newName) { Name = newName.str(); }
/// \return an ID for the concrete type of this object.
/// This is used to implement the classof checks. This should not be used
/// for any other purpose, as the values may change as LLVM evolves.
unsigned getVPBlockID() const { return SubclassID; }
VPRegionBlock *getParent() { return Parent; }
const VPRegionBlock *getParent() const { return Parent; }
/// \return A pointer to the plan containing the current block.
VPlan *getPlan();
const VPlan *getPlan() const;
/// Sets the pointer of the plan containing the block. The block must be the
/// entry block into the VPlan.
void setPlan(VPlan *ParentPlan);
void setParent(VPRegionBlock *P) { Parent = P; }
/// \return the VPBasicBlock that is the entry of this VPBlockBase,
/// recursively, if the latter is a VPRegionBlock. Otherwise, if this
/// VPBlockBase is a VPBasicBlock, it is returned.
const VPBasicBlock *getEntryBasicBlock() const;
VPBasicBlock *getEntryBasicBlock();
/// \return the VPBasicBlock that is the exiting this VPBlockBase,
/// recursively, if the latter is a VPRegionBlock. Otherwise, if this
/// VPBlockBase is a VPBasicBlock, it is returned.
const VPBasicBlock *getExitingBasicBlock() const;
VPBasicBlock *getExitingBasicBlock();
const VPBlocksTy &getSuccessors() const { return Successors; }
VPBlocksTy &getSuccessors() { return Successors; }
iterator_range<VPBlockBase **> successors() { return Successors; }
const VPBlocksTy &getPredecessors() const { return Predecessors; }
VPBlocksTy &getPredecessors() { return Predecessors; }
/// \return the successor of this VPBlockBase if it has a single successor.
/// Otherwise return a null pointer.
VPBlockBase *getSingleSuccessor() const {
return (Successors.size() == 1 ? *Successors.begin() : nullptr);
}
/// \return the predecessor of this VPBlockBase if it has a single
/// predecessor. Otherwise return a null pointer.
VPBlockBase *getSinglePredecessor() const {
return (Predecessors.size() == 1 ? *Predecessors.begin() : nullptr);
}
size_t getNumSuccessors() const { return Successors.size(); }
size_t getNumPredecessors() const { return Predecessors.size(); }
/// An Enclosing Block of a block B is any block containing B, including B
/// itself. \return the closest enclosing block starting from "this", which
/// has successors. \return the root enclosing block if all enclosing blocks
/// have no successors.
VPBlockBase *getEnclosingBlockWithSuccessors();
/// \return the closest enclosing block starting from "this", which has
/// predecessors. \return the root enclosing block if all enclosing blocks
/// have no predecessors.
VPBlockBase *getEnclosingBlockWithPredecessors();
/// \return the successors either attached directly to this VPBlockBase or, if
/// this VPBlockBase is the exit block of a VPRegionBlock and has no
/// successors of its own, search recursively for the first enclosing
/// VPRegionBlock that has successors and return them. If no such
/// VPRegionBlock exists, return the (empty) successors of the topmost
/// VPBlockBase reached.
const VPBlocksTy &getHierarchicalSuccessors() {
return getEnclosingBlockWithSuccessors()->getSuccessors();
}
/// \return the hierarchical successor of this VPBlockBase if it has a single
/// hierarchical successor. Otherwise return a null pointer.
VPBlockBase *getSingleHierarchicalSuccessor() {
return getEnclosingBlockWithSuccessors()->getSingleSuccessor();
}
/// \return the predecessors either attached directly to this VPBlockBase or,
/// if this VPBlockBase is the entry block of a VPRegionBlock and has no
/// predecessors of its own, search recursively for the first enclosing
/// VPRegionBlock that has predecessors and return them. If no such
/// VPRegionBlock exists, return the (empty) predecessors of the topmost
/// VPBlockBase reached.
const VPBlocksTy &getHierarchicalPredecessors() {
return getEnclosingBlockWithPredecessors()->getPredecessors();
}
/// \return the hierarchical predecessor of this VPBlockBase if it has a
/// single hierarchical predecessor. Otherwise return a null pointer.
VPBlockBase *getSingleHierarchicalPredecessor() {
return getEnclosingBlockWithPredecessors()->getSinglePredecessor();
}
/// Set a given VPBlockBase \p Successor as the single successor of this
/// VPBlockBase. This VPBlockBase is not added as predecessor of \p Successor.
/// This VPBlockBase must have no successors.
void setOneSuccessor(VPBlockBase *Successor) {
assert(Successors.empty() && "Setting one successor when others exist.");
appendSuccessor(Successor);
}
/// Set two given VPBlockBases \p IfTrue and \p IfFalse to be the two
/// successors of this VPBlockBase. This VPBlockBase is not added as
/// predecessor of \p IfTrue or \p IfFalse. This VPBlockBase must have no
/// successors.
void setTwoSuccessors(VPBlockBase *IfTrue, VPBlockBase *IfFalse) {
assert(Successors.empty() && "Setting two successors when others exist.");
appendSuccessor(IfTrue);
appendSuccessor(IfFalse);
}
/// Set each VPBasicBlock in \p NewPreds as predecessor of this VPBlockBase.
/// This VPBlockBase must have no predecessors. This VPBlockBase is not added
/// as successor of any VPBasicBlock in \p NewPreds.
void setPredecessors(ArrayRef<VPBlockBase *> NewPreds) {
assert(Predecessors.empty() && "Block predecessors already set.");
for (auto *Pred : NewPreds)
appendPredecessor(Pred);
}
/// Remove all the predecessor of this block.
void clearPredecessors() { Predecessors.clear(); }
/// Remove all the successors of this block.
void clearSuccessors() { Successors.clear(); }
/// The method which generates the output IR that correspond to this
/// VPBlockBase, thereby "executing" the VPlan.
virtual void execute(struct VPTransformState *State) = 0;
/// Delete all blocks reachable from a given VPBlockBase, inclusive.
static void deleteCFG(VPBlockBase *Entry);
/// Return true if it is legal to hoist instructions into this block.
bool isLegalToHoistInto() {
// There are currently no constraints that prevent an instruction to be
// hoisted into a VPBlockBase.
return true;
}
/// Replace all operands of VPUsers in the block with \p NewValue and also
/// replaces all uses of VPValues defined in the block with NewValue.
virtual void dropAllReferences(VPValue *NewValue) = 0;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void printAsOperand(raw_ostream &OS, bool PrintType) const {
OS << getName();
}
/// Print plain-text dump of this VPBlockBase to \p O, prefixing all lines
/// with \p Indent. \p SlotTracker is used to print unnamed VPValue's using
/// consequtive numbers.
///
/// Note that the numbering is applied to the whole VPlan, so printing
/// individual blocks is consistent with the whole VPlan printing.
virtual void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const = 0;
/// Print plain-text dump of this VPlan to \p O.
void print(raw_ostream &O) const {
VPSlotTracker SlotTracker(getPlan());
print(O, "", SlotTracker);
}
/// Print the successors of this block to \p O, prefixing all lines with \p
/// Indent.
void printSuccessors(raw_ostream &O, const Twine &Indent) const;
/// Dump this VPBlockBase to dbgs().
LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
#endif
};
/// A value that is used outside the VPlan. The operand of the user needs to be
/// added to the associated LCSSA phi node.
class VPLiveOut : public VPUser {
PHINode *Phi;
public:
VPLiveOut(PHINode *Phi, VPValue *Op)
: VPUser({Op}, VPUser::VPUserID::LiveOut), Phi(Phi) {}
/// Fixup the wrapped LCSSA phi node in the unique exit block. This simply
/// means we need to add the appropriate incoming value from the middle
/// block as exiting edges from the scalar epilogue loop (if present) are
/// already in place, and we exit the vector loop exclusively to the middle
/// block.
void fixPhi(VPlan &Plan, VPTransformState &State);
/// Returns true if the VPLiveOut uses scalars of operand \p Op.
bool usesScalars(const VPValue *Op) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return true;
}
PHINode *getPhi() const { return Phi; }
};
/// VPRecipeBase is a base class modeling a sequence of one or more output IR
/// instructions. VPRecipeBase owns the the VPValues it defines through VPDef
/// and is responsible for deleting its defined values. Single-value
/// VPRecipeBases that also inherit from VPValue must make sure to inherit from
/// VPRecipeBase before VPValue.
class VPRecipeBase : public ilist_node_with_parent<VPRecipeBase, VPBasicBlock>,
public VPDef,
public VPUser {
friend VPBasicBlock;
friend class VPBlockUtils;
/// Each VPRecipe belongs to a single VPBasicBlock.
VPBasicBlock *Parent = nullptr;
public:
VPRecipeBase(const unsigned char SC, ArrayRef<VPValue *> Operands)
: VPDef(SC), VPUser(Operands, VPUser::VPUserID::Recipe) {}
template <typename IterT>
VPRecipeBase(const unsigned char SC, iterator_range<IterT> Operands)
: VPDef(SC), VPUser(Operands, VPUser::VPUserID::Recipe) {}
virtual ~VPRecipeBase() = default;
/// \return the VPBasicBlock which this VPRecipe belongs to.
VPBasicBlock *getParent() { return Parent; }
const VPBasicBlock *getParent() const { return Parent; }
/// The method which generates the output IR instructions that correspond to
/// this VPRecipe, thereby "executing" the VPlan.
virtual void execute(struct VPTransformState &State) = 0;
/// Insert an unlinked recipe into a basic block immediately before
/// the specified recipe.
void insertBefore(VPRecipeBase *InsertPos);
/// Insert an unlinked recipe into \p BB immediately before the insertion
/// point \p IP;
void insertBefore(VPBasicBlock &BB, iplist<VPRecipeBase>::iterator IP);
/// Insert an unlinked Recipe into a basic block immediately after
/// the specified Recipe.
void insertAfter(VPRecipeBase *InsertPos);
/// Unlink this recipe from its current VPBasicBlock and insert it into
/// the VPBasicBlock that MovePos lives in, right after MovePos.
void moveAfter(VPRecipeBase *MovePos);
/// Unlink this recipe and insert into BB before I.
///
/// \pre I is a valid iterator into BB.
void moveBefore(VPBasicBlock &BB, iplist<VPRecipeBase>::iterator I);
/// This method unlinks 'this' from the containing basic block, but does not
/// delete it.
void removeFromParent();
/// This method unlinks 'this' from the containing basic block and deletes it.
///
/// \returns an iterator pointing to the element after the erased one
iplist<VPRecipeBase>::iterator eraseFromParent();
/// Returns the underlying instruction, if the recipe is a VPValue or nullptr
/// otherwise.
Instruction *getUnderlyingInstr() {
return cast<Instruction>(getVPSingleValue()->getUnderlyingValue());
}
const Instruction *getUnderlyingInstr() const {
return cast<Instruction>(getVPSingleValue()->getUnderlyingValue());
}
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
// All VPDefs are also VPRecipeBases.
return true;
}
static inline bool classof(const VPUser *U) {
return U->getVPUserID() == VPUser::VPUserID::Recipe;
}
/// Returns true if the recipe may have side-effects.
bool mayHaveSideEffects() const;
/// Returns true for PHI-like recipes.
bool isPhi() const {
return getVPDefID() >= VPFirstPHISC && getVPDefID() <= VPLastPHISC;
}
/// Returns true if the recipe may read from memory.
bool mayReadFromMemory() const;
/// Returns true if the recipe may write to memory.
bool mayWriteToMemory() const;
/// Returns true if the recipe may read from or write to memory.
bool mayReadOrWriteMemory() const {
return mayReadFromMemory() || mayWriteToMemory();
}
};
inline bool VPUser::classof(const VPDef *Def) {
return Def->getVPDefID() == VPRecipeBase::VPInstructionSC ||
Def->getVPDefID() == VPRecipeBase::VPWidenSC ||
Def->getVPDefID() == VPRecipeBase::VPWidenCallSC ||
Def->getVPDefID() == VPRecipeBase::VPWidenSelectSC ||
Def->getVPDefID() == VPRecipeBase::VPWidenGEPSC ||
Def->getVPDefID() == VPRecipeBase::VPBlendSC ||
Def->getVPDefID() == VPRecipeBase::VPInterleaveSC ||
Def->getVPDefID() == VPRecipeBase::VPReplicateSC ||
Def->getVPDefID() == VPRecipeBase::VPReductionSC ||
Def->getVPDefID() == VPRecipeBase::VPBranchOnMaskSC ||
Def->getVPDefID() == VPRecipeBase::VPWidenMemoryInstructionSC;
}
/// This is a concrete Recipe that models a single VPlan-level instruction.
/// While as any Recipe it may generate a sequence of IR instructions when
/// executed, these instructions would always form a single-def expression as
/// the VPInstruction is also a single def-use vertex.
class VPInstruction : public VPRecipeBase, public VPValue {
friend class VPlanSlp;
public:
/// VPlan opcodes, extending LLVM IR with idiomatics instructions.
enum {
FirstOrderRecurrenceSplice =
Instruction::OtherOpsEnd + 1, // Combines the incoming and previous
// values of a first-order recurrence.
Not,
ICmpULE,
SLPLoad,
SLPStore,
ActiveLaneMask,
CanonicalIVIncrement,
CanonicalIVIncrementNUW,
// The next two are similar to the above, but instead increment the
// canonical IV separately for each unrolled part.
CanonicalIVIncrementForPart,
CanonicalIVIncrementForPartNUW,
BranchOnCount,
BranchOnCond
};
private:
typedef unsigned char OpcodeTy;
OpcodeTy Opcode;
FastMathFlags FMF;
DebugLoc DL;
/// An optional name that can be used for the generated IR instruction.
const std::string Name;
/// Utility method serving execute(): generates a single instance of the
/// modeled instruction.
void generateInstruction(VPTransformState &State, unsigned Part);
protected:
void setUnderlyingInstr(Instruction *I) { setUnderlyingValue(I); }
public:
VPInstruction(unsigned Opcode, ArrayRef<VPValue *> Operands, DebugLoc DL,
const Twine &Name = "")
: VPRecipeBase(VPRecipeBase::VPInstructionSC, Operands),
VPValue(VPValue::VPVInstructionSC, nullptr, this), Opcode(Opcode),
DL(DL), Name(Name.str()) {}
VPInstruction(unsigned Opcode, std::initializer_list<VPValue *> Operands,
DebugLoc DL = {}, const Twine &Name = "")
: VPInstruction(Opcode, ArrayRef<VPValue *>(Operands), DL, Name) {}
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPValue *V) {
return V->getVPValueID() == VPValue::VPVInstructionSC;
}
VPInstruction *clone() const {
SmallVector<VPValue *, 2> Operands(operands());
return new VPInstruction(Opcode, Operands, DL, Name);
}
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *R) {
return R->getVPDefID() == VPRecipeBase::VPInstructionSC;
}
/// Extra classof implementations to allow directly casting from VPUser ->
/// VPInstruction.
static inline bool classof(const VPUser *U) {
auto *R = dyn_cast<VPRecipeBase>(U);
return R && R->getVPDefID() == VPRecipeBase::VPInstructionSC;
}
static inline bool classof(const VPRecipeBase *R) {
return R->getVPDefID() == VPRecipeBase::VPInstructionSC;
}
unsigned getOpcode() const { return Opcode; }
/// Generate the instruction.
/// TODO: We currently execute only per-part unless a specific instance is
/// provided.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the VPInstruction to \p O.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
/// Print the VPInstruction to dbgs() (for debugging).
LLVM_DUMP_METHOD void dump() const;
#endif
/// Return true if this instruction may modify memory.
bool mayWriteToMemory() const {
// TODO: we can use attributes of the called function to rule out memory
// modifications.
return Opcode == Instruction::Store || Opcode == Instruction::Call ||
Opcode == Instruction::Invoke || Opcode == SLPStore;
}
bool hasResult() const {
// CallInst may or may not have a result, depending on the called function.
// Conservatively return calls have results for now.
switch (getOpcode()) {
case Instruction::Ret:
case Instruction::Br:
case Instruction::Store:
case Instruction::Switch:
case Instruction::IndirectBr:
case Instruction::Resume:
case Instruction::CatchRet:
case Instruction::Unreachable:
case Instruction::Fence:
case Instruction::AtomicRMW:
case VPInstruction::BranchOnCond:
case VPInstruction::BranchOnCount:
return false;
default:
return true;
}
}
/// Set the fast-math flags.
void setFastMathFlags(FastMathFlags FMFNew);
/// Returns true if the recipe only uses the first lane of operand \p Op.
bool onlyFirstLaneUsed(const VPValue *Op) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
if (getOperand(0) != Op)
return false;
switch (getOpcode()) {
default:
return false;
case VPInstruction::ActiveLaneMask:
case VPInstruction::CanonicalIVIncrement:
case VPInstruction::CanonicalIVIncrementNUW:
case VPInstruction::CanonicalIVIncrementForPart:
case VPInstruction::CanonicalIVIncrementForPartNUW:
case VPInstruction::BranchOnCount:
return true;
};
llvm_unreachable("switch should return");
}
};
/// VPWidenRecipe is a recipe for producing a copy of vector type its
/// ingredient. This recipe covers most of the traditional vectorization cases
/// where each ingredient transforms into a vectorized version of itself.
class VPWidenRecipe : public VPRecipeBase, public VPValue {
public:
template <typename IterT>
VPWidenRecipe(Instruction &I, iterator_range<IterT> Operands)
: VPRecipeBase(VPRecipeBase::VPWidenSC, Operands),
VPValue(VPValue::VPVWidenSC, &I, this) {}
~VPWidenRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPWidenSC;
}
static inline bool classof(const VPValue *V) {
return V->getVPValueID() == VPValue::VPVWidenSC;
}
/// Produce widened copies of all Ingredients.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
};
/// A recipe for widening Call instructions.
class VPWidenCallRecipe : public VPRecipeBase, public VPValue {
public:
template <typename IterT>
VPWidenCallRecipe(CallInst &I, iterator_range<IterT> CallArguments)
: VPRecipeBase(VPRecipeBase::VPWidenCallSC, CallArguments),
VPValue(VPValue::VPVWidenCallSC, &I, this) {}
~VPWidenCallRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPWidenCallSC;
}
/// Produce a widened version of the call instruction.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
};
/// A recipe for widening select instructions.
class VPWidenSelectRecipe : public VPRecipeBase, public VPValue {
/// Is the condition of the select loop invariant?
bool InvariantCond;
public:
template <typename IterT>
VPWidenSelectRecipe(SelectInst &I, iterator_range<IterT> Operands,
bool InvariantCond)
: VPRecipeBase(VPRecipeBase::VPWidenSelectSC, Operands),
VPValue(VPValue::VPVWidenSelectSC, &I, this),
InvariantCond(InvariantCond) {}
~VPWidenSelectRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPWidenSelectSC;
}
/// Produce a widened version of the select instruction.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
};
/// A recipe for handling GEP instructions.
class VPWidenGEPRecipe : public VPRecipeBase, public VPValue {
bool IsPtrLoopInvariant;
SmallBitVector IsIndexLoopInvariant;
public:
template <typename IterT>
VPWidenGEPRecipe(GetElementPtrInst *GEP, iterator_range<IterT> Operands)
: VPRecipeBase(VPRecipeBase::VPWidenGEPSC, Operands),
VPValue(VPWidenGEPSC, GEP, this),
IsIndexLoopInvariant(GEP->getNumIndices(), false) {}
template <typename IterT>
VPWidenGEPRecipe(GetElementPtrInst *GEP, iterator_range<IterT> Operands,
Loop *OrigLoop)
: VPRecipeBase(VPRecipeBase::VPWidenGEPSC, Operands),
VPValue(VPValue::VPVWidenGEPSC, GEP, this),
IsIndexLoopInvariant(GEP->getNumIndices(), false) {
IsPtrLoopInvariant = OrigLoop->isLoopInvariant(GEP->getPointerOperand());
for (auto Index : enumerate(GEP->indices()))
IsIndexLoopInvariant[Index.index()] =
OrigLoop->isLoopInvariant(Index.value().get());
}
~VPWidenGEPRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPWidenGEPSC;
}
/// Generate the gep nodes.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
};
/// A recipe for handling phi nodes of integer and floating-point inductions,
/// producing their vector values.
class VPWidenIntOrFpInductionRecipe : public VPRecipeBase, public VPValue {
PHINode *IV;
const InductionDescriptor &IndDesc;
bool NeedsVectorIV;
public:
VPWidenIntOrFpInductionRecipe(PHINode *IV, VPValue *Start, VPValue *Step,
const InductionDescriptor &IndDesc,
bool NeedsVectorIV)
: VPRecipeBase(VPWidenIntOrFpInductionSC, {Start, Step}),
VPValue(IV, this), IV(IV), IndDesc(IndDesc),
NeedsVectorIV(NeedsVectorIV) {}
VPWidenIntOrFpInductionRecipe(PHINode *IV, VPValue *Start, VPValue *Step,
const InductionDescriptor &IndDesc,
TruncInst *Trunc, bool NeedsVectorIV)
: VPRecipeBase(VPWidenIntOrFpInductionSC, {Start, Step}),
VPValue(Trunc, this), IV(IV), IndDesc(IndDesc),
NeedsVectorIV(NeedsVectorIV) {}
~VPWidenIntOrFpInductionRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPWidenIntOrFpInductionSC;
}
/// Generate the vectorized and scalarized versions of the phi node as
/// needed by their users.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
/// Returns the start value of the induction.
VPValue *getStartValue() { return getOperand(0); }
const VPValue *getStartValue() const { return getOperand(0); }
/// Returns the step value of the induction.
VPValue *getStepValue() { return getOperand(1); }
const VPValue *getStepValue() const { return getOperand(1); }
/// Returns the first defined value as TruncInst, if it is one or nullptr
/// otherwise.
TruncInst *getTruncInst() {
return dyn_cast_or_null<TruncInst>(getVPValue(0)->getUnderlyingValue());
}
const TruncInst *getTruncInst() const {
return dyn_cast_or_null<TruncInst>(getVPValue(0)->getUnderlyingValue());
}
PHINode *getPHINode() { return IV; }
/// Returns the induction descriptor for the recipe.
const InductionDescriptor &getInductionDescriptor() const { return IndDesc; }
/// Returns true if the induction is canonical, i.e. starting at 0 and
/// incremented by UF * VF (= the original IV is incremented by 1).
bool isCanonical() const;
/// Returns the scalar type of the induction.
const Type *getScalarType() const {
const TruncInst *TruncI = getTruncInst();
return TruncI ? TruncI->getType() : IV->getType();
}
/// Returns true if a vector phi needs to be created for the induction.
bool needsVectorIV() const { return NeedsVectorIV; }
};
/// A pure virtual base class for all recipes modeling header phis, including
/// phis for first order recurrences, pointer inductions and reductions. The
/// start value is the first operand of the recipe and the incoming value from
/// the backedge is the second operand.
class VPHeaderPHIRecipe : public VPRecipeBase, public VPValue {
protected:
VPHeaderPHIRecipe(unsigned char VPVID, unsigned char VPDefID, PHINode *Phi,
VPValue *Start = nullptr)
: VPRecipeBase(VPDefID, {}), VPValue(VPVID, Phi, this) {
if (Start)
addOperand(Start);
}
public:
~VPHeaderPHIRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPRecipeBase *B) {
return B->getVPDefID() == VPRecipeBase::VPCanonicalIVPHISC ||
B->getVPDefID() == VPRecipeBase::VPActiveLaneMaskPHISC ||
B->getVPDefID() == VPRecipeBase::VPFirstOrderRecurrencePHISC ||
B->getVPDefID() == VPRecipeBase::VPReductionPHISC ||
B->getVPDefID() == VPRecipeBase::VPWidenIntOrFpInductionSC ||
B->getVPDefID() == VPRecipeBase::VPWidenPHISC;
}
static inline bool classof(const VPValue *V) {
return V->getVPValueID() == VPValue::VPVCanonicalIVPHISC ||
V->getVPValueID() == VPValue::VPVActiveLaneMaskPHISC ||
V->getVPValueID() == VPValue::VPVFirstOrderRecurrencePHISC ||
V->getVPValueID() == VPValue::VPVReductionPHISC ||
V->getVPValueID() == VPValue::VPVWidenIntOrFpInductionSC ||
V->getVPValueID() == VPValue::VPVWidenPHISC;
}
/// Generate the phi nodes.
void execute(VPTransformState &State) override = 0;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override = 0;
#endif
/// Returns the start value of the phi, if one is set.
VPValue *getStartValue() {
return getNumOperands() == 0 ? nullptr : getOperand(0);
}
VPValue *getStartValue() const {
return getNumOperands() == 0 ? nullptr : getOperand(0);
}
/// Returns the incoming value from the loop backedge.
VPValue *getBackedgeValue() {
return getOperand(1);
}
/// Returns the backedge value as a recipe. The backedge value is guaranteed
/// to be a recipe.
VPRecipeBase *getBackedgeRecipe() {
return cast<VPRecipeBase>(getBackedgeValue()->getDef());
}
};
class VPWidenPointerInductionRecipe : public VPHeaderPHIRecipe {
const InductionDescriptor &IndDesc;
/// SCEV used to expand step.
/// FIXME: move expansion of step to the pre-header, once it is modeled
/// explicitly.
ScalarEvolution &SE;
+ bool IsScalarAfterVectorization;
+
public:
/// Create a new VPWidenPointerInductionRecipe for \p Phi with start value \p
/// Start.
VPWidenPointerInductionRecipe(PHINode *Phi, VPValue *Start,
const InductionDescriptor &IndDesc,
- ScalarEvolution &SE)
+ ScalarEvolution &SE,
+ bool IsScalarAfterVectorization)
: VPHeaderPHIRecipe(VPVWidenPointerInductionSC, VPWidenPointerInductionSC,
Phi),
- IndDesc(IndDesc), SE(SE) {
+ IndDesc(IndDesc), SE(SE),
+ IsScalarAfterVectorization(IsScalarAfterVectorization) {
addOperand(Start);
}
~VPWidenPointerInductionRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPRecipeBase *B) {
return B->getVPDefID() == VPRecipeBase::VPWidenPointerInductionSC;
}
static inline bool classof(const VPHeaderPHIRecipe *R) {
return R->getVPDefID() == VPRecipeBase::VPWidenPointerInductionSC;
}
static inline bool classof(const VPValue *V) {
return V->getVPValueID() == VPValue::VPVWidenPointerInductionSC;
}
/// Generate vector values for the pointer induction.
void execute(VPTransformState &State) override;
/// Returns true if only scalar values will be generated.
bool onlyScalarsGenerated(ElementCount VF);
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
};
/// A recipe for handling header phis that are widened in the vector loop.
/// In the VPlan native path, all incoming VPValues & VPBasicBlock pairs are
/// managed in the recipe directly.
class VPWidenPHIRecipe : public VPHeaderPHIRecipe {
/// List of incoming blocks. Only used in the VPlan native path.
SmallVector<VPBasicBlock *, 2> IncomingBlocks;
public:
/// Create a new VPWidenPHIRecipe for \p Phi with start value \p Start.
VPWidenPHIRecipe(PHINode *Phi, VPValue *Start = nullptr)
: VPHeaderPHIRecipe(VPVWidenPHISC, VPWidenPHISC, Phi) {
if (Start)
addOperand(Start);
}
~VPWidenPHIRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPRecipeBase *B) {
return B->getVPDefID() == VPRecipeBase::VPWidenPHISC;
}
static inline bool classof(const VPHeaderPHIRecipe *R) {
return R->getVPDefID() == VPRecipeBase::VPWidenPHISC;
}
static inline bool classof(const VPValue *V) {
return V->getVPValueID() == VPValue::VPVWidenPHISC;
}
/// Generate the phi/select nodes.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
/// Adds a pair (\p IncomingV, \p IncomingBlock) to the phi.
void addIncoming(VPValue *IncomingV, VPBasicBlock *IncomingBlock) {
addOperand(IncomingV);
IncomingBlocks.push_back(IncomingBlock);
}
/// Returns the \p I th incoming VPBasicBlock.
VPBasicBlock *getIncomingBlock(unsigned I) { return IncomingBlocks[I]; }
/// Returns the \p I th incoming VPValue.
VPValue *getIncomingValue(unsigned I) { return getOperand(I); }
};
/// A recipe for handling first-order recurrence phis. The start value is the
/// first operand of the recipe and the incoming value from the backedge is the
/// second operand.
struct VPFirstOrderRecurrencePHIRecipe : public VPHeaderPHIRecipe {
VPFirstOrderRecurrencePHIRecipe(PHINode *Phi, VPValue &Start)
: VPHeaderPHIRecipe(VPVFirstOrderRecurrencePHISC,
VPFirstOrderRecurrencePHISC, Phi, &Start) {}
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPRecipeBase *R) {
return R->getVPDefID() == VPRecipeBase::VPFirstOrderRecurrencePHISC;
}
static inline bool classof(const VPHeaderPHIRecipe *R) {
return R->getVPDefID() == VPRecipeBase::VPFirstOrderRecurrencePHISC;
}
static inline bool classof(const VPValue *V) {
return V->getVPValueID() == VPValue::VPVFirstOrderRecurrencePHISC;
}
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
};
/// A recipe for handling reduction phis. The start value is the first operand
/// of the recipe and the incoming value from the backedge is the second
/// operand.
class VPReductionPHIRecipe : public VPHeaderPHIRecipe {
/// Descriptor for the reduction.
const RecurrenceDescriptor &RdxDesc;
/// The phi is part of an in-loop reduction.
bool IsInLoop;
/// The phi is part of an ordered reduction. Requires IsInLoop to be true.
bool IsOrdered;
public:
/// Create a new VPReductionPHIRecipe for the reduction \p Phi described by \p
/// RdxDesc.
VPReductionPHIRecipe(PHINode *Phi, const RecurrenceDescriptor &RdxDesc,
VPValue &Start, bool IsInLoop = false,
bool IsOrdered = false)
: VPHeaderPHIRecipe(VPVReductionPHISC, VPReductionPHISC, Phi, &Start),
RdxDesc(RdxDesc), IsInLoop(IsInLoop), IsOrdered(IsOrdered) {
assert((!IsOrdered || IsInLoop) && "IsOrdered requires IsInLoop");
}
~VPReductionPHIRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPRecipeBase *R) {
return R->getVPDefID() == VPRecipeBase::VPReductionPHISC;
}
static inline bool classof(const VPHeaderPHIRecipe *R) {
return R->getVPDefID() == VPRecipeBase::VPReductionPHISC;
}
static inline bool classof(const VPValue *V) {
return V->getVPValueID() == VPValue::VPVReductionPHISC;
}
/// Generate the phi/select nodes.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
const RecurrenceDescriptor &getRecurrenceDescriptor() const {
return RdxDesc;
}
/// Returns true, if the phi is part of an ordered reduction.
bool isOrdered() const { return IsOrdered; }
/// Returns true, if the phi is part of an in-loop reduction.
bool isInLoop() const { return IsInLoop; }
};
/// A recipe for vectorizing a phi-node as a sequence of mask-based select
/// instructions.
class VPBlendRecipe : public VPRecipeBase, public VPValue {
PHINode *Phi;
public:
/// The blend operation is a User of the incoming values and of their
/// respective masks, ordered [I0, M0, I1, M1, ...]. Note that a single value
/// might be incoming with a full mask for which there is no VPValue.
VPBlendRecipe(PHINode *Phi, ArrayRef<VPValue *> Operands)
: VPRecipeBase(VPBlendSC, Operands),
VPValue(VPValue::VPVBlendSC, Phi, this), Phi(Phi) {
assert(Operands.size() > 0 &&
((Operands.size() == 1) || (Operands.size() % 2 == 0)) &&
"Expected either a single incoming value or a positive even number "
"of operands");
}
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPBlendSC;
}
/// Return the number of incoming values, taking into account that a single
/// incoming value has no mask.
unsigned getNumIncomingValues() const { return (getNumOperands() + 1) / 2; }
/// Return incoming value number \p Idx.
VPValue *getIncomingValue(unsigned Idx) const { return getOperand(Idx * 2); }
/// Return mask number \p Idx.
VPValue *getMask(unsigned Idx) const { return getOperand(Idx * 2 + 1); }
/// Generate the phi/select nodes.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
/// Returns true if the recipe only uses the first lane of operand \p Op.
bool onlyFirstLaneUsed(const VPValue *Op) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
// Recursing through Blend recipes only, must terminate at header phi's the
// latest.
return all_of(users(),
[this](VPUser *U) { return U->onlyFirstLaneUsed(this); });
}
};
/// VPInterleaveRecipe is a recipe for transforming an interleave group of load
/// or stores into one wide load/store and shuffles. The first operand of a
/// VPInterleave recipe is the address, followed by the stored values, followed
/// by an optional mask.
class VPInterleaveRecipe : public VPRecipeBase {
const InterleaveGroup<Instruction> *IG;
bool HasMask = false;
public:
VPInterleaveRecipe(const InterleaveGroup<Instruction> *IG, VPValue *Addr,
ArrayRef<VPValue *> StoredValues, VPValue *Mask)
: VPRecipeBase(VPInterleaveSC, {Addr}), IG(IG) {
for (unsigned i = 0; i < IG->getFactor(); ++i)
if (Instruction *I = IG->getMember(i)) {
if (I->getType()->isVoidTy())
continue;
new VPValue(I, this);
}
for (auto *SV : StoredValues)
addOperand(SV);
if (Mask) {
HasMask = true;
addOperand(Mask);
}
}
~VPInterleaveRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPInterleaveSC;
}
/// Return the address accessed by this recipe.
VPValue *getAddr() const {
return getOperand(0); // Address is the 1st, mandatory operand.
}
/// Return the mask used by this recipe. Note that a full mask is represented
/// by a nullptr.
VPValue *getMask() const {
// Mask is optional and therefore the last, currently 2nd operand.
return HasMask ? getOperand(getNumOperands() - 1) : nullptr;
}
/// Return the VPValues stored by this interleave group. If it is a load
/// interleave group, return an empty ArrayRef.
ArrayRef<VPValue *> getStoredValues() const {
// The first operand is the address, followed by the stored values, followed
// by an optional mask.
return ArrayRef<VPValue *>(op_begin(), getNumOperands())
.slice(1, getNumStoreOperands());
}
/// Generate the wide load or store, and shuffles.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
const InterleaveGroup<Instruction> *getInterleaveGroup() { return IG; }
/// Returns the number of stored operands of this interleave group. Returns 0
/// for load interleave groups.
unsigned getNumStoreOperands() const {
return getNumOperands() - (HasMask ? 2 : 1);
}
/// The recipe only uses the first lane of the address.
bool onlyFirstLaneUsed(const VPValue *Op) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return Op == getAddr() && all_of(getStoredValues(), [Op](VPValue *StoredV) {
return Op != StoredV;
});
}
};
/// A recipe to represent inloop reduction operations, performing a reduction on
/// a vector operand into a scalar value, and adding the result to a chain.
/// The Operands are {ChainOp, VecOp, [Condition]}.
class VPReductionRecipe : public VPRecipeBase, public VPValue {
/// The recurrence decriptor for the reduction in question.
const RecurrenceDescriptor *RdxDesc;
/// Pointer to the TTI, needed to create the target reduction
const TargetTransformInfo *TTI;
public:
VPReductionRecipe(const RecurrenceDescriptor *R, Instruction *I,
VPValue *ChainOp, VPValue *VecOp, VPValue *CondOp,
const TargetTransformInfo *TTI)
: VPRecipeBase(VPRecipeBase::VPReductionSC, {ChainOp, VecOp}),
VPValue(VPValue::VPVReductionSC, I, this), RdxDesc(R), TTI(TTI) {
if (CondOp)
addOperand(CondOp);
}
~VPReductionRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPValue *V) {
return V->getVPValueID() == VPValue::VPVReductionSC;
}
/// Generate the reduction in the loop
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
/// The VPValue of the scalar Chain being accumulated.
VPValue *getChainOp() const { return getOperand(0); }
/// The VPValue of the vector value to be reduced.
VPValue *getVecOp() const { return getOperand(1); }
/// The VPValue of the condition for the block.
VPValue *getCondOp() const {
return getNumOperands() > 2 ? getOperand(2) : nullptr;
}
};
/// VPReplicateRecipe replicates a given instruction producing multiple scalar
/// copies of the original scalar type, one per lane, instead of producing a
/// single copy of widened type for all lanes. If the instruction is known to be
/// uniform only one copy, per lane zero, will be generated.
class VPReplicateRecipe : public VPRecipeBase, public VPValue {
/// Indicator if only a single replica per lane is needed.
bool IsUniform;
/// Indicator if the replicas are also predicated.
bool IsPredicated;
/// Indicator if the scalar values should also be packed into a vector.
bool AlsoPack;
public:
template <typename IterT>
VPReplicateRecipe(Instruction *I, iterator_range<IterT> Operands,
bool IsUniform, bool IsPredicated = false)
: VPRecipeBase(VPReplicateSC, Operands), VPValue(VPVReplicateSC, I, this),
IsUniform(IsUniform), IsPredicated(IsPredicated) {
// Retain the previous behavior of predicateInstructions(), where an
// insert-element of a predicated instruction got hoisted into the
// predicated basic block iff it was its only user. This is achieved by
// having predicated instructions also pack their values into a vector by
// default unless they have a replicated user which uses their scalar value.
AlsoPack = IsPredicated && !I->use_empty();
}
~VPReplicateRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPReplicateSC;
}
static inline bool classof(const VPValue *V) {
return V->getVPValueID() == VPValue::VPVReplicateSC;
}
/// Generate replicas of the desired Ingredient. Replicas will be generated
/// for all parts and lanes unless a specific part and lane are specified in
/// the \p State.
void execute(VPTransformState &State) override;
void setAlsoPack(bool Pack) { AlsoPack = Pack; }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
bool isUniform() const { return IsUniform; }
bool isPacked() const { return AlsoPack; }
bool isPredicated() const { return IsPredicated; }
/// Returns true if the recipe only uses the first lane of operand \p Op.
bool onlyFirstLaneUsed(const VPValue *Op) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return isUniform();
}
/// Returns true if the recipe uses scalars of operand \p Op.
bool usesScalars(const VPValue *Op) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return true;
}
};
/// A recipe for generating conditional branches on the bits of a mask.
class VPBranchOnMaskRecipe : public VPRecipeBase {
public:
VPBranchOnMaskRecipe(VPValue *BlockInMask)
: VPRecipeBase(VPBranchOnMaskSC, {}) {
if (BlockInMask) // nullptr means all-one mask.
addOperand(BlockInMask);
}
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPBranchOnMaskSC;
}
/// Generate the extraction of the appropriate bit from the block mask and the
/// conditional branch.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override {
O << Indent << "BRANCH-ON-MASK ";
if (VPValue *Mask = getMask())
Mask->printAsOperand(O, SlotTracker);
else
O << " All-One";
}
#endif
/// Return the mask used by this recipe. Note that a full mask is represented
/// by a nullptr.
VPValue *getMask() const {
assert(getNumOperands() <= 1 && "should have either 0 or 1 operands");
// Mask is optional.
return getNumOperands() == 1 ? getOperand(0) : nullptr;
}
/// Returns true if the recipe uses scalars of operand \p Op.
bool usesScalars(const VPValue *Op) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return true;
}
};
/// VPPredInstPHIRecipe is a recipe for generating the phi nodes needed when
/// control converges back from a Branch-on-Mask. The phi nodes are needed in
/// order to merge values that are set under such a branch and feed their uses.
/// The phi nodes can be scalar or vector depending on the users of the value.
/// This recipe works in concert with VPBranchOnMaskRecipe.
class VPPredInstPHIRecipe : public VPRecipeBase, public VPValue {
public:
/// Construct a VPPredInstPHIRecipe given \p PredInst whose value needs a phi
/// nodes after merging back from a Branch-on-Mask.
VPPredInstPHIRecipe(VPValue *PredV)
: VPRecipeBase(VPPredInstPHISC, PredV),
VPValue(VPValue::VPVPredInstPHI, nullptr, this) {}
~VPPredInstPHIRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPPredInstPHISC;
}
/// Generates phi nodes for live-outs as needed to retain SSA form.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
/// Returns true if the recipe uses scalars of operand \p Op.
bool usesScalars(const VPValue *Op) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return true;
}
};
/// A Recipe for widening load/store operations.
/// The recipe uses the following VPValues:
/// - For load: Address, optional mask
/// - For store: Address, stored value, optional mask
/// TODO: We currently execute only per-part unless a specific instance is
/// provided.
class VPWidenMemoryInstructionRecipe : public VPRecipeBase {
Instruction &Ingredient;
// Whether the loaded-from / stored-to addresses are consecutive.
bool Consecutive;
// Whether the consecutive loaded/stored addresses are in reverse order.
bool Reverse;
void setMask(VPValue *Mask) {
if (!Mask)
return;
addOperand(Mask);
}
bool isMasked() const {
return isStore() ? getNumOperands() == 3 : getNumOperands() == 2;
}
public:
VPWidenMemoryInstructionRecipe(LoadInst &Load, VPValue *Addr, VPValue *Mask,
bool Consecutive, bool Reverse)
: VPRecipeBase(VPWidenMemoryInstructionSC, {Addr}), Ingredient(Load),
Consecutive(Consecutive), Reverse(Reverse) {
assert((Consecutive || !Reverse) && "Reverse implies consecutive");
new VPValue(VPValue::VPVMemoryInstructionSC, &Load, this);
setMask(Mask);
}
VPWidenMemoryInstructionRecipe(StoreInst &Store, VPValue *Addr,
VPValue *StoredValue, VPValue *Mask,
bool Consecutive, bool Reverse)
: VPRecipeBase(VPWidenMemoryInstructionSC, {Addr, StoredValue}),
Ingredient(Store), Consecutive(Consecutive), Reverse(Reverse) {
assert((Consecutive || !Reverse) && "Reverse implies consecutive");
setMask(Mask);
}
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPWidenMemoryInstructionSC;
}
/// Return the address accessed by this recipe.
VPValue *getAddr() const {
return getOperand(0); // Address is the 1st, mandatory operand.
}
/// Return the mask used by this recipe. Note that a full mask is represented
/// by a nullptr.
VPValue *getMask() const {
// Mask is optional and therefore the last operand.
return isMasked() ? getOperand(getNumOperands() - 1) : nullptr;
}
/// Returns true if this recipe is a store.
bool isStore() const { return isa<StoreInst>(Ingredient); }
/// Return the address accessed by this recipe.
VPValue *getStoredValue() const {
assert(isStore() && "Stored value only available for store instructions");
return getOperand(1); // Stored value is the 2nd, mandatory operand.
}
// Return whether the loaded-from / stored-to addresses are consecutive.
bool isConsecutive() const { return Consecutive; }
// Return whether the consecutive loaded/stored addresses are in reverse
// order.
bool isReverse() const { return Reverse; }
/// Generate the wide load/store.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
/// Returns true if the recipe only uses the first lane of operand \p Op.
bool onlyFirstLaneUsed(const VPValue *Op) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
// Widened, consecutive memory operations only demand the first lane of
// their address, unless the same operand is also stored. That latter can
// happen with opaque pointers.
return Op == getAddr() && isConsecutive() &&
(!isStore() || Op != getStoredValue());
}
Instruction &getIngredient() const { return Ingredient; }
};
/// Recipe to expand a SCEV expression.
class VPExpandSCEVRecipe : public VPRecipeBase, public VPValue {
const SCEV *Expr;
ScalarEvolution &SE;
public:
VPExpandSCEVRecipe(const SCEV *Expr, ScalarEvolution &SE)
: VPRecipeBase(VPExpandSCEVSC, {}), VPValue(nullptr, this), Expr(Expr),
SE(SE) {}
~VPExpandSCEVRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPExpandSCEVSC;
}
/// Generate a canonical vector induction variable of the vector loop, with
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
const SCEV *getSCEV() const { return Expr; }
};
/// Canonical scalar induction phi of the vector loop. Starting at the specified
/// start value (either 0 or the resume value when vectorizing the epilogue
/// loop). VPWidenCanonicalIVRecipe represents the vector version of the
/// canonical induction variable.
class VPCanonicalIVPHIRecipe : public VPHeaderPHIRecipe {
DebugLoc DL;
public:
VPCanonicalIVPHIRecipe(VPValue *StartV, DebugLoc DL)
: VPHeaderPHIRecipe(VPValue::VPVCanonicalIVPHISC, VPCanonicalIVPHISC,
nullptr, StartV),
DL(DL) {}
~VPCanonicalIVPHIRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPCanonicalIVPHISC;
}
static inline bool classof(const VPHeaderPHIRecipe *D) {
return D->getVPDefID() == VPCanonicalIVPHISC;
}
static inline bool classof(const VPValue *V) {
return V->getVPValueID() == VPValue::VPVCanonicalIVPHISC;
}
/// Generate the canonical scalar induction phi of the vector loop.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
/// Returns the scalar type of the induction.
const Type *getScalarType() const {
return getOperand(0)->getLiveInIRValue()->getType();
}
/// Returns true if the recipe only uses the first lane of operand \p Op.
bool onlyFirstLaneUsed(const VPValue *Op) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return true;
}
};
/// A recipe for generating the active lane mask for the vector loop that is
/// used to predicate the vector operations.
/// TODO: It would be good to use the existing VPWidenPHIRecipe instead and
/// remove VPActiveLaneMaskPHIRecipe.
class VPActiveLaneMaskPHIRecipe : public VPHeaderPHIRecipe {
DebugLoc DL;
public:
VPActiveLaneMaskPHIRecipe(VPValue *StartMask, DebugLoc DL)
: VPHeaderPHIRecipe(VPValue::VPVActiveLaneMaskPHISC,
VPActiveLaneMaskPHISC, nullptr, StartMask),
DL(DL) {}
~VPActiveLaneMaskPHIRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPActiveLaneMaskPHISC;
}
static inline bool classof(const VPHeaderPHIRecipe *D) {
return D->getVPDefID() == VPActiveLaneMaskPHISC;
}
static inline bool classof(const VPValue *V) {
return V->getVPValueID() == VPValue::VPVActiveLaneMaskPHISC;
}
/// Generate the active lane mask phi of the vector loop.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
};
/// A Recipe for widening the canonical induction variable of the vector loop.
class VPWidenCanonicalIVRecipe : public VPRecipeBase, public VPValue {
public:
VPWidenCanonicalIVRecipe(VPCanonicalIVPHIRecipe *CanonicalIV)
: VPRecipeBase(VPWidenCanonicalIVSC, {CanonicalIV}),
VPValue(VPValue::VPVWidenCanonicalIVSC, nullptr, this) {}
~VPWidenCanonicalIVRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPWidenCanonicalIVSC;
}
/// Extra classof implementations to allow directly casting from VPUser ->
/// VPWidenCanonicalIVRecipe.
static inline bool classof(const VPUser *U) {
auto *R = dyn_cast<VPRecipeBase>(U);
return R && R->getVPDefID() == VPRecipeBase::VPWidenCanonicalIVSC;
}
static inline bool classof(const VPRecipeBase *R) {
return R->getVPDefID() == VPRecipeBase::VPWidenCanonicalIVSC;
}
/// Generate a canonical vector induction variable of the vector loop, with
/// start = {<Part*VF, Part*VF+1, ..., Part*VF+VF-1> for 0 <= Part < UF}, and
/// step = <VF*UF, VF*UF, ..., VF*UF>.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
/// Returns the scalar type of the induction.
const Type *getScalarType() const {
return cast<VPCanonicalIVPHIRecipe>(getOperand(0)->getDef())
->getScalarType();
}
};
/// A recipe for handling phi nodes of integer and floating-point inductions,
/// producing their scalar values.
class VPScalarIVStepsRecipe : public VPRecipeBase, public VPValue {
/// Scalar type to use for the generated values.
Type *Ty;
/// If not nullptr, truncate the generated values to TruncToTy.
Type *TruncToTy;
const InductionDescriptor &IndDesc;
public:
VPScalarIVStepsRecipe(Type *Ty, const InductionDescriptor &IndDesc,
VPValue *CanonicalIV, VPValue *Start, VPValue *Step,
Type *TruncToTy)
: VPRecipeBase(VPScalarIVStepsSC, {CanonicalIV, Start, Step}),
VPValue(nullptr, this), Ty(Ty), TruncToTy(TruncToTy), IndDesc(IndDesc) {
}
~VPScalarIVStepsRecipe() override = default;
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPDef *D) {
return D->getVPDefID() == VPRecipeBase::VPScalarIVStepsSC;
}
/// Extra classof implementations to allow directly casting from VPUser ->
/// VPScalarIVStepsRecipe.
static inline bool classof(const VPUser *U) {
auto *R = dyn_cast<VPRecipeBase>(U);
return R && R->getVPDefID() == VPRecipeBase::VPScalarIVStepsSC;
}
static inline bool classof(const VPRecipeBase *R) {
return R->getVPDefID() == VPRecipeBase::VPScalarIVStepsSC;
}
/// Generate the scalarized versions of the phi node as needed by their users.
void execute(VPTransformState &State) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print the recipe.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif
/// Returns true if the induction is canonical, i.e. starting at 0 and
/// incremented by UF * VF (= the original IV is incremented by 1).
bool isCanonical() const;
VPCanonicalIVPHIRecipe *getCanonicalIV() const;
VPValue *getStartValue() const { return getOperand(1); }
VPValue *getStepValue() const { return getOperand(2); }
/// Returns true if the recipe only uses the first lane of operand \p Op.
bool onlyFirstLaneUsed(const VPValue *Op) const override {
assert(is_contained(operands(), Op) &&
"Op must be an operand of the recipe");
return true;
}
};
/// VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph. It
/// holds a sequence of zero or more VPRecipe's each representing a sequence of
/// output IR instructions. All PHI-like recipes must come before any non-PHI recipes.
class VPBasicBlock : public VPBlockBase {
public:
using RecipeListTy = iplist<VPRecipeBase>;
private:
/// The VPRecipes held in the order of output instructions to generate.
RecipeListTy Recipes;
public:
VPBasicBlock(const Twine &Name = "", VPRecipeBase *Recipe = nullptr)
: VPBlockBase(VPBasicBlockSC, Name.str()) {
if (Recipe)
appendRecipe(Recipe);
}
~VPBasicBlock() override {
while (!Recipes.empty())
Recipes.pop_back();
}
/// Instruction iterators...
using iterator = RecipeListTy::iterator;
using const_iterator = RecipeListTy::const_iterator;
using reverse_iterator = RecipeListTy::reverse_iterator;
using const_reverse_iterator = RecipeListTy::const_reverse_iterator;
//===--------------------------------------------------------------------===//
/// Recipe iterator methods
///
inline iterator begin() { return Recipes.begin(); }
inline const_iterator begin() const { return Recipes.begin(); }
inline iterator end() { return Recipes.end(); }
inline const_iterator end() const { return Recipes.end(); }
inline reverse_iterator rbegin() { return Recipes.rbegin(); }
inline const_reverse_iterator rbegin() const { return Recipes.rbegin(); }
inline reverse_iterator rend() { return Recipes.rend(); }
inline const_reverse_iterator rend() const { return Recipes.rend(); }
inline size_t size() const { return Recipes.size(); }
inline bool empty() const { return Recipes.empty(); }
inline const VPRecipeBase &front() const { return Recipes.front(); }
inline VPRecipeBase &front() { return Recipes.front(); }
inline const VPRecipeBase &back() const { return Recipes.back(); }
inline VPRecipeBase &back() { return Recipes.back(); }
/// Returns a reference to the list of recipes.
RecipeListTy &getRecipeList() { return Recipes; }
/// Returns a pointer to a member of the recipe list.
static RecipeListTy VPBasicBlock::*getSublistAccess(VPRecipeBase *) {
return &VPBasicBlock::Recipes;
}
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPBlockBase *V) {
return V->getVPBlockID() == VPBlockBase::VPBasicBlockSC;
}
void insert(VPRecipeBase *Recipe, iterator InsertPt) {
assert(Recipe && "No recipe to append.");
assert(!Recipe->Parent && "Recipe already in VPlan");
Recipe->Parent = this;
Recipes.insert(InsertPt, Recipe);
}
/// Augment the existing recipes of a VPBasicBlock with an additional
/// \p Recipe as the last recipe.
void appendRecipe(VPRecipeBase *Recipe) { insert(Recipe, end()); }
/// The method which generates the output IR instructions that correspond to
/// this VPBasicBlock, thereby "executing" the VPlan.
void execute(struct VPTransformState *State) override;
/// Return the position of the first non-phi node recipe in the block.
iterator getFirstNonPhi();
/// Returns an iterator range over the PHI-like recipes in the block.
iterator_range<iterator> phis() {
return make_range(begin(), getFirstNonPhi());
}
void dropAllReferences(VPValue *NewValue) override;
/// Split current block at \p SplitAt by inserting a new block between the
/// current block and its successors and moving all recipes starting at
/// SplitAt to the new block. Returns the new block.
VPBasicBlock *splitAt(iterator SplitAt);
VPRegionBlock *getEnclosingLoopRegion();
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print this VPBsicBlock to \p O, prefixing all lines with \p Indent. \p
/// SlotTracker is used to print unnamed VPValue's using consequtive numbers.
///
/// Note that the numbering is applied to the whole VPlan, so printing
/// individual blocks is consistent with the whole VPlan printing.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
using VPBlockBase::print; // Get the print(raw_stream &O) version.
#endif
/// If the block has multiple successors, return the branch recipe terminating
/// the block. If there are no or only a single successor, return nullptr;
VPRecipeBase *getTerminator();
const VPRecipeBase *getTerminator() const;
/// Returns true if the block is exiting it's parent region.
bool isExiting() const;
private:
/// Create an IR BasicBlock to hold the output instructions generated by this
/// VPBasicBlock, and return it. Update the CFGState accordingly.
BasicBlock *createEmptyBasicBlock(VPTransformState::CFGState &CFG);
};
/// VPRegionBlock represents a collection of VPBasicBlocks and VPRegionBlocks
/// which form a Single-Entry-Single-Exiting subgraph of the output IR CFG.
/// A VPRegionBlock may indicate that its contents are to be replicated several
/// times. This is designed to support predicated scalarization, in which a
/// scalar if-then code structure needs to be generated VF * UF times. Having
/// this replication indicator helps to keep a single model for multiple
/// candidate VF's. The actual replication takes place only once the desired VF
/// and UF have been determined.
class VPRegionBlock : public VPBlockBase {
/// Hold the Single Entry of the SESE region modelled by the VPRegionBlock.
VPBlockBase *Entry;
/// Hold the Single Exiting block of the SESE region modelled by the
/// VPRegionBlock.
VPBlockBase *Exiting;
/// An indicator whether this region is to generate multiple replicated
/// instances of output IR corresponding to its VPBlockBases.
bool IsReplicator;
public:
VPRegionBlock(VPBlockBase *Entry, VPBlockBase *Exiting,
const std::string &Name = "", bool IsReplicator = false)
: VPBlockBase(VPRegionBlockSC, Name), Entry(Entry), Exiting(Exiting),
IsReplicator(IsReplicator) {
assert(Entry->getPredecessors().empty() && "Entry block has predecessors.");
assert(Exiting->getSuccessors().empty() && "Exit block has successors.");
Entry->setParent(this);
Exiting->setParent(this);
}
VPRegionBlock(const std::string &Name = "", bool IsReplicator = false)
: VPBlockBase(VPRegionBlockSC, Name), Entry(nullptr), Exiting(nullptr),
IsReplicator(IsReplicator) {}
~VPRegionBlock() override {
if (Entry) {
VPValue DummyValue;
Entry->dropAllReferences(&DummyValue);
deleteCFG(Entry);
}
}
/// Method to support type inquiry through isa, cast, and dyn_cast.
static inline bool classof(const VPBlockBase *V) {
return V->getVPBlockID() == VPBlockBase::VPRegionBlockSC;
}
const VPBlockBase *getEntry() const { return Entry; }
VPBlockBase *getEntry() { return Entry; }
/// Set \p EntryBlock as the entry VPBlockBase of this VPRegionBlock. \p
/// EntryBlock must have no predecessors.
void setEntry(VPBlockBase *EntryBlock) {
assert(EntryBlock->getPredecessors().empty() &&
"Entry block cannot have predecessors.");
Entry = EntryBlock;
EntryBlock->setParent(this);
}
// FIXME: DominatorTreeBase is doing 'A->getParent()->front()'. 'front' is a
// specific interface of llvm::Function, instead of using
// GraphTraints::getEntryNode. We should add a new template parameter to
// DominatorTreeBase representing the Graph type.
VPBlockBase &front() const { return *Entry; }
const VPBlockBase *getExiting() const { return Exiting; }
VPBlockBase *getExiting() { return Exiting; }
/// Set \p ExitingBlock as the exiting VPBlockBase of this VPRegionBlock. \p
/// ExitingBlock must have no successors.
void setExiting(VPBlockBase *ExitingBlock) {
assert(ExitingBlock->getSuccessors().empty() &&
"Exit block cannot have successors.");
Exiting = ExitingBlock;
ExitingBlock->setParent(this);
}
/// Returns the pre-header VPBasicBlock of the loop region.
VPBasicBlock *getPreheaderVPBB() {
assert(!isReplicator() && "should only get pre-header of loop regions");
return getSinglePredecessor()->getExitingBasicBlock();
}
/// An indicator whether this region is to generate multiple replicated
/// instances of output IR corresponding to its VPBlockBases.
bool isReplicator() const { return IsReplicator; }
/// The method which generates the output IR instructions that correspond to
/// this VPRegionBlock, thereby "executing" the VPlan.
void execute(struct VPTransformState *State) override;
void dropAllReferences(VPValue *NewValue) override;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print this VPRegionBlock to \p O (recursively), prefixing all lines with
/// \p Indent. \p SlotTracker is used to print unnamed VPValue's using
/// consequtive numbers.
///
/// Note that the numbering is applied to the whole VPlan, so printing
/// individual regions is consistent with the whole VPlan printing.
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
using VPBlockBase::print; // Get the print(raw_stream &O) version.
#endif
};
//===----------------------------------------------------------------------===//
// GraphTraits specializations for VPlan Hierarchical Control-Flow Graphs //
//===----------------------------------------------------------------------===//
// The following set of template specializations implement GraphTraits to treat
// any VPBlockBase as a node in a graph of VPBlockBases. It's important to note
// that VPBlockBase traits don't recurse into VPRegioBlocks, i.e., if the
// VPBlockBase is a VPRegionBlock, this specialization provides access to its
// successors/predecessors but not to the blocks inside the region.
template <> struct GraphTraits<VPBlockBase *> {
using NodeRef = VPBlockBase *;
using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::iterator;
static NodeRef getEntryNode(NodeRef N) { return N; }
static inline ChildIteratorType child_begin(NodeRef N) {
return N->getSuccessors().begin();
}
static inline ChildIteratorType child_end(NodeRef N) {
return N->getSuccessors().end();
}
};
template <> struct GraphTraits<const VPBlockBase *> {
using NodeRef = const VPBlockBase *;
using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::const_iterator;
static NodeRef getEntryNode(NodeRef N) { return N; }
static inline ChildIteratorType child_begin(NodeRef N) {
return N->getSuccessors().begin();
}
static inline ChildIteratorType child_end(NodeRef N) {
return N->getSuccessors().end();
}
};
// Inverse order specialization for VPBasicBlocks. Predecessors are used instead
// of successors for the inverse traversal.
template <> struct GraphTraits<Inverse<VPBlockBase *>> {
using NodeRef = VPBlockBase *;
using ChildIteratorType = SmallVectorImpl<VPBlockBase *>::iterator;
static NodeRef getEntryNode(Inverse<NodeRef> B) { return B.Graph; }
static inline ChildIteratorType child_begin(NodeRef N) {
return N->getPredecessors().begin();
}
static inline ChildIteratorType child_end(NodeRef N) {
return N->getPredecessors().end();
}
};
// The following set of template specializations implement GraphTraits to
// treat VPRegionBlock as a graph and recurse inside its nodes. It's important
// to note that the blocks inside the VPRegionBlock are treated as VPBlockBases
// (i.e., no dyn_cast is performed, VPBlockBases specialization is used), so
// there won't be automatic recursion into other VPBlockBases that turn to be
// VPRegionBlocks.
template <>
struct GraphTraits<VPRegionBlock *> : public GraphTraits<VPBlockBase *> {
using GraphRef = VPRegionBlock *;
using nodes_iterator = df_iterator<NodeRef>;
static NodeRef getEntryNode(GraphRef N) { return N->getEntry(); }
static nodes_iterator nodes_begin(GraphRef N) {
return nodes_iterator::begin(N->getEntry());
}
static nodes_iterator nodes_end(GraphRef N) {
// df_iterator::end() returns an empty iterator so the node used doesn't
// matter.
return nodes_iterator::end(N);
}
};
template <>
struct GraphTraits<const VPRegionBlock *>
: public GraphTraits<const VPBlockBase *> {
using GraphRef = const VPRegionBlock *;
using nodes_iterator = df_iterator<NodeRef>;
static NodeRef getEntryNode(GraphRef N) { return N->getEntry(); }
static nodes_iterator nodes_begin(GraphRef N) {
return nodes_iterator::begin(N->getEntry());
}
static nodes_iterator nodes_end(GraphRef N) {
// df_iterator::end() returns an empty iterator so the node used doesn't
// matter.
return nodes_iterator::end(N);
}
};
template <>
struct GraphTraits<Inverse<VPRegionBlock *>>
: public GraphTraits<Inverse<VPBlockBase *>> {
using GraphRef = VPRegionBlock *;
using nodes_iterator = df_iterator<NodeRef>;
static NodeRef getEntryNode(Inverse<GraphRef> N) {
return N.Graph->getExiting();
}
static nodes_iterator nodes_begin(GraphRef N) {
return nodes_iterator::begin(N->getExiting());
}
static nodes_iterator nodes_end(GraphRef N) {
// df_iterator::end() returns an empty iterator so the node used doesn't
// matter.
return nodes_iterator::end(N);
}
};
/// Iterator to traverse all successors of a VPBlockBase node. This includes the
/// entry node of VPRegionBlocks. Exit blocks of a region implicitly have their
/// parent region's successors. This ensures all blocks in a region are visited
/// before any blocks in a successor region when doing a reverse post-order
// traversal of the graph.
template <typename BlockPtrTy>
class VPAllSuccessorsIterator
: public iterator_facade_base<VPAllSuccessorsIterator<BlockPtrTy>,
std::forward_iterator_tag, VPBlockBase> {
BlockPtrTy Block;
/// Index of the current successor. For VPBasicBlock nodes, this simply is the
/// index for the successor array. For VPRegionBlock, SuccessorIdx == 0 is
/// used for the region's entry block, and SuccessorIdx - 1 are the indices
/// for the successor array.
size_t SuccessorIdx;
static BlockPtrTy getBlockWithSuccs(BlockPtrTy Current) {
while (Current && Current->getNumSuccessors() == 0)
Current = Current->getParent();
return Current;
}
/// Templated helper to dereference successor \p SuccIdx of \p Block. Used by
/// both the const and non-const operator* implementations.
template <typename T1> static T1 deref(T1 Block, unsigned SuccIdx) {
if (auto *R = dyn_cast<VPRegionBlock>(Block)) {
if (SuccIdx == 0)
return R->getEntry();
SuccIdx--;
}
// For exit blocks, use the next parent region with successors.
return getBlockWithSuccs(Block)->getSuccessors()[SuccIdx];
}
public:
VPAllSuccessorsIterator(BlockPtrTy Block, size_t Idx = 0)
: Block(Block), SuccessorIdx(Idx) {}
VPAllSuccessorsIterator(const VPAllSuccessorsIterator &Other)
: Block(Other.Block), SuccessorIdx(Other.SuccessorIdx) {}
VPAllSuccessorsIterator &operator=(const VPAllSuccessorsIterator &R) {
Block = R.Block;
SuccessorIdx = R.SuccessorIdx;
return *this;
}
static VPAllSuccessorsIterator end(BlockPtrTy Block) {
BlockPtrTy ParentWithSuccs = getBlockWithSuccs(Block);
unsigned NumSuccessors = ParentWithSuccs
? ParentWithSuccs->getNumSuccessors()
: Block->getNumSuccessors();
if (auto *R = dyn_cast<VPRegionBlock>(Block))
return {R, NumSuccessors + 1};
return {Block, NumSuccessors};
}
bool operator==(const VPAllSuccessorsIterator &R) const {
return Block == R.Block && SuccessorIdx == R.SuccessorIdx;
}
const VPBlockBase *operator*() const { return deref(Block, SuccessorIdx); }
BlockPtrTy operator*() { return deref(Block, SuccessorIdx); }
VPAllSuccessorsIterator &operator++() {
SuccessorIdx++;
return *this;
}
VPAllSuccessorsIterator operator++(int X) {
VPAllSuccessorsIterator Orig = *this;
SuccessorIdx++;
return Orig;
}
};
/// Helper for GraphTraits specialization that traverses through VPRegionBlocks.
template <typename BlockTy> class VPBlockRecursiveTraversalWrapper {
BlockTy Entry;
public:
VPBlockRecursiveTraversalWrapper(BlockTy Entry) : Entry(Entry) {}
BlockTy getEntry() { return Entry; }
};
/// GraphTraits specialization to recursively traverse VPBlockBase nodes,
/// including traversing through VPRegionBlocks. Exit blocks of a region
/// implicitly have their parent region's successors. This ensures all blocks in
/// a region are visited before any blocks in a successor region when doing a
/// reverse post-order traversal of the graph.
template <>
struct GraphTraits<VPBlockRecursiveTraversalWrapper<VPBlockBase *>> {
using NodeRef = VPBlockBase *;
using ChildIteratorType = VPAllSuccessorsIterator<VPBlockBase *>;
static NodeRef
getEntryNode(VPBlockRecursiveTraversalWrapper<VPBlockBase *> N) {
return N.getEntry();
}
static inline ChildIteratorType child_begin(NodeRef N) {
return ChildIteratorType(N);
}
static inline ChildIteratorType child_end(NodeRef N) {
return ChildIteratorType::end(N);
}
};
template <>
struct GraphTraits<VPBlockRecursiveTraversalWrapper<const VPBlockBase *>> {
using NodeRef = const VPBlockBase *;
using ChildIteratorType = VPAllSuccessorsIterator<const VPBlockBase *>;
static NodeRef
getEntryNode(VPBlockRecursiveTraversalWrapper<const VPBlockBase *> N) {
return N.getEntry();
}
static inline ChildIteratorType child_begin(NodeRef N) {
return ChildIteratorType(N);
}
static inline ChildIteratorType child_end(NodeRef N) {
return ChildIteratorType::end(N);
}
};
/// VPlan models a candidate for vectorization, encoding various decisions take
/// to produce efficient output IR, including which branches, basic-blocks and
/// output IR instructions to generate, and their cost. VPlan holds a
/// Hierarchical-CFG of VPBasicBlocks and VPRegionBlocks rooted at an Entry
/// VPBlock.
class VPlan {
friend class VPlanPrinter;
friend class VPSlotTracker;
/// Hold the single entry to the Hierarchical CFG of the VPlan.
VPBlockBase *Entry;
/// Holds the VFs applicable to this VPlan.
SmallSetVector<ElementCount, 2> VFs;
/// Holds the name of the VPlan, for printing.
std::string Name;
/// Holds all the external definitions created for this VPlan. External
/// definitions must be immutable and hold a pointer to their underlying IR.
DenseMap<Value *, VPValue *> VPExternalDefs;
/// Represents the trip count of the original loop, for folding
/// the tail.
VPValue *TripCount = nullptr;
/// Represents the backedge taken count of the original loop, for folding
/// the tail. It equals TripCount - 1.
VPValue *BackedgeTakenCount = nullptr;
/// Represents the vector trip count.
VPValue VectorTripCount;
/// Holds a mapping between Values and their corresponding VPValue inside
/// VPlan.
Value2VPValueTy Value2VPValue;
/// Contains all VPValues that been allocated by addVPValue directly and need
/// to be free when the plan's destructor is called.
SmallVector<VPValue *, 16> VPValuesToFree;
/// Indicates whether it is safe use the Value2VPValue mapping or if the
/// mapping cannot be used any longer, because it is stale.
bool Value2VPValueEnabled = true;
/// Values used outside the plan.
MapVector<PHINode *, VPLiveOut *> LiveOuts;
public:
VPlan(VPBlockBase *Entry = nullptr) : Entry(Entry) {
if (Entry)
Entry->setPlan(this);
}
~VPlan() {
clearLiveOuts();
if (Entry) {
VPValue DummyValue;
for (VPBlockBase *Block : depth_first(Entry))
Block->dropAllReferences(&DummyValue);
VPBlockBase::deleteCFG(Entry);
}
for (VPValue *VPV : VPValuesToFree)
delete VPV;
if (TripCount)
delete TripCount;
if (BackedgeTakenCount)
delete BackedgeTakenCount;
for (auto &P : VPExternalDefs)
delete P.second;
}
/// Prepare the plan for execution, setting up the required live-in values.
void prepareToExecute(Value *TripCount, Value *VectorTripCount,
Value *CanonicalIVStartValue, VPTransformState &State,
bool IsEpilogueVectorization);
/// Generate the IR code for this VPlan.
void execute(struct VPTransformState *State);
VPBlockBase *getEntry() { return Entry; }
const VPBlockBase *getEntry() const { return Entry; }
VPBlockBase *setEntry(VPBlockBase *Block) {
Entry = Block;
Block->setPlan(this);
return Entry;
}
/// The trip count of the original loop.
VPValue *getOrCreateTripCount() {
if (!TripCount)
TripCount = new VPValue();
return TripCount;
}
/// The backedge taken count of the original loop.
VPValue *getOrCreateBackedgeTakenCount() {
if (!BackedgeTakenCount)
BackedgeTakenCount = new VPValue();
return BackedgeTakenCount;
}
/// The vector trip count.
VPValue &getVectorTripCount() { return VectorTripCount; }
/// Mark the plan to indicate that using Value2VPValue is not safe any
/// longer, because it may be stale.
void disableValue2VPValue() { Value2VPValueEnabled = false; }
void addVF(ElementCount VF) { VFs.insert(VF); }
bool hasVF(ElementCount VF) { return VFs.count(VF); }
const std::string &getName() const { return Name; }
void setName(const Twine &newName) { Name = newName.str(); }
/// Get the existing or add a new external definition for \p V.
VPValue *getOrAddExternalDef(Value *V) {
auto I = VPExternalDefs.insert({V, nullptr});
if (I.second)
I.first->second = new VPValue(V);
return I.first->second;
}
void addVPValue(Value *V) {
assert(Value2VPValueEnabled &&
"IR value to VPValue mapping may be out of date!");
assert(V && "Trying to add a null Value to VPlan");
assert(!Value2VPValue.count(V) && "Value already exists in VPlan");
VPValue *VPV = new VPValue(V);
Value2VPValue[V] = VPV;
VPValuesToFree.push_back(VPV);
}
void addVPValue(Value *V, VPValue *VPV) {
assert(Value2VPValueEnabled && "Value2VPValue mapping may be out of date!");
assert(V && "Trying to add a null Value to VPlan");
assert(!Value2VPValue.count(V) && "Value already exists in VPlan");
Value2VPValue[V] = VPV;
}
/// Returns the VPValue for \p V. \p OverrideAllowed can be used to disable
/// checking whether it is safe to query VPValues using IR Values.
VPValue *getVPValue(Value *V, bool OverrideAllowed = false) {
assert((OverrideAllowed || isa<Constant>(V) || Value2VPValueEnabled) &&
"Value2VPValue mapping may be out of date!");
assert(V && "Trying to get the VPValue of a null Value");
assert(Value2VPValue.count(V) && "Value does not exist in VPlan");
return Value2VPValue[V];
}
/// Gets the VPValue or adds a new one (if none exists yet) for \p V. \p
/// OverrideAllowed can be used to disable checking whether it is safe to
/// query VPValues using IR Values.
VPValue *getOrAddVPValue(Value *V, bool OverrideAllowed = false) {
assert((OverrideAllowed || isa<Constant>(V) || Value2VPValueEnabled) &&
"Value2VPValue mapping may be out of date!");
assert(V && "Trying to get or add the VPValue of a null Value");
if (!Value2VPValue.count(V))
addVPValue(V);
return getVPValue(V);
}
void removeVPValueFor(Value *V) {
assert(Value2VPValueEnabled &&
"IR value to VPValue mapping may be out of date!");
Value2VPValue.erase(V);
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print this VPlan to \p O.
void print(raw_ostream &O) const;
/// Print this VPlan in DOT format to \p O.
void printDOT(raw_ostream &O) const;
/// Dump the plan to stderr (for debugging).
LLVM_DUMP_METHOD void dump() const;
#endif
/// Returns a range mapping the values the range \p Operands to their
/// corresponding VPValues.
iterator_range<mapped_iterator<Use *, std::function<VPValue *(Value *)>>>
mapToVPValues(User::op_range Operands) {
std::function<VPValue *(Value *)> Fn = [this](Value *Op) {
return getOrAddVPValue(Op);
};
return map_range(Operands, Fn);
}
/// Returns true if \p VPV is uniform after vectorization.
bool isUniformAfterVectorization(VPValue *VPV) const {
auto RepR = dyn_cast_or_null<VPReplicateRecipe>(VPV->getDef());
return !VPV->getDef() || (RepR && RepR->isUniform());
}
/// Returns the VPRegionBlock of the vector loop.
VPRegionBlock *getVectorLoopRegion() {
return cast<VPRegionBlock>(getEntry()->getSingleSuccessor());
}
const VPRegionBlock *getVectorLoopRegion() const {
return cast<VPRegionBlock>(getEntry()->getSingleSuccessor());
}
/// Returns the canonical induction recipe of the vector loop.
VPCanonicalIVPHIRecipe *getCanonicalIV() {
VPBasicBlock *EntryVPBB = getVectorLoopRegion()->getEntryBasicBlock();
if (EntryVPBB->empty()) {
// VPlan native path.
EntryVPBB = cast<VPBasicBlock>(EntryVPBB->getSingleSuccessor());
}
return cast<VPCanonicalIVPHIRecipe>(&*EntryVPBB->begin());
}
/// Find and return the VPActiveLaneMaskPHIRecipe from the header - there
/// be only one at most. If there isn't one, then return nullptr.
VPActiveLaneMaskPHIRecipe *getActiveLaneMaskPhi();
void addLiveOut(PHINode *PN, VPValue *V);
void clearLiveOuts() {
for (auto &KV : LiveOuts)
delete KV.second;
LiveOuts.clear();
}
void removeLiveOut(PHINode *PN) {
delete LiveOuts[PN];
LiveOuts.erase(PN);
}
const MapVector<PHINode *, VPLiveOut *> &getLiveOuts() const {
return LiveOuts;
}
private:
/// Add to the given dominator tree the header block and every new basic block
/// that was created between it and the latch block, inclusive.
static void updateDominatorTree(DominatorTree *DT, BasicBlock *LoopLatchBB,
BasicBlock *LoopPreHeaderBB,
BasicBlock *LoopExitBB);
};
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// VPlanPrinter prints a given VPlan to a given output stream. The printing is
/// indented and follows the dot format.
class VPlanPrinter {
raw_ostream &OS;
const VPlan &Plan;
unsigned Depth = 0;
unsigned TabWidth = 2;
std::string Indent;
unsigned BID = 0;
SmallDenseMap<const VPBlockBase *, unsigned> BlockID;
VPSlotTracker SlotTracker;
/// Handle indentation.
void bumpIndent(int b) { Indent = std::string((Depth += b) * TabWidth, ' '); }
/// Print a given \p Block of the Plan.
void dumpBlock(const VPBlockBase *Block);
/// Print the information related to the CFG edges going out of a given
/// \p Block, followed by printing the successor blocks themselves.
void dumpEdges(const VPBlockBase *Block);
/// Print a given \p BasicBlock, including its VPRecipes, followed by printing
/// its successor blocks.
void dumpBasicBlock(const VPBasicBlock *BasicBlock);
/// Print a given \p Region of the Plan.
void dumpRegion(const VPRegionBlock *Region);
unsigned getOrCreateBID(const VPBlockBase *Block) {
return BlockID.count(Block) ? BlockID[Block] : BlockID[Block] = BID++;
}
Twine getOrCreateName(const VPBlockBase *Block);
Twine getUID(const VPBlockBase *Block);
/// Print the information related to a CFG edge between two VPBlockBases.
void drawEdge(const VPBlockBase *From, const VPBlockBase *To, bool Hidden,
const Twine &Label);
public:
VPlanPrinter(raw_ostream &O, const VPlan &P)
: OS(O), Plan(P), SlotTracker(&P) {}
LLVM_DUMP_METHOD void dump();
};
struct VPlanIngredient {
const Value *V;
VPlanIngredient(const Value *V) : V(V) {}
void print(raw_ostream &O) const;
};
inline raw_ostream &operator<<(raw_ostream &OS, const VPlanIngredient &I) {
I.print(OS);
return OS;
}
inline raw_ostream &operator<<(raw_ostream &OS, const VPlan &Plan) {
Plan.print(OS);
return OS;
}
#endif
//===----------------------------------------------------------------------===//
// VPlan Utilities
//===----------------------------------------------------------------------===//
/// Class that provides utilities for VPBlockBases in VPlan.
class VPBlockUtils {
public:
VPBlockUtils() = delete;
/// Insert disconnected VPBlockBase \p NewBlock after \p BlockPtr. Add \p
/// NewBlock as successor of \p BlockPtr and \p BlockPtr as predecessor of \p
/// NewBlock, and propagate \p BlockPtr parent to \p NewBlock. \p BlockPtr's
/// successors are moved from \p BlockPtr to \p NewBlock. \p NewBlock must
/// have neither successors nor predecessors.
static void insertBlockAfter(VPBlockBase *NewBlock, VPBlockBase *BlockPtr) {
assert(NewBlock->getSuccessors().empty() &&
NewBlock->getPredecessors().empty() &&
"Can't insert new block with predecessors or successors.");
NewBlock->setParent(BlockPtr->getParent());
SmallVector<VPBlockBase *> Succs(BlockPtr->successors());
for (VPBlockBase *Succ : Succs) {
disconnectBlocks(BlockPtr, Succ);
connectBlocks(NewBlock, Succ);
}
connectBlocks(BlockPtr, NewBlock);
}
/// Insert disconnected VPBlockBases \p IfTrue and \p IfFalse after \p
/// BlockPtr. Add \p IfTrue and \p IfFalse as succesors of \p BlockPtr and \p
/// BlockPtr as predecessor of \p IfTrue and \p IfFalse. Propagate \p BlockPtr
/// parent to \p IfTrue and \p IfFalse. \p BlockPtr must have no successors
/// and \p IfTrue and \p IfFalse must have neither successors nor
/// predecessors.
static void insertTwoBlocksAfter(VPBlockBase *IfTrue, VPBlockBase *IfFalse,
VPBlockBase *BlockPtr) {
assert(IfTrue->getSuccessors().empty() &&
"Can't insert IfTrue with successors.");
assert(IfFalse->getSuccessors().empty() &&
"Can't insert IfFalse with successors.");
BlockPtr->setTwoSuccessors(IfTrue, IfFalse);
IfTrue->setPredecessors({BlockPtr});
IfFalse->setPredecessors({BlockPtr});
IfTrue->setParent(BlockPtr->getParent());
IfFalse->setParent(BlockPtr->getParent());
}
/// Connect VPBlockBases \p From and \p To bi-directionally. Append \p To to
/// the successors of \p From and \p From to the predecessors of \p To. Both
/// VPBlockBases must have the same parent, which can be null. Both
/// VPBlockBases can be already connected to other VPBlockBases.
static void connectBlocks(VPBlockBase *From, VPBlockBase *To) {
assert((From->getParent() == To->getParent()) &&
"Can't connect two block with different parents");
assert(From->getNumSuccessors() < 2 &&
"Blocks can't have more than two successors.");
From->appendSuccessor(To);
To->appendPredecessor(From);
}
/// Disconnect VPBlockBases \p From and \p To bi-directionally. Remove \p To
/// from the successors of \p From and \p From from the predecessors of \p To.
static void disconnectBlocks(VPBlockBase *From, VPBlockBase *To) {
assert(To && "Successor to disconnect is null.");
From->removeSuccessor(To);
To->removePredecessor(From);
}
/// Try to merge \p Block into its single predecessor, if \p Block is a
/// VPBasicBlock and its predecessor has a single successor. Returns a pointer
/// to the predecessor \p Block was merged into or nullptr otherwise.
static VPBasicBlock *tryToMergeBlockIntoPredecessor(VPBlockBase *Block) {
auto *VPBB = dyn_cast<VPBasicBlock>(Block);
auto *PredVPBB =
dyn_cast_or_null<VPBasicBlock>(Block->getSinglePredecessor());
if (!VPBB || !PredVPBB || PredVPBB->getNumSuccessors() != 1)
return nullptr;
for (VPRecipeBase &R : make_early_inc_range(*VPBB))
R.moveBefore(*PredVPBB, PredVPBB->end());
VPBlockUtils::disconnectBlocks(PredVPBB, VPBB);
auto *ParentRegion = cast<VPRegionBlock>(Block->getParent());
if (ParentRegion->getExiting() == Block)
ParentRegion->setExiting(PredVPBB);
SmallVector<VPBlockBase *> Successors(Block->successors());
for (auto *Succ : Successors) {
VPBlockUtils::disconnectBlocks(Block, Succ);
VPBlockUtils::connectBlocks(PredVPBB, Succ);
}
delete Block;
return PredVPBB;
}
/// Return an iterator range over \p Range which only includes \p BlockTy
/// blocks. The accesses are casted to \p BlockTy.
template <typename BlockTy, typename T>
static auto blocksOnly(const T &Range) {
// Create BaseTy with correct const-ness based on BlockTy.
using BaseTy =
typename std::conditional<std::is_const<BlockTy>::value,
const VPBlockBase, VPBlockBase>::type;
// We need to first create an iterator range over (const) BlocktTy & instead
// of (const) BlockTy * for filter_range to work properly.
auto Mapped =
map_range(Range, [](BaseTy *Block) -> BaseTy & { return *Block; });
auto Filter = make_filter_range(
Mapped, [](BaseTy &Block) { return isa<BlockTy>(&Block); });
return map_range(Filter, [](BaseTy &Block) -> BlockTy * {
return cast<BlockTy>(&Block);
});
}
};
class VPInterleavedAccessInfo {
DenseMap<VPInstruction *, InterleaveGroup<VPInstruction> *>
InterleaveGroupMap;
/// Type for mapping of instruction based interleave groups to VPInstruction
/// interleave groups
using Old2NewTy = DenseMap<InterleaveGroup<Instruction> *,
InterleaveGroup<VPInstruction> *>;
/// Recursively \p Region and populate VPlan based interleave groups based on
/// \p IAI.
void visitRegion(VPRegionBlock *Region, Old2NewTy &Old2New,
InterleavedAccessInfo &IAI);
/// Recursively traverse \p Block and populate VPlan based interleave groups
/// based on \p IAI.
void visitBlock(VPBlockBase *Block, Old2NewTy &Old2New,
InterleavedAccessInfo &IAI);
public:
VPInterleavedAccessInfo(VPlan &Plan, InterleavedAccessInfo &IAI);
~VPInterleavedAccessInfo() {
SmallPtrSet<InterleaveGroup<VPInstruction> *, 4> DelSet;
// Avoid releasing a pointer twice.
for (auto &I : InterleaveGroupMap)
DelSet.insert(I.second);
for (auto *Ptr : DelSet)
delete Ptr;
}
/// Get the interleave group that \p Instr belongs to.
///
/// \returns nullptr if doesn't have such group.
InterleaveGroup<VPInstruction> *
getInterleaveGroup(VPInstruction *Instr) const {
return InterleaveGroupMap.lookup(Instr);
}
};
/// Class that maps (parts of) an existing VPlan to trees of combined
/// VPInstructions.
class VPlanSlp {
enum class OpMode { Failed, Load, Opcode };
/// A DenseMapInfo implementation for using SmallVector<VPValue *, 4> as
/// DenseMap keys.
struct BundleDenseMapInfo {
static SmallVector<VPValue *, 4> getEmptyKey() {
return {reinterpret_cast<VPValue *>(-1)};
}
static SmallVector<VPValue *, 4> getTombstoneKey() {
return {reinterpret_cast<VPValue *>(-2)};
}
static unsigned getHashValue(const SmallVector<VPValue *, 4> &V) {
return static_cast<unsigned>(hash_combine_range(V.begin(), V.end()));
}
static bool isEqual(const SmallVector<VPValue *, 4> &LHS,
const SmallVector<VPValue *, 4> &RHS) {
return LHS == RHS;
}
};
/// Mapping of values in the original VPlan to a combined VPInstruction.
DenseMap<SmallVector<VPValue *, 4>, VPInstruction *, BundleDenseMapInfo>
BundleToCombined;
VPInterleavedAccessInfo &IAI;
/// Basic block to operate on. For now, only instructions in a single BB are
/// considered.
const VPBasicBlock &BB;
/// Indicates whether we managed to combine all visited instructions or not.
bool CompletelySLP = true;
/// Width of the widest combined bundle in bits.
unsigned WidestBundleBits = 0;
using MultiNodeOpTy =
typename std::pair<VPInstruction *, SmallVector<VPValue *, 4>>;
// Input operand bundles for the current multi node. Each multi node operand
// bundle contains values not matching the multi node's opcode. They will
// be reordered in reorderMultiNodeOps, once we completed building a
// multi node.
SmallVector<MultiNodeOpTy, 4> MultiNodeOps;
/// Indicates whether we are building a multi node currently.
bool MultiNodeActive = false;
/// Check if we can vectorize Operands together.
bool areVectorizable(ArrayRef<VPValue *> Operands) const;
/// Add combined instruction \p New for the bundle \p Operands.
void addCombined(ArrayRef<VPValue *> Operands, VPInstruction *New);
/// Indicate we hit a bundle we failed to combine. Returns nullptr for now.
VPInstruction *markFailed();
/// Reorder operands in the multi node to maximize sequential memory access
/// and commutative operations.
SmallVector<MultiNodeOpTy, 4> reorderMultiNodeOps();
/// Choose the best candidate to use for the lane after \p Last. The set of
/// candidates to choose from are values with an opcode matching \p Last's
/// or loads consecutive to \p Last.
std::pair<OpMode, VPValue *> getBest(OpMode Mode, VPValue *Last,
SmallPtrSetImpl<VPValue *> &Candidates,
VPInterleavedAccessInfo &IAI);
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// Print bundle \p Values to dbgs().
void dumpBundle(ArrayRef<VPValue *> Values);
#endif
public:
VPlanSlp(VPInterleavedAccessInfo &IAI, VPBasicBlock &BB) : IAI(IAI), BB(BB) {}
~VPlanSlp() = default;
/// Tries to build an SLP tree rooted at \p Operands and returns a
/// VPInstruction combining \p Operands, if they can be combined.
VPInstruction *buildGraph(ArrayRef<VPValue *> Operands);
/// Return the width of the widest combined bundle in bits.
unsigned getWidestBundleBits() const { return WidestBundleBits; }
/// Return true if all visited instruction can be combined.
bool isCompletelySLP() const { return CompletelySLP; }
};
namespace vputils {
/// Returns true if only the first lane of \p Def is used.
bool onlyFirstLaneUsed(VPValue *Def);
/// Get or create a VPValue that corresponds to the expansion of \p Expr. If \p
/// Expr is a SCEVConstant or SCEVUnknown, return a VPValue wrapping the live-in
/// value. Otherwise return a VPExpandSCEVRecipe to expand \p Expr. If \p Plan's
/// pre-header already contains a recipe expanding \p Expr, return it. If not,
/// create a new one.
VPValue *getOrCreateVPValueForSCEVExpr(VPlan &Plan, const SCEV *Expr,
ScalarEvolution &SE);
} // end namespace vputils
} // end namespace llvm
#endif // LLVM_TRANSFORMS_VECTORIZE_VPLAN_H
diff --git a/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index cb7507264667..9a404640b4b8 100644
--- a/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -1,1237 +1,1235 @@
//===- VPlanRecipes.cpp - Implementations for VPlan recipes ---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains implementations for different VPlan recipes.
///
//===----------------------------------------------------------------------===//
#include "VPlan.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Analysis/IVDescriptors.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h"
#include <cassert>
using namespace llvm;
using VectorParts = SmallVector<Value *, 2>;
extern cl::opt<bool> EnableVPlanNativePath;
#define LV_NAME "loop-vectorize"
#define DEBUG_TYPE LV_NAME
bool VPRecipeBase::mayWriteToMemory() const {
switch (getVPDefID()) {
case VPWidenMemoryInstructionSC: {
return cast<VPWidenMemoryInstructionRecipe>(this)->isStore();
}
case VPReplicateSC:
case VPWidenCallSC:
return cast<Instruction>(getVPSingleValue()->getUnderlyingValue())
->mayWriteToMemory();
case VPBranchOnMaskSC:
return false;
case VPWidenIntOrFpInductionSC:
case VPWidenCanonicalIVSC:
case VPWidenPHISC:
case VPBlendSC:
case VPWidenSC:
case VPWidenGEPSC:
case VPReductionSC:
case VPWidenSelectSC: {
const Instruction *I =
dyn_cast_or_null<Instruction>(getVPSingleValue()->getUnderlyingValue());
(void)I;
assert((!I || !I->mayWriteToMemory()) &&
"underlying instruction may write to memory");
return false;
}
default:
return true;
}
}
bool VPRecipeBase::mayReadFromMemory() const {
switch (getVPDefID()) {
case VPWidenMemoryInstructionSC: {
return !cast<VPWidenMemoryInstructionRecipe>(this)->isStore();
}
case VPReplicateSC:
case VPWidenCallSC:
return cast<Instruction>(getVPSingleValue()->getUnderlyingValue())
->mayReadFromMemory();
case VPBranchOnMaskSC:
return false;
case VPWidenIntOrFpInductionSC:
case VPWidenCanonicalIVSC:
case VPWidenPHISC:
case VPBlendSC:
case VPWidenSC:
case VPWidenGEPSC:
case VPReductionSC:
case VPWidenSelectSC: {
const Instruction *I =
dyn_cast_or_null<Instruction>(getVPSingleValue()->getUnderlyingValue());
(void)I;
assert((!I || !I->mayReadFromMemory()) &&
"underlying instruction may read from memory");
return false;
}
default:
return true;
}
}
bool VPRecipeBase::mayHaveSideEffects() const {
switch (getVPDefID()) {
case VPWidenIntOrFpInductionSC:
case VPWidenPointerInductionSC:
case VPWidenCanonicalIVSC:
case VPWidenPHISC:
case VPBlendSC:
case VPWidenSC:
case VPWidenGEPSC:
case VPReductionSC:
case VPWidenSelectSC:
case VPScalarIVStepsSC: {
const Instruction *I =
dyn_cast_or_null<Instruction>(getVPSingleValue()->getUnderlyingValue());
(void)I;
assert((!I || !I->mayHaveSideEffects()) &&
"underlying instruction has side-effects");
return false;
}
case VPReplicateSC: {
auto *R = cast<VPReplicateRecipe>(this);
return R->getUnderlyingInstr()->mayHaveSideEffects();
}
default:
return true;
}
}
void VPLiveOut::fixPhi(VPlan &Plan, VPTransformState &State) {
auto Lane = VPLane::getLastLaneForVF(State.VF);
VPValue *ExitValue = getOperand(0);
if (Plan.isUniformAfterVectorization(ExitValue))
Lane = VPLane::getFirstLane();
Phi->addIncoming(State.get(ExitValue, VPIteration(State.UF - 1, Lane)),
State.Builder.GetInsertBlock());
}
void VPRecipeBase::insertBefore(VPRecipeBase *InsertPos) {
assert(!Parent && "Recipe already in some VPBasicBlock");
assert(InsertPos->getParent() &&
"Insertion position not in any VPBasicBlock");
Parent = InsertPos->getParent();
Parent->getRecipeList().insert(InsertPos->getIterator(), this);
}
void VPRecipeBase::insertBefore(VPBasicBlock &BB,
iplist<VPRecipeBase>::iterator I) {
assert(!Parent && "Recipe already in some VPBasicBlock");
assert(I == BB.end() || I->getParent() == &BB);
Parent = &BB;
BB.getRecipeList().insert(I, this);
}
void VPRecipeBase::insertAfter(VPRecipeBase *InsertPos) {
assert(!Parent && "Recipe already in some VPBasicBlock");
assert(InsertPos->getParent() &&
"Insertion position not in any VPBasicBlock");
Parent = InsertPos->getParent();
Parent->getRecipeList().insertAfter(InsertPos->getIterator(), this);
}
void VPRecipeBase::removeFromParent() {
assert(getParent() && "Recipe not in any VPBasicBlock");
getParent()->getRecipeList().remove(getIterator());
Parent = nullptr;
}
iplist<VPRecipeBase>::iterator VPRecipeBase::eraseFromParent() {
assert(getParent() && "Recipe not in any VPBasicBlock");
return getParent()->getRecipeList().erase(getIterator());
}
void VPRecipeBase::moveAfter(VPRecipeBase *InsertPos) {
removeFromParent();
insertAfter(InsertPos);
}
void VPRecipeBase::moveBefore(VPBasicBlock &BB,
iplist<VPRecipeBase>::iterator I) {
removeFromParent();
insertBefore(BB, I);
}
void VPInstruction::generateInstruction(VPTransformState &State,
unsigned Part) {
IRBuilderBase &Builder = State.Builder;
Builder.SetCurrentDebugLocation(DL);
if (Instruction::isBinaryOp(getOpcode())) {
Value *A = State.get(getOperand(0), Part);
Value *B = State.get(getOperand(1), Part);
Value *V =
Builder.CreateBinOp((Instruction::BinaryOps)getOpcode(), A, B, Name);
State.set(this, V, Part);
return;
}
switch (getOpcode()) {
case VPInstruction::Not: {
Value *A = State.get(getOperand(0), Part);
Value *V = Builder.CreateNot(A, Name);
State.set(this, V, Part);
break;
}
case VPInstruction::ICmpULE: {
Value *IV = State.get(getOperand(0), Part);
Value *TC = State.get(getOperand(1), Part);
Value *V = Builder.CreateICmpULE(IV, TC, Name);
State.set(this, V, Part);
break;
}
case Instruction::Select: {
Value *Cond = State.get(getOperand(0), Part);
Value *Op1 = State.get(getOperand(1), Part);
Value *Op2 = State.get(getOperand(2), Part);
Value *V = Builder.CreateSelect(Cond, Op1, Op2, Name);
State.set(this, V, Part);
break;
}
case VPInstruction::ActiveLaneMask: {
// Get first lane of vector induction variable.
Value *VIVElem0 = State.get(getOperand(0), VPIteration(Part, 0));
// Get the original loop tripcount.
Value *ScalarTC = State.get(getOperand(1), Part);
auto *Int1Ty = Type::getInt1Ty(Builder.getContext());
auto *PredTy = VectorType::get(Int1Ty, State.VF);
Instruction *Call = Builder.CreateIntrinsic(
Intrinsic::get_active_lane_mask, {PredTy, ScalarTC->getType()},
{VIVElem0, ScalarTC}, nullptr, Name);
State.set(this, Call, Part);
break;
}
case VPInstruction::FirstOrderRecurrenceSplice: {
// Generate code to combine the previous and current values in vector v3.
//
// vector.ph:
// v_init = vector(..., ..., ..., a[-1])
// br vector.body
//
// vector.body
// i = phi [0, vector.ph], [i+4, vector.body]
// v1 = phi [v_init, vector.ph], [v2, vector.body]
// v2 = a[i, i+1, i+2, i+3];
// v3 = vector(v1(3), v2(0, 1, 2))
// For the first part, use the recurrence phi (v1), otherwise v2.
auto *V1 = State.get(getOperand(0), 0);
Value *PartMinus1 = Part == 0 ? V1 : State.get(getOperand(1), Part - 1);
if (!PartMinus1->getType()->isVectorTy()) {
State.set(this, PartMinus1, Part);
} else {
Value *V2 = State.get(getOperand(1), Part);
State.set(this, Builder.CreateVectorSplice(PartMinus1, V2, -1, Name),
Part);
}
break;
}
case VPInstruction::CanonicalIVIncrement:
case VPInstruction::CanonicalIVIncrementNUW: {
Value *Next = nullptr;
if (Part == 0) {
bool IsNUW = getOpcode() == VPInstruction::CanonicalIVIncrementNUW;
auto *Phi = State.get(getOperand(0), 0);
// The loop step is equal to the vectorization factor (num of SIMD
// elements) times the unroll factor (num of SIMD instructions).
Value *Step =
createStepForVF(Builder, Phi->getType(), State.VF, State.UF);
Next = Builder.CreateAdd(Phi, Step, Name, IsNUW, false);
} else {
Next = State.get(this, 0);
}
State.set(this, Next, Part);
break;
}
case VPInstruction::CanonicalIVIncrementForPart:
case VPInstruction::CanonicalIVIncrementForPartNUW: {
bool IsNUW = getOpcode() == VPInstruction::CanonicalIVIncrementForPartNUW;
auto *IV = State.get(getOperand(0), VPIteration(0, 0));
if (Part == 0) {
State.set(this, IV, Part);
break;
}
// The canonical IV is incremented by the vectorization factor (num of SIMD
// elements) times the unroll part.
Value *Step = createStepForVF(Builder, IV->getType(), State.VF, Part);
Value *Next = Builder.CreateAdd(IV, Step, Name, IsNUW, false);
State.set(this, Next, Part);
break;
}
case VPInstruction::BranchOnCond: {
if (Part != 0)
break;
Value *Cond = State.get(getOperand(0), VPIteration(Part, 0));
VPRegionBlock *ParentRegion = getParent()->getParent();
VPBasicBlock *Header = ParentRegion->getEntryBasicBlock();
// Replace the temporary unreachable terminator with a new conditional
// branch, hooking it up to backward destination for exiting blocks now and
// to forward destination(s) later when they are created.
BranchInst *CondBr =
Builder.CreateCondBr(Cond, Builder.GetInsertBlock(), nullptr);
if (getParent()->isExiting())
CondBr->setSuccessor(1, State.CFG.VPBB2IRBB[Header]);
CondBr->setSuccessor(0, nullptr);
Builder.GetInsertBlock()->getTerminator()->eraseFromParent();
break;
}
case VPInstruction::BranchOnCount: {
if (Part != 0)
break;
// First create the compare.
Value *IV = State.get(getOperand(0), Part);
Value *TC = State.get(getOperand(1), Part);
Value *Cond = Builder.CreateICmpEQ(IV, TC);
// Now create the branch.
auto *Plan = getParent()->getPlan();
VPRegionBlock *TopRegion = Plan->getVectorLoopRegion();
VPBasicBlock *Header = TopRegion->getEntry()->getEntryBasicBlock();
// Replace the temporary unreachable terminator with a new conditional
// branch, hooking it up to backward destination (the header) now and to the
// forward destination (the exit/middle block) later when it is created.
// Note that CreateCondBr expects a valid BB as first argument, so we need
// to set it to nullptr later.
BranchInst *CondBr = Builder.CreateCondBr(Cond, Builder.GetInsertBlock(),
State.CFG.VPBB2IRBB[Header]);
CondBr->setSuccessor(0, nullptr);
Builder.GetInsertBlock()->getTerminator()->eraseFromParent();
break;
}
default:
llvm_unreachable("Unsupported opcode for instruction");
}
}
void VPInstruction::execute(VPTransformState &State) {
assert(!State.Instance && "VPInstruction executing an Instance");
IRBuilderBase::FastMathFlagGuard FMFGuard(State.Builder);
State.Builder.setFastMathFlags(FMF);
for (unsigned Part = 0; Part < State.UF; ++Part)
generateInstruction(State, Part);
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPInstruction::dump() const {
VPSlotTracker SlotTracker(getParent()->getPlan());
print(dbgs(), "", SlotTracker);
}
void VPInstruction::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "EMIT ";
if (hasResult()) {
printAsOperand(O, SlotTracker);
O << " = ";
}
switch (getOpcode()) {
case VPInstruction::Not:
O << "not";
break;
case VPInstruction::ICmpULE:
O << "icmp ule";
break;
case VPInstruction::SLPLoad:
O << "combined load";
break;
case VPInstruction::SLPStore:
O << "combined store";
break;
case VPInstruction::ActiveLaneMask:
O << "active lane mask";
break;
case VPInstruction::FirstOrderRecurrenceSplice:
O << "first-order splice";
break;
case VPInstruction::CanonicalIVIncrement:
O << "VF * UF + ";
break;
case VPInstruction::CanonicalIVIncrementNUW:
O << "VF * UF +(nuw) ";
break;
case VPInstruction::BranchOnCond:
O << "branch-on-cond";
break;
case VPInstruction::CanonicalIVIncrementForPart:
O << "VF * Part + ";
break;
case VPInstruction::CanonicalIVIncrementForPartNUW:
O << "VF * Part +(nuw) ";
break;
case VPInstruction::BranchOnCount:
O << "branch-on-count ";
break;
default:
O << Instruction::getOpcodeName(getOpcode());
}
O << FMF;
for (const VPValue *Operand : operands()) {
O << " ";
Operand->printAsOperand(O, SlotTracker);
}
if (DL) {
O << ", !dbg ";
DL.print(O);
}
}
#endif
void VPInstruction::setFastMathFlags(FastMathFlags FMFNew) {
// Make sure the VPInstruction is a floating-point operation.
assert((Opcode == Instruction::FAdd || Opcode == Instruction::FMul ||
Opcode == Instruction::FNeg || Opcode == Instruction::FSub ||
Opcode == Instruction::FDiv || Opcode == Instruction::FRem ||
Opcode == Instruction::FCmp) &&
"this op can't take fast-math flags");
FMF = FMFNew;
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPWidenCallRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "WIDEN-CALL ";
auto *CI = cast<CallInst>(getUnderlyingInstr());
if (CI->getType()->isVoidTy())
O << "void ";
else {
printAsOperand(O, SlotTracker);
O << " = ";
}
O << "call @" << CI->getCalledFunction()->getName() << "(";
printOperands(O, SlotTracker);
O << ")";
}
void VPWidenSelectRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "WIDEN-SELECT ";
printAsOperand(O, SlotTracker);
O << " = select ";
getOperand(0)->printAsOperand(O, SlotTracker);
O << ", ";
getOperand(1)->printAsOperand(O, SlotTracker);
O << ", ";
getOperand(2)->printAsOperand(O, SlotTracker);
O << (InvariantCond ? " (condition is loop invariant)" : "");
}
#endif
void VPWidenSelectRecipe::execute(VPTransformState &State) {
auto &I = *cast<SelectInst>(getUnderlyingInstr());
State.setDebugLocFromInst(&I);
// The condition can be loop invariant but still defined inside the
// loop. This means that we can't just use the original 'cond' value.
// We have to take the 'vectorized' value and pick the first lane.
// Instcombine will make this a no-op.
auto *InvarCond =
InvariantCond ? State.get(getOperand(0), VPIteration(0, 0)) : nullptr;
for (unsigned Part = 0; Part < State.UF; ++Part) {
Value *Cond = InvarCond ? InvarCond : State.get(getOperand(0), Part);
Value *Op0 = State.get(getOperand(1), Part);
Value *Op1 = State.get(getOperand(2), Part);
Value *Sel = State.Builder.CreateSelect(Cond, Op0, Op1);
State.set(this, Sel, Part);
State.addMetadata(Sel, &I);
}
}
void VPWidenRecipe::execute(VPTransformState &State) {
auto &I = *cast<Instruction>(getUnderlyingValue());
auto &Builder = State.Builder;
switch (I.getOpcode()) {
case Instruction::Call:
case Instruction::Br:
case Instruction::PHI:
case Instruction::GetElementPtr:
case Instruction::Select:
llvm_unreachable("This instruction is handled by a different recipe.");
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::SRem:
case Instruction::URem:
case Instruction::Add:
case Instruction::FAdd:
case Instruction::Sub:
case Instruction::FSub:
case Instruction::FNeg:
case Instruction::Mul:
case Instruction::FMul:
case Instruction::FDiv:
case Instruction::FRem:
case Instruction::Shl:
case Instruction::LShr:
case Instruction::AShr:
case Instruction::And:
case Instruction::Or:
case Instruction::Xor: {
// Just widen unops and binops.
State.setDebugLocFromInst(&I);
for (unsigned Part = 0; Part < State.UF; ++Part) {
SmallVector<Value *, 2> Ops;
for (VPValue *VPOp : operands())
Ops.push_back(State.get(VPOp, Part));
Value *V = Builder.CreateNAryOp(I.getOpcode(), Ops);
if (auto *VecOp = dyn_cast<Instruction>(V)) {
VecOp->copyIRFlags(&I);
// If the instruction is vectorized and was in a basic block that needed
// predication, we can't propagate poison-generating flags (nuw/nsw,
// exact, etc.). The control flow has been linearized and the
// instruction is no longer guarded by the predicate, which could make
// the flag properties to no longer hold.
if (State.MayGeneratePoisonRecipes.contains(this))
VecOp->dropPoisonGeneratingFlags();
}
// Use this vector value for all users of the original instruction.
State.set(this, V, Part);
State.addMetadata(V, &I);
}
break;
}
case Instruction::Freeze: {
State.setDebugLocFromInst(&I);
for (unsigned Part = 0; Part < State.UF; ++Part) {
Value *Op = State.get(getOperand(0), Part);
Value *Freeze = Builder.CreateFreeze(Op);
State.set(this, Freeze, Part);
}
break;
}
case Instruction::ICmp:
case Instruction::FCmp: {
// Widen compares. Generate vector compares.
bool FCmp = (I.getOpcode() == Instruction::FCmp);
auto *Cmp = cast<CmpInst>(&I);
State.setDebugLocFromInst(Cmp);
for (unsigned Part = 0; Part < State.UF; ++Part) {
Value *A = State.get(getOperand(0), Part);
Value *B = State.get(getOperand(1), Part);
Value *C = nullptr;
if (FCmp) {
// Propagate fast math flags.
IRBuilder<>::FastMathFlagGuard FMFG(Builder);
Builder.setFastMathFlags(Cmp->getFastMathFlags());
C = Builder.CreateFCmp(Cmp->getPredicate(), A, B);
} else {
C = Builder.CreateICmp(Cmp->getPredicate(), A, B);
}
State.set(this, C, Part);
State.addMetadata(C, &I);
}
break;
}
case Instruction::ZExt:
case Instruction::SExt:
case Instruction::FPToUI:
case Instruction::FPToSI:
case Instruction::FPExt:
case Instruction::PtrToInt:
case Instruction::IntToPtr:
case Instruction::SIToFP:
case Instruction::UIToFP:
case Instruction::Trunc:
case Instruction::FPTrunc:
case Instruction::BitCast: {
auto *CI = cast<CastInst>(&I);
State.setDebugLocFromInst(CI);
/// Vectorize casts.
Type *DestTy = (State.VF.isScalar())
? CI->getType()
: VectorType::get(CI->getType(), State.VF);
for (unsigned Part = 0; Part < State.UF; ++Part) {
Value *A = State.get(getOperand(0), Part);
Value *Cast = Builder.CreateCast(CI->getOpcode(), A, DestTy);
State.set(this, Cast, Part);
State.addMetadata(Cast, &I);
}
break;
}
default:
// This instruction is not vectorized by simple widening.
LLVM_DEBUG(dbgs() << "LV: Found an unhandled instruction: " << I);
llvm_unreachable("Unhandled instruction!");
} // end of switch.
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPWidenRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "WIDEN ";
printAsOperand(O, SlotTracker);
O << " = " << getUnderlyingInstr()->getOpcodeName() << " ";
printOperands(O, SlotTracker);
}
void VPWidenIntOrFpInductionRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "WIDEN-INDUCTION";
if (getTruncInst()) {
O << "\\l\"";
O << " +\n" << Indent << "\" " << VPlanIngredient(IV) << "\\l\"";
O << " +\n" << Indent << "\" ";
getVPValue(0)->printAsOperand(O, SlotTracker);
} else
O << " " << VPlanIngredient(IV);
O << ", ";
getStepValue()->printAsOperand(O, SlotTracker);
}
#endif
bool VPWidenIntOrFpInductionRecipe::isCanonical() const {
auto *StartC = dyn_cast<ConstantInt>(getStartValue()->getLiveInIRValue());
auto *StepC = dyn_cast<SCEVConstant>(getInductionDescriptor().getStep());
return StartC && StartC->isZero() && StepC && StepC->isOne();
}
VPCanonicalIVPHIRecipe *VPScalarIVStepsRecipe::getCanonicalIV() const {
return cast<VPCanonicalIVPHIRecipe>(getOperand(0));
}
bool VPScalarIVStepsRecipe::isCanonical() const {
auto *CanIV = getCanonicalIV();
// The start value of the steps-recipe must match the start value of the
// canonical induction and it must step by 1.
if (CanIV->getStartValue() != getStartValue())
return false;
auto *StepVPV = getStepValue();
if (StepVPV->getDef())
return false;
auto *StepC = dyn_cast_or_null<ConstantInt>(StepVPV->getLiveInIRValue());
return StepC && StepC->isOne();
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPScalarIVStepsRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent;
printAsOperand(O, SlotTracker);
O << Indent << "= SCALAR-STEPS ";
printOperands(O, SlotTracker);
}
#endif
void VPWidenGEPRecipe::execute(VPTransformState &State) {
auto *GEP = cast<GetElementPtrInst>(getUnderlyingInstr());
// Construct a vector GEP by widening the operands of the scalar GEP as
// necessary. We mark the vector GEP 'inbounds' if appropriate. A GEP
// results in a vector of pointers when at least one operand of the GEP
// is vector-typed. Thus, to keep the representation compact, we only use
// vector-typed operands for loop-varying values.
if (State.VF.isVector() && IsPtrLoopInvariant && IsIndexLoopInvariant.all()) {
// If we are vectorizing, but the GEP has only loop-invariant operands,
// the GEP we build (by only using vector-typed operands for
// loop-varying values) would be a scalar pointer. Thus, to ensure we
// produce a vector of pointers, we need to either arbitrarily pick an
// operand to broadcast, or broadcast a clone of the original GEP.
// Here, we broadcast a clone of the original.
//
// TODO: If at some point we decide to scalarize instructions having
// loop-invariant operands, this special case will no longer be
// required. We would add the scalarization decision to
// collectLoopScalars() and teach getVectorValue() to broadcast
// the lane-zero scalar value.
auto *Clone = State.Builder.Insert(GEP->clone());
for (unsigned Part = 0; Part < State.UF; ++Part) {
Value *EntryPart = State.Builder.CreateVectorSplat(State.VF, Clone);
State.set(this, EntryPart, Part);
State.addMetadata(EntryPart, GEP);
}
} else {
// If the GEP has at least one loop-varying operand, we are sure to
// produce a vector of pointers. But if we are only unrolling, we want
// to produce a scalar GEP for each unroll part. Thus, the GEP we
// produce with the code below will be scalar (if VF == 1) or vector
// (otherwise). Note that for the unroll-only case, we still maintain
// values in the vector mapping with initVector, as we do for other
// instructions.
for (unsigned Part = 0; Part < State.UF; ++Part) {
// The pointer operand of the new GEP. If it's loop-invariant, we
// won't broadcast it.
auto *Ptr = IsPtrLoopInvariant
? State.get(getOperand(0), VPIteration(0, 0))
: State.get(getOperand(0), Part);
// Collect all the indices for the new GEP. If any index is
// loop-invariant, we won't broadcast it.
SmallVector<Value *, 4> Indices;
for (unsigned I = 1, E = getNumOperands(); I < E; I++) {
VPValue *Operand = getOperand(I);
if (IsIndexLoopInvariant[I - 1])
Indices.push_back(State.get(Operand, VPIteration(0, 0)));
else
Indices.push_back(State.get(Operand, Part));
}
// If the GEP instruction is vectorized and was in a basic block that
// needed predication, we can't propagate the poison-generating 'inbounds'
// flag. The control flow has been linearized and the GEP is no longer
// guarded by the predicate, which could make the 'inbounds' properties to
// no longer hold.
bool IsInBounds =
GEP->isInBounds() && State.MayGeneratePoisonRecipes.count(this) == 0;
// Create the new GEP. Note that this GEP may be a scalar if VF == 1,
// but it should be a vector, otherwise.
auto *NewGEP = State.Builder.CreateGEP(GEP->getSourceElementType(), Ptr,
Indices, "", IsInBounds);
assert((State.VF.isScalar() || NewGEP->getType()->isVectorTy()) &&
"NewGEP is not a pointer vector");
State.set(this, NewGEP, Part);
State.addMetadata(NewGEP, GEP);
}
}
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPWidenGEPRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "WIDEN-GEP ";
O << (IsPtrLoopInvariant ? "Inv" : "Var");
size_t IndicesNumber = IsIndexLoopInvariant.size();
for (size_t I = 0; I < IndicesNumber; ++I)
O << "[" << (IsIndexLoopInvariant[I] ? "Inv" : "Var") << "]";
O << " ";
printAsOperand(O, SlotTracker);
O << " = getelementptr ";
printOperands(O, SlotTracker);
}
#endif
void VPBlendRecipe::execute(VPTransformState &State) {
State.setDebugLocFromInst(Phi);
// We know that all PHIs in non-header blocks are converted into
// selects, so we don't have to worry about the insertion order and we
// can just use the builder.
// At this point we generate the predication tree. There may be
// duplications since this is a simple recursive scan, but future
// optimizations will clean it up.
unsigned NumIncoming = getNumIncomingValues();
// Generate a sequence of selects of the form:
// SELECT(Mask3, In3,
// SELECT(Mask2, In2,
// SELECT(Mask1, In1,
// In0)))
// Note that Mask0 is never used: lanes for which no path reaches this phi and
// are essentially undef are taken from In0.
VectorParts Entry(State.UF);
for (unsigned In = 0; In < NumIncoming; ++In) {
for (unsigned Part = 0; Part < State.UF; ++Part) {
// We might have single edge PHIs (blocks) - use an identity
// 'select' for the first PHI operand.
Value *In0 = State.get(getIncomingValue(In), Part);
if (In == 0)
Entry[Part] = In0; // Initialize with the first incoming value.
else {
// Select between the current value and the previous incoming edge
// based on the incoming mask.
Value *Cond = State.get(getMask(In), Part);
Entry[Part] =
State.Builder.CreateSelect(Cond, In0, Entry[Part], "predphi");
}
}
}
for (unsigned Part = 0; Part < State.UF; ++Part)
State.set(this, Entry[Part], Part);
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPBlendRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "BLEND ";
Phi->printAsOperand(O, false);
O << " =";
if (getNumIncomingValues() == 1) {
// Not a User of any mask: not really blending, this is a
// single-predecessor phi.
O << " ";
getIncomingValue(0)->printAsOperand(O, SlotTracker);
} else {
for (unsigned I = 0, E = getNumIncomingValues(); I < E; ++I) {
O << " ";
getIncomingValue(I)->printAsOperand(O, SlotTracker);
O << "/";
getMask(I)->printAsOperand(O, SlotTracker);
}
}
}
void VPReductionRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "REDUCE ";
printAsOperand(O, SlotTracker);
O << " = ";
getChainOp()->printAsOperand(O, SlotTracker);
O << " +";
if (isa<FPMathOperator>(getUnderlyingInstr()))
O << getUnderlyingInstr()->getFastMathFlags();
O << " reduce." << Instruction::getOpcodeName(RdxDesc->getOpcode()) << " (";
getVecOp()->printAsOperand(O, SlotTracker);
if (getCondOp()) {
O << ", ";
getCondOp()->printAsOperand(O, SlotTracker);
}
O << ")";
if (RdxDesc->IntermediateStore)
O << " (with final reduction value stored in invariant address sank "
"outside of loop)";
}
void VPReplicateRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << (IsUniform ? "CLONE " : "REPLICATE ");
if (!getUnderlyingInstr()->getType()->isVoidTy()) {
printAsOperand(O, SlotTracker);
O << " = ";
}
if (auto *CB = dyn_cast<CallBase>(getUnderlyingInstr())) {
O << "call @" << CB->getCalledFunction()->getName() << "(";
interleaveComma(make_range(op_begin(), op_begin() + (getNumOperands() - 1)),
O, [&O, &SlotTracker](VPValue *Op) {
Op->printAsOperand(O, SlotTracker);
});
O << ")";
} else {
O << Instruction::getOpcodeName(getUnderlyingInstr()->getOpcode()) << " ";
printOperands(O, SlotTracker);
}
if (AlsoPack)
O << " (S->V)";
}
#endif
void VPBranchOnMaskRecipe::execute(VPTransformState &State) {
assert(State.Instance && "Branch on Mask works only on single instance.");
unsigned Part = State.Instance->Part;
unsigned Lane = State.Instance->Lane.getKnownLane();
Value *ConditionBit = nullptr;
VPValue *BlockInMask = getMask();
if (BlockInMask) {
ConditionBit = State.get(BlockInMask, Part);
if (ConditionBit->getType()->isVectorTy())
ConditionBit = State.Builder.CreateExtractElement(
ConditionBit, State.Builder.getInt32(Lane));
} else // Block in mask is all-one.
ConditionBit = State.Builder.getTrue();
// Replace the temporary unreachable terminator with a new conditional branch,
// whose two destinations will be set later when they are created.
auto *CurrentTerminator = State.CFG.PrevBB->getTerminator();
assert(isa<UnreachableInst>(CurrentTerminator) &&
"Expected to replace unreachable terminator with conditional branch.");
auto *CondBr = BranchInst::Create(State.CFG.PrevBB, nullptr, ConditionBit);
CondBr->setSuccessor(0, nullptr);
ReplaceInstWithInst(CurrentTerminator, CondBr);
}
void VPPredInstPHIRecipe::execute(VPTransformState &State) {
assert(State.Instance && "Predicated instruction PHI works per instance.");
Instruction *ScalarPredInst =
cast<Instruction>(State.get(getOperand(0), *State.Instance));
BasicBlock *PredicatedBB = ScalarPredInst->getParent();
BasicBlock *PredicatingBB = PredicatedBB->getSinglePredecessor();
assert(PredicatingBB && "Predicated block has no single predecessor.");
assert(isa<VPReplicateRecipe>(getOperand(0)) &&
"operand must be VPReplicateRecipe");
// By current pack/unpack logic we need to generate only a single phi node: if
// a vector value for the predicated instruction exists at this point it means
// the instruction has vector users only, and a phi for the vector value is
// needed. In this case the recipe of the predicated instruction is marked to
// also do that packing, thereby "hoisting" the insert-element sequence.
// Otherwise, a phi node for the scalar value is needed.
unsigned Part = State.Instance->Part;
if (State.hasVectorValue(getOperand(0), Part)) {
Value *VectorValue = State.get(getOperand(0), Part);
InsertElementInst *IEI = cast<InsertElementInst>(VectorValue);
PHINode *VPhi = State.Builder.CreatePHI(IEI->getType(), 2);
VPhi->addIncoming(IEI->getOperand(0), PredicatingBB); // Unmodified vector.
VPhi->addIncoming(IEI, PredicatedBB); // New vector with inserted element.
if (State.hasVectorValue(this, Part))
State.reset(this, VPhi, Part);
else
State.set(this, VPhi, Part);
// NOTE: Currently we need to update the value of the operand, so the next
// predicated iteration inserts its generated value in the correct vector.
State.reset(getOperand(0), VPhi, Part);
} else {
Type *PredInstType = getOperand(0)->getUnderlyingValue()->getType();
PHINode *Phi = State.Builder.CreatePHI(PredInstType, 2);
Phi->addIncoming(PoisonValue::get(ScalarPredInst->getType()),
PredicatingBB);
Phi->addIncoming(ScalarPredInst, PredicatedBB);
if (State.hasScalarValue(this, *State.Instance))
State.reset(this, Phi, *State.Instance);
else
State.set(this, Phi, *State.Instance);
// NOTE: Currently we need to update the value of the operand, so the next
// predicated iteration inserts its generated value in the correct vector.
State.reset(getOperand(0), Phi, *State.Instance);
}
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPPredInstPHIRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "PHI-PREDICATED-INSTRUCTION ";
printAsOperand(O, SlotTracker);
O << " = ";
printOperands(O, SlotTracker);
}
void VPWidenMemoryInstructionRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "WIDEN ";
if (!isStore()) {
getVPSingleValue()->printAsOperand(O, SlotTracker);
O << " = ";
}
O << Instruction::getOpcodeName(Ingredient.getOpcode()) << " ";
printOperands(O, SlotTracker);
}
#endif
void VPCanonicalIVPHIRecipe::execute(VPTransformState &State) {
Value *Start = getStartValue()->getLiveInIRValue();
PHINode *EntryPart = PHINode::Create(
Start->getType(), 2, "index", &*State.CFG.PrevBB->getFirstInsertionPt());
BasicBlock *VectorPH = State.CFG.getPreheaderBBFor(this);
EntryPart->addIncoming(Start, VectorPH);
EntryPart->setDebugLoc(DL);
for (unsigned Part = 0, UF = State.UF; Part < UF; ++Part)
State.set(this, EntryPart, Part);
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPCanonicalIVPHIRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "EMIT ";
printAsOperand(O, SlotTracker);
O << " = CANONICAL-INDUCTION";
}
#endif
bool VPWidenPointerInductionRecipe::onlyScalarsGenerated(ElementCount VF) {
- bool IsUniform = vputils::onlyFirstLaneUsed(this);
- return all_of(users(),
- [&](const VPUser *U) { return U->usesScalars(this); }) &&
- (IsUniform || !VF.isScalable());
+ return IsScalarAfterVectorization &&
+ (!VF.isScalable() || vputils::onlyFirstLaneUsed(this));
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPWidenPointerInductionRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "EMIT ";
printAsOperand(O, SlotTracker);
O << " = WIDEN-POINTER-INDUCTION ";
getStartValue()->printAsOperand(O, SlotTracker);
O << ", " << *IndDesc.getStep();
}
#endif
void VPExpandSCEVRecipe::execute(VPTransformState &State) {
assert(!State.Instance && "cannot be used in per-lane");
const DataLayout &DL = State.CFG.PrevBB->getModule()->getDataLayout();
SCEVExpander Exp(SE, DL, "induction");
Value *Res = Exp.expandCodeFor(Expr, Expr->getType(),
&*State.Builder.GetInsertPoint());
for (unsigned Part = 0, UF = State.UF; Part < UF; ++Part)
State.set(this, Res, Part);
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPExpandSCEVRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "EMIT ";
getVPSingleValue()->printAsOperand(O, SlotTracker);
O << " = EXPAND SCEV " << *Expr;
}
#endif
void VPWidenCanonicalIVRecipe::execute(VPTransformState &State) {
Value *CanonicalIV = State.get(getOperand(0), 0);
Type *STy = CanonicalIV->getType();
IRBuilder<> Builder(State.CFG.PrevBB->getTerminator());
ElementCount VF = State.VF;
Value *VStart = VF.isScalar()
? CanonicalIV
: Builder.CreateVectorSplat(VF, CanonicalIV, "broadcast");
for (unsigned Part = 0, UF = State.UF; Part < UF; ++Part) {
Value *VStep = createStepForVF(Builder, STy, VF, Part);
if (VF.isVector()) {
VStep = Builder.CreateVectorSplat(VF, VStep);
VStep =
Builder.CreateAdd(VStep, Builder.CreateStepVector(VStep->getType()));
}
Value *CanonicalVectorIV = Builder.CreateAdd(VStart, VStep, "vec.iv");
State.set(this, CanonicalVectorIV, Part);
}
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPWidenCanonicalIVRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "EMIT ";
printAsOperand(O, SlotTracker);
O << " = WIDEN-CANONICAL-INDUCTION ";
printOperands(O, SlotTracker);
}
#endif
void VPFirstOrderRecurrencePHIRecipe::execute(VPTransformState &State) {
auto &Builder = State.Builder;
// Create a vector from the initial value.
auto *VectorInit = getStartValue()->getLiveInIRValue();
Type *VecTy = State.VF.isScalar()
? VectorInit->getType()
: VectorType::get(VectorInit->getType(), State.VF);
BasicBlock *VectorPH = State.CFG.getPreheaderBBFor(this);
if (State.VF.isVector()) {
auto *IdxTy = Builder.getInt32Ty();
auto *One = ConstantInt::get(IdxTy, 1);
IRBuilder<>::InsertPointGuard Guard(Builder);
Builder.SetInsertPoint(VectorPH->getTerminator());
auto *RuntimeVF = getRuntimeVF(Builder, IdxTy, State.VF);
auto *LastIdx = Builder.CreateSub(RuntimeVF, One);
VectorInit = Builder.CreateInsertElement(
PoisonValue::get(VecTy), VectorInit, LastIdx, "vector.recur.init");
}
// Create a phi node for the new recurrence.
PHINode *EntryPart = PHINode::Create(
VecTy, 2, "vector.recur", &*State.CFG.PrevBB->getFirstInsertionPt());
EntryPart->addIncoming(VectorInit, VectorPH);
State.set(this, EntryPart, 0);
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPFirstOrderRecurrencePHIRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "FIRST-ORDER-RECURRENCE-PHI ";
printAsOperand(O, SlotTracker);
O << " = phi ";
printOperands(O, SlotTracker);
}
#endif
void VPReductionPHIRecipe::execute(VPTransformState &State) {
PHINode *PN = cast<PHINode>(getUnderlyingValue());
auto &Builder = State.Builder;
// In order to support recurrences we need to be able to vectorize Phi nodes.
// Phi nodes have cycles, so we need to vectorize them in two stages. This is
// stage #1: We create a new vector PHI node with no incoming edges. We'll use
// this value when we vectorize all of the instructions that use the PHI.
bool ScalarPHI = State.VF.isScalar() || IsInLoop;
Type *VecTy =
ScalarPHI ? PN->getType() : VectorType::get(PN->getType(), State.VF);
BasicBlock *HeaderBB = State.CFG.PrevBB;
assert(State.CurrentVectorLoop->getHeader() == HeaderBB &&
"recipe must be in the vector loop header");
unsigned LastPartForNewPhi = isOrdered() ? 1 : State.UF;
for (unsigned Part = 0; Part < LastPartForNewPhi; ++Part) {
Value *EntryPart =
PHINode::Create(VecTy, 2, "vec.phi", &*HeaderBB->getFirstInsertionPt());
State.set(this, EntryPart, Part);
}
BasicBlock *VectorPH = State.CFG.getPreheaderBBFor(this);
// Reductions do not have to start at zero. They can start with
// any loop invariant values.
VPValue *StartVPV = getStartValue();
Value *StartV = StartVPV->getLiveInIRValue();
Value *Iden = nullptr;
RecurKind RK = RdxDesc.getRecurrenceKind();
if (RecurrenceDescriptor::isMinMaxRecurrenceKind(RK) ||
RecurrenceDescriptor::isSelectCmpRecurrenceKind(RK)) {
// MinMax reduction have the start value as their identify.
if (ScalarPHI) {
Iden = StartV;
} else {
IRBuilderBase::InsertPointGuard IPBuilder(Builder);
Builder.SetInsertPoint(VectorPH->getTerminator());
StartV = Iden =
Builder.CreateVectorSplat(State.VF, StartV, "minmax.ident");
}
} else {
Iden = RdxDesc.getRecurrenceIdentity(RK, VecTy->getScalarType(),
RdxDesc.getFastMathFlags());
if (!ScalarPHI) {
Iden = Builder.CreateVectorSplat(State.VF, Iden);
IRBuilderBase::InsertPointGuard IPBuilder(Builder);
Builder.SetInsertPoint(VectorPH->getTerminator());
Constant *Zero = Builder.getInt32(0);
StartV = Builder.CreateInsertElement(Iden, StartV, Zero);
}
}
for (unsigned Part = 0; Part < LastPartForNewPhi; ++Part) {
Value *EntryPart = State.get(this, Part);
// Make sure to add the reduction start value only to the
// first unroll part.
Value *StartVal = (Part == 0) ? StartV : Iden;
cast<PHINode>(EntryPart)->addIncoming(StartVal, VectorPH);
}
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPReductionPHIRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "WIDEN-REDUCTION-PHI ";
printAsOperand(O, SlotTracker);
O << " = phi ";
printOperands(O, SlotTracker);
}
#endif
void VPWidenPHIRecipe::execute(VPTransformState &State) {
assert(EnableVPlanNativePath &&
"Non-native vplans are not expected to have VPWidenPHIRecipes.");
// Currently we enter here in the VPlan-native path for non-induction
// PHIs where all control flow is uniform. We simply widen these PHIs.
// Create a vector phi with no operands - the vector phi operands will be
// set at the end of vector code generation.
VPBasicBlock *Parent = getParent();
VPRegionBlock *LoopRegion = Parent->getEnclosingLoopRegion();
unsigned StartIdx = 0;
// For phis in header blocks of loop regions, use the index of the value
// coming from the preheader.
if (LoopRegion->getEntryBasicBlock() == Parent) {
for (unsigned I = 0; I < getNumOperands(); ++I) {
if (getIncomingBlock(I) ==
LoopRegion->getSinglePredecessor()->getExitingBasicBlock())
StartIdx = I;
}
}
Value *Op0 = State.get(getOperand(StartIdx), 0);
Type *VecTy = Op0->getType();
Value *VecPhi = State.Builder.CreatePHI(VecTy, 2, "vec.phi");
State.set(this, VecPhi, 0);
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPWidenPHIRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "WIDEN-PHI ";
auto *OriginalPhi = cast<PHINode>(getUnderlyingValue());
// Unless all incoming values are modeled in VPlan print the original PHI
// directly.
// TODO: Remove once all VPWidenPHIRecipe instances keep all relevant incoming
// values as VPValues.
if (getNumOperands() != OriginalPhi->getNumOperands()) {
O << VPlanIngredient(OriginalPhi);
return;
}
printAsOperand(O, SlotTracker);
O << " = phi ";
printOperands(O, SlotTracker);
}
#endif
// TODO: It would be good to use the existing VPWidenPHIRecipe instead and
// remove VPActiveLaneMaskPHIRecipe.
void VPActiveLaneMaskPHIRecipe::execute(VPTransformState &State) {
BasicBlock *VectorPH = State.CFG.getPreheaderBBFor(this);
for (unsigned Part = 0, UF = State.UF; Part < UF; ++Part) {
Value *StartMask = State.get(getOperand(0), Part);
PHINode *EntryPart =
State.Builder.CreatePHI(StartMask->getType(), 2, "active.lane.mask");
EntryPart->addIncoming(StartMask, VectorPH);
EntryPart->setDebugLoc(DL);
State.set(this, EntryPart, Part);
}
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPActiveLaneMaskPHIRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << Indent << "ACTIVE-LANE-MASK-PHI ";
printAsOperand(O, SlotTracker);
O << " = phi ";
printOperands(O, SlotTracker);
}
#endif
diff --git a/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp b/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp
index ca73dafe2b8e..61676b4323d2 100644
--- a/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp
+++ b/contrib/llvm-project/llvm/tools/llvm-objdump/ELFDump.cpp
@@ -1,395 +1,396 @@
//===-- ELFDump.cpp - ELF-specific dumper -----------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file implements the ELF-specific dumper for llvm-objdump.
///
//===----------------------------------------------------------------------===//
#include "ELFDump.h"
#include "llvm-objdump.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::object;
using namespace llvm::objdump;
template <class ELFT>
static Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> &Elf) {
auto DynamicEntriesOrError = Elf.dynamicEntries();
if (!DynamicEntriesOrError)
return DynamicEntriesOrError.takeError();
for (const typename ELFT::Dyn &Dyn : *DynamicEntriesOrError) {
if (Dyn.d_tag == ELF::DT_STRTAB) {
auto MappedAddrOrError = Elf.toMappedAddr(Dyn.getPtr());
if (!MappedAddrOrError)
consumeError(MappedAddrOrError.takeError());
return StringRef(reinterpret_cast<const char *>(*MappedAddrOrError));
}
}
// If the dynamic segment is not present, we fall back on the sections.
auto SectionsOrError = Elf.sections();
if (!SectionsOrError)
return SectionsOrError.takeError();
for (const typename ELFT::Shdr &Sec : *SectionsOrError) {
if (Sec.sh_type == ELF::SHT_DYNSYM)
return Elf.getStringTableForSymtab(Sec);
}
return createError("dynamic string table not found");
}
template <class ELFT>
static Error getRelocationValueString(const ELFObjectFile<ELFT> *Obj,
const RelocationRef &RelRef,
SmallVectorImpl<char> &Result) {
const ELFFile<ELFT> &EF = Obj->getELFFile();
DataRefImpl Rel = RelRef.getRawDataRefImpl();
auto SecOrErr = EF.getSection(Rel.d.a);
if (!SecOrErr)
return SecOrErr.takeError();
int64_t Addend = 0;
// If there is no Symbol associated with the relocation, we set the undef
// boolean value to 'true'. This will prevent us from calling functions that
// requires the relocation to be associated with a symbol.
//
// In SHT_REL case we would need to read the addend from section data.
// GNU objdump does not do that and we just follow for simplicity atm.
bool Undef = false;
if ((*SecOrErr)->sh_type == ELF::SHT_RELA) {
const typename ELFT::Rela *ERela = Obj->getRela(Rel);
Addend = ERela->r_addend;
Undef = ERela->getSymbol(false) == 0;
} else if ((*SecOrErr)->sh_type == ELF::SHT_REL) {
const typename ELFT::Rel *ERel = Obj->getRel(Rel);
Undef = ERel->getSymbol(false) == 0;
} else {
return make_error<BinaryError>();
}
// Default scheme is to print Target, as well as "+ <addend>" for nonzero
// addend. Should be acceptable for all normal purposes.
std::string FmtBuf;
raw_string_ostream Fmt(FmtBuf);
if (!Undef) {
symbol_iterator SI = RelRef.getSymbol();
Expected<const typename ELFT::Sym *> SymOrErr =
Obj->getSymbol(SI->getRawDataRefImpl());
// TODO: test this error.
if (!SymOrErr)
return SymOrErr.takeError();
if ((*SymOrErr)->getType() == ELF::STT_SECTION) {
Expected<section_iterator> SymSI = SI->getSection();
if (!SymSI)
return SymSI.takeError();
const typename ELFT::Shdr *SymSec =
Obj->getSection((*SymSI)->getRawDataRefImpl());
auto SecName = EF.getSectionName(*SymSec);
if (!SecName)
return SecName.takeError();
Fmt << *SecName;
} else {
Expected<StringRef> SymName = SI->getName();
if (!SymName)
return SymName.takeError();
if (Demangle)
Fmt << demangle(std::string(*SymName));
else
Fmt << *SymName;
}
} else {
Fmt << "*ABS*";
}
if (Addend != 0) {
Fmt << (Addend < 0
? "-"
: "+") << format("0x%" PRIx64,
(Addend < 0 ? -(uint64_t)Addend : (uint64_t)Addend));
}
Fmt.flush();
Result.append(FmtBuf.begin(), FmtBuf.end());
return Error::success();
}
Error objdump::getELFRelocationValueString(const ELFObjectFileBase *Obj,
const RelocationRef &Rel,
SmallVectorImpl<char> &Result) {
if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj))
return getRelocationValueString(ELF32LE, Rel, Result);
if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj))
return getRelocationValueString(ELF64LE, Rel, Result);
if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj))
return getRelocationValueString(ELF32BE, Rel, Result);
auto *ELF64BE = cast<ELF64BEObjectFile>(Obj);
return getRelocationValueString(ELF64BE, Rel, Result);
}
template <class ELFT>
static uint64_t getSectionLMA(const ELFFile<ELFT> &Obj,
const object::ELFSectionRef &Sec) {
auto PhdrRangeOrErr = Obj.program_headers();
if (!PhdrRangeOrErr)
report_fatal_error(Twine(toString(PhdrRangeOrErr.takeError())));
// Search for a PT_LOAD segment containing the requested section. Use this
// segment's p_addr to calculate the section's LMA.
for (const typename ELFT::Phdr &Phdr : *PhdrRangeOrErr)
if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_vaddr <= Sec.getAddress()) &&
(Phdr.p_vaddr + Phdr.p_memsz > Sec.getAddress()))
return Sec.getAddress() - Phdr.p_vaddr + Phdr.p_paddr;
// Return section's VMA if it isn't in a PT_LOAD segment.
return Sec.getAddress();
}
uint64_t objdump::getELFSectionLMA(const object::ELFSectionRef &Sec) {
if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Sec.getObject()))
return getSectionLMA(ELFObj->getELFFile(), Sec);
else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Sec.getObject()))
return getSectionLMA(ELFObj->getELFFile(), Sec);
else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Sec.getObject()))
return getSectionLMA(ELFObj->getELFFile(), Sec);
const auto *ELFObj = cast<ELF64BEObjectFile>(Sec.getObject());
return getSectionLMA(ELFObj->getELFFile(), Sec);
}
template <class ELFT>
static void printDynamicSection(const ELFFile<ELFT> &Elf, StringRef Filename) {
auto DynamicEntriesOrErr = Elf.dynamicEntries();
if (!DynamicEntriesOrErr) {
reportWarning(toString(DynamicEntriesOrErr.takeError()), Filename);
return;
}
ArrayRef<typename ELFT::Dyn> DynamicEntries = *DynamicEntriesOrErr;
// Find the maximum tag name length to format the value column properly.
size_t MaxLen = 0;
for (const typename ELFT::Dyn &Dyn : DynamicEntries)
MaxLen = std::max(MaxLen, Elf.getDynamicTagAsString(Dyn.d_tag).size());
std::string TagFmt = " %-" + std::to_string(MaxLen) + "s ";
outs() << "\nDynamic Section:\n";
for (const typename ELFT::Dyn &Dyn : DynamicEntries) {
if (Dyn.d_tag == ELF::DT_NULL)
continue;
std::string Str = Elf.getDynamicTagAsString(Dyn.d_tag);
outs() << format(TagFmt.c_str(), Str.c_str());
const char *Fmt =
ELFT::Is64Bits ? "0x%016" PRIx64 "\n" : "0x%08" PRIx64 "\n";
if (Dyn.d_tag == ELF::DT_NEEDED || Dyn.d_tag == ELF::DT_RPATH ||
Dyn.d_tag == ELF::DT_RUNPATH || Dyn.d_tag == ELF::DT_SONAME ||
Dyn.d_tag == ELF::DT_AUXILIARY || Dyn.d_tag == ELF::DT_FILTER) {
Expected<StringRef> StrTabOrErr = getDynamicStrTab(Elf);
if (StrTabOrErr) {
const char *Data = StrTabOrErr.get().data();
outs() << (Data + Dyn.d_un.d_val) << "\n";
continue;
}
reportWarning(toString(StrTabOrErr.takeError()), Filename);
consumeError(StrTabOrErr.takeError());
}
outs() << format(Fmt, (uint64_t)Dyn.d_un.d_val);
}
}
template <class ELFT>
static void printProgramHeaders(const ELFFile<ELFT> &Obj, StringRef FileName) {
outs() << "\nProgram Header:\n";
auto ProgramHeaderOrError = Obj.program_headers();
if (!ProgramHeaderOrError) {
reportWarning("unable to read program headers: " +
toString(ProgramHeaderOrError.takeError()),
FileName);
return;
}
for (const typename ELFT::Phdr &Phdr : *ProgramHeaderOrError) {
switch (Phdr.p_type) {
case ELF::PT_DYNAMIC:
outs() << " DYNAMIC ";
break;
case ELF::PT_GNU_EH_FRAME:
outs() << "EH_FRAME ";
break;
case ELF::PT_GNU_RELRO:
outs() << " RELRO ";
break;
case ELF::PT_GNU_PROPERTY:
outs() << " PROPERTY ";
break;
case ELF::PT_GNU_STACK:
outs() << " STACK ";
break;
case ELF::PT_INTERP:
outs() << " INTERP ";
break;
case ELF::PT_LOAD:
outs() << " LOAD ";
break;
case ELF::PT_NOTE:
outs() << " NOTE ";
break;
case ELF::PT_OPENBSD_BOOTDATA:
outs() << " OPENBSD_BOOTDATA ";
break;
case ELF::PT_OPENBSD_RANDOMIZE:
outs() << " OPENBSD_RANDOMIZE ";
break;
case ELF::PT_OPENBSD_WXNEEDED:
outs() << " OPENBSD_WXNEEDED ";
break;
case ELF::PT_PHDR:
outs() << " PHDR ";
break;
case ELF::PT_TLS:
outs() << " TLS ";
break;
default:
outs() << " UNKNOWN ";
}
const char *Fmt = ELFT::Is64Bits ? "0x%016" PRIx64 " " : "0x%08" PRIx64 " ";
outs() << "off " << format(Fmt, (uint64_t)Phdr.p_offset) << "vaddr "
<< format(Fmt, (uint64_t)Phdr.p_vaddr) << "paddr "
<< format(Fmt, (uint64_t)Phdr.p_paddr)
<< format("align 2**%u\n",
countTrailingZeros<uint64_t>(Phdr.p_align))
<< " filesz " << format(Fmt, (uint64_t)Phdr.p_filesz)
<< "memsz " << format(Fmt, (uint64_t)Phdr.p_memsz) << "flags "
<< ((Phdr.p_flags & ELF::PF_R) ? "r" : "-")
<< ((Phdr.p_flags & ELF::PF_W) ? "w" : "-")
<< ((Phdr.p_flags & ELF::PF_X) ? "x" : "-") << "\n";
}
}
template <class ELFT>
-static void printSymbolVersionDependency(ArrayRef<uint8_t> Contents,
- StringRef StrTab) {
+static void printSymbolVersionDependency(StringRef FileName,
+ const ELFFile<ELFT> &Obj,
+ const typename ELFT::Shdr &Sec) {
outs() << "\nVersion References:\n";
- const uint8_t *Buf = Contents.data();
- while (Buf) {
- auto *Verneed = reinterpret_cast<const typename ELFT::Verneed *>(Buf);
- outs() << " required from "
- << StringRef(StrTab.drop_front(Verneed->vn_file).data()) << ":\n";
+ auto WarningHandler = [&](const Twine &Msg) {
+ reportWarning(Msg, FileName);
+ return Error::success();
+ };
+ Expected<std::vector<VerNeed>> V =
+ Obj.getVersionDependencies(Sec, WarningHandler);
+ if (!V) {
+ reportWarning(toString(V.takeError()), FileName);
+ return;
+ }
- const uint8_t *BufAux = Buf + Verneed->vn_aux;
- while (BufAux) {
- auto *Vernaux = reinterpret_cast<const typename ELFT::Vernaux *>(BufAux);
- outs() << " "
- << format("0x%08" PRIx32 " ", (uint32_t)Vernaux->vna_hash)
- << format("0x%02" PRIx16 " ", (uint16_t)Vernaux->vna_flags)
- << format("%02" PRIu16 " ", (uint16_t)Vernaux->vna_other)
- << StringRef(StrTab.drop_front(Vernaux->vna_name).data()) << '\n';
- BufAux = Vernaux->vna_next ? BufAux + Vernaux->vna_next : nullptr;
- }
- Buf = Verneed->vn_next ? Buf + Verneed->vn_next : nullptr;
+ raw_fd_ostream &OS = outs();
+ for (const VerNeed &VN : *V) {
+ OS << " required from " << VN.File << ":\n";
+ for (const VernAux &Aux : VN.AuxV)
+ OS << format(" 0x%08x 0x%02x %02u %s\n", Aux.Hash, Aux.Flags,
+ Aux.Other, Aux.Name.c_str());
}
}
template <class ELFT>
static void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr,
ArrayRef<uint8_t> Contents,
StringRef StrTab) {
outs() << "\nVersion definitions:\n";
const uint8_t *Buf = Contents.data();
uint32_t VerdefIndex = 1;
// sh_info contains the number of entries in the SHT_GNU_verdef section. To
// make the index column have consistent width, we should insert blank spaces
// according to sh_info.
uint16_t VerdefIndexWidth = std::to_string(Shdr.sh_info).size();
while (Buf) {
auto *Verdef = reinterpret_cast<const typename ELFT::Verdef *>(Buf);
outs() << format_decimal(VerdefIndex++, VerdefIndexWidth) << " "
<< format("0x%02" PRIx16 " ", (uint16_t)Verdef->vd_flags)
<< format("0x%08" PRIx32 " ", (uint32_t)Verdef->vd_hash);
const uint8_t *BufAux = Buf + Verdef->vd_aux;
uint16_t VerdauxIndex = 0;
while (BufAux) {
auto *Verdaux = reinterpret_cast<const typename ELFT::Verdaux *>(BufAux);
if (VerdauxIndex)
outs() << std::string(VerdefIndexWidth + 17, ' ');
outs() << StringRef(StrTab.drop_front(Verdaux->vda_name).data()) << '\n';
BufAux = Verdaux->vda_next ? BufAux + Verdaux->vda_next : nullptr;
++VerdauxIndex;
}
Buf = Verdef->vd_next ? Buf + Verdef->vd_next : nullptr;
}
}
template <class ELFT>
static void printSymbolVersionInfo(const ELFFile<ELFT> &Elf,
StringRef FileName) {
ArrayRef<typename ELFT::Shdr> Sections =
unwrapOrError(Elf.sections(), FileName);
for (const typename ELFT::Shdr &Shdr : Sections) {
if (Shdr.sh_type != ELF::SHT_GNU_verneed &&
Shdr.sh_type != ELF::SHT_GNU_verdef)
continue;
ArrayRef<uint8_t> Contents =
unwrapOrError(Elf.getSectionContents(Shdr), FileName);
const typename ELFT::Shdr *StrTabSec =
unwrapOrError(Elf.getSection(Shdr.sh_link), FileName);
StringRef StrTab = unwrapOrError(Elf.getStringTable(*StrTabSec), FileName);
if (Shdr.sh_type == ELF::SHT_GNU_verneed)
- printSymbolVersionDependency<ELFT>(Contents, StrTab);
+ printSymbolVersionDependency<ELFT>(FileName, Elf, Shdr);
else
printSymbolVersionDefinition<ELFT>(Shdr, Contents, StrTab);
}
}
void objdump::printELFFileHeader(const object::ObjectFile *Obj) {
if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName());
else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName());
else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName());
else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName());
}
void objdump::printELFDynamicSection(const object::ObjectFile *Obj) {
if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
printDynamicSection(ELFObj->getELFFile(), Obj->getFileName());
else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
printDynamicSection(ELFObj->getELFFile(), Obj->getFileName());
else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
printDynamicSection(ELFObj->getELFFile(), Obj->getFileName());
else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
printDynamicSection(ELFObj->getELFFile(), Obj->getFileName());
}
void objdump::printELFSymbolVersionInfo(const object::ObjectFile *Obj) {
if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName());
else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName());
else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName());
else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName());
}
diff --git a/etc/mtree/BSD.debug.dist b/etc/mtree/BSD.debug.dist
index 053d76eb05c7..75ac69ff3d7c 100644
--- a/etc/mtree/BSD.debug.dist
+++ b/etc/mtree/BSD.debug.dist
@@ -1,66 +1,66 @@
# $FreeBSD$
#
# Please see the file src/etc/mtree/README before making changes to this file.
#
/set type=dir uname=root gname=wheel mode=0755
.
debug
bin
..
boot
kernel
..
modules
..
..
lib
casper
..
geom
..
nvmecontrol
..
..
libexec
..
sbin
..
usr
bin
..
lib
clang
- 15.0.0
+ 15.0.3
lib
freebsd
..
..
..
..
engines
..
i18n
..
..
libexec
bsdinstall
..
lpr
ru
..
..
sendmail
..
sm.bin
..
zfs
..
..
sbin
..
tests
..
..
..
..
diff --git a/etc/mtree/BSD.usr.dist b/etc/mtree/BSD.usr.dist
index e754b71bdd62..b227ef6cfe88 100644
--- a/etc/mtree/BSD.usr.dist
+++ b/etc/mtree/BSD.usr.dist
@@ -1,1292 +1,1292 @@
# $FreeBSD$
#
# Please see the file src/etc/mtree/README before making changes to this file.
#
/set type=dir uname=root gname=wheel mode=0755
.
bin
..
include
private
bsdstat
..
event1
..
gmock
internal
custom
..
..
..
gtest
internal
custom
..
..
..
sqlite3
..
ucl
..
zstd
..
..
..
lib
clang
- 15.0.0
+ 15.0.3
include
cuda_wrappers
..
fuzzer
..
hlsl
..
openmp_wrappers
..
ppc_wrappers
..
profile
..
sanitizer
..
xray
..
..
lib
freebsd
..
..
share
..
..
..
compat
..
dtrace
..
engines
..
flua
..
i18n
..
libxo
encoder
..
..
..
libdata
gcc
..
ldscripts
..
pkgconfig
..
..
libexec
bsdconfig
020.docsinstall
include
..
..
030.packages
include
..
..
040.password
include
..
..
050.diskmgmt
include
..
..
070.usermgmt
include
..
..
080.console
include
..
..
090.timezone
include
..
..
110.mouse
include
..
..
120.networking
include
..
..
130.security
include
..
..
140.startup
include
..
..
150.ttys
include
..
..
dot
include
..
..
include
..
includes
include
..
..
..
bsdinstall
..
dwatch
..
hyperv
..
lpr
ru
..
..
sendmail
..
sm.bin
..
zfs
..
..
local
..
obj nochange
..
sbin
..
share
atf tags=package=tests
..
bhyve
kbdlayout
..
..
bsdconfig
media
..
networking
..
packages
..
password
..
startup
..
timezone
..
usermgmt
..
..
calendar
de_AT.ISO_8859-15
..
de_DE.ISO8859-1
..
fr_FR.ISO8859-1
..
hr_HR.ISO8859-2
..
hu_HU.ISO8859-2
..
pt_BR.ISO8859-1
..
pt_BR.UTF-8
..
ru_RU.KOI8-R
..
ru_RU.UTF-8
..
uk_UA.KOI8-U
..
..
certs
blacklisted tags=package=caroot
..
trusted tags=package=caroot
..
..
dict
..
doc
IPv6
..
atf tags=package=tests
..
kyua tags=package=tests
..
legal
..
llvm
clang
..
..
ncurses
..
ntp
drivers
icons
..
scripts
..
..
hints
..
icons
..
pic
..
scripts
..
..
pjdfstest
..
..
dtrace
..
examples
BSD_daemon
..
FreeBSD_version
..
IPv6
..
bhyve
..
bootforth
..
bsdconfig
..
csh
..
diskless
..
dma
..
drivers
..
dwatch
..
etc
defaults
..
..
find_interface
..
flua
..
hast
..
hostapd
..
indent
..
ipfilter
..
ipfw
..
jails
..
kld
cdev
module
..
test
..
..
dyn_sysctl
..
firmware
fwconsumer
..
fwimage
..
..
khelp
..
syscall
module
..
test
..
..
..
kyua tags=package=tests
..
libusb20
..
libvgl
..
mdoc
..
netgraph
..
perfmon
..
pf
..
ppi
..
ppp
..
printing
..
scsi_target
..
ses
getencstat
..
sesd
..
setencstat
..
setobjstat
..
srcs
..
..
smbfs
print
..
..
sunrpc
dir
..
msg
..
sort
..
..
tcsh
..
uefisign
..
ypldap
..
..
firmware
..
flua
..
games
fortune
..
..
i18n
csmapper
APPLE
..
AST
..
BIG5
..
CNS
..
CP
..
EBCDIC
..
GB
..
GEORGIAN
..
ISO-8859
..
ISO646
..
JIS
..
KAZAKH
..
KOI
..
KS
..
MISC
..
TCVN
..
..
esdb
APPLE
..
AST
..
BIG5
..
CP
..
DEC
..
EBCDIC
..
EUC
..
GB
..
GEORGIAN
..
ISO-2022
..
ISO-8859
..
ISO646
..
KAZAKH
..
KOI
..
MISC
..
TCVN
..
UTF
..
..
..
keys
pkg
revoked tags=package=runtime
..
trusted tags=package=runtime
..
..
..
kyua tags=package=tests
misc tags=package=tests
..
store tags=package=tests
..
..
locale
af_ZA.ISO8859-1
..
af_ZA.ISO8859-15
..
af_ZA.UTF-8
..
ar_AE.UTF-8
..
ar_EG.UTF-8
..
ar_JO.UTF-8
..
ar_MA.UTF-8
..
ar_QA.UTF-8
..
ar_SA.UTF-8
..
am_ET.UTF-8
..
be_BY.CP1131
..
be_BY.CP1251
..
be_BY.ISO8859-5
..
be_BY.UTF-8
..
bg_BG.CP1251
..
bg_BG.UTF-8
..
ca_AD.ISO8859-1
..
ca_AD.ISO8859-15
..
ca_ES.ISO8859-1
..
ca_ES.ISO8859-15
..
ca_FR.ISO8859-1
..
ca_FR.ISO8859-15
..
ca_IT.ISO8859-1
..
ca_IT.ISO8859-15
..
ca_AD.UTF-8
..
ca_ES.UTF-8
..
ca_FR.UTF-8
..
ca_IT.UTF-8
..
cs_CZ.ISO8859-2
..
cs_CZ.UTF-8
..
da_DK.ISO8859-1
..
da_DK.ISO8859-15
..
da_DK.UTF-8
..
de_AT.ISO8859-1
..
de_AT.ISO8859-15
..
de_AT.UTF-8
..
de_CH.ISO8859-1
..
de_CH.ISO8859-15
..
de_CH.UTF-8
..
de_DE.ISO8859-1
..
de_DE.ISO8859-15
..
de_DE.UTF-8
..
el_GR.ISO8859-7
..
el_GR.UTF-8
..
en_AU.ISO8859-1
..
en_AU.ISO8859-15
..
en_AU.US-ASCII
..
en_AU.UTF-8
..
en_CA.ISO8859-1
..
en_CA.ISO8859-15
..
en_CA.US-ASCII
..
en_CA.UTF-8
..
en_GB.ISO8859-1
..
en_GB.ISO8859-15
..
en_GB.US-ASCII
..
en_GB.UTF-8
..
en_HK.ISO8859-1
..
en_HK.UTF-8
..
en_IE.ISO8859-1
..
en_IE.ISO8859-15
..
en_IE.UTF-8
..
en_NZ.ISO8859-1
..
en_NZ.ISO8859-15
..
en_NZ.US-ASCII
..
en_NZ.UTF-8
..
en_PH.UTF-8
..
en_SG.ISO8859-1
..
en_SG.UTF-8
..
en_US.ISO8859-1
..
en_US.ISO8859-15
..
en_US.US-ASCII
..
en_US.UTF-8
..
en_ZA.ISO8859-1
..
en_ZA.ISO8859-15
..
en_ZA.US-ASCII
..
en_ZA.UTF-8
..
es_AR.ISO8859-1
..
es_AR.UTF-8
..
es_CR.UTF-8
..
es_ES.ISO8859-1
..
es_ES.ISO8859-15
..
es_ES.UTF-8
..
es_MX.ISO8859-1
..
es_MX.UTF-8
..
et_EE.ISO8859-1
..
et_EE.ISO8859-15
..
et_EE.UTF-8
..
eu_ES.ISO8859-1
..
eu_ES.ISO8859-15
..
eu_ES.UTF-8
..
fi_FI.ISO8859-1
..
fi_FI.ISO8859-15
..
fi_FI.UTF-8
..
fr_BE.ISO8859-1
..
fr_BE.ISO8859-15
..
fr_BE.UTF-8
..
fr_CA.ISO8859-1
..
fr_CA.ISO8859-15
..
fr_CA.UTF-8
..
fr_CH.ISO8859-1
..
fr_CH.ISO8859-15
..
fr_CH.UTF-8
..
fr_FR.ISO8859-1
..
fr_FR.ISO8859-15
..
fr_FR.UTF-8
..
ga_IE.UTF-8
..
he_IL.UTF-8
..
hi_IN.ISCII-DEV
..
hi_IN.UTF-8
..
hr_HR.ISO8859-2
..
hr_HR.UTF-8
..
hu_HU.ISO8859-2
..
hu_HU.UTF-8
..
hy_AM.ARMSCII-8
..
hy_AM.UTF-8
..
is_IS.ISO8859-1
..
is_IS.ISO8859-15
..
is_IS.UTF-8
..
it_CH.ISO8859-1
..
it_CH.ISO8859-15
..
it_CH.UTF-8
..
it_IT.ISO8859-1
..
it_IT.ISO8859-15
..
it_IT.UTF-8
..
ja_JP.SJIS
..
ja_JP.UTF-8
..
ja_JP.eucJP
..
kk_KZ.UTF-8
..
ko_KR.CP949
..
ko_KR.UTF-8
..
ko_KR.eucKR
..
lt_LT.ISO8859-13
..
lt_LT.UTF-8
..
lv_LV.ISO8859-13
..
lv_LV.UTF-8
..
mn_MN.UTF-8
..
nb_NO.ISO8859-1
..
nb_NO.ISO8859-15
..
nb_NO.UTF-8
..
nl_BE.ISO8859-1
..
nl_BE.ISO8859-15
..
nl_BE.UTF-8
..
nl_NL.ISO8859-1
..
nl_NL.ISO8859-15
..
nl_NL.UTF-8
..
nn_NO.ISO8859-1
..
nn_NO.ISO8859-15
..
nn_NO.UTF-8
..
pl_PL.ISO8859-2
..
pl_PL.UTF-8
..
pt_BR.ISO8859-1
..
pt_BR.UTF-8
..
pt_PT.ISO8859-1
..
pt_PT.ISO8859-15
..
pt_PT.UTF-8
..
ro_RO.ISO8859-2
..
ro_RO.UTF-8
..
ru_RU.CP1251
..
ru_RU.CP866
..
ru_RU.ISO8859-5
..
ru_RU.KOI8-R
..
ru_RU.UTF-8
..
se_FI.UTF-8
..
se_NO.UTF-8
..
sk_SK.ISO8859-2
..
sk_SK.UTF-8
..
sl_SI.ISO8859-2
..
sl_SI.UTF-8
..
sr_RS.ISO8859-5
..
sr_RS.UTF-8
..
sr_RS.ISO8859-2
..
sr_RS.UTF-8@latin
..
sv_FI.ISO8859-1
..
sv_FI.ISO8859-15
..
sv_FI.UTF-8
..
sv_SE.ISO8859-1
..
sv_SE.ISO8859-15
..
sv_SE.UTF-8
..
tr_TR.ISO8859-9
..
tr_TR.UTF-8
..
uk_UA.CP1251
..
uk_UA.ISO8859-5
..
uk_UA.KOI8-U
..
uk_UA.UTF-8
..
zh_CN.GB18030
..
zh_CN.GB2312
..
zh_CN.GBK
..
zh_CN.eucCN
..
zh_CN.UTF-8
..
zh_HK.UTF-8
..
zh_TW.Big5
..
zh_TW.UTF-8
..
..
man
man1
..
man2
..
man3
..
man3lua
..
man4
aarch64
..
amd64
..
arm
..
i386
..
powerpc
..
..
man5
..
man6
..
man7
..
man8
amd64
..
i386
..
powerpc
..
..
man9
..
..
misc
fonts
..
..
mk
..
nls
C
..
af_ZA.ISO8859-1
..
af_ZA.ISO8859-15
..
af_ZA.UTF-8
..
am_ET.UTF-8
..
be_BY.CP1131
..
be_BY.CP1251
..
be_BY.ISO8859-5
..
be_BY.UTF-8
..
bg_BG.CP1251
..
bg_BG.UTF-8
..
ca_ES.ISO8859-1
..
ca_ES.ISO8859-15
..
ca_ES.UTF-8
..
cs_CZ.ISO8859-2
..
cs_CZ.UTF-8
..
da_DK.ISO8859-1
..
da_DK.ISO8859-15
..
da_DK.UTF-8
..
de_AT.ISO8859-1
..
de_AT.ISO8859-15
..
de_AT.UTF-8
..
de_CH.ISO8859-1
..
de_CH.ISO8859-15
..
de_CH.UTF-8
..
de_DE.ISO8859-1
..
de_DE.ISO8859-15
..
de_DE.UTF-8
..
el_GR.ISO8859-7
..
el_GR.UTF-8
..
en_AU.ISO8859-1
..
en_AU.ISO8859-15
..
en_AU.US-ASCII
..
en_AU.UTF-8
..
en_CA.ISO8859-1
..
en_CA.ISO8859-15
..
en_CA.US-ASCII
..
en_CA.UTF-8
..
en_GB.ISO8859-1
..
en_GB.ISO8859-15
..
en_GB.US-ASCII
..
en_GB.UTF-8
..
en_IE.UTF-8
..
en_NZ.ISO8859-1
..
en_NZ.ISO8859-15
..
en_NZ.US-ASCII
..
en_NZ.UTF-8
..
en_US.ISO8859-1
..
en_US.ISO8859-15
..
en_US.UTF-8
..
es_ES.ISO8859-1
..
es_ES.ISO8859-15
..
es_ES.UTF-8
..
et_EE.ISO8859-15
..
et_EE.UTF-8
..
fi_FI.ISO8859-1
..
fi_FI.ISO8859-15
..
fi_FI.UTF-8
..
fr_BE.ISO8859-1
..
fr_BE.ISO8859-15
..
fr_BE.UTF-8
..
fr_CA.ISO8859-1
..
fr_CA.ISO8859-15
..
fr_CA.UTF-8
..
fr_CH.ISO8859-1
..
fr_CH.ISO8859-15
..
fr_CH.UTF-8
..
fr_FR.ISO8859-1
..
fr_FR.ISO8859-15
..
fr_FR.UTF-8
..
gl_ES.ISO8859-1
..
he_IL.UTF-8
..
hi_IN.ISCII-DEV
..
hr_HR.ISO8859-2
..
hr_HR.UTF-8
..
hu_HU.ISO8859-2
..
hu_HU.UTF-8
..
hy_AM.ARMSCII-8
..
hy_AM.UTF-8
..
is_IS.ISO8859-1
..
is_IS.ISO8859-15
..
is_IS.UTF-8
..
it_CH.ISO8859-1
..
it_CH.ISO8859-15
..
it_CH.UTF-8
..
it_IT.ISO8859-1
..
it_IT.ISO8859-15
..
it_IT.UTF-8
..
ja_JP.SJIS
..
ja_JP.UTF-8
..
ja_JP.eucJP
..
kk_KZ.PT154
..
kk_KZ.UTF-8
..
ko_KR.CP949
..
ko_KR.UTF-8
..
ko_KR.eucKR
..
lt_LT.ISO8859-13
..
lt_LT.UTF-8
..
lv_LV.ISO8859-13
..
lv_LV.UTF-8
..
mn_MN.UTF-8
..
nl_BE.ISO8859-1
..
nl_BE.ISO8859-15
..
nl_BE.UTF-8
..
nl_NL.ISO8859-1
..
nl_NL.ISO8859-15
..
nl_NL.UTF-8
..
no_NO.ISO8859-1
..
no_NO.ISO8859-15
..
no_NO.UTF-8
..
pl_PL.ISO8859-2
..
pl_PL.UTF-8
..
pt_BR.ISO8859-1
..
pt_BR.UTF-8
..
pt_PT.ISO8859-1
..
pt_PT.ISO8859-15
..
pt_PT.UTF-8
..
ro_RO.ISO8859-2
..
ro_RO.UTF-8
..
ru_RU.CP1251
..
ru_RU.CP866
..
ru_RU.ISO8859-5
..
ru_RU.KOI8-R
..
ru_RU.UTF-8
..
sk_SK.ISO8859-2
..
sk_SK.UTF-8
..
sl_SI.ISO8859-2
..
sl_SI.UTF-8
..
sr_YU.ISO8859-2
..
sr_YU.ISO8859-5
..
sr_YU.UTF-8
..
sv_SE.ISO8859-1
..
sv_SE.ISO8859-15
..
sv_SE.UTF-8
..
tr_TR.ISO8859-9
..
tr_TR.UTF-8
..
uk_UA.ISO8859-5
..
uk_UA.KOI8-U
..
uk_UA.UTF-8
..
zh_CN.GB18030
..
zh_CN.GB2312
..
zh_CN.GBK
..
zh_CN.UTF-8
..
zh_CN.eucCN
..
zh_HK.UTF-8
..
zh_TW.UTF-8
..
..
openssl
man
man1
..
man3
..
man5
..
man7
..
..
..
security
..
sendmail
..
skel
..
snmp
defs
..
mibs
..
..
syscons
fonts
..
keymaps
..
scrnmaps
..
..
tabset
..
vi
catalog
..
..
vt
fonts
..
keymaps
..
..
zfs
compatibility.d
..
..
zoneinfo
Africa
..
America
Argentina
..
Indiana
..
Kentucky
..
North_Dakota
..
..
Antarctica
..
Arctic
..
Asia
..
Atlantic
..
Australia
..
Brazil
..
Canada
..
Chile
..
Etc
..
Europe
..
Indian
..
Mexico
..
Pacific
..
US
..
..
..
src nochange
..
..
diff --git a/lib/clang/headers/Makefile b/lib/clang/headers/Makefile
index 58a5d458667f..c0f80c95e1d4 100644
--- a/lib/clang/headers/Makefile
+++ b/lib/clang/headers/Makefile
@@ -1,219 +1,219 @@
# $FreeBSD$
.include "../clang.pre.mk"
.PATH: ${CLANG_SRCS}/lib/Headers
INCSGROUPS= INCS CUDA HLSL OMP PPC
-INCSDIR= ${LIBDIR}/clang/15.0.0/include
+INCSDIR= ${LIBDIR}/clang/15.0.3/include
CUDADIR= ${INCSDIR}/cuda_wrappers
HLSLDIR= ${INCSDIR}/hlsl
OMPDIR= ${INCSDIR}/openmp_wrappers
PPCDIR= ${INCSDIR}/ppc_wrappers
INCS+= __clang_cuda_builtin_vars.h
INCS+= __clang_cuda_cmath.h
INCS+= __clang_cuda_complex_builtins.h
INCS+= __clang_cuda_device_functions.h
INCS+= __clang_cuda_intrinsics.h
INCS+= __clang_cuda_libdevice_declares.h
INCS+= __clang_cuda_math.h
INCS+= __clang_cuda_math_forward_declares.h
INCS+= __clang_cuda_runtime_wrapper.h
INCS+= __clang_cuda_texture_intrinsics.h
INCS+= __clang_hip_cmath.h
INCS+= __clang_hip_libdevice_declares.h
INCS+= __clang_hip_math.h
INCS+= __clang_hip_runtime_wrapper.h
INCS+= __stddef_max_align_t.h
INCS+= __wmmintrin_aes.h
INCS+= __wmmintrin_pclmul.h
INCS+= adxintrin.h
INCS+= altivec.h
INCS+= ammintrin.h
INCS+= amxintrin.h
INCS+= arm64intr.h
INCS+= arm_acle.h
INCS+= arm_cmse.h
INCS+= arm_neon_sve_bridge.h
INCS+= armintr.h
INCS+= avx2intrin.h
INCS+= avx512bf16intrin.h
INCS+= avx512bitalgintrin.h
INCS+= avx512bwintrin.h
INCS+= avx512cdintrin.h
INCS+= avx512dqintrin.h
INCS+= avx512erintrin.h
INCS+= avx512fintrin.h
INCS+= avx512fp16intrin.h
INCS+= avx512ifmaintrin.h
INCS+= avx512ifmavlintrin.h
INCS+= avx512pfintrin.h
INCS+= avx512vbmi2intrin.h
INCS+= avx512vbmiintrin.h
INCS+= avx512vbmivlintrin.h
INCS+= avx512vlbf16intrin.h
INCS+= avx512vlbitalgintrin.h
INCS+= avx512vlbwintrin.h
INCS+= avx512vlcdintrin.h
INCS+= avx512vldqintrin.h
INCS+= avx512vlfp16intrin.h
INCS+= avx512vlintrin.h
INCS+= avx512vlvbmi2intrin.h
INCS+= avx512vlvnniintrin.h
INCS+= avx512vlvp2intersectintrin.h
INCS+= avx512vnniintrin.h
INCS+= avx512vp2intersectintrin.h
INCS+= avx512vpopcntdqintrin.h
INCS+= avx512vpopcntdqvlintrin.h
INCS+= avxintrin.h
INCS+= avxvnniintrin.h
INCS+= bmi2intrin.h
INCS+= bmiintrin.h
INCS+= builtins.h
INCS+= cet.h
INCS+= cetintrin.h
INCS+= cldemoteintrin.h
INCS+= clflushoptintrin.h
INCS+= clwbintrin.h
INCS+= clzerointrin.h
INCS+= cpuid.h
INCS+= crc32intrin.h
INCS+= emmintrin.h
INCS+= enqcmdintrin.h
INCS+= f16cintrin.h
INCS+= fma4intrin.h
INCS+= fmaintrin.h
INCS+= fxsrintrin.h
INCS+= gfniintrin.h
INCS+= hexagon_circ_brev_intrinsics.h
INCS+= hexagon_protos.h
INCS+= hexagon_types.h
INCS+= hlsl.h
INCS+= hresetintrin.h
INCS+= htmintrin.h
INCS+= htmxlintrin.h
INCS+= hvx_hexagon_protos.h
INCS+= ia32intrin.h
INCS+= immintrin.h
INCS+= invpcidintrin.h
INCS+= keylockerintrin.h
INCS+= lwpintrin.h
INCS+= lzcntintrin.h
INCS+= mm3dnow.h
INCS+= mm_malloc.h
INCS+= mmintrin.h
INCS+= module.modulemap
INCS+= movdirintrin.h
INCS+= msa.h
INCS+= mwaitxintrin.h
INCS+= nmmintrin.h
INCS+= opencl-c-base.h
INCS+= opencl-c.h
INCS+= pconfigintrin.h
INCS+= pkuintrin.h
INCS+= pmmintrin.h
INCS+= popcntintrin.h
INCS+= prfchwintrin.h
INCS+= ptwriteintrin.h
INCS+= rdpruintrin.h
INCS+= rdseedintrin.h
INCS+= rtmintrin.h
INCS+= s390intrin.h
INCS+= serializeintrin.h
INCS+= sgxintrin.h
INCS+= shaintrin.h
INCS+= smmintrin.h
INCS+= tbmintrin.h
INCS+= tmmintrin.h
INCS+= tsxldtrkintrin.h
INCS+= uintrintrin.h
INCS+= vadefs.h
INCS+= vaesintrin.h
INCS+= vecintrin.h
INCS+= velintrin.h
INCS+= velintrin_approx.h
INCS+= velintrin_gen.h
INCS+= vpclmulqdqintrin.h
INCS+= waitpkgintrin.h
INCS+= wasm_simd128.h
INCS+= wbnoinvdintrin.h
INCS+= wmmintrin.h
INCS+= x86gprintrin.h
INCS+= x86intrin.h
INCS+= xmmintrin.h
INCS+= xopintrin.h
INCS+= xsavecintrin.h
INCS+= xsaveintrin.h
INCS+= xsaveoptintrin.h
INCS+= xsavesintrin.h
INCS+= xtestintrin.h
INCS+= ${GENINCS}
# Headers which possibly conflict with our own versions:
.ifdef INSTALL_CONFLICTING_CLANG_HEADERS
INCS+= float.h
INCS+= intrin.h
INCS+= inttypes.h
INCS+= iso646.h
INCS+= limits.h
INCS+= stdalign.h
INCS+= stdarg.h
INCS+= stdatomic.h
INCS+= stdbool.h
INCS+= stddef.h
INCS+= stdint.h
INCS+= stdnoreturn.h
INCS+= tgmath.h
INCS+= unwind.h
INCS+= varargs.h
.endif # INSTALL_CONFLICTING_CLANG_HEADERS
CUDA+= cuda_wrappers/algorithm
CUDA+= cuda_wrappers/complex
CUDA+= cuda_wrappers/new
HLSL+= hlsl/hlsl_basic_types.h
HLSL+= hlsl/hlsl_intrinsics.h
OMP+= openmp_wrappers/__clang_openmp_device_functions.h
OMP+= openmp_wrappers/cmath
OMP+= openmp_wrappers/complex
OMP+= openmp_wrappers/complex.h
OMP+= openmp_wrappers/complex_cmath.h
OMP+= openmp_wrappers/math.h
OMP+= openmp_wrappers/new
PPC+= ppc_wrappers/bmi2intrin.h
PPC+= ppc_wrappers/bmiintrin.h
PPC+= ppc_wrappers/emmintrin.h
PPC+= ppc_wrappers/immintrin.h
PPC+= ppc_wrappers/mm_malloc.h
PPC+= ppc_wrappers/mmintrin.h
PPC+= ppc_wrappers/pmmintrin.h
PPC+= ppc_wrappers/smmintrin.h
PPC+= ppc_wrappers/tmmintrin.h
PPC+= ppc_wrappers/x86gprintrin.h
PPC+= ppc_wrappers/x86intrin.h
PPC+= ppc_wrappers/xmmintrin.h
.for hdr in bf16/bf16 cde/cde-header fp16/fp16 mve/mve-header neon/neon \
sve/sve-header
arm_${hdr:H}.h: ${CLANG_SRCS}/include/clang/Basic/arm_${hdr:H}.td
${CLANG_TBLGEN} -gen-arm-${hdr:T} \
-I ${CLANG_SRCS}/include/clang/Basic -d ${.TARGET:C/$/.d/} \
-o ${.TARGET} ${CLANG_SRCS}/include/clang/Basic/arm_${hdr:H}.td
GENINCS+= arm_${hdr:H}.h
.endfor
.for hdr in vector/vector-header
riscv_${hdr:H}.h: ${CLANG_SRCS}/include/clang/Basic/riscv_${hdr:H}.td
${CLANG_TBLGEN} -gen-riscv-${hdr:T} \
-I ${CLANG_SRCS}/include/clang/Basic -d ${.TARGET:C/$/.d/} \
-o ${.TARGET} ${CLANG_SRCS}/include/clang/Basic/riscv_${hdr:H}.td
GENINCS+= riscv_${hdr:H}.h
.endfor
CLEANFILES= ${GENINCS} ${GENINCS:C/$/.d/}
.include <bsd.prog.mk>
diff --git a/lib/clang/include/VCSVersion.inc b/lib/clang/include/VCSVersion.inc
index 4441e4d4aafa..8b9c83471140 100644
--- a/lib/clang/include/VCSVersion.inc
+++ b/lib/clang/include/VCSVersion.inc
@@ -1,10 +1,10 @@
// $FreeBSD$
-#define LLVM_REVISION "llvmorg-15.0.0-9-g1c73596d3454"
+#define LLVM_REVISION "llvmorg-15.0.2-10-gf3c5289e7846"
#define LLVM_REPOSITORY "https://github.com/llvm/llvm-project.git"
-#define CLANG_REVISION "llvmorg-15.0.0-9-g1c73596d3454"
+#define CLANG_REVISION "llvmorg-15.0.2-10-gf3c5289e7846"
#define CLANG_REPOSITORY "https://github.com/llvm/llvm-project.git"
-#define LLDB_REVISION "llvmorg-15.0.0-9-g1c73596d3454"
+#define LLDB_REVISION "llvmorg-15.0.2-10-gf3c5289e7846"
#define LLDB_REPOSITORY "https://github.com/llvm/llvm-project.git"
diff --git a/lib/clang/include/clang/Basic/Version.inc b/lib/clang/include/clang/Basic/Version.inc
index a7851f10eb7a..dfac74612407 100644
--- a/lib/clang/include/clang/Basic/Version.inc
+++ b/lib/clang/include/clang/Basic/Version.inc
@@ -1,9 +1,9 @@
/* $FreeBSD$ */
-#define CLANG_VERSION 15.0.0
-#define CLANG_VERSION_STRING "15.0.0"
+#define CLANG_VERSION 15.0.3
+#define CLANG_VERSION_STRING "15.0.3"
#define CLANG_VERSION_MAJOR 15
#define CLANG_VERSION_MINOR 0
-#define CLANG_VERSION_PATCHLEVEL 0
+#define CLANG_VERSION_PATCHLEVEL 3
#define CLANG_VENDOR "FreeBSD "
diff --git a/lib/clang/include/clang/Config/config.h b/lib/clang/include/clang/Config/config.h
index 6c3208239419..92267b160d05 100644
--- a/lib/clang/include/clang/Config/config.h
+++ b/lib/clang/include/clang/Config/config.h
@@ -1,108 +1,108 @@
/* $FreeBSD$ */
/* This generated file is for internal use. Do not include it from headers. */
#ifdef CLANG_CONFIG_H
#error config.h can only be included once
#else
#define CLANG_CONFIG_H
/* Bug report URL. */
#define BUG_REPORT_URL "https://bugs.freebsd.org/submit/"
/* Default to -fPIE and -pie on Linux. */
#define CLANG_DEFAULT_PIE_ON_LINUX 1
/* Default linker to use. */
#define CLANG_DEFAULT_LINKER ""
/* Default C/ObjC standard to use. */
/* #undef CLANG_DEFAULT_STD_C */
/* Always #define something so that missing the config.h #include at use sites
* becomes a compile error.
*/
#ifndef CLANG_DEFAULT_STD_C
#define CLANG_DEFAULT_STD_C LangStandard::lang_unspecified
#endif
/* Default C++/ObjC++ standard to use. */
/* #undef CLANG_DEFAULT_STD_CXX */
/* Always #define something so that missing the config.h #include at use sites
* becomes a compile error.
*/
#ifndef CLANG_DEFAULT_STD_CXX
#define CLANG_DEFAULT_STD_CXX LangStandard::lang_unspecified
#endif
/* Default C++ stdlib to use. */
#define CLANG_DEFAULT_CXX_STDLIB ""
/* Default runtime library to use. */
#define CLANG_DEFAULT_RTLIB ""
/* Default unwind library to use. */
#define CLANG_DEFAULT_UNWINDLIB ""
/* Default objcopy to use */
#define CLANG_DEFAULT_OBJCOPY "objcopy"
/* Default OpenMP runtime used by -fopenmp. */
#define CLANG_DEFAULT_OPENMP_RUNTIME "libomp"
/* Default architecture for OpenMP offloading to Nvidia GPUs. */
#define CLANG_OPENMP_NVPTX_DEFAULT_ARCH "sm_35"
/* Default architecture for SystemZ. */
#define CLANG_SYSTEMZ_DEFAULT_ARCH "z10"
/* Multilib suffix for libdir. */
#define CLANG_LIBDIR_SUFFIX ""
/* Relative directory for resource files */
#define CLANG_RESOURCE_DIR ""
/* Directories clang will search for headers */
#define C_INCLUDE_DIRS ""
/* Directories clang will search for configuration files */
/* #undef CLANG_CONFIG_FILE_SYSTEM_DIR */
/* #undef CLANG_CONFIG_FILE_USER_DIR */
/* Default <path> to all compiler invocations for --sysroot=<path>. */
/* #undef DEFAULT_SYSROOT */
/* Directory where gcc is installed. */
#define GCC_INSTALL_PREFIX ""
/* Define if we have libxml2 */
/* #undef CLANG_HAVE_LIBXML */
/* Define if we have sys/resource.h (rlimits) */
#define CLANG_HAVE_RLIMITS 1
/* The LLVM product name and version */
-#define BACKEND_PACKAGE_STRING "LLVM 15.0.0"
+#define BACKEND_PACKAGE_STRING "LLVM 15.0.3"
/* Linker version detected at compile time. */
/* #undef HOST_LINK_VERSION */
/* pass --build-id to ld */
/* #undef ENABLE_LINKER_BUILD_ID */
/* enable x86 relax relocations by default */
#define ENABLE_X86_RELAX_RELOCATIONS 1
/* Enable IEEE binary128 as default long double format on PowerPC Linux. */
#define PPC_LINUX_DEFAULT_IEEELONGDOUBLE 0
/* Enable each functionality of modules */
/* #undef CLANG_ENABLE_ARCMT */
/* #undef CLANG_ENABLE_OBJC_REWRITER */
/* #undef CLANG_ENABLE_STATIC_ANALYZER */
/* Spawn a new process clang.exe for the CC1 tool invocation, when necessary */
#define CLANG_SPAWN_CC1 0
/* Whether to enable opaque pointers by default */
#define CLANG_ENABLE_OPAQUE_POINTERS_INTERNAL 1
#endif
diff --git a/lib/clang/include/lld/Common/Version.inc b/lib/clang/include/lld/Common/Version.inc
index 7325d25e08a6..cf87a5e72363 100644
--- a/lib/clang/include/lld/Common/Version.inc
+++ b/lib/clang/include/lld/Common/Version.inc
@@ -1,4 +1,4 @@
// Local identifier in __FreeBSD_version style
#define LLD_FREEBSD_VERSION 1400005
-#define LLD_VERSION_STRING "15.0.0 (FreeBSD llvmorg-15.0.0-9-g1c73596d3454-" __XSTRING(LLD_FREEBSD_VERSION) ")"
+#define LLD_VERSION_STRING "15.0.3 (FreeBSD llvmorg-15.0.2-10-gf3c5289e7846-" __XSTRING(LLD_FREEBSD_VERSION) ")"
diff --git a/lib/clang/include/lldb/Version/Version.inc b/lib/clang/include/lldb/Version/Version.inc
index 919499091d2a..30970de1d1d9 100644
--- a/lib/clang/include/lldb/Version/Version.inc
+++ b/lib/clang/include/lldb/Version/Version.inc
@@ -1,6 +1,6 @@
-#define LLDB_VERSION 15.0.0
-#define LLDB_VERSION_STRING "15.0.0"
+#define LLDB_VERSION 15.0.3
+#define LLDB_VERSION_STRING "15.0.3"
#define LLDB_VERSION_MAJOR 15
#define LLDB_VERSION_MINOR 0
-#define LLDB_VERSION_PATCH 0
+#define LLDB_VERSION_PATCH 3
/* #undef LLDB_FULL_VERSION_STRING */
diff --git a/lib/clang/include/llvm/Config/config.h b/lib/clang/include/llvm/Config/config.h
index 4834ac961e39..4343e1a77f1c 100644
--- a/lib/clang/include/llvm/Config/config.h
+++ b/lib/clang/include/llvm/Config/config.h
@@ -1,388 +1,388 @@
/* $FreeBSD$ */
#ifndef CONFIG_H
#define CONFIG_H
// Include this header only under the llvm source tree.
// This is a private header.
/* Exported configuration */
#include "llvm/Config/llvm-config.h"
/* Bug report URL. */
#define BUG_REPORT_URL "https://bugs.freebsd.org/submit/"
/* Define to 1 to enable backtraces, and to 0 otherwise. */
#define ENABLE_BACKTRACES 1
/* Define to 1 to enable crash overrides, and to 0 otherwise. */
#define ENABLE_CRASH_OVERRIDES 1
/* Define to 1 to enable crash memory dumps, and to 0 otherwise. */
#define LLVM_ENABLE_CRASH_DUMPS 0
/* Define to 1 to prefer forward slashes on Windows, and to 0 prefer
backslashes. */
#define LLVM_WINDOWS_PREFER_FORWARD_SLASH 0
/* Define to 1 if you have the `backtrace' function. */
#define HAVE_BACKTRACE TRUE
#define BACKTRACE_HEADER <execinfo.h>
/* Define to 1 if you have the <CrashReporterClient.h> header file. */
/* #undef HAVE_CRASHREPORTERCLIENT_H */
/* can use __crashreporter_info__ */
#if defined(__APPLE__)
#define HAVE_CRASHREPORTER_INFO 1
#else
#define HAVE_CRASHREPORTER_INFO 0
#endif
/* Define to 1 if you have the declaration of `arc4random', and to 0 if you
don't. */
#define HAVE_DECL_ARC4RANDOM 1
/* Define to 1 if you have the declaration of `FE_ALL_EXCEPT', and to 0 if you
don't. */
#define HAVE_DECL_FE_ALL_EXCEPT 1
/* Define to 1 if you have the declaration of `FE_INEXACT', and to 0 if you
don't. */
#define HAVE_DECL_FE_INEXACT 1
/* Define to 1 if you have the declaration of `strerror_s', and to 0 if you
don't. */
#define HAVE_DECL_STRERROR_S 0
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define if dlopen() is available on this platform. */
#define HAVE_DLOPEN 1
/* Define if dladdr() is available on this platform. */
#define HAVE_DLADDR 1
#if !defined(__arm__) || defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH__)
/* Define to 1 if we can register EH frames on this platform. */
#define HAVE_REGISTER_FRAME 1
/* Define to 1 if we can deregister EH frames on this platform. */
#define HAVE_DEREGISTER_FRAME 1
#endif // !arm || USING_SJLJ_EXCEPTIONS || ARM_DWARF_EH_
/* Define if __unw_add_dynamic_fde() is available on this platform. */
/* #undef HAVE_UNW_ADD_DYNAMIC_FDE */
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the <fenv.h> header file. */
#define HAVE_FENV_H 1
/* Define if libffi is available on this platform. */
/* #undef HAVE_FFI_CALL */
/* Define to 1 if you have the <ffi/ffi.h> header file. */
/* #undef HAVE_FFI_FFI_H */
/* Define to 1 if you have the <ffi.h> header file. */
/* #undef HAVE_FFI_H */
/* Define to 1 if you have the `futimens' function. */
#define HAVE_FUTIMENS 1
/* Define to 1 if you have the `futimes' function. */
#define HAVE_FUTIMES 1
/* Define to 1 if you have the `getpagesize' function. */
#define HAVE_GETPAGESIZE 1
/* Define to 1 if you have the `getrlimit' function. */
#define HAVE_GETRLIMIT 1
/* Define to 1 if you have the `getrusage' function. */
#define HAVE_GETRUSAGE 1
/* Define to 1 if you have the `isatty' function. */
#define HAVE_ISATTY 1
/* Define to 1 if you have the `edit' library (-ledit). */
#define HAVE_LIBEDIT TRUE
/* Define to 1 if you have the `pfm' library (-lpfm). */
/* #undef HAVE_LIBPFM */
/* Define to 1 if the `perf_branch_entry' struct has field cycles. */
/* #undef LIBPFM_HAS_FIELD_CYCLES */
/* Define to 1 if you have the `psapi' library (-lpsapi). */
/* #undef HAVE_LIBPSAPI */
/* Define to 1 if you have the `pthread' library (-lpthread). */
#define HAVE_LIBPTHREAD 1
/* Define to 1 if you have the `pthread_getname_np' function. */
#define HAVE_PTHREAD_GETNAME_NP 1
/* Define to 1 if you have the `pthread_setname_np' function. */
#define HAVE_PTHREAD_SETNAME_NP 1
/* Define to 1 if you have the <link.h> header file. */
#if __has_include(<link.h>)
#define HAVE_LINK_H 1
#else
#define HAVE_LINK_H 0
#endif
/* Define to 1 if you have the `lseek64' function. */
#if defined(__linux__)
#define HAVE_LSEEK64 1
#endif
/* Define to 1 if you have the <mach/mach.h> header file. */
#if __has_include(<mach/mach.h>)
#define HAVE_MACH_MACH_H 1
#endif
/* Define to 1 if you have the `mallctl' function. */
#if defined(__FreeBSD__)
#define HAVE_MALLCTL 1
#endif
/* Define to 1 if you have the `mallinfo' function. */
#if defined(__linux__)
#define HAVE_MALLINFO 1
#endif
/* Define to 1 if you have the `mallinfo2' function. */
/* #undef HAVE_MALLINFO2 */
/* Define to 1 if you have the <malloc/malloc.h> header file. */
#if __has_include(<malloc/malloc.h>)
#define HAVE_MALLOC_MALLOC_H 1
#endif
/* Define to 1 if you have the `malloc_zone_statistics' function. */
#if defined(__APPLE__)
#define HAVE_MALLOC_ZONE_STATISTICS 1
#endif
/* Define to 1 if you have the `posix_spawn' function. */
#define HAVE_POSIX_SPAWN 1
/* Define to 1 if you have the `pread' function. */
#define HAVE_PREAD 1
/* Define to 1 if you have the <pthread.h> header file. */
#define HAVE_PTHREAD_H 1
/* Have pthread_mutex_lock */
#define HAVE_PTHREAD_MUTEX_LOCK 1
/* Have pthread_rwlock_init */
#define HAVE_PTHREAD_RWLOCK_INIT 1
/* Define to 1 if you have the `sbrk' function. */
#define HAVE_SBRK 1
/* Define to 1 if you have the `setenv' function. */
#define HAVE_SETENV 1
/* Define to 1 if you have the `setrlimit' function. */
#define HAVE_SETRLIMIT 1
/* Define to 1 if you have the `sigaltstack' function. */
#define HAVE_SIGALTSTACK 1
/* Define to 1 if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the `strerror_r' function. */
#define HAVE_STRERROR_R 1
/* Define to 1 if you have the `sysconf' function. */
#define HAVE_SYSCONF 1
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
/* Define to 1 if you have the <sys/mman.h> header file. */
#define HAVE_SYS_MMAN_H 1
/* Define to 1 if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
/* Define to 1 if you have the <sys/resource.h> header file. */
#define HAVE_SYS_RESOURCE_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if stat struct has st_mtimespec member .*/
#if !defined(__linux__)
#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
#endif
/* Define to 1 if stat struct has st_mtim member. */
#if !defined(__APPLE__)
#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1
#endif
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define if the setupterm() function is supported this platform. */
#if defined(__FreeBSD__)
/*
* This is only needed for terminalHasColors(). When disabled LLVM falls back
* to checking a list of TERM prefixes which is sufficient for a bootstrap tool.
*/
#define LLVM_ENABLE_TERMINFO TRUE
#endif
/* Define to 1 if you have the <termios.h> header file. */
#define HAVE_TERMIOS_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the <valgrind/valgrind.h> header file. */
/* #undef HAVE_VALGRIND_VALGRIND_H */
/* Have host's _alloca */
/* #undef HAVE__ALLOCA */
/* Define to 1 if you have the `_chsize_s' function. */
/* #undef HAVE__CHSIZE_S */
/* Define to 1 if you have the `_Unwind_Backtrace' function. */
#define HAVE__UNWIND_BACKTRACE 1
/* Have host's __alloca */
/* #undef HAVE___ALLOCA */
/* Have host's __ashldi3 */
/* #undef HAVE___ASHLDI3 */
/* Have host's __ashrdi3 */
/* #undef HAVE___ASHRDI3 */
/* Have host's __chkstk */
/* #undef HAVE___CHKSTK */
/* Have host's __chkstk_ms */
/* #undef HAVE___CHKSTK_MS */
/* Have host's __cmpdi2 */
/* #undef HAVE___CMPDI2 */
/* Have host's __divdi3 */
/* #undef HAVE___DIVDI3 */
/* Have host's __fixdfdi */
/* #undef HAVE___FIXDFDI */
/* Have host's __fixsfdi */
/* #undef HAVE___FIXSFDI */
/* Have host's __floatdidf */
/* #undef HAVE___FLOATDIDF */
/* Have host's __lshrdi3 */
/* #undef HAVE___LSHRDI3 */
/* Have host's __main */
/* #undef HAVE___MAIN */
/* Have host's __moddi3 */
/* #undef HAVE___MODDI3 */
/* Have host's __udivdi3 */
/* #undef HAVE___UDIVDI3 */
/* Have host's __umoddi3 */
/* #undef HAVE___UMODDI3 */
/* Have host's ___chkstk */
/* #undef HAVE____CHKSTK */
/* Have host's ___chkstk_ms */
/* #undef HAVE____CHKSTK_MS */
/* Linker version detected at compile time. */
/* #undef HOST_LINK_VERSION */
/* Define if overriding target triple is enabled */
/* #undef LLVM_TARGET_TRIPLE_ENV */
/* Whether tools show host and target info when invoked with --version */
#define LLVM_VERSION_PRINTER_SHOW_HOST_TARGET_INFO 1
/* Define if libxml2 is supported on this platform. */
/* #undef LLVM_ENABLE_LIBXML2 */
/* Define to the extension used for shared libraries, say, ".so". */
#if defined(__APPLE__)
#define LTDL_SHLIB_EXT ".dylib"
#else
#define LTDL_SHLIB_EXT ".so"
#endif
/* Define to the extension used for plugin libraries, say, ".so". */
#if defined(__APPLE__)
#define LLVM_PLUGIN_EXT ".dylib"
#else
#define LLVM_PLUGIN_EXT ".so"
#endif
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "https://bugs.freebsd.org/submit/"
/* Define to the full name of this package. */
#define PACKAGE_NAME "LLVM"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "LLVM 15.0.0"
+#define PACKAGE_STRING "LLVM 15.0.3"
/* Define to the version of this package. */
-#define PACKAGE_VERSION "15.0.0"
+#define PACKAGE_VERSION "15.0.3"
/* Define to the vendor of this package. */
/* #undef PACKAGE_VENDOR */
/* Define if std::is_trivially_copyable is supported */
#define HAVE_STD_IS_TRIVIALLY_COPYABLE 1
/* Define to a function implementing stricmp */
/* #undef stricmp */
/* Define to a function implementing strdup */
/* #undef strdup */
/* Whether GlobalISel rule coverage is being collected */
#define LLVM_GISEL_COV_ENABLED 0
/* Define to the default GlobalISel coverage file prefix */
/* #undef LLVM_GISEL_COV_PREFIX */
/* Whether Timers signpost passes in Xcode Instruments */
#if defined(__APPLE__)
#define LLVM_SUPPORT_XCODE_SIGNPOSTS 1
#else
#define LLVM_SUPPORT_XCODE_SIGNPOSTS 0
#endif
/* #undef HAVE_PROC_PID_RUSAGE */
#endif
diff --git a/lib/clang/include/llvm/Config/llvm-config.h b/lib/clang/include/llvm/Config/llvm-config.h
index e0f50991ec6d..3cb632668e85 100644
--- a/lib/clang/include/llvm/Config/llvm-config.h
+++ b/lib/clang/include/llvm/Config/llvm-config.h
@@ -1,129 +1,129 @@
/* $FreeBSD$ */
/*===------- llvm/Config/llvm-config.h - llvm configuration -------*- C -*-===*/
/* */
/* Part of the LLVM Project, under the Apache License v2.0 with LLVM */
/* Exceptions. */
/* See https://llvm.org/LICENSE.txt for license information. */
/* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */
/* */
/*===----------------------------------------------------------------------===*/
/* This file enumerates variables from the LLVM configuration so that they
can be in exported headers and won't override package specific directives.
This is a C header that can be included in the llvm-c headers. */
#ifndef LLVM_CONFIG_H
#define LLVM_CONFIG_H
/* Define if LLVM_ENABLE_DUMP is enabled */
/* #undef LLVM_ENABLE_DUMP */
/* Target triple LLVM will generate code for by default */
/* Doesn't use `cmakedefine` because it is allowed to be empty. */
/* #undef LLVM_DEFAULT_TARGET_TRIPLE */
/* Define if threads enabled */
#define LLVM_ENABLE_THREADS 1
/* Has gcc/MSVC atomic intrinsics */
#define LLVM_HAS_ATOMICS 1
/* Host triple LLVM will be executed on */
/* #undef LLVM_HOST_TRIPLE */
/* LLVM architecture name for the native architecture, if available */
/* #undef LLVM_NATIVE_ARCH */
/* LLVM name for the native AsmParser init function, if available */
/* #undef LLVM_NATIVE_ASMPARSER */
/* LLVM name for the native AsmPrinter init function, if available */
/* #undef LLVM_NATIVE_ASMPRINTER */
/* LLVM name for the native Disassembler init function, if available */
/* #undef LLVM_NATIVE_DISASSEMBLER */
/* LLVM name for the native Target init function, if available */
/* #undef LLVM_NATIVE_TARGET */
/* LLVM name for the native TargetInfo init function, if available */
/* #undef LLVM_NATIVE_TARGETINFO */
/* LLVM name for the native target MC init function, if available */
/* #undef LLVM_NATIVE_TARGETMC */
/* LLVM name for the native target MCA init function, if available */
/* #undef LLVM_NATIVE_TARGETMCA */
/* Define if this is Unixish platform */
#define LLVM_ON_UNIX 1
/* Define if we have the Intel JIT API runtime support library */
#define LLVM_USE_INTEL_JITEVENTS 0
/* Define if we have the oprofile JIT-support library */
#define LLVM_USE_OPROFILE 0
/* Define if we have the perf JIT-support library */
#define LLVM_USE_PERF 0
/* Major version of the LLVM API */
#define LLVM_VERSION_MAJOR 15
/* Minor version of the LLVM API */
#define LLVM_VERSION_MINOR 0
/* Patch version of the LLVM API */
-#define LLVM_VERSION_PATCH 0
+#define LLVM_VERSION_PATCH 3
/* LLVM version string */
-#define LLVM_VERSION_STRING "15.0.0"
+#define LLVM_VERSION_STRING "15.0.3"
/* Whether LLVM records statistics for use with GetStatistics(),
* PrintStatistics() or PrintStatisticsJSON()
*/
#define LLVM_FORCE_ENABLE_STATS 0
/* Define if we have z3 and want to build it */
/* #undef LLVM_WITH_Z3 */
/* Define if we have curl and want to use it */
/* #undef LLVM_ENABLE_CURL */
/* Define if we have cpp-httplib and want to use it */
/* #undef LLVM_ENABLE_HTTPLIB */
/* Define if zlib compression is available */
#define LLVM_ENABLE_ZLIB 1
/* Define if zstd compression is available */
#define LLVM_ENABLE_ZSTD 0
/* Define if LLVM was built with a dependency to the libtensorflow dynamic library */
/* #undef LLVM_HAVE_TF_API */
/* Define to 1 if you have the <sysexits.h> header file. */
#define HAVE_SYSEXITS_H 1
/* Define if the xar_open() function is supported on this platform. */
#if defined(__APPLE__)
#define LLVM_HAVE_LIBXAR 1
#endif
/* Define if building libLLVM shared library */
/* #undef LLVM_BUILD_LLVM_DYLIB */
/* Define if building LLVM with BUILD_SHARED_LIBS */
/* #undef LLVM_BUILD_SHARED_LIBS */
/* Define if building LLVM with LLVM_FORCE_USE_OLD_TOOLCHAIN_LIBS */
/* #undef LLVM_FORCE_USE_OLD_TOOLCHAIN */
/* Define if llvm_unreachable should be optimized with undefined behavior
* in non assert builds */
#define LLVM_UNREACHABLE_OPTIMIZE 1
/* Define to 1 if you have the DIA SDK installed, and to 0 if you don't. */
#define LLVM_ENABLE_DIA_SDK 0
#endif
diff --git a/lib/clang/include/llvm/Support/VCSRevision.h b/lib/clang/include/llvm/Support/VCSRevision.h
index a655458a3666..36e2fcbcd33c 100644
--- a/lib/clang/include/llvm/Support/VCSRevision.h
+++ b/lib/clang/include/llvm/Support/VCSRevision.h
@@ -1,3 +1,3 @@
/* $FreeBSD$ */
-#define LLVM_REVISION "llvmorg-15.0.0-9-g1c73596d3454"
+#define LLVM_REVISION "llvmorg-15.0.2-10-gf3c5289e7846"
#define LLVM_REPOSITORY "https://github.com/llvm/llvm-project.git"
diff --git a/lib/libc++/module.modulemap b/lib/libc++/module.modulemap
index 900e077944f6..6d788743f68b 100644
--- a/lib/libc++/module.modulemap
+++ b/lib/libc++/module.modulemap
@@ -1,1367 +1,1401 @@
// define the module for __config outside of the top level 'std' module
// since __config may be included from C headers which may create an
// include cycle.
module std_config [system] [extern_c] {
header "__config"
export *
}
module std [system] {
export std_config
// FIXME: The standard does not require that each of these submodules
// re-exports its imported modules. We should provide an alternative form of
// export that issues a warning if a name from the submodule is used, and
// use that to provide a 'strict mode' for libc++.
// Deprecated C-compatibility headers. These can all be included from within
// an 'extern "C"' context.
module depr [extern_c] {
// <assert.h> provided by C library.
module ctype_h {
header "ctype.h"
export *
}
module errno_h {
header "errno.h"
export *
}
module fenv_h {
header "fenv.h"
export *
}
// <float.h> provided by compiler or C library.
module inttypes_h {
header "inttypes.h"
export stdint_h
export *
}
// <iso646.h> provided by compiler.
// <limits.h> provided by compiler or C library.
module locale_h {
header "locale.h"
export *
}
module math_h {
header "math.h"
export *
}
module setjmp_h {
header "setjmp.h"
export *
}
module stdatomic_h {
requires cplusplus23
header "stdatomic.h"
export *
}
// FIXME: <stdalign.h> is missing.
// <signal.h> provided by C library.
// <stdarg.h> provided by compiler.
- // <stdbool.h> provided by compiler.
+ module stdbool_h {
+ // <stdbool.h>'s __bool_true_false_are_defined macro requires textual inclusion.
+ textual header "stdbool.h"
+ }
module stddef_h {
// <stddef.h>'s __need_* macros require textual inclusion.
textual header "stddef.h"
}
module stdint_h {
header "stdint.h"
export *
// FIXME: This module only exists on OS X and for some reason the
// wildcard above doesn't export it.
export Darwin.C.stdint
}
module stdio_h {
// <stdio.h>'s __need_* macros require textual inclusion.
textual header "stdio.h"
export *
export Darwin.C.stdio
}
module stdlib_h {
// <stdlib.h>'s __need_* macros require textual inclusion.
textual header "stdlib.h"
export *
}
module string_h {
header "string.h"
export *
}
module uchar_h {
header "uchar.h"
export *
}
// <time.h> provided by C library.
module wchar_h {
// <wchar.h>'s __need_* macros require textual inclusion.
textual header "wchar.h"
export *
}
module wctype_h {
header "wctype.h"
export *
}
}
// <complex.h> and <tgmath.h> are not C headers in any real sense, do not
// allow their use in extern "C" contexts.
module complex_h {
header "complex.h"
export ccomplex
export *
}
module tgmath_h {
header "tgmath.h"
export ccomplex
export cmath
export *
}
// C compatibility headers.
module compat {
module cassert {
// <cassert>'s use of NDEBUG requires textual inclusion.
textual header "cassert"
}
module ccomplex {
header "ccomplex"
export complex
export *
}
module cctype {
header "cctype"
export *
}
module cerrno {
header "cerrno"
export *
}
module cfenv {
header "cfenv"
export *
}
module cfloat {
header "cfloat"
export *
}
module cinttypes {
header "cinttypes"
export cstdint
export *
}
module ciso646 {
header "ciso646"
export *
}
module climits {
header "climits"
export *
}
module clocale {
header "clocale"
export *
}
module cmath {
header "cmath"
export *
}
module csetjmp {
header "csetjmp"
export *
}
module csignal {
header "csignal"
export *
}
// FIXME: <cstdalign> is missing.
module cstdarg {
header "cstdarg"
export *
}
module cstdbool {
header "cstdbool"
export *
}
module cstddef {
header "cstddef"
export *
}
module cstdint {
header "cstdint"
export depr.stdint_h
export *
}
module cstdio {
header "cstdio"
export *
}
module cstdlib {
header "cstdlib"
export *
}
module cstring {
header "cstring"
export *
}
module ctgmath {
header "ctgmath"
export ccomplex
export cmath
export *
}
module ctime {
header "ctime"
export *
}
module cuchar {
header "cuchar"
export *
}
module cwchar {
header "cwchar"
export depr.stdio_h
export *
}
module cwctype {
header "cwctype"
export *
}
}
module algorithm {
header "algorithm"
export initializer_list
export *
module __algorithm {
module adjacent_find { private header "__algorithm/adjacent_find.h" }
module all_of { private header "__algorithm/all_of.h" }
module any_of { private header "__algorithm/any_of.h" }
module binary_search { private header "__algorithm/binary_search.h" }
module clamp { private header "__algorithm/clamp.h" }
module comp { private header "__algorithm/comp.h" }
module comp_ref_type { private header "__algorithm/comp_ref_type.h" }
module copy { private header "__algorithm/copy.h" }
module copy_backward { private header "__algorithm/copy_backward.h" }
module copy_if { private header "__algorithm/copy_if.h" }
module copy_n { private header "__algorithm/copy_n.h" }
module count { private header "__algorithm/count.h" }
module count_if { private header "__algorithm/count_if.h" }
module equal { private header "__algorithm/equal.h" }
module equal_range { private header "__algorithm/equal_range.h" }
module fill { private header "__algorithm/fill.h" }
module fill_n { private header "__algorithm/fill_n.h" }
module find { private header "__algorithm/find.h" }
module find_end { private header "__algorithm/find_end.h" }
module find_first_of { private header "__algorithm/find_first_of.h" }
module find_if { private header "__algorithm/find_if.h" }
module find_if_not { private header "__algorithm/find_if_not.h" }
module for_each { private header "__algorithm/for_each.h" }
module for_each_n { private header "__algorithm/for_each_n.h" }
module generate { private header "__algorithm/generate.h" }
module generate_n { private header "__algorithm/generate_n.h" }
module half_positive { private header "__algorithm/half_positive.h" }
module in_found_result { private header "__algorithm/in_found_result.h" }
module in_fun_result { private header "__algorithm/in_fun_result.h" }
module in_in_out_result { private header "__algorithm/in_in_out_result.h" }
module in_in_result { private header "__algorithm/in_in_result.h" }
module in_out_out_result { private header "__algorithm/in_out_out_result.h" }
module in_out_result { private header "__algorithm/in_out_result.h" }
module includes { private header "__algorithm/includes.h" }
module inplace_merge { private header "__algorithm/inplace_merge.h" }
module is_heap { private header "__algorithm/is_heap.h" }
module is_heap_until { private header "__algorithm/is_heap_until.h" }
module is_partitioned { private header "__algorithm/is_partitioned.h" }
module is_permutation { private header "__algorithm/is_permutation.h" }
module is_sorted { private header "__algorithm/is_sorted.h" }
module is_sorted_until { private header "__algorithm/is_sorted_until.h" }
module iter_swap { private header "__algorithm/iter_swap.h" }
module iterator_operations { private header "__algorithm/iterator_operations.h" }
module lexicographical_compare { private header "__algorithm/lexicographical_compare.h" }
module lower_bound { private header "__algorithm/lower_bound.h" }
module make_heap { private header "__algorithm/make_heap.h" }
module make_projected { private header "__algorithm/make_projected.h" }
module max { private header "__algorithm/max.h" }
module max_element { private header "__algorithm/max_element.h" }
module merge { private header "__algorithm/merge.h" }
module min { private header "__algorithm/min.h" }
module min_element { private header "__algorithm/min_element.h" }
module min_max_result { private header "__algorithm/min_max_result.h" }
module minmax { private header "__algorithm/minmax.h" }
module minmax_element { private header "__algorithm/minmax_element.h" }
module mismatch { private header "__algorithm/mismatch.h" }
module move { private header "__algorithm/move.h" }
module move_backward { private header "__algorithm/move_backward.h" }
module next_permutation { private header "__algorithm/next_permutation.h" }
module none_of { private header "__algorithm/none_of.h" }
module nth_element { private header "__algorithm/nth_element.h" }
module partial_sort { private header "__algorithm/partial_sort.h" }
module partial_sort_copy { private header "__algorithm/partial_sort_copy.h" }
module partition { private header "__algorithm/partition.h" }
module partition_copy { private header "__algorithm/partition_copy.h" }
module partition_point { private header "__algorithm/partition_point.h" }
module pop_heap { private header "__algorithm/pop_heap.h" }
module prev_permutation { private header "__algorithm/prev_permutation.h" }
module push_heap { private header "__algorithm/push_heap.h" }
module ranges_adjacent_find { private header "__algorithm/ranges_adjacent_find.h" }
module ranges_all_of { private header "__algorithm/ranges_all_of.h" }
module ranges_any_of { private header "__algorithm/ranges_any_of.h" }
module ranges_binary_search { private header "__algorithm/ranges_binary_search.h" }
+ module ranges_clamp { private header "__algorithm/ranges_clamp.h" }
module ranges_copy { private header "__algorithm/ranges_copy.h" }
module ranges_copy_backward { private header "__algorithm/ranges_copy_backward.h" }
module ranges_copy_if { private header "__algorithm/ranges_copy_if.h" }
module ranges_copy_n { private header "__algorithm/ranges_copy_n.h" }
module ranges_count { private header "__algorithm/ranges_count.h" }
module ranges_count_if { private header "__algorithm/ranges_count_if.h" }
module ranges_equal { private header "__algorithm/ranges_equal.h" }
module ranges_equal_range { private header "__algorithm/ranges_equal_range.h" }
module ranges_fill { private header "__algorithm/ranges_fill.h" }
module ranges_fill_n { private header "__algorithm/ranges_fill_n.h" }
module ranges_find { private header "__algorithm/ranges_find.h" }
module ranges_find_end { private header "__algorithm/ranges_find_end.h" }
module ranges_find_first_of { private header "__algorithm/ranges_find_first_of.h" }
module ranges_find_if { private header "__algorithm/ranges_find_if.h" }
module ranges_find_if_not { private header "__algorithm/ranges_find_if_not.h" }
module ranges_for_each { private header "__algorithm/ranges_for_each.h" }
module ranges_for_each_n { private header "__algorithm/ranges_for_each_n.h" }
module ranges_generate { private header "__algorithm/ranges_generate.h" }
module ranges_generate_n { private header "__algorithm/ranges_generate_n.h" }
module ranges_includes { private header "__algorithm/ranges_includes.h" }
module ranges_inplace_merge { private header "__algorithm/ranges_inplace_merge.h" }
module ranges_is_heap { private header "__algorithm/ranges_is_heap.h" }
module ranges_is_heap_until { private header "__algorithm/ranges_is_heap_until.h" }
module ranges_is_partitioned { private header "__algorithm/ranges_is_partitioned.h" }
+ module ranges_is_permutation { private header "__algorithm/ranges_is_permutation.h" }
module ranges_is_sorted { private header "__algorithm/ranges_is_sorted.h" }
module ranges_is_sorted_until { private header "__algorithm/ranges_is_sorted_until.h" }
module ranges_iterator_concept { private header "__algorithm/ranges_iterator_concept.h" }
module ranges_lexicographical_compare { private header "__algorithm/ranges_lexicographical_compare.h" }
module ranges_lower_bound { private header "__algorithm/ranges_lower_bound.h" }
module ranges_make_heap { private header "__algorithm/ranges_make_heap.h" }
module ranges_max { private header "__algorithm/ranges_max.h" }
module ranges_max_element { private header "__algorithm/ranges_max_element.h" }
module ranges_merge { private header "__algorithm/ranges_merge.h" }
module ranges_min { private header "__algorithm/ranges_min.h" }
module ranges_min_element { private header "__algorithm/ranges_min_element.h" }
module ranges_minmax { private header "__algorithm/ranges_minmax.h" }
module ranges_minmax_element { private header "__algorithm/ranges_minmax_element.h" }
module ranges_mismatch { private header "__algorithm/ranges_mismatch.h" }
module ranges_move { private header "__algorithm/ranges_move.h" }
module ranges_move_backward { private header "__algorithm/ranges_move_backward.h" }
+ module ranges_next_permutation { private header "__algorithm/ranges_next_permutation.h" }
module ranges_none_of { private header "__algorithm/ranges_none_of.h" }
module ranges_nth_element { private header "__algorithm/ranges_nth_element.h" }
module ranges_partial_sort { private header "__algorithm/ranges_partial_sort.h" }
module ranges_partial_sort_copy { private header "__algorithm/ranges_partial_sort_copy.h" }
module ranges_partition { private header "__algorithm/ranges_partition.h" }
module ranges_partition_copy { private header "__algorithm/ranges_partition_copy.h" }
module ranges_partition_point { private header "__algorithm/ranges_partition_point.h" }
module ranges_pop_heap { private header "__algorithm/ranges_pop_heap.h" }
+ module ranges_prev_permutation { private header "__algorithm/ranges_prev_permutation.h" }
module ranges_push_heap { private header "__algorithm/ranges_push_heap.h" }
module ranges_remove { private header "__algorithm/ranges_remove.h" }
module ranges_remove_copy { private header "__algorithm/ranges_remove_copy.h" }
module ranges_remove_copy_if { private header "__algorithm/ranges_remove_copy_if.h" }
module ranges_remove_if { private header "__algorithm/ranges_remove_if.h" }
module ranges_replace { private header "__algorithm/ranges_replace.h" }
module ranges_replace_copy { private header "__algorithm/ranges_replace_copy.h" }
module ranges_replace_copy_if { private header "__algorithm/ranges_replace_copy_if.h" }
module ranges_replace_if { private header "__algorithm/ranges_replace_if.h" }
module ranges_reverse { private header "__algorithm/ranges_reverse.h" }
module ranges_reverse_copy { private header "__algorithm/ranges_reverse_copy.h" }
+ module ranges_rotate { private header "__algorithm/ranges_rotate.h" }
module ranges_rotate_copy { private header "__algorithm/ranges_rotate_copy.h" }
+ module ranges_sample { private header "__algorithm/ranges_sample.h" }
module ranges_search { private header "__algorithm/ranges_search.h" }
module ranges_search_n { private header "__algorithm/ranges_search_n.h" }
module ranges_set_difference { private header "__algorithm/ranges_set_difference.h" }
module ranges_set_intersection { private header "__algorithm/ranges_set_intersection.h" }
module ranges_set_symmetric_difference { private header "__algorithm/ranges_set_symmetric_difference.h" }
module ranges_set_union { private header "__algorithm/ranges_set_union.h" }
module ranges_shuffle { private header "__algorithm/ranges_shuffle.h" }
module ranges_sort { private header "__algorithm/ranges_sort.h" }
module ranges_sort_heap { private header "__algorithm/ranges_sort_heap.h" }
module ranges_stable_partition { private header "__algorithm/ranges_stable_partition.h" }
module ranges_stable_sort { private header "__algorithm/ranges_stable_sort.h" }
module ranges_swap_ranges { private header "__algorithm/ranges_swap_ranges.h" }
module ranges_transform { private header "__algorithm/ranges_transform.h" }
+ module uniform_random_bit_generator_adaptor {
+ private header "__algorithm/uniform_random_bit_generator_adaptor.h"
+ }
module ranges_unique { private header "__algorithm/ranges_unique.h" }
module ranges_unique_copy { private header "__algorithm/ranges_unique_copy.h" }
module ranges_upper_bound { private header "__algorithm/ranges_upper_bound.h" }
module remove { private header "__algorithm/remove.h" }
module remove_copy { private header "__algorithm/remove_copy.h" }
module remove_copy_if { private header "__algorithm/remove_copy_if.h" }
module remove_if { private header "__algorithm/remove_if.h" }
module replace { private header "__algorithm/replace.h" }
module replace_copy { private header "__algorithm/replace_copy.h" }
module replace_copy_if { private header "__algorithm/replace_copy_if.h" }
module replace_if { private header "__algorithm/replace_if.h" }
module reverse { private header "__algorithm/reverse.h" }
module reverse_copy { private header "__algorithm/reverse_copy.h" }
module rotate { private header "__algorithm/rotate.h" }
module rotate_copy { private header "__algorithm/rotate_copy.h" }
module sample { private header "__algorithm/sample.h" }
module search { private header "__algorithm/search.h" }
module search_n { private header "__algorithm/search_n.h" }
module set_difference { private header "__algorithm/set_difference.h" }
module set_intersection { private header "__algorithm/set_intersection.h" }
module set_symmetric_difference { private header "__algorithm/set_symmetric_difference.h" }
module set_union { private header "__algorithm/set_union.h" }
module shift_left { private header "__algorithm/shift_left.h" }
module shift_right { private header "__algorithm/shift_right.h" }
module shuffle { private header "__algorithm/shuffle.h" }
module sift_down { private header "__algorithm/sift_down.h" }
module sort { private header "__algorithm/sort.h" }
module sort_heap { private header "__algorithm/sort_heap.h" }
module stable_partition { private header "__algorithm/stable_partition.h" }
module stable_sort { private header "__algorithm/stable_sort.h" }
module swap_ranges { private header "__algorithm/swap_ranges.h" }
module transform { private header "__algorithm/transform.h" }
module unique { private header "__algorithm/unique.h" }
module unique_copy { private header "__algorithm/unique_copy.h" }
module unwrap_iter { private header "__algorithm/unwrap_iter.h" }
+ module unwrap_range { private header "__algorithm/unwrap_range.h" }
module upper_bound { private header "__algorithm/upper_bound.h" }
}
}
module any {
header "any"
export *
}
module array {
header "array"
export initializer_list
export *
}
module atomic {
header "atomic"
export *
}
module barrier {
header "barrier"
export *
}
module bit {
header "bit"
export *
module __bit {
module bit_cast { private header "__bit/bit_cast.h" }
module byteswap { private header "__bit/byteswap.h" }
}
}
module bitset {
header "bitset"
export string
export iosfwd
export *
}
// No submodule for cassert. It fundamentally needs repeated, textual inclusion.
module charconv {
header "charconv"
export *
module __charconv {
module chars_format { private header "__charconv/chars_format.h" }
module from_chars_result { private header "__charconv/from_chars_result.h" }
module tables { private header "__charconv/tables.h" }
module to_chars_base_10 { private header "__charconv/to_chars_base_10.h" }
module to_chars_result { private header "__charconv/to_chars_result.h" }
}
}
module chrono {
header "chrono"
export *
module __chrono {
module calendar { private header "__chrono/calendar.h" }
module convert_to_timespec { private header "__chrono/convert_to_timespec.h" }
module day { private header "__chrono/day.h" }
module duration { private header "__chrono/duration.h" }
module file_clock { private header "__chrono/file_clock.h" }
module hh_mm_ss { private header "__chrono/hh_mm_ss.h" }
module high_resolution_clock {
private header "__chrono/high_resolution_clock.h"
export steady_clock
export system_clock
}
module literals { private header "__chrono/literals.h" }
module month { private header "__chrono/month.h" }
module month_weekday { private header "__chrono/month_weekday.h" }
module monthday { private header "__chrono/monthday.h" }
module steady_clock { private header "__chrono/steady_clock.h" }
module system_clock { private header "__chrono/system_clock.h" }
module time_point { private header "__chrono/time_point.h" }
module weekday { private header "__chrono/weekday.h" }
module year { private header "__chrono/year.h" }
module year_month { private header "__chrono/year_month.h" }
module year_month_day { private header "__chrono/year_month_day.h" }
module year_month_weekday { private header "__chrono/year_month_weekday.h" }
}
}
module codecvt {
header "codecvt"
export *
}
module compare {
header "compare"
export *
module __compare {
module common_comparison_category { private header "__compare/common_comparison_category.h" }
module compare_partial_order_fallback { private header "__compare/compare_partial_order_fallback.h" }
module compare_strong_order_fallback { private header "__compare/compare_strong_order_fallback.h" }
module compare_three_way { private header "__compare/compare_three_way.h" }
module compare_three_way_result { private header "__compare/compare_three_way_result.h" }
module compare_weak_order_fallback { private header "__compare/compare_weak_order_fallback.h" }
module is_eq { private header "__compare/is_eq.h" }
module ordering { private header "__compare/ordering.h" }
module partial_order { private header "__compare/partial_order.h" }
module strong_order { private header "__compare/strong_order.h" }
module synth_three_way { private header "__compare/synth_three_way.h" }
module three_way_comparable { private header "__compare/three_way_comparable.h" }
module weak_order { private header "__compare/weak_order.h" }
}
}
module complex {
header "complex"
export *
}
module concepts {
header "concepts"
export *
module __concepts {
module arithmetic { private header "__concepts/arithmetic.h" }
module assignable { private header "__concepts/assignable.h" }
module boolean_testable { private header "__concepts/boolean_testable.h" }
module class_or_enum { private header "__concepts/class_or_enum.h" }
module common_reference_with { private header "__concepts/common_reference_with.h" }
module common_with { private header "__concepts/common_with.h" }
module constructible { private header "__concepts/constructible.h" }
module convertible_to { private header "__concepts/convertible_to.h" }
module copyable { private header "__concepts/copyable.h" }
module derived_from { private header "__concepts/derived_from.h" }
module destructible { private header "__concepts/destructible.h" }
module different_from { private header "__concepts/different_from.h" }
module equality_comparable { private header "__concepts/equality_comparable.h" }
module invocable { private header "__concepts/invocable.h" }
module movable { private header "__concepts/movable.h" }
module predicate { private header "__concepts/predicate.h" }
module regular { private header "__concepts/regular.h" }
module relation { private header "__concepts/relation.h" }
module same_as { private header "__concepts/same_as.h" }
module semiregular { private header "__concepts/semiregular.h" }
module swappable { private header "__concepts/swappable.h" }
module totally_ordered { private header "__concepts/totally_ordered.h" }
}
}
module condition_variable {
header "condition_variable"
export *
}
module coroutine {
requires coroutines
header "coroutine"
export compare
export *
module __coroutine {
module coroutine_handle { private header "__coroutine/coroutine_handle.h" }
module coroutine_traits { private header "__coroutine/coroutine_traits.h" }
module noop_coroutine_handle { private header "__coroutine/noop_coroutine_handle.h" }
module trivial_awaitables { private header "__coroutine/trivial_awaitables.h" }
}
}
module deque {
header "deque"
export initializer_list
export *
}
module exception {
header "exception"
export *
}
module execution {
header "execution"
export *
}
module filesystem {
header "filesystem"
export *
module __filesystem {
module copy_options { private header "__filesystem/copy_options.h" }
module directory_entry { private header "__filesystem/directory_entry.h" }
module directory_iterator { private header "__filesystem/directory_iterator.h" }
module directory_options { private header "__filesystem/directory_options.h" }
module file_status { private header "__filesystem/file_status.h" }
module file_time_type { private header "__filesystem/file_time_type.h" }
module file_type { private header "__filesystem/file_type.h" }
module filesystem_error { private header "__filesystem/filesystem_error.h" }
module operations { private header "__filesystem/operations.h" }
module path { private header "__filesystem/path.h" }
module path_iterator { private header "__filesystem/path_iterator.h" }
module perm_options { private header "__filesystem/perm_options.h" }
module perms { private header "__filesystem/perms.h" }
module recursive_directory_iterator { private header "__filesystem/recursive_directory_iterator.h" }
module space_info { private header "__filesystem/space_info.h" }
module u8path { private header "__filesystem/u8path.h" }
}
}
module format {
header "format"
export *
module __format {
module buffer { private header "__format/buffer.h" }
module concepts { private header "__format/concepts.h" }
module enable_insertable { private header "__format/enable_insertable.h" }
module extended_grapheme_cluster_table { private header "__format/extended_grapheme_cluster_table.h" }
module format_arg { private header "__format/format_arg.h" }
module format_arg_store { private header "__format/format_arg_store.h" }
module format_args { private header "__format/format_args.h" }
module format_context {
private header "__format/format_context.h"
export optional
export locale
}
module format_error { private header "__format/format_error.h" }
module format_fwd { private header "__format/format_fwd.h" }
module format_parse_context { private header "__format/format_parse_context.h" }
module format_string { private header "__format/format_string.h" }
module format_to_n_result { private header "__format/format_to_n_result.h" }
module formatter { private header "__format/formatter.h" }
module formatter_bool { private header "__format/formatter_bool.h" }
module formatter_char { private header "__format/formatter_char.h" }
module formatter_floating_point { private header "__format/formatter_floating_point.h" }
module formatter_integer { private header "__format/formatter_integer.h" }
module formatter_integral { private header "__format/formatter_integral.h" }
module formatter_output { private header "__format/formatter_output.h" }
module formatter_pointer { private header "__format/formatter_pointer.h" }
module formatter_string { private header "__format/formatter_string.h" }
module parser_std_format_spec { private header "__format/parser_std_format_spec.h" }
module unicode { private header "__format/unicode.h" }
}
}
module forward_list {
header "forward_list"
export initializer_list
export *
}
module fstream {
header "fstream"
export *
}
module functional {
header "functional"
export *
module __functional {
module binary_function { private header "__functional/binary_function.h" }
module binary_negate { private header "__functional/binary_negate.h" }
module bind { private header "__functional/bind.h" }
module bind_back { private header "__functional/bind_back.h" }
module bind_front { private header "__functional/bind_front.h" }
module binder1st { private header "__functional/binder1st.h" }
module binder2nd { private header "__functional/binder2nd.h" }
module boyer_moore_searcher { private header "__functional/boyer_moore_searcher.h" }
module compose { private header "__functional/compose.h" }
module default_searcher { private header "__functional/default_searcher.h" }
module function { private header "__functional/function.h" }
module hash { private header "__functional/hash.h" }
module identity { private header "__functional/identity.h" }
module invoke { private header "__functional/invoke.h" }
module is_transparent { private header "__functional/is_transparent.h" }
module mem_fn { private header "__functional/mem_fn.h" }
module mem_fun_ref { private header "__functional/mem_fun_ref.h" }
module not_fn { private header "__functional/not_fn.h" }
module operations { private header "__functional/operations.h" }
module perfect_forward { private header "__functional/perfect_forward.h" }
module pointer_to_binary_function { private header "__functional/pointer_to_binary_function.h" }
module pointer_to_unary_function { private header "__functional/pointer_to_unary_function.h" }
module ranges_operations { private header "__functional/ranges_operations.h" }
module reference_wrapper { private header "__functional/reference_wrapper.h" }
module unary_function { private header "__functional/unary_function.h" }
module unary_negate { private header "__functional/unary_negate.h" }
module unwrap_ref { private header "__functional/unwrap_ref.h" }
module weak_result_type { private header "__functional/weak_result_type.h" }
}
}
module future {
header "future"
export *
}
module initializer_list {
header "initializer_list"
export *
}
module iomanip {
header "iomanip"
export *
}
module ios {
header "ios"
export iosfwd
export *
module __ios {
module fpos { private header "__ios/fpos.h" }
}
}
module iosfwd {
header "iosfwd"
export *
}
module iostream {
header "iostream"
export ios
export streambuf
export istream
export ostream
export *
}
module istream {
header "istream"
// FIXME: should re-export ios, streambuf?
export *
}
module iterator {
header "iterator"
export *
module __iterator {
module access { private header "__iterator/access.h" }
module advance { private header "__iterator/advance.h" }
module back_insert_iterator { private header "__iterator/back_insert_iterator.h" }
module bounded_iter { private header "__iterator/bounded_iter.h" }
module common_iterator { private header "__iterator/common_iterator.h" }
module concepts { private header "__iterator/concepts.h" }
module counted_iterator { private header "__iterator/counted_iterator.h" }
module data { private header "__iterator/data.h" }
module default_sentinel { private header "__iterator/default_sentinel.h" }
module distance { private header "__iterator/distance.h" }
module empty { private header "__iterator/empty.h" }
module erase_if_container { private header "__iterator/erase_if_container.h" }
module front_insert_iterator { private header "__iterator/front_insert_iterator.h" }
module incrementable_traits { private header "__iterator/incrementable_traits.h" }
module indirectly_comparable { private header "__iterator/indirectly_comparable.h" }
module insert_iterator { private header "__iterator/insert_iterator.h" }
module istream_iterator { private header "__iterator/istream_iterator.h" }
module istreambuf_iterator { private header "__iterator/istreambuf_iterator.h" }
module iter_move { private header "__iterator/iter_move.h" }
module iter_swap { private header "__iterator/iter_swap.h" }
module iterator { private header "__iterator/iterator.h" }
module iterator_traits { private header "__iterator/iterator_traits.h" }
module mergeable { private header "__iterator/mergeable.h" }
module move_iterator { private header "__iterator/move_iterator.h" }
module move_sentinel { private header "__iterator/move_sentinel.h" }
module next { private header "__iterator/next.h" }
module ostream_iterator { private header "__iterator/ostream_iterator.h" }
module ostreambuf_iterator {
private header "__iterator/ostreambuf_iterator.h"
export iosfwd
}
module permutable { private header "__iterator/permutable.h" }
module prev { private header "__iterator/prev.h" }
module projected { private header "__iterator/projected.h" }
module readable_traits { private header "__iterator/readable_traits.h" }
module reverse_access { private header "__iterator/reverse_access.h" }
module reverse_iterator { private header "__iterator/reverse_iterator.h" }
module size { private header "__iterator/size.h" }
module sortable { private header "__iterator/sortable.h" }
module unreachable_sentinel { private header "__iterator/unreachable_sentinel.h" }
module wrap_iter { private header "__iterator/wrap_iter.h" }
}
}
module latch {
header "latch"
export *
}
module __debug_utils {
module randomize_range { private header "__debug_utils/randomize_range.h" }
}
module limits {
header "limits"
export *
}
module list {
header "list"
export initializer_list
export *
}
module locale {
header "locale"
export *
}
module map {
header "map"
export initializer_list
export *
}
module memory {
header "memory"
export *
module __memory {
module addressof { private header "__memory/addressof.h" }
module allocate_at_least { private header "__memory/allocate_at_least.h" }
module allocation_guard { private header "__memory/allocation_guard.h" }
module allocator { private header "__memory/allocator.h" }
module allocator_arg_t { private header "__memory/allocator_arg_t.h" }
module allocator_traits { private header "__memory/allocator_traits.h" }
module assume_aligned { private header "__memory/assume_aligned.h" }
module auto_ptr { private header "__memory/auto_ptr.h" }
module compressed_pair { private header "__memory/compressed_pair.h" }
module concepts { private header "__memory/concepts.h" }
module construct_at { private header "__memory/construct_at.h" }
module pointer_traits { private header "__memory/pointer_traits.h" }
module ranges_construct_at { private header "__memory/ranges_construct_at.h" }
module ranges_uninitialized_algorithms { private header "__memory/ranges_uninitialized_algorithms.h" }
module raw_storage_iterator { private header "__memory/raw_storage_iterator.h" }
module shared_ptr { private header "__memory/shared_ptr.h" }
+ module swap_allocator { private header "__memory/swap_allocator.h" }
module temporary_buffer { private header "__memory/temporary_buffer.h" }
module uninitialized_algorithms { private header "__memory/uninitialized_algorithms.h" }
module unique_ptr { private header "__memory/unique_ptr.h" }
module uses_allocator { private header "__memory/uses_allocator.h" }
module voidify { private header "__memory/voidify.h" }
}
}
module mutex {
header "mutex"
export *
}
module new {
header "new"
export *
}
module numbers {
header "numbers"
export *
}
module numeric {
header "numeric"
export *
module __numeric {
module accumulate { private header "__numeric/accumulate.h" }
module adjacent_difference { private header "__numeric/adjacent_difference.h" }
module exclusive_scan { private header "__numeric/exclusive_scan.h" }
module gcd_lcm { private header "__numeric/gcd_lcm.h" }
module inclusive_scan { private header "__numeric/inclusive_scan.h" }
module inner_product { private header "__numeric/inner_product.h" }
module iota { private header "__numeric/iota.h" }
module midpoint { private header "__numeric/midpoint.h" }
module partial_sum { private header "__numeric/partial_sum.h" }
module reduce { private header "__numeric/reduce.h" }
module transform_exclusive_scan { private header "__numeric/transform_exclusive_scan.h" }
module transform_inclusive_scan { private header "__numeric/transform_inclusive_scan.h" }
module transform_reduce { private header "__numeric/transform_reduce.h" }
}
}
module optional {
header "optional"
export *
}
module ostream {
header "ostream"
// FIXME: should re-export ios, streambuf?
export *
}
module queue {
header "queue"
export initializer_list
export *
}
module random {
header "random"
export initializer_list
export *
module __random {
module bernoulli_distribution { private header "__random/bernoulli_distribution.h" }
module binomial_distribution { private header "__random/binomial_distribution.h" }
module cauchy_distribution { private header "__random/cauchy_distribution.h" }
module chi_squared_distribution { private header "__random/chi_squared_distribution.h" }
module clamp_to_integral { private header "__random/clamp_to_integral.h" }
module default_random_engine { private header "__random/default_random_engine.h" }
module discard_block_engine { private header "__random/discard_block_engine.h" }
module discrete_distribution { private header "__random/discrete_distribution.h" }
module exponential_distribution { private header "__random/exponential_distribution.h" }
module extreme_value_distribution { private header "__random/extreme_value_distribution.h" }
module fisher_f_distribution { private header "__random/fisher_f_distribution.h" }
module gamma_distribution { private header "__random/gamma_distribution.h" }
module generate_canonical { private header "__random/generate_canonical.h" }
module geometric_distribution { private header "__random/geometric_distribution.h" }
module independent_bits_engine { private header "__random/independent_bits_engine.h" }
module is_seed_sequence { private header "__random/is_seed_sequence.h" }
module is_valid { private header "__random/is_valid.h" }
module knuth_b { private header "__random/knuth_b.h" }
module linear_congruential_engine { private header "__random/linear_congruential_engine.h" }
module log2 { private header "__random/log2.h" }
module lognormal_distribution { private header "__random/lognormal_distribution.h" }
module mersenne_twister_engine { private header "__random/mersenne_twister_engine.h" }
module negative_binomial_distribution { private header "__random/negative_binomial_distribution.h" }
module normal_distribution { private header "__random/normal_distribution.h" }
module piecewise_constant_distribution { private header "__random/piecewise_constant_distribution.h" }
module piecewise_linear_distribution { private header "__random/piecewise_linear_distribution.h" }
module poisson_distribution { private header "__random/poisson_distribution.h" }
module random_device { private header "__random/random_device.h" }
module ranlux { private header "__random/ranlux.h" }
module seed_seq { private header "__random/seed_seq.h" }
module shuffle_order_engine { private header "__random/shuffle_order_engine.h" }
module student_t_distribution { private header "__random/student_t_distribution.h" }
module subtract_with_carry_engine { private header "__random/subtract_with_carry_engine.h" }
module uniform_int_distribution { private header "__random/uniform_int_distribution.h" }
module uniform_random_bit_generator { private header "__random/uniform_random_bit_generator.h" }
module uniform_real_distribution { private header "__random/uniform_real_distribution.h" }
module weibull_distribution { private header "__random/weibull_distribution.h" }
}
}
module ranges {
header "ranges"
export compare
export initializer_list
export iterator
export *
module __ranges {
module access { private header "__ranges/access.h" }
module all {
private header "__ranges/all.h"
export functional.__functional.compose
export functional.__functional.perfect_forward
}
module common_view { private header "__ranges/common_view.h" }
module concepts { private header "__ranges/concepts.h" }
module copyable_box { private header "__ranges/copyable_box.h" }
module counted {
private header "__ranges/counted.h"
export span
}
module dangling { private header "__ranges/dangling.h" }
module data { private header "__ranges/data.h" }
module drop_view { private header "__ranges/drop_view.h" }
module empty { private header "__ranges/empty.h" }
module empty_view { private header "__ranges/empty_view.h" }
module enable_borrowed_range { private header "__ranges/enable_borrowed_range.h" }
module enable_view { private header "__ranges/enable_view.h" }
module filter_view { private header "__ranges/filter_view.h" }
module iota_view { private header "__ranges/iota_view.h" }
module join_view { private header "__ranges/join_view.h" }
module lazy_split_view { private header "__ranges/lazy_split_view.h" }
module non_propagating_cache { private header "__ranges/non_propagating_cache.h" }
module owning_view { private header "__ranges/owning_view.h" }
module range_adaptor { private header "__ranges/range_adaptor.h" }
module rbegin { private header "__ranges/rbegin.h" }
module ref_view { private header "__ranges/ref_view.h" }
module rend { private header "__ranges/rend.h" }
module reverse_view { private header "__ranges/reverse_view.h" }
module single_view { private header "__ranges/single_view.h" }
module size { private header "__ranges/size.h" }
module subrange { private header "__ranges/subrange.h" }
module take_view { private header "__ranges/take_view.h" }
module transform_view {
private header "__ranges/transform_view.h"
export functional.__functional.bind_back
export functional.__functional.perfect_forward
}
module view_interface { private header "__ranges/view_interface.h" }
module views { private header "__ranges/views.h" }
module zip_view { private header "__ranges/zip_view.h" }
}
}
module ratio {
header "ratio"
export *
}
module regex {
header "regex"
export initializer_list
export *
}
module scoped_allocator {
header "scoped_allocator"
export *
}
module semaphore {
header "semaphore"
export *
}
module set {
header "set"
export initializer_list
export *
}
module shared_mutex {
header "shared_mutex"
export version
}
module span {
header "span"
export ranges.__ranges.enable_borrowed_range
export version
module span_fwd { private header "__fwd/span.h" }
}
module sstream {
header "sstream"
// FIXME: should re-export istream, ostream, ios, streambuf, string?
export *
}
module stack {
header "stack"
export initializer_list
export *
}
module stdexcept {
header "stdexcept"
export *
}
module streambuf {
header "streambuf"
export *
}
module string {
header "string"
export initializer_list
export string_view
module __string {
module char_traits { private header "__string/char_traits.h" }
module extern_template_lists { private header "__string/extern_template_lists.h" }
}
export *
}
module string_view {
header "string_view"
export initializer_list
export *
module string_view_fwd { private header "__fwd/string_view.h" }
}
module strstream {
header "strstream"
export *
}
module system_error {
header "system_error"
export *
}
module thread {
header "thread"
export *
module __thread {
module poll_with_backoff { private header "__thread/poll_with_backoff.h" }
module timed_backoff_policy { private header "__thread/timed_backoff_policy.h" }
}
}
module tuple {
header "tuple"
export *
}
module type_traits {
header "type_traits"
export functional.__functional.unwrap_ref
export *
module add_const { private header "__type_traits/add_const.h" }
module add_cv { private header "__type_traits/add_cv.h" }
module add_lvalue_reference { private header "__type_traits/add_lvalue_reference.h" }
module add_pointer { private header "__type_traits/add_pointer.h" }
module add_rvalue_reference { private header "__type_traits/add_rvalue_reference.h" }
module add_volatile { private header "__type_traits/add_volatile.h" }
+ module aligned_storage { private header "__type_traits/aligned_storage.h" }
+ module aligned_union { private header "__type_traits/aligned_union.h" }
module alignment_of { private header "__type_traits/alignment_of.h" }
module apply_cv { private header "__type_traits/apply_cv.h" }
+ module common_reference { private header "__type_traits/common_reference.h" }
+ module common_type { private header "__type_traits/common_type.h" }
module conditional { private header "__type_traits/conditional.h" }
module conjunction { private header "__type_traits/conjunction.h" }
+ module copy_cv { private header "__type_traits/copy_cv.h" }
+ module copy_cvref { private header "__type_traits/copy_cvref.h" }
module decay { private header "__type_traits/decay.h" }
module disjunction { private header "__type_traits/disjunction.h" }
module enable_if { private header "__type_traits/enable_if.h" }
module extent { private header "__type_traits/extent.h" }
module has_unique_object_representation { private header "__type_traits/has_unique_object_representation.h" }
module has_virtual_destructor { private header "__type_traits/has_virtual_destructor.h" }
module integral_constant { private header "__type_traits/integral_constant.h" }
module is_abstract { private header "__type_traits/is_abstract.h" }
module is_aggregate { private header "__type_traits/is_aggregate.h" }
module is_arithmetic { private header "__type_traits/is_arithmetic.h" }
module is_array { private header "__type_traits/is_array.h" }
module is_assignable { private header "__type_traits/is_assignable.h" }
module is_base_of { private header "__type_traits/is_base_of.h" }
module is_bounded_array { private header "__type_traits/is_bounded_array.h" }
module is_callable { private header "__type_traits/is_callable.h" }
module is_class { private header "__type_traits/is_class.h" }
module is_compound { private header "__type_traits/is_compound.h" }
module is_const { private header "__type_traits/is_const.h" }
module is_constant_evaluated { private header "__type_traits/is_constant_evaluated.h" }
module is_constructible { private header "__type_traits/is_constructible.h" }
module is_convertible { private header "__type_traits/is_convertible.h" }
module is_copy_assignable { private header "__type_traits/is_copy_assignable.h" }
module is_copy_constructible { private header "__type_traits/is_copy_constructible.h" }
module is_core_convertible { private header "__type_traits/is_core_convertible.h" }
module is_default_constructible { private header "__type_traits/is_default_constructible.h" }
module is_destructible { private header "__type_traits/is_destructible.h" }
module is_empty { private header "__type_traits/is_empty.h" }
module is_enum { private header "__type_traits/is_enum.h" }
module is_final { private header "__type_traits/is_final.h" }
module is_floating_point { private header "__type_traits/is_floating_point.h" }
module is_function { private header "__type_traits/is_function.h" }
module is_fundamental { private header "__type_traits/is_fundamental.h" }
module is_integral { private header "__type_traits/is_integral.h" }
module is_literal_type { private header "__type_traits/is_literal_type.h" }
module is_member_function_pointer { private header "__type_traits/is_member_function_pointer.h" }
module is_member_object_pointer { private header "__type_traits/is_member_object_pointer.h" }
module is_member_pointer { private header "__type_traits/is_member_pointer.h" }
module is_move_assignable { private header "__type_traits/is_move_assignable.h" }
module is_move_constructible { private header "__type_traits/is_move_constructible.h" }
module is_nothrow_assignable { private header "__type_traits/is_nothrow_assignable.h" }
module is_nothrow_constructible { private header "__type_traits/is_nothrow_constructible.h" }
+ module is_nothrow_convertible { private header "__type_traits/is_nothrow_convertible.h" }
module is_nothrow_copy_assignable { private header "__type_traits/is_nothrow_copy_assignable.h" }
module is_nothrow_copy_constructible { private header "__type_traits/is_nothrow_copy_constructible.h" }
module is_nothrow_default_constructible { private header "__type_traits/is_nothrow_default_constructible.h" }
module is_nothrow_destructible { private header "__type_traits/is_nothrow_destructible.h" }
module is_nothrow_move_assignable { private header "__type_traits/is_nothrow_move_assignable.h" }
module is_nothrow_move_constructible { private header "__type_traits/is_nothrow_move_constructible.h" }
module is_null_pointer { private header "__type_traits/is_null_pointer.h" }
module is_object { private header "__type_traits/is_object.h" }
module is_pod { private header "__type_traits/is_pod.h" }
module is_pointer { private header "__type_traits/is_pointer.h" }
module is_polymorphic { private header "__type_traits/is_polymorphic.h" }
+ module is_primary_template { private header "__type_traits/is_primary_template.h" }
module is_reference { private header "__type_traits/is_reference.h" }
module is_reference_wrapper { private header "__type_traits/is_reference_wrapper.h" }
module is_referenceable { private header "__type_traits/is_referenceable.h" }
module is_same { private header "__type_traits/is_same.h" }
module is_scalar { private header "__type_traits/is_scalar.h" }
module is_scoped_enum { private header "__type_traits/is_scoped_enum.h" }
module is_signed { private header "__type_traits/is_signed.h" }
+ module is_signed_integer { private header "__type_traits/is_signed_integer.h" }
module is_standard_layout { private header "__type_traits/is_standard_layout.h" }
module is_trivial { private header "__type_traits/is_trivial.h" }
module is_trivially_assignable { private header "__type_traits/is_trivially_assignable.h" }
module is_trivially_constructible { private header "__type_traits/is_trivially_constructible.h" }
module is_trivially_copy_assignable { private header "__type_traits/is_trivially_copy_assignable.h" }
module is_trivially_copy_constructible { private header "__type_traits/is_trivially_copy_constructible.h" }
module is_trivially_copyable { private header "__type_traits/is_trivially_copyable.h" }
module is_trivially_default_constructible { private header "__type_traits/is_trivially_default_constructible.h" }
module is_trivially_destructible { private header "__type_traits/is_trivially_destructible.h" }
module is_trivially_move_assignable { private header "__type_traits/is_trivially_move_assignable.h" }
module is_trivially_move_constructible { private header "__type_traits/is_trivially_move_constructible.h" }
module is_unbounded_array { private header "__type_traits/is_unbounded_array.h" }
module is_union { private header "__type_traits/is_union.h" }
module is_unsigned { private header "__type_traits/is_unsigned.h" }
+ module is_unsigned_integer { private header "__type_traits/is_unsigned_integer.h" }
+ module is_valid_expansion { private header "__type_traits/is_valid_expansion.h" }
module is_void { private header "__type_traits/is_void.h" }
module is_volatile { private header "__type_traits/is_volatile.h" }
+ module lazy { private header "__type_traits/lazy.h" }
+ module make_32_64_or_128_bit { private header "__type_traits/make_32_64_or_128_bit.h" }
+ module make_signed { private header "__type_traits/make_signed.h" }
+ module make_unsigned { private header "__type_traits/make_unsigned.h" }
+ module nat { private header "__type_traits/nat.h" }
module negation { private header "__type_traits/negation.h" }
+ module promote { private header "__type_traits/promote.h" }
module rank { private header "__type_traits/rank.h" }
module remove_all_extents { private header "__type_traits/remove_all_extents.h" }
module remove_const { private header "__type_traits/remove_const.h" }
module remove_cv { private header "__type_traits/remove_cv.h" }
+ module remove_cvref { private header "__type_traits/remove_cvref.h" }
module remove_extent { private header "__type_traits/remove_extent.h" }
module remove_pointer { private header "__type_traits/remove_pointer.h" }
module remove_reference { private header "__type_traits/remove_reference.h" }
module remove_volatile { private header "__type_traits/remove_volatile.h" }
module type_identity { private header "__type_traits/type_identity.h" }
+ module type_list { private header "__type_traits/type_list.h" }
module underlying_type { private header "__type_traits/underlying_type.h" }
module void_t { private header "__type_traits/void_t.h" }
}
module typeindex {
header "typeindex"
export *
}
module typeinfo {
header "typeinfo"
export *
}
module unordered_map {
header "unordered_map"
export initializer_list
export *
}
module unordered_set {
header "unordered_set"
export initializer_list
export *
}
module utility {
header "utility"
export initializer_list
export *
module __utility {
module as_const { private header "__utility/as_const.h" }
module auto_cast { private header "__utility/auto_cast.h" }
module cmp { private header "__utility/cmp.h" }
module declval { private header "__utility/declval.h" }
module exchange { private header "__utility/exchange.h" }
module forward { private header "__utility/forward.h" }
module in_place { private header "__utility/in_place.h" }
module integer_sequence { private header "__utility/integer_sequence.h" }
module move { private header "__utility/move.h" }
module pair { private header "__utility/pair.h" }
module piecewise_construct { private header "__utility/piecewise_construct.h" }
module priority_tag { private header "__utility/priority_tag.h" }
module rel_ops { private header "__utility/rel_ops.h" }
module swap { private header "__utility/swap.h" }
module to_underlying { private header "__utility/to_underlying.h" }
module transaction { private header "__utility/transaction.h" }
module unreachable { private header "__utility/unreachable.h" }
}
}
module valarray {
header "valarray"
export initializer_list
export *
}
module variant {
header "variant"
export *
module __variant {
module monostate { private header "__variant/monostate.h" }
}
}
module vector {
header "vector"
export initializer_list
export *
}
module version {
header "version"
export *
}
// FIXME: These should be private.
module __assert { header "__assert" export * }
module __availability { private header "__availability" export * }
module __bit_reference { private header "__bit_reference" export * }
module __bits { private header "__bits" export * }
module __debug { header "__debug" export * }
module __errc { private header "__errc" export * }
module __hash_table { header "__hash_table" export * }
module __locale {
private header "__locale" export *
}
module __mbstate_t { private header "__mbstate_t.h" export * }
module __mutex_base { private header "__mutex_base" export * }
module __node_handle { private header "__node_handle" export * }
module __split_buffer { private header "__split_buffer" export * }
module __std_stream {
private header "__std_stream" export *
}
module __threading_support { header "__threading_support" export * }
module __tree { header "__tree" export * }
module __tuple { private header "__tuple" export * }
module __undef_macros { header "__undef_macros" export * }
+ module __verbose_abort { header "__verbose_abort" export * }
module experimental {
requires cplusplus11
module algorithm {
header "experimental/algorithm"
export *
}
module coroutine {
requires coroutines
header "experimental/coroutine"
export *
}
module deque {
header "experimental/deque"
export *
}
module forward_list {
header "experimental/forward_list"
export *
}
module functional {
header "experimental/functional"
export *
}
module iterator {
header "experimental/iterator"
export *
}
module list {
header "experimental/list"
export *
}
module map {
header "experimental/map"
export *
}
module memory_resource {
header "experimental/memory_resource"
export *
}
module propagate_const {
header "experimental/propagate_const"
export *
}
module regex {
header "experimental/regex"
export *
}
module simd {
header "experimental/simd"
export *
}
module set {
header "experimental/set"
export *
}
module span {
header "span"
export *
}
module string {
header "experimental/string"
export *
}
module type_traits {
header "experimental/type_traits"
export *
}
module unordered_map {
header "experimental/unordered_map"
export *
}
module unordered_set {
header "experimental/unordered_set"
export *
}
module utility {
header "experimental/utility"
export *
}
module vector {
header "experimental/vector"
export *
}
// FIXME these should be private
module __memory {
header "experimental/__memory"
export *
}
} // end experimental
}
diff --git a/lib/libclang_rt/compiler-rt-vars.mk b/lib/libclang_rt/compiler-rt-vars.mk
index c2ba71ed302f..b7be63f7e990 100644
--- a/lib/libclang_rt/compiler-rt-vars.mk
+++ b/lib/libclang_rt/compiler-rt-vars.mk
@@ -1,25 +1,25 @@
-CLANG_SUBDIR=clang/15.0.0
+CLANG_SUBDIR=clang/15.0.3
CLANGDIR= /usr/lib/${CLANG_SUBDIR}
SANITIZER_LIBDIR= ${CLANGDIR}/lib/freebsd
SANITIZER_SHAREDIR= ${CLANGDIR}/share
# armv[67] is a bit special since we allow a soft-floating version via
# CPUTYPE matching *soft*. This variant may not actually work though.
.if ${MACHINE_ARCH:Marmv[67]*} != "" && \
(!defined(CPUTYPE) || ${CPUTYPE:M*soft*} == "")
CRTARCH?= armhf
.else
CRTARCH?= ${MACHINE_ARCH:S/amd64/x86_64/:C/hf$//:C/sf$//:S/mipsn32/mips64/}
.endif
.if ${COMPILER_TYPE} == "clang"
# The only way to set the path to the sanitizer libraries with clang is to
# override the resource directory.
# Note: lib/freebsd is automatically appended to the -resource-dir value.
SANITIZER_LDFLAGS= -resource-dir=${SYSROOT}${CLANGDIR}
# Also set RPATH to ensure that the dynamically linked runtime libs are found.
SANITIZER_LDFLAGS+= -Wl,--enable-new-dtags
SANITIZER_LDFLAGS+= -Wl,-rpath,${SANITIZER_LIBDIR}
.else
.error "Unknown link flags for -fsanitize=... COMPILER_TYPE=${COMPILER_TYPE}"
.endif
diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc
index 41ef67bb8a77..d5d6858ff24a 100644
--- a/tools/build/mk/OptionalObsoleteFiles.inc
+++ b/tools/build/mk/OptionalObsoleteFiles.inc
@@ -1,10197 +1,10197 @@
#
# $FreeBSD$
#
# This file adds support for the WITHOUT_* and WITH_* knobs in src.conf(5) to
# the check-old* and delete-old* targets.
#
.if ${MK_ACCT} == no
OLD_FILES+=etc/rc.d/accounting
OLD_FILES+=etc/periodic/daily/310.accounting
OLD_FILES+=usr/sbin/accton
OLD_FILES+=usr/sbin/sa
OLD_FILES+=usr/share/man/man8/accton.8.gz
OLD_FILES+=usr/share/man/man8/sa.8.gz
OLD_FILES+=usr/tests/usr.sbin/sa/Kyuafile
OLD_FILES+=usr/tests/usr.sbin/sa/legacy_test
OLD_FILES+=usr/tests/usr.sbin/sa/v1-amd64-sav.in
OLD_FILES+=usr/tests/usr.sbin/sa/v1-amd64-sav.out
OLD_FILES+=usr/tests/usr.sbin/sa/v1-amd64-u.out
OLD_FILES+=usr/tests/usr.sbin/sa/v1-amd64-usr.in
OLD_FILES+=usr/tests/usr.sbin/sa/v1-amd64-usr.out
OLD_FILES+=usr/tests/usr.sbin/sa/v1-i386-sav.in
OLD_FILES+=usr/tests/usr.sbin/sa/v1-i386-sav.out
OLD_FILES+=usr/tests/usr.sbin/sa/v1-i386-u.out
OLD_FILES+=usr/tests/usr.sbin/sa/v1-i386-usr.in
OLD_FILES+=usr/tests/usr.sbin/sa/v1-i386-usr.out
OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-sav.in
OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-sav.out
OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-u.out
OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-usr.in
OLD_FILES+=usr/tests/usr.sbin/sa/v1-sparc64-usr.out
OLD_FILES+=usr/tests/usr.sbin/sa/v2-amd64-sav.in
OLD_FILES+=usr/tests/usr.sbin/sa/v2-amd64-u.out
OLD_FILES+=usr/tests/usr.sbin/sa/v2-amd64-usr.in
OLD_FILES+=usr/tests/usr.sbin/sa/v2-i386-sav.in
OLD_FILES+=usr/tests/usr.sbin/sa/v2-i386-u.out
OLD_FILES+=usr/tests/usr.sbin/sa/v2-i386-usr.in
OLD_FILES+=usr/tests/usr.sbin/sa/v2-sparc64-sav.in
OLD_FILES+=usr/tests/usr.sbin/sa/v2-sparc64-u.out
OLD_FILES+=usr/tests/usr.sbin/sa/v2-sparc64-usr.in
OLD_DIRS+=usr/tests/usr.sbin/sa
.endif
.if ${MK_ACPI} == no
OLD_FILES+=etc/devd/asus.conf
OLD_FILES+=etc/rc.d/power_profile
OLD_FILES+=usr/sbin/acpiconf
OLD_FILES+=usr/sbin/acpidb
OLD_FILES+=usr/sbin/acpidump
OLD_FILES+=usr/sbin/iasl
OLD_FILES+=usr/share/man/man8/acpiconf.8.gz
OLD_FILES+=usr/share/man/man8/acpidb.8.gz
OLD_FILES+=usr/share/man/man8/acpidump.8.gz
OLD_FILES+=usr/share/man/man8/iasl.8.gz
.endif
.if ${MK_ACPI} == no && ${MK_APM} == no
OLD_FILES+=etc/rc.d/powerd
.endif
.if ${MK_APM} == no
OLD_FILES+=etc/rc.d/apm
OLD_FILES+=etc/rc.d/apmd
OLD_FILES+=etc/apmd.conf
OLD_FILES+=usr/sbin/apm
OLD_FILES+=usr/share/examples/etc/apmd.conf
OLD_FILES+=usr/share/man/man8/amd64/apm.8.gz
OLD_FILES+=usr/share/man/man8/amd64/apmconf.8.gz
.endif
.if ${MK_AT} == no
OLD_FILES+=etc/pam.d/atrun
OLD_FILES+=usr/bin/at
OLD_FILES+=usr/bin/atq
OLD_FILES+=usr/bin/atrm
OLD_FILES+=usr/bin/batch
OLD_FILES+=usr/libexec/atrun
OLD_FILES+=usr/share/man/man1/at.1.gz
OLD_FILES+=usr/share/man/man1/atq.1.gz
OLD_FILES+=usr/share/man/man1/atrm.1.gz
OLD_FILES+=usr/share/man/man1/batch.1.gz
OLD_FILES+=usr/share/man/man8/atrun.8.gz
.endif
.if ${MK_ATM} == no
OLD_FILES+=usr/bin/sscop
OLD_FILES+=usr/include/netnatm/addr.h
OLD_FILES+=usr/include/netnatm/api/atmapi.h
OLD_FILES+=usr/include/netnatm/api/ccatm.h
OLD_FILES+=usr/include/netnatm/api/unisap.h
OLD_DIRS+=usr/include/netnatm/api
OLD_FILES+=usr/include/netnatm/msg/uni_config.h
OLD_FILES+=usr/include/netnatm/msg/uni_hdr.h
OLD_FILES+=usr/include/netnatm/msg/uni_ie.h
OLD_FILES+=usr/include/netnatm/msg/uni_msg.h
OLD_FILES+=usr/include/netnatm/msg/unimsglib.h
OLD_FILES+=usr/include/netnatm/msg/uniprint.h
OLD_FILES+=usr/include/netnatm/msg/unistruct.h
OLD_DIRS+=usr/include/netnatm/msg
OLD_FILES+=usr/include/netnatm/saal/sscfu.h
OLD_FILES+=usr/include/netnatm/saal/sscfudef.h
OLD_FILES+=usr/include/netnatm/saal/sscop.h
OLD_FILES+=usr/include/netnatm/saal/sscopdef.h
OLD_DIRS+=usr/include/netnatm/saal
OLD_FILES+=usr/include/netnatm/sig/uni.h
OLD_FILES+=usr/include/netnatm/sig/unidef.h
OLD_FILES+=usr/include/netnatm/sig/unisig.h
OLD_DIRS+=usr/include/netnatm/sig
OLD_FILES+=usr/include/netnatm/unimsg.h
OLD_FILES+=usr/lib/libngatm.a
OLD_FILES+=usr/lib/libngatm.so
OLD_LIBS+=usr/lib/libngatm.so.4
OLD_FILES+=usr/lib/libngatm_p.a
OLD_FILES+=usr/share/man/man1/sscop.1.gz
OLD_FILES+=usr/share/man/man3/libngatm.3.gz
OLD_FILES+=usr/share/man/man3/uniaddr.3.gz
OLD_FILES+=usr/share/man/man3/unifunc.3.gz
OLD_FILES+=usr/share/man/man3/unimsg.3.gz
OLD_FILES+=usr/share/man/man3/unisap.3.gz
OLD_FILES+=usr/share/man/man3/unistruct.3.gz
.endif
.if ${MK_AUDIT} == no
OLD_FILES+=etc/rc.d/auditd
OLD_FILES+=etc/rc.d/auditdistd
OLD_FILES+=usr/sbin/audit
OLD_FILES+=usr/sbin/auditd
OLD_FILES+=usr/sbin/auditdistd
OLD_FILES+=usr/sbin/auditreduce
OLD_FILES+=usr/sbin/praudit
OLD_FILES+=usr/share/man/man1/auditreduce.1.gz
OLD_FILES+=usr/share/man/man1/praudit.1.gz
OLD_FILES+=usr/share/man/man5/auditdistd.conf.5.gz
OLD_FILES+=usr/share/man/man8/audit.8.gz
OLD_FILES+=usr/share/man/man8/auditd.8.gz
OLD_FILES+=usr/share/man/man8/auditdistd.8.gz
OLD_FILES+=usr/tests/sys/audit/process-control
OLD_FILES+=usr/tests/sys/audit/open
OLD_FILES+=usr/tests/sys/audit/network
OLD_FILES+=usr/tests/sys/audit/miscellaneous
OLD_FILES+=usr/tests/sys/audit/Kyuafile
OLD_FILES+=usr/tests/sys/audit/ioctl
OLD_FILES+=usr/tests/sys/audit/inter-process
OLD_FILES+=usr/tests/sys/audit/file-write
OLD_FILES+=usr/tests/sys/audit/file-read
OLD_FILES+=usr/tests/sys/audit/file-delete
OLD_FILES+=usr/tests/sys/audit/file-create
OLD_FILES+=usr/tests/sys/audit/file-close
OLD_FILES+=usr/tests/sys/audit/file-attribute-modify
OLD_FILES+=usr/tests/sys/audit/file-attribute-access
OLD_FILES+=usr/tests/sys/audit/administrative
OLD_DIRS+=usr/tests/sys/audit
.endif
.if ${MK_AUTHPF} == no
OLD_FILES+=usr/sbin/authpf
OLD_FILES+=usr/sbin/authpf-noip
OLD_FILES+=usr/share/man/man8/authpf.8.gz
OLD_FILES+=usr/share/man/man8/authpf-noip.8.gz
.endif
.if ${MK_AUTOFS} == no
OLD_FILES+=etc/autofs/include_ldap
OLD_FILES+=etc/autofs/special_hosts
OLD_FILES+=etc/autofs/special_media
OLD_FILES+=etc/autofs/special_noauto
OLD_FILES+=etc/autofs/special_null
OLD_FILES+=etc/auto_master
OLD_FILES+=etc/rc.d/automount
OLD_FILES+=etc/rc.d/automountd
OLD_FILES+=etc/rc.d/autounmountd
OLD_FILES+=usr/sbin/automount
OLD_FILES+=usr/sbin/automountd
OLD_FILES+=usr/sbin/autounmountd
OLD_FILES+=usr/share/man/man5/autofs.5.gz
OLD_FILES+=usr/share/man/man5/auto_master.5.gz
OLD_FILES+=usr/share/man/man8/automount.8.gz
OLD_FILES+=usr/share/man/man8/automountd.8.gz
OLD_FILES+=usr/share/man/man8/autounmountd.8.gz
OLD_DIRS+=etc/autofs
.endif
.if ${MK_BHYVE} == no
OLD_FILES+=usr/lib/libvmmapi.a
OLD_FILES+=usr/lib/libvmmapi.so
OLD_LIBS+=usr/lib/libvmmapi.so.5
OLD_FILES+=usr/include/vmmapi.h
OLD_FILES+=usr/sbin/bhyve
OLD_FILES+=usr/sbin/bhyvectl
OLD_FILES+=usr/sbin/bhyveload
OLD_FILES+=usr/share/examples/bhyve/vmrun.sh
OLD_FILES+=usr/share/man/man8/bhyve.8.gz
OLD_FILES+=usr/share/man/man8/bhyveload.8.gz
OLD_DIRS+=usr/share/examples/bhyve
.endif
.if !defined(WITH_PORT_BASE_BINUTILS)
.if ${MK_LLD_IS_LD} == no
OLD_FILES+=usr/bin/ld
OLD_FILES+=usr/share/man/man1/ld.1.gz
.endif
.endif
.if ${MK_BLACKLIST} == no
OLD_FILES+=etc/blacklistd.conf
OLD_FILES+=etc/rc.d/blacklistd
OLD_FILES+=usr/include/blacklist.h
OLD_FILES+=usr/lib/libblacklist.a
OLD_FILES+=usr/lib/libblacklist_p.a
OLD_FILES+=usr/lib/libblacklist.so
OLD_LIBS+=usr/lib/libblacklist.so.0
OLD_FILES+=usr/libexec/blacklistd-helper
OLD_FILES+=usr/sbin/blacklistctl
OLD_FILES+=usr/sbin/blacklistd
OLD_FILES+=usr/share/man/man3/blacklist.3.gz
OLD_FILES+=usr/share/man/man3/blacklist_close.3.gz
OLD_FILES+=usr/share/man/man3/blacklist_open.3.gz
OLD_FILES+=usr/share/man/man3/blacklist_r.3.gz
OLD_FILES+=usr/share/man/man3/blacklist_sa.3.gz
OLD_FILES+=usr/share/man/man3/blacklist_sa_r.3.gz
OLD_FILES+=usr/share/man/man5/blacklistd.conf.5.gz
OLD_FILES+=usr/share/man/man8/blacklistctl.8.gz
OLD_FILES+=usr/share/man/man8/blacklistd.8.gz
.endif
.if ${MK_BLUETOOTH} == no
OLD_FILES+=etc/bluetooth/hcsecd.conf
OLD_FILES+=etc/bluetooth/hosts
OLD_FILES+=etc/bluetooth/protocols
OLD_FILES+=etc/defaults/bluetooth.device.conf
OLD_FILES+=etc/devd/iwmbtfw.conf
OLD_DIRS+=etc/bluetooth
OLD_FILES+=etc/rc.d/bluetooth
OLD_FILES+=etc/rc.d/bthidd
OLD_FILES+=etc/rc.d/hcsecd
OLD_FILES+=etc/rc.d/rfcomm_pppd_server
OLD_FILES+=etc/rc.d/sdpd
OLD_FILES+=etc/rc.d/ubthidhci
OLD_FILES+=usr/bin/bthost
OLD_FILES+=usr/bin/btsockstat
OLD_FILES+=usr/bin/rfcomm_sppd
OLD_FILES+=usr/include/bluetooth.h
OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_bluetooth.h
OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_bt3c.h
OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket.h
OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket_hci_raw.h
OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket_l2cap.h
OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket_rfcomm.h
OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket_sco.h
OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_h4.h
OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_hci.h
OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_l2cap.h
OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_ubt.h
OLD_DIRS+=usr/include/netgraph/bluetooth/include
OLD_DIRS+=usr/include/netgraph/bluetooth
OLD_FILES+=usr/include/sdp.h
OLD_FILES+=usr/lib/libbluetooth.a
OLD_FILES+=usr/lib/libbluetooth.so
OLD_LIBS+=usr/lib/libbluetooth.so.4
OLD_FILES+=usr/lib/libbluetooth_p.a
OLD_FILES+=usr/lib/libsdp.a
OLD_FILES+=usr/lib/libsdp.so
OLD_LIBS+=usr/lib/libsdp.so.4
OLD_FILES+=usr/lib/libsdp_p.a
OLD_FILES+=usr/sbin/ath3kfw
OLD_FILES+=usr/sbin/bcmfw
OLD_FILES+=usr/sbin/bluetooth-config
OLD_FILES+=usr/sbin/bt3cfw
OLD_FILES+=usr/sbin/bthidcontrol
OLD_FILES+=usr/sbin/bthidd
OLD_FILES+=usr/sbin/btpand
OLD_FILES+=usr/sbin/hccontrol
OLD_FILES+=usr/sbin/hcsecd
OLD_FILES+=usr/sbin/hcseriald
OLD_FILES+=usr/sbin/iwmbtfw
OLD_FILES+=usr/sbin/l2control
OLD_FILES+=usr/sbin/l2ping
OLD_FILES+=usr/sbin/rfcomm_pppd
OLD_FILES+=usr/sbin/sdpcontrol
OLD_FILES+=usr/sbin/sdpd
OLD_FILES+=usr/share/examples/etc/defaults/bluetooth.device.conf
OLD_FILES+=usr/share/man/man1/bthost.1.gz
OLD_FILES+=usr/share/man/man1/btsockstat.1.gz
OLD_FILES+=usr/share/man/man1/rfcomm_sppd.1.gz
OLD_FILES+=usr/share/man/man3/SDP_GET128.3.gz
OLD_FILES+=usr/share/man/man3/SDP_GET16.3.gz
OLD_FILES+=usr/share/man/man3/SDP_GET32.3.gz
OLD_FILES+=usr/share/man/man3/SDP_GET64.3.gz
OLD_FILES+=usr/share/man/man3/SDP_GET8.3.gz
OLD_FILES+=usr/share/man/man3/SDP_PUT128.3.gz
OLD_FILES+=usr/share/man/man3/SDP_PUT16.3.gz
OLD_FILES+=usr/share/man/man3/SDP_PUT32.3.gz
OLD_FILES+=usr/share/man/man3/SDP_PUT64.3.gz
OLD_FILES+=usr/share/man/man3/SDP_PUT8.3.gz
OLD_FILES+=usr/share/man/man3/bdaddr_any.3.gz
OLD_FILES+=usr/share/man/man3/bdaddr_copy.3.gz
OLD_FILES+=usr/share/man/man3/bdaddr_same.3.gz
OLD_FILES+=usr/share/man/man3/bluetooth.3.gz
OLD_FILES+=usr/share/man/man3/bt_aton.3.gz
OLD_FILES+=usr/share/man/man3/bt_devaddr.3.gz
OLD_FILES+=usr/share/man/man3/bt_devclose.3.gz
OLD_FILES+=usr/share/man/man3/bt_devenum.3.gz
OLD_FILES+=usr/share/man/man3/bt_devfilter.3.gz
OLD_FILES+=usr/share/man/man3/bt_devfilter_evt_clr.3.gz
OLD_FILES+=usr/share/man/man3/bt_devfilter_evt_set.3.gz
OLD_FILES+=usr/share/man/man3/bt_devfilter_evt_tst.3.gz
OLD_FILES+=usr/share/man/man3/bt_devfilter_pkt_clr.3.gz
OLD_FILES+=usr/share/man/man3/bt_devfilter_pkt_set.3.gz
OLD_FILES+=usr/share/man/man3/bt_devfilter_pkt_tst.3.gz
OLD_FILES+=usr/share/man/man3/bt_devinfo.3.gz
OLD_FILES+=usr/share/man/man3/bt_devinquiry.3.gz
OLD_FILES+=usr/share/man/man3/bt_devname.3.gz
OLD_FILES+=usr/share/man/man3/bt_devopen.3.gz
OLD_FILES+=usr/share/man/man3/bt_devreq.3.gz
OLD_FILES+=usr/share/man/man3/bt_devsend.3.gz
OLD_FILES+=usr/share/man/man3/bt_endhostent.3.gz
OLD_FILES+=usr/share/man/man3/bt_endprotoent.3.gz
OLD_FILES+=usr/share/man/man3/bt_gethostbyaddr.3.gz
OLD_FILES+=usr/share/man/man3/bt_gethostbyname.3.gz
OLD_FILES+=usr/share/man/man3/bt_gethostent.3.gz
OLD_FILES+=usr/share/man/man3/bt_getprotobyname.3.gz
OLD_FILES+=usr/share/man/man3/bt_getprotobynumber.3.gz
OLD_FILES+=usr/share/man/man3/bt_getprotoent.3.gz
OLD_FILES+=usr/share/man/man3/bt_ntoa.3.gz
OLD_FILES+=usr/share/man/man3/bt_sethostent.3.gz
OLD_FILES+=usr/share/man/man3/bt_setprotoent.3.gz
OLD_FILES+=usr/share/man/man3/sdp.3.gz
OLD_FILES+=usr/share/man/man3/sdp_attr2desc.3.gz
OLD_FILES+=usr/share/man/man3/sdp_change_service.3.gz
OLD_FILES+=usr/share/man/man3/sdp_close.3.gz
OLD_FILES+=usr/share/man/man3/sdp_error.3.gz
OLD_FILES+=usr/share/man/man3/sdp_open.3.gz
OLD_FILES+=usr/share/man/man3/sdp_open_local.3.gz
OLD_FILES+=usr/share/man/man3/sdp_register_service.3.gz
OLD_FILES+=usr/share/man/man3/sdp_search.3.gz
OLD_FILES+=usr/share/man/man3/sdp_unregister_service.3.gz
OLD_FILES+=usr/share/man/man3/sdp_uuid2desc.3.gz
OLD_FILES+=usr/share/man/man4/ng_bluetooth.4.gz
OLD_FILES+=usr/share/man/man5/bluetooth.device.conf.5.gz
OLD_FILES+=usr/share/man/man5/bluetooth.hosts.5.gz
OLD_FILES+=usr/share/man/man5/bluetooth.protocols.5.gz
OLD_FILES+=usr/share/man/man5/hcsecd.conf.5.gz
OLD_FILES+=usr/share/man/man8/ath3kfw.8.gz
OLD_FILES+=usr/share/man/man8/bcmfw.8.gz
OLD_FILES+=usr/share/man/man8/bluetooth-config.8.gz
OLD_FILES+=usr/share/man/man8/bt3cfw.8.gz
OLD_FILES+=usr/share/man/man8/bthidcontrol.8.gz
OLD_FILES+=usr/share/man/man8/bthidd.8.gz
OLD_FILES+=usr/share/man/man8/btpand.8.gz
OLD_FILES+=usr/share/man/man8/hccontrol.8.gz
OLD_FILES+=usr/share/man/man8/hcsecd.8.gz
OLD_FILES+=usr/share/man/man8/hcseriald.8.gz
OLD_FILES+=usr/share/man/man8/iwmbtfw.8.gz
OLD_FILES+=usr/share/man/man8/l2control.8.gz
OLD_FILES+=usr/share/man/man8/l2ping.8.gz
OLD_FILES+=usr/share/man/man8/rfcomm_pppd.8.gz
OLD_FILES+=usr/share/man/man8/sdpcontrol.8.gz
OLD_FILES+=usr/share/man/man8/sdpd.8.gz
.endif
.if ${MK_BOOT} == no
OLD_FILES+=boot/beastie.4th
OLD_FILES+=boot/boot
OLD_FILES+=boot/boot0
OLD_FILES+=boot/boot0sio
OLD_FILES+=boot/boot1
OLD_FILES+=boot/boot1.efi
OLD_FILES+=boot/boot2
OLD_FILES+=boot/brand.4th
OLD_FILES+=boot/cdboot
OLD_FILES+=boot/check-password.4th
OLD_FILES+=boot/color.4th
OLD_FILES+=boot/defaults/loader.conf
OLD_FILES+=boot/delay.4th
OLD_FILES+=boot/device.hints
OLD_FILES+=boot/frames.4th
OLD_FILES+=boot/gptboot
OLD_FILES+=boot/gptzfsboot
OLD_FILES+=boot/loader
OLD_FILES+=boot/loader.4th
OLD_FILES+=boot/loader.efi
OLD_FILES+=boot/loader.help
OLD_FILES+=boot/loader.rc
OLD_FILES+=boot/mbr
OLD_FILES+=boot/menu-commands.4th
OLD_FILES+=boot/menu.4th
OLD_FILES+=boot/menu.rc
OLD_FILES+=boot/menusets.4th
OLD_FILES+=boot/pcibios.4th
OLD_FILES+=boot/pmbr
OLD_FILES+=boot/pxeboot
OLD_FILES+=boot/screen.4th
OLD_FILES+=boot/shortcuts.4th
OLD_FILES+=boot/support.4th
OLD_FILES+=boot/userboot.so
OLD_FILES+=boot/version.4th
OLD_FILES+=boot/zfsboot
OLD_FILES+=boot/zfsloader
OLD_FILES+=usr/lib/kgzldr.o
OLD_FILES+=usr/share/man/man5/loader.conf.5.gz
OLD_FILES+=usr/share/man/man8/beastie.4th.8.gz
OLD_FILES+=usr/share/man/man8/brand.4th.8.gz
OLD_FILES+=usr/share/man/man8/check-password.4th.8.gz
OLD_FILES+=usr/share/man/man8/color.4th.8.gz
OLD_FILES+=usr/share/man/man8/delay.4th.8.gz
OLD_FILES+=usr/share/man/man8/gptboot.8.gz
OLD_FILES+=usr/share/man/man8/gptzfsboot.8.gz
OLD_FILES+=usr/share/man/man8/loader.4th.8.gz
OLD_FILES+=usr/share/man/man8/loader.8.gz
OLD_FILES+=usr/share/man/man8/menu.4th.8.gz
OLD_FILES+=usr/share/man/man8/menusets.4th.8.gz
OLD_FILES+=usr/share/man/man8/pxeboot.8.gz
OLD_FILES+=usr/share/man/man8/version.4th.8.gz
OLD_FILES+=usr/share/man/man8/zfsboot.8.gz
OLD_FILES+=usr/share/man/man8/zfsloader.8.gz
.endif
.if ${MK_BOOTPARAMD} == no
OLD_FILES+=etc/rc.d/bootparams
OLD_FILES+=usr/sbin/bootparamd
OLD_FILES+=usr/share/man/man5/bootparams.5.gz
OLD_FILES+=usr/share/man/man8/bootparamd.8.gz
OLD_FILES+=usr/sbin/callbootd
.endif
.if ${MK_BOOTPD} == no
OLD_FILES+=usr/libexec/bootpd
OLD_FILES+=usr/share/man/man5/bootptab.5.gz
OLD_FILES+=usr/share/man/man8/bootpd.8.gz
OLD_FILES+=usr/libexec/bootpgw
OLD_FILES+=usr/sbin/bootpef
OLD_FILES+=usr/share/man/man8/bootpef.8.gz
OLD_FILES+=usr/sbin/bootptest
OLD_FILES+=usr/share/man/man8/bootptest.8.gz
.endif
.if ${MK_BSD_CPIO} == no
OLD_FILES+=usr/bin/bsdcpio
OLD_FILES+=usr/bin/cpio
OLD_FILES+=usr/share/man/man1/bsdcpio.1.gz
OLD_FILES+=usr/share/man/man1/cpio.1.gz
.endif
.if ${MK_BSDINSTALL} == no
OLD_FILES+=usr/libexec/bsdinstall/adduser
OLD_FILES+=usr/libexec/bsdinstall/auto
OLD_FILES+=usr/libexec/bsdinstall/autopart
OLD_FILES+=usr/libexec/bsdinstall/bootconfig
OLD_FILES+=usr/libexec/bsdinstall/checksum
OLD_FILES+=usr/libexec/bsdinstall/config
OLD_FILES+=usr/libexec/bsdinstall/distextract
OLD_FILES+=usr/libexec/bsdinstall/distfetch
OLD_FILES+=usr/libexec/bsdinstall/docsinstall
OLD_FILES+=usr/libexec/bsdinstall/entropy
OLD_FILES+=usr/libexec/bsdinstall/hardening
OLD_FILES+=usr/libexec/bsdinstall/hostname
OLD_FILES+=usr/libexec/bsdinstall/jail
OLD_FILES+=usr/libexec/bsdinstall/keymap
OLD_FILES+=usr/libexec/bsdinstall/mirrorselect
OLD_FILES+=usr/libexec/bsdinstall/mount
OLD_FILES+=usr/libexec/bsdinstall/netconfig
OLD_FILES+=usr/libexec/bsdinstall/netconfig_ipv4
OLD_FILES+=usr/libexec/bsdinstall/netconfig_ipv6
OLD_FILES+=usr/libexec/bsdinstall/partedit
OLD_FILES+=usr/libexec/bsdinstall/rootpass
OLD_FILES+=usr/libexec/bsdinstall/script
OLD_FILES+=usr/libexec/bsdinstall/scriptedpart
OLD_FILES+=usr/libexec/bsdinstall/services
OLD_FILES+=usr/libexec/bsdinstall/time
OLD_FILES+=usr/libexec/bsdinstall/umount
OLD_FILES+=usr/libexec/bsdinstall/wlanconfig
OLD_FILES+=usr/libexec/bsdinstall/zfsboot
OLD_FILES+=usr/sbin/bsdinstall
OLD_FILES+=usr/share/man/man8/bsdinstall.8.gz
OLD_FILES+=usr/share/man/man8/sade.8.gz
OLD_DIRS+=usr/libexec/bsdinstall
.endif
.if ${MK_BSNMP} == no
OLD_FILES+=etc/snmpd.config
OLD_FILES+=etc/rc.d/bsnmpd
OLD_FILES+=usr/bin/bsnmpget
OLD_FILES+=usr/bin/bsnmpset
OLD_FILES+=usr/bin/bsnmpwalk
OLD_FILES+=usr/include/bsnmp/asn1.h
OLD_FILES+=usr/include/bsnmp/bridge_snmp.h
OLD_FILES+=usr/include/bsnmp/snmp.h
OLD_FILES+=usr/include/bsnmp/snmp_mibII.h
OLD_FILES+=usr/include/bsnmp/snmp_netgraph.h
OLD_FILES+=usr/include/bsnmp/snmpagent.h
OLD_FILES+=usr/include/bsnmp/snmpclient.h
OLD_FILES+=usr/include/bsnmp/snmpmod.h
OLD_FILES+=usr/lib/libbsnmp.a
OLD_FILES+=usr/lib/libbsnmp.so
OLD_LIBS+=usr/lib/libbsnmp.so.6
OLD_FILES+=usr/lib/libbsnmp_p.a
OLD_FILES+=usr/lib/libbsnmptools.a
OLD_FILES+=usr/lib/libbsnmptools.so
OLD_LIBS+=usr/lib/libbsnmptools.so.0
OLD_FILES+=usr/lib/libbsnmptools_p.a
OLD_FILES+=usr/lib/snmp_bridge.so
OLD_LIBS+=usr/lib/snmp_bridge.so.6
OLD_FILES+=usr/lib/snmp_hast.so
OLD_LIBS+=usr/lib/snmp_hast.so.6
OLD_FILES+=usr/lib/snmp_hostres.so
OLD_LIBS+=usr/lib/snmp_hostres.so.6
OLD_FILES+=usr/lib/snmp_lm75.so
OLD_LIBS+=usr/lib/snmp_lm75.so.6
OLD_FILES+=usr/lib/snmp_mibII.so
OLD_LIBS+=usr/lib/snmp_mibII.so.6
OLD_FILES+=usr/lib/snmp_netgraph.so
OLD_LIBS+=usr/lib/snmp_netgraph.so.6
OLD_FILES+=usr/lib/snmp_pf.so
OLD_LIBS+=usr/lib/snmp_pf.so.6
OLD_FILES+=usr/lib/snmp_target.so
OLD_LIBS+=usr/lib/snmp_target.so.6
OLD_FILES+=usr/lib/snmp_usm.so
OLD_LIBS+=usr/lib/snmp_usm.so.6
OLD_FILES+=usr/lib/snmp_vacm.so
OLD_LIBS+=usr/lib/snmp_vacm.so.6
OLD_FILES+=usr/lib/snmp_wlan.so
OLD_LIBS+=usr/lib/snmp_wlan.so.6
OLD_FILES+=usr/sbin/bsnmpd
OLD_FILES+=usr/sbin/gensnmptree
OLD_FILES+=usr/share/examples/etc/snmpd.config
OLD_FILES+=usr/share/man/man1/bsnmpd.1.gz
OLD_FILES+=usr/share/man/man1/bsnmpget.1.gz
OLD_FILES+=usr/share/man/man1/bsnmpset.1.gz
OLD_FILES+=usr/share/man/man1/bsnmpwalk.1.gz
OLD_FILES+=usr/share/man/man1/gensnmptree.1.gz
# lib/libbsnmp/libbsnmp
OLD_FILES+=usr/share/man/man3/TRUTH_GET.3.gz
OLD_FILES+=usr/share/man/man3/TRUTH_MK.3.gz
OLD_FILES+=usr/share/man/man3/TRUTH_OK.3.gz
OLD_FILES+=usr/share/man/man3/asn1.3.gz
OLD_FILES+=usr/share/man/man3/asn_append_oid.3.gz
OLD_FILES+=usr/share/man/man3/asn_commit_header.3.gz
OLD_FILES+=usr/share/man/man3/asn_compare_oid.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_counter64_raw.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_header.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_integer.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_integer_raw.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_ipaddress.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_ipaddress_raw.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_null.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_null_raw.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_objid.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_objid_raw.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_octetstring.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_octetstring_raw.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_sequence.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_timeticks.3.gz
OLD_FILES+=usr/share/man/man3/asn_get_uint32_raw.3.gz
OLD_FILES+=usr/share/man/man3/asn_is_suboid.3.gz
OLD_FILES+=usr/share/man/man3/asn_oid2str.3.gz
OLD_FILES+=usr/share/man/man3/asn_oid2str_r.3.gz
OLD_FILES+=usr/share/man/man3/asn_put_counter64.3.gz
OLD_FILES+=usr/share/man/man3/asn_put_exception.3.gz
OLD_FILES+=usr/share/man/man3/asn_put_header.3.gz
OLD_FILES+=usr/share/man/man3/asn_put_integer.3.gz
OLD_FILES+=usr/share/man/man3/asn_put_ipaddress.3.gz
OLD_FILES+=usr/share/man/man3/asn_put_null.3.gz
OLD_FILES+=usr/share/man/man3/asn_put_objid.3.gz
OLD_FILES+=usr/share/man/man3/asn_put_octetstring.3.gz
OLD_FILES+=usr/share/man/man3/asn_put_temp_header.3.gz
OLD_FILES+=usr/share/man/man3/asn_put_timeticks.3.gz
OLD_FILES+=usr/share/man/man3/asn_put_uint32.3.gz
OLD_FILES+=usr/share/man/man3/asn_skip.3.gz
OLD_FILES+=usr/share/man/man3/asn_slice_oid.3.gz
OLD_FILES+=usr/share/man/man3/snmp_add_binding.3.gz
OLD_FILES+=usr/share/man/man3/snmp_calc_keychange.3.gz
OLD_FILES+=usr/share/man/man3/snmp_client.3.gz
OLD_FILES+=usr/share/man/man3/snmp_client_init.3.gz
OLD_FILES+=usr/share/man/man3/snmp_client_set_host.3.gz
OLD_FILES+=usr/share/man/man3/snmp_client_set_port.3.gz
OLD_FILES+=usr/share/man/man3/snmp_close.3.gz
OLD_FILES+=usr/share/man/man3/snmp_debug.3.gz
OLD_FILES+=usr/share/man/man3/snmp_dep_commit.3.gz
OLD_FILES+=usr/share/man/man3/snmp_dep_finish.3.gz
OLD_FILES+=usr/share/man/man3/snmp_dep_lookup.3.gz
OLD_FILES+=usr/share/man/man3/snmp_dep_rollback.3.gz
OLD_FILES+=usr/share/man/man3/snmp_depop_t.3.gz
OLD_FILES+=usr/share/man/man3/snmp_dialog.3.gz
OLD_FILES+=usr/share/man/man3/snmp_discover_engine.3.gz
OLD_FILES+=usr/share/man/man3/snmp_get.3.gz
OLD_FILES+=usr/share/man/man3/snmp_get_local_keys.3.gz
OLD_FILES+=usr/share/man/man3/snmp_getbulk.3.gz
OLD_FILES+=usr/share/man/man3/snmp_getnext.3.gz
OLD_FILES+=usr/share/man/man3/snmp_init_context.3.gz
OLD_FILES+=usr/share/man/man3/snmp_make_errresp.3.gz
OLD_FILES+=usr/share/man/man3/snmp_oid_append.3.gz
OLD_FILES+=usr/share/man/man3/snmp_op_t.3.gz
OLD_FILES+=usr/share/man/man3/snmp_open.3.gz
OLD_FILES+=usr/share/man/man3/snmp_parse_server.3.gz
OLD_FILES+=usr/share/man/man3/snmp_passwd_to_keys.3.gz
OLD_FILES+=usr/share/man/man3/snmp_pdu_check.3.gz
OLD_FILES+=usr/share/man/man3/snmp_pdu_create.3.gz
OLD_FILES+=usr/share/man/man3/snmp_pdu_decode.3.gz
OLD_FILES+=usr/share/man/man3/snmp_pdu_decode_header.3.gz
OLD_FILES+=usr/share/man/man3/snmp_pdu_decode_scoped.3.gz
OLD_FILES+=usr/share/man/man3/snmp_pdu_decode_secmode.3.gz
OLD_FILES+=usr/share/man/man3/snmp_pdu_dump.3.gz
OLD_FILES+=usr/share/man/man3/snmp_pdu_encode.3.gz
OLD_FILES+=usr/share/man/man3/snmp_pdu_free.3.gz
OLD_FILES+=usr/share/man/man3/snmp_pdu_init_secparams.3.gz
OLD_FILES+=usr/share/man/man3/snmp_pdu_send.3.gz
OLD_FILES+=usr/share/man/man3/snmp_receive.3.gz
OLD_FILES+=usr/share/man/man3/snmp_send_cb_f.3.gz
OLD_FILES+=usr/share/man/man3/snmp_set.3.gz
OLD_FILES+=usr/share/man/man3/snmp_table_cb_f.3.gz
OLD_FILES+=usr/share/man/man3/snmp_table_fetch.3.gz
OLD_FILES+=usr/share/man/man3/snmp_table_fetch_async.3.gz
OLD_FILES+=usr/share/man/man3/snmp_timeout_cb_f.3.gz
OLD_FILES+=usr/share/man/man3/snmp_timeout_start_f.3.gz
OLD_FILES+=usr/share/man/man3/snmp_timeout_stop_f.3.gz
OLD_FILES+=usr/share/man/man3/snmp_trace.3.gz
OLD_FILES+=usr/share/man/man3/snmp_value_copy.3.gz
OLD_FILES+=usr/share/man/man3/snmp_value_free.3.gz
OLD_FILES+=usr/share/man/man3/snmp_value_parse.3.gz
OLD_FILES+=usr/share/man/man3/tree_size.3.gz
# usr.sbin/bsnmpd/bsnmpd
OLD_FILES+=usr/share/man/man3/FIND_OBJECT_INT.3.gz
OLD_FILES+=usr/share/man/man3/FIND_OBJECT_INT_LINK.3.gz
OLD_FILES+=usr/share/man/man3/FIND_OBJECT_INT_LINK_INDEX.3.gz
OLD_FILES+=usr/share/man/man3/FIND_OBJECT_OID.3.gz
OLD_FILES+=usr/share/man/man3/FIND_OBJECT_OID_LINK.3.gz
OLD_FILES+=usr/share/man/man3/FIND_OBJECT_OID_LINK_INDEX.3.gz
OLD_FILES+=usr/share/man/man3/INSERT_OBJECT_INT.3.gz
OLD_FILES+=usr/share/man/man3/INSERT_OBJECT_INT_LINK.3.gz
OLD_FILES+=usr/share/man/man3/INSERT_OBJECT_INT_LINK_INDEX.3.gz
OLD_FILES+=usr/share/man/man3/INSERT_OBJECT_OID.3.gz
OLD_FILES+=usr/share/man/man3/INSERT_OBJECT_OID_LINK.3.gz
OLD_FILES+=usr/share/man/man3/INSERT_OBJECT_OID_LINK_INDEX.3.gz
OLD_FILES+=usr/share/man/man3/NEXT_OBJECT_INT.3.gz
OLD_FILES+=usr/share/man/man3/NEXT_OBJECT_INT_LINK.3.gz
OLD_FILES+=usr/share/man/man3/NEXT_OBJECT_INT_LINK_INDEX.3.gz
OLD_FILES+=usr/share/man/man3/NEXT_OBJECT_OID.3.gz
OLD_FILES+=usr/share/man/man3/NEXT_OBJECT_OID_LINK.3.gz
OLD_FILES+=usr/share/man/man3/NEXT_OBJECT_OID_LINK_INDEX.3.gz
OLD_FILES+=usr/share/man/man3/asn1.3.gz
OLD_FILES+=usr/share/man/man3/bsnmpagent.3.gz
OLD_FILES+=usr/share/man/man3/bsnmpclient.3.gz
OLD_FILES+=usr/share/man/man3/bsnmpd_get_target_stats.3.gz
OLD_FILES+=usr/share/man/man3/bsnmpd_get_usm_stats.3.gz
OLD_FILES+=usr/share/man/man3/bsnmpd_reset_usm_stats.3.gz
OLD_FILES+=usr/share/man/man3/bsnmplib.3.gz
OLD_FILES+=usr/share/man/man3/buf_alloc.3.gz
OLD_FILES+=usr/share/man/man3/buf_size.3.gz
OLD_FILES+=usr/share/man/man3/comm_define.3.gz
OLD_FILES+=usr/share/man/man3/community.3.gz
OLD_FILES+=usr/share/man/man3/fd_deselect.3.gz
OLD_FILES+=usr/share/man/man3/fd_resume.3.gz
OLD_FILES+=usr/share/man/man3/fd_select.3.gz
OLD_FILES+=usr/share/man/man3/fd_suspend.3.gz
OLD_FILES+=usr/share/man/man3/get_ticks.3.gz
OLD_FILES+=usr/share/man/man3/index_append.3.gz
OLD_FILES+=usr/share/man/man3/index_append_off.3.gz
OLD_FILES+=usr/share/man/man3/index_compare.3.gz
OLD_FILES+=usr/share/man/man3/index_compare_off.3.gz
OLD_FILES+=usr/share/man/man3/index_decode.3.gz
OLD_FILES+=usr/share/man/man3/ip_commit.3.gz
OLD_FILES+=usr/share/man/man3/ip_get.3.gz
OLD_FILES+=usr/share/man/man3/ip_rollback.3.gz
OLD_FILES+=usr/share/man/man3/ip_save.3.gz
OLD_FILES+=usr/share/man/man3/or_register.3.gz
OLD_FILES+=usr/share/man/man3/or_unregister.3.gz
OLD_FILES+=usr/share/man/man3/oid_commit.3.gz
OLD_FILES+=usr/share/man/man3/oid_get.3.gz
OLD_FILES+=usr/share/man/man3/oid_rollback.3.gz
OLD_FILES+=usr/share/man/man3/oid_save.3.gz
OLD_FILES+=usr/share/man/man3/oid_usmNotInTimeWindows.3.gz
OLD_FILES+=usr/share/man/man3/oid_usmUnknownEngineIDs.3.gz
OLD_FILES+=usr/share/man/man3/oid_zeroDotZero.3.gz
OLD_FILES+=usr/share/man/man3/reqid_allocate.3.gz
OLD_FILES+=usr/share/man/man3/reqid_base.3.gz
OLD_FILES+=usr/share/man/man3/reqid_istype.3.gz
OLD_FILES+=usr/share/man/man3/reqid_next.3.gz
OLD_FILES+=usr/share/man/man3/reqid_type.3.gz
OLD_FILES+=usr/share/man/man3/snmp_bridge.3.gz
OLD_FILES+=usr/share/man/man3/snmp_hast.3.gz
OLD_FILES+=usr/share/man/man3/snmp_hostres.3.gz
OLD_FILES+=usr/share/man/man3/snmp_input_finish.3.gz
OLD_FILES+=usr/share/man/man3/snmp_input_start.3.gz
OLD_FILES+=usr/share/man/man3/snmp_lm75.3.gz
OLD_FILES+=usr/share/man/man3/snmp_mibII.3.gz
OLD_FILES+=usr/share/man/man3/snmp_netgraph.3.gz
OLD_FILES+=usr/share/man/man3/snmp_output.3.gz
OLD_FILES+=usr/share/man/man3/snmp_pdu_auth_access.3.gz
OLD_FILES+=usr/share/man/man3/snmp_send_port.3.gz
OLD_FILES+=usr/share/man/man3/snmp_send_trap.3.gz
OLD_FILES+=usr/share/man/man3/snmp_target.3.gz
OLD_FILES+=usr/share/man/man3/snmp_usm.3.gz
OLD_FILES+=usr/share/man/man3/snmp_vacm.3.gz
OLD_FILES+=usr/share/man/man3/snmp_wlan.3.gz
OLD_FILES+=usr/share/man/man3/snmpd_target_stat.3.gz
OLD_FILES+=usr/share/man/man3/snmpd_usmstats.3.gz
OLD_FILES+=usr/share/man/man3/snmpmod.3.gz
OLD_FILES+=usr/share/man/man3/start_tick.3.gz
OLD_FILES+=usr/share/man/man3/string_commit.3.gz
OLD_FILES+=usr/share/man/man3/string_free.3.gz
OLD_FILES+=usr/share/man/man3/string_get.3.gz
OLD_FILES+=usr/share/man/man3/string_get_max.3.gz
OLD_FILES+=usr/share/man/man3/string_rollback.3.gz
OLD_FILES+=usr/share/man/man3/string_save.3.gz
OLD_FILES+=usr/share/man/man3/systemg.3.gz
OLD_FILES+=usr/share/man/man3/this_tick.3.gz
OLD_FILES+=usr/share/man/man3/timer_start.3.gz
OLD_FILES+=usr/share/man/man3/timer_start_repeat.3.gz
OLD_FILES+=usr/share/man/man3/timer_stop.3.gz
OLD_FILES+=usr/share/man/man3/target_activate_address.3.gz
OLD_FILES+=usr/share/man/man3/target_address.3.gz
OLD_FILES+=usr/share/man/man3/target_delete_address.3.gz
OLD_FILES+=usr/share/man/man3/target_delete_notify.3.gz
OLD_FILES+=usr/share/man/man3/target_delete_param.3.gz
OLD_FILES+=usr/share/man/man3/target_first_address.3.gz
OLD_FILES+=usr/share/man/man3/target_first_notify.3.gz
OLD_FILES+=usr/share/man/man3/target_first_param.3.gz
OLD_FILES+=usr/share/man/man3/target_flush_all.3.gz
OLD_FILES+=usr/share/man/man3/target_next_address.3.gz
OLD_FILES+=usr/share/man/man3/target_next_notify.3.gz
OLD_FILES+=usr/share/man/man3/target_next_param.3.gz
OLD_FILES+=usr/share/man/man3/target_new_address.3.gz
OLD_FILES+=usr/share/man/man3/target_new_notify.3.gz
OLD_FILES+=usr/share/man/man3/target_new_param.3.gz
OLD_FILES+=usr/share/man/man3/target_notify.3.gz
OLD_FILES+=usr/share/man/man3/target_param.3.gz
OLD_FILES+=usr/share/man/man3/usm_delete_user.3.gz
OLD_FILES+=usr/share/man/man3/usm_find_user.3.gz
OLD_FILES+=usr/share/man/man3/usm_first_user.3.gz
OLD_FILES+=usr/share/man/man3/usm_flush_users.3.gz
OLD_FILES+=usr/share/man/man3/usm_next_user.3.gz
OLD_FILES+=usr/share/man/man3/usm_new_user.3.gz
OLD_FILES+=usr/share/man/man3/usm_user.3.gz
OLD_FILES+=usr/share/snmp/defs/bridge_tree.def
OLD_FILES+=usr/share/snmp/defs/hast_tree.def
OLD_FILES+=usr/share/snmp/defs/hostres_tree.def
OLD_FILES+=usr/share/snmp/defs/lm75_tree.def
OLD_FILES+=usr/share/snmp/defs/mibII_tree.def
OLD_FILES+=usr/share/snmp/defs/netgraph_tree.def
OLD_FILES+=usr/share/snmp/defs/pf_tree.def
OLD_FILES+=usr/share/snmp/defs/target_tree.def
OLD_FILES+=usr/share/snmp/defs/tc.def
OLD_FILES+=usr/share/snmp/defs/tree.def
OLD_FILES+=usr/share/snmp/defs/usm_tree.def
OLD_FILES+=usr/share/snmp/defs/vacm_tree.def
OLD_FILES+=usr/share/snmp/defs/wlan_tree.def
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM-FREEBSD-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-BRIDGE-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-HAST-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-HOSTRES-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-IP-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-LM75-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-MIB2-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-NETGRAPH.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-PF-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-SNMPD.txt
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-WIRELESS-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/BRIDGE-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/FOKUS-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/FREEBSD-MIB.txt
OLD_FILES+=usr/share/snmp/mibs/RSTP-MIB.txt
OLD_DIRS+=usr/include/bsnmp
OLD_DIRS+=usr/share/snmp
OLD_DIRS+=usr/share/snmp/defs
OLD_DIRS+=usr/share/snmp/mibs
.endif
.if ${MK_CALENDAR} == no
OLD_FILES+=etc/periodic/daily/300.calendar
OLD_FILES+=usr/bin/calendar
OLD_FILES+=usr/share/calendar/calendar.all
OLD_FILES+=usr/share/calendar/calendar.australia
OLD_FILES+=usr/share/calendar/calendar.birthday
OLD_FILES+=usr/share/calendar/calendar.brazilian
OLD_FILES+=usr/share/calendar/calendar.christian
OLD_FILES+=usr/share/calendar/calendar.computer
OLD_FILES+=usr/share/calendar/calendar.croatian
OLD_FILES+=usr/share/calendar/calendar.dutch
OLD_FILES+=usr/share/calendar/calendar.freebsd
OLD_FILES+=usr/share/calendar/calendar.french
OLD_FILES+=usr/share/calendar/calendar.german
OLD_FILES+=usr/share/calendar/calendar.history
OLD_FILES+=usr/share/calendar/calendar.holiday
OLD_FILES+=usr/share/calendar/calendar.hungarian
OLD_FILES+=usr/share/calendar/calendar.judaic
OLD_FILES+=usr/share/calendar/calendar.lotr
OLD_FILES+=usr/share/calendar/calendar.music
OLD_FILES+=usr/share/calendar/calendar.newzealand
OLD_FILES+=usr/share/calendar/calendar.russian
OLD_FILES+=usr/share/calendar/calendar.southafrica
OLD_FILES+=usr/share/calendar/calendar.ukrainian
OLD_FILES+=usr/share/calendar/calendar.usholiday
OLD_FILES+=usr/share/calendar/calendar.world
OLD_FILES+=usr/share/calendar/de_AT.ISO_8859-15/calendar.feiertag
OLD_DIRS+=usr/share/calendar/de_AT.ISO_8859-15
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.all
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.feiertag
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.geschichte
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.kirche
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.literatur
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.musik
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.wissenschaft
OLD_DIRS+=usr/share/calendar/de_DE.ISO8859-1
OLD_FILES+=usr/share/calendar/de_DE.ISO8859-15
OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.all
OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.fetes
OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.french
OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.jferies
OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.proverbes
OLD_DIRS+=usr/share/calendar/fr_FR.ISO8859-1
OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-15
OLD_FILES+=usr/share/calendar/hr_HR.ISO8859-2/calendar.all
OLD_FILES+=usr/share/calendar/hr_HR.ISO8859-2/calendar.praznici
OLD_DIRS+=usr/share/calendar/hr_HR.ISO8859-2
OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.all
OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.nevnapok
OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.unnepek
OLD_DIRS+=usr/share/calendar/hu_HU.ISO8859-2
OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.all
OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.commemorative
OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.holidays
OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.mcommemorative
OLD_DIRS+=usr/share/calendar/pt_BR.ISO8859-1
OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.all
OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.commemorative
OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.holidays
OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.mcommemorative
OLD_DIRS+=usr/share/calendar/pt_BR.UTF-8
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.all
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.common
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.holiday
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.military
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.orthodox
OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.pagan
OLD_DIRS+=usr/share/calendar/ru_RU.KOI8-R
OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.all
OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.common
OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.holiday
OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.military
OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.orthodox
OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.pagan
OLD_DIRS+=usr/share/calendar/ru_RU.UTF-8
OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.all
OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.holiday
OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.misc
OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.orthodox
OLD_DIRS+=usr/share/calendar/uk_UA.KOI8-U
OLD_DIRS+=usr/share/calendar
OLD_FILES+=usr/share/man/man1/calendar.1.gz
OLD_FILES+=usr/tests/usr.bin/calendar/Kyuafile
OLD_FILES+=usr/tests/usr.bin/calendar/calendar.calibrate
OLD_FILES+=usr/tests/usr.bin/calendar/legacy_test
OLD_FILES+=usr/tests/usr.bin/calendar/regress.a1.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.a2.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.a3.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.a4.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.a5.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.b1.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.b2.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.b3.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.b4.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.b5.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.s1.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.s2.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.s3.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.s4.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.sh
OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-1.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-2.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-3.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-4.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-5.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-6.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-7.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-1.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-2.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-3.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-4.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-5.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-6.out
OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-7.out
OLD_DIRS+=usr/tests/usr.bin/calendar
.endif
.if ${MK_CASPER} == no
OLD_LIBS+=lib/libcasper.so.1
OLD_LIBS+=lib/casper/libcap_dns.so.2
OLD_LIBS+=lib/casper/libcap_fileargs.so.1
OLD_LIBS+=lib/casper/libcap_grp.so.1
OLD_LIBS+=lib/casper/libcap_net.so.1
OLD_LIBS+=lib/casper/libcap_pwd.so.1
OLD_LIBS+=lib/casper/libcap_sysctl.so.1
OLD_LIBS+=lib/casper/libcap_sysctl.so.2
OLD_LIBS+=lib/casper/libcap_syslog.so.1
.endif
.if ${MK_CCD} == no
OLD_FILES+=etc/rc.d/ccd
OLD_FILES+=rescue/ccdconfig
OLD_FILES+=sbin/ccdconfig
OLD_FILES+=usr/share/man/man4/ccd.4.gz
OLD_FILES+=usr/share/man/man8/ccdconfig.8.gz
.endif
.if ${MK_CDDL} == no
OLD_LIBS+=lib/libavl.so.2
OLD_LIBS+=lib/libctf.so.2
OLD_LIBS+=lib/libdtrace.so.2
OLD_LIBS+=lib/libnvpair.so.2
OLD_LIBS+=lib/libumem.so.2
OLD_LIBS+=lib/libuutil.so.2
OLD_FILES+=usr/bin/ctfconvert
OLD_FILES+=usr/bin/ctfdump
OLD_FILES+=usr/bin/ctfmerge
OLD_FILES+=usr/lib/dtrace/drti.o
OLD_FILES+=usr/lib/dtrace/errno.d
OLD_FILES+=usr/lib/dtrace/io.d
OLD_FILES+=usr/lib/dtrace/ip.d
OLD_FILES+=usr/lib/dtrace/mbuf.d
OLD_FILES+=usr/lib/dtrace/psinfo.d
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/lib/dtrace/regs_x86.d
.endif
OLD_FILES+=usr/lib/dtrace/sctp.d
OLD_FILES+=usr/lib/dtrace/siftr.d
OLD_FILES+=usr/lib/dtrace/signal.d
OLD_FILES+=usr/lib/dtrace/socket.d
OLD_FILES+=usr/lib/dtrace/tcp.d
OLD_FILES+=usr/lib/dtrace/udp.d
OLD_FILES+=usr/lib/dtrace/udplite.d
OLD_FILES+=usr/lib/dtrace/unistd.d
OLD_FILES+=usr/lib/libavl.a
OLD_FILES+=usr/lib/libavl.so
OLD_FILES+=usr/lib/libavl_p.a
OLD_FILES+=usr/lib/libctf.a
OLD_FILES+=usr/lib/libctf.so
OLD_FILES+=usr/lib/libctf_p.a
OLD_FILES+=usr/lib/libdtrace.a
OLD_FILES+=usr/lib/libdtrace.so
OLD_FILES+=usr/lib/libdtrace_p.a
OLD_FILES+=usr/lib/libnvpair.a
OLD_FILES+=usr/lib/libnvpair.so
OLD_FILES+=usr/lib/libnvpair_p.a
OLD_FILES+=usr/lib/libumem.a
OLD_FILES+=usr/lib/libumem.so
OLD_FILES+=usr/lib/libumem_p.a
OLD_FILES+=usr/lib/libuutil.a
OLD_FILES+=usr/lib/libuutil.so
OLD_FILES+=usr/lib/libuutil_p.a
OLD_LIBS+=lib/libdtrace.so.2
OLD_FILES+=usr/libexec/dwatch/chmod
OLD_FILES+=usr/libexec/dwatch/errno
OLD_FILES+=usr/libexec/dwatch/fchmodat
OLD_FILES+=usr/libexec/dwatch/io
OLD_FILES+=usr/libexec/dwatch/io-done
OLD_FILES+=usr/libexec/dwatch/io-start
OLD_FILES+=usr/libexec/dwatch/ip
OLD_FILES+=usr/libexec/dwatch/ip-receive
OLD_FILES+=usr/libexec/dwatch/ip-send
OLD_FILES+=usr/libexec/dwatch/kill
OLD_FILES+=usr/libexec/dwatch/lchmod
OLD_FILES+=usr/libexec/dwatch/nanosleep
OLD_FILES+=usr/libexec/dwatch/open
OLD_FILES+=usr/libexec/dwatch/openat
OLD_FILES+=usr/libexec/dwatch/proc
OLD_FILES+=usr/libexec/dwatch/proc-create
OLD_FILES+=usr/libexec/dwatch/proc-exec
OLD_FILES+=usr/libexec/dwatch/proc-exec-failure
OLD_FILES+=usr/libexec/dwatch/proc-exec-success
OLD_FILES+=usr/libexec/dwatch/proc-exit
OLD_FILES+=usr/libexec/dwatch/proc-signal
OLD_FILES+=usr/libexec/dwatch/proc-signal-clear
OLD_FILES+=usr/libexec/dwatch/proc-signal-discard
OLD_FILES+=usr/libexec/dwatch/proc-signal-send
OLD_FILES+=usr/libexec/dwatch/proc-status
OLD_FILES+=usr/libexec/dwatch/read
OLD_FILES+=usr/libexec/dwatch/recv
OLD_FILES+=usr/libexec/dwatch/recvfrom
OLD_FILES+=usr/libexec/dwatch/recvmsg
OLD_FILES+=usr/libexec/dwatch/rw
OLD_FILES+=usr/libexec/dwatch/sched
OLD_FILES+=usr/libexec/dwatch/sched-change-pri
OLD_FILES+=usr/libexec/dwatch/sched-cpu
OLD_FILES+=usr/libexec/dwatch/sched-dequeue
OLD_FILES+=usr/libexec/dwatch/sched-enqueue
OLD_FILES+=usr/libexec/dwatch/sched-exec
OLD_FILES+=usr/libexec/dwatch/sched-lend-pri
OLD_FILES+=usr/libexec/dwatch/sched-load-change
OLD_FILES+=usr/libexec/dwatch/sched-off-cpu
OLD_FILES+=usr/libexec/dwatch/sched-on-cpu
OLD_FILES+=usr/libexec/dwatch/sched-preempt
OLD_FILES+=usr/libexec/dwatch/sched-pri
OLD_FILES+=usr/libexec/dwatch/sched-queue
OLD_FILES+=usr/libexec/dwatch/sched-remain-cpu
OLD_FILES+=usr/libexec/dwatch/sched-sleep
OLD_FILES+=usr/libexec/dwatch/sched-surrender
OLD_FILES+=usr/libexec/dwatch/sched-tick
OLD_FILES+=usr/libexec/dwatch/sched-wakeup
OLD_FILES+=usr/libexec/dwatch/send
OLD_FILES+=usr/libexec/dwatch/sendmsg
OLD_FILES+=usr/libexec/dwatch/sendrecv
OLD_FILES+=usr/libexec/dwatch/sendto
OLD_FILES+=usr/libexec/dwatch/systop
OLD_FILES+=usr/libexec/dwatch/tcp
OLD_FILES+=usr/libexec/dwatch/tcp-accept
OLD_FILES+=usr/libexec/dwatch/tcp-accept-established
OLD_FILES+=usr/libexec/dwatch/tcp-accept-refused
OLD_FILES+=usr/libexec/dwatch/tcp-connect
OLD_FILES+=usr/libexec/dwatch/tcp-connect-established
OLD_FILES+=usr/libexec/dwatch/tcp-connect-refused
OLD_FILES+=usr/libexec/dwatch/tcp-connect-request
OLD_FILES+=usr/libexec/dwatch/tcp-established
OLD_FILES+=usr/libexec/dwatch/tcp-init
OLD_FILES+=usr/libexec/dwatch/tcp-io
OLD_FILES+=usr/libexec/dwatch/tcp-receive
OLD_FILES+=usr/libexec/dwatch/tcp-refused
OLD_FILES+=usr/libexec/dwatch/tcp-send
OLD_FILES+=usr/libexec/dwatch/tcp-state-change
OLD_FILES+=usr/libexec/dwatch/tcp-status
OLD_FILES+=usr/libexec/dwatch/udp
OLD_FILES+=usr/libexec/dwatch/udp-receive
OLD_FILES+=usr/libexec/dwatch/udp-send
OLD_FILES+=usr/libexec/dwatch/udplite
OLD_FILES+=usr/libexec/dwatch/udplite-receive
OLD_FILES+=usr/libexec/dwatch/udplite-send
OLD_FILES+=usr/libexec/dwatch/vop_create
OLD_FILES+=usr/libexec/dwatch/vop_lookup
OLD_FILES+=usr/libexec/dwatch/vop_mkdir
OLD_FILES+=usr/libexec/dwatch/vop_mknod
OLD_FILES+=usr/libexec/dwatch/vop_readdir
OLD_FILES+=usr/libexec/dwatch/vop_remove
OLD_FILES+=usr/libexec/dwatch/vop_rename
OLD_FILES+=usr/libexec/dwatch/vop_rmdir
OLD_FILES+=usr/libexec/dwatch/vop_symlink
OLD_FILES+=usr/libexec/dwatch/write
OLD_FILES+=usr/sbin/dtrace
OLD_FILES+=usr/sbin/dwatch
OLD_FILES+=usr/sbin/lockstat
OLD_FILES+=usr/sbin/plockstat
OLD_FILES+=usr/share/man/man1/dtrace.1.gz
OLD_FILES+=usr/share/man/man1/dtruss.1.gz
OLD_FILES+=usr/share/man/man1/lockstat.1.gz
OLD_FILES+=usr/share/man/man1/plockstat.1.gz
OLD_FILES+=usr/share/dtrace/blocking
OLD_FILES+=usr/share/dtrace/disklatency
OLD_FILES+=usr/share/dtrace/disklatencycmd
OLD_FILES+=usr/share/dtrace/hotopen
OLD_FILES+=usr/share/dtrace/nfsattrstats
OLD_FILES+=usr/share/dtrace/nfsclienttime
OLD_FILES+=usr/share/dtrace/siftr
OLD_FILES+=usr/share/dtrace/toolkit/execsnoop
OLD_FILES+=usr/share/dtrace/toolkit/hotkernel
OLD_FILES+=usr/share/dtrace/toolkit/hotuser
OLD_FILES+=usr/share/dtrace/toolkit/opensnoop
OLD_FILES+=usr/share/dtrace/toolkit/procsystime
OLD_FILES+=usr/share/dtrace/tcpconn
OLD_FILES+=usr/share/dtrace/tcpdebug
OLD_FILES+=usr/share/dtrace/tcpstate
OLD_FILES+=usr/share/dtrace/tcptrack
OLD_FILES+=usr/share/dtrace/udptrack
OLD_FILES+=usr/share/man/man1/dtrace.1.gz
OLD_DIRS+=usr/lib/dtrace
OLD_DIRS+=usr/lib32/dtrace
OLD_DIRS+=usr/libexec/dwatch
OLD_DIRS+=usr/share/dtrace/toolkit
OLD_DIRS+=usr/share/dtrace
.endif
.if ${MK_ZFS} == no
OLD_FILES+=boot/gptzfsboot
OLD_FILES+=boot/zfsboot
OLD_FILES+=boot/zfsloader
OLD_FILES+=etc/rc.d/zfs
OLD_FILES+=etc/rc.d/zfsbe
OLD_FILES+=etc/rc.d/zfsd
OLD_FILES+=etc/rc.d/zfskeys
OLD_FILES+=etc/rc.d/zvol
OLD_FILES+=etc/devd/zfs.conf
OLD_FILES+=etc/periodic/daily/404.status-zfs
OLD_FILES+=etc/periodic/daily/800.scrub-zfs
OLD_FILES+=etc/zfs/exports
OLD_DIRS+=etc/zfs
OLD_LIBS+=lib/libzfs.so.2
OLD_LIBS+=lib/libzfs.so.3
OLD_LIBS+=lib/libzfs_core.so.2
OLD_LIBS+=lib/libzpool.so.2
OLD_FILES+=rescue/zdb
OLD_FILES+=rescue/zfs
OLD_FILES+=rescue/zpool
OLD_FILES+=sbin/bectl
OLD_FILES+=sbin/zfs
OLD_FILES+=sbin/zpool
OLD_FILES+=sbin/zfsbootcfg
OLD_FILES+=usr/bin/zinject
OLD_FILES+=usr/bin/zstreamdump
OLD_FILES+=usr/bin/ztest
OLD_FILES+=usr/lib/libbe.a
OLD_FILES+=usr/lib/libbe_p.a
OLD_FILES+=usr/lib/libbe.so
OLD_LIBS+=lib/libbe.so.1
OLD_FILES+=usr/lib/libzfs.a
OLD_FILES+=usr/lib/libzfs.so
OLD_FILES+=usr/lib/libzfs_core.a
OLD_FILES+=usr/lib/libzfs_core.so
OLD_FILES+=usr/lib/libzfs_core_p.a
OLD_FILES+=usr/lib/libzfs_p.a
OLD_FILES+=usr/lib/libzpool.a
OLD_FILES+=usr/lib/libzpool.so
OLD_LIBS+=usr/lib/libzpool.so.2
OLD_FILES+=usr/sbin/zfsd
OLD_FILES+=usr/sbin/zhack
OLD_FILES+=usr/sbin/zdb
OLD_FILES+=usr/share/man/man3/be_activate.3.gz
OLD_FILES+=usr/share/man/man3/be_active_name.3.gz
OLD_FILES+=usr/share/man/man3/be_active_path.3.gz
OLD_FILES+=usr/share/man/man3/be_create_depth.3.gz
OLD_FILES+=usr/share/man/man3/be_create_from_existing_snap.3.gz
OLD_FILES+=usr/share/man/man3/be_create_from_existing.3.gz
OLD_FILES+=usr/share/man/man3/be_create.3.gz
OLD_FILES+=usr/share/man/man3/be_deactivate.3.gz
OLD_FILES+=usr/share/man/man3/be_destroy.3.gz
OLD_FILES+=usr/share/man/man3/be_exists.3.gz
OLD_FILES+=usr/share/man/man3/be_export.3.gz
OLD_FILES+=usr/share/man/man3/be_get_bootenv_props.3.gz
OLD_FILES+=usr/share/man/man3/be_get_dataset_props.3.gz
OLD_FILES+=usr/share/man/man3/be_get_dataset_snapshots.3.gz
OLD_FILES+=usr/share/man/man3/be_import.3.gz
OLD_FILES+=usr/share/man/man3/be_is_auto_snapshot_name.3.gz
OLD_FILES+=usr/share/man/man3/be_mount.3.gz
OLD_FILES+=usr/share/man/man3/be_mounted_at.3.gz
OLD_FILES+=usr/share/man/man3/be_nextboot_name.3.gz
OLD_FILES+=usr/share/man/man3/be_nextboot_path.3.gz
OLD_FILES+=usr/share/man/man3/be_nicenum.3.gz
OLD_FILES+=usr/share/man/man3/be_prop_list_alloc.3.gz
OLD_FILES+=usr/share/man/man3/be_prop_list_free.3.gz
OLD_FILES+=usr/share/man/man3/be_rename.3.gz
OLD_FILES+=usr/share/man/man3/be_root_concat.3.gz
OLD_FILES+=usr/share/man/man3/be_root_path.3.gz
OLD_FILES+=usr/share/man/man3/be_snapshot.3.gz
OLD_FILES+=usr/share/man/man3/be_unmount.3.gz
OLD_FILES+=usr/share/man/man3/be_validate_name.3.gz
OLD_FILES+=usr/share/man/man3/be_validate_snap.3.gz
OLD_FILES+=usr/share/man/man3/libbe_close.3.gz
OLD_FILES+=usr/share/man/man3/libbe_errno.3.gz
OLD_FILES+=usr/share/man/man3/libbe_error_description.3.gz
OLD_FILES+=usr/share/man/man3/libbe_init.3.gz
OLD_FILES+=usr/share/man/man3/libbe_print_on_error.3.gz
OLD_FILES+=usr/share/man/man3/libbe.3.gz
OLD_FILES+=usr/share/man/man5/zpool-features.5.gz
OLD_FILES+=usr/share/man/man8/bectl.8.gz
OLD_FILES+=usr/share/man/man8/gptzfsboot.8.gz
OLD_FILES+=usr/share/man/man8/zdb.8.gz
OLD_FILES+=usr/share/man/man8/zfs-program.8.gz
OLD_FILES+=usr/share/man/man8/zfs.8.gz
OLD_FILES+=usr/share/man/man8/zfsboot.8.gz
OLD_FILES+=usr/share/man/man8/zfsbootcfg.8.gz
OLD_FILES+=usr/share/man/man8/zfsd.8.gz
OLD_FILES+=usr/share/man/man8/zfsloader.8.gz
OLD_FILES+=usr/share/man/man8/zpool.8.gz
.endif
.if ${MK_CLANG} == no && ${MK_LLVM_BINUTILS} == no
OLD_FILES+=usr/bin/llvm-addr2line
OLD_FILES+=usr/bin/llvm-ar
OLD_FILES+=usr/bin/llvm-nm
OLD_FILES+=usr/bin/llvm-objcopy
OLD_FILES+=usr/bin/llvm-objdump
OLD_FILES+=usr/bin/llvm-ranlib
OLD_FILES+=usr/bin/llvm-readelf
OLD_FILES+=usr/bin/llvm-readobj
OLD_FILES+=usr/bin/llvm-size
OLD_FILES+=usr/bin/llvm-strings
OLD_FILES+=usr/bin/llvm-symbolizer
OLD_FILES+=usr/bin/objdump
OLD_FILES+=usr/share/man/man1/llvm-addr2line.1.gz
OLD_FILES+=usr/share/man/man1/llvm-ar.1.gz
OLD_FILES+=usr/share/man/man1/llvm-nm.1.gz
OLD_FILES+=usr/share/man/man1/llvm-objcopy.1.gz
OLD_FILES+=usr/share/man/man1/llvm-ranlib.1.gz
OLD_FILES+=usr/share/man/man1/llvm-readelf.1.gz
OLD_FILES+=usr/share/man/man1/llvm-readobj.1.gz
OLD_FILES+=usr/share/man/man1/llvm-size.1.gz
OLD_FILES+=usr/share/man/man1/llvm-strings.1.gz
OLD_FILES+=usr/share/man/man1/llvm-symbolizer.1.gz
OLD_FILES+=usr/share/man/man1/objdump.1.gz
.endif
.if ${MK_CLANG} == no
OLD_FILES+=usr/bin/clang
OLD_FILES+=usr/bin/clang++
OLD_FILES+=usr/bin/clang-cpp
-OLD_FILES+=usr/lib/clang/15.0.0/include/cuda_wrappers/algorithm
-OLD_FILES+=usr/lib/clang/15.0.0/include/cuda_wrappers/complex
-OLD_FILES+=usr/lib/clang/15.0.0/include/cuda_wrappers/new
-OLD_DIRS+=usr/lib/clang/15.0.0/include/cuda_wrappers
-OLD_FILES+=usr/lib/clang/15.0.0/include/fuzzer/FuzzedDataProvider.h
-OLD_DIRS+=usr/lib/clang/15.0.0/include/fuzzer
-OLD_FILES+=usr/lib/clang/15.0.0/include/hlsl/hlsl_basic_types.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/hlsl/hlsl_intrinsics.h
-OLD_DIRS+=usr/lib/clang/15.0.0/include/hlsl
-OLD_FILES+=usr/lib/clang/15.0.0/include/openmp_wrappers/__clang_openmp_device_functions.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/openmp_wrappers/cmath
-OLD_FILES+=usr/lib/clang/15.0.0/include/openmp_wrappers/complex
-OLD_FILES+=usr/lib/clang/15.0.0/include/openmp_wrappers/complex.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/openmp_wrappers/complex_cmath.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/openmp_wrappers/math.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/openmp_wrappers/new
-OLD_DIRS+=usr/lib/clang/15.0.0/include/openmp_wrappers
-OLD_FILES+=usr/lib/clang/15.0.0/include/ppc_wrappers/bmi2intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ppc_wrappers/bmiintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ppc_wrappers/emmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ppc_wrappers/immintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ppc_wrappers/mm_malloc.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ppc_wrappers/mmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ppc_wrappers/pmmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ppc_wrappers/smmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ppc_wrappers/tmmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ppc_wrappers/x86gprintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ppc_wrappers/x86intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ppc_wrappers/xmmintrin.h
-OLD_DIRS+=usr/lib/clang/15.0.0/include/ppc_wrappers
-OLD_FILES+=usr/lib/clang/15.0.0/include/profile/InstrProfData.inc
-OLD_FILES+=usr/lib/clang/15.0.0/include/profile/MemProfData.inc
-OLD_DIRS+=usr/lib/clang/15.0.0/include/profile
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/allocator_interface.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/asan_interface.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/common_interface_defs.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/coverage_interface.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/dfsan_interface.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/hwasan_interface.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/linux_syscall_hooks.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/lsan_interface.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/memprof_interface.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/msan_interface.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/netbsd_syscall_hooks.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/scudo_interface.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/tsan_interface.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/tsan_interface_atomic.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sanitizer/ubsan_interface.h
-OLD_DIRS+=usr/lib/clang/15.0.0/include/sanitizer
-OLD_FILES+=usr/lib/clang/15.0.0/include/xray/xray_interface.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/xray/xray_log_interface.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/xray/xray_records.h
-OLD_DIRS+=usr/lib/clang/15.0.0/include/xray
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_cuda_builtin_vars.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_cuda_cmath.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_cuda_complex_builtins.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_cuda_device_functions.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_cuda_intrinsics.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_cuda_libdevice_declares.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_cuda_math.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_cuda_math_forward_declares.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_cuda_runtime_wrapper.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_cuda_texture_intrinsics.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_hip_cmath.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_hip_libdevice_declares.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_hip_math.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__clang_hip_runtime_wrapper.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__stddef_max_align_t.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__wmmintrin_aes.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/__wmmintrin_pclmul.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/adxintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/altivec.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ammintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/amxintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/arm64intr.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/arm_acle.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/arm_bf16.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/arm_cde.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/arm_cmse.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/arm_fp16.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/arm_mve.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/arm_neon.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/arm_neon_sve_bridge.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/arm_sve.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/armintr.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx2intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512bf16intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512bitalgintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512bwintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512cdintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512dqintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512erintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512fintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512fp16intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512ifmaintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512ifmavlintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512pfintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vbmi2intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vbmiintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vbmivlintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vlbf16intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vlbitalgintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vlbwintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vlcdintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vldqintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vlfp16intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vlintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vlvbmi2intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vlvnniintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vlvp2intersectintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vnniintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vp2intersectintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vpopcntdqintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avx512vpopcntdqvlintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avxintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/avxvnniintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/bmi2intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/bmiintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/builtins.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/cet.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/cetintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/cldemoteintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/clflushoptintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/clwbintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/clzerointrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/cpuid.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/crc32intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/emmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/enqcmdintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/f16cintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/float.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/fma4intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/fmaintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/fxsrintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/gfniintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/hexagon_circ_brev_intrinsics.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/hexagon_protos.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/hexagon_types.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/hlsl.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/hresetintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/htmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/htmxlintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/hvx_hexagon_protos.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ia32intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/immintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/inttypes.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/invpcidintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/iso646.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/keylockerintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/limits.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/lwpintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/lzcntintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/mm3dnow.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/mm_malloc.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/mmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/module.modulemap
-OLD_FILES+=usr/lib/clang/15.0.0/include/movdirintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/msa.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/mwaitxintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/nmmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/omp-tools.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/omp.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ompt.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/opencl-c-base.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/opencl-c.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/pconfigintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/pkuintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/pmmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/popcntintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/prfchwintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/ptwriteintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/rdpruintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/rdseedintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/riscv_vector.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/rtmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/s390intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/serializeintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/sgxintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/shaintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/smmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/stdalign.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/stdarg.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/stdatomic.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/stdbool.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/stddef.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/stdint.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/stdnoreturn.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/tbmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/tgmath.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/tmmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/tsxldtrkintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/uintrintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/unwind.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/vadefs.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/vaesintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/varargs.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/vecintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/velintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/velintrin_approx.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/velintrin_gen.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/vpclmulqdqintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/waitpkgintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/wasm_simd128.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/wbnoinvdintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/wmmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/x86gprintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/x86intrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/xmmintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/xopintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/xsavecintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/xsaveintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/xsaveoptintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/xsavesintrin.h
-OLD_FILES+=usr/lib/clang/15.0.0/include/xtestintrin.h
-OLD_DIRS+=usr/lib/clang/15.0.0/include
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-aarch64.so
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-arm.so
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-armhf.so
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-i386.so
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-preinit-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-preinit-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan-x86_64.so
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan_cxx-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan_cxx-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan_static-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.asan_static-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.cfi-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.cfi-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.cfi-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.cfi-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.cfi-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.cfi_diag-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.cfi_diag-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.cfi_diag-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.dd-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.dd-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.fuzzer-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.fuzzer-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.msan-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.msan-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.profile-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.profile-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.profile-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.profile-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.profile-powerpc.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.profile-powerpc64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.profile-powerpc64le.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.profile-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.safestack-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.safestack-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.safestack-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.stats-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.stats-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.stats-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.stats-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.stats-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.stats_client-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.stats_client-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.stats_client-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.stats_client-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.stats_client-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.tsan-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.tsan-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-basic-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-basic-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-basic-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-basic-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-fdr-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-fdr-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-profiling-arm.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-profiling-armhf.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
-OLD_FILES+=usr/lib/clang/15.0.0/lib/freebsd/libclang_rt.xray-x86_64.a
-OLD_DIRS+=usr/lib/clang/15.0.0/lib/freebsd
-OLD_DIRS+=usr/lib/clang/15.0.0/lib
-OLD_FILES+=usr/lib/clang/15.0.0/share/asan_ignorelist.txt
-OLD_FILES+=usr/lib/clang/15.0.0/share/cfi_ignorelist.txt
-OLD_FILES+=usr/lib/clang/15.0.0/share/msan_ignorelist.txt
-OLD_DIRS+=usr/lib/clang/15.0.0/share
-OLD_DIRS+=usr/lib/clang/15.0.0
+OLD_FILES+=usr/lib/clang/15.0.3/include/cuda_wrappers/algorithm
+OLD_FILES+=usr/lib/clang/15.0.3/include/cuda_wrappers/complex
+OLD_FILES+=usr/lib/clang/15.0.3/include/cuda_wrappers/new
+OLD_DIRS+=usr/lib/clang/15.0.3/include/cuda_wrappers
+OLD_FILES+=usr/lib/clang/15.0.3/include/fuzzer/FuzzedDataProvider.h
+OLD_DIRS+=usr/lib/clang/15.0.3/include/fuzzer
+OLD_FILES+=usr/lib/clang/15.0.3/include/hlsl/hlsl_basic_types.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/hlsl/hlsl_intrinsics.h
+OLD_DIRS+=usr/lib/clang/15.0.3/include/hlsl
+OLD_FILES+=usr/lib/clang/15.0.3/include/openmp_wrappers/__clang_openmp_device_functions.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/openmp_wrappers/cmath
+OLD_FILES+=usr/lib/clang/15.0.3/include/openmp_wrappers/complex
+OLD_FILES+=usr/lib/clang/15.0.3/include/openmp_wrappers/complex.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/openmp_wrappers/complex_cmath.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/openmp_wrappers/math.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/openmp_wrappers/new
+OLD_DIRS+=usr/lib/clang/15.0.3/include/openmp_wrappers
+OLD_FILES+=usr/lib/clang/15.0.3/include/ppc_wrappers/bmi2intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ppc_wrappers/bmiintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ppc_wrappers/emmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ppc_wrappers/immintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ppc_wrappers/mm_malloc.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ppc_wrappers/mmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ppc_wrappers/pmmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ppc_wrappers/smmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ppc_wrappers/tmmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ppc_wrappers/x86gprintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ppc_wrappers/x86intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ppc_wrappers/xmmintrin.h
+OLD_DIRS+=usr/lib/clang/15.0.3/include/ppc_wrappers
+OLD_FILES+=usr/lib/clang/15.0.3/include/profile/InstrProfData.inc
+OLD_FILES+=usr/lib/clang/15.0.3/include/profile/MemProfData.inc
+OLD_DIRS+=usr/lib/clang/15.0.3/include/profile
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/allocator_interface.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/asan_interface.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/common_interface_defs.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/coverage_interface.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/dfsan_interface.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/hwasan_interface.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/linux_syscall_hooks.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/lsan_interface.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/memprof_interface.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/msan_interface.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/netbsd_syscall_hooks.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/scudo_interface.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/tsan_interface.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/tsan_interface_atomic.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sanitizer/ubsan_interface.h
+OLD_DIRS+=usr/lib/clang/15.0.3/include/sanitizer
+OLD_FILES+=usr/lib/clang/15.0.3/include/xray/xray_interface.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/xray/xray_log_interface.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/xray/xray_records.h
+OLD_DIRS+=usr/lib/clang/15.0.3/include/xray
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_cuda_builtin_vars.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_cuda_cmath.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_cuda_complex_builtins.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_cuda_device_functions.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_cuda_intrinsics.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_cuda_libdevice_declares.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_cuda_math.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_cuda_math_forward_declares.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_cuda_runtime_wrapper.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_cuda_texture_intrinsics.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_hip_cmath.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_hip_libdevice_declares.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_hip_math.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__clang_hip_runtime_wrapper.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__stddef_max_align_t.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__wmmintrin_aes.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/__wmmintrin_pclmul.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/adxintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/altivec.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ammintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/amxintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/arm64intr.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/arm_acle.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/arm_bf16.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/arm_cde.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/arm_cmse.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/arm_fp16.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/arm_mve.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/arm_neon.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/arm_neon_sve_bridge.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/arm_sve.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/armintr.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx2intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512bf16intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512bitalgintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512bwintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512cdintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512dqintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512erintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512fintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512fp16intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512ifmaintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512ifmavlintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512pfintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vbmi2intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vbmiintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vbmivlintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vlbf16intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vlbitalgintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vlbwintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vlcdintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vldqintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vlfp16intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vlintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vlvbmi2intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vlvnniintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vlvp2intersectintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vnniintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vp2intersectintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vpopcntdqintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avx512vpopcntdqvlintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avxintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/avxvnniintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/bmi2intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/bmiintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/builtins.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/cet.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/cetintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/cldemoteintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/clflushoptintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/clwbintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/clzerointrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/cpuid.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/crc32intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/emmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/enqcmdintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/f16cintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/float.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/fma4intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/fmaintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/fxsrintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/gfniintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/hexagon_circ_brev_intrinsics.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/hexagon_protos.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/hexagon_types.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/hlsl.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/hresetintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/htmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/htmxlintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/hvx_hexagon_protos.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ia32intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/immintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/inttypes.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/invpcidintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/iso646.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/keylockerintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/limits.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/lwpintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/lzcntintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/mm3dnow.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/mm_malloc.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/mmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/module.modulemap
+OLD_FILES+=usr/lib/clang/15.0.3/include/movdirintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/msa.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/mwaitxintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/nmmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/omp-tools.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/omp.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ompt.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/opencl-c-base.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/opencl-c.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/pconfigintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/pkuintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/pmmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/popcntintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/prfchwintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/ptwriteintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/rdpruintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/rdseedintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/riscv_vector.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/rtmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/s390intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/serializeintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/sgxintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/shaintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/smmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/stdalign.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/stdarg.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/stdatomic.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/stdbool.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/stddef.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/stdint.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/stdnoreturn.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/tbmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/tgmath.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/tmmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/tsxldtrkintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/uintrintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/unwind.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/vadefs.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/vaesintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/varargs.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/vecintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/velintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/velintrin_approx.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/velintrin_gen.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/vpclmulqdqintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/waitpkgintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/wasm_simd128.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/wbnoinvdintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/wmmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/x86gprintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/x86intrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/xmmintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/xopintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/xsavecintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/xsaveintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/xsaveoptintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/xsavesintrin.h
+OLD_FILES+=usr/lib/clang/15.0.3/include/xtestintrin.h
+OLD_DIRS+=usr/lib/clang/15.0.3/include
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-aarch64.so
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-arm.so
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-armhf.so
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-i386.so
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-preinit-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-preinit-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-preinit-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan-x86_64.so
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan_cxx-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan_cxx-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan_cxx-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan_static-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.asan_static-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.cfi-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.cfi-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.cfi-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.cfi-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.cfi-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.cfi_diag-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.cfi_diag-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.cfi_diag-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.dd-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.dd-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.fuzzer-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.fuzzer-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.msan-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.msan-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.profile-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.profile-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.profile-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.profile-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.profile-powerpc.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.profile-powerpc64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.profile-powerpc64le.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.profile-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.safestack-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.safestack-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.safestack-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.stats-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.stats-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.stats-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.stats-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.stats-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.stats_client-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.stats_client-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.stats_client-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.stats_client-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.stats_client-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.tsan-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.tsan-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-basic-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-basic-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-basic-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-basic-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-fdr-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-fdr-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-profiling-arm.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-profiling-armhf.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
+OLD_FILES+=usr/lib/clang/15.0.3/lib/freebsd/libclang_rt.xray-x86_64.a
+OLD_DIRS+=usr/lib/clang/15.0.3/lib/freebsd
+OLD_DIRS+=usr/lib/clang/15.0.3/lib
+OLD_FILES+=usr/lib/clang/15.0.3/share/asan_ignorelist.txt
+OLD_FILES+=usr/lib/clang/15.0.3/share/cfi_ignorelist.txt
+OLD_FILES+=usr/lib/clang/15.0.3/share/msan_ignorelist.txt
+OLD_DIRS+=usr/lib/clang/15.0.3/share
+OLD_DIRS+=usr/lib/clang/15.0.3
OLD_DIRS+=usr/lib/clang
OLD_FILES+=usr/share/doc/llvm/clang/LICENSE.TXT
OLD_DIRS+=usr/share/doc/llvm/clang
OLD_FILES+=usr/share/doc/llvm/COPYRIGHT.regex
OLD_FILES+=usr/share/doc/llvm/LICENSE.TXT
OLD_DIRS+=usr/share/doc/llvm
OLD_FILES+=usr/share/man/man1/clang.1.gz
OLD_FILES+=usr/share/man/man1/clang++.1.gz
OLD_FILES+=usr/share/man/man1/clang-cpp.1.gz
.endif
.if ${MK_CLANG_EXTRAS} == no
OLD_FILES+=usr/bin/bugpoint
OLD_FILES+=usr/bin/llc
OLD_FILES+=usr/bin/lli
OLD_FILES+=usr/bin/llvm-as
OLD_FILES+=usr/bin/llvm-bcanalyzer
OLD_FILES+=usr/bin/llvm-cxxdump
OLD_FILES+=usr/bin/llvm-diff
OLD_FILES+=usr/bin/llvm-dis
OLD_FILES+=usr/bin/llvm-dwarfdump
OLD_FILES+=usr/bin/llvm-dwp
OLD_FILES+=usr/bin/llvm-extract
OLD_FILES+=usr/bin/llvm-link
OLD_FILES+=usr/bin/llvm-lto
OLD_FILES+=usr/bin/llvm-lto2
OLD_FILES+=usr/bin/llvm-mc
OLD_FILES+=usr/bin/llvm-mca
OLD_FILES+=usr/bin/llvm-modextract
OLD_FILES+=usr/bin/llvm-pdbutil
OLD_FILES+=usr/bin/llvm-rtdyld
OLD_FILES+=usr/bin/llvm-xray
OLD_FILES+=usr/bin/opt
OLD_FILES+=usr/share/man/man1/bugpoint.1.gz
OLD_FILES+=usr/share/man/man1/llc.1.gz
OLD_FILES+=usr/share/man/man1/lli.1.gz
OLD_FILES+=usr/share/man/man1/llvm-as.1.gz
OLD_FILES+=usr/share/man/man1/llvm-bcanalyzer.1.gz
OLD_FILES+=usr/share/man/man1/llvm-diff.1.gz
OLD_FILES+=usr/share/man/man1/llvm-dis.1.gz
OLD_FILES+=usr/share/man/man1/llvm-dwarfdump.1
OLD_FILES+=usr/share/man/man1/llvm-extract.1.gz
OLD_FILES+=usr/share/man/man1/llvm-link.1.gz
OLD_FILES+=usr/share/man/man1/llvm-pdbutil.1.gz
OLD_FILES+=usr/share/man/man1/opt.1.gz
.endif
.if ${MK_CLANG_EXTRAS} == no && ${MK_CLANG_FORMAT} == no
OLD_FILES+=usr/bin/clang-format
.endif
.if ${MK_CLANG_EXTRAS} == no && ${MK_LLVM_CXXFILT} == no
OLD_FILES+=usr/bin/llvm-cxxfilt
OLD_FILES+=usr/share/man/man1/llvm-cxxfilt.1.gz
.endif
.if ${MK_CPP} == no
OLD_FILES+=usr/bin/cpp
OLD_FILES+=usr/share/man/man1/cpp.1.gz
.endif
.if ${MK_CUSE} == no
OLD_FILES+=usr/include/fs/cuse/cuse_defs.h
OLD_FILES+=usr/include/fs/cuse/cuse_ioctl.h
OLD_FILES+=usr/include/cuse.h
OLD_FILES+=usr/lib/libcuse.a
OLD_LIBS+=usr/lib/libcuse.so.1
OLD_FILES+=usr/lib/libcuse_p.a
OLD_FILES+=usr/share/man/man3/cuse.3.gz
OLD_FILES+=usr/share/man/man3/cuse_alloc_unit_number.3.gz
OLD_FILES+=usr/share/man/man3/cuse_alloc_unit_number_by_id.3.gz
OLD_FILES+=usr/share/man/man3/cuse_copy_in.3.gz
OLD_FILES+=usr/share/man/man3/cuse_copy_out.3.gz
OLD_FILES+=usr/share/man/man3/cuse_dev_create.3.gz
OLD_FILES+=usr/share/man/man3/cuse_dev_destroy.3.gz
OLD_FILES+=usr/share/man/man3/cuse_dev_get_current.3.gz
OLD_FILES+=usr/share/man/man3/cuse_dev_get_per_file_handle.3.gz
OLD_FILES+=usr/share/man/man3/cuse_dev_get_priv0.3.gz
OLD_FILES+=usr/share/man/man3/cuse_dev_get_priv1.3.gz
OLD_FILES+=usr/share/man/man3/cuse_dev_set_per_file_handle.3.gz
OLD_FILES+=usr/share/man/man3/cuse_dev_set_priv0.3.gz
OLD_FILES+=usr/share/man/man3/cuse_dev_set_priv1.3.gz
OLD_FILES+=usr/share/man/man3/cuse_free_unit_number.3.gz
OLD_FILES+=usr/share/man/man3/cuse_free_unit_number_by_id.3.gz
OLD_FILES+=usr/share/man/man3/cuse_get_local.3.gz
OLD_FILES+=usr/share/man/man3/cuse_got_peer_signal.3.gz
OLD_FILES+=usr/share/man/man3/cuse_init.3.gz
OLD_FILES+=usr/share/man/man3/cuse_is_vmalloc_addr.3.gz
OLD_FILES+=usr/share/man/man3/cuse_poll_wakeup.3.gz
OLD_FILES+=usr/share/man/man3/cuse_set_local.3.gz
OLD_FILES+=usr/share/man/man3/cuse_uninit.3.gz
OLD_FILES+=usr/share/man/man3/cuse_vmalloc.3.gz
OLD_FILES+=usr/share/man/man3/cuse_vmfree.3.gz
OLD_FILES+=usr/share/man/man3/cuse_vmoffset.3.gz
OLD_FILES+=usr/share/man/man3/cuse_wait_and_process.3.gz
OLD_DIRS+=usr/include/fs/cuse
.endif
.if ${MK_DEBUG_FILES} == no
.if exists(${DESTDIR}/usr/lib/debug)
DEBUG_DIRS!=find ${DESTDIR}/usr/lib/debug -mindepth 1 \
-type d \! -path "${DESTDIR}/usr/lib/debug/boot/*" \
| sed -e 's,^${DESTDIR}/,,'; echo
DEBUG_FILES!=find ${DESTDIR}/usr/lib/debug \
\! -type d \! -path "${DESTDIR}/usr/lib/debug/boot/*" \! -name "lib*.so*" \
| sed -e 's,^${DESTDIR}/,,'; echo
DEBUG_LIBS!=find ${DESTDIR}/usr/lib/debug \! -type d -name "lib*.so*" \
| sed -e 's,^${DESTDIR}/,,'; echo
OLD_DIRS+=${DEBUG_DIRS}
OLD_FILES+=${DEBUG_FILES}
OLD_LIBS+=${DEBUG_LIBS}
.endif
.endif
.if ${MK_DIALOG} == no
OLD_FILES+=usr/bin/dialog
OLD_FILES+=usr/bin/dpv
OLD_FILES+=usr/lib/libdialog.a
OLD_FILES+=usr/lib/libdialog.so
OLD_FILES+=usr/lib/libdialog.so.8
OLD_FILES+=usr/lib/libdialog_p.a
OLD_FILES+=usr/lib/libdpv.a
OLD_FILES+=usr/lib/libdpv.so
OLD_FILES+=usr/lib/libdpv.so.1
OLD_FILES+=usr/lib/libdpv_p.a
OLD_FILES+=usr/sbin/bsdconfig
OLD_FILES+=usr/share/man/man1/dialog.1.gz
OLD_FILES+=usr/share/man/man1/dpv.1.gz
OLD_FILES+=usr/share/man/man3/dialog.3.gz
OLD_FILES+=usr/share/man/man3/dpv.3.gz
OLD_FILES+=usr/share/man/man8/bsdconfig.8.gz
OLD_DIRS+=usr/share/bsdconfig
OLD_DIRS+=usr/share/bsdconfig/media
OLD_DIRS+=usr/share/bsdconfig/networking
OLD_DIRS+=usr/share/bsdconfig/packages
OLD_DIRS+=usr/share/bsdconfig/password
OLD_DIRS+=usr/share/bsdconfig/startup
OLD_DIRS+=usr/share/bsdconfig/timezone
OLD_DIRS+=usr/share/bsdconfig/usermgmt
.endif
.if ${MK_EFI} == no
OLD_FILES+=usr/sbin/efibootmgr
OLD_FILES+=usr/sbin/efidp
OLD_FILES+=usr/sbin/efivar
OLD_FILES+=usr/sbin/uefisign
OLD_FILES+=usr/share/examples/uefisign/uefikeys
.endif
.if ${MK_FMTREE} == no
OLD_FILES+=usr/sbin/fmtree
OLD_FILES+=usr/share/man/man8/fmtree.8.gz
.endif
.if ${MK_FTP} == no
OLD_FILES+=etc/ftpusers
OLD_FILES+=etc/newsyslog.conf.d/ftp.conf
OLD_FILES+=etc/pam.d/ftp
OLD_FILES+=etc/pam.d/ftpd
OLD_FILES+=etc/rc.d/ftpd
OLD_FILES+=etc/syslog.d/ftp.conf
OLD_FILES+=usr/bin/ftp
OLD_FILES+=usr/bin/gate-ftp
OLD_FILES+=usr/bin/pftp
OLD_FILES+=usr/libexec/ftpd
OLD_FILES+=usr/share/man/man1/ftp.1.gz
OLD_FILES+=usr/share/man/man1/gate-ftp.1.gz
OLD_FILES+=usr/share/man/man1/pftp.1.gz
OLD_FILES+=usr/share/man/man5/ftpchroot.5.gz
OLD_FILES+=usr/share/man/man8/ftpd.8.gz
.endif
.if ${MK_DICT} == no
OLD_FILES+=usr/share/dict/README
OLD_FILES+=usr/share/dict/freebsd
OLD_FILES+=usr/share/dict/propernames
OLD_FILES+=usr/share/dict/web2
OLD_FILES+=usr/share/dict/web2a
OLD_FILES+=usr/share/dict/words
OLD_DIRS+=usr/share/dict
.endif
.if ${MK_DMAGENT} == no
OLD_FILES+=etc/dma/dma.conf
OLD_DIRS+=etc/dma
OLD_FILES+=usr/libexec/dma
OLD_FILES+=usr/libexec/dma-mbox-create
OLD_FILES+=usr/share/man/man8/dma.8.gz
OLD_FILES+=usr/share/examples/dma/mailer.conf
.endif
.if ${MK_EE} == no
OLD_FILES+=usr/bin/edit
OLD_FILES+=usr/bin/ee
OLD_FILES+=usr/bin/ree
OLD_FILES+=usr/share/man/man1/edit.1.gz
OLD_FILES+=usr/share/man/man1/ee.1.gz
OLD_FILES+=usr/share/man/man1/ree.1.gz
OLD_FILES+=usr/share/nls/C/ee.cat
OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/ee.cat
OLD_FILES+=usr/share/nls/pl_PL.ISO8859-2/ee.cat
OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/ee.cat
OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/ee.cat
.endif
.if ${MK_EXAMPLES} == no
OLD_FILES+=usr/share/examples/BSD_daemon/FreeBSD.pfa
OLD_FILES+=usr/share/examples/BSD_daemon/README
OLD_FILES+=usr/share/examples/BSD_daemon/beastie.eps
OLD_FILES+=usr/share/examples/BSD_daemon/beastie.fig
OLD_FILES+=usr/share/examples/BSD_daemon/eps.patch
OLD_FILES+=usr/share/examples/BSD_daemon/poster.sh
OLD_FILES+=usr/share/examples/FreeBSD_version/FreeBSD_version.c
OLD_FILES+=usr/share/examples/FreeBSD_version/Makefile
OLD_FILES+=usr/share/examples/FreeBSD_version/README
OLD_FILES+=usr/share/examples/IPv6/USAGE
OLD_FILES+=usr/share/examples/bhyve/vmrun.sh
OLD_FILES+=usr/share/examples/bootforth/README
OLD_FILES+=usr/share/examples/bootforth/boot.4th
OLD_FILES+=usr/share/examples/bootforth/frames.4th
OLD_FILES+=usr/share/examples/bootforth/loader.rc
OLD_FILES+=usr/share/examples/bootforth/menu.4th
OLD_FILES+=usr/share/examples/bootforth/menuconf.4th
OLD_FILES+=usr/share/examples/bootforth/screen.4th
OLD_FILES+=usr/share/examples/bsdconfig/add_some_packages.sh
OLD_FILES+=usr/share/examples/bsdconfig/browse_packages_http.sh
OLD_FILES+=usr/share/examples/bsdconfig/bsdconfigrc
OLD_FILES+=usr/share/examples/csh/dot.cshrc
OLD_FILES+=usr/share/examples/diskless/ME
OLD_FILES+=usr/share/examples/diskless/README.BOOTP
OLD_FILES+=usr/share/examples/diskless/README.TEMPLATING
OLD_FILES+=usr/share/examples/diskless/clone_root
OLD_FILES+=usr/share/examples/dma/mailer.conf
OLD_FILES+=usr/share/examples/drivers/README
OLD_FILES+=usr/share/examples/drivers/make_device_driver.sh
OLD_FILES+=usr/share/examples/drivers/make_pseudo_driver.sh
OLD_FILES+=usr/share/examples/dwatch/profile_template
OLD_FILES+=usr/share/examples/etc/README.examples
OLD_FILES+=usr/share/examples/etc/bsd-style-copyright
OLD_FILES+=usr/share/examples/etc/group
OLD_FILES+=usr/share/examples/etc/login.access
OLD_FILES+=usr/share/examples/etc/make.conf
OLD_FILES+=usr/share/examples/etc/rc.bsdextended
OLD_FILES+=usr/share/examples/etc/rc.firewall
OLD_FILES+=usr/share/examples/etc/rc.sendmail
OLD_FILES+=usr/share/examples/etc/termcap.small
OLD_FILES+=usr/share/examples/etc/wpa_supplicant.conf
OLD_FILES+=usr/share/examples/find_interface/Makefile
OLD_FILES+=usr/share/examples/find_interface/README
OLD_FILES+=usr/share/examples/find_interface/find_interface.c
OLD_FILES+=usr/share/examples/hast/ucarp.sh
OLD_FILES+=usr/share/examples/hast/ucarp_down.sh
OLD_FILES+=usr/share/examples/hast/ucarp_up.sh
OLD_FILES+=usr/share/examples/hast/vip-down.sh
OLD_FILES+=usr/share/examples/hast/vip-up.sh
OLD_FILES+=usr/share/examples/hostapd/hostapd.conf
OLD_FILES+=usr/share/examples/hostapd/hostapd.eap_user
OLD_FILES+=usr/share/examples/hostapd/hostapd.wpa_psk
OLD_FILES+=usr/share/examples/indent/indent.pro
OLD_FILES+=usr/share/examples/ipfilter/BASIC.NAT
OLD_FILES+=usr/share/examples/ipfilter/BASIC_1.FW
OLD_FILES+=usr/share/examples/ipfilter/BASIC_2.FW
OLD_FILES+=usr/share/examples/ipfilter/README
OLD_FILES+=usr/share/examples/ipfilter/example.1
OLD_FILES+=usr/share/examples/ipfilter/example.10
OLD_FILES+=usr/share/examples/ipfilter/example.11
OLD_FILES+=usr/share/examples/ipfilter/example.12
OLD_FILES+=usr/share/examples/ipfilter/example.13
OLD_FILES+=usr/share/examples/ipfilter/example.14
OLD_FILES+=usr/share/examples/ipfilter/example.2
OLD_FILES+=usr/share/examples/ipfilter/example.3
OLD_FILES+=usr/share/examples/ipfilter/example.4
OLD_FILES+=usr/share/examples/ipfilter/example.5
OLD_FILES+=usr/share/examples/ipfilter/example.6
OLD_FILES+=usr/share/examples/ipfilter/example.7
OLD_FILES+=usr/share/examples/ipfilter/example.8
OLD_FILES+=usr/share/examples/ipfilter/example.9
OLD_FILES+=usr/share/examples/ipfilter/example.sr
OLD_FILES+=usr/share/examples/ipfilter/examples.txt
OLD_FILES+=usr/share/examples/ipfilter/firewall
OLD_FILES+=usr/share/examples/ipfilter/firewall.1
OLD_FILES+=usr/share/examples/ipfilter/firewall.2
OLD_FILES+=usr/share/examples/ipfilter/ftp-proxy
OLD_FILES+=usr/share/examples/ipfilter/ftppxy
OLD_FILES+=usr/share/examples/ipfilter/ipf-howto.txt
OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.permissive
OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.restrictive
OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.sample
OLD_FILES+=usr/share/examples/ipfilter/ipnat.conf.sample
OLD_FILES+=usr/share/examples/ipfilter/mkfilters
OLD_FILES+=usr/share/examples/ipfilter/nat-setup
OLD_FILES+=usr/share/examples/ipfilter/nat.eg
OLD_FILES+=usr/share/examples/ipfilter/rules.txt
OLD_FILES+=usr/share/examples/ipfilter/server
OLD_FILES+=usr/share/examples/ipfilter/tcpstate
OLD_FILES+=usr/share/examples/ipfw/change_rules.sh
OLD_FILES+=usr/share/examples/jails/README
OLD_FILES+=usr/share/examples/jails/VIMAGE
OLD_FILES+=usr/share/examples/jails/jail.xxx.conf
OLD_FILES+=usr/share/examples/jails/jib
OLD_FILES+=usr/share/examples/jails/jng
OLD_FILES+=usr/share/examples/jails/rc.conf.jails
OLD_FILES+=usr/share/examples/jails/rcjail.xxx.conf
OLD_FILES+=usr/share/examples/kld/Makefile
OLD_FILES+=usr/share/examples/kld/cdev/Makefile
OLD_FILES+=usr/share/examples/kld/cdev/README
OLD_FILES+=usr/share/examples/kld/cdev/module/Makefile
OLD_FILES+=usr/share/examples/kld/cdev/module/cdev.c
OLD_FILES+=usr/share/examples/kld/cdev/module/cdev.h
OLD_FILES+=usr/share/examples/kld/cdev/module/cdevmod.c
OLD_FILES+=usr/share/examples/kld/cdev/test/Makefile
OLD_FILES+=usr/share/examples/kld/cdev/test/testcdev.c
OLD_FILES+=usr/share/examples/kld/dyn_sysctl/Makefile
OLD_FILES+=usr/share/examples/kld/dyn_sysctl/README
OLD_FILES+=usr/share/examples/kld/dyn_sysctl/dyn_sysctl.c
OLD_FILES+=usr/share/examples/kld/firmware/Makefile
OLD_FILES+=usr/share/examples/kld/firmware/README
OLD_FILES+=usr/share/examples/kld/firmware/fwconsumer/Makefile
OLD_FILES+=usr/share/examples/kld/firmware/fwconsumer/fw_consumer.c
OLD_FILES+=usr/share/examples/kld/firmware/fwimage/Makefile
OLD_FILES+=usr/share/examples/kld/firmware/fwimage/firmware.img.uu
OLD_FILES+=usr/share/examples/kld/khelp/Makefile
OLD_FILES+=usr/share/examples/kld/khelp/README
OLD_FILES+=usr/share/examples/kld/khelp/h_example.c
OLD_FILES+=usr/share/examples/kld/syscall/Makefile
OLD_FILES+=usr/share/examples/kld/syscall/module/Makefile
OLD_FILES+=usr/share/examples/kld/syscall/module/syscall.c
OLD_FILES+=usr/share/examples/kld/syscall/test/Makefile
OLD_FILES+=usr/share/examples/kld/syscall/test/call.c
OLD_FILES+=usr/share/examples/libusb20/Makefile
OLD_FILES+=usr/share/examples/libusb20/README
OLD_FILES+=usr/share/examples/libusb20/bulk.c
OLD_FILES+=usr/share/examples/libusb20/control.c
OLD_FILES+=usr/share/examples/libusb20/util.c
OLD_FILES+=usr/share/examples/libusb20/util.h
OLD_FILES+=usr/share/examples/libvgl/Makefile
OLD_FILES+=usr/share/examples/libvgl/demo.c
OLD_FILES+=usr/share/examples/mdoc/POSIX-copyright
OLD_FILES+=usr/share/examples/mdoc/deshallify.sh
OLD_FILES+=usr/share/examples/mdoc/example.1
OLD_FILES+=usr/share/examples/mdoc/example.3
OLD_FILES+=usr/share/examples/mdoc/example.4
OLD_FILES+=usr/share/examples/mdoc/example.9
OLD_FILES+=usr/share/examples/netgraph/ether.bridge
OLD_FILES+=usr/share/examples/netgraph/frame_relay
OLD_FILES+=usr/share/examples/netgraph/ngctl
OLD_FILES+=usr/share/examples/netgraph/raw
OLD_FILES+=usr/share/examples/netgraph/udp.tunnel
OLD_FILES+=usr/share/examples/netgraph/virtual.chain
OLD_FILES+=usr/share/examples/netgraph/virtual.lan
OLD_FILES+=usr/share/examples/perfmon/Makefile
OLD_FILES+=usr/share/examples/perfmon/README
OLD_FILES+=usr/share/examples/perfmon/perfmon.c
OLD_FILES+=usr/share/examples/pf/ackpri
OLD_FILES+=usr/share/examples/pf/faq-example1
OLD_FILES+=usr/share/examples/pf/faq-example2
OLD_FILES+=usr/share/examples/pf/faq-example3
OLD_FILES+=usr/share/examples/pf/pf.conf
OLD_FILES+=usr/share/examples/pf/queue1
OLD_FILES+=usr/share/examples/pf/queue2
OLD_FILES+=usr/share/examples/pf/queue3
OLD_FILES+=usr/share/examples/pf/queue4
OLD_FILES+=usr/share/examples/pf/spamd
OLD_FILES+=usr/share/examples/ppi/Makefile
OLD_FILES+=usr/share/examples/ppi/ppilcd.c
OLD_FILES+=usr/share/examples/ppp/chap-auth
OLD_FILES+=usr/share/examples/ppp/login-auth
OLD_FILES+=usr/share/examples/ppp/ppp.conf.sample
OLD_FILES+=usr/share/examples/ppp/ppp.conf.span-isp
OLD_FILES+=usr/share/examples/ppp/ppp.conf.span-isp.working
OLD_FILES+=usr/share/examples/ppp/ppp.linkdown.sample
OLD_FILES+=usr/share/examples/ppp/ppp.linkdown.span-isp
OLD_FILES+=usr/share/examples/ppp/ppp.linkdown.span-isp.working
OLD_FILES+=usr/share/examples/ppp/ppp.linkup.sample
OLD_FILES+=usr/share/examples/ppp/ppp.linkup.span-isp
OLD_FILES+=usr/share/examples/ppp/ppp.linkup.span-isp.working
OLD_FILES+=usr/share/examples/ppp/ppp.secret.sample
OLD_FILES+=usr/share/examples/ppp/ppp.secret.span-isp
OLD_FILES+=usr/share/examples/ppp/ppp.secret.span-isp.working
OLD_FILES+=usr/share/examples/printing/diablo-if-net
OLD_FILES+=usr/share/examples/printing/hpdf
OLD_FILES+=usr/share/examples/printing/hpif
OLD_FILES+=usr/share/examples/printing/hpof
OLD_FILES+=usr/share/examples/printing/hprf
OLD_FILES+=usr/share/examples/printing/hpvf
OLD_FILES+=usr/share/examples/printing/if-simple
OLD_FILES+=usr/share/examples/printing/if-simpleX
OLD_FILES+=usr/share/examples/printing/ifhp
OLD_FILES+=usr/share/examples/printing/make-ps-header
OLD_FILES+=usr/share/examples/printing/netprint
OLD_FILES+=usr/share/examples/printing/psdf
OLD_FILES+=usr/share/examples/printing/psdfX
OLD_FILES+=usr/share/examples/printing/psif
OLD_FILES+=usr/share/examples/printing/pstf
OLD_FILES+=usr/share/examples/printing/pstfX
OLD_FILES+=usr/share/examples/scsi_target/Makefile
OLD_FILES+=usr/share/examples/scsi_target/scsi_cmds.c
OLD_FILES+=usr/share/examples/scsi_target/scsi_target.8
OLD_FILES+=usr/share/examples/scsi_target/scsi_target.c
OLD_FILES+=usr/share/examples/scsi_target/scsi_target.h
OLD_FILES+=usr/share/examples/ses/Makefile
OLD_FILES+=usr/share/examples/ses/Makefile.inc
OLD_FILES+=usr/share/examples/ses/getencstat/Makefile
OLD_FILES+=usr/share/examples/ses/getencstat/getencstat.0
OLD_FILES+=usr/share/examples/ses/sesd/Makefile
OLD_FILES+=usr/share/examples/ses/sesd/sesd.0
OLD_FILES+=usr/share/examples/ses/setencstat/Makefile
OLD_FILES+=usr/share/examples/ses/setencstat/setencstat.0
OLD_FILES+=usr/share/examples/ses/setobjstat/Makefile
OLD_FILES+=usr/share/examples/ses/setobjstat/setobjstat.0
OLD_FILES+=usr/share/examples/ses/srcs/chpmon.c
OLD_FILES+=usr/share/examples/ses/srcs/eltsub.c
OLD_FILES+=usr/share/examples/ses/srcs/eltsub.h
OLD_FILES+=usr/share/examples/ses/srcs/getencstat.c
OLD_FILES+=usr/share/examples/ses/srcs/getnobj.c
OLD_FILES+=usr/share/examples/ses/srcs/getobjmap.c
OLD_FILES+=usr/share/examples/ses/srcs/getobjstat.c
OLD_FILES+=usr/share/examples/ses/srcs/inienc.c
OLD_FILES+=usr/share/examples/ses/srcs/sesd.c
OLD_FILES+=usr/share/examples/ses/srcs/setencstat.c
OLD_FILES+=usr/share/examples/ses/srcs/setobjstat.c
OLD_FILES+=usr/share/examples/smbfs/dot.nsmbrc
OLD_FILES+=usr/share/examples/smbfs/print/lj6l
OLD_FILES+=usr/share/examples/smbfs/print/ljspool
OLD_FILES+=usr/share/examples/smbfs/print/printcap.sample
OLD_FILES+=usr/share/examples/smbfs/print/tolj
OLD_FILES+=usr/share/examples/sunrpc/Makefile
OLD_FILES+=usr/share/examples/sunrpc/dir/Makefile
OLD_FILES+=usr/share/examples/sunrpc/dir/dir.x
OLD_FILES+=usr/share/examples/sunrpc/dir/dir_proc.c
OLD_FILES+=usr/share/examples/sunrpc/dir/rls.c
OLD_FILES+=usr/share/examples/sunrpc/msg/Makefile
OLD_FILES+=usr/share/examples/sunrpc/msg/msg.x
OLD_FILES+=usr/share/examples/sunrpc/msg/msg_proc.c
OLD_FILES+=usr/share/examples/sunrpc/msg/printmsg.c
OLD_FILES+=usr/share/examples/sunrpc/msg/rprintmsg.c
OLD_FILES+=usr/share/examples/sunrpc/sort/Makefile
OLD_FILES+=usr/share/examples/sunrpc/sort/rsort.c
OLD_FILES+=usr/share/examples/sunrpc/sort/sort.x
OLD_FILES+=usr/share/examples/sunrpc/sort/sort_proc.c
OLD_FILES+=usr/share/examples/tcsh/complete.tcsh
OLD_FILES+=usr/share/examples/tcsh/csh-mode.el
OLD_FILES+=usr/share/examples/uefisign/uefikeys
OLD_FILES+=usr/share/examples/ypldap/ypldap.conf
OLD_DIRS+=usr/share/examples
OLD_DIRS+=usr/share/examples/BSD_daemon
OLD_DIRS+=usr/share/examples/FreeBSD_version
OLD_DIRS+=usr/share/examples/IPv6
OLD_DIRS+=usr/share/examples/bhyve
OLD_DIRS+=usr/share/examples/bootforth
OLD_DIRS+=usr/share/examples/bsdconfig
OLD_DIRS+=usr/share/examples/csh
OLD_DIRS+=usr/share/examples/diskless
OLD_DIRS+=usr/share/examples/dma
OLD_DIRS+=usr/share/examples/drivers
OLD_DIRS+=usr/share/examples/dwatch
OLD_DIRS+=usr/share/examples/etc
OLD_DIRS+=usr/share/examples/etc/defaults
OLD_DIRS+=usr/share/examples/find_interface
OLD_DIRS+=usr/share/examples/hast
OLD_DIRS+=usr/share/examples/ibcs2
OLD_DIRS+=usr/share/examples/hostapd
OLD_DIRS+=usr/share/examples/indent
OLD_DIRS+=usr/share/examples/ipfilter
OLD_DIRS+=usr/share/examples/ipfw
OLD_DIRS+=usr/share/examples/jails
OLD_DIRS+=usr/share/examples/kld
OLD_DIRS+=usr/share/examples/kld/cdev
OLD_DIRS+=usr/share/examples/kld/cdev/module
OLD_DIRS+=usr/share/examples/kld/cdev/test
OLD_DIRS+=usr/share/examples/kld/dyn_sysctl
OLD_DIRS+=usr/share/examples/kld/firmware
OLD_DIRS+=usr/share/examples/kld/firmware/fwconsumer
OLD_DIRS+=usr/share/examples/kld/firmware/fwimage
OLD_DIRS+=usr/share/examples/kld/khelp
OLD_DIRS+=usr/share/examples/kld/syscall
OLD_DIRS+=usr/share/examples/kld/syscall/module
OLD_DIRS+=usr/share/examples/kld/syscall/test
OLD_DIRS+=usr/share/examples/libusb20
OLD_DIRS+=usr/share/examples/libvgl
OLD_DIRS+=usr/share/examples/mdoc
OLD_DIRS+=usr/share/examples/netgraph
OLD_DIRS+=usr/share/examples/perfmon
OLD_DIRS+=usr/share/examples/pf
OLD_DIRS+=usr/share/examples/ppi
OLD_DIRS+=usr/share/examples/ppp
OLD_DIRS+=usr/share/examples/printing
OLD_DIRS+=usr/share/examples/scsi_target
OLD_DIRS+=usr/share/examples/ses
OLD_DIRS+=usr/share/examples/ses/getencstat
OLD_DIRS+=usr/share/examples/ses/sesd
OLD_DIRS+=usr/share/examples/ses/setencstat
OLD_DIRS+=usr/share/examples/ses/setobjstat
OLD_DIRS+=usr/share/examples/ses/srcs
OLD_DIRS+=usr/share/examples/smbfs
OLD_DIRS+=usr/share/examples/smbfs/print
OLD_DIRS+=usr/share/examples/sunrpc
OLD_DIRS+=usr/share/examples/sunrpc/dir
OLD_DIRS+=usr/share/examples/sunrpc/msg
OLD_DIRS+=usr/share/examples/sunrpc/sort
OLD_DIRS+=usr/share/examples/tcsh
OLD_DIRS+=usr/share/examples/uefisign
OLD_DIRS+=usr/share/examples/ypldap
.endif
.if ${MK_FINGER} == no
OLD_FILES+=usr/bin/finger
OLD_FILES+=usr/share/man/man1/finger.1.gz
OLD_FILES+=usr/share/man/man5/finger.conf.5.gz
OLD_FILES+=usr/libexec/fingerd
OLD_FILES+=usr/share/man/man8/fingerd.8.gz
.endif
.if ${MK_FLOPPY} == no
OLD_FILES+=usr/sbin/fdcontrol
OLD_FILES+=usr/sbin/fdformat
OLD_FILES+=usr/sbin/fdread
OLD_FILES+=usr/sbin/fdwrite
OLD_FILES+=usr/share/man/man1/fdformat.1.gz
OLD_FILES+=usr/share/man/man1/fdread.1.gz
OLD_FILES+=usr/share/man/man1/fdwrite.1.gz
OLD_FILES+=usr/share/man/man8/fdcontrol.8.gz
.endif
.if ${MK_FORTH} == no
OLD_FILES+=usr/share/man/man8/beastie.4th.8.gz
OLD_FILES+=usr/share/man/man8/brand.4th.8.gz
OLD_FILES+=usr/share/man/man8/check-password.4th.8.gz
OLD_FILES+=usr/share/man/man8/color.4th.8.gz
OLD_FILES+=usr/share/man/man8/delay.4th.8.gz
OLD_FILES+=usr/share/man/man8/loader.4th.8.gz
OLD_FILES+=usr/share/man/man8/menu.4th.8.gz
OLD_FILES+=usr/share/man/man8/menusets.4th.8.gz
OLD_FILES+=usr/share/man/man8/version.4th.8.gz
.endif
.if ${MK_FREEBSD_UPDATE} == no
OLD_FILES+=etc/freebsd-update.conf
OLD_FILES+=usr/sbin/freebsd-update
OLD_FILES+=usr/share/examples/etc/freebsd-update.conf
OLD_FILES+=usr/share/man/man5/freebsd-update.conf.5.gz
OLD_FILES+=usr/share/man/man8/freebsd-update.8.gz
.endif
.if ${MK_FREEBSD_UPDATE} == no && ${MK_PORTSNAP} == no
OLD_FILES+=usr/libexec/phttpget
OLD_FILES+=usr/share/man/man8/phttpget.8.gz
.endif
.if ${MK_GAMES} == no
OLD_FILES+=usr/bin/caesar
OLD_FILES+=usr/bin/factor
OLD_FILES+=usr/bin/fortune
OLD_FILES+=usr/bin/grdc
OLD_FILES+=usr/bin/morse
OLD_FILES+=usr/bin/number
OLD_FILES+=usr/bin/pom
OLD_FILES+=usr/bin/primes
OLD_FILES+=usr/bin/random
OLD_FILES+=usr/bin/rot13
OLD_FILES+=usr/bin/strfile
OLD_FILES+=usr/bin/unstr
OLD_FILES+=usr/share/games/fortune/fortunes
OLD_FILES+=usr/share/games/fortune/fortunes.dat
OLD_FILES+=usr/share/games/fortune/freebsd-tips
OLD_FILES+=usr/share/games/fortune/freebsd-tips.dat
OLD_FILES+=usr/share/games/fortune/gerrold.limerick
OLD_FILES+=usr/share/games/fortune/gerrold.limerick.dat
OLD_FILES+=usr/share/games/fortune/limerick
OLD_FILES+=usr/share/games/fortune/limerick.dat
OLD_FILES+=usr/share/games/fortune/murphy
OLD_FILES+=usr/share/games/fortune/murphy-o
OLD_FILES+=usr/share/games/fortune/murphy-o.dat
OLD_FILES+=usr/share/games/fortune/murphy.dat
OLD_FILES+=usr/share/games/fortune/startrek
OLD_FILES+=usr/share/games/fortune/startrek.dat
OLD_FILES+=usr/share/games/fortune/zippy
OLD_FILES+=usr/share/games/fortune/zippy.dat
OLD_DIRS+=usr/share/games/fortune
OLD_DIRS+=usr/share/games
OLD_FILES+=usr/share/man/man6/caesar.6.gz
OLD_FILES+=usr/share/man/man6/factor.6.gz
OLD_FILES+=usr/share/man/man6/fortune.6.gz
OLD_FILES+=usr/share/man/man6/grdc.6.gz
OLD_FILES+=usr/share/man/man6/morse.6.gz
OLD_FILES+=usr/share/man/man6/number.6.gz
OLD_FILES+=usr/share/man/man6/pom.6.gz
OLD_FILES+=usr/share/man/man6/primes.6.gz
OLD_FILES+=usr/share/man/man6/random.6.gz
OLD_FILES+=usr/share/man/man6/rot13.6.gz
OLD_FILES+=usr/share/man/man8/strfile.8.gz
OLD_FILES+=usr/share/man/man8/unstr.8.gz
.endif
.if ${MK_LLVM_COV} == no && !defined(WITH_PORT_BASE_GCC)
OLD_FILES+=usr/bin/gcov
OLD_FILES+=usr/share/man/man1/gcov.1.gz
.endif
.if ${MK_LLVM_COV} == no
OLD_FILES+=usr/bin/llvm-cov
OLD_FILES+=usr/bin/llvm-profdata
OLD_FILES+=usr/share/man/man1/llvm-cov.1.gz
OLD_FILES+=usr/share/man/man1/llvm-profdata.1.gz
.endif
.if ${MK_GOOGLETEST} == no
OLD_FILES+=usr/include/gmock/gmock-actions.h
OLD_FILES+=usr/include/gmock/gmock-cardinalities.h
OLD_FILES+=usr/include/gmock/gmock-generated-actions.h
OLD_FILES+=usr/include/gmock/gmock-generated-function-mockers.h
OLD_FILES+=usr/include/gmock/gmock-generated-matchers.h
OLD_FILES+=usr/include/gmock/gmock-generated-nice-strict.h
OLD_FILES+=usr/include/gmock/gmock-matchers.h
OLD_FILES+=usr/include/gmock/gmock-more-actions.h
OLD_FILES+=usr/include/gmock/gmock-more-matchers.h
OLD_FILES+=usr/include/gmock/gmock-spec-builders.h
OLD_FILES+=usr/include/gmock/gmock.h
OLD_FILES+=usr/include/gmock/internal/custom/gmock-generated-actions.h
OLD_FILES+=usr/include/gmock/internal/custom/gmock-matchers.h
OLD_FILES+=usr/include/gmock/internal/custom/gmock-port.h
OLD_FILES+=usr/include/gmock/internal/gmock-generated-internal-utils.h
OLD_FILES+=usr/include/gmock/internal/gmock-internal-utils.h
OLD_FILES+=usr/include/gmock/internal/gmock-port.h
OLD_DIRS+=usr/include/gmock
OLD_FILES+=usr/include/gtest/gtest_pred_impl.h
OLD_FILES+=usr/include/gtest/gtest_prod.h
OLD_FILES+=usr/include/gtest/gtest-death-test.h
OLD_FILES+=usr/include/gtest/gtest-message.h
OLD_FILES+=usr/include/gtest/gtest-param-test.h
OLD_FILES+=usr/include/gtest/gtest-printers.h
OLD_FILES+=usr/include/gtest/gtest-spi.h
OLD_FILES+=usr/include/gtest/gtest-test-part.h
OLD_FILES+=usr/include/gtest/gtest-typed-test.h
OLD_FILES+=usr/include/gtest/gtest.h
OLD_FILES+=usr/include/gtest/internal/custom/gtest-port.h
OLD_FILES+=usr/include/gtest/internal/custom/gtest-printers.h
OLD_FILES+=usr/include/gtest/internal/custom/gtest.h
OLD_FILES+=usr/include/gtest/internal/gtest-death-test-internal.h
OLD_FILES+=usr/include/gtest/internal/gtest-filepath.h
OLD_FILES+=usr/include/gtest/internal/gtest-internal.h
OLD_FILES+=usr/include/gtest/internal/gtest-linked_ptr.h
OLD_FILES+=usr/include/gtest/internal/gtest-param-util-generated.h
OLD_FILES+=usr/include/gtest/internal/gtest-param-util.h
OLD_FILES+=usr/include/gtest/internal/gtest-port-arch.h
OLD_FILES+=usr/include/gtest/internal/gtest-port.h
OLD_FILES+=usr/include/gtest/internal/gtest-string.h
OLD_FILES+=usr/include/gtest/internal/gtest-tuple.h
OLD_FILES+=usr/include/gtest/internal/gtest-type-util.h
OLD_DIRS+=usr/include/gtest
OLD_FILES+=usr/lib/libprivategmock_main.a
OLD_FILES+=usr/lib/libprivategmock_main.so
OLD_LIBS+=usr/lib/libprivategmock_main.so.0
OLD_FILES+=usr/lib/libprivategmock_main_p.a
OLD_FILES+=usr/lib/libprivategmock.a
OLD_FILES+=usr/lib/libprivategmock.so
OLD_LIBS+=usr/lib/libprivategmock.so.0
OLD_FILES+=usr/lib/libprivategmock_p.a
OLD_FILES+=usr/lib/libprivategtest_main.a
OLD_FILES+=usr/lib/libprivategtest_main.so
OLD_LIBS+=usr/lib/libprivategtest_main.so.0
OLD_FILES+=usr/lib/libprivategtest_main_p.a
OLD_FILES+=usr/lib/libprivategtest.a
OLD_FILES+=usr/lib/libprivategtest.so
OLD_LIBS+=usr/lib/libprivategtest.so.0
OLD_FILES+=usr/lib/libprivategtest_p.a
OLD_FILES+=usr/tests/lib/googletest/gmock/gmock_stress_test
OLD_FILES+=usr/tests/lib/googletest/gmock/Kyuafile
OLD_DIRS+=usr/tests/lib/googletest/gmock
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock_ex_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock_link_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-actions_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-cardinalities_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-ex_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-generated-actions_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-generated-function-mockers_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-generated-internal-utils_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-generated-matchers_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-internal-utils_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-matchers_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-more-actions_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-nice-strict_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-port_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-spec-builders_test
OLD_FILES+=usr/tests/lib/googletest/gmock_main/Kyuafile
OLD_DIRS+=usr/tests/lib/googletest/gmock_main
OLD_FILES+=usr/tests/lib/googletest/gtest/googletest-param-test-test
OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_all_test
OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_environment_test
OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_no_test_unittest
OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_premature_exit_test
OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_repeat_test
OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_stress_test
OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_throw_on_failure_ex_test
OLD_FILES+=usr/tests/lib/googletest/gtest/gtest-death-test_ex_catch_test
OLD_FILES+=usr/tests/lib/googletest/gtest/gtest-death-test_ex_nocatch_test
OLD_FILES+=usr/tests/lib/googletest/gtest/gtest-unittest-api_test
OLD_FILES+=usr/tests/lib/googletest/gtest/Kyuafile
OLD_DIRS+=usr/tests/lib/googletest/gtest
OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-death-test-test
OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-filepath-test
OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-linked-ptr-test
OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-listener-test
OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-message-test
OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-options-test
OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-port-test
OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-printers-test
OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-test-part-test
OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_help_test_
OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_main_unittest
OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_pred_impl_unittest
OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_prod_test
OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_sole_header_test
OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_unittest
OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_xml_outfile1_test_
OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_xml_outfile2_test_
OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest-typed-test_test
OLD_FILES+=usr/tests/lib/googletest/gtest_main/Kyuafile
OLD_DIRS+=usr/tests/lib/googletest/gtest_main
OLD_FILES+=usr/tests/lib/googletest/Kyuafile
OLD_DIRS+=usr/tests/lib/googletest/
OLD_FILES+=usr/tests/share/examples/tests/googletest/Kyuafile
OLD_FILES+=usr/tests/share/examples/tests/googletest/sample1_unittest
OLD_FILES+=usr/tests/share/examples/tests/googletest/sample10_unittest
OLD_FILES+=usr/tests/share/examples/tests/googletest/sample2_unittest
OLD_FILES+=usr/tests/share/examples/tests/googletest/sample3_unittest
OLD_FILES+=usr/tests/share/examples/tests/googletest/sample4_unittest
OLD_FILES+=usr/tests/share/examples/tests/googletest/sample5_unittest
OLD_FILES+=usr/tests/share/examples/tests/googletest/sample6_unittest
OLD_FILES+=usr/tests/share/examples/tests/googletest/sample7_unittest
OLD_FILES+=usr/tests/share/examples/tests/googletest/sample8_unittest
OLD_DIRS+=usr/tests/share/examples/tests/googletest
.endif
.if ${MK_GPIO} == no
OLD_FILES+=usr/include/libgpio.h
OLD_FILES+=usr/lib/libgpio.a
OLD_FILES+=usr/lib/libgpio.so
OLD_LIBS+=usr/lib/libgpio.so.0
OLD_FILES+=usr/lib/libgpio_p.a
OLD_FILES+=usr/sbin/gpioctl
OLD_FILES+=usr/share/man/man3/gpio.3.gz
OLD_FILES+=usr/share/man/man3/gpio_close.3.gz
OLD_FILES+=usr/share/man/man3/gpio_open.3.gz
OLD_FILES+=usr/share/man/man3/gpio_open_device.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_config.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_get.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_high.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_input.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_invin.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_invout.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_list.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_low.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_opendrain.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_output.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_pulldown.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_pullup.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_pulsate.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_pushpull.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_set.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_set_flags.3.gz
OLD_FILES+=usr/share/man/man3/gpio_pin_tristate.3.gz
OLD_FILES+=usr/share/man/man8/gpioctl.8.gz
.endif
.if ${MK_GNU_DIFF} == no
OLD_FILES+=usr/bin/diff3
OLD_FILES+=usr/share/man/man1/diff3.1.gz
.endif
.if ${MK_GSSAPI} == no
OLD_FILES+=usr/include/gssapi/gssapi.h
OLD_DIRS+=usr/include/gssapi
OLD_FILES+=usr/include/gssapi.h
OLD_FILES+=usr/lib/libgssapi.a
OLD_FILES+=usr/lib/libgssapi.so
OLD_LIBS+=usr/lib/libgssapi.so.10
OLD_FILES+=usr/lib/libgssapi_p.a
OLD_FILES+=usr/lib/librpcsec_gss.a
OLD_FILES+=usr/lib/librpcsec_gss.so
OLD_LIBS+=usr/lib/librpcsec_gss.so.1
OLD_FILES+=usr/sbin/gssd
OLD_FILES+=usr/share/man/man3/gss_accept_sec_context.3.gz
OLD_FILES+=usr/share/man/man3/gss_acquire_cred.3.gz
OLD_FILES+=usr/share/man/man3/gss_add_cred.3.gz
OLD_FILES+=usr/share/man/man3/gss_add_oid_set_member.3.gz
OLD_FILES+=usr/share/man/man3/gss_canonicalize_name.3.gz
OLD_FILES+=usr/share/man/man3/gss_compare_name.3.gz
OLD_FILES+=usr/share/man/man3/gss_context_time.3.gz
OLD_FILES+=usr/share/man/man3/gss_create_empty_oid_set.3.gz
OLD_FILES+=usr/share/man/man3/gss_delete_sec_context.3.gz
OLD_FILES+=usr/share/man/man3/gss_display_name.3.gz
OLD_FILES+=usr/share/man/man3/gss_display_status.3.gz
OLD_FILES+=usr/share/man/man3/gss_duplicate_name.3.gz
OLD_FILES+=usr/share/man/man3/gss_export_name.3.gz
OLD_FILES+=usr/share/man/man3/gss_export_sec_context.3.gz
OLD_FILES+=usr/share/man/man3/gss_get_mic.3.gz
OLD_FILES+=usr/share/man/man3/gss_import_name.3.gz
OLD_FILES+=usr/share/man/man3/gss_import_sec_context.3.gz
OLD_FILES+=usr/share/man/man3/gss_indicate_mechs.3.gz
OLD_FILES+=usr/share/man/man3/gss_init_sec_context.3.gz
OLD_FILES+=usr/share/man/man3/gss_inquire_context.3.gz
OLD_FILES+=usr/share/man/man3/gss_inquire_cred.3.gz
OLD_FILES+=usr/share/man/man3/gss_inquire_cred_by_mech.3.gz
OLD_FILES+=usr/share/man/man3/gss_inquire_mechs_for_name.3.gz
OLD_FILES+=usr/share/man/man3/gss_inquire_names_for_mech.3.gz
OLD_FILES+=usr/share/man/man3/gss_process_context_token.3.gz
OLD_FILES+=usr/share/man/man3/gss_release_buffer.3.gz
OLD_FILES+=usr/share/man/man3/gss_release_cred.3.gz
OLD_FILES+=usr/share/man/man3/gss_release_name.3.gz
OLD_FILES+=usr/share/man/man3/gss_release_oid_set.3.gz
OLD_FILES+=usr/share/man/man3/gss_seal.3.gz
OLD_FILES+=usr/share/man/man3/gss_sign.3.gz
OLD_FILES+=usr/share/man/man3/gss_test_oid_set_member.3.gz
OLD_FILES+=usr/share/man/man3/gss_unseal.3.gz
OLD_FILES+=usr/share/man/man3/gss_unwrap.3.gz
OLD_FILES+=usr/share/man/man3/gss_verify.3.gz
OLD_FILES+=usr/share/man/man3/gss_verify_mic.3.gz
OLD_FILES+=usr/share/man/man3/gss_wrap.3.gz
OLD_FILES+=usr/share/man/man3/gss_wrap_size_limit.3.gz
OLD_FILES+=usr/share/man/man3/gssapi.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_get_error.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_get_mech_info.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_get_mechanisms.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_get_principal_name.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_get_versions.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_getcred.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_is_installed.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_max_data_length.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_mech_to_oid.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_oid_to_mech.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_qop_to_num.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_seccreate.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_set_callback.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_set_defaults.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_set_svc_name.3.gz
OLD_FILES+=usr/share/man/man3/rpc_gss_svc_max_data_length.3.gz
OLD_FILES+=usr/share/man/man3/rpcsec_gss.3.gz
OLD_FILES+=usr/share/man/man5/mech.5.gz
OLD_FILES+=usr/share/man/man5/qop.5.gz
OLD_FILES+=usr/share/man/man8/gssd.8.gz
.endif
.if ${MK_HAST} == no
OLD_FILES+=etc/rc.d/hastd
OLD_FILES+=sbin/hastctl
OLD_FILES+=sbin/hastd
OLD_FILES+=usr/share/examples/hast/ucarp.sh
OLD_FILES+=usr/share/examples/hast/ucarp_down.sh
OLD_FILES+=usr/share/examples/hast/ucarp_up.sh
OLD_FILES+=usr/share/examples/hast/vip-down.sh
OLD_FILES+=usr/share/examples/hast/vip-up.sh
OLD_FILES+=usr/share/man/man5/hast.conf.5.gz
OLD_FILES+=usr/share/man/man8/hastctl.8.gz
OLD_FILES+=usr/share/man/man8/hastd.8.gz
OLD_DIRS+=usr/share/examples/hast
# bsnmp
OLD_FILES+=usr/lib/snmp_hast.so
OLD_LIBS+=usr/lib/snmp_hast.so.6
OLD_FILES+=usr/share/man/man3/snmp_hast.3.gz
OLD_FILES+=usr/share/snmp/defs/hast_tree.def
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-HAST-MIB.txt
.endif
.if ${MK_HESIOD} == no
OLD_FILES+=usr/bin/hesinfo
OLD_FILES+=usr/include/hesiod.h
OLD_FILES+=usr/share/man/man1/hesinfo.1.gz
OLD_FILES+=usr/share/man/man3/hesiod.3.gz
OLD_FILES+=usr/share/man/man5/hesiod.conf.5.gz
.endif
.if ${MK_HTML} == no
OLD_FILES+=usr/share/doc/ncurses/hackguide.html
OLD_FILES+=usr/share/doc/ncurses/ncurses-intro.html
OLD_DIRS+=usr/share/doc/ncurses
OLD_FILES+=usr/share/doc/ntp/accopt.html
OLD_FILES+=usr/share/doc/ntp/assoc.html
OLD_FILES+=usr/share/doc/ntp/audio.html
OLD_FILES+=usr/share/doc/ntp/authopt.html
OLD_FILES+=usr/share/doc/ntp/build.html
OLD_FILES+=usr/share/doc/ntp/clockopt.html
OLD_FILES+=usr/share/doc/ntp/config.html
OLD_FILES+=usr/share/doc/ntp/confopt.html
OLD_FILES+=usr/share/doc/ntp/copyright.html
OLD_FILES+=usr/share/doc/ntp/debug.html
OLD_FILES+=usr/share/doc/ntp/driver1.html
OLD_FILES+=usr/share/doc/ntp/driver10.html
OLD_FILES+=usr/share/doc/ntp/driver11.html
OLD_FILES+=usr/share/doc/ntp/driver12.html
OLD_FILES+=usr/share/doc/ntp/driver16.html
OLD_FILES+=usr/share/doc/ntp/driver18.html
OLD_FILES+=usr/share/doc/ntp/driver19.html
OLD_FILES+=usr/share/doc/ntp/driver2.html
OLD_FILES+=usr/share/doc/ntp/driver20.html
OLD_FILES+=usr/share/doc/ntp/driver22.html
OLD_FILES+=usr/share/doc/ntp/driver26.html
OLD_FILES+=usr/share/doc/ntp/driver27.html
OLD_FILES+=usr/share/doc/ntp/driver28.html
OLD_FILES+=usr/share/doc/ntp/driver29.html
OLD_FILES+=usr/share/doc/ntp/driver3.html
OLD_FILES+=usr/share/doc/ntp/driver30.html
OLD_FILES+=usr/share/doc/ntp/driver32.html
OLD_FILES+=usr/share/doc/ntp/driver33.html
OLD_FILES+=usr/share/doc/ntp/driver34.html
OLD_FILES+=usr/share/doc/ntp/driver35.html
OLD_FILES+=usr/share/doc/ntp/driver36.html
OLD_FILES+=usr/share/doc/ntp/driver37.html
OLD_FILES+=usr/share/doc/ntp/driver4.html
OLD_FILES+=usr/share/doc/ntp/driver5.html
OLD_FILES+=usr/share/doc/ntp/driver6.html
OLD_FILES+=usr/share/doc/ntp/driver7.html
OLD_FILES+=usr/share/doc/ntp/driver8.html
OLD_FILES+=usr/share/doc/ntp/driver9.html
OLD_FILES+=usr/share/doc/ntp/extern.html
OLD_FILES+=usr/share/doc/ntp/hints.html
OLD_FILES+=usr/share/doc/ntp/howto.html
OLD_FILES+=usr/share/doc/ntp/index.html
OLD_FILES+=usr/share/doc/ntp/kern.html
OLD_FILES+=usr/share/doc/ntp/ldisc.html
OLD_FILES+=usr/share/doc/ntp/measure.html
OLD_FILES+=usr/share/doc/ntp/miscopt.html
OLD_FILES+=usr/share/doc/ntp/monopt.html
OLD_FILES+=usr/share/doc/ntp/mx4200data.html
OLD_FILES+=usr/share/doc/ntp/notes.html
OLD_FILES+=usr/share/doc/ntp/ntpd.html
OLD_FILES+=usr/share/doc/ntp/ntpdate.html
OLD_FILES+=usr/share/doc/ntp/ntpdc.html
OLD_FILES+=usr/share/doc/ntp/ntpq.html
OLD_FILES+=usr/share/doc/ntp/ntptime.html
OLD_FILES+=usr/share/doc/ntp/ntptrace.html
OLD_FILES+=usr/share/doc/ntp/parsedata.html
OLD_FILES+=usr/share/doc/ntp/parsenew.html
OLD_FILES+=usr/share/doc/ntp/patches.html
OLD_FILES+=usr/share/doc/ntp/porting.html
OLD_FILES+=usr/share/doc/ntp/pps.html
OLD_FILES+=usr/share/doc/ntp/prefer.html
OLD_FILES+=usr/share/doc/ntp/quick.html
OLD_FILES+=usr/share/doc/ntp/rdebug.html
OLD_FILES+=usr/share/doc/ntp/refclock.html
OLD_FILES+=usr/share/doc/ntp/release.html
OLD_FILES+=usr/share/doc/ntp/tickadj.html
.endif
.if ${MK_ICONV} == no
OLD_FILES+=usr/bin/iconv
OLD_FILES+=usr/bin/mkcsmapper
OLD_FILES+=usr/bin/mkesdb
OLD_FILES+=usr/include/_libiconv_compat.h
OLD_FILES+=usr/include/iconv.h
OLD_FILES+=usr/share/man/man1/iconv.1.gz
OLD_FILES+=usr/share/man/man1/mkcsmapper.1.gz
OLD_FILES+=usr/share/man/man1/mkesdb.1.gz
OLD_FILES+=usr/share/man/man3/__iconv.3.gz
OLD_FILES+=usr/share/man/man3/__iconv_free_list.3.gz
OLD_FILES+=usr/share/man/man3/__iconv_get_list.3.gz
OLD_FILES+=usr/share/man/man3/iconv.3.gz
OLD_FILES+=usr/share/man/man3/iconv_canonicalize.3.gz
OLD_FILES+=usr/share/man/man3/iconv_close.3.gz
OLD_FILES+=usr/share/man/man3/iconv_open.3.gz
OLD_FILES+=usr/share/man/man3/iconv_open_into.3.gz
OLD_FILES+=usr/share/man/man3/iconvctl.3.gz
OLD_FILES+=usr/share/man/man3/iconvlist.3.gz
OLD_DIRS+=usr/share/i18n
OLD_DIRS+=usr/share/i18n/esdb
OLD_DIRS+=usr/share/i18n/esdb/ISO-2022
OLD_DIRS+=usr/share/i18n/esdb/BIG5
OLD_DIRS+=usr/share/i18n/esdb/MISC
OLD_DIRS+=usr/share/i18n/esdb/TCVN
OLD_DIRS+=usr/share/i18n/esdb/EBCDIC
OLD_DIRS+=usr/share/i18n/esdb/ISO-8859
OLD_DIRS+=usr/share/i18n/esdb/GEORGIAN
OLD_DIRS+=usr/share/i18n/esdb/AST
OLD_DIRS+=usr/share/i18n/esdb/KAZAKH
OLD_DIRS+=usr/share/i18n/esdb/APPLE
OLD_DIRS+=usr/share/i18n/esdb/EUC
OLD_DIRS+=usr/share/i18n/esdb/CP
OLD_DIRS+=usr/share/i18n/esdb/DEC
OLD_DIRS+=usr/share/i18n/esdb/UTF
OLD_DIRS+=usr/share/i18n/esdb/GB
OLD_DIRS+=usr/share/i18n/esdb/ISO646
OLD_DIRS+=usr/share/i18n/esdb/KOI
OLD_DIRS+=usr/share/i18n/csmapper
OLD_DIRS+=usr/share/i18n/csmapper/KAZAKH
OLD_DIRS+=usr/share/i18n/csmapper/CNS
OLD_DIRS+=usr/share/i18n/csmapper/BIG5
OLD_DIRS+=usr/share/i18n/csmapper/JIS
OLD_DIRS+=usr/share/i18n/csmapper/KOI
OLD_DIRS+=usr/share/i18n/csmapper/TCVN
OLD_DIRS+=usr/share/i18n/csmapper/MISC
OLD_DIRS+=usr/share/i18n/csmapper/EBCDIC
OLD_DIRS+=usr/share/i18n/csmapper/ISO646
OLD_DIRS+=usr/share/i18n/csmapper/CP
OLD_DIRS+=usr/share/i18n/csmapper/GEORGIAN
OLD_DIRS+=usr/share/i18n/csmapper/ISO-8859
OLD_DIRS+=usr/share/i18n/csmapper/AST
OLD_DIRS+=usr/share/i18n/csmapper/APPLE
OLD_DIRS+=usr/share/i18n/csmapper/KS
OLD_DIRS+=usr/share/i18n/csmapper/GB
.endif
.if ${MK_INET} == no && ${MK_INET6} == no
OLD_FILES+=sbin/ping
OLD_FILES+=usr/share/man/man8/ping.8.gz
.endif
.if ${MK_INET6} == no
OLD_FILES+=sbin/ping6
OLD_FILES+=sbin/rtsol
OLD_FILES+=usr/sbin/ip6addrctl
OLD_FILES+=usr/sbin/mld6query
OLD_FILES+=usr/sbin/ndp
OLD_FILES+=usr/sbin/rip6query
OLD_FILES+=usr/sbin/route6d
OLD_FILES+=usr/sbin/rrenumd
OLD_FILES+=usr/sbin/rtadvctl
OLD_FILES+=usr/sbin/rtadvd
OLD_FILES+=usr/sbin/rtsold
OLD_FILES+=usr/sbin/traceroute6
OLD_FILES+=usr/share/doc/IPv6/IMPLEMENTATION
OLD_FILES+=usr/share/man/man5/rrenumd.conf.5.gz
OLD_FILES+=usr/share/man/man5/rtadvd.conf.5.gz
OLD_FILES+=usr/share/man/man8/ip6addrctl.8.gz
OLD_FILES+=usr/share/man/man8/mld6query.8.gz
OLD_FILES+=usr/share/man/man8/ndp.8.gz
OLD_FILES+=usr/share/man/man8/rip6query.8.gz
OLD_FILES+=usr/share/man/man8/route6d.8.gz
OLD_FILES+=usr/share/man/man8/rrenumd.8.gz
OLD_FILES+=usr/share/man/man8/rtadvctl.8.gz
OLD_FILES+=usr/share/man/man8/rtadvd.8.gz
OLD_FILES+=usr/share/man/man8/rtsol.8.gz
OLD_FILES+=usr/share/man/man8/rtsold.8.gz
OLD_FILES+=usr/share/man/man8/traceroute6.8.gz
.endif
.if ${MK_INET6_SUPPORT} == no
OLD_FILES+=rescue/ping6
OLD_FILES+=rescue/rtsol
.endif
.if ${MK_INETD} == no
OLD_FILES+=etc/inetd.conf
OLD_FILES+=etc/rc.d/inetd
OLD_FILES+=usr/sbin/inetd
OLD_FILES+=usr/share/man/man5/inetd.conf.5.gz
OLD_FILES+=usr/share/man/man8/inetd.8.gz
.endif
.if ${MK_IPFILTER} == no
OLD_FILES+=etc/periodic/security/510.ipfdenied
OLD_FILES+=etc/periodic/security/610.ipf6denied
OLD_FILES+=etc/rc.d/ipfilter
OLD_FILES+=etc/rc.d/ipfs
OLD_FILES+=etc/rc.d/ipmon
OLD_FILES+=etc/rc.d/ipnat
OLD_FILES+=etc/rc.d/ippool
OLD_FILES+=rescue/ipf
OLD_FILES+=sbin/ipf
OLD_FILES+=sbin/ipfs
OLD_FILES+=sbin/ipfstat
OLD_FILES+=sbin/ipftest
OLD_FILES+=sbin/ipmon
OLD_FILES+=sbin/ipnat
OLD_FILES+=sbin/ippool
OLD_FILES+=sbin/ipresend
OLD_FILES+=usr/include/netinet/ip_auth.h
OLD_FILES+=usr/include/netinet/ip_compat.h
OLD_FILES+=usr/include/netinet/ip_fil.h
OLD_FILES+=usr/include/netinet/ip_frag.h
OLD_FILES+=usr/include/netinet/ip_htable.h
OLD_FILES+=usr/include/netinet/ip_lookup.h
OLD_FILES+=usr/include/netinet/ip_nat.h
OLD_FILES+=usr/include/netinet/ip_pool.h
OLD_FILES+=usr/include/netinet/ip_proxy.h
OLD_FILES+=usr/include/netinet/ip_rules.h
OLD_FILES+=usr/include/netinet/ip_scan.h
OLD_FILES+=usr/include/netinet/ip_state.h
OLD_FILES+=usr/include/netinet/ip_sync.h
OLD_FILES+=usr/include/netinet/ipl.h
OLD_FILES+=usr/share/examples/ipfilter/README
OLD_FILES+=usr/share/examples/ipfilter/BASIC.NAT
OLD_FILES+=usr/share/examples/ipfilter/BASIC_1.FW
OLD_FILES+=usr/share/examples/ipfilter/BASIC_2.FW
OLD_FILES+=usr/share/examples/ipfilter/example.1
OLD_FILES+=usr/share/examples/ipfilter/example.2
OLD_FILES+=usr/share/examples/ipfilter/example.3
OLD_FILES+=usr/share/examples/ipfilter/example.4
OLD_FILES+=usr/share/examples/ipfilter/example.5
OLD_FILES+=usr/share/examples/ipfilter/example.6
OLD_FILES+=usr/share/examples/ipfilter/example.7
OLD_FILES+=usr/share/examples/ipfilter/example.8
OLD_FILES+=usr/share/examples/ipfilter/example.9
OLD_FILES+=usr/share/examples/ipfilter/example.10
OLD_FILES+=usr/share/examples/ipfilter/example.11
OLD_FILES+=usr/share/examples/ipfilter/example.12
OLD_FILES+=usr/share/examples/ipfilter/example.13
OLD_FILES+=usr/share/examples/ipfilter/example.sr
OLD_FILES+=usr/share/examples/ipfilter/firewall
OLD_FILES+=usr/share/examples/ipfilter/ftp-proxy
OLD_FILES+=usr/share/examples/ipfilter/ftppxy
OLD_FILES+=usr/share/examples/ipfilter/nat-setup
OLD_FILES+=usr/share/examples/ipfilter/nat.eg
OLD_FILES+=usr/share/examples/ipfilter/server
OLD_FILES+=usr/share/examples/ipfilter/tcpstate
OLD_FILES+=usr/share/examples/ipfilter/example.14
OLD_FILES+=usr/share/examples/ipfilter/firewall.1
OLD_FILES+=usr/share/examples/ipfilter/firewall.2
OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.permissive
OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.restrictive
OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.sample
OLD_FILES+=usr/share/examples/ipfilter/ipnat.conf.sample
OLD_FILES+=usr/share/examples/ipfilter/ipf-howto.txt
OLD_FILES+=usr/share/examples/ipfilter/examples.txt
OLD_FILES+=usr/share/examples/ipfilter/rules.txt
OLD_FILES+=usr/share/examples/ipfilter/mkfilters
OLD_DIRS+=usr/share/examples/ipfilter
OLD_FILES+=usr/share/man/man1/ipftest.1.gz
OLD_FILES+=usr/share/man/man1/ipresend.1.gz
OLD_FILES+=usr/share/man/man4/ipf.4.gz
OLD_FILES+=usr/share/man/man4/ipl.4.gz
OLD_FILES+=usr/share/man/man4/ipfilter.4.gz
OLD_FILES+=usr/share/man/man4/ipnat.4.gz
OLD_FILES+=usr/share/man/man5/ipf.5.gz
OLD_FILES+=usr/share/man/man5/ipf.conf.5.gz
OLD_FILES+=usr/share/man/man5/ipf6.conf.5.gz
OLD_FILES+=usr/share/man/man5/ipfilter.5.gz
OLD_FILES+=usr/share/man/man8/ipmon.5.gz
OLD_FILES+=usr/share/man/man5/ipmon.conf.5.gz
OLD_FILES+=usr/share/man/man5/ipnat.5.gz
OLD_FILES+=usr/share/man/man5/ipnat.conf.5.gz
OLD_FILES+=usr/share/man/man5/ippool.5.gz
OLD_FILES+=usr/share/man/man8/ipf.8.gz
OLD_FILES+=usr/share/man/man8/ipfs.8.gz
OLD_FILES+=usr/share/man/man8/ipfstat.8.gz
OLD_FILES+=usr/share/man/man8/ipmon.8.gz
OLD_FILES+=usr/share/man/man8/ipnat.8.gz
OLD_FILES+=usr/share/man/man8/ippool.8.gz
.endif
.if ${MK_IPFW} == no
OLD_FILES+=etc/rc.d/ipfw
OLD_FILES+=etc/periodic/security/500.ipfwdenied
OLD_FILES+=etc/periodic/security/550.ipfwlimit
OLD_FILES+=sbin/ipfw
OLD_FILES+=sbin/natd
OLD_FILES+=usr/sbin/ipfwpcap
OLD_FILES+=usr/share/man/man8/ipfw.8.gz
OLD_FILES+=usr/share/man/man8/ipfwpcap.8.gz
OLD_FILES+=usr/share/man/man8/natd.8.gz
.endif
.if ${MK_ISCSI} == no
OLD_FILES+=etc/rc.d/iscsictl
OLD_FILES+=etc/rc.d/iscsid
OLD_FILES+=rescue/iscsictl
OLD_FILES+=rescue/iscsid
OLD_FILES+=sbin/iscontrol
OLD_FILES+=usr/bin/iscsictl
OLD_FILES+=usr/sbin/iscsid
OLD_FILES+=usr/share/man/man4/iscsi.4.gz
OLD_FILES+=usr/share/man/man4/iscsi_initiator.4.gz
OLD_FILES+=usr/share/man/man5/iscsi.conf.5.gz
OLD_FILES+=usr/share/man/man8/iscontrol.8.gz
OLD_FILES+=usr/share/man/man8/iscsictl.8.gz
OLD_FILES+=usr/share/man/man8/iscsid.8.gz
.endif
.if ${MK_JAIL} == no
OLD_FILES+=etc/rc.d/jail
OLD_FILES+=usr/sbin/jail
OLD_FILES+=usr/sbin/jexec
OLD_FILES+=usr/sbin/jls
OLD_FILES+=usr/share/man/man5/jail.conf.5.gz
OLD_FILES+=usr/share/man/man8/jail.8.gz
OLD_FILES+=usr/share/man/man8/jexec.8.gz
OLD_FILES+=usr/share/man/man8/jls.8.gz
.endif
.if ${MK_KDUMP} == no
OLD_FILES+=usr/bin/kdump
OLD_FILES+=usr/bin/truss
OLD_FILES+=usr/share/man/man1/kdump.1.gz
OLD_FILES+=usr/share/man/man1/truss.1.gz
.endif
.if ${MK_KERBEROS} == no
OLD_FILES+=etc/rc.d/ipropd_master
OLD_FILES+=etc/rc.d/ipropd_slave
OLD_FILES+=usr/bin/asn1_compile
OLD_FILES+=usr/bin/compile_et
OLD_FILES+=usr/bin/hxtool
OLD_FILES+=usr/bin/kadmin
OLD_FILES+=usr/bin/kcc
OLD_FILES+=usr/bin/kdestroy
OLD_FILES+=usr/bin/kf
OLD_FILES+=usr/bin/kgetcred
OLD_FILES+=usr/bin/kinit
OLD_FILES+=usr/bin/klist
OLD_FILES+=usr/bin/kpasswd
OLD_FILES+=usr/bin/krb5-config
OLD_FILES+=usr/bin/ksu
OLD_FILES+=usr/bin/kswitch
OLD_FILES+=usr/bin/make-roken
OLD_FILES+=usr/bin/slc
OLD_FILES+=usr/bin/string2key
OLD_FILES+=usr/bin/verify_krb5_conf
OLD_FILES+=usr/include/asn1-common.h
OLD_FILES+=usr/include/asn1_err.h
OLD_FILES+=usr/include/base64.h
OLD_FILES+=usr/include/cms_asn1.h
OLD_FILES+=usr/include/crmf_asn1.h
OLD_FILES+=usr/include/der-private.h
OLD_FILES+=usr/include/der-protos.h
OLD_FILES+=usr/include/der.h
OLD_FILES+=usr/include/digest_asn1.h
OLD_FILES+=usr/include/getarg.h
OLD_FILES+=usr/include/gssapi/gssapi_krb5.h
OLD_FILES+=usr/include/hdb-protos.h
OLD_FILES+=usr/include/hdb.h
OLD_FILES+=usr/include/hdb_asn1.h
OLD_FILES+=usr/include/hdb_err.h
OLD_FILES+=usr/include/heim_asn1.h
OLD_FILES+=usr/include/heim_err.h
OLD_FILES+=usr/include/heim_threads.h
OLD_FILES+=usr/include/heimbase.h
OLD_FILES+=usr/include/heimntlm-protos.h
OLD_FILES+=usr/include/heimntlm.h
OLD_FILES+=usr/include/hex.h
OLD_FILES+=usr/include/hx509-private.h
OLD_FILES+=usr/include/hx509-protos.h
OLD_FILES+=usr/include/hx509.h
OLD_FILES+=usr/include/hx509_err.h
OLD_FILES+=usr/include/k524_err.h
OLD_FILES+=usr/include/kadm5/admin.h
OLD_FILES+=usr/include/kadm5/kadm5-private.h
OLD_FILES+=usr/include/kadm5/kadm5-protos.h
OLD_FILES+=usr/include/kadm5/kadm5-pwcheck.h
OLD_FILES+=usr/include/kadm5/kadm5_err.h
OLD_FILES+=usr/include/kadm5/private.h
OLD_DIRS+=usr/include/kadm5
OLD_FILES+=usr/include/kafs.h
OLD_FILES+=usr/include/kdc-protos.h
OLD_FILES+=usr/include/kdc.h
OLD_FILES+=usr/include/krb5-private.h
OLD_FILES+=usr/include/krb5-protos.h
OLD_FILES+=usr/include/krb5-types.h
OLD_FILES+=usr/include/krb5.h
OLD_FILES+=usr/include/krb5/ccache_plugin.h
OLD_FILES+=usr/include/krb5/locate_plugin.h
OLD_FILES+=usr/include/krb5/send_to_kdc_plugin.h
OLD_FILES+=usr/include/krb5/windc_plugin.h
OLD_DIRS+=usr/include/krb5
OLD_FILES+=usr/include/krb5_asn1.h
OLD_FILES+=usr/include/krb5_ccapi.h
OLD_FILES+=usr/include/krb5_err.h
OLD_FILES+=usr/include/kx509_asn1.h
OLD_FILES+=usr/include/ntlm_err.h
OLD_FILES+=usr/include/ocsp_asn1.h
OLD_FILES+=usr/include/parse_bytes.h
OLD_FILES+=usr/include/parse_time.h
OLD_FILES+=usr/include/parse_units.h
OLD_FILES+=usr/include/pkcs10_asn1.h
OLD_FILES+=usr/include/pkcs12_asn1.h
OLD_FILES+=usr/include/pkcs8_asn1.h
OLD_FILES+=usr/include/pkcs9_asn1.h
OLD_FILES+=usr/include/pkinit_asn1.h
OLD_FILES+=usr/include/resolve.h
OLD_FILES+=usr/include/rfc2459_asn1.h
OLD_FILES+=usr/include/roken-common.h
OLD_FILES+=usr/include/rtbl.h
OLD_FILES+=usr/include/wind.h
OLD_FILES+=usr/include/wind_err.h
OLD_FILES+=usr/include/xdbm.h
OLD_FILES+=usr/lib/libasn1.a
OLD_FILES+=usr/lib/libasn1.so
OLD_LIBS+=usr/lib/libasn1.so.11
OLD_FILES+=usr/lib/libasn1_p.a
OLD_FILES+=usr/lib/libcom_err.a
OLD_FILES+=usr/lib/libcom_err.so
OLD_LIBS+=usr/lib/libcom_err.so.5
OLD_FILES+=usr/lib/libcom_err_p.a
OLD_FILES+=usr/lib/libgssapi_krb5.a
OLD_FILES+=usr/lib/libgssapi_krb5.so
OLD_LIBS+=usr/lib/libgssapi_krb5.so.10
OLD_FILES+=usr/lib/libgssapi_krb5_p.a
OLD_FILES+=usr/lib/libgssapi_ntlm.a
OLD_FILES+=usr/lib/libgssapi_ntlm.so
OLD_LIBS+=usr/lib/libgssapi_ntlm.so.10
OLD_FILES+=usr/lib/libgssapi_ntlm_p.a
OLD_FILES+=usr/lib/libgssapi_spnego.a
OLD_FILES+=usr/lib/libgssapi_spnego.so
OLD_LIBS+=usr/lib/libgssapi_spnego.so.10
OLD_FILES+=usr/lib/libgssapi_spnego_p.a
OLD_FILES+=usr/lib/libhdb.a
OLD_FILES+=usr/lib/libhdb.so
OLD_LIBS+=usr/lib/libhdb.so.11
OLD_FILES+=usr/lib/libhdb_p.a
OLD_FILES+=usr/lib/libheimbase.a
OLD_FILES+=usr/lib/libheimbase.so
OLD_LIBS+=usr/lib/libheimbase.so.11
OLD_FILES+=usr/lib/libheimbase_p.a
OLD_FILES+=usr/lib/libheimntlm.a
OLD_FILES+=usr/lib/libheimntlm.so
OLD_LIBS+=usr/lib/libheimntlm.so.11
OLD_FILES+=usr/lib/libheimntlm_p.a
OLD_FILES+=usr/lib/libheimsqlite.a
OLD_FILES+=usr/lib/libheimsqlite.so
OLD_LIBS+=usr/lib/libheimsqlite.so.11
OLD_FILES+=usr/lib/libheimsqlite_p.a
OLD_FILES+=usr/lib/libhx509.a
OLD_FILES+=usr/lib/libhx509.so
OLD_LIBS+=usr/lib/libhx509.so.11
OLD_FILES+=usr/lib/libhx509_p.a
OLD_FILES+=usr/lib/libkadm5clnt.a
OLD_FILES+=usr/lib/libkadm5clnt.so
OLD_LIBS+=usr/lib/libkadm5clnt.so.11
OLD_FILES+=usr/lib/libkadm5clnt_p.a
OLD_FILES+=usr/lib/libkadm5srv.a
OLD_FILES+=usr/lib/libkadm5srv.so
OLD_LIBS+=usr/lib/libkadm5srv.so.11
OLD_FILES+=usr/lib/libkadm5srv_p.a
OLD_FILES+=usr/lib/libkafs5.a
OLD_FILES+=usr/lib/libkafs5.so
OLD_LIBS+=usr/lib/libkafs5.so.11
OLD_FILES+=usr/lib/libkafs5_p.a
OLD_FILES+=usr/lib/libkdc.a
OLD_FILES+=usr/lib/libkdc.so
OLD_LIBS+=usr/lib/libkdc.so.11
OLD_FILES+=usr/lib/libkdc_p.a
OLD_FILES+=usr/lib/libkrb5.a
OLD_FILES+=usr/lib/libkrb5.so
OLD_LIBS+=usr/lib/libkrb5.so.11
OLD_FILES+=usr/lib/libkrb5_p.a
OLD_FILES+=usr/lib/libroken.a
OLD_FILES+=usr/lib/libroken.so
OLD_LIBS+=usr/lib/libroken.so.11
OLD_FILES+=usr/lib/libroken_p.a
OLD_FILES+=usr/lib/libwind.a
OLD_FILES+=usr/lib/libwind.so
OLD_LIBS+=usr/lib/libwind.so.11
OLD_FILES+=usr/lib/libwind_p.a
OLD_FILES+=usr/lib/pam_krb5.so
OLD_LIBS+=usr/lib/pam_krb5.so.6
OLD_FILES+=usr/lib/pam_ksu.so
OLD_LIBS+=usr/lib/pam_ksu.so.6
OLD_FILES+=usr/lib/libprivateheimipcc.a
OLD_FILES+=usr/lib/libprivateheimipcc.so
OLD_LIBS+=usr/lib/libprivateheimipcc.so.11
OLD_FILES+=usr/lib/libprivateheimipcc_p.a
OLD_FILES+=usr/lib/libprivateheimipcs.a
OLD_FILES+=usr/lib/libprivateheimipcs.so
OLD_LIBS+=usr/lib/libprivateheimipcs.so.11
OLD_FILES+=usr/lib/libprivateheimipcs_p.a
OLD_FILES+=usr/libexec/digest-service
OLD_FILES+=usr/libexec/hprop
OLD_FILES+=usr/libexec/hpropd
OLD_FILES+=usr/libexec/ipropd-master
OLD_FILES+=usr/libexec/ipropd-slave
OLD_FILES+=usr/libexec/kadmind
OLD_FILES+=usr/libexec/kcm
OLD_FILES+=usr/libexec/kdc
OLD_FILES+=usr/libexec/kdigest
OLD_FILES+=usr/libexec/kfd
OLD_FILES+=usr/libexec/kimpersonate
OLD_FILES+=usr/libexec/kpasswdd
OLD_FILES+=usr/sbin/kstash
OLD_FILES+=usr/sbin/ktutil
OLD_FILES+=usr/sbin/iprop-log
OLD_FILES+=usr/share/man/man1/kdestroy.1.gz
OLD_FILES+=usr/share/man/man1/kf.1.gz
OLD_FILES+=usr/share/man/man1/kinit.1.gz
OLD_FILES+=usr/share/man/man1/klist.1.gz
OLD_FILES+=usr/share/man/man1/kpasswd.1.gz
OLD_FILES+=usr/share/man/man1/krb5-config.1.gz
OLD_FILES+=usr/share/man/man1/kswitch.1.gz
OLD_FILES+=usr/share/man/man3/HDB.3.gz
OLD_FILES+=usr/share/man/man3/hdb__del.3.gz
OLD_FILES+=usr/share/man/man3/hdb__get.3.gz
OLD_FILES+=usr/share/man/man3/hdb__put.3.gz
OLD_FILES+=usr/share/man/man3/hdb_auth_status.3.gz
OLD_FILES+=usr/share/man/man3/hdb_check_constrained_delegation.3.gz
OLD_FILES+=usr/share/man/man3/hdb_check_pkinit_ms_upn_match.3.gz
OLD_FILES+=usr/share/man/man3/hdb_check_s4u2self.3.gz
OLD_FILES+=usr/share/man/man3/hdb_close.3.gz
OLD_FILES+=usr/share/man/man3/hdb_destroy.3.gz
OLD_FILES+=usr/share/man/man3/hdb_entry_ex.3.gz
OLD_FILES+=usr/share/man/man3/hdb_fetch_kvno.3.gz
OLD_FILES+=usr/share/man/man3/hdb_firstkey.3.gz
OLD_FILES+=usr/share/man/man3/hdb_free.3.gz
OLD_FILES+=usr/share/man/man3/hdb_get_realms.3.gz
OLD_FILES+=usr/share/man/man3/hdb_lock.3.gz
OLD_FILES+=usr/share/man/man3/hdb_name.3.gz
OLD_FILES+=usr/share/man/man3/hdb_nextkey.3.gz
OLD_FILES+=usr/share/man/man3/hdb_open.3.gz
OLD_FILES+=usr/share/man/man3/hdb_password.3.gz
OLD_FILES+=usr/share/man/man3/hdb_remove.3.gz
OLD_FILES+=usr/share/man/man3/hdb_rename.3.gz
OLD_FILES+=usr/share/man/man3/hdb_store.3.gz
OLD_FILES+=usr/share/man/man3/hdb_unlock.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_build_ntlm1_master.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_build_ntlm2_master.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_calculate_lm2.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_calculate_ntlm1.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_calculate_ntlm2.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_decode_targetinfo.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_encode_targetinfo.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_encode_type1.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_encode_type2.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_encode_type3.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_free_buf.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_free_targetinfo.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_free_type1.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_free_type2.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_free_type3.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_keyex_unwrap.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_nt_key.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_ntlmv2_key.3.gz
OLD_FILES+=usr/share/man/man3/heim_ntlm_verify_ntlm2.3.gz
OLD_FILES+=usr/share/man/man3/hx509.3.gz
OLD_FILES+=usr/share/man/man3/hx509_bitstring_print.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_sign.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_sign_self.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_crl_dp_uri.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_eku.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_san_hostname.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_san_jid.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_san_ms_upn.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_san_otherName.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_san_pkinit.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_san_rfc822name.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_free.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_init.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_ca.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_domaincontroller.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_notAfter.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_notAfter_lifetime.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_notBefore.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_proxy.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_serialnumber.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_spki.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_subject.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_template.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_unique.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_subject_expand.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_template_units.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_binary.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_check_eku.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_cmp.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_find_subjectAltName_otherName.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_free.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_get_SPKI.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_get_SPKI_AlgorithmIdentifier.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_get_attribute.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_get_base_subject.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_get_friendly_name.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_get_issuer.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_get_issuer_unique_id.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_get_notAfter.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_get_notBefore.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_get_serialnumber.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_get_subject.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_get_subject_unique_id.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_init.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_init_data.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_keyusage_print.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_ref.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cert_set_friendly_name.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_add.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_append.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_end_seq.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_filter.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_find.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_free.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_info.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_init.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_iter_f.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_merge.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_next_cert.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_start_seq.3.gz
OLD_FILES+=usr/share/man/man3/hx509_certs_store.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ci_print_names.3.gz
OLD_FILES+=usr/share/man/man3/hx509_clear_error_string.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cms.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cms_create_signed_1.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cms_envelope_1.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cms_unenvelope.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cms_unwrap_ContentInfo.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cms_verify_signed.3.gz
OLD_FILES+=usr/share/man/man3/hx509_cms_wrap_ContentInfo.3.gz
OLD_FILES+=usr/share/man/man3/hx509_context_free.3.gz
OLD_FILES+=usr/share/man/man3/hx509_context_init.3.gz
OLD_FILES+=usr/share/man/man3/hx509_context_set_missing_revoke.3.gz
OLD_FILES+=usr/share/man/man3/hx509_crl_add_revoked_certs.3.gz
OLD_FILES+=usr/share/man/man3/hx509_crl_alloc.3.gz
OLD_FILES+=usr/share/man/man3/hx509_crl_free.3.gz
OLD_FILES+=usr/share/man/man3/hx509_crl_lifetime.3.gz
OLD_FILES+=usr/share/man/man3/hx509_crl_sign.3.gz
OLD_FILES+=usr/share/man/man3/hx509_crypto.3.gz
OLD_FILES+=usr/share/man/man3/hx509_env.3.gz
OLD_FILES+=usr/share/man/man3/hx509_env_add.3.gz
OLD_FILES+=usr/share/man/man3/hx509_env_add_binding.3.gz
OLD_FILES+=usr/share/man/man3/hx509_env_find.3.gz
OLD_FILES+=usr/share/man/man3/hx509_env_find_binding.3.gz
OLD_FILES+=usr/share/man/man3/hx509_env_free.3.gz
OLD_FILES+=usr/share/man/man3/hx509_env_lfind.3.gz
OLD_FILES+=usr/share/man/man3/hx509_err.3.gz
OLD_FILES+=usr/share/man/man3/hx509_error.3.gz
OLD_FILES+=usr/share/man/man3/hx509_free_error_string.3.gz
OLD_FILES+=usr/share/man/man3/hx509_free_octet_string_list.3.gz
OLD_FILES+=usr/share/man/man3/hx509_general_name_unparse.3.gz
OLD_FILES+=usr/share/man/man3/hx509_get_error_string.3.gz
OLD_FILES+=usr/share/man/man3/hx509_get_one_cert.3.gz
OLD_FILES+=usr/share/man/man3/hx509_keyset.3.gz
OLD_FILES+=usr/share/man/man3/hx509_lock.3.gz
OLD_FILES+=usr/share/man/man3/hx509_misc.3.gz
OLD_FILES+=usr/share/man/man3/hx509_name.3.gz
OLD_FILES+=usr/share/man/man3/hx509_name_binary.3.gz
OLD_FILES+=usr/share/man/man3/hx509_name_cmp.3.gz
OLD_FILES+=usr/share/man/man3/hx509_name_copy.3.gz
OLD_FILES+=usr/share/man/man3/hx509_name_expand.3.gz
OLD_FILES+=usr/share/man/man3/hx509_name_free.3.gz
OLD_FILES+=usr/share/man/man3/hx509_name_is_null_p.3.gz
OLD_FILES+=usr/share/man/man3/hx509_name_to_Name.3.gz
OLD_FILES+=usr/share/man/man3/hx509_name_to_string.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ocsp_request.3.gz
OLD_FILES+=usr/share/man/man3/hx509_ocsp_verify.3.gz
OLD_FILES+=usr/share/man/man3/hx509_oid_print.3.gz
OLD_FILES+=usr/share/man/man3/hx509_oid_sprint.3.gz
OLD_FILES+=usr/share/man/man3/hx509_parse_name.3.gz
OLD_FILES+=usr/share/man/man3/hx509_peer.3.gz
OLD_FILES+=usr/share/man/man3/hx509_peer_info_add_cms_alg.3.gz
OLD_FILES+=usr/share/man/man3/hx509_peer_info_alloc.3.gz
OLD_FILES+=usr/share/man/man3/hx509_peer_info_free.3.gz
OLD_FILES+=usr/share/man/man3/hx509_peer_info_set_cert.3.gz
OLD_FILES+=usr/share/man/man3/hx509_peer_info_set_cms_algs.3.gz
OLD_FILES+=usr/share/man/man3/hx509_print.3.gz
OLD_FILES+=usr/share/man/man3/hx509_print_cert.3.gz
OLD_FILES+=usr/share/man/man3/hx509_print_stdout.3.gz
OLD_FILES+=usr/share/man/man3/hx509_query.3.gz
OLD_FILES+=usr/share/man/man3/hx509_query_alloc.3.gz
OLD_FILES+=usr/share/man/man3/hx509_query_free.3.gz
OLD_FILES+=usr/share/man/man3/hx509_query_match_cmp_func.3.gz
OLD_FILES+=usr/share/man/man3/hx509_query_match_eku.3.gz
OLD_FILES+=usr/share/man/man3/hx509_query_match_friendly_name.3.gz
OLD_FILES+=usr/share/man/man3/hx509_query_match_issuer_serial.3.gz
OLD_FILES+=usr/share/man/man3/hx509_query_match_option.3.gz
OLD_FILES+=usr/share/man/man3/hx509_query_statistic_file.3.gz
OLD_FILES+=usr/share/man/man3/hx509_query_unparse_stats.3.gz
OLD_FILES+=usr/share/man/man3/hx509_revoke.3.gz
OLD_FILES+=usr/share/man/man3/hx509_revoke_add_crl.3.gz
OLD_FILES+=usr/share/man/man3/hx509_revoke_add_ocsp.3.gz
OLD_FILES+=usr/share/man/man3/hx509_revoke_free.3.gz
OLD_FILES+=usr/share/man/man3/hx509_revoke_init.3.gz
OLD_FILES+=usr/share/man/man3/hx509_revoke_ocsp_print.3.gz
OLD_FILES+=usr/share/man/man3/hx509_revoke_verify.3.gz
OLD_FILES+=usr/share/man/man3/hx509_set_error_string.3.gz
OLD_FILES+=usr/share/man/man3/hx509_set_error_stringv.3.gz
OLD_FILES+=usr/share/man/man3/hx509_unparse_der_name.3.gz
OLD_FILES+=usr/share/man/man3/hx509_validate_cert.3.gz
OLD_FILES+=usr/share/man/man3/hx509_validate_ctx_add_flags.3.gz
OLD_FILES+=usr/share/man/man3/hx509_validate_ctx_free.3.gz
OLD_FILES+=usr/share/man/man3/hx509_validate_ctx_init.3.gz
OLD_FILES+=usr/share/man/man3/hx509_validate_ctx_set_print.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify_attach_anchors.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify_attach_revoke.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify_ctx_f_allow_default_trustanchors.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify_destroy_ctx.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify_hostname.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify_init_ctx.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify_path.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify_set_max_depth.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify_set_proxy_certificate.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify_set_strict_rfc3280_verification.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify_set_time.3.gz
OLD_FILES+=usr/share/man/man3/hx509_verify_signature.3.gz
OLD_FILES+=usr/share/man/man3/hx509_xfree.3.gz
OLD_FILES+=usr/share/man/man3/k_afs_cell_of_file.3.gz
OLD_FILES+=usr/share/man/man3/k_hasafs.3.gz
OLD_FILES+=usr/share/man/man3/k_pioctl.3.gz
OLD_FILES+=usr/share/man/man3/k_setpag.3.gz
OLD_FILES+=usr/share/man/man3/k_unlog.3.gz
OLD_FILES+=usr/share/man/man3/kadm5_pwcheck.3.gz
OLD_FILES+=usr/share/man/man3/kafs.3.gz
OLD_FILES+=usr/share/man/man3/kafs5.3.gz
OLD_FILES+=usr/share/man/man3/kafs_set_verbose.3.gz
OLD_FILES+=usr/share/man/man3/kafs_settoken.3.gz
OLD_FILES+=usr/share/man/man3/kafs_settoken5.3.gz
OLD_FILES+=usr/share/man/man3/kafs_settoken_rxkad.3.gz
OLD_FILES+=usr/share/man/man3/krb5.3.gz
OLD_FILES+=usr/share/man/man3/krb524_convert_creds_kdc.3.gz
OLD_FILES+=usr/share/man/man3/krb524_convert_creds_kdc_ccache.3.gz
OLD_FILES+=usr/share/man/man3/krb5_425_conv_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_425_conv_principal_ext.3.gz
OLD_FILES+=usr/share/man/man3/krb5_524_conv_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_acc_ops.3.gz
OLD_FILES+=usr/share/man/man3/krb5_acl_match_file.3.gz
OLD_FILES+=usr/share/man/man3/krb5_acl_match_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_add_et_list.3.gz
OLD_FILES+=usr/share/man/man3/krb5_add_extra_addresses.3.gz
OLD_FILES+=usr/share/man/man3/krb5_add_ignore_addresses.3.gz
OLD_FILES+=usr/share/man/man3/krb5_addlog_dest.3.gz
OLD_FILES+=usr/share/man/man3/krb5_addlog_func.3.gz
OLD_FILES+=usr/share/man/man3/krb5_addr2sockaddr.3.gz
OLD_FILES+=usr/share/man/man3/krb5_address.3.gz
OLD_FILES+=usr/share/man/man3/krb5_address_compare.3.gz
OLD_FILES+=usr/share/man/man3/krb5_address_order.3.gz
OLD_FILES+=usr/share/man/man3/krb5_address_prefixlen_boundary.3.gz
OLD_FILES+=usr/share/man/man3/krb5_address_search.3.gz
OLD_FILES+=usr/share/man/man3/krb5_afslog.3.gz
OLD_FILES+=usr/share/man/man3/krb5_afslog_uid.3.gz
OLD_FILES+=usr/share/man/man3/krb5_allow_weak_crypto.3.gz
OLD_FILES+=usr/share/man/man3/krb5_aname_to_localname.3.gz
OLD_FILES+=usr/share/man/man3/krb5_anyaddr.3.gz
OLD_FILES+=usr/share/man/man3/krb5_appdefault.3.gz
OLD_FILES+=usr/share/man/man3/krb5_appdefault_boolean.3.gz
OLD_FILES+=usr/share/man/man3/krb5_appdefault_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_appdefault_time.3.gz
OLD_FILES+=usr/share/man/man3/krb5_append_addresses.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_free.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_genaddrs.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_getaddrs.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_getflags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_getkey.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_getlocalsubkey.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_getrcache.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_getremotesubkey.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_getuserkey.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_init.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_initivector.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_setaddrs.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_setaddrs_from_fd.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_setflags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_setivector.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_setkey.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_setlocalsubkey.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_setrcache.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_setremotesubkey.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_con_setuserkey.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_context.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_getauthenticator.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_getcksumtype.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_getkeytype.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_getlocalseqnumber.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_getremoteseqnumber.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_setcksumtype.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_setkeytype.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_setlocalseqnumber.3.gz
OLD_FILES+=usr/share/man/man3/krb5_auth_setremoteseqnumber.3.gz
OLD_FILES+=usr/share/man/man3/krb5_build_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_build_principal_ext.3.gz
OLD_FILES+=usr/share/man/man3/krb5_build_principal_va.3.gz
OLD_FILES+=usr/share/man/man3/krb5_build_principal_va_ext.3.gz
OLD_FILES+=usr/share/man/man3/krb5_c_enctype_compare.3.gz
OLD_FILES+=usr/share/man/man3/krb5_c_make_checksum.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_cache_end_seq_get.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_cache_get_first.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_cache_match.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_cache_next.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_clear_mcred.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_close.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_copy_cache.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_copy_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_copy_match_f.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_default.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_default_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_destroy.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_end_seq_get.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_gen_new.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_get_config.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_get_flags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_get_friendly_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_get_full_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_get_kdc_offset.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_get_lifetime.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_get_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_get_ops.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_get_prefix_ops.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_get_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_get_type.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_get_version.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_initialize.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_last_change_time.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_move.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_new_unique.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_next_cred.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_register.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_remove_cred.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_resolve.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_retrieve_cred.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_set_config.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_set_default_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_set_flags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_set_friendly_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_set_kdc_offset.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_start_seq_get.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_store_cred.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_support_switch.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cc_switch.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ccache.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ccache_intro.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cccol_cursor_free.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cccol_cursor_new.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cccol_cursor_next.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cccol_last_change_time.3.gz
OLD_FILES+=usr/share/man/man3/krb5_change_password.3.gz
OLD_FILES+=usr/share/man/man3/krb5_check_transited.3.gz
OLD_FILES+=usr/share/man/man3/krb5_checksum_is_collision_proof.3.gz
OLD_FILES+=usr/share/man/man3/krb5_checksum_is_keyed.3.gz
OLD_FILES+=usr/share/man/man3/krb5_checksumsize.3.gz
OLD_FILES+=usr/share/man/man3/krb5_cksumtype_to_enctype.3.gz
OLD_FILES+=usr/share/man/man3/krb5_clear_error_message.3.gz
OLD_FILES+=usr/share/man/man3/krb5_clear_error_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_closelog.3.gz
OLD_FILES+=usr/share/man/man3/krb5_compare_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_file_free.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_free_strings.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_get_bool.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_get_bool_default.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_get_list.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_get_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_get_string_default.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_get_strings.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_get_time.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_get_time_default.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_parse_file_multi.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_parse_string_multi.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_vget_bool.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_vget_bool_default.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_vget_list.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_vget_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_vget_string_default.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_vget_strings.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_vget_time.3.gz
OLD_FILES+=usr/share/man/man3/krb5_config_vget_time_default.3.gz
OLD_FILES+=usr/share/man/man3/krb5_copy_address.3.gz
OLD_FILES+=usr/share/man/man3/krb5_copy_addresses.3.gz
OLD_FILES+=usr/share/man/man3/krb5_copy_context.3.gz
OLD_FILES+=usr/share/man/man3/krb5_copy_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_copy_creds_contents.3.gz
OLD_FILES+=usr/share/man/man3/krb5_copy_data.3.gz
OLD_FILES+=usr/share/man/man3/krb5_copy_host_realm.3.gz
OLD_FILES+=usr/share/man/man3/krb5_copy_keyblock.3.gz
OLD_FILES+=usr/share/man/man3/krb5_copy_keyblock_contents.3.gz
OLD_FILES+=usr/share/man/man3/krb5_copy_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_copy_ticket.3.gz
OLD_FILES+=usr/share/man/man3/krb5_create_checksum.3.gz
OLD_FILES+=usr/share/man/man3/krb5_create_checksum_iov.3.gz
OLD_FILES+=usr/share/man/man3/krb5_credential.3.gz
OLD_FILES+=usr/share/man/man3/krb5_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_creds_get_ticket_flags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_crypto.3.gz
OLD_FILES+=usr/share/man/man3/krb5_crypto_destroy.3.gz
OLD_FILES+=usr/share/man/man3/krb5_crypto_fx_cf2.3.gz
OLD_FILES+=usr/share/man/man3/krb5_crypto_getblocksize.3.gz
OLD_FILES+=usr/share/man/man3/krb5_crypto_getconfoundersize.3.gz
OLD_FILES+=usr/share/man/man3/krb5_crypto_getenctype.3.gz
OLD_FILES+=usr/share/man/man3/krb5_crypto_getpadsize.3.gz
OLD_FILES+=usr/share/man/man3/krb5_crypto_init.3.gz
OLD_FILES+=usr/share/man/man3/krb5_crypto_iov.3.gz
OLD_FILES+=usr/share/man/man3/krb5_data_alloc.3.gz
OLD_FILES+=usr/share/man/man3/krb5_data_cmp.3.gz
OLD_FILES+=usr/share/man/man3/krb5_data_copy.3.gz
OLD_FILES+=usr/share/man/man3/krb5_data_ct_cmp.3.gz
OLD_FILES+=usr/share/man/man3/krb5_data_free.3.gz
OLD_FILES+=usr/share/man/man3/krb5_data_realloc.3.gz
OLD_FILES+=usr/share/man/man3/krb5_data_zero.3.gz
OLD_FILES+=usr/share/man/man3/krb5_decrypt.3.gz
OLD_FILES+=usr/share/man/man3/krb5_decrypt_EncryptedData.3.gz
OLD_FILES+=usr/share/man/man3/krb5_decrypt_iov_ivec.3.gz
OLD_FILES+=usr/share/man/man3/krb5_deprecated.3.gz
OLD_FILES+=usr/share/man/man3/krb5_digest.3.gz
OLD_FILES+=usr/share/man/man3/krb5_digest_probe.3.gz
OLD_FILES+=usr/share/man/man3/krb5_eai_to_heim_errno.3.gz
OLD_FILES+=usr/share/man/man3/krb5_encrypt.3.gz
OLD_FILES+=usr/share/man/man3/krb5_encrypt_EncryptedData.3.gz
OLD_FILES+=usr/share/man/man3/krb5_encrypt_iov_ivec.3.gz
OLD_FILES+=usr/share/man/man3/krb5_enctype_disable.3.gz
OLD_FILES+=usr/share/man/man3/krb5_enctype_enable.3.gz
OLD_FILES+=usr/share/man/man3/krb5_enctype_valid.3.gz
OLD_FILES+=usr/share/man/man3/krb5_enctypes_compatible_keys.3.gz
OLD_FILES+=usr/share/man/man3/krb5_error.3.gz
OLD_FILES+=usr/share/man/man3/krb5_expand_hostname.3.gz
OLD_FILES+=usr/share/man/man3/krb5_expand_hostname_realms.3.gz
OLD_FILES+=usr/share/man/man3/krb5_fcc_ops.3.gz
OLD_FILES+=usr/share/man/man3/krb5_fileformats.3.gz
OLD_FILES+=usr/share/man/man3/krb5_find_padata.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_address.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_addresses.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_config_files.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_context.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_cred_contents.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_creds_contents.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_data.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_data_contents.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_error_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_host_realm.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_keyblock.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_keyblock_contents.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_krbhst.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_ticket.3.gz
OLD_FILES+=usr/share/man/man3/krb5_free_unparsed_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_fwd_tgt_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_generate_random_block.3.gz
OLD_FILES+=usr/share/man/man3/krb5_generate_subkey.3.gz
OLD_FILES+=usr/share/man/man3/krb5_generate_subkey_extended.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_all_client_addrs.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_all_server_addrs.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_cred_from_kdc.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_cred_from_kdc_opt.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_credentials.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_default_config_files.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_default_in_tkt_etypes.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_default_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_default_realm.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_default_realms.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_dns_canonicalize_hostname.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_extra_addresses.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_fcache_version.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_forwarded_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_host_realm.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_ignore_addresses.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_in_cred.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_in_tkt_with_keytab.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_in_tkt_with_password.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_in_tkt_with_skey.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_init_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_keyblock.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_keytab.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_opt_alloc.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_opt_free.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_opt_get_error.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_opt_init.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_password.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_kdc_sec_offset.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_krb524hst.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_krb_admin_hst.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_krb_changepw_hst.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_krbhst.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_max_time_skew.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_use_admin_kdc.3.gz
OLD_FILES+=usr/share/man/man3/krb5_get_validated_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_getportbyname.3.gz
OLD_FILES+=usr/share/man/man3/krb5_h_addr2addr.3.gz
OLD_FILES+=usr/share/man/man3/krb5_h_addr2sockaddr.3.gz
OLD_FILES+=usr/share/man/man3/krb5_h_errno_to_heim_errno.3.gz
OLD_FILES+=usr/share/man/man3/krb5_init_context.3.gz
OLD_FILES+=usr/share/man/man3/krb5_init_creds_free.3.gz
OLD_FILES+=usr/share/man/man3/krb5_init_creds_get.3.gz
OLD_FILES+=usr/share/man/man3/krb5_init_creds_get_error.3.gz
OLD_FILES+=usr/share/man/man3/krb5_init_creds_init.3.gz
OLD_FILES+=usr/share/man/man3/krb5_init_creds_intro.3.gz
OLD_FILES+=usr/share/man/man3/krb5_init_creds_set_keytab.3.gz
OLD_FILES+=usr/share/man/man3/krb5_init_creds_set_password.3.gz
OLD_FILES+=usr/share/man/man3/krb5_init_creds_set_service.3.gz
OLD_FILES+=usr/share/man/man3/krb5_init_creds_step.3.gz
OLD_FILES+=usr/share/man/man3/krb5_init_ets.3.gz
OLD_FILES+=usr/share/man/man3/krb5_initlog.3.gz
OLD_FILES+=usr/share/man/man3/krb5_introduction.3.gz
OLD_FILES+=usr/share/man/man3/krb5_is_config_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_is_thread_safe.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kerberos_enctypes.3.gz
OLD_FILES+=usr/share/man/man3/krb5_keyblock_get_enctype.3.gz
OLD_FILES+=usr/share/man/man3/krb5_keyblock_init.3.gz
OLD_FILES+=usr/share/man/man3/krb5_keyblock_zero.3.gz
OLD_FILES+=usr/share/man/man3/krb5_keytab.3.gz
OLD_FILES+=usr/share/man/man3/krb5_keytab_intro.3.gz
OLD_FILES+=usr/share/man/man3/krb5_keytab_key_proc.3.gz
OLD_FILES+=usr/share/man/man3/krb5_keytype_to_enctypes.3.gz
OLD_FILES+=usr/share/man/man3/krb5_keytype_to_enctypes_default.3.gz
OLD_FILES+=usr/share/man/man3/krb5_keytype_to_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_krbhst_format_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_krbhst_free.3.gz
OLD_FILES+=usr/share/man/man3/krb5_krbhst_get_addrinfo.3.gz
OLD_FILES+=usr/share/man/man3/krb5_krbhst_init.3.gz
OLD_FILES+=usr/share/man/man3/krb5_krbhst_next.3.gz
OLD_FILES+=usr/share/man/man3/krb5_krbhst_next_as_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_krbhst_reset.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_add_entry.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_close.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_compare.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_copy_entry_contents.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_default.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_default_modify_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_default_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_destroy.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_end_seq_get.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_free_entry.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_get_entry.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_get_full_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_get_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_get_type.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_have_content.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_next_entry.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_read_service_key.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_register.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_remove_entry.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_resolve.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kt_start_seq_get.3.gz
OLD_FILES+=usr/share/man/man3/krb5_kuserok.3.gz
OLD_FILES+=usr/share/man/man3/krb5_log.3.gz
OLD_FILES+=usr/share/man/man3/krb5_log_msg.3.gz
OLD_FILES+=usr/share/man/man3/krb5_make_addrport.3.gz
OLD_FILES+=usr/share/man/man3/krb5_make_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_max_sockaddr_size.3.gz
OLD_FILES+=usr/share/man/man3/krb5_mcc_ops.3.gz
OLD_FILES+=usr/share/man/man3/krb5_mk_req.3.gz
OLD_FILES+=usr/share/man/man3/krb5_mk_safe.3.gz
OLD_FILES+=usr/share/man/man3/krb5_openlog.3.gz
OLD_FILES+=usr/share/man/man3/krb5_pac.3.gz
OLD_FILES+=usr/share/man/man3/krb5_pac_get_buffer.3.gz
OLD_FILES+=usr/share/man/man3/krb5_pac_verify.3.gz
OLD_FILES+=usr/share/man/man3/krb5_parse_address.3.gz
OLD_FILES+=usr/share/man/man3/krb5_parse_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_parse_name_flags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_parse_nametype.3.gz
OLD_FILES+=usr/share/man/man3/krb5_password_key_proc.3.gz
OLD_FILES+=usr/share/man/man3/krb5_plugin_register.3.gz
OLD_FILES+=usr/share/man/man3/krb5_prepend_config_files_default.3.gz
OLD_FILES+=usr/share/man/man3/krb5_princ_realm.3.gz
OLD_FILES+=usr/share/man/man3/krb5_princ_set_realm.3.gz
OLD_FILES+=usr/share/man/man3/krb5_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_principal_compare.3.gz
OLD_FILES+=usr/share/man/man3/krb5_principal_compare_any_realm.3.gz
OLD_FILES+=usr/share/man/man3/krb5_principal_get_comp_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_principal_get_num_comp.3.gz
OLD_FILES+=usr/share/man/man3/krb5_principal_get_realm.3.gz
OLD_FILES+=usr/share/man/man3/krb5_principal_get_type.3.gz
OLD_FILES+=usr/share/man/man3/krb5_principal_intro.3.gz
OLD_FILES+=usr/share/man/man3/krb5_principal_is_krbtgt.3.gz
OLD_FILES+=usr/share/man/man3/krb5_principal_match.3.gz
OLD_FILES+=usr/share/man/man3/krb5_principal_set_realm.3.gz
OLD_FILES+=usr/share/man/man3/krb5_principal_set_type.3.gz
OLD_FILES+=usr/share/man/man3/krb5_print_address.3.gz
OLD_FILES+=usr/share/man/man3/krb5_random_to_key.3.gz
OLD_FILES+=usr/share/man/man3/krb5_rcache.3.gz
OLD_FILES+=usr/share/man/man3/krb5_rd_error.3.gz
OLD_FILES+=usr/share/man/man3/krb5_rd_req_ctx.3.gz
OLD_FILES+=usr/share/man/man3/krb5_rd_req_in_ctx_alloc.3.gz
OLD_FILES+=usr/share/man/man3/krb5_rd_req_in_set_keytab.3.gz
OLD_FILES+=usr/share/man/man3/krb5_rd_req_in_set_pac_check.3.gz
OLD_FILES+=usr/share/man/man3/krb5_rd_req_out_ctx_free.3.gz
OLD_FILES+=usr/share/man/man3/krb5_rd_req_out_get_server.3.gz
OLD_FILES+=usr/share/man/man3/krb5_rd_safe.3.gz
OLD_FILES+=usr/share/man/man3/krb5_realm_compare.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_address.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_addrs.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_authdata.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_creds_tag.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_data.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_int16.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_int32.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_int8.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_keyblock.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_stringz.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_times.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_uint16.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_uint32.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ret_uint8.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_config_files.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_default_in_tkt_etypes.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_default_realm.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_dns_canonicalize_hostname.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_error_message.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_error_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_extra_addresses.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_fcache_version.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_home_dir_access.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_ignore_addresses.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_kdc_sec_offset.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_max_time_skew.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_password.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_real_time.3.gz
OLD_FILES+=usr/share/man/man3/krb5_set_use_admin_kdc.3.gz
OLD_FILES+=usr/share/man/man3/krb5_sname_to_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_sock_to_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_sockaddr2address.3.gz
OLD_FILES+=usr/share/man/man3/krb5_sockaddr2port.3.gz
OLD_FILES+=usr/share/man/man3/krb5_sockaddr_uninteresting.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_clear_flags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_emem.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_free.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_from_data.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_from_fd.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_from_mem.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_from_readonly_mem.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_get_byteorder.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_get_eof_code.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_is_flags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_read.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_seek.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_set_byteorder.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_set_eof_code.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_set_flags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_set_max_alloc.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_to_data.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_truncate.3.gz
OLD_FILES+=usr/share/man/man3/krb5_storage_write.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_address.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_addrs.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_authdata.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_creds_tag.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_data.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_int16.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_int32.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_int8.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_keyblock.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_principal.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_stringz.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_times.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_uint16.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_uint32.3.gz
OLD_FILES+=usr/share/man/man3/krb5_store_uint8.3.gz
OLD_FILES+=usr/share/man/man3/krb5_string_to_key.3.gz
OLD_FILES+=usr/share/man/man3/krb5_string_to_keytype.3.gz
OLD_FILES+=usr/share/man/man3/krb5_support.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ticket.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ticket_get_authorization_data_type.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ticket_get_client.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ticket_get_endtime.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ticket_get_flags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_ticket_get_server.3.gz
OLD_FILES+=usr/share/man/man3/krb5_timeofday.3.gz
OLD_FILES+=usr/share/man/man3/krb5_unparse_name.3.gz
OLD_FILES+=usr/share/man/man3/krb5_unparse_name_fixed.3.gz
OLD_FILES+=usr/share/man/man3/krb5_unparse_name_fixed_flags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_unparse_name_fixed_short.3.gz
OLD_FILES+=usr/share/man/man3/krb5_unparse_name_flags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_unparse_name_short.3.gz
OLD_FILES+=usr/share/man/man3/krb5_us_timeofday.3.gz
OLD_FILES+=usr/share/man/man3/krb5_v4compat.3.gz
OLD_FILES+=usr/share/man/man3/krb5_verify_checksum.3.gz
OLD_FILES+=usr/share/man/man3/krb5_verify_checksum_iov.3.gz
OLD_FILES+=usr/share/man/man3/krb5_verify_init_creds.3.gz
OLD_FILES+=usr/share/man/man3/krb5_verify_opt_init.3.gz
OLD_FILES+=usr/share/man/man3/krb5_verify_opt_set_flags.3.gz
OLD_FILES+=usr/share/man/man3/krb5_verify_opt_set_keytab.3.gz
OLD_FILES+=usr/share/man/man3/krb5_verify_opt_set_secure.3.gz
OLD_FILES+=usr/share/man/man3/krb5_verify_opt_set_service.3.gz
OLD_FILES+=usr/share/man/man3/krb5_verify_user.3.gz
OLD_FILES+=usr/share/man/man3/krb5_verify_user_lrealm.3.gz
OLD_FILES+=usr/share/man/man3/krb5_verify_user_opt.3.gz
OLD_FILES+=usr/share/man/man3/krb5_vlog.3.gz
OLD_FILES+=usr/share/man/man3/krb5_vlog_msg.3.gz
OLD_FILES+=usr/share/man/man3/krb5_vset_error_string.3.gz
OLD_FILES+=usr/share/man/man3/krb5_vwarn.3.gz
OLD_FILES+=usr/share/man/man3/krb_afslog.3.gz
OLD_FILES+=usr/share/man/man3/krb_afslog_uid.3.gz
OLD_FILES+=usr/share/man/man3/ntlm_buf.3.gz
OLD_FILES+=usr/share/man/man3/ntlm_core.3.gz
OLD_FILES+=usr/share/man/man3/ntlm_type1.3.gz
OLD_FILES+=usr/share/man/man3/ntlm_type2.3.gz
OLD_FILES+=usr/share/man/man3/ntlm_type3.3.gz
OLD_FILES+=usr/share/man/man5/krb5.conf.5.gz
OLD_FILES+=usr/share/man/man8/hprop.8.gz
OLD_FILES+=usr/share/man/man8/hpropd.8.gz
OLD_FILES+=usr/share/man/man8/iprop-log.8.gz
OLD_FILES+=usr/share/man/man8/iprop.8.gz
OLD_FILES+=usr/share/man/man8/kadmin.8.gz
OLD_FILES+=usr/share/man/man8/kadmind.8.gz
OLD_FILES+=usr/share/man/man8/kcm.8.gz
OLD_FILES+=usr/share/man/man8/kdc.8.gz
OLD_FILES+=usr/share/man/man8/kdigest.8.gz
OLD_FILES+=usr/share/man/man8/kerberos.8.gz
OLD_FILES+=usr/share/man/man8/kimpersonate.8.gz
OLD_FILES+=usr/share/man/man8/kpasswdd.8.gz
OLD_FILES+=usr/share/man/man8/kstash.8.gz
OLD_FILES+=usr/share/man/man8/ktutil.8.gz
OLD_FILES+=usr/share/man/man8/pam_krb5.8.gz
OLD_FILES+=usr/share/man/man8/pam_ksu.8.gz
OLD_FILES+=usr/share/man/man8/string2key.8.gz
OLD_FILES+=usr/share/man/man8/verify_krb5_conf.8.gz
.endif
.if ${MK_KERBEROS_SUPPORT} == no
OLD_FILES+=usr/bin/compile_et
OLD_FILES+=usr/include/com_err.h
OLD_FILES+=usr/include/com_right.h
OLD_FILES+=usr/lib/libcom_err.a
OLD_FILES+=usr/lib/libcom_err.so
OLD_LIBS+=usr/lib/libcom_err.so.5
OLD_FILES+=usr/lib/libcom_err_p.a
OLD_FILES+=usr/share/man/man1/compile_et.1.gz
OLD_FILES+=usr/share/man/man3/com_err.3.gz
.endif
.if ${MK_LDNS} == no
OLD_FILES+=usr/lib/libprivateldns.a
OLD_FILES+=usr/lib/libprivateldns.so
OLD_LIBS+=usr/lib/libprivateldns.so.5
OLD_FILES+=usr/lib/libprivateldns_p.a
.endif
.if ${MK_LDNS_UTILS} == no
OLD_FILES+=usr/bin/drill
OLD_FILES+=usr/share/man/man1/drill.1.gz
OLD_FILES+=usr/bin/host
OLD_FILES+=usr/share/man/man1/host.1.gz
.endif
.if ${MK_LEGACY_CONSOLE} == no
OLD_FILES+=etc/rc.d/moused
OLD_FILES+=etc/rc.d/syscons
OLD_FILES+=usr/sbin/kbdcontrol
OLD_FILES+=usr/sbin/kbdmap
OLD_FILES+=usr/sbin/moused
OLD_FILES+=usr/sbin/vidcontrol
OLD_FILES+=usr/sbin/vidfont
OLD_FILES+=usr/share/man/man1/kbdcontrol.1.gz
OLD_FILES+=usr/share/man/man1/kbdmap.1.gz
OLD_FILES+=usr/share/man/man1/vidcontrol.1.gz
OLD_FILES+=usr/share/man/man1/vidfont.1.gz
OLD_FILES+=usr/share/man/man5/kbdmap.5.gz
OLD_FILES+=usr/share/man/man5/keymap.5.gz
OLD_FILES+=usr/share/man/man8/moused.8.gz
.endif
.if ${MK_LIB32} == no
OLD_FILES+=etc/mtree/BSD.lib32.dist
OLD_FILES+=libexec/ld-elf32.so.1
. if exists(${DESTDIR}/usr/lib32)
LIB32_DIRS!=find ${DESTDIR}/usr/lib32 -type d \
| sed -e 's,^${DESTDIR}/,,'; echo
LIB32_FILES!=find ${DESTDIR}/usr/lib32 \! -type d \
\! -name "lib*.so*" | sed -e 's,^${DESTDIR}/,,'; echo
LIB32_LIBS!=find ${DESTDIR}/usr/lib32 \! -type d \
-name "lib*.so*" | sed -e 's,^${DESTDIR}/,,'; echo
OLD_DIRS+=${LIB32_DIRS}
OLD_FILES+=${LIB32_FILES}
OLD_LIBS+=${LIB32_LIBS}
. endif
. if ${MK_DEBUG_FILES} == no
. if exists(${DESTDIR}/usr/lib/debug/usr/lib32)
DEBUG_LIB32_DIRS!=find ${DESTDIR}/usr/lib/debug/usr/lib32 -type d \
| sed -e 's,^${DESTDIR}/,,'; echo
DEBUG_LIB32_FILES!=find ${DESTDIR}/usr/lib/debug/usr/lib32 \! -type d \
\! -name "lib*.so*" | sed -e 's,^${DESTDIR}/,,'; echo
DEBUG_LIB32_LIBS!=find ${DESTDIR}/usr/lib/debug/usr/lib32 \! -type d \
-name "lib*.so*" | sed -e 's,^${DESTDIR}/,,'; echo
OLD_DIRS+=${DEBUG_LIB32_DIRS}
OLD_FILES+=${DEBUG_LIB32_FILES}
OLD_LIBS+=${DEBUG_LIB32_LIBS}
. endif
. endif
.endif
.if ${MK_CXX} == no
OLD_LIBS+=lib/libcxxrt.so.1
OLD_FILES+=usr/lib/libc++.a
OLD_FILES+=usr/lib/libc++_p.a
OLD_FILES+=usr/lib/libc++experimental.a
OLD_FILES+=usr/lib/libc++.so
OLD_LIBS+=usr/lib/libc++.so.1
OLD_FILES+=usr/lib/libcxxrt.a
OLD_FILES+=usr/lib/libcxxrt.so
OLD_FILES+=usr/lib/libcxxrt_p.a
OLD_FILES+=usr/include/c++/v1/__algorithm/adjacent_find.h
OLD_FILES+=usr/include/c++/v1/__algorithm/all_of.h
OLD_FILES+=usr/include/c++/v1/__algorithm/any_of.h
OLD_FILES+=usr/include/c++/v1/__algorithm/binary_search.h
OLD_FILES+=usr/include/c++/v1/__algorithm/clamp.h
OLD_FILES+=usr/include/c++/v1/__algorithm/comp.h
OLD_FILES+=usr/include/c++/v1/__algorithm/comp_ref_type.h
OLD_FILES+=usr/include/c++/v1/__algorithm/copy.h
OLD_FILES+=usr/include/c++/v1/__algorithm/copy_backward.h
OLD_FILES+=usr/include/c++/v1/__algorithm/copy_if.h
OLD_FILES+=usr/include/c++/v1/__algorithm/copy_n.h
OLD_FILES+=usr/include/c++/v1/__algorithm/count.h
OLD_FILES+=usr/include/c++/v1/__algorithm/count_if.h
OLD_FILES+=usr/include/c++/v1/__algorithm/equal.h
OLD_FILES+=usr/include/c++/v1/__algorithm/equal_range.h
OLD_FILES+=usr/include/c++/v1/__algorithm/fill.h
OLD_FILES+=usr/include/c++/v1/__algorithm/fill_n.h
OLD_FILES+=usr/include/c++/v1/__algorithm/find.h
OLD_FILES+=usr/include/c++/v1/__algorithm/find_end.h
OLD_FILES+=usr/include/c++/v1/__algorithm/find_first_of.h
OLD_FILES+=usr/include/c++/v1/__algorithm/find_if.h
OLD_FILES+=usr/include/c++/v1/__algorithm/find_if_not.h
OLD_FILES+=usr/include/c++/v1/__algorithm/for_each.h
OLD_FILES+=usr/include/c++/v1/__algorithm/for_each_n.h
OLD_FILES+=usr/include/c++/v1/__algorithm/generate.h
OLD_FILES+=usr/include/c++/v1/__algorithm/generate_n.h
OLD_FILES+=usr/include/c++/v1/__algorithm/half_positive.h
OLD_FILES+=usr/include/c++/v1/__algorithm/in_in_out_result.h
OLD_FILES+=usr/include/c++/v1/__algorithm/in_in_result.h
OLD_FILES+=usr/include/c++/v1/__algorithm/in_out_result.h
OLD_FILES+=usr/include/c++/v1/__algorithm/includes.h
OLD_FILES+=usr/include/c++/v1/__algorithm/inplace_merge.h
OLD_FILES+=usr/include/c++/v1/__algorithm/is_heap.h
OLD_FILES+=usr/include/c++/v1/__algorithm/is_heap_until.h
OLD_FILES+=usr/include/c++/v1/__algorithm/is_partitioned.h
OLD_FILES+=usr/include/c++/v1/__algorithm/is_permutation.h
OLD_FILES+=usr/include/c++/v1/__algorithm/is_sorted.h
OLD_FILES+=usr/include/c++/v1/__algorithm/is_sorted_until.h
OLD_FILES+=usr/include/c++/v1/__algorithm/iter_swap.h
OLD_FILES+=usr/include/c++/v1/__algorithm/lexicographical_compare.h
OLD_FILES+=usr/include/c++/v1/__algorithm/lower_bound.h
OLD_FILES+=usr/include/c++/v1/__algorithm/make_heap.h
OLD_FILES+=usr/include/c++/v1/__algorithm/max.h
OLD_FILES+=usr/include/c++/v1/__algorithm/max_element.h
OLD_FILES+=usr/include/c++/v1/__algorithm/merge.h
OLD_FILES+=usr/include/c++/v1/__algorithm/min.h
OLD_FILES+=usr/include/c++/v1/__algorithm/min_element.h
OLD_FILES+=usr/include/c++/v1/__algorithm/minmax.h
OLD_FILES+=usr/include/c++/v1/__algorithm/minmax_element.h
OLD_FILES+=usr/include/c++/v1/__algorithm/mismatch.h
OLD_FILES+=usr/include/c++/v1/__algorithm/move.h
OLD_FILES+=usr/include/c++/v1/__algorithm/move_backward.h
OLD_FILES+=usr/include/c++/v1/__algorithm/next_permutation.h
OLD_FILES+=usr/include/c++/v1/__algorithm/none_of.h
OLD_FILES+=usr/include/c++/v1/__algorithm/nth_element.h
OLD_FILES+=usr/include/c++/v1/__algorithm/partial_sort.h
OLD_FILES+=usr/include/c++/v1/__algorithm/partial_sort_copy.h
OLD_FILES+=usr/include/c++/v1/__algorithm/partition.h
OLD_FILES+=usr/include/c++/v1/__algorithm/partition_copy.h
OLD_FILES+=usr/include/c++/v1/__algorithm/partition_point.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pop_heap.h
OLD_FILES+=usr/include/c++/v1/__algorithm/prev_permutation.h
OLD_FILES+=usr/include/c++/v1/__algorithm/push_heap.h
OLD_FILES+=usr/include/c++/v1/__algorithm/remove.h
OLD_FILES+=usr/include/c++/v1/__algorithm/remove_copy.h
OLD_FILES+=usr/include/c++/v1/__algorithm/remove_copy_if.h
OLD_FILES+=usr/include/c++/v1/__algorithm/remove_if.h
OLD_FILES+=usr/include/c++/v1/__algorithm/replace.h
OLD_FILES+=usr/include/c++/v1/__algorithm/replace_copy.h
OLD_FILES+=usr/include/c++/v1/__algorithm/replace_copy_if.h
OLD_FILES+=usr/include/c++/v1/__algorithm/replace_if.h
OLD_FILES+=usr/include/c++/v1/__algorithm/reverse.h
OLD_FILES+=usr/include/c++/v1/__algorithm/reverse_copy.h
OLD_FILES+=usr/include/c++/v1/__algorithm/rotate.h
OLD_FILES+=usr/include/c++/v1/__algorithm/rotate_copy.h
OLD_FILES+=usr/include/c++/v1/__algorithm/sample.h
OLD_FILES+=usr/include/c++/v1/__algorithm/search.h
OLD_FILES+=usr/include/c++/v1/__algorithm/search_n.h
OLD_FILES+=usr/include/c++/v1/__algorithm/set_difference.h
OLD_FILES+=usr/include/c++/v1/__algorithm/set_intersection.h
OLD_FILES+=usr/include/c++/v1/__algorithm/set_symmetric_difference.h
OLD_FILES+=usr/include/c++/v1/__algorithm/set_union.h
OLD_FILES+=usr/include/c++/v1/__algorithm/shift_left.h
OLD_FILES+=usr/include/c++/v1/__algorithm/shift_right.h
OLD_FILES+=usr/include/c++/v1/__algorithm/shuffle.h
OLD_FILES+=usr/include/c++/v1/__algorithm/sift_down.h
OLD_FILES+=usr/include/c++/v1/__algorithm/sort.h
OLD_FILES+=usr/include/c++/v1/__algorithm/sort_heap.h
OLD_FILES+=usr/include/c++/v1/__algorithm/stable_partition.h
OLD_FILES+=usr/include/c++/v1/__algorithm/stable_sort.h
OLD_FILES+=usr/include/c++/v1/__algorithm/swap_ranges.h
OLD_FILES+=usr/include/c++/v1/__algorithm/transform.h
OLD_FILES+=usr/include/c++/v1/__algorithm/unique.h
OLD_FILES+=usr/include/c++/v1/__algorithm/unique_copy.h
OLD_FILES+=usr/include/c++/v1/__algorithm/unwrap_iter.h
OLD_FILES+=usr/include/c++/v1/__algorithm/upper_bound.h
OLD_DIRS+=usr/include/c++/v1/__algorithm
OLD_FILES+=usr/include/c++/v1/__availability
OLD_FILES+=usr/include/c++/v1/__bit/bit_cast.h
OLD_FILES+=usr/include/c++/v1/__bit/byteswap.h
OLD_DIRS+=usr/include/c++/v1/__bit
OLD_FILES+=usr/include/c++/v1/__bit_reference
OLD_FILES+=usr/include/c++/v1/__bits
OLD_FILES+=usr/include/c++/v1/__bsd_locale_defaults.h
OLD_FILES+=usr/include/c++/v1/__bsd_locale_fallbacks.h
OLD_FILES+=usr/include/c++/v1/__charconv/chars_format.h
OLD_FILES+=usr/include/c++/v1/__charconv/from_chars_result.h
OLD_FILES+=usr/include/c++/v1/__charconv/to_chars_result.h
OLD_DIRS+=usr/include/c++/v1/__charconv
OLD_FILES+=usr/include/c++/v1/__chrono/calendar.h
OLD_FILES+=usr/include/c++/v1/__chrono/convert_to_timespec.h
OLD_FILES+=usr/include/c++/v1/__chrono/duration.h
OLD_FILES+=usr/include/c++/v1/__chrono/file_clock.h
OLD_FILES+=usr/include/c++/v1/__chrono/high_resolution_clock.h
OLD_FILES+=usr/include/c++/v1/__chrono/steady_clock.h
OLD_FILES+=usr/include/c++/v1/__chrono/system_clock.h
OLD_FILES+=usr/include/c++/v1/__chrono/time_point.h
OLD_DIRS+=usr/include/c++/v1/__chrono
OLD_FILES+=usr/include/c++/v1/__compare/common_comparison_category.h
OLD_FILES+=usr/include/c++/v1/__compare/compare_partial_order_fallback.h
OLD_FILES+=usr/include/c++/v1/__compare/compare_strong_order_fallback.h
OLD_FILES+=usr/include/c++/v1/__compare/compare_three_way.h
OLD_FILES+=usr/include/c++/v1/__compare/compare_three_way_result.h
OLD_FILES+=usr/include/c++/v1/__compare/compare_weak_order_fallback.h
OLD_FILES+=usr/include/c++/v1/__compare/is_eq.h
OLD_FILES+=usr/include/c++/v1/__compare/ordering.h
OLD_FILES+=usr/include/c++/v1/__compare/partial_order.h
OLD_FILES+=usr/include/c++/v1/__compare/strong_order.h
OLD_FILES+=usr/include/c++/v1/__compare/synth_three_way.h
OLD_FILES+=usr/include/c++/v1/__compare/three_way_comparable.h
OLD_FILES+=usr/include/c++/v1/__compare/weak_order.h
OLD_DIRS+=usr/include/c++/v1/__compare
OLD_FILES+=usr/include/c++/v1/__concepts/arithmetic.h
OLD_FILES+=usr/include/c++/v1/__concepts/assignable.h
OLD_FILES+=usr/include/c++/v1/__concepts/boolean_testable.h
OLD_FILES+=usr/include/c++/v1/__concepts/class_or_enum.h
OLD_FILES+=usr/include/c++/v1/__concepts/common_reference_with.h
OLD_FILES+=usr/include/c++/v1/__concepts/common_with.h
OLD_FILES+=usr/include/c++/v1/__concepts/constructible.h
OLD_FILES+=usr/include/c++/v1/__concepts/convertible_to.h
OLD_FILES+=usr/include/c++/v1/__concepts/copyable.h
OLD_FILES+=usr/include/c++/v1/__concepts/derived_from.h
OLD_FILES+=usr/include/c++/v1/__concepts/destructible.h
OLD_FILES+=usr/include/c++/v1/__concepts/different_from.h
OLD_FILES+=usr/include/c++/v1/__concepts/equality_comparable.h
OLD_FILES+=usr/include/c++/v1/__concepts/invocable.h
OLD_FILES+=usr/include/c++/v1/__concepts/movable.h
OLD_FILES+=usr/include/c++/v1/__concepts/predicate.h
OLD_FILES+=usr/include/c++/v1/__concepts/regular.h
OLD_FILES+=usr/include/c++/v1/__concepts/relation.h
OLD_FILES+=usr/include/c++/v1/__concepts/same_as.h
OLD_FILES+=usr/include/c++/v1/__concepts/semiregular.h
OLD_FILES+=usr/include/c++/v1/__concepts/swappable.h
OLD_FILES+=usr/include/c++/v1/__concepts/totally_ordered.h
OLD_DIRS+=usr/include/c++/v1/__concepts
OLD_FILES+=usr/include/c++/v1/__config
OLD_FILES+=usr/include/c++/v1/__config_site
OLD_FILES+=usr/include/c++/v1/__coroutine/coroutine_handle.h
OLD_FILES+=usr/include/c++/v1/__coroutine/coroutine_traits.h
OLD_FILES+=usr/include/c++/v1/__coroutine/noop_coroutine_handle.h
OLD_FILES+=usr/include/c++/v1/__coroutine/trivial_awaitables.h
OLD_DIRS+=usr/include/c++/v1/__coroutine
OLD_FILES+=usr/include/c++/v1/__debug
OLD_FILES+=usr/include/c++/v1/__errc
OLD_FILES+=usr/include/c++/v1/__filesystem/copy_options.h
OLD_FILES+=usr/include/c++/v1/__filesystem/directory_entry.h
OLD_FILES+=usr/include/c++/v1/__filesystem/directory_iterator.h
OLD_FILES+=usr/include/c++/v1/__filesystem/directory_options.h
OLD_FILES+=usr/include/c++/v1/__filesystem/file_status.h
OLD_FILES+=usr/include/c++/v1/__filesystem/file_time_type.h
OLD_FILES+=usr/include/c++/v1/__filesystem/file_type.h
OLD_FILES+=usr/include/c++/v1/__filesystem/filesystem_error.h
OLD_FILES+=usr/include/c++/v1/__filesystem/operations.h
OLD_FILES+=usr/include/c++/v1/__filesystem/path.h
OLD_FILES+=usr/include/c++/v1/__filesystem/path_iterator.h
OLD_FILES+=usr/include/c++/v1/__filesystem/perm_options.h
OLD_FILES+=usr/include/c++/v1/__filesystem/perms.h
OLD_FILES+=usr/include/c++/v1/__filesystem/recursive_directory_iterator.h
OLD_FILES+=usr/include/c++/v1/__filesystem/space_info.h
OLD_FILES+=usr/include/c++/v1/__filesystem/u8path.h
OLD_DIRS+=usr/include/c++/v1/__filesystem
OLD_FILES+=usr/include/c++/v1/__format/format_arg.h
OLD_FILES+=usr/include/c++/v1/__format/format_args.h
OLD_FILES+=usr/include/c++/v1/__format/format_context.h
OLD_FILES+=usr/include/c++/v1/__format/format_error.h
OLD_FILES+=usr/include/c++/v1/__format/format_fwd.h
OLD_FILES+=usr/include/c++/v1/__format/format_parse_context.h
OLD_FILES+=usr/include/c++/v1/__format/format_string.h
OLD_FILES+=usr/include/c++/v1/__format/format_to_n_result.h
OLD_FILES+=usr/include/c++/v1/__format/formatter.h
OLD_FILES+=usr/include/c++/v1/__format/formatter_bool.h
OLD_FILES+=usr/include/c++/v1/__format/formatter_char.h
OLD_FILES+=usr/include/c++/v1/__format/formatter_floating_point.h
OLD_FILES+=usr/include/c++/v1/__format/formatter_integer.h
OLD_FILES+=usr/include/c++/v1/__format/formatter_integral.h
OLD_FILES+=usr/include/c++/v1/__format/formatter_pointer.h
OLD_FILES+=usr/include/c++/v1/__format/formatter_string.h
OLD_FILES+=usr/include/c++/v1/__format/parser_std_format_spec.h
OLD_DIRS+=usr/include/c++/v1/__format
OLD_FILES+=usr/include/c++/v1/__functional/binary_function.h
OLD_FILES+=usr/include/c++/v1/__functional/binary_negate.h
OLD_FILES+=usr/include/c++/v1/__functional/bind.h
OLD_FILES+=usr/include/c++/v1/__functional/bind_back.h
OLD_FILES+=usr/include/c++/v1/__functional/bind_front.h
OLD_FILES+=usr/include/c++/v1/__functional/binder1st.h
OLD_FILES+=usr/include/c++/v1/__functional/binder2nd.h
OLD_FILES+=usr/include/c++/v1/__functional/compose.h
OLD_FILES+=usr/include/c++/v1/__functional/default_searcher.h
OLD_FILES+=usr/include/c++/v1/__functional/function.h
OLD_FILES+=usr/include/c++/v1/__functional/hash.h
OLD_FILES+=usr/include/c++/v1/__functional/identity.h
OLD_FILES+=usr/include/c++/v1/__functional/invoke.h
OLD_FILES+=usr/include/c++/v1/__functional/is_transparent.h
OLD_FILES+=usr/include/c++/v1/__functional/mem_fn.h
OLD_FILES+=usr/include/c++/v1/__functional/mem_fun_ref.h
OLD_FILES+=usr/include/c++/v1/__functional/not_fn.h
OLD_FILES+=usr/include/c++/v1/__functional/operations.h
OLD_FILES+=usr/include/c++/v1/__functional/perfect_forward.h
OLD_FILES+=usr/include/c++/v1/__functional/pointer_to_binary_function.h
OLD_FILES+=usr/include/c++/v1/__functional/pointer_to_unary_function.h
OLD_FILES+=usr/include/c++/v1/__functional/ranges_operations.h
OLD_FILES+=usr/include/c++/v1/__functional/reference_wrapper.h
OLD_FILES+=usr/include/c++/v1/__functional/unary_function.h
OLD_FILES+=usr/include/c++/v1/__functional/unary_negate.h
OLD_FILES+=usr/include/c++/v1/__functional/unwrap_ref.h
OLD_FILES+=usr/include/c++/v1/__functional/weak_result_type.h
OLD_DIRS+=usr/include/c++/v1/__functional
OLD_FILES+=usr/include/c++/v1/__functional_base
OLD_FILES+=usr/include/c++/v1/__hash_table
OLD_FILES+=usr/include/c++/v1/__iterator/access.h
OLD_FILES+=usr/include/c++/v1/__iterator/advance.h
OLD_FILES+=usr/include/c++/v1/__iterator/back_insert_iterator.h
OLD_FILES+=usr/include/c++/v1/__iterator/common_iterator.h
OLD_FILES+=usr/include/c++/v1/__iterator/concepts.h
OLD_FILES+=usr/include/c++/v1/__iterator/counted_iterator.h
OLD_FILES+=usr/include/c++/v1/__iterator/data.h
OLD_FILES+=usr/include/c++/v1/__iterator/default_sentinel.h
OLD_FILES+=usr/include/c++/v1/__iterator/distance.h
OLD_FILES+=usr/include/c++/v1/__iterator/empty.h
OLD_FILES+=usr/include/c++/v1/__iterator/erase_if_container.h
OLD_FILES+=usr/include/c++/v1/__iterator/front_insert_iterator.h
OLD_FILES+=usr/include/c++/v1/__iterator/incrementable_traits.h
OLD_FILES+=usr/include/c++/v1/__iterator/indirectly_comparable.h
OLD_FILES+=usr/include/c++/v1/__iterator/insert_iterator.h
OLD_FILES+=usr/include/c++/v1/__iterator/istream_iterator.h
OLD_FILES+=usr/include/c++/v1/__iterator/istreambuf_iterator.h
OLD_FILES+=usr/include/c++/v1/__iterator/iter_move.h
OLD_FILES+=usr/include/c++/v1/__iterator/iter_swap.h
OLD_FILES+=usr/include/c++/v1/__iterator/iterator.h
OLD_FILES+=usr/include/c++/v1/__iterator/iterator_traits.h
OLD_FILES+=usr/include/c++/v1/__iterator/move_iterator.h
OLD_FILES+=usr/include/c++/v1/__iterator/next.h
OLD_FILES+=usr/include/c++/v1/__iterator/ostream_iterator.h
OLD_FILES+=usr/include/c++/v1/__iterator/ostreambuf_iterator.h
OLD_FILES+=usr/include/c++/v1/__iterator/prev.h
OLD_FILES+=usr/include/c++/v1/__iterator/projected.h
OLD_FILES+=usr/include/c++/v1/__iterator/readable_traits.h
OLD_FILES+=usr/include/c++/v1/__iterator/reverse_access.h
OLD_FILES+=usr/include/c++/v1/__iterator/reverse_iterator.h
OLD_FILES+=usr/include/c++/v1/__iterator/size.h
OLD_FILES+=usr/include/c++/v1/__iterator/unreachable_sentinel.h
OLD_FILES+=usr/include/c++/v1/__iterator/wrap_iter.h
OLD_DIRS+=usr/include/c++/v1/__iterator
OLD_FILES+=usr/include/c++/v1/__libcpp_version
OLD_FILES+=usr/include/c++/v1/__locale
OLD_FILES+=usr/include/c++/v1/__mbstate_t.h
OLD_FILES+=usr/include/c++/v1/__memory/addressof.h
OLD_FILES+=usr/include/c++/v1/__memory/allocation_guard.h
OLD_FILES+=usr/include/c++/v1/__memory/allocator.h
OLD_FILES+=usr/include/c++/v1/__memory/allocator_arg_t.h
OLD_FILES+=usr/include/c++/v1/__memory/allocator_traits.h
OLD_FILES+=usr/include/c++/v1/__memory/auto_ptr.h
OLD_FILES+=usr/include/c++/v1/__memory/compressed_pair.h
OLD_FILES+=usr/include/c++/v1/__memory/concepts.h
OLD_FILES+=usr/include/c++/v1/__memory/construct_at.h
OLD_FILES+=usr/include/c++/v1/__memory/pointer_traits.h
OLD_FILES+=usr/include/c++/v1/__memory/ranges_construct_at.h
OLD_FILES+=usr/include/c++/v1/__memory/ranges_uninitialized_algorithms.h
OLD_FILES+=usr/include/c++/v1/__memory/raw_storage_iterator.h
OLD_FILES+=usr/include/c++/v1/__memory/shared_ptr.h
OLD_FILES+=usr/include/c++/v1/__memory/temporary_buffer.h
OLD_FILES+=usr/include/c++/v1/__memory/uninitialized_algorithms.h
OLD_FILES+=usr/include/c++/v1/__memory/unique_ptr.h
OLD_FILES+=usr/include/c++/v1/__memory/uses_allocator.h
OLD_FILES+=usr/include/c++/v1/__memory/voidify.h
OLD_DIRS+=usr/include/c++/v1/__memory
OLD_FILES+=usr/include/c++/v1/__mutex_base
OLD_FILES+=usr/include/c++/v1/__node_handle
OLD_FILES+=usr/include/c++/v1/__nullptr
OLD_FILES+=usr/include/c++/v1/__numeric/accumulate.h
OLD_FILES+=usr/include/c++/v1/__numeric/adjacent_difference.h
OLD_FILES+=usr/include/c++/v1/__numeric/exclusive_scan.h
OLD_FILES+=usr/include/c++/v1/__numeric/gcd_lcm.h
OLD_FILES+=usr/include/c++/v1/__numeric/inclusive_scan.h
OLD_FILES+=usr/include/c++/v1/__numeric/inner_product.h
OLD_FILES+=usr/include/c++/v1/__numeric/iota.h
OLD_FILES+=usr/include/c++/v1/__numeric/midpoint.h
OLD_FILES+=usr/include/c++/v1/__numeric/partial_sum.h
OLD_FILES+=usr/include/c++/v1/__numeric/reduce.h
OLD_FILES+=usr/include/c++/v1/__numeric/transform_exclusive_scan.h
OLD_FILES+=usr/include/c++/v1/__numeric/transform_inclusive_scan.h
OLD_FILES+=usr/include/c++/v1/__numeric/transform_reduce.h
OLD_DIRS+=usr/include/c++/v1/__numeric
OLD_FILES+=usr/include/c++/v1/__random/bernoulli_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/binomial_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/cauchy_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/chi_squared_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/clamp_to_integral.h
OLD_FILES+=usr/include/c++/v1/__random/default_random_engine.h
OLD_FILES+=usr/include/c++/v1/__random/discard_block_engine.h
OLD_FILES+=usr/include/c++/v1/__random/discrete_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/exponential_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/extreme_value_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/fisher_f_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/gamma_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/generate_canonical.h
OLD_FILES+=usr/include/c++/v1/__random/geometric_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/independent_bits_engine.h
OLD_FILES+=usr/include/c++/v1/__random/is_seed_sequence.h
OLD_FILES+=usr/include/c++/v1/__random/knuth_b.h
OLD_FILES+=usr/include/c++/v1/__random/linear_congruential_engine.h
OLD_FILES+=usr/include/c++/v1/__random/log2.h
OLD_FILES+=usr/include/c++/v1/__random/lognormal_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/mersenne_twister_engine.h
OLD_FILES+=usr/include/c++/v1/__random/negative_binomial_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/normal_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/piecewise_constant_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/piecewise_linear_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/poisson_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/random_device.h
OLD_FILES+=usr/include/c++/v1/__random/ranlux.h
OLD_FILES+=usr/include/c++/v1/__random/seed_seq.h
OLD_FILES+=usr/include/c++/v1/__random/shuffle_order_engine.h
OLD_FILES+=usr/include/c++/v1/__random/student_t_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/subtract_with_carry_engine.h
OLD_FILES+=usr/include/c++/v1/__random/uniform_int_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/uniform_random_bit_generator.h
OLD_FILES+=usr/include/c++/v1/__random/uniform_real_distribution.h
OLD_FILES+=usr/include/c++/v1/__random/weibull_distribution.h
OLD_DIRS+=usr/include/c++/v1/__random
OLD_FILES+=usr/include/c++/v1/__ranges/access.h
OLD_FILES+=usr/include/c++/v1/__ranges/all.h
OLD_FILES+=usr/include/c++/v1/__ranges/common_view.h
OLD_FILES+=usr/include/c++/v1/__ranges/concepts.h
OLD_FILES+=usr/include/c++/v1/__ranges/copyable_box.h
OLD_FILES+=usr/include/c++/v1/__ranges/counted.h
OLD_FILES+=usr/include/c++/v1/__ranges/dangling.h
OLD_FILES+=usr/include/c++/v1/__ranges/data.h
OLD_FILES+=usr/include/c++/v1/__ranges/drop_view.h
OLD_FILES+=usr/include/c++/v1/__ranges/empty.h
OLD_FILES+=usr/include/c++/v1/__ranges/empty_view.h
OLD_FILES+=usr/include/c++/v1/__ranges/enable_borrowed_range.h
OLD_FILES+=usr/include/c++/v1/__ranges/enable_view.h
OLD_FILES+=usr/include/c++/v1/__ranges/iota_view.h
OLD_FILES+=usr/include/c++/v1/__ranges/join_view.h
OLD_FILES+=usr/include/c++/v1/__ranges/non_propagating_cache.h
OLD_FILES+=usr/include/c++/v1/__ranges/owning_view.h
OLD_FILES+=usr/include/c++/v1/__ranges/range_adaptor.h
OLD_FILES+=usr/include/c++/v1/__ranges/ref_view.h
OLD_FILES+=usr/include/c++/v1/__ranges/reverse_view.h
OLD_FILES+=usr/include/c++/v1/__ranges/single_view.h
OLD_FILES+=usr/include/c++/v1/__ranges/size.h
OLD_FILES+=usr/include/c++/v1/__ranges/subrange.h
OLD_FILES+=usr/include/c++/v1/__ranges/take_view.h
OLD_FILES+=usr/include/c++/v1/__ranges/transform_view.h
OLD_FILES+=usr/include/c++/v1/__ranges/view_interface.h
OLD_DIRS+=usr/include/c++/v1/__ranges
OLD_FILES+=usr/include/c++/v1/__split_buffer
OLD_FILES+=usr/include/c++/v1/__std_stream
OLD_FILES+=usr/include/c++/v1/__string
OLD_FILES+=usr/include/c++/v1/__thread/poll_with_backoff.h
OLD_FILES+=usr/include/c++/v1/__thread/timed_backoff_policy.h
OLD_DIRS+=usr/include/c++/v1/__thread
OLD_FILES+=usr/include/c++/v1/__threading_support
OLD_FILES+=usr/include/c++/v1/__tree
OLD_FILES+=usr/include/c++/v1/__tuple
OLD_FILES+=usr/include/c++/v1/__undef_macros
OLD_FILES+=usr/include/c++/v1/__utility/as_const.h
OLD_FILES+=usr/include/c++/v1/__utility/auto_cast.h
OLD_FILES+=usr/include/c++/v1/__utility/cmp.h
OLD_FILES+=usr/include/c++/v1/__utility/declval.h
OLD_FILES+=usr/include/c++/v1/__utility/exchange.h
OLD_FILES+=usr/include/c++/v1/__utility/forward.h
OLD_FILES+=usr/include/c++/v1/__utility/in_place.h
OLD_FILES+=usr/include/c++/v1/__utility/integer_sequence.h
OLD_FILES+=usr/include/c++/v1/__utility/move.h
OLD_FILES+=usr/include/c++/v1/__utility/pair.h
OLD_FILES+=usr/include/c++/v1/__utility/piecewise_construct.h
OLD_FILES+=usr/include/c++/v1/__utility/priority_tag.h
OLD_FILES+=usr/include/c++/v1/__utility/rel_ops.h
OLD_FILES+=usr/include/c++/v1/__utility/swap.h
OLD_FILES+=usr/include/c++/v1/__utility/to_underlying.h
OLD_FILES+=usr/include/c++/v1/__utility/transaction.h
OLD_DIRS+=usr/include/c++/v1/__utility
OLD_FILES+=usr/include/c++/v1/__variant/monostate.h
OLD_DIRS+=usr/include/c++/v1/__variant
OLD_FILES+=usr/include/c++/v1/algorithm
OLD_FILES+=usr/include/c++/v1/any
OLD_FILES+=usr/include/c++/v1/array
OLD_FILES+=usr/include/c++/v1/atomic
OLD_FILES+=usr/include/c++/v1/barrier
OLD_FILES+=usr/include/c++/v1/bit
OLD_FILES+=usr/include/c++/v1/bitset
OLD_FILES+=usr/include/c++/v1/cassert
OLD_FILES+=usr/include/c++/v1/ccomplex
OLD_FILES+=usr/include/c++/v1/cctype
OLD_FILES+=usr/include/c++/v1/cerrno
OLD_FILES+=usr/include/c++/v1/cfenv
OLD_FILES+=usr/include/c++/v1/cfloat
OLD_FILES+=usr/include/c++/v1/charconv
OLD_FILES+=usr/include/c++/v1/chrono
OLD_FILES+=usr/include/c++/v1/cinttypes
OLD_FILES+=usr/include/c++/v1/ciso646
OLD_FILES+=usr/include/c++/v1/climits
OLD_FILES+=usr/include/c++/v1/clocale
OLD_FILES+=usr/include/c++/v1/cmath
OLD_FILES+=usr/include/c++/v1/codecvt
OLD_FILES+=usr/include/c++/v1/compare
OLD_FILES+=usr/include/c++/v1/complex
OLD_FILES+=usr/include/c++/v1/complex.h
OLD_FILES+=usr/include/c++/v1/concepts
OLD_FILES+=usr/include/c++/v1/condition_variable
OLD_FILES+=usr/include/c++/v1/coroutine
OLD_FILES+=usr/include/c++/v1/csetjmp
OLD_FILES+=usr/include/c++/v1/csignal
OLD_FILES+=usr/include/c++/v1/cstdarg
OLD_FILES+=usr/include/c++/v1/cstdbool
OLD_FILES+=usr/include/c++/v1/cstddef
OLD_FILES+=usr/include/c++/v1/cstdint
OLD_FILES+=usr/include/c++/v1/cstdio
OLD_FILES+=usr/include/c++/v1/cstdlib
OLD_FILES+=usr/include/c++/v1/cstring
OLD_FILES+=usr/include/c++/v1/ctgmath
OLD_FILES+=usr/include/c++/v1/ctime
OLD_FILES+=usr/include/c++/v1/ctype.h
OLD_FILES+=usr/include/c++/v1/cwchar
OLD_FILES+=usr/include/c++/v1/cwctype
OLD_FILES+=usr/include/c++/v1/cxxabi.h
OLD_FILES+=usr/include/c++/v1/deque
OLD_FILES+=usr/include/c++/v1/errno.h
OLD_FILES+=usr/include/c++/v1/exception
OLD_FILES+=usr/include/c++/v1/execution
OLD_FILES+=usr/include/c++/v1/experimental/__config
OLD_FILES+=usr/include/c++/v1/experimental/__memory
OLD_FILES+=usr/include/c++/v1/experimental/algorithm
OLD_FILES+=usr/include/c++/v1/experimental/coroutine
OLD_FILES+=usr/include/c++/v1/experimental/deque
OLD_FILES+=usr/include/c++/v1/experimental/filesystem
OLD_FILES+=usr/include/c++/v1/experimental/forward_list
OLD_FILES+=usr/include/c++/v1/experimental/functional
OLD_FILES+=usr/include/c++/v1/experimental/iterator
OLD_FILES+=usr/include/c++/v1/experimental/list
OLD_FILES+=usr/include/c++/v1/experimental/map
OLD_FILES+=usr/include/c++/v1/experimental/memory_resource
OLD_FILES+=usr/include/c++/v1/experimental/propagate_const
OLD_FILES+=usr/include/c++/v1/experimental/regex
OLD_FILES+=usr/include/c++/v1/experimental/set
OLD_FILES+=usr/include/c++/v1/experimental/simd
OLD_FILES+=usr/include/c++/v1/experimental/string
OLD_FILES+=usr/include/c++/v1/experimental/type_traits
OLD_FILES+=usr/include/c++/v1/experimental/unordered_map
OLD_FILES+=usr/include/c++/v1/experimental/unordered_set
OLD_FILES+=usr/include/c++/v1/experimental/utility
OLD_FILES+=usr/include/c++/v1/experimental/vector
OLD_DIRS+=usr/include/c++/v1/experimental
OLD_FILES+=usr/include/c++/v1/ext/__hash
OLD_FILES+=usr/include/c++/v1/ext/hash_map
OLD_FILES+=usr/include/c++/v1/ext/hash_set
OLD_DIRS+=usr/include/c++/v1/ext
OLD_FILES+=usr/include/c++/v1/fenv.h
OLD_FILES+=usr/include/c++/v1/filesystem
OLD_FILES+=usr/include/c++/v1/float.h
OLD_FILES+=usr/include/c++/v1/format
OLD_FILES+=usr/include/c++/v1/forward_list
OLD_FILES+=usr/include/c++/v1/fstream
OLD_FILES+=usr/include/c++/v1/functional
OLD_FILES+=usr/include/c++/v1/future
OLD_FILES+=usr/include/c++/v1/initializer_list
OLD_FILES+=usr/include/c++/v1/inttypes.h
OLD_FILES+=usr/include/c++/v1/iomanip
OLD_FILES+=usr/include/c++/v1/ios
OLD_FILES+=usr/include/c++/v1/iosfwd
OLD_FILES+=usr/include/c++/v1/iostream
OLD_FILES+=usr/include/c++/v1/istream
OLD_FILES+=usr/include/c++/v1/iterator
OLD_FILES+=usr/include/c++/v1/latch
OLD_FILES+=usr/include/c++/v1/limits
OLD_FILES+=usr/include/c++/v1/limits.h
OLD_FILES+=usr/include/c++/v1/list
OLD_FILES+=usr/include/c++/v1/locale
OLD_FILES+=usr/include/c++/v1/locale.h
OLD_FILES+=usr/include/c++/v1/map
OLD_FILES+=usr/include/c++/v1/math.h
OLD_FILES+=usr/include/c++/v1/memory
OLD_FILES+=usr/include/c++/v1/module.modulemap
OLD_FILES+=usr/include/c++/v1/mutex
OLD_FILES+=usr/include/c++/v1/new
OLD_FILES+=usr/include/c++/v1/numbers
OLD_FILES+=usr/include/c++/v1/numeric
OLD_FILES+=usr/include/c++/v1/optional
OLD_FILES+=usr/include/c++/v1/ostream
OLD_FILES+=usr/include/c++/v1/queue
OLD_FILES+=usr/include/c++/v1/random
OLD_FILES+=usr/include/c++/v1/ranges
OLD_FILES+=usr/include/c++/v1/ratio
OLD_FILES+=usr/include/c++/v1/regex
OLD_FILES+=usr/include/c++/v1/scoped_allocator
OLD_FILES+=usr/include/c++/v1/semaphore
OLD_FILES+=usr/include/c++/v1/set
OLD_FILES+=usr/include/c++/v1/setjmp.h
OLD_FILES+=usr/include/c++/v1/shared_mutex
OLD_FILES+=usr/include/c++/v1/span
OLD_FILES+=usr/include/c++/v1/sstream
OLD_FILES+=usr/include/c++/v1/stack
OLD_FILES+=usr/include/c++/v1/stdbool.h
OLD_FILES+=usr/include/c++/v1/stddef.h
OLD_FILES+=usr/include/c++/v1/stdexcept
OLD_FILES+=usr/include/c++/v1/stdint.h
OLD_FILES+=usr/include/c++/v1/stdio.h
OLD_FILES+=usr/include/c++/v1/stdlib.h
OLD_FILES+=usr/include/c++/v1/streambuf
OLD_FILES+=usr/include/c++/v1/string
OLD_FILES+=usr/include/c++/v1/string.h
OLD_FILES+=usr/include/c++/v1/string_view
OLD_FILES+=usr/include/c++/v1/strstream
OLD_FILES+=usr/include/c++/v1/system_error
OLD_FILES+=usr/include/c++/v1/tgmath.h
OLD_FILES+=usr/include/c++/v1/thread
OLD_FILES+=usr/include/c++/v1/tuple
OLD_FILES+=usr/include/c++/v1/type_traits
OLD_FILES+=usr/include/c++/v1/typeindex
OLD_FILES+=usr/include/c++/v1/typeinfo
OLD_FILES+=usr/include/c++/v1/unordered_map
OLD_FILES+=usr/include/c++/v1/unordered_set
OLD_FILES+=usr/include/c++/v1/utility
OLD_FILES+=usr/include/c++/v1/valarray
OLD_FILES+=usr/include/c++/v1/variant
OLD_FILES+=usr/include/c++/v1/vector
OLD_FILES+=usr/include/c++/v1/version
OLD_FILES+=usr/include/c++/v1/wchar.h
OLD_FILES+=usr/include/c++/v1/wctype.h
OLD_DIRS+=usr/include/c++/v1
.endif
.if ${MK_LLD} == no
OLD_FILES+=usr/bin/ld.lld
.endif
.if ${MK_LLDB} == no
OLD_FILES+=usr/bin/lldb
OLD_FILES+=usr/bin/lldb-server
OLD_FILES+=usr/share/man/man1/lldb-server.1.gz
OLD_FILES+=usr/share/man/man1/lldb.1.gz
.endif
.if ${MK_LOCALES} == no
OLD_DIRS+=usr/share/locale/af_ZA.ISO8859-15
OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/af_ZA.ISO8859-1
OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/af_ZA.UTF-8
OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/am_ET.UTF-8
OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ar_AE.UTF-8
OLD_FILES+=usr/share/locale/ar_AE.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ar_AE.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ar_AE.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ar_AE.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ar_AE.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ar_AE.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ar_EG.UTF-8
OLD_FILES+=usr/share/locale/ar_EG.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ar_EG.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ar_EG.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ar_EG.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ar_EG.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ar_EG.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ar_JO.UTF-8
OLD_FILES+=usr/share/locale/ar_JO.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ar_JO.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ar_JO.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ar_JO.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ar_JO.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ar_JO.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ar_MA.UTF-8
OLD_FILES+=usr/share/locale/ar_MA.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ar_MA.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ar_MA.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ar_MA.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ar_MA.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ar_MA.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ar_QA.UTF-8
OLD_FILES+=usr/share/locale/ar_QA.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ar_QA.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ar_QA.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ar_QA.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ar_QA.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ar_QA.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ar_SA.UTF-8
OLD_FILES+=usr/share/locale/ar_SA.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ar_SA.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ar_SA.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ar_SA.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ar_SA.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ar_SA.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/be_BY.CP1131
OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_COLLATE
OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_CTYPE
OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_MESSAGES
OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_MONETARY
OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_NUMERIC
OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_TIME
OLD_DIRS+=usr/share/locale/be_BY.CP1251
OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_COLLATE
OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_CTYPE
OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_MESSAGES
OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_MONETARY
OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_NUMERIC
OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_TIME
OLD_DIRS+=usr/share/locale/be_BY.ISO8859-5
OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_COLLATE
OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_CTYPE
OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_MESSAGES
OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_MONETARY
OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_NUMERIC
OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_TIME
OLD_DIRS+=usr/share/locale/be_BY.UTF-8
OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/bg_BG.CP1251
OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_COLLATE
OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_CTYPE
OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_MESSAGES
OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_MONETARY
OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_NUMERIC
OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_TIME
OLD_DIRS+=usr/share/locale/bg_BG.UTF-8
OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ca_AD.ISO8859-1
OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/ca_AD.ISO8859-15
OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/ca_AD.UTF-8
OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ca_ES.ISO8859-1
OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/ca_ES.ISO8859-15
OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/ca_ES.UTF-8
OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ca_FR.ISO8859-1
OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/ca_FR.ISO8859-15
OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/ca_FR.UTF-8
OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ca_IT.ISO8859-1
OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/ca_IT.ISO8859-15
OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/ca_IT.UTF-8
OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/cs_CZ.ISO8859-2
OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_COLLATE
OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_CTYPE
OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_MESSAGES
OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_MONETARY
OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_NUMERIC
OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_TIME
OLD_DIRS+=usr/share/locale/cs_CZ.UTF-8
OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/da_DK.ISO8859-1
OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/da_DK.ISO8859-15
OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/da_DK.UTF-8
OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/de_AT.ISO8859-1
OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/de_AT.ISO8859-15
OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/de_AT.UTF-8
OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/de_CH.ISO8859-1
OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/de_CH.ISO8859-15
OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/de_CH.UTF-8
OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/de_DE.ISO8859-1
OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/de_DE.ISO8859-15
OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/de_DE.UTF-8
OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/el_GR.ISO8859-7
OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_COLLATE
OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_CTYPE
OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_MESSAGES
OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_MONETARY
OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_NUMERIC
OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_TIME
OLD_DIRS+=usr/share/locale/el_GR.UTF-8
OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/en_AU.ISO8859-1
OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/en_AU.ISO8859-15
OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/en_AU.US-ASCII
OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_COLLATE
OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_CTYPE
OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_MONETARY
OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_TIME
OLD_DIRS+=usr/share/locale/en_AU.UTF-8
OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/en_CA.ISO8859-1
OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/en_CA.ISO8859-15
OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/en_CA.US-ASCII
OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_COLLATE
OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_CTYPE
OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_MONETARY
OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_TIME
OLD_DIRS+=usr/share/locale/en_CA.UTF-8
OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/en_GB.ISO8859-1
OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/en_GB.ISO8859-15
OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/en_GB.US-ASCII
OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_COLLATE
OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_CTYPE
OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_MONETARY
OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_TIME
OLD_DIRS+=usr/share/locale/en_GB.UTF-8
OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/en_HK.ISO8859-1
OLD_FILES+=usr/share/locale/en_HK.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/en_HK.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/en_HK.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_HK.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/en_HK.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_HK.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/en_HK.UTF-8
OLD_FILES+=usr/share/locale/en_HK.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/en_HK.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/en_HK.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_HK.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/en_HK.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_HK.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/en_IE.ISO8859-1
OLD_FILES+=usr/share/locale/en_IE.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/en_IE.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/en_IE.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_IE.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/en_IE.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_IE.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/en_IE.ISO8859-15
OLD_FILES+=usr/share/locale/en_IE.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/en_IE.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/en_IE.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_IE.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/en_IE.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_IE.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/en_IE.UTF-8
OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/en_NZ.ISO8859-1
OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/en_NZ.ISO8859-15
OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/en_NZ.US-ASCII
OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_COLLATE
OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_CTYPE
OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_MONETARY
OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_TIME
OLD_DIRS+=usr/share/locale/en_NZ.UTF-8
OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/en_PH.UTF-8
OLD_FILES+=usr/share/locale/en_PH.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/en_PH.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/en_PH.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_PH.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/en_PH.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_PH.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/en_SG.ISO8859-1
OLD_FILES+=usr/share/locale/en_SG.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/en_SG.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/en_SG.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_SG.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/en_SG.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_SG.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/en_SG.UTF-8
OLD_FILES+=usr/share/locale/en_SG.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/en_SG.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/en_SG.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_SG.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/en_SG.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_SG.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/en_US.ISO8859-1
OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/en_US.ISO8859-15
OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/en_US.US-ASCII
OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_COLLATE
OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_CTYPE
OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_MONETARY
OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_TIME
OLD_DIRS+=usr/share/locale/en_US.UTF-8
OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/en_ZA.ISO8859-1
OLD_FILES+=usr/share/locale/en_ZA.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/en_ZA.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/en_ZA.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_ZA.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/en_ZA.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_ZA.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/en_ZA.ISO8859-15
OLD_FILES+=usr/share/locale/en_ZA.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/en_ZA.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/en_ZA.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_ZA.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/en_ZA.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_ZA.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/en_ZA.US-ASCII
OLD_FILES+=usr/share/locale/en_ZA.US-ASCII/LC_COLLATE
OLD_FILES+=usr/share/locale/en_ZA.US-ASCII/LC_CTYPE
OLD_FILES+=usr/share/locale/en_ZA.US-ASCII/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_ZA.US-ASCII/LC_MONETARY
OLD_FILES+=usr/share/locale/en_ZA.US-ASCII/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_ZA.US-ASCII/LC_TIME
OLD_DIRS+=usr/share/locale/en_ZA.UTF-8
OLD_FILES+=usr/share/locale/en_ZA.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/en_ZA.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/en_ZA.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/en_ZA.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/en_ZA.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/en_ZA.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/es_AR.ISO8859-1
OLD_FILES+=usr/share/locale/es_AR.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/es_AR.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/es_AR.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/es_AR.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/es_AR.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/es_AR.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/es_AR.UTF-8
OLD_FILES+=usr/share/locale/es_AR.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/es_AR.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/es_AR.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/es_AR.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/es_AR.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/es_AR.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/es_CR.UTF-8
OLD_FILES+=usr/share/locale/es_CR.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/es_CR.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/es_CR.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/es_CR.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/es_CR.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/es_CR.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/es_ES.ISO8859-1
OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/es_ES.ISO8859-15
OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/es_ES.UTF-8
OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/es_MX.ISO8859-1
OLD_FILES+=usr/share/locale/es_MX.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/es_MX.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/es_MX.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/es_MX.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/es_MX.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/es_MX.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/es_MX.UTF-8
OLD_FILES+=usr/share/locale/es_MX.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/es_MX.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/es_MX.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/es_MX.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/es_MX.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/es_MX.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/et_EE.ISO8859-1
OLD_FILES+=usr/share/locale/et_EE.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/et_EE.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/et_EE.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/et_EE.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/et_EE.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/et_EE.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/et_EE.ISO8859-15
OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/et_EE.UTF-8
OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/eu_ES.ISO8859-1
OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/eu_ES.ISO8859-15
OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/eu_ES.UTF-8
OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/fi_FI.ISO8859-1
OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/fi_FI.ISO8859-15
OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/fi_FI.UTF-8
OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/fr_BE.ISO8859-1
OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/fr_BE.ISO8859-15
OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/fr_BE.UTF-8
OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/fr_CA.ISO8859-1
OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/fr_CA.ISO8859-15
OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/fr_CA.UTF-8
OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/fr_CH.ISO8859-1
OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/fr_CH.ISO8859-15
OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/fr_CH.UTF-8
OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/fr_FR.ISO8859-1
OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/fr_FR.ISO8859-15
OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/fr_FR.UTF-8
OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/he_IL.UTF-8
OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/hi_IN.ISCII-DEV
OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_COLLATE
OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_CTYPE
OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_MESSAGES
OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_MONETARY
OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_NUMERIC
OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_TIME
OLD_DIRS+=usr/share/locale/hi_IN.UTF-8
OLD_FILES+=usr/share/locale/hi_IN.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/hi_IN.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/hi_IN.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/hi_IN.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/hi_IN.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/hi_IN.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/hr_HR.ISO8859-2
OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_COLLATE
OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_CTYPE
OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_MESSAGES
OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_MONETARY
OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_NUMERIC
OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_TIME
OLD_DIRS+=usr/share/locale/hr_HR.UTF-8
OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/hu_HU.ISO8859-2
OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_COLLATE
OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_CTYPE
OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_MESSAGES
OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_MONETARY
OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_NUMERIC
OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_TIME
OLD_DIRS+=usr/share/locale/hu_HU.UTF-8
OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/hy_AM.ARMSCII-8
OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_COLLATE
OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_CTYPE
OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_MONETARY
OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_TIME
OLD_DIRS+=usr/share/locale/hy_AM.UTF-8
OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/is_IS.ISO8859-1
OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/is_IS.ISO8859-15
OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/is_IS.UTF-8
OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/it_CH.ISO8859-1
OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/it_CH.ISO8859-15
OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/it_CH.UTF-8
OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/it_IT.ISO8859-1
OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/it_IT.ISO8859-15
OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/it_IT.UTF-8
OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ja_JP.eucJP
OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_COLLATE
OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_CTYPE
OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_MESSAGES
OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_MONETARY
OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_NUMERIC
OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_TIME
OLD_DIRS+=usr/share/locale/ja_JP.SJIS
OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_COLLATE
OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_CTYPE
OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_MESSAGES
OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_MONETARY
OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_NUMERIC
OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_TIME
OLD_DIRS+=usr/share/locale/ja_JP.UTF-8
OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/kk_KZ.UTF-8
OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ko_KR.CP949
OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_COLLATE
OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_CTYPE
OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_MESSAGES
OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_MONETARY
OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_NUMERIC
OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_TIME
OLD_DIRS+=usr/share/locale/ko_KR.eucKR
OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_COLLATE
OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_CTYPE
OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_MESSAGES
OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_MONETARY
OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_NUMERIC
OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_TIME
OLD_DIRS+=usr/share/locale/ko_KR.UTF-8
OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/lt_LT.ISO8859-13
OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_COLLATE
OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_CTYPE
OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_MESSAGES
OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_MONETARY
OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_NUMERIC
OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_TIME
OLD_DIRS+=usr/share/locale/lt_LT.UTF-8
OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/lv_LV.ISO8859-13
OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_COLLATE
OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_CTYPE
OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_MESSAGES
OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_MONETARY
OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_NUMERIC
OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_TIME
OLD_DIRS+=usr/share/locale/lv_LV.UTF-8
OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/mn_MN.UTF-8
OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/nb_NO.ISO8859-1
OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/nb_NO.ISO8859-15
OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/nb_NO.UTF-8
OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/nl_BE.ISO8859-1
OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/nl_BE.ISO8859-15
OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/nl_BE.UTF-8
OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/nl_NL.ISO8859-1
OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/nl_NL.ISO8859-15
OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/nl_NL.UTF-8
OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/nn_NO.ISO8859-1
OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/nn_NO.ISO8859-15
OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/nn_NO.UTF-8
OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/pl_PL.ISO8859-2
OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_COLLATE
OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_CTYPE
OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_MESSAGES
OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_MONETARY
OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_NUMERIC
OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_TIME
OLD_DIRS+=usr/share/locale/pl_PL.UTF-8
OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/pt_BR.ISO8859-1
OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/pt_BR.UTF-8
OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/pt_PT.ISO8859-1
OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/pt_PT.ISO8859-15
OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/pt_PT.UTF-8
OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ro_RO.ISO8859-2
OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_COLLATE
OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_CTYPE
OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_MESSAGES
OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_MONETARY
OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_NUMERIC
OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_TIME
OLD_DIRS+=usr/share/locale/ro_RO.UTF-8
OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/ru_RU.CP1251
OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_COLLATE
OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_CTYPE
OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_MESSAGES
OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_MONETARY
OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_NUMERIC
OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_TIME
OLD_DIRS+=usr/share/locale/ru_RU.CP866
OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_COLLATE
OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_CTYPE
OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_MESSAGES
OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_MONETARY
OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_NUMERIC
OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_TIME
OLD_DIRS+=usr/share/locale/ru_RU.ISO8859-5
OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_COLLATE
OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_CTYPE
OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_MESSAGES
OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_MONETARY
OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_NUMERIC
OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_TIME
OLD_DIRS+=usr/share/locale/ru_RU.KOI8-R
OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_COLLATE
OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_CTYPE
OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_MESSAGES
OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_MONETARY
OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_NUMERIC
OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_TIME
OLD_DIRS+=usr/share/locale/ru_RU.UTF-8
OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/se_FI.UTF-8
OLD_FILES+=usr/share/locale/se_FI.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/se_FI.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/se_FI.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/se_FI.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/se_FI.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/se_FI.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/se_NO.UTF-8
OLD_FILES+=usr/share/locale/se_NO.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/se_NO.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/se_NO.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/se_NO.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/se_NO.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/se_NO.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/sk_SK.ISO8859-2
OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_COLLATE
OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_CTYPE
OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_MESSAGES
OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_MONETARY
OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_NUMERIC
OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_TIME
OLD_DIRS+=usr/share/locale/sk_SK.UTF-8
OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/sl_SI.ISO8859-2
OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_COLLATE
OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_CTYPE
OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_MESSAGES
OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_MONETARY
OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_NUMERIC
OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_TIME
OLD_DIRS+=usr/share/locale/sl_SI.UTF-8
OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/sr_RS.ISO8859-5
OLD_FILES+=usr/share/locale/sr_RS.ISO8859-5/LC_COLLATE
OLD_FILES+=usr/share/locale/sr_RS.ISO8859-5/LC_CTYPE
OLD_FILES+=usr/share/locale/sr_RS.ISO8859-5/LC_MESSAGES
OLD_FILES+=usr/share/locale/sr_RS.ISO8859-5/LC_MONETARY
OLD_FILES+=usr/share/locale/sr_RS.ISO8859-5/LC_NUMERIC
OLD_FILES+=usr/share/locale/sr_RS.ISO8859-5/LC_TIME
OLD_DIRS+=usr/share/locale/sr_RS.UTF-8
OLD_FILES+=usr/share/locale/sr_RS.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/sr_RS.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/sr_RS.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/sr_RS.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/sr_RS.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/sr_RS.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/sr_RS.ISO8859-2
OLD_FILES+=usr/share/locale/sr_RS.ISO8859-2/LC_COLLATE
OLD_FILES+=usr/share/locale/sr_RS.ISO8859-2/LC_CTYPE
OLD_FILES+=usr/share/locale/sr_RS.ISO8859-2/LC_MESSAGES
OLD_FILES+=usr/share/locale/sr_RS.ISO8859-2/LC_MONETARY
OLD_FILES+=usr/share/locale/sr_RS.ISO8859-2/LC_NUMERIC
OLD_FILES+=usr/share/locale/sr_RS.ISO8859-2/LC_TIME
OLD_DIRS+=usr/share/locale/sr_RS.UTF-8@latin
OLD_FILES+=usr/share/locale/sr_RS.UTF-8@latin/LC_COLLATE
OLD_FILES+=usr/share/locale/sr_RS.UTF-8@latin/LC_CTYPE
OLD_FILES+=usr/share/locale/sr_RS.UTF-8@latin/LC_MESSAGES
OLD_FILES+=usr/share/locale/sr_RS.UTF-8@latin/LC_MONETARY
OLD_FILES+=usr/share/locale/sr_RS.UTF-8@latin/LC_NUMERIC
OLD_FILES+=usr/share/locale/sr_RS.UTF-8@latin/LC_TIME
OLD_DIRS+=usr/share/locale/sv_FI.ISO8859-1
OLD_FILES+=usr/share/locale/sv_FI.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/sv_FI.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/sv_FI.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/sv_FI.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/sv_FI.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/sv_FI.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/sv_FI.ISO8859-15
OLD_FILES+=usr/share/locale/sv_FI.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/sv_FI.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/sv_FI.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/sv_FI.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/sv_FI.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/sv_FI.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/sv_FI.UTF-8
OLD_FILES+=usr/share/locale/sv_FI.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/sv_FI.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/sv_FI.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/sv_FI.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/sv_FI.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/sv_FI.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/sv_SE.ISO8859-1
OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_COLLATE
OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_CTYPE
OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_MESSAGES
OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_MONETARY
OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_NUMERIC
OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_TIME
OLD_DIRS+=usr/share/locale/sv_SE.ISO8859-15
OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_COLLATE
OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_CTYPE
OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_MESSAGES
OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_MONETARY
OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_NUMERIC
OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_TIME
OLD_DIRS+=usr/share/locale/sv_SE.UTF-8
OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/tr_TR.ISO8859-9
OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_COLLATE
OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_CTYPE
OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_MESSAGES
OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_MONETARY
OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_NUMERIC
OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_TIME
OLD_DIRS+=usr/share/locale/tr_TR.UTF-8
OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/uk_UA.CP1251
OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_COLLATE
OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_CTYPE
OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_MESSAGES
OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_MONETARY
OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_NUMERIC
OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_TIME
OLD_DIRS+=usr/share/locale/uk_UA.ISO8859-5
OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_COLLATE
OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_CTYPE
OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_MESSAGES
OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_MONETARY
OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_NUMERIC
OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_TIME
OLD_DIRS+=usr/share/locale/uk_UA.KOI8-U
OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_COLLATE
OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_CTYPE
OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_MESSAGES
OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_MONETARY
OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_NUMERIC
OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_TIME
OLD_DIRS+=usr/share/locale/uk_UA.UTF-8
OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/zh_CN.eucCN
OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_TIME
OLD_DIRS+=usr/share/locale/zh_CN.GB18030
OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_TIME
OLD_DIRS+=usr/share/locale/zh_CN.GB2312
OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_TIME
OLD_DIRS+=usr/share/locale/zh_CN.GBK
OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_TIME
OLD_DIRS+=usr/share/locale/zh_CN.UTF-8
OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/zh_HK.UTF-8
OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_TIME
OLD_DIRS+=usr/share/locale/zh_TW.Big5
OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_TIME
OLD_DIRS+=usr/share/locale/zh_TW.UTF-8
OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_COLLATE
OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_CTYPE
OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_MESSAGES
OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_MONETARY
OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_NUMERIC
OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_TIME
.endif
.if ${MK_LOCATE} == no
OLD_FILES+=etc/locate.rc
OLD_FILES+=etc/periodic/weekly/310.locate
OLD_FILES+=usr/bin/locate
OLD_FILES+=usr/libexec/locate.bigram
OLD_FILES+=usr/libexec/locate.code
OLD_FILES+=usr/libexec/locate.concatdb
OLD_FILES+=usr/libexec/locate.mklocatedb
OLD_FILES+=usr/libexec/locate.updatedb
OLD_FILES+=usr/share/man/man1/locate.1.gz
OLD_FILES+=usr/share/man/man8/locate.updatedb.8.gz
OLD_FILES+=usr/share/man/man8/updatedb.8.gz
.endif
.if ${MK_LPR} == no
OLD_FILES+=etc/hosts.lpd
OLD_FILES+=etc/printcap
OLD_FILES+=etc/newsyslog.conf.d/lpr.conf
OLD_FILES+=etc/rc.d/lpd
OLD_FILES+=etc/syslog.d/lpr.conf
OLD_FILES+=usr/bin/lp
OLD_FILES+=usr/bin/lpq
OLD_FILES+=usr/bin/lpr
OLD_FILES+=usr/bin/lprm
OLD_FILES+=usr/libexec/lpr/ru/bjc-240.sh.sample
OLD_FILES+=usr/libexec/lpr/ru/koi2alt
OLD_FILES+=usr/libexec/lpr/ru/koi2855
OLD_DIRS+=usr/libexec/lpr/ru
OLD_FILES+=usr/libexec/lpr/lpf
OLD_DIRS+=usr/libexec/lpr
OLD_FILES+=usr/sbin/chkprintcap
OLD_FILES+=usr/sbin/lpc
OLD_FILES+=usr/sbin/lpd
OLD_FILES+=usr/sbin/lptest
OLD_FILES+=usr/sbin/pac
OLD_FILES+=usr/share/doc/smm/07.lpd/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/07.lpd
OLD_FILES+=usr/share/examples/etc/hosts.lpd
OLD_FILES+=usr/share/examples/etc/printcap
OLD_FILES+=usr/share/man/man1/lp.1.gz
OLD_FILES+=usr/share/man/man1/lpq.1.gz
OLD_FILES+=usr/share/man/man1/lpr.1.gz
OLD_FILES+=usr/share/man/man1/lprm.1.gz
OLD_FILES+=usr/share/man/man1/lptest.1.gz
OLD_FILES+=usr/share/man/man5/printcap.5.gz
OLD_FILES+=usr/share/man/man8/chkprintcap.8.gz
OLD_FILES+=usr/share/man/man8/lpc.8.gz
OLD_FILES+=usr/share/man/man8/lpd.8.gz
OLD_FILES+=usr/share/man/man8/pac.8.gz
.endif
.if ${MK_MAIL} == no
OLD_FILES+=etc/aliases
OLD_FILES+=etc/mail.rc
OLD_FILES+=etc/mail/aliases
OLD_FILES+=etc/mail/mailer.conf
OLD_FILES+=etc/periodic/daily/130.clean-msgs
OLD_FILES+=etc/rc.d/othermta
OLD_FILES+=usr/bin/Mail
OLD_FILES+=usr/bin/biff
OLD_FILES+=usr/bin/from
OLD_FILES+=usr/bin/mail
OLD_FILES+=usr/bin/mailx
OLD_FILES+=usr/bin/msgs
OLD_FILES+=usr/libexec/comsat
OLD_FILES+=usr/share/examples/etc/mail.rc
OLD_FILES+=usr/share/man/man1/Mail.1.gz
OLD_FILES+=usr/share/man/man1/biff.1.gz
OLD_FILES+=usr/share/man/man1/from.1.gz
OLD_FILES+=usr/share/man/man1/mail.1.gz
OLD_FILES+=usr/share/man/man1/mailx.1.gz
OLD_FILES+=usr/share/man/man1/msgs.1.gz
OLD_FILES+=usr/share/man/man8/comsat.8.gz
OLD_FILES+=usr/share/misc/mail.help
OLD_FILES+=usr/share/misc/mail.tildehelp
.endif
.if ${MK_MAILWRAPPER} == no
OLD_FILES+=etc/mail/mailer.conf
# Don't remove, for no mailwrapper case:
# /usr/sbin/sendmail -> /usr/sbin/mailwrapper
# /usr/sbin/mailwrapper -> /usr/libexec/sendmail/sendmail
#OLD_FILES+=usr/sbin/mailwrapper
OLD_FILES+=usr/share/man/man8/mailwrapper.8.gz
.endif
.if ${MK_MAKE} == no
OLD_FILES+=usr/bin/make
OLD_FILES+=usr/share/man/man1/make.1.gz
OLD_FILES+=usr/share/mk/atf.test.mk
OLD_FILES+=usr/share/mk/bsd.README
OLD_FILES+=usr/share/mk/bsd.arch.inc.mk
OLD_FILES+=usr/share/mk/bsd.compiler.mk
OLD_FILES+=usr/share/mk/bsd.cpu.mk
OLD_FILES+=usr/share/mk/bsd.crunchgen.mk
OLD_FILES+=usr/share/mk/bsd.dep.mk
OLD_FILES+=usr/share/mk/bsd.doc.mk
OLD_FILES+=usr/share/mk/bsd.dtb.mk
OLD_FILES+=usr/share/mk/bsd.endian.mk
OLD_FILES+=usr/share/mk/bsd.files.mk
OLD_FILES+=usr/share/mk/bsd.incs.mk
OLD_FILES+=usr/share/mk/bsd.info.mk
OLD_FILES+=usr/share/mk/bsd.init.mk
OLD_FILES+=usr/share/mk/bsd.kmod.mk
OLD_FILES+=usr/share/mk/bsd.lib.mk
OLD_FILES+=usr/share/mk/bsd.libnames.mk
OLD_FILES+=usr/share/mk/bsd.links.mk
OLD_FILES+=usr/share/mk/bsd.man.mk
OLD_FILES+=usr/share/mk/bsd.mkopt.mk
OLD_FILES+=usr/share/mk/bsd.nls.mk
OLD_FILES+=usr/share/mk/bsd.obj.mk
OLD_FILES+=usr/share/mk/bsd.opts.mk
OLD_FILES+=usr/share/mk/bsd.own.mk
OLD_FILES+=usr/share/mk/bsd.port.mk
OLD_FILES+=usr/share/mk/bsd.port.options.mk
OLD_FILES+=usr/share/mk/bsd.port.post.mk
OLD_FILES+=usr/share/mk/bsd.port.pre.mk
OLD_FILES+=usr/share/mk/bsd.port.subdir.mk
OLD_FILES+=usr/share/mk/bsd.prog.mk
OLD_FILES+=usr/share/mk/bsd.progs.mk
OLD_FILES+=usr/share/mk/bsd.snmpmod.mk
OLD_FILES+=usr/share/mk/bsd.subdir.mk
OLD_FILES+=usr/share/mk/bsd.symver.mk
OLD_FILES+=usr/share/mk/bsd.sys.mk
OLD_FILES+=usr/share/mk/bsd.test.mk
OLD_FILES+=usr/share/mk/plain.test.mk
OLD_FILES+=usr/share/mk/suite.test.mk
OLD_FILES+=usr/share/mk/sys.mk
OLD_FILES+=usr/share/mk/tap.test.mk
OLD_FILES+=usr/share/mk/version_gen.awk
OLD_FILES+=usr/tests/usr.bin/bmake/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/archives/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.3
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.4
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.5
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.6
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.7
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.3
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.4
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.5
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.6
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.7
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.3
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.4
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.5
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.6
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.7
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/libtest.a
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.3
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.4
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.5
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.6
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.7
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.3
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.4
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.5
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.6
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.7
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.3
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.4
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.5
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.6
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.7
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/libtest.a
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.3
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.4
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.5
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.6
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.7
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.3
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.4
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.5
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.6
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.7
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.3
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.4
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.5
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.6
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.7
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/libtest.a
OLD_FILES+=usr/tests/usr.bin/bmake/basic/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/common.sh
OLD_FILES+=usr/tests/usr.bin/bmake/execution/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/shell/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/sh
OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/sh
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/sh
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/shell
OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/shell
OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/TEST1.a
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/TEST1.a
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/TEST2.a
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/TEST1.a
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/TEST2.a
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.3
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.4
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.5
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.3
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.4
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.5
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.3
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.4
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.5
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/mk/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/mk/sys.mk
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/cleanup
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/mk/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/mk/sys.mk
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/cleanup
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/mk/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/mk/sys.mk
OLD_FILES+=usr/tests/usr.bin/bmake/test-new.mk
OLD_FILES+=usr/tests/usr.bin/bmake/variables/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.status.3
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stderr.3
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stdout.3
OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.status.2
OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/legacy_test
OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/Kyuafile
OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/Makefile.test
OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/expected.status.1
OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/legacy_test
.endif
.if ${MK_MAN} == no
MAN_FILES!=find ${DESTDIR}/usr/share/man ${DESTDIR}/usr/share/openssl/man -type f | sed -e 's,^${DESTDIR}/,,'; echo
OLD_FILES+=${MAN_FILES}
MAN_DIRS!=find ${DESTDIR}/usr/share/man ${DESTDIR}/usr/share/openssl/man -type d | sed -e 's,^${DESTDIR}/,,'; echo
OLD_DIRS+=${MAN_DIRS}
.endif
.if ${MK_MAN_UTILS} == no
OLD_FILES+=etc/periodic/weekly/320.whatis
OLD_FILES+=usr/bin/apropos
OLD_FILES+=usr/bin/makewhatis
OLD_FILES+=usr/bin/man
OLD_FILES+=usr/bin/manpath
OLD_FILES+=usr/bin/whatis
OLD_FILES+=usr/libexec/makewhatis.local
OLD_FILES+=usr/sbin/manctl
OLD_FILES+=usr/share/man/man1/apropos.1.gz
OLD_FILES+=usr/share/man/man1/makewhatis.1.gz
OLD_FILES+=usr/share/man/man1/man.1.gz
OLD_FILES+=usr/share/man/man1/manpath.1.gz
OLD_FILES+=usr/share/man/man1/whatis.1.gz
OLD_FILES+=usr/share/man/man5/man.conf.5.gz
OLD_FILES+=usr/share/man/man8/makewhatis.local.8.gz
OLD_FILES+=usr/share/man/man8/manctl.8.gz
OLD_FILES+=usr/share/man/whatis
OLD_FILES+=usr/share/openssl/man/whatis
.endif
.if ${MK_NDIS} == no
OLD_FILES+=usr/sbin/ndiscvt
OLD_FILES+=usr/sbin/ndisgen
OLD_FILES+=usr/share/man/man8/ndiscvt.8.gz
OLD_FILES+=usr/share/man/man8/ndisgen.8.gz
OLD_FILES+=usr/share/misc/windrv_stub.c
.endif
.if ${MK_NETCAT} == no
OLD_FILES+=rescue/nc
OLD_FILES+=usr/bin/nc
OLD_FILES+=usr/share/man/man1/nc.1.gz
.endif
.if ${MK_NETGRAPH} == no
OLD_FILES+=usr/include/netgraph.h
OLD_FILES+=usr/lib/libnetgraph.a
OLD_FILES+=usr/lib/libnetgraph.so
OLD_LIBS+=usr/lib/libnetgraph.so.4
OLD_FILES+=usr/lib/libnetgraph_p.a
OLD_FILES+=usr/libexec/pppoed
OLD_FILES+=usr/sbin/flowctl
OLD_FILES+=usr/sbin/lmcconfig
OLD_FILES+=usr/sbin/ngctl
OLD_FILES+=usr/sbin/nghook
OLD_FILES+=usr/share/man/man3/NgAllocRecvAsciiMsg.3.gz
OLD_FILES+=usr/share/man/man3/NgAllocRecvData.3.gz
OLD_FILES+=usr/share/man/man3/NgAllocRecvMsg.3.gz
OLD_FILES+=usr/share/man/man3/NgMkSockNode.3.gz
OLD_FILES+=usr/share/man/man3/NgNameNode.3.gz
OLD_FILES+=usr/share/man/man3/NgRecvAsciiMsg.3.gz
OLD_FILES+=usr/share/man/man3/NgRecvData.3.gz
OLD_FILES+=usr/share/man/man3/NgRecvMsg.3.gz
OLD_FILES+=usr/share/man/man3/NgSendAsciiMsg.3.gz
OLD_FILES+=usr/share/man/man3/NgSendData.3.gz
OLD_FILES+=usr/share/man/man3/NgSendMsg.3.gz
OLD_FILES+=usr/share/man/man3/NgSendReplyMsg.3.gz
OLD_FILES+=usr/share/man/man3/NgSetDebug.3.gz
OLD_FILES+=usr/share/man/man3/NgSetErrLog.3.gz
OLD_FILES+=usr/share/man/man3/netgraph.3.gz
OLD_FILES+=usr/share/man/man8/flowctl.8.gz
OLD_FILES+=usr/share/man/man8/lmcconfig.8.gz
OLD_FILES+=usr/share/man/man8/ngctl.8.gz
OLD_FILES+=usr/share/man/man8/nghook.8.gz
OLD_FILES+=usr/share/man/man8/pppoed.8.gz
.endif
.if ${MK_IPFW} == no || ${MK_NETGRAPH} == no
OLD_FILES+=etc/rc.d/ipfw_netflow
.endif
.if ${MK_NETGRAPH_SUPPORT} == no
OLD_FILES+=usr/include/bsnmp/snmp_netgraph.h
OLD_FILES+=usr/lib/snmp_netgraph.so
OLD_LIBS+=usr/lib/snmp_netgraph.so.6
OLD_FILES+=usr/share/man/man3/snmp_netgraph.3.gz
OLD_FILES+=usr/share/snmp/defs/netgraph_tree.def
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-NETGRAPH.txt
.endif
.if ${MK_NIS} == no
OLD_FILES+=etc/rc.d/ypbind
OLD_FILES+=etc/rc.d/ypldap
OLD_FILES+=etc/rc.d/yppasswdd
OLD_FILES+=etc/rc.d/ypserv
OLD_FILES+=etc/rc.d/ypset
OLD_FILES+=etc/rc.d/ypupdated
OLD_FILES+=etc/rc.d/ypxfrd
OLD_FILES+=usr/bin/ypcat
OLD_FILES+=usr/bin/ypchfn
OLD_FILES+=usr/bin/ypchpass
OLD_FILES+=usr/bin/ypchsh
OLD_FILES+=usr/bin/ypmatch
OLD_FILES+=usr/bin/yppasswd
OLD_FILES+=usr/bin/ypwhich
OLD_FILES+=usr/include/ypclnt.h
OLD_FILES+=usr/lib/libypclnt.a
OLD_FILES+=usr/lib/libypclnt.so
OLD_LIBS+=usr/lib/libypclnt.so.4
OLD_FILES+=usr/lib/libypclnt_p.a
OLD_FILES+=usr/libexec/mknetid
OLD_FILES+=usr/libexec/yppwupdate
OLD_FILES+=usr/libexec/ypxfr
OLD_FILES+=usr/sbin/rpc.yppasswdd
OLD_FILES+=usr/sbin/rpc.ypupdated
OLD_FILES+=usr/sbin/rpc.ypxfrd
OLD_FILES+=usr/sbin/yp_mkdb
OLD_FILES+=usr/sbin/ypbind
OLD_FILES+=usr/sbin/ypinit
OLD_FILES+=usr/sbin/ypldap
OLD_FILES+=usr/sbin/yppoll
OLD_FILES+=usr/sbin/yppush
OLD_FILES+=usr/sbin/ypserv
OLD_FILES+=usr/sbin/ypset
OLD_FILES+=usr/share/man/man1/ypcat.1.gz
OLD_FILES+=usr/share/man/man1/ypchfn.1.gz
OLD_FILES+=usr/share/man/man1/ypchpass.1.gz
OLD_FILES+=usr/share/man/man1/ypchsh.1.gz
OLD_FILES+=usr/share/man/man1/ypmatch.1.gz
OLD_FILES+=usr/share/man/man1/yppasswd.1.gz
OLD_FILES+=usr/share/man/man1/ypwhich.1.gz
OLD_FILES+=usr/share/man/man5/netid.5.gz
OLD_FILES+=usr/share/man/man5/ypldap.conf.5.gz
OLD_FILES+=usr/share/man/man8/mknetid.8.gz
OLD_FILES+=usr/share/man/man8/rpc.yppasswdd.8.gz
OLD_FILES+=usr/share/man/man8/rpc.ypxfrd.8.gz
OLD_FILES+=usr/share/man/man8/NIS.8.gz
OLD_FILES+=usr/share/man/man8/YP.8.gz
OLD_FILES+=usr/share/man/man8/yp.8.gz
OLD_FILES+=usr/share/man/man8/nis.8.gz
OLD_FILES+=usr/share/man/man8/yp_mkdb.8.gz
OLD_FILES+=usr/share/man/man8/ypbind.8.gz
OLD_FILES+=usr/share/man/man8/ypinit.8.gz
OLD_FILES+=usr/share/man/man8/ypldap.8.gz
OLD_FILES+=usr/share/man/man8/yppoll.8.gz
OLD_FILES+=usr/share/man/man8/yppush.8.gz
OLD_FILES+=usr/share/man/man8/ypserv.8.gz
OLD_FILES+=usr/share/man/man8/ypset.8.gz
OLD_FILES+=usr/share/man/man8/ypxfr.8.gz
OLD_FILES+=var/yp/Makefile
OLD_FILES+=var/yp/Makefile.dist
OLD_DIRS+=var/yp
.endif
.if ${MK_NLS} == no
OLD_DIRS+=usr/share/nls/
OLD_DIRS+=usr/share/nls/C
OLD_FILES+=usr/share/nls/C/ee.cat
OLD_DIRS+=usr/share/nls/af_ZA.ISO8859-1
OLD_DIRS+=usr/share/nls/af_ZA.ISO8859-15
OLD_DIRS+=usr/share/nls/af_ZA.UTF-8
OLD_DIRS+=usr/share/nls/am_ET.UTF-8
OLD_DIRS+=usr/share/nls/be_BY.CP1131
OLD_DIRS+=usr/share/nls/be_BY.CP1251
OLD_DIRS+=usr/share/nls/be_BY.ISO8859-5
OLD_DIRS+=usr/share/nls/be_BY.UTF-8
OLD_FILES+=usr/share/nls/be_BY.UTF-8/libc.cat
OLD_DIRS+=usr/share/nls/bg_BG.CP1251
OLD_DIRS+=usr/share/nls/bg_BG.UTF-8
OLD_DIRS+=usr/share/nls/ca_ES.ISO8859-1
OLD_FILES+=usr/share/nls/ca_ES.ISO8859-1/libc.cat
OLD_DIRS+=usr/share/nls/ca_ES.ISO8859-15
OLD_DIRS+=usr/share/nls/ca_ES.UTF-8
OLD_DIRS+=usr/share/nls/cs_CZ.ISO8859-2
OLD_DIRS+=usr/share/nls/cs_CZ.UTF-8
OLD_DIRS+=usr/share/nls/da_DK.ISO8859-1
OLD_DIRS+=usr/share/nls/da_DK.ISO8859-15
OLD_DIRS+=usr/share/nls/da_DK.UTF-8
OLD_DIRS+=usr/share/nls/de_AT.ISO8859-1
OLD_FILES+=usr/share/nls/de_AT.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/de_AT.ISO8859-1/tcsh.cat
OLD_DIRS+=usr/share/nls/de_AT.ISO8859-15
OLD_FILES+=usr/share/nls/de_AT.ISO8859-15/ee.cat
OLD_FILES+=usr/share/nls/de_AT.ISO8859-15/tcsh.cat
OLD_DIRS+=usr/share/nls/de_AT.UTF-8
OLD_FILES+=usr/share/nls/de_AT.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/de_CH.ISO8859-1
OLD_FILES+=usr/share/nls/de_CH.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/de_CH.ISO8859-1/tcsh.cat
OLD_DIRS+=usr/share/nls/de_CH.ISO8859-15
OLD_FILES+=usr/share/nls/de_CH.ISO8859-15/ee.cat
OLD_FILES+=usr/share/nls/de_CH.ISO8859-15/tcsh.cat
OLD_DIRS+=usr/share/nls/de_CH.UTF-8
OLD_FILES+=usr/share/nls/de_CH.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/de_DE.ISO8859-1
OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/libc.cat
OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/tcsh.cat
OLD_DIRS+=usr/share/nls/de_DE.ISO8859-15
OLD_FILES+=usr/share/nls/de_DE.ISO8859-15/ee.cat
OLD_FILES+=usr/share/nls/de_DE.ISO8859-15/tcsh.cat
OLD_DIRS+=usr/share/nls/de_DE.UTF-8
OLD_FILES+=usr/share/nls/de_DE.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/el_GR.ISO8859-7
OLD_FILES+=usr/share/nls/el_GR.ISO8859-7/libc.cat
OLD_FILES+=usr/share/nls/el_GR.ISO8859-7/tcsh.cat
OLD_DIRS+=usr/share/nls/el_GR.UTF-8
OLD_FILES+=usr/share/nls/el_GR.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/en_AU.ISO8859-1
OLD_DIRS+=usr/share/nls/en_AU.ISO8859-15
OLD_DIRS+=usr/share/nls/en_AU.US-ASCII
OLD_DIRS+=usr/share/nls/en_AU.UTF-8
OLD_DIRS+=usr/share/nls/en_CA.ISO8859-1
OLD_FILES+=usr/share/nls/en_US.ISO8859-1/ee.cat
OLD_DIRS+=usr/share/nls/en_CA.ISO8859-15
OLD_DIRS+=usr/share/nls/en_CA.US-ASCII
OLD_DIRS+=usr/share/nls/en_CA.UTF-8
OLD_DIRS+=usr/share/nls/en_GB.ISO8859-1
OLD_DIRS+=usr/share/nls/en_GB.ISO8859-15
OLD_DIRS+=usr/share/nls/en_GB.US-ASCII
OLD_DIRS+=usr/share/nls/en_GB.UTF-8
OLD_DIRS+=usr/share/nls/en_IE.UTF-8
OLD_DIRS+=usr/share/nls/en_NZ.ISO8859-1
OLD_DIRS+=usr/share/nls/en_NZ.ISO8859-15
OLD_DIRS+=usr/share/nls/en_NZ.US-ASCII
OLD_DIRS+=usr/share/nls/en_NZ.UTF-8
OLD_DIRS+=usr/share/nls/en_US.ISO8859-1
OLD_DIRS+=usr/share/nls/en_US.ISO8859-15
OLD_FILES+=usr/share/nls/en_US.ISO8859-15/ee.cat
OLD_DIRS+=usr/share/nls/en_US.UTF-8
OLD_DIRS+=usr/share/nls/es_ES.UTF-8
OLD_FILES+=usr/share/nls/es_ES.ISO8859-1/libc.cat
OLD_FILES+=usr/share/nls/es_ES.ISO8859-1/tcsh.cat
OLD_DIRS+=usr/share/nls/es_ES.ISO8859-1
OLD_DIRS+=usr/share/nls/es_ES.ISO8859-15
OLD_FILES+=usr/share/nls/es_ES.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/es_ES.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/et_EE.ISO8859-15
OLD_FILES+=usr/share/nls/et_EE.ISO8859-15/tcsh.cat
OLD_DIRS+=usr/share/nls/et_EE.UTF-8
OLD_FILES+=usr/share/nls/et_EE.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/fi_FI.ISO8859-1
OLD_FILES+=usr/share/nls/fi_FI.ISO8859-1/libc.cat
OLD_FILES+=usr/share/nls/fi_FI.ISO8859-1/tcsh.cat
OLD_DIRS+=usr/share/nls/fi_FI.ISO8859-15
OLD_FILES+=usr/share/nls/fi_FI.ISO8859-15/tcsh.cat
OLD_DIRS+=usr/share/nls/fi_FI.UTF-8
OLD_FILES+=usr/share/nls/fi_FI.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/fr_BE.ISO8859-1
OLD_FILES+=usr/share/nls/fr_BE.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/fr_BE.ISO8859-1/tcsh.cat
OLD_DIRS+=usr/share/nls/fr_BE.ISO8859-15
OLD_FILES+=usr/share/nls/fr_BE.ISO8859-15/ee.cat
OLD_FILES+=usr/share/nls/fr_BE.ISO8859-15/tcsh.cat
OLD_DIRS+=usr/share/nls/fr_BE.UTF-8
OLD_FILES+=usr/share/nls/fr_BE.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/fr_CA.ISO8859-1
OLD_FILES+=usr/share/nls/fr_CA.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/fr_CA.ISO8859-1/tcsh.cat
OLD_DIRS+=usr/share/nls/fr_CA.ISO8859-15
OLD_FILES+=usr/share/nls/fr_CA.ISO8859-15/ee.cat
OLD_FILES+=usr/share/nls/fr_CA.ISO8859-15/tcsh.cat
OLD_DIRS+=usr/share/nls/fr_CA.UTF-8
OLD_FILES+=usr/share/nls/fr_CA.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/fr_CH.ISO8859-1
OLD_FILES+=usr/share/nls/fr_CH.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/fr_CH.ISO8859-1/tcsh.cat
OLD_DIRS+=usr/share/nls/fr_CH.ISO8859-15
OLD_FILES+=usr/share/nls/fr_CH.ISO8859-15/ee.cat
OLD_FILES+=usr/share/nls/fr_CH.ISO8859-15/tcsh.cat
OLD_DIRS+=usr/share/nls/fr_CH.UTF-8
OLD_FILES+=usr/share/nls/fr_CH.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/fr_FR.ISO8859-1
OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/libc.cat
OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/tcsh.cat
OLD_DIRS+=usr/share/nls/fr_FR.ISO8859-15
OLD_FILES+=usr/share/nls/fr_FR.ISO8859-15/ee.cat
OLD_FILES+=usr/share/nls/fr_FR.ISO8859-15/tcsh.cat
OLD_DIRS+=usr/share/nls/fr_FR.UTF-8
OLD_FILES+=usr/share/nls/fr_FR.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/gl_ES.ISO8859-1
OLD_FILES+=usr/share/nls/gl_ES.ISO8859-1/libc.cat
OLD_DIRS+=usr/share/nls/he_IL.UTF-8
OLD_DIRS+=usr/share/nls/hi_IN.ISCII-DEV
OLD_DIRS+=usr/share/nls/hr_HR.ISO8859-2
OLD_DIRS+=usr/share/nls/hu_HU.ISO8859-2
OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/ee.cat
OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/libc.cat
OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/sort.cat
OLD_DIRS+=usr/share/nls/hr_HR.UTF-8
OLD_DIRS+=usr/share/nls/hu_HU.UTF-8
OLD_DIRS+=usr/share/nls/hy_AM.ARMSCII-8
OLD_DIRS+=usr/share/nls/hy_AM.UTF-8
OLD_DIRS+=usr/share/nls/is_IS.ISO8859-1
OLD_DIRS+=usr/share/nls/is_IS.ISO8859-15
OLD_DIRS+=usr/share/nls/is_IS.UTF-8
OLD_DIRS+=usr/share/nls/it_CH.ISO8859-1
OLD_FILES+=usr/share/nls/it_CH.ISO8859-1/tcsh.cat
OLD_DIRS+=usr/share/nls/it_CH.ISO8859-15
OLD_FILES+=usr/share/nls/it_CH.ISO8859-15/tcsh.cat
OLD_DIRS+=usr/share/nls/it_CH.UTF-8
OLD_FILES+=usr/share/nls/it_CH.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/it_IT.ISO8859-1
OLD_FILES+=usr/share/nls/it_IT.ISO8859-1/tcsh.cat
OLD_DIRS+=usr/share/nls/it_IT.ISO8859-15
OLD_FILES+=usr/share/nls/it_IT.ISO8859-15/libc.cat
OLD_FILES+=usr/share/nls/it_IT.ISO8859-15/tcsh.cat
OLD_DIRS+=usr/share/nls/it_IT.UTF-8
OLD_FILES+=usr/share/nls/it_IT.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/ja_JP.SJIS
OLD_FILES+=usr/share/nls/ja_JP.SJIS/tcsh.cat
OLD_DIRS+=usr/share/nls/ja_JP.UTF-8
OLD_FILES+=usr/share/nls/ja_JP.UTF-8/libc.cat
OLD_FILES+=usr/share/nls/ja_JP.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/ja_JP.eucJP
OLD_FILES+=usr/share/nls/ja_JP.eucJP/libc.cat
OLD_FILES+=usr/share/nls/ja_JP.eucJP/tcsh.cat
OLD_DIRS+=usr/share/nls/kk_KZ.PT154
OLD_DIRS+=usr/share/nls/kk_KZ.UTF-8
OLD_DIRS+=usr/share/nls/ko_KR.CP949
OLD_DIRS+=usr/share/nls/ko_KR.UTF-8
OLD_FILES+=usr/share/nls/ko_KR.UTF-8/libc.cat
OLD_DIRS+=usr/share/nls/ko_KR.eucKR
OLD_FILES+=usr/share/nls/ko_KR.eucKR/libc.cat
OLD_DIRS+=usr/share/nls/lv_LV.UTF-8
OLD_DIRS+=usr/share/nls/lt_LT.ISO8859-13
OLD_DIRS+=usr/share/nls/lt_LT.UTF-8
OLD_DIRS+=usr/share/nls/lv_LV.ISO8859-13
OLD_DIRS+=usr/share/nls/mn_MN.UTF-8
OLD_FILES+=usr/share/nls/mn_MN.UTF-8/libc.cat
OLD_DIRS+=usr/share/nls/nl_BE.ISO8859-1
OLD_DIRS+=usr/share/nls/nl_BE.ISO8859-15
OLD_DIRS+=usr/share/nls/nl_BE.UTF-8
OLD_DIRS+=usr/share/nls/no_NO.ISO8859-1
OLD_FILES+=usr/share/nls/nl_NL.ISO8859-1/libc.cat
OLD_DIRS+=usr/share/nls/nl_NL.ISO8859-15
OLD_DIRS+=usr/share/nls/nl_NL.ISO8859-1
OLD_FILES+=usr/share/nls/no_NO.ISO8859-1/libc.cat
OLD_DIRS+=usr/share/nls/no_NO.ISO8859-15
OLD_DIRS+=usr/share/nls/nl_NL.UTF-8
OLD_DIRS+=usr/share/nls/no_NO.UTF-8
OLD_DIRS+=usr/share/nls/pl_PL.ISO8859-2
OLD_FILES+=usr/share/nls/pl_PL.ISO8859-2/ee.cat
OLD_FILES+=usr/share/nls/pl_PL.ISO8859-2/libc.cat
OLD_DIRS+=usr/share/nls/pl_PL.UTF-8
OLD_DIRS+=usr/share/nls/pt_BR.ISO8859-1
OLD_DIRS+=usr/share/nls/pt_BR.UTF-8
OLD_DIRS+=usr/share/nls/pt_PT.ISO8859-1
OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/libc.cat
OLD_FILES+=usr/share/nls/pt_PT.ISO8859-1/ee.cat
OLD_DIRS+=usr/share/nls/pt_PT.ISO8859-15
OLD_DIRS+=usr/share/nls/pt_PT.UTF-8
OLD_DIRS+=usr/share/nls/ro_RO.ISO8859-2
OLD_DIRS+=usr/share/nls/ro_RO.UTF-8
OLD_DIRS+=usr/share/nls/ru_RU.CP1251
OLD_FILES+=usr/share/nls/ru_RU.CP1251/tcsh.cat
OLD_DIRS+=usr/share/nls/ru_RU.CP866
OLD_FILES+=usr/share/nls/ru_RU.CP866/tcsh.cat
OLD_DIRS+=usr/share/nls/ru_RU.ISO8859-5
OLD_FILES+=usr/share/nls/ru_RU.ISO8859-5/tcsh.cat
OLD_DIRS+=usr/share/nls/ru_RU.KOI8-R
OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/ee.cat
OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/libc.cat
OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/tcsh.cat
OLD_DIRS+=usr/share/nls/ru_RU.UTF-8
OLD_FILES+=usr/share/nls/ru_RU.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/sk_SK.ISO8859-2
OLD_FILES+=usr/share/nls/sk_SK.ISO8859-2/libc.cat
OLD_DIRS+=usr/share/nls/sk_SK.UTF-8
OLD_DIRS+=usr/share/nls/sl_SI.ISO8859-2
OLD_DIRS+=usr/share/nls/sl_SI.UTF-8
OLD_DIRS+=usr/share/nls/sr_YU.ISO8859-2
OLD_DIRS+=usr/share/nls/sr_YU.ISO8859-5
OLD_DIRS+=usr/share/nls/sr_YU.UTF-8
OLD_DIRS+=usr/share/nls/sv_SE.ISO8859-1
OLD_FILES+=usr/share/nls/sv_SE.ISO8859-1/libc.cat
OLD_DIRS+=usr/share/nls/sv_SE.ISO8859-15
OLD_DIRS+=usr/share/nls/sv_SE.UTF-8
OLD_DIRS+=usr/share/nls/tr_TR.ISO8859-9
OLD_DIRS+=usr/share/nls/tr_TR.UTF-8
OLD_DIRS+=usr/share/nls/uk_UA.ISO8859-5
OLD_FILES+=usr/share/nls/uk_UA.ISO8859-5/tcsh.cat
OLD_DIRS+=usr/share/nls/uk_UA.KOI8-U
OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/ee.cat
OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/tcsh.cat
OLD_DIRS+=usr/share/nls/uk_UA.UTF-8
OLD_FILES+=usr/share/nls/uk_UA.UTF-8/libc.cat
OLD_FILES+=usr/share/nls/uk_UA.UTF-8/tcsh.cat
OLD_DIRS+=usr/share/nls/zh_CN.GB18030
OLD_FILES+=usr/share/nls/zh_CN.GB18030/libc.cat
OLD_DIRS+=usr/share/nls/zh_CN.GBK
OLD_DIRS+=usr/share/nls/zh_CN.GB2312
OLD_FILES+=usr/share/nls/zh_CN.GB2312/libc.cat
OLD_DIRS+=usr/share/nls/zh_CN.UTF-8
OLD_FILES+=usr/share/nls/zh_CN.UTF-8/libc.cat
OLD_DIRS+=usr/share/nls/zh_CN.eucCN
OLD_DIRS+=usr/share/nls/zh_HK.UTF-8
OLD_DIRS+=usr/share/nls/zh_TW.UTF-8
OLD_FILES+=usr/tests/bin/sh/builtins/locale1.0
.endif
.if ${MK_NLS_CATALOGS} == no
OLD_FILES+=usr/share/nls/de_AT.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/de_CH.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/de_DE.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/el_GR.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/es_ES.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/et_EE.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/fi_FI.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/fr_BE.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/fr_CA.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/fr_CH.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/fr_FR.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/it_CH.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/it_IT.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/ja_JP.SJIS/tcsh.cat
OLD_FILES+=usr/share/nls/ja_JP.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/ru_RU.CP1251/tcsh.cat
OLD_FILES+=usr/share/nls/ru_RU.CP866/tcsh.cat
OLD_FILES+=usr/share/nls/ru_RU.ISO8859-5/tcsh.cat
OLD_FILES+=usr/share/nls/ru_RU.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/uk_UA.ISO8859-5/tcsh.cat
OLD_FILES+=usr/share/nls/uk_UA.UTF-8/tcsh.cat
.endif
.if ${MK_NS_CACHING} == no
OLD_FILES+=etc/nscd.conf
OLD_FILES+=etc/rc.d/nscd
OLD_FILES+=usr/sbin/nscd
OLD_FILES+=usr/share/examples/etc/nscd.conf
OLD_FILES+=usr/share/man/man5/nscd.conf.5.gz
OLD_FILES+=usr/share/man/man8/nscd.8.gz
.endif
.if ${MK_NTP} == no
OLD_FILES+=etc/ntp/leap-seconds
OLD_DIRS+=etc/ntp
OLD_FILES+=etc/ntp.conf
OLD_FILES+=etc/periodic/daily/480.status-ntpd
OLD_FILES+=etc/periodic/daily/480.leapfile-ntpd
OLD_FILES+=etc/rc.d/ntpd
OLD_FILES+=usr/bin/ntpq
OLD_FILES+=usr/sbin/ntp-keygen
OLD_FILES+=usr/sbin/ntpd
OLD_FILES+=usr/sbin/ntpdate
OLD_FILES+=usr/sbin/ntpdc
OLD_FILES+=usr/sbin/ntptime
OLD_FILES+=usr/sbin/sntp
OLD_FILES+=usr/share/doc/ntp/access.html
OLD_FILES+=usr/share/doc/ntp/accopt.html
OLD_FILES+=usr/share/doc/ntp/assoc.html
OLD_FILES+=usr/share/doc/ntp/audio.html
OLD_FILES+=usr/share/doc/ntp/authentic.html
OLD_FILES+=usr/share/doc/ntp/authopt.html
OLD_FILES+=usr/share/doc/ntp/autokey.html
OLD_FILES+=usr/share/doc/ntp/bugs.html
OLD_FILES+=usr/share/doc/ntp/build.html
OLD_FILES+=usr/share/doc/ntp/clock.html
OLD_FILES+=usr/share/doc/ntp/clockopt.html
OLD_FILES+=usr/share/doc/ntp/cluster.html
OLD_FILES+=usr/share/doc/ntp/comdex.html
OLD_FILES+=usr/share/doc/ntp/config.html
OLD_FILES+=usr/share/doc/ntp/confopt.html
OLD_FILES+=usr/share/doc/ntp/copyright.html
OLD_FILES+=usr/share/doc/ntp/debug.html
OLD_FILES+=usr/share/doc/ntp/decode.html
OLD_FILES+=usr/share/doc/ntp/discipline.html
OLD_FILES+=usr/share/doc/ntp/discover.html
OLD_FILES+=usr/share/doc/ntp/driver1.html
OLD_FILES+=usr/share/doc/ntp/driver10.html
OLD_FILES+=usr/share/doc/ntp/driver11.html
OLD_FILES+=usr/share/doc/ntp/driver12.html
OLD_FILES+=usr/share/doc/ntp/driver16.html
OLD_FILES+=usr/share/doc/ntp/driver18.html
OLD_FILES+=usr/share/doc/ntp/driver19.html
OLD_FILES+=usr/share/doc/ntp/driver2.html
OLD_FILES+=usr/share/doc/ntp/driver20.html
OLD_FILES+=usr/share/doc/ntp/driver22.html
OLD_FILES+=usr/share/doc/ntp/driver26.html
OLD_FILES+=usr/share/doc/ntp/driver27.html
OLD_FILES+=usr/share/doc/ntp/driver28.html
OLD_FILES+=usr/share/doc/ntp/driver29.html
OLD_FILES+=usr/share/doc/ntp/driver3.html
OLD_FILES+=usr/share/doc/ntp/driver30.html
OLD_FILES+=usr/share/doc/ntp/driver32.html
OLD_FILES+=usr/share/doc/ntp/driver33.html
OLD_FILES+=usr/share/doc/ntp/driver34.html
OLD_FILES+=usr/share/doc/ntp/driver35.html
OLD_FILES+=usr/share/doc/ntp/driver36.html
OLD_FILES+=usr/share/doc/ntp/driver37.html
OLD_FILES+=usr/share/doc/ntp/driver4.html
OLD_FILES+=usr/share/doc/ntp/driver5.html
OLD_FILES+=usr/share/doc/ntp/driver6.html
OLD_FILES+=usr/share/doc/ntp/driver7.html
OLD_FILES+=usr/share/doc/ntp/driver8.html
OLD_FILES+=usr/share/doc/ntp/driver9.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver1.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver10.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver11.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver12.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver16.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver18.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver19.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver20.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver22.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver26.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver27.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver28.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver29.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver3.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver30.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver31.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver32.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver33.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver34.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver35.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver36.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver37.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver38.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver39.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver4.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver40.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver42.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver43.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver44.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver45.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver46.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver5.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver6.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver7.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver8.html
OLD_FILES+=usr/share/doc/ntp/drivers/driver9.html
OLD_FILES+=usr/share/doc/ntp/drivers/icons/home.gif
OLD_FILES+=usr/share/doc/ntp/drivers/icons/mail2.gif
OLD_FILES+=usr/share/doc/ntp/drivers/mx4200data.html
OLD_FILES+=usr/share/doc/ntp/drivers/oncore-shmem.html
OLD_FILES+=usr/share/doc/ntp/drivers/scripts/footer.txt
OLD_FILES+=usr/share/doc/ntp/drivers/scripts/style.css
OLD_FILES+=usr/share/doc/ntp/drivers/tf582_4.html
OLD_FILES+=usr/share/doc/ntp/extern.html
OLD_FILES+=usr/share/doc/ntp/filter.html
OLD_FILES+=usr/share/doc/ntp/hints.html
OLD_FILES+=usr/share/doc/ntp/hints/a-ux
OLD_FILES+=usr/share/doc/ntp/hints/aix
OLD_FILES+=usr/share/doc/ntp/hints/bsdi
OLD_FILES+=usr/share/doc/ntp/hints/changes
OLD_FILES+=usr/share/doc/ntp/hints/decosf1
OLD_FILES+=usr/share/doc/ntp/hints/decosf2
OLD_FILES+=usr/share/doc/ntp/hints/freebsd
OLD_FILES+=usr/share/doc/ntp/hints/hpux
OLD_FILES+=usr/share/doc/ntp/hints/linux
OLD_FILES+=usr/share/doc/ntp/hints/mpeix
OLD_FILES+=usr/share/doc/ntp/hints/notes-xntp-v3
OLD_FILES+=usr/share/doc/ntp/hints/parse
OLD_FILES+=usr/share/doc/ntp/hints/refclocks
OLD_FILES+=usr/share/doc/ntp/hints/rs6000
OLD_FILES+=usr/share/doc/ntp/hints/sco.html
OLD_FILES+=usr/share/doc/ntp/hints/sgi
OLD_FILES+=usr/share/doc/ntp/hints/solaris-dosynctodr.html
OLD_FILES+=usr/share/doc/ntp/hints/solaris.html
OLD_FILES+=usr/share/doc/ntp/hints/solaris.xtra.4023118
OLD_FILES+=usr/share/doc/ntp/hints/solaris.xtra.4095849
OLD_FILES+=usr/share/doc/ntp/hints/solaris.xtra.S99ntpd
OLD_FILES+=usr/share/doc/ntp/hints/solaris.xtra.patchfreq
OLD_FILES+=usr/share/doc/ntp/hints/sun4
OLD_FILES+=usr/share/doc/ntp/hints/svr4-dell
OLD_FILES+=usr/share/doc/ntp/hints/svr4_package
OLD_FILES+=usr/share/doc/ntp/hints/todo
OLD_FILES+=usr/share/doc/ntp/hints/vxworks.html
OLD_FILES+=usr/share/doc/ntp/hints/winnt.html
OLD_FILES+=usr/share/doc/ntp/history.html
OLD_FILES+=usr/share/doc/ntp/howto.html
OLD_FILES+=usr/share/doc/ntp/huffpuff.html
OLD_FILES+=usr/share/doc/ntp/icons/home.gif
OLD_FILES+=usr/share/doc/ntp/icons/mail2.gif
OLD_FILES+=usr/share/doc/ntp/icons/sitemap.png
OLD_FILES+=usr/share/doc/ntp/index.html
OLD_FILES+=usr/share/doc/ntp/kern.html
OLD_FILES+=usr/share/doc/ntp/kernpps.html
OLD_FILES+=usr/share/doc/ntp/keygen.html
OLD_FILES+=usr/share/doc/ntp/ldisc.html
OLD_FILES+=usr/share/doc/ntp/leap.html
OLD_FILES+=usr/share/doc/ntp/measure.html
OLD_FILES+=usr/share/doc/ntp/miscopt.html
OLD_FILES+=usr/share/doc/ntp/monopt.html
OLD_FILES+=usr/share/doc/ntp/msyslog.html
OLD_FILES+=usr/share/doc/ntp/mx4200data.html
OLD_FILES+=usr/share/doc/ntp/notes.html
OLD_FILES+=usr/share/doc/ntp/ntp-keygen.html
OLD_FILES+=usr/share/doc/ntp/ntp-wait.html
OLD_FILES+=usr/share/doc/ntp/ntp.conf.html
OLD_FILES+=usr/share/doc/ntp/ntp.keys.html
OLD_FILES+=usr/share/doc/ntp/ntp_conf.html
OLD_FILES+=usr/share/doc/ntp/ntpd.html
OLD_FILES+=usr/share/doc/ntp/ntpdate.html
OLD_FILES+=usr/share/doc/ntp/ntpdc.html
OLD_FILES+=usr/share/doc/ntp/ntpdsim.html
OLD_FILES+=usr/share/doc/ntp/ntpdsim_new.html
OLD_FILES+=usr/share/doc/ntp/ntpq.html
OLD_FILES+=usr/share/doc/ntp/ntpsnmpd.html
OLD_FILES+=usr/share/doc/ntp/ntptime.html
OLD_FILES+=usr/share/doc/ntp/ntptrace.html
OLD_FILES+=usr/share/doc/ntp/orphan.html
OLD_FILES+=usr/share/doc/ntp/parsedata.html
OLD_FILES+=usr/share/doc/ntp/parsenew.html
OLD_FILES+=usr/share/doc/ntp/patches.html
OLD_FILES+=usr/share/doc/ntp/pic/9400n.jpg
OLD_FILES+=usr/share/doc/ntp/pic/alice11.gif
OLD_FILES+=usr/share/doc/ntp/pic/alice13.gif
OLD_FILES+=usr/share/doc/ntp/pic/alice15.gif
OLD_FILES+=usr/share/doc/ntp/pic/alice23.gif
OLD_FILES+=usr/share/doc/ntp/pic/alice31.gif
OLD_FILES+=usr/share/doc/ntp/pic/alice32.gif
OLD_FILES+=usr/share/doc/ntp/pic/alice35.gif
OLD_FILES+=usr/share/doc/ntp/pic/alice38.gif
OLD_FILES+=usr/share/doc/ntp/pic/alice44.gif
OLD_FILES+=usr/share/doc/ntp/pic/alice47.gif
OLD_FILES+=usr/share/doc/ntp/pic/alice51.gif
OLD_FILES+=usr/share/doc/ntp/pic/alice61.gif
OLD_FILES+=usr/share/doc/ntp/pic/barnstable.gif
OLD_FILES+=usr/share/doc/ntp/pic/beaver.gif
OLD_FILES+=usr/share/doc/ntp/pic/boom3.gif
OLD_FILES+=usr/share/doc/ntp/pic/boom3a.gif
OLD_FILES+=usr/share/doc/ntp/pic/boom4.gif
OLD_FILES+=usr/share/doc/ntp/pic/broad.gif
OLD_FILES+=usr/share/doc/ntp/pic/bustardfly.gif
OLD_FILES+=usr/share/doc/ntp/pic/c51.jpg
OLD_FILES+=usr/share/doc/ntp/pic/description.jpg
OLD_FILES+=usr/share/doc/ntp/pic/discipline.gif
OLD_FILES+=usr/share/doc/ntp/pic/dogsnake.gif
OLD_FILES+=usr/share/doc/ntp/pic/driver29.gif
OLD_FILES+=usr/share/doc/ntp/pic/driver43_1.gif
OLD_FILES+=usr/share/doc/ntp/pic/driver43_2.jpg
OLD_FILES+=usr/share/doc/ntp/pic/fg6021.gif
OLD_FILES+=usr/share/doc/ntp/pic/fg6039.jpg
OLD_FILES+=usr/share/doc/ntp/pic/fig_3_1.gif
OLD_FILES+=usr/share/doc/ntp/pic/flatheads.gif
OLD_FILES+=usr/share/doc/ntp/pic/flt1.gif
OLD_FILES+=usr/share/doc/ntp/pic/flt2.gif
OLD_FILES+=usr/share/doc/ntp/pic/flt3.gif
OLD_FILES+=usr/share/doc/ntp/pic/flt4.gif
OLD_FILES+=usr/share/doc/ntp/pic/flt5.gif
OLD_FILES+=usr/share/doc/ntp/pic/flt6.gif
OLD_FILES+=usr/share/doc/ntp/pic/flt7.gif
OLD_FILES+=usr/share/doc/ntp/pic/flt8.gif
OLD_FILES+=usr/share/doc/ntp/pic/flt9.gif
OLD_FILES+=usr/share/doc/ntp/pic/freq1211.gif
OLD_FILES+=usr/share/doc/ntp/pic/gadget.jpg
OLD_FILES+=usr/share/doc/ntp/pic/gps167.jpg
OLD_FILES+=usr/share/doc/ntp/pic/group.gif
OLD_FILES+=usr/share/doc/ntp/pic/hornraba.gif
OLD_FILES+=usr/share/doc/ntp/pic/igclock.gif
OLD_FILES+=usr/share/doc/ntp/pic/neoclock4x.gif
OLD_FILES+=usr/share/doc/ntp/pic/offset1211.gif
OLD_FILES+=usr/share/doc/ntp/pic/oncore_evalbig.gif
OLD_FILES+=usr/share/doc/ntp/pic/oncore_remoteant.jpg
OLD_FILES+=usr/share/doc/ntp/pic/oncore_utplusbig.gif
OLD_FILES+=usr/share/doc/ntp/pic/oz2.gif
OLD_FILES+=usr/share/doc/ntp/pic/panda.gif
OLD_FILES+=usr/share/doc/ntp/pic/pd_om006.gif
OLD_FILES+=usr/share/doc/ntp/pic/pd_om011.gif
OLD_FILES+=usr/share/doc/ntp/pic/peer.gif
OLD_FILES+=usr/share/doc/ntp/pic/pogo.gif
OLD_FILES+=usr/share/doc/ntp/pic/pogo1a.gif
OLD_FILES+=usr/share/doc/ntp/pic/pogo3a.gif
OLD_FILES+=usr/share/doc/ntp/pic/pogo4.gif
OLD_FILES+=usr/share/doc/ntp/pic/pogo5.gif
OLD_FILES+=usr/share/doc/ntp/pic/pogo6.gif
OLD_FILES+=usr/share/doc/ntp/pic/pogo7.gif
OLD_FILES+=usr/share/doc/ntp/pic/pogo8.gif
OLD_FILES+=usr/share/doc/ntp/pic/pzf509.jpg
OLD_FILES+=usr/share/doc/ntp/pic/pzf511.jpg
OLD_FILES+=usr/share/doc/ntp/pic/rabbit.gif
OLD_FILES+=usr/share/doc/ntp/pic/radio2.jpg
OLD_FILES+=usr/share/doc/ntp/pic/sheepb.jpg
OLD_FILES+=usr/share/doc/ntp/pic/stack1a.jpg
OLD_FILES+=usr/share/doc/ntp/pic/stats.gif
OLD_FILES+=usr/share/doc/ntp/pic/sx5.gif
OLD_FILES+=usr/share/doc/ntp/pic/thunderbolt.jpg
OLD_FILES+=usr/share/doc/ntp/pic/time1.gif
OLD_FILES+=usr/share/doc/ntp/pic/tonea.gif
OLD_FILES+=usr/share/doc/ntp/pic/tribeb.gif
OLD_FILES+=usr/share/doc/ntp/pic/wingdorothy.gif
OLD_FILES+=usr/share/doc/ntp/poll.html
OLD_FILES+=usr/share/doc/ntp/porting.html
OLD_FILES+=usr/share/doc/ntp/pps.html
OLD_FILES+=usr/share/doc/ntp/prefer.html
OLD_FILES+=usr/share/doc/ntp/quick.html
OLD_FILES+=usr/share/doc/ntp/rate.html
OLD_FILES+=usr/share/doc/ntp/rdebug.html
OLD_FILES+=usr/share/doc/ntp/refclock.html
OLD_FILES+=usr/share/doc/ntp/release.html
OLD_FILES+=usr/share/doc/ntp/scripts/accopt.txt
OLD_FILES+=usr/share/doc/ntp/scripts/audio.txt
OLD_FILES+=usr/share/doc/ntp/scripts/authopt.txt
OLD_FILES+=usr/share/doc/ntp/scripts/clockopt.txt
OLD_FILES+=usr/share/doc/ntp/scripts/command.txt
OLD_FILES+=usr/share/doc/ntp/scripts/config.txt
OLD_FILES+=usr/share/doc/ntp/scripts/confopt.txt
OLD_FILES+=usr/share/doc/ntp/scripts/external.txt
OLD_FILES+=usr/share/doc/ntp/scripts/footer.txt
OLD_FILES+=usr/share/doc/ntp/scripts/hand.txt
OLD_FILES+=usr/share/doc/ntp/scripts/install.txt
OLD_FILES+=usr/share/doc/ntp/scripts/manual.txt
OLD_FILES+=usr/share/doc/ntp/scripts/misc.txt
OLD_FILES+=usr/share/doc/ntp/scripts/miscopt.txt
OLD_FILES+=usr/share/doc/ntp/scripts/monopt.txt
OLD_FILES+=usr/share/doc/ntp/scripts/refclock.txt
OLD_FILES+=usr/share/doc/ntp/scripts/special.txt
OLD_FILES+=usr/share/doc/ntp/scripts/style.css
OLD_FILES+=usr/share/doc/ntp/select.html
OLD_FILES+=usr/share/doc/ntp/sitemap.html
OLD_FILES+=usr/share/doc/ntp/sntp.html
OLD_FILES+=usr/share/doc/ntp/stats.html
OLD_FILES+=usr/share/doc/ntp/tickadj.html
OLD_FILES+=usr/share/doc/ntp/warp.html
OLD_FILES+=usr/share/doc/ntp/xleave.html
OLD_DIRS+=usr/share/doc/ntp/drivers
OLD_DIRS+=usr/share/doc/ntp/drivers/scripts
OLD_DIRS+=usr/share/doc/ntp/drivers/icons
OLD_DIRS+=usr/share/doc/ntp/hints
OLD_DIRS+=usr/share/doc/ntp/icons
OLD_DIRS+=usr/share/doc/ntp/pic
OLD_DIRS+=usr/share/doc/ntp/scripts
OLD_DIRS+=usr/share/doc/ntp
OLD_FILES+=usr/share/examples/etc/ntp.conf
OLD_FILES+=usr/share/man/man1/sntp.1.gz
OLD_FILES+=usr/share/man/man5/ntp.conf.5.gz
OLD_FILES+=usr/share/man/man5/ntp.keys.5.gz
OLD_FILES+=usr/share/man/man8/ntp-keygen.8.gz
OLD_FILES+=usr/share/man/man8/ntpd.8.gz
OLD_FILES+=usr/share/man/man8/ntpdate.8.gz
OLD_FILES+=usr/share/man/man8/ntpdc.8.gz
OLD_FILES+=usr/share/man/man8/ntpq.8.gz
OLD_FILES+=usr/share/man/man8/ntptime.8.gz
.endif
.if ${MK_OFED} == no
OLD_FILES+=etc/newsyslog.conf.d/opensm.conf
OLD_FILES+=etc/rc.d/opensm
OLD_FILES+=usr/bin/ibstat
OLD_FILES+=usr/bin/ibv_asyncwatch
OLD_FILES+=usr/bin/ibv_devices
OLD_FILES+=usr/bin/ibv_devinfo
OLD_FILES+=usr/bin/ibv_rc_pingpong
OLD_FILES+=usr/bin/ibv_srq_pingpong
OLD_FILES+=usr/bin/ibv_uc_pingpong
OLD_FILES+=usr/bin/ibv_ud_pingpong
OLD_FILES+=usr/bin/mckey
OLD_FILES+=usr/bin/rping
OLD_FILES+=usr/bin/ucmatose
OLD_FILES+=usr/bin/udaddy
OLD_FILES+=usr/include/infiniband/marshall.h
OLD_FILES+=usr/include/infiniband/kern-abi.h
OLD_FILES+=usr/include/infiniband/umad_sm.h
OLD_FILES+=usr/include/infiniband/umad.h
OLD_FILES+=usr/include/infiniband/arch.h
OLD_FILES+=usr/include/infiniband/verbs.h
OLD_FILES+=usr/include/infiniband/ib.h
OLD_FILES+=usr/include/infiniband/cm.h
OLD_FILES+=usr/include/infiniband/opcode.h
OLD_FILES+=usr/include/infiniband/ibnetdisc.h
OLD_FILES+=usr/include/infiniband/driver.h
OLD_FILES+=usr/include/infiniband/mad_osd.h
OLD_FILES+=usr/include/infiniband/umad_types.h
OLD_FILES+=usr/include/infiniband/umad_cm.h
OLD_FILES+=usr/include/infiniband/cm_abi.h
OLD_FILES+=usr/include/infiniband/sa-kern-abi.h
OLD_FILES+=usr/include/infiniband/ibnetdisc_osd.h
OLD_FILES+=usr/include/infiniband/opensm/osm_event_plugin.h
OLD_FILES+=usr/include/infiniband/opensm/osm_console_io.h
OLD_FILES+=usr/include/infiniband/opensm/osm_ucast_cache.h
OLD_FILES+=usr/include/infiniband/opensm/osm_port.h
OLD_FILES+=usr/include/infiniband/opensm/osm_path.h
OLD_FILES+=usr/include/infiniband/opensm/osm_mtree.h
OLD_FILES+=usr/include/infiniband/opensm/osm_log.h
OLD_FILES+=usr/include/infiniband/opensm/osm_mcm_port.h
OLD_FILES+=usr/include/infiniband/opensm/osm_subnet.h
OLD_FILES+=usr/include/infiniband/opensm/osm_pkey.h
OLD_FILES+=usr/include/infiniband/opensm/osm_remote_sm.h
OLD_FILES+=usr/include/infiniband/opensm/osm_qos_policy.h
OLD_FILES+=usr/include/infiniband/opensm/osm_sm.h
OLD_FILES+=usr/include/infiniband/opensm/osm_node.h
OLD_FILES+=usr/include/infiniband/opensm/osm_mcast_mgr.h
OLD_FILES+=usr/include/infiniband/opensm/osm_madw.h
OLD_FILES+=usr/include/infiniband/opensm/osm_lid_mgr.h
OLD_FILES+=usr/include/infiniband/opensm/osm_congestion_control.h
OLD_FILES+=usr/include/infiniband/opensm/osm_port_profile.h
OLD_FILES+=usr/include/infiniband/opensm/osm_perfmgr.h
OLD_FILES+=usr/include/infiniband/opensm/osm_service.h
OLD_FILES+=usr/include/infiniband/opensm/osm_base.h
OLD_FILES+=usr/include/infiniband/opensm/osm_vl15intf.h
OLD_FILES+=usr/include/infiniband/opensm/st.h
OLD_FILES+=usr/include/infiniband/opensm/osm_attrib_req.h
OLD_FILES+=usr/include/infiniband/opensm/osm_ucast_mgr.h
OLD_FILES+=usr/include/infiniband/opensm/osm_db.h
OLD_FILES+=usr/include/infiniband/opensm/osm_sa_mad_ctrl.h
OLD_FILES+=usr/include/infiniband/opensm/osm_db_pack.h
OLD_FILES+=usr/include/infiniband/opensm/osm_opensm.h
OLD_FILES+=usr/include/infiniband/opensm/osm_mesh.h
OLD_FILES+=usr/include/infiniband/opensm/osm_mcast_tbl.h
OLD_FILES+=usr/include/infiniband/opensm/osm_sm_mad_ctrl.h
OLD_FILES+=usr/include/infiniband/opensm/osm_stats.h
OLD_FILES+=usr/include/infiniband/opensm/osm_mad_pool.h
OLD_FILES+=usr/include/infiniband/opensm/osm_switch.h
OLD_FILES+=usr/include/infiniband/opensm/osm_ucast_lash.h
OLD_FILES+=usr/include/infiniband/opensm/osm_errors.h
OLD_FILES+=usr/include/infiniband/opensm/osm_partition.h
OLD_FILES+=usr/include/infiniband/opensm/osm_prefix_route.h
OLD_FILES+=usr/include/infiniband/opensm/osm_helper.h
OLD_FILES+=usr/include/infiniband/opensm/osm_version.h
OLD_FILES+=usr/include/infiniband/opensm/osm_sa.h
OLD_FILES+=usr/include/infiniband/opensm/osm_config.h
OLD_FILES+=usr/include/infiniband/opensm/osm_multicast.h
OLD_FILES+=usr/include/infiniband/opensm/osm_file_ids.h
OLD_FILES+=usr/include/infiniband/opensm/osm_perfmgr_db.h
OLD_FILES+=usr/include/infiniband/opensm/osm_console.h
OLD_FILES+=usr/include/infiniband/opensm/osm_msgdef.h
OLD_FILES+=usr/include/infiniband/opensm/osm_router.h
OLD_FILES+=usr/include/infiniband/opensm/osm_guid.h
OLD_FILES+=usr/include/infiniband/opensm/osm_inform.h
OLD_DIRS+=usr/include/infiniband/opensm
OLD_FILES+=usr/include/infiniband/iba/ib_types.h
OLD_FILES+=usr/include/infiniband/iba/ib_cm_types.h
OLD_DIRS+=usr/include/infiniband/iba
OLD_FILES+=usr/include/infiniband/umad_str.h
OLD_FILES+=usr/include/infiniband/udma_barrier.h
OLD_FILES+=usr/include/infiniband/umad_sa.h
OLD_FILES+=usr/include/infiniband/mad.h
OLD_FILES+=usr/include/infiniband/sa.h
OLD_FILES+=usr/include/infiniband/byteorder.h
OLD_FILES+=usr/include/infiniband/types.h
OLD_FILES+=usr/include/infiniband/byteswap.h
OLD_FILES+=usr/include/infiniband/vendor/osm_pkt_randomizer.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_rmpp_ctx.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mtl_hca_guid.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_txn.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_svc.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_test.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_inout.h
OLD_FILES+=usr/include/infiniband/vendor/osm_mtl_bind.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_hca.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_sa_api.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_sender.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor.h
OLD_FILES+=usr/include/infiniband/vendor/osm_umadt.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mtl_transaction_mgr.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_defs.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_dispatcher.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_api.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mtl.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_transport.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_al.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_sar.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_umadt.h
OLD_FILES+=usr/include/infiniband/vendor/osm_ts_useraccess.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_ts.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_transport_anafa.h
OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_ibumad.h
OLD_DIRS+=usr/include/infiniband/vendor
OLD_FILES+=usr/include/infiniband/endian.h
OLD_FILES+=usr/include/infiniband/complib/cl_byteswap.h
OLD_FILES+=usr/include/infiniband/complib/cl_types.h
OLD_FILES+=usr/include/infiniband/complib/cl_map.h
OLD_FILES+=usr/include/infiniband/complib/cl_packon.h
OLD_FILES+=usr/include/infiniband/complib/cl_timer.h
OLD_FILES+=usr/include/infiniband/complib/cl_thread_osd.h
OLD_FILES+=usr/include/infiniband/complib/cl_thread.h
OLD_FILES+=usr/include/infiniband/complib/cl_event.h
OLD_FILES+=usr/include/infiniband/complib/cl_byteswap_osd.h
OLD_FILES+=usr/include/infiniband/complib/cl_passivelock.h
OLD_FILES+=usr/include/infiniband/complib/cl_vector.h
OLD_FILES+=usr/include/infiniband/complib/cl_nodenamemap.h
OLD_FILES+=usr/include/infiniband/complib/cl_event_wheel.h
OLD_FILES+=usr/include/infiniband/complib/cl_log.h
OLD_FILES+=usr/include/infiniband/complib/cl_fleximap.h
OLD_FILES+=usr/include/infiniband/complib/cl_qlist.h
OLD_FILES+=usr/include/infiniband/complib/cl_timer_osd.h
OLD_FILES+=usr/include/infiniband/complib/cl_pool.h
OLD_FILES+=usr/include/infiniband/complib/cl_debug.h
OLD_FILES+=usr/include/infiniband/complib/cl_types_osd.h
OLD_FILES+=usr/include/infiniband/complib/cl_dispatcher.h
OLD_FILES+=usr/include/infiniband/complib/cl_ptr_vector.h
OLD_FILES+=usr/include/infiniband/complib/cl_atomic_osd.h
OLD_FILES+=usr/include/infiniband/complib/cl_qmap.h
OLD_FILES+=usr/include/infiniband/complib/cl_spinlock_osd.h
OLD_FILES+=usr/include/infiniband/complib/cl_qcomppool.h
OLD_FILES+=usr/include/infiniband/complib/cl_threadpool.h
OLD_FILES+=usr/include/infiniband/complib/cl_list.h
OLD_FILES+=usr/include/infiniband/complib/cl_debug_osd.h
OLD_FILES+=usr/include/infiniband/complib/cl_packoff.h
OLD_FILES+=usr/include/infiniband/complib/cl_qpool.h
OLD_FILES+=usr/include/infiniband/complib/cl_spinlock.h
OLD_FILES+=usr/include/infiniband/complib/cl_event_osd.h
OLD_FILES+=usr/include/infiniband/complib/cl_atomic.h
OLD_FILES+=usr/include/infiniband/complib/cl_math.h
OLD_FILES+=usr/include/infiniband/complib/cl_comppool.h
OLD_DIRS+=usr/include/infiniband/complib
OLD_DIRS+=usr/include/infiniband
OLD_FILES+=usr/lib/libcxgb4.a
OLD_FILES+=usr/lib/libcxgb4.so
OLD_LIBS+=usr/lib/libcxgb4.so.1
OLD_FILES+=usr/lib/libibcm.a
OLD_FILES+=usr/lib/libibcm.so
OLD_LIBS+=usr/lib/libibcm.so.1
OLD_FILES+=usr/lib/libibmad.a
OLD_FILES+=usr/lib/libibmad.so
OLD_LIBS+=usr/lib/libibmad.so.5
OLD_FILES+=usr/lib/libibnetdisc.a
OLD_FILES+=usr/lib/libibnetdisc.so
OLD_LIBS+=usr/lib/libibnetdisc.so.5
OLD_FILES+=usr/lib/libibumad.a
OLD_FILES+=usr/lib/libibumad.so
OLD_LIBS+=usr/lib/libibumad.so.1
OLD_FILES+=usr/lib/libibverbs.a
OLD_FILES+=usr/lib/libibverbs.so
OLD_LIBS+=lib/libibverbs.so.1
OLD_FILES+=usr/lib/libmlx4.a
OLD_FILES+=usr/lib/libmlx4.so
OLD_LIBS+=usr/lib/libmlx4.so.1
OLD_FILES+=usr/lib/libmlx5.a
OLD_FILES+=usr/lib/libmlx5.so
OLD_LIBS+=lib/libmlx5.so.1
OLD_FILES+=usr/lib/libopensm.a
OLD_FILES+=usr/lib/libopensm.so
OLD_LIBS+=usr/lib/libopensm.so.5
OLD_FILES+=usr/lib/libosmcomp.a
OLD_FILES+=usr/lib/libosmcomp.so
OLD_LIBS+=usr/lib/libosmcomp.so.3
OLD_FILES+=usr/lib/libosmvendor.a
OLD_FILES+=usr/lib/libosmvendor.so
OLD_LIBS+=usr/lib/libosmvendor.so.4
OLD_FILES+=usr/lib/librdmacm.a
OLD_FILES+=usr/lib/librdmacm.so
OLD_LIBS+=usr/lib/librdmacm.so.1
OLD_FILES+=usr/share/man/man1/ibv_asyncwatch.1.gz
OLD_FILES+=usr/share/man/man1/ibv_devices.1.gz
OLD_FILES+=usr/share/man/man1/ibv_devinfo.1.gz
OLD_FILES+=usr/share/man/man1/ibv_rc_pingpong.1.gz
OLD_FILES+=usr/share/man/man1/ibv_srq_pingpong.1.gz
OLD_FILES+=usr/share/man/man1/ibv_uc_pingpong.1.gz
OLD_FILES+=usr/share/man/man1/ibv_ud_pingpong.1.gz
OLD_FILES+=usr/share/man/man1/mckey.1.gz
OLD_FILES+=usr/share/man/man1/rping.1.gz
OLD_FILES+=usr/share/man/man1/ucmatose.1.gz
OLD_FILES+=usr/share/man/man1/udaddy.1.gz
OLD_FILES+=usr/share/man/man3/ibnd_debug.3.gz
OLD_FILES+=usr/share/man/man3/ibnd_destroy_fabric.3.gz
OLD_FILES+=usr/share/man/man3/ibnd_discover_fabric.3.gz
OLD_FILES+=usr/share/man/man3/ibnd_find_node_dr.3.gz
OLD_FILES+=usr/share/man/man3/ibnd_find_node_guid.3.gz
OLD_FILES+=usr/share/man/man3/ibnd_iter_nodes.3.gz
OLD_FILES+=usr/share/man/man3/ibnd_iter_nodes_type.3.gz
OLD_FILES+=usr/share/man/man3/ibnd_show_progress.3.gz
OLD_FILES+=usr/share/man/man3/ibv_alloc_mw.3.gz
OLD_FILES+=usr/share/man/man3/ibv_alloc_pd.3.gz
OLD_FILES+=usr/share/man/man3/ibv_attach_mcast.3.gz
OLD_FILES+=usr/share/man/man3/ibv_bind_mw.3.gz
OLD_FILES+=usr/share/man/man3/ibv_create_ah.3.gz
OLD_FILES+=usr/share/man/man3/ibv_create_ah_from_wc.3.gz
OLD_FILES+=usr/share/man/man3/ibv_create_comp_channel.3.gz
OLD_FILES+=usr/share/man/man3/ibv_create_cq.3.gz
OLD_FILES+=usr/share/man/man3/ibv_create_cq_ex.3.gz
OLD_FILES+=usr/share/man/man3/ibv_create_flow.3.gz
OLD_FILES+=usr/share/man/man3/ibv_create_qp.3.gz
OLD_FILES+=usr/share/man/man3/ibv_create_qp_ex.3.gz
OLD_FILES+=usr/share/man/man3/ibv_create_rwq_ind_table.3.gz
OLD_FILES+=usr/share/man/man3/ibv_create_srq.3.gz
OLD_FILES+=usr/share/man/man3/ibv_create_srq_ex.3.gz
OLD_FILES+=usr/share/man/man3/ibv_create_wq.3.gz
OLD_FILES+=usr/share/man/man3/ibv_event_type_str.3.gz
OLD_FILES+=usr/share/man/man3/ibv_fork_init.3.gz
OLD_FILES+=usr/share/man/man3/ibv_get_async_event.3.gz
OLD_FILES+=usr/share/man/man3/ibv_get_cq_event.3.gz
OLD_FILES+=usr/share/man/man3/ibv_get_device_guid.3.gz
OLD_FILES+=usr/share/man/man3/ibv_get_device_list.3.gz
OLD_FILES+=usr/share/man/man3/ibv_get_device_name.3.gz
OLD_FILES+=usr/share/man/man3/ibv_get_srq_num.3.gz
OLD_FILES+=usr/share/man/man3/ibv_inc_rkey.3.gz
OLD_FILES+=usr/share/man/man3/ibv_modify_qp.3.gz
OLD_FILES+=usr/share/man/man3/ibv_modify_srq.3.gz
OLD_FILES+=usr/share/man/man3/ibv_modify_wq.3.gz
OLD_FILES+=usr/share/man/man3/ibv_open_device.3.gz
OLD_FILES+=usr/share/man/man3/ibv_open_qp.3.gz
OLD_FILES+=usr/share/man/man3/ibv_open_xrcd.3.gz
OLD_FILES+=usr/share/man/man3/ibv_poll_cq.3.gz
OLD_FILES+=usr/share/man/man3/ibv_post_recv.3.gz
OLD_FILES+=usr/share/man/man3/ibv_post_send.3.gz
OLD_FILES+=usr/share/man/man3/ibv_post_srq_recv.3.gz
OLD_FILES+=usr/share/man/man3/ibv_query_device.3.gz
OLD_FILES+=usr/share/man/man3/ibv_query_device_ex.3.gz
OLD_FILES+=usr/share/man/man3/ibv_query_gid.3.gz
OLD_FILES+=usr/share/man/man3/ibv_query_pkey.3.gz
OLD_FILES+=usr/share/man/man3/ibv_query_port.3.gz
OLD_FILES+=usr/share/man/man3/ibv_query_qp.3.gz
OLD_FILES+=usr/share/man/man3/ibv_query_rt_values_ex.3.gz
OLD_FILES+=usr/share/man/man3/ibv_query_srq.3.gz
OLD_FILES+=usr/share/man/man3/ibv_rate_to_mbps.3.gz
OLD_FILES+=usr/share/man/man3/ibv_rate_to_mult.3.gz
OLD_FILES+=usr/share/man/man3/ibv_reg_mr.3.gz
OLD_FILES+=usr/share/man/man3/ibv_req_notify_cq.3.gz
OLD_FILES+=usr/share/man/man3/ibv_rereg_mr.3.gz
OLD_FILES+=usr/share/man/man3/ibv_resize_cq.3.gz
OLD_FILES+=usr/share/man/man3/rdma_accept.3.gz
OLD_FILES+=usr/share/man/man3/rdma_ack_cm_event.3.gz
OLD_FILES+=usr/share/man/man3/rdma_bind_addr.3.gz
OLD_FILES+=usr/share/man/man3/rdma_connect.3.gz
OLD_FILES+=usr/share/man/man3/rdma_create_ep.3.gz
OLD_FILES+=usr/share/man/man3/rdma_create_event_channel.3.gz
OLD_FILES+=usr/share/man/man3/rdma_create_id.3.gz
OLD_FILES+=usr/share/man/man3/rdma_create_qp.3.gz
OLD_FILES+=usr/share/man/man3/rdma_create_srq.3.gz
OLD_FILES+=usr/share/man/man3/rdma_dereg_mr.3.gz
OLD_FILES+=usr/share/man/man3/rdma_destroy_ep.3.gz
OLD_FILES+=usr/share/man/man3/rdma_destroy_event_channel.3.gz
OLD_FILES+=usr/share/man/man3/rdma_destroy_id.3.gz
OLD_FILES+=usr/share/man/man3/rdma_destroy_qp.3.gz
OLD_FILES+=usr/share/man/man3/rdma_destroy_srq.3.gz
OLD_FILES+=usr/share/man/man3/rdma_disconnect.3.gz
OLD_FILES+=usr/share/man/man3/rdma_event_str.3.gz
OLD_FILES+=usr/share/man/man3/rdma_free_devices.3.gz
OLD_FILES+=usr/share/man/man3/rdma_get_cm_event.3.gz
OLD_FILES+=usr/share/man/man3/rdma_get_devices.3.gz
OLD_FILES+=usr/share/man/man3/rdma_get_dst_port.3.gz
OLD_FILES+=usr/share/man/man3/rdma_get_local_addr.3.gz
OLD_FILES+=usr/share/man/man3/rdma_get_peer_addr.3.gz
OLD_FILES+=usr/share/man/man3/rdma_get_recv_comp.3.gz
OLD_FILES+=usr/share/man/man3/rdma_get_request.3.gz
OLD_FILES+=usr/share/man/man3/rdma_get_send_comp.3.gz
OLD_FILES+=usr/share/man/man3/rdma_get_src_port.3.gz
OLD_FILES+=usr/share/man/man3/rdma_getaddrinfo.3.gz
OLD_FILES+=usr/share/man/man3/rdma_join_multicast.3.gz
OLD_FILES+=usr/share/man/man3/rdma_leave_multicast.3.gz
OLD_FILES+=usr/share/man/man3/rdma_listen.3.gz
OLD_FILES+=usr/share/man/man3/rdma_migrate_id.3.gz
OLD_FILES+=usr/share/man/man3/rdma_notify.3.gz
OLD_FILES+=usr/share/man/man3/rdma_post_read.3.gz
OLD_FILES+=usr/share/man/man3/rdma_post_readv.3.gz
OLD_FILES+=usr/share/man/man3/rdma_post_recv.3.gz
OLD_FILES+=usr/share/man/man3/rdma_post_recvv.3.gz
OLD_FILES+=usr/share/man/man3/rdma_post_send.3.gz
OLD_FILES+=usr/share/man/man3/rdma_post_sendv.3.gz
OLD_FILES+=usr/share/man/man3/rdma_post_ud_send.3.gz
OLD_FILES+=usr/share/man/man3/rdma_post_write.3.gz
OLD_FILES+=usr/share/man/man3/rdma_post_writev.3.gz
OLD_FILES+=usr/share/man/man3/rdma_reg_msgs.3.gz
OLD_FILES+=usr/share/man/man3/rdma_reg_read.3.gz
OLD_FILES+=usr/share/man/man3/rdma_reg_write.3.gz
OLD_FILES+=usr/share/man/man3/rdma_reject.3.gz
OLD_FILES+=usr/share/man/man3/rdma_resolve_addr.3.gz
OLD_FILES+=usr/share/man/man3/rdma_resolve_route.3.gz
OLD_FILES+=usr/share/man/man3/rdma_set_option.3.gz
OLD_FILES+=usr/share/man/man4/mlx4ib.4.gz
OLD_FILES+=usr/share/man/man4/mlx5ib.4.gz
OLD_FILES+=usr/share/man/man8/ibstat.8.gz
.endif
.if ${MK_OFED_EXTRA} == no
OLD_FILES+=usr/bin/dump_fts
OLD_FILES+=usr/bin/ibaddr
OLD_FILES+=usr/bin/ibcacheedit
OLD_FILES+=usr/bin/ibccconfig
OLD_FILES+=usr/bin/ibccquery
OLD_FILES+=usr/bin/iblinkinfo
OLD_FILES+=usr/bin/ibmirror
OLD_FILES+=usr/bin/ibnetdiscover
OLD_FILES+=usr/bin/ibping
OLD_FILES+=usr/bin/ibportstate
OLD_FILES+=usr/bin/ibqueryerrors
OLD_FILES+=usr/bin/ibroute
OLD_FILES+=usr/bin/ibsysstat
OLD_FILES+=usr/bin/ibtracert
OLD_FILES+=usr/bin/opensm
OLD_FILES+=usr/bin/perfquery
OLD_FILES+=usr/bin/saquery
OLD_FILES+=usr/bin/sminfo
OLD_FILES+=usr/bin/smpdump
OLD_FILES+=usr/bin/smpquery
OLD_FILES+=usr/bin/vendstat
OLD_FILES+=usr/share/man/man8/dump_fts.8.gz
OLD_FILES+=usr/share/man/man8/ibaddr.8.gz
OLD_FILES+=usr/share/man/man8/ibcacheedit.8.gz
OLD_FILES+=usr/share/man/man8/ibccconfig.8.gz
OLD_FILES+=usr/share/man/man8/ibccquery.8.gz
OLD_FILES+=usr/share/man/man8/iblinkinfo.8.gz
OLD_FILES+=usr/share/man/man8/ibnetdiscover.8.gz
OLD_FILES+=usr/share/man/man8/ibping.8.gz
OLD_FILES+=usr/share/man/man8/ibportstate.8.gz
OLD_FILES+=usr/share/man/man8/ibqueryerrors.8.gz
OLD_FILES+=usr/share/man/man8/ibroute.8.gz
OLD_FILES+=usr/share/man/man8/ibsysstat.8.gz
OLD_FILES+=usr/share/man/man8/ibtracert.8.gz
OLD_FILES+=usr/share/man/man8/opensm.8.gz
OLD_FILES+=usr/share/man/man8/perfquery.8.gz
OLD_FILES+=usr/share/man/man8/saquery.8.gz
OLD_FILES+=usr/share/man/man8/sminfo.8.gz
OLD_FILES+=usr/share/man/man8/smpdump.8.gz
OLD_FILES+=usr/share/man/man8/smpquery.8.gz
OLD_FILES+=usr/share/man/man8/vendstat.8.gz
.endif
.if ${MK_OPENMP} == no
OLD_FILES+=usr/include/omp.h
OLD_FILES+=usr/lib/libgomp.so
OLD_LIBS+=usr/lib/libomp.so
.endif
.if ${MK_OPENSSH} == no
OLD_FILES+=etc/rc.d/sshd
OLD_FILES+=etc/ssh/moduli
OLD_FILES+=etc/ssh/ssh_config
OLD_FILES+=etc/ssh/sshd_config
OLD_DIRS+=etc/ssh
OLD_FILES+=usr/bin/scp
OLD_FILES+=usr/bin/sftp
OLD_FILES+=usr/bin/slogin
OLD_FILES+=usr/bin/ssh
OLD_FILES+=usr/bin/ssh-add
OLD_FILES+=usr/bin/ssh-agent
OLD_FILES+=usr/bin/ssh-copy-id
OLD_FILES+=usr/bin/ssh-keygen
OLD_FILES+=usr/bin/ssh-keyscan
OLD_FILES+=usr/lib/libprivatecbor.a
OLD_FILES+=usr/lib/libprivatecbor.so
OLD_LIBS+=usr/lib/libprivatecbor.so.5
OLD_FILES+=/usr/lib/libprivatefido2.a
OLD_FILES+=/usr/lib/libprivatefido2.so
OLD_LIBS+=/usr/lib/libprivatefido2.so.5
OLD_FILES+=usr/lib/pam_ssh.so
OLD_LIBS+=usr/lib/pam_ssh.so.6
OLD_FILES+=usr/lib/libprivatessh.a
OLD_FILES+=usr/lib/libprivatessh.so
OLD_LIBS+=usr/lib/libprivatessh.so.5
OLD_FILES+=usr/lib/libprivatessh_p.a
OLD_FILES+=usr/libexec/sftp-server
OLD_FILES+=usr/libexec/ssh-keysign
OLD_FILES+=usr/libexec/ssh-pkcs11-helper
OLD_FILES+=usr/libexec/ssh-sk-helper
OLD_FILES+=usr/sbin/sshd
OLD_FILES+=usr/share/man/man1/scp.1.gz
OLD_FILES+=usr/share/man/man1/sftp.1.gz
OLD_FILES+=usr/share/man/man1/slogin.1.gz
OLD_FILES+=usr/share/man/man1/ssh-add.1.gz
OLD_FILES+=usr/share/man/man1/ssh-agent.1.gz
OLD_FILES+=usr/share/man/man1/ssh-copy-id.1.gz
OLD_FILES+=usr/share/man/man1/ssh-keygen.1.gz
OLD_FILES+=usr/share/man/man1/ssh-keyscan.1.gz
OLD_FILES+=usr/share/man/man1/ssh.1.gz
OLD_FILES+=usr/share/man/man5/ssh_config.5.gz
OLD_FILES+=usr/share/man/man5/sshd_config.5.gz
OLD_FILES+=usr/share/man/man8/pam_ssh.8.gz
OLD_FILES+=usr/share/man/man8/sftp-server.8.gz
OLD_FILES+=usr/share/man/man8/ssh-keysign.8.gz
OLD_FILES+=usr/share/man/man8/ssh-pkcs11-helper.8.gz
OLD_FILES+=usr/share/man/man8/ssh-sk-helper.8.gz
OLD_FILES+=usr/share/man/man8/sshd.8.gz
.endif
.if ${MK_OPENSSL} == no
OLD_FILES+=etc/rc.d/keyserv
.endif
.if ${MK_PF} == no
OLD_FILES+=etc/newsyslog.conf.d/pf.conf
OLD_FILES+=etc/periodic/security/520.pfdenied
OLD_FILES+=etc/pf.os
OLD_FILES+=etc/rc.d/ftp-proxy
OLD_FILES+=sbin/pfctl
OLD_FILES+=sbin/pflogd
OLD_FILES+=usr/include/netpfil/pf/pf.h
OLD_FILES+=usr/include/netpfil/pf/pf_altq.h
OLD_FILES+=usr/include/netpfil/pf/pf_mtag.h
OLD_FILES+=usr/lib/snmp_pf.so
OLD_LIBS+=usr/lib/snmp_pf.so.6
OLD_FILES+=usr/libexec/tftp-proxy
OLD_FILES+=usr/sbin/ftp-proxy
OLD_FILES+=usr/share/examples/etc/pf.os
OLD_FILES+=usr/share/examples/pf/ackpri
OLD_FILES+=usr/share/examples/pf/faq-example1
OLD_FILES+=usr/share/examples/pf/faq-example2
OLD_FILES+=usr/share/examples/pf/faq-example3
OLD_FILES+=usr/share/examples/pf/pf.conf
OLD_FILES+=usr/share/examples/pf/queue1
OLD_FILES+=usr/share/examples/pf/queue2
OLD_FILES+=usr/share/examples/pf/queue3
OLD_FILES+=usr/share/examples/pf/queue4
OLD_FILES+=usr/share/examples/pf/spamd
OLD_DIRS+=usr/share/examples/pf
OLD_FILES+=usr/share/man/man4/pf.4.gz
OLD_FILES+=usr/share/man/man4/pflog.4.gz
OLD_FILES+=usr/share/man/man4/pfsync.4.gz
OLD_FILES+=usr/share/man/man5/pf.conf.5.gz
OLD_FILES+=usr/share/man/man5/pf.os.5.gz
OLD_FILES+=usr/share/man/man8/ftp-proxy.8.gz
OLD_FILES+=usr/share/man/man8/pfctl.8.gz
OLD_FILES+=usr/share/man/man8/pflogd.8.gz
OLD_FILES+=usr/share/man/man8/tftp-proxy.8.gz
OLD_FILES+=usr/share/snmp/defs/pf_tree.def
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-PF-MIB.txt
.endif
.if ${MK_PKGBOOTSTRAP} == no
OLD_FILES+=usr/sbin/pkg
OLD_FILES+=usr/share/man/man7/pkg.7.gz
.endif
.if ${MK_PMC} == no
OLD_FILES+=usr/bin/pmcstudy
.if ${TARGET_ARCH} == "amd64"
OLD_FILES+=usr/include/libipt/pt_last_ip.h
OLD_FILES+=usr/include/libipt/intel-pt.h
OLD_FILES+=usr/include/libipt/pt_time.h
OLD_FILES+=usr/include/libipt/pt_cpu.h
OLD_FILES+=usr/include/libipt/pt_compiler.h
OLD_DIRS+=usr/include/libipt
.endif
.if ${TARGET_ARCH} == "aarch64"
OLD_FILES+=usr/include/opencsd/c_api/opencsd_c_api.h
OLD_FILES+=usr/include/opencsd/c_api/ocsd_c_api_cust_impl.h
OLD_FILES+=usr/include/opencsd/c_api/ocsd_c_api_types.h
OLD_FILES+=usr/include/opencsd/c_api/ocsd_c_api_cust_fact.h
OLD_FILES+=usr/include/opencsd/c_api/ocsd_c_api_custom.h
OLD_DIRS+=usr/include/opencsd/c_api
OLD_FILES+=usr/include/opencsd/ocsd_if_types.h
OLD_FILES+=usr/include/opencsd/ptm/trc_dcd_mngr_ptm.h
OLD_FILES+=usr/include/opencsd/ptm/trc_pkt_proc_ptm.h
OLD_FILES+=usr/include/opencsd/ptm/trc_cmp_cfg_ptm.h
OLD_FILES+=usr/include/opencsd/ptm/ptm_decoder.h
OLD_FILES+=usr/include/opencsd/ptm/trc_pkt_elem_ptm.h
OLD_FILES+=usr/include/opencsd/ptm/trc_pkt_decode_ptm.h
OLD_FILES+=usr/include/opencsd/ptm/trc_pkt_types_ptm.h
OLD_DIRS+=usr/include/opencsd/ptm
OLD_FILES+=usr/include/opencsd/trc_gen_elem_types.h
OLD_FILES+=usr/include/opencsd/etmv4/trc_pkt_proc_etmv4.h
OLD_FILES+=usr/include/opencsd/etmv4/trc_etmv4_stack_elem.h
OLD_FILES+=usr/include/opencsd/etmv4/etmv4_decoder.h
OLD_FILES+=usr/include/opencsd/etmv4/trc_pkt_elem_etmv4i.h
OLD_FILES+=usr/include/opencsd/etmv4/trc_dcd_mngr_etmv4i.h
OLD_FILES+=usr/include/opencsd/etmv4/trc_pkt_types_etmv4.h
OLD_FILES+=usr/include/opencsd/etmv4/trc_pkt_elem_etmv4d.h
OLD_FILES+=usr/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h
OLD_FILES+=usr/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h
OLD_DIRS+=usr/include/opencsd/etmv4
OLD_FILES+=usr/include/opencsd/etmv3/trc_pkt_decode_etmv3.h
OLD_FILES+=usr/include/opencsd/etmv3/trc_cmp_cfg_etmv3.h
OLD_FILES+=usr/include/opencsd/etmv3/etmv3_decoder.h
OLD_FILES+=usr/include/opencsd/etmv3/trc_pkt_proc_etmv3.h
OLD_FILES+=usr/include/opencsd/etmv3/trc_pkt_elem_etmv3.h
OLD_FILES+=usr/include/opencsd/etmv3/trc_pkt_types_etmv3.h
OLD_FILES+=usr/include/opencsd/etmv3/trc_dcd_mngr_etmv3.h
OLD_DIRS+=usr/include/opencsd/etmv3
OLD_FILES+=usr/include/opencsd/trc_pkt_types.h
OLD_FILES+=usr/include/opencsd/stm/trc_pkt_proc_stm.h
OLD_FILES+=usr/include/opencsd/stm/trc_pkt_types_stm.h
OLD_FILES+=usr/include/opencsd/stm/stm_decoder.h
OLD_FILES+=usr/include/opencsd/stm/trc_dcd_mngr_stm.h
OLD_FILES+=usr/include/opencsd/stm/trc_cmp_cfg_stm.h
OLD_FILES+=usr/include/opencsd/stm/trc_pkt_elem_stm.h
OLD_FILES+=usr/include/opencsd/stm/trc_pkt_decode_stm.h
OLD_DIRS+=usr/include/opencsd/stm
OLD_DIRS+=usr/include/opencsd
.endif
OLD_FILES+=usr/include/pmc.h
OLD_FILES+=usr/include/pmclog.h
OLD_FILES+=usr/include/pmcformat.h
OLD_FILES+=usr/include/libpmcstat.h
.if ${TARGET_ARCH} == "amd64"
OLD_FILES+=usr/lib/libipt.a
OLD_FILES+=usr/lib/libipt.so
OLD_LIBS+=lib/libipt.so.0
OLD_FILES+=usr/lib/libipt_p.a
.endif
.if ${TARGET_ARCH} == "aarch64"
OLD_FILES+=usr/lib/libopencsd.a
OLD_FILES+=usr/lib/libopencsd.so
OLD_LIBS+=lib/libopencsd.so.0
OLD_FILES+=usr/lib/libopencsd_p.a
.endif
OLD_FILES+=usr/lib/libpmc.a
OLD_FILES+=usr/lib/libpmc.so
OLD_LIBS+=usr/lib/libpmc.so.5
OLD_FILES+=usr/lib/libpmc_p.a
OLD_FILES+=usr/sbin/pmc
OLD_FILES+=usr/sbin/pmcannotate
OLD_FILES+=usr/sbin/pmccontrol
OLD_FILES+=usr/sbin/pmcstat
OLD_FILES+=usr/share/man/man3/pmc.3.gz
OLD_FILES+=usr/share/man/man3/pmc.atom.3.gz
OLD_FILES+=usr/share/man/man3/pmc.atomsilvermont.3.gz
OLD_FILES+=usr/share/man/man3/pmc.core.3.gz
OLD_FILES+=usr/share/man/man3/pmc.core2.3.gz
OLD_FILES+=usr/share/man/man3/pmc.corei7.3.gz
OLD_FILES+=usr/share/man/man3/pmc.corei7uc.3.gz
OLD_FILES+=usr/share/man/man3/pmc.haswell.3.gz
OLD_FILES+=usr/share/man/man3/pmc.haswelluc.3.gz
OLD_FILES+=usr/share/man/man3/pmc.haswellxeon.3.gz
OLD_FILES+=usr/share/man/man3/pmc.iaf.3.gz
OLD_FILES+=usr/share/man/man3/pmc.ivybridge.3.gz
OLD_FILES+=usr/share/man/man3/pmc.ivybridgexeon.3.gz
OLD_FILES+=usr/share/man/man3/pmc.k7.3.gz
OLD_FILES+=usr/share/man/man3/pmc.k8.3.gz
OLD_FILES+=usr/share/man/man3/pmc.mips24k.3.gz
OLD_FILES+=usr/share/man/man3/pmc.octeon.3.gz
OLD_FILES+=usr/share/man/man3/pmc.p4.3.gz
OLD_FILES+=usr/share/man/man3/pmc.p5.3.gz
OLD_FILES+=usr/share/man/man3/pmc.p6.3.gz
OLD_FILES+=usr/share/man/man3/pmc.sandybridge.3.gz
OLD_FILES+=usr/share/man/man3/pmc.sandybridgeuc.3.gz
OLD_FILES+=usr/share/man/man3/pmc.sandybridgexeon.3.gz
OLD_FILES+=usr/share/man/man3/pmc.soft.3.gz
OLD_FILES+=usr/share/man/man3/pmc.tsc.3.gz
OLD_FILES+=usr/share/man/man3/pmc.ucf.3.gz
OLD_FILES+=usr/share/man/man3/pmc.westmere.3.gz
OLD_FILES+=usr/share/man/man3/pmc.westmereuc.3.gz
OLD_FILES+=usr/share/man/man3/pmc.xscale.3.gz
OLD_FILES+=usr/share/man/man3/pmc_allocate.3.gz
OLD_FILES+=usr/share/man/man3/pmc_attach.3.gz
OLD_FILES+=usr/share/man/man3/pmc_capabilities.3.gz
OLD_FILES+=usr/share/man/man3/pmc_configure_logfile.3.gz
OLD_FILES+=usr/share/man/man3/pmc_cpuinfo.3.gz
OLD_FILES+=usr/share/man/man3/pmc_detach.3.gz
OLD_FILES+=usr/share/man/man3/pmc_disable.3.gz
OLD_FILES+=usr/share/man/man3/pmc_enable.3.gz
OLD_FILES+=usr/share/man/man3/pmc_event_names_of_class.3.gz
OLD_FILES+=usr/share/man/man3/pmc_flush_logfile.3.gz
OLD_FILES+=usr/share/man/man3/pmc_get_driver_stats.3.gz
OLD_FILES+=usr/share/man/man3/pmc_get_msr.3.gz
OLD_FILES+=usr/share/man/man3/pmc_init.3.gz
OLD_FILES+=usr/share/man/man3/pmc_name_of_capability.3.gz
OLD_FILES+=usr/share/man/man3/pmc_name_of_class.3.gz
OLD_FILES+=usr/share/man/man3/pmc_name_of_cputype.3.gz
OLD_FILES+=usr/share/man/man3/pmc_name_of_disposition.3.gz
OLD_FILES+=usr/share/man/man3/pmc_name_of_event.3.gz
OLD_FILES+=usr/share/man/man3/pmc_name_of_mode.3.gz
OLD_FILES+=usr/share/man/man3/pmc_name_of_state.3.gz
OLD_FILES+=usr/share/man/man3/pmc_ncpu.3.gz
OLD_FILES+=usr/share/man/man3/pmc_npmc.3.gz
OLD_FILES+=usr/share/man/man3/pmc_pmcinfo.3.gz
OLD_FILES+=usr/share/man/man3/pmc_read.3.gz
OLD_FILES+=usr/share/man/man3/pmc_release.3.gz
OLD_FILES+=usr/share/man/man3/pmc_rw.3.gz
OLD_FILES+=usr/share/man/man3/pmc_set.3.gz
OLD_FILES+=usr/share/man/man3/pmc_start.3.gz
OLD_FILES+=usr/share/man/man3/pmc_stop.3.gz
OLD_FILES+=usr/share/man/man3/pmc_width.3.gz
OLD_FILES+=usr/share/man/man3/pmc_write.3.gz
OLD_FILES+=usr/share/man/man3/pmc_writelog.3.gz
OLD_FILES+=usr/share/man/man3/pmclog.3.gz
OLD_FILES+=usr/share/man/man3/pmclog_close.3.gz
OLD_FILES+=usr/share/man/man3/pmclog_feed.3.gz
OLD_FILES+=usr/share/man/man3/pmclog_open.3.gz
OLD_FILES+=usr/share/man/man3/pmclog_read.3.gz
OLD_FILES+=usr/share/man/man8/pmcannotate.8.gz
OLD_FILES+=usr/share/man/man8/pmccontrol.8.gz
OLD_FILES+=usr/share/man/man8/pmcstat.8.gz
OLD_FILES+=usr/share/man/man8/pmcstudy.8.gz
.endif
.if ${MK_PORTSNAP} == no
OLD_FILES+=etc/portsnap.conf
OLD_FILES+=usr/libexec/make_index
OLD_FILES+=usr/sbin/portsnap
OLD_FILES+=usr/share/examples/etc/portsnap.conf
OLD_FILES+=usr/share/man/man8/portsnap.8.gz
.endif
.if ${MK_PPP} == no
OLD_FILES+=etc/newsyslog.conf.d/ppp.conf
OLD_FILES+=etc/ppp/ppp.conf
OLD_FILES+=etc/syslog.d/ppp.conf
OLD_DIRS+=etc/ppp
OLD_FILES+=usr/sbin/ppp
OLD_FILES+=usr/sbin/pppctl
OLD_FILES+=usr/share/man/man8/ppp.8.gz
OLD_FILES+=usr/share/man/man8/pppctl.8.gz
.endif
.if ${MK_PROFILE} == no
OLD_FILES+=usr/lib/lib80211_p.a
OLD_FILES+=usr/lib/lib9p_p.a
OLD_FILES+=usr/lib/libBlocksRuntime_p.a
OLD_FILES+=usr/lib/libalias_dummy_p.a
OLD_FILES+=usr/lib/libalias_ftp_p.a
OLD_FILES+=usr/lib/libalias_irc_p.a
OLD_FILES+=usr/lib/libalias_nbt_p.a
OLD_FILES+=usr/lib/libalias_p.a
OLD_FILES+=usr/lib/libalias_pptp_p.a
OLD_FILES+=usr/lib/libalias_skinny_p.a
OLD_FILES+=usr/lib/libalias_smedia_p.a
OLD_FILES+=usr/lib/libarchive_p.a
OLD_FILES+=usr/lib/libasn1_p.a
OLD_FILES+=usr/lib/libauditd_p.a
OLD_FILES+=usr/lib/libavl_p.a
OLD_FILES+=usr/lib/libbe_p.a
OLD_FILES+=usr/lib/libbegemot_p.a
OLD_FILES+=usr/lib/libblacklist_p.a
OLD_FILES+=usr/lib/libbluetooth_p.a
OLD_FILES+=usr/lib/libbsdxml_p.a
OLD_FILES+=usr/lib/libbsm_p.a
OLD_FILES+=usr/lib/libbsnmp_p.a
OLD_FILES+=usr/lib/libbz2_p.a
OLD_FILES+=usr/lib/libc++_p.a
OLD_FILES+=usr/lib/libc_p.a
OLD_FILES+=usr/lib/libcalendar_p.a
OLD_FILES+=usr/lib/libcam_p.a
OLD_FILES+=usr/lib/libcom_err_p.a
OLD_FILES+=usr/lib/libcompat_p.a
OLD_FILES+=usr/lib/libcompiler_rt_p.a
OLD_FILES+=usr/lib/libcrypt_p.a
OLD_FILES+=usr/lib/libcrypto_p.a
OLD_FILES+=usr/lib/libctf_p.a
OLD_FILES+=usr/lib/libcurses_p.a
OLD_FILES+=usr/lib/libcursesw_p.a
OLD_FILES+=usr/lib/libcuse_p.a
OLD_FILES+=usr/lib/libcxxrt_p.a
OLD_FILES+=usr/lib/libdevctl_p.a
OLD_FILES+=usr/lib/libdevinfo_p.a
OLD_FILES+=usr/lib/libdevstat_p.a
OLD_FILES+=usr/lib/libdialog_p.a
OLD_FILES+=usr/lib/libdl_p.a
OLD_FILES+=usr/lib/libdpv_p.a
OLD_FILES+=usr/lib/libdtrace_p.a
OLD_FILES+=usr/lib/libdwarf_p.a
OLD_FILES+=usr/lib/libedit_p.a
OLD_FILES+=usr/lib/libefivar_p.a
OLD_FILES+=usr/lib/libelf_p.a
OLD_FILES+=usr/lib/libexecinfo_p.a
OLD_FILES+=usr/lib/libfetch_p.a
OLD_FILES+=usr/lib/libfigpar_p.a
OLD_FILES+=usr/lib/libfl_p.a
OLD_FILES+=usr/lib/libform_p.a
OLD_FILES+=usr/lib/libformw_p.a
OLD_FILES+=usr/lib/libgcc_eh_p.a
OLD_FILES+=usr/lib/libgcc_p.a
OLD_FILES+=usr/lib/libgeom_p.a
OLD_FILES+=usr/lib/libgpio_p.a
OLD_FILES+=usr/lib/libgssapi_krb5_p.a
OLD_FILES+=usr/lib/libgssapi_ntlm_p.a
OLD_FILES+=usr/lib/libgssapi_p.a
OLD_FILES+=usr/lib/libgssapi_spnego_p.a
OLD_FILES+=usr/lib/libhdb_p.a
OLD_FILES+=usr/lib/libheimbase_p.a
OLD_FILES+=usr/lib/libheimntlm_p.a
OLD_FILES+=usr/lib/libheimsqlite_p.a
OLD_FILES+=usr/lib/libhistory_p.a
OLD_FILES+=usr/lib/libhx509_p.a
OLD_FILES+=usr/lib/libicp_p.a
OLD_FILES+=usr/lib/libicp_rescue_p.a
OLD_FILES+=usr/lib/libipsec_p.a
OLD_FILES+=usr/lib/libipt_p.a
OLD_FILES+=usr/lib/libjail_p.a
OLD_FILES+=usr/lib/libkadm5clnt_p.a
OLD_FILES+=usr/lib/libkadm5srv_p.a
OLD_FILES+=usr/lib/libkafs5_p.a
OLD_FILES+=usr/lib/libkdc_p.a
OLD_FILES+=usr/lib/libkiconv_p.a
OLD_FILES+=usr/lib/libkrb5_p.a
OLD_FILES+=usr/lib/libkvm_p.a
OLD_FILES+=usr/lib/libl_p.a
OLD_FILES+=usr/lib/libln_p.a
OLD_FILES+=usr/lib/liblzma_p.a
OLD_FILES+=usr/lib/libm_p.a
OLD_FILES+=usr/lib/libmagic_p.a
OLD_FILES+=usr/lib/libmd_p.a
OLD_FILES+=usr/lib/libmemstat_p.a
OLD_FILES+=usr/lib/libmenu_p.a
OLD_FILES+=usr/lib/libmenuw_p.a
OLD_FILES+=usr/lib/libmilter_p.a
OLD_FILES+=usr/lib/libmp_p.a
OLD_FILES+=usr/lib/libmt_p.a
OLD_FILES+=usr/lib/libncurses_p.a
OLD_FILES+=usr/lib/libncursesw_p.a
OLD_FILES+=usr/lib/libnetgraph_p.a
OLD_FILES+=usr/lib/libnetmap_p.a
OLD_FILES+=usr/lib/libngatm_p.a
OLD_FILES+=usr/lib/libnv_p.a
OLD_FILES+=usr/lib/libnvpair_p.a
OLD_FILES+=usr/lib/libopencsd_p.a
OLD_FILES+=usr/lib/libopie_p.a
OLD_FILES+=usr/lib/libpanel_p.a
OLD_FILES+=usr/lib/libpanelw_p.a
OLD_FILES+=usr/lib/libpathconv_p.a
OLD_FILES+=usr/lib/libpcap_p.a
OLD_FILES+=usr/lib/libpjdlog_p.a
OLD_FILES+=usr/lib/libpmc_p.a
OLD_FILES+=usr/lib/libprivateatf-c++_p.a
OLD_FILES+=usr/lib/libprivateatf-c_p.a
OLD_FILES+=usr/lib/libprivateauditd_p.a
OLD_FILES+=usr/lib/libprivatebsdstat_p.a
OLD_FILES+=usr/lib/libprivatedevdctl_p.a
OLD_FILES+=usr/lib/libprivateevent_p.a
OLD_FILES+=usr/lib/libprivateevent1_p.a
OLD_FILES+=usr/lib/libprivategmock_main_p.a
OLD_FILES+=usr/lib/libprivategmock_p.a
OLD_FILES+=usr/lib/libprivategtest_main_p.a
OLD_FILES+=usr/lib/libprivategtest_p.a
OLD_FILES+=usr/lib/libprivateheimipcc_p.a
OLD_FILES+=usr/lib/libprivateheimipcs_p.a
OLD_FILES+=usr/lib/libprivateifconfig_p.a
OLD_FILES+=usr/lib/libprivateldns_p.a
OLD_FILES+=usr/lib/libprivatesqlite3_p.a
OLD_FILES+=usr/lib/libprivatessh_p.a
OLD_FILES+=usr/lib/libprivateucl_p.a
OLD_FILES+=usr/lib/libprivateunbound_p.a
OLD_FILES+=usr/lib/libprivatezstd_p.a
OLD_FILES+=usr/lib/libproc_p.a
OLD_FILES+=usr/lib/libprocstat_p.a
OLD_FILES+=usr/lib/libpthread_p.a
OLD_FILES+=usr/lib/libradius_p.a
OLD_FILES+=usr/lib/libregex_p.a
OLD_FILES+=usr/lib/libroken_p.a
OLD_FILES+=usr/lib/librpcsvc_p.a
OLD_FILES+=usr/lib/librss_p.a
OLD_FILES+=usr/lib/librt_p.a
OLD_FILES+=usr/lib/librtld_db_p.a
OLD_FILES+=usr/lib/libsbuf_p.a
OLD_FILES+=usr/lib/libsdp_p.a
OLD_FILES+=usr/lib/libsmb_p.a
OLD_FILES+=usr/lib/libspl_p.a
OLD_FILES+=usr/lib/libssl_p.a
OLD_FILES+=usr/lib/libstats_p.a
OLD_FILES+=usr/lib/libstdbuf_p.a
OLD_FILES+=usr/lib/libstdc++_p.a
OLD_FILES+=usr/lib/libstdthreads_p.a
OLD_FILES+=usr/lib/libsupc++_p.a
OLD_FILES+=usr/lib/libsysdecode_p.a
OLD_FILES+=usr/lib/libtacplus_p.a
OLD_FILES+=usr/lib/libtermcap_p.a
OLD_FILES+=usr/lib/libtermcapw_p.a
OLD_FILES+=usr/lib/libtermlib_p.a
OLD_FILES+=usr/lib/libtermlibw_p.a
OLD_FILES+=usr/lib/libthr_p.a
OLD_FILES+=usr/lib/libthread_db_p.a
OLD_FILES+=usr/lib/libtinfo_p.a
OLD_FILES+=usr/lib/libtinfow_p.a
OLD_FILES+=usr/lib/libtpool_p.a
OLD_FILES+=usr/lib/libufs_p.a
OLD_FILES+=usr/lib/libugidfw_p.a
OLD_FILES+=usr/lib/libulog_p.a
OLD_FILES+=usr/lib/libumem_p.a
OLD_FILES+=usr/lib/libusb_p.a
OLD_FILES+=usr/lib/libusbhid_p.a
OLD_FILES+=usr/lib/libutempter_p.a
OLD_FILES+=usr/lib/libutil_p.a
OLD_FILES+=usr/lib/libuutil_p.a
OLD_FILES+=usr/lib/libvgl_p.a
OLD_FILES+=usr/lib/libvmmapi_p.a
OLD_FILES+=usr/lib/libwind_p.a
OLD_FILES+=usr/lib/libwrap_p.a
OLD_FILES+=usr/lib/libxo_p.a
OLD_FILES+=usr/lib/liby_p.a
OLD_FILES+=usr/lib/libypclnt_p.a
OLD_FILES+=usr/lib/libz_p.a
OLD_FILES+=usr/lib/libzfs_core_p.a
OLD_FILES+=usr/lib/libzfs_p.a
OLD_FILES+=usr/lib/libzfsbootenv_p.a
OLD_FILES+=usr/lib/libzutil_p.a
.endif
.if ${MK_QUOTAS} == no
OLD_FILES+=sbin/quotacheck
OLD_FILES+=usr/bin/quota
OLD_FILES+=usr/sbin/edquota
OLD_FILES+=usr/sbin/quotaoff
OLD_FILES+=usr/sbin/quotaon
OLD_FILES+=usr/sbin/repquota
OLD_FILES+=usr/share/man/man1/quota.1.gz
OLD_FILES+=usr/share/man/man8/edquota.8.gz
OLD_FILES+=usr/share/man/man8/quotacheck.8.gz
OLD_FILES+=usr/share/man/man8/quotaoff.8.gz
OLD_FILES+=usr/share/man/man8/quotaon.8.gz
OLD_FILES+=usr/share/man/man8/repquota.8.gz
.endif
.if ${MK_RADIUS_SUPPORT} == no
OLD_FILES+=usr/lib/libradius.a
OLD_FILES+=usr/lib/libradius.so
OLD_LIBS+=usr/lib/libradius.so.4
OLD_FILES+=usr/lib/libradius_p.a
OLD_FILES+=usr/lib/pam_radius.so
OLD_LIBS+=usr/lib/pam_radius.so.6
OLD_FILES+=usr/include/radlib.h
OLD_FILES+=usr/include/radlib_vs.h
OLD_FILES+=usr/share/man/man3/libradius.3.gz
OLD_FILES+=usr/share/man/man3/rad_acct_open.3.gz
OLD_FILES+=usr/share/man/man3/rad_add_server.3.gz
OLD_FILES+=usr/share/man/man3/rad_add_server_ex.3.gz
OLD_FILES+=usr/share/man/man3/rad_auth_open.3.gz
OLD_FILES+=usr/share/man/man3/rad_bind_to.3.gz
OLD_FILES+=usr/share/man/man3/rad_close.3.gz
OLD_FILES+=usr/share/man/man3/rad_config.3.gz
OLD_FILES+=usr/share/man/man3/rad_continue_send_request.3.gz
OLD_FILES+=usr/share/man/man3/rad_create_request.3.gz
OLD_FILES+=usr/share/man/man3/rad_create_response.3.gz
OLD_FILES+=usr/share/man/man3/rad_cvt_addr.3.gz
OLD_FILES+=usr/share/man/man3/rad_cvt_int.3.gz
OLD_FILES+=usr/share/man/man3/rad_cvt_string.3.gz
OLD_FILES+=usr/share/man/man3/rad_demangle.3.gz
OLD_FILES+=usr/share/man/man3/rad_demangle_mppe_key.3.gz
OLD_FILES+=usr/share/man/man3/rad_get_attr.3.gz
OLD_FILES+=usr/share/man/man3/rad_get_vendor_attr.3.gz
OLD_FILES+=usr/share/man/man3/rad_init_send_request.3.gz
OLD_FILES+=usr/share/man/man3/rad_put_addr.3.gz
OLD_FILES+=usr/share/man/man3/rad_put_attr.3.gz
OLD_FILES+=usr/share/man/man3/rad_put_int.3.gz
OLD_FILES+=usr/share/man/man3/rad_put_message_authentic.3.gz
OLD_FILES+=usr/share/man/man3/rad_put_string.3.gz
OLD_FILES+=usr/share/man/man3/rad_put_vendor_addr.3.gz
OLD_FILES+=usr/share/man/man3/rad_put_vendor_attr.3.gz
OLD_FILES+=usr/share/man/man3/rad_put_vendor_int.3.gz
OLD_FILES+=usr/share/man/man3/rad_put_vendor_string.3.gz
OLD_FILES+=usr/share/man/man3/rad_receive_request.3.gz
OLD_FILES+=usr/share/man/man3/rad_request_authenticator.3.gz
OLD_FILES+=usr/share/man/man3/rad_send_request.3.gz
OLD_FILES+=usr/share/man/man3/rad_send_response.3.gz
OLD_FILES+=usr/share/man/man3/rad_server_open.3.gz
OLD_FILES+=usr/share/man/man3/rad_server_secret.3.gz
OLD_FILES+=usr/share/man/man3/rad_strerror.3.gz
OLD_FILES+=usr/share/man/man5/radius.conf.5.gz
OLD_FILES+=usr/share/man/man8/pam_radius.8.gz
.endif
.if ${MK_RBOOTD} == no
OLD_FILES+=usr/libexec/rbootd
OLD_FILES+=usr/share/man/man8/rbootd.8.gz
.endif
.if ${MK_RESCUE} == no
. if exists(${DESTDIR}${TESTSBASE})
RESCUE_DIRS!=find ${DESTDIR}/rescue -type d 2>/dev/null | sed -e 's,^${DESTDIR}/,,'; echo
OLD_DIRS+=${RESCUE_DIRS}
RESCUE_FILES!=find ${DESTDIR}/rescue \! -type d 2>/dev/null | sed -e 's,^${DESTDIR}/,,'; echo
OLD_FILES+=${RESCUE_FILES}
. endif
.endif
.if ${MK_ROUTED} == no
OLD_FILES+=etc/rc.d/routed
OLD_FILES+=rescue/routed
OLD_FILES+=rescue/rtquery
OLD_FILES+=sbin/routed
OLD_FILES+=sbin/rtquery
OLD_FILES+=usr/share/man/man8/routed.8.gz
OLD_FILES+=usr/share/man/man8/rtquery.8.gz
.endif
.if ${MK_SENDMAIL} == no
OLD_FILES+=etc/mtree/BSD.sendmail.dist
OLD_FILES+=etc/newsyslog.conf.d/sendmail.conf
OLD_FILES+=etc/periodic/daily/150.clean-hoststat
OLD_FILES+=etc/periodic/daily/440.status-mailq
OLD_FILES+=etc/periodic/daily/460.status-mail-rejects
OLD_FILES+=etc/periodic/daily/500.queuerun
OLD_FILES+=etc/rc.d/sendmail
.if ${MK_MAILWRAPPER} == no
OLD_FILES+=bin/rmail
.endif
OLD_FILES+=usr/bin/vacation
OLD_FILES+=usr/include/libmilter/mfapi.h
OLD_FILES+=usr/include/libmilter/mfdef.h
OLD_DIRS+=usr/include/libmilter
OLD_FILES+=usr/lib/libmilter.a
OLD_FILES+=usr/lib/libmilter.so
OLD_LIBS+=usr/lib/libmilter.so.5
OLD_FILES+=usr/lib/libmilter_p.a
OLD_FILES+=usr/libexec/mail.local
OLD_FILES+=usr/libexec/sendmail/sendmail
OLD_FILES+=usr/libexec/smrsh
OLD_FILES+=usr/sbin/editmap
OLD_FILES+=usr/sbin/mailstats
OLD_FILES+=usr/sbin/makemap
OLD_FILES+=usr/sbin/praliases
OLD_FILES+=usr/share/doc/smm/08.sendmailop/paper.ascii.gz
OLD_DIRS+=usr/share/doc/smm/08.sendmailop
OLD_FILES+=usr/share/man/man1/mailq.1.gz
OLD_FILES+=usr/share/man/man1/newaliases.1.gz
OLD_FILES+=usr/share/man/man1/vacation.1.gz
OLD_FILES+=usr/share/man/man5/aliases.5.gz
OLD_FILES+=usr/share/man/man8/editmap.8.gz
OLD_FILES+=usr/share/man/man8/hoststat.8.gz
OLD_FILES+=usr/share/man/man8/mail.local.8.gz
OLD_FILES+=usr/share/man/man8/mailstats.8.gz
OLD_FILES+=usr/share/man/man8/makemap.8.gz
OLD_FILES+=usr/share/man/man8/praliases.8.gz
OLD_FILES+=usr/share/man/man8/purgestat.8.gz
OLD_FILES+=usr/share/man/man8/rmail.8.gz
OLD_FILES+=usr/share/man/man8/sendmail.8.gz
OLD_FILES+=usr/share/man/man8/smrsh.8.gz
OLD_FILES+=usr/share/sendmail/cf/README
OLD_FILES+=usr/share/sendmail/cf/cf/Makefile
OLD_FILES+=usr/share/sendmail/cf/cf/README
OLD_FILES+=usr/share/sendmail/cf/cf/chez.cs.mc
OLD_FILES+=usr/share/sendmail/cf/cf/clientproto.mc
OLD_FILES+=usr/share/sendmail/cf/cf/cs-hpux10.mc
OLD_FILES+=usr/share/sendmail/cf/cf/cs-hpux9.mc
OLD_FILES+=usr/share/sendmail/cf/cf/cs-osf1.mc
OLD_FILES+=usr/share/sendmail/cf/cf/cs-solaris2.mc
OLD_FILES+=usr/share/sendmail/cf/cf/cs-sunos4.1.mc
OLD_FILES+=usr/share/sendmail/cf/cf/cs-ultrix4.mc
OLD_FILES+=usr/share/sendmail/cf/cf/cyrusproto.mc
OLD_FILES+=usr/share/sendmail/cf/cf/generic-bsd4.4.mc
OLD_FILES+=usr/share/sendmail/cf/cf/generic-hpux10.mc
OLD_FILES+=usr/share/sendmail/cf/cf/generic-hpux9.mc
OLD_FILES+=usr/share/sendmail/cf/cf/generic-linux.mc
OLD_FILES+=usr/share/sendmail/cf/cf/generic-mpeix.mc
OLD_FILES+=usr/share/sendmail/cf/cf/generic-nextstep3.3.mc
OLD_FILES+=usr/share/sendmail/cf/cf/generic-osf1.mc
OLD_FILES+=usr/share/sendmail/cf/cf/generic-solaris.mc
OLD_FILES+=usr/share/sendmail/cf/cf/generic-sunos4.1.mc
OLD_FILES+=usr/share/sendmail/cf/cf/generic-ultrix4.mc
OLD_FILES+=usr/share/sendmail/cf/cf/huginn.cs.mc
OLD_FILES+=usr/share/sendmail/cf/cf/knecht.mc
OLD_FILES+=usr/share/sendmail/cf/cf/mail.cs.mc
OLD_FILES+=usr/share/sendmail/cf/cf/mail.eecs.mc
OLD_FILES+=usr/share/sendmail/cf/cf/mailspool.cs.mc
OLD_FILES+=usr/share/sendmail/cf/cf/python.cs.mc
OLD_FILES+=usr/share/sendmail/cf/cf/s2k-osf1.mc
OLD_FILES+=usr/share/sendmail/cf/cf/s2k-ultrix4.mc
OLD_FILES+=usr/share/sendmail/cf/cf/submit.cf
OLD_FILES+=usr/share/sendmail/cf/cf/submit.mc
OLD_FILES+=usr/share/sendmail/cf/cf/tcpproto.mc
OLD_FILES+=usr/share/sendmail/cf/cf/ucbarpa.mc
OLD_FILES+=usr/share/sendmail/cf/cf/ucbvax.mc
OLD_FILES+=usr/share/sendmail/cf/cf/uucpproto.mc
OLD_FILES+=usr/share/sendmail/cf/cf/vangogh.cs.mc
OLD_DIRS+=usr/share/sendmail/cf/cf
OLD_FILES+=usr/share/sendmail/cf/domain/Berkeley.EDU.m4
OLD_FILES+=usr/share/sendmail/cf/domain/CS.Berkeley.EDU.m4
OLD_FILES+=usr/share/sendmail/cf/domain/EECS.Berkeley.EDU.m4
OLD_FILES+=usr/share/sendmail/cf/domain/S2K.Berkeley.EDU.m4
OLD_FILES+=usr/share/sendmail/cf/domain/berkeley-only.m4
OLD_FILES+=usr/share/sendmail/cf/domain/generic.m4
OLD_DIRS+=usr/share/sendmail/cf/domain
OLD_FILES+=usr/share/sendmail/cf/feature/accept_unqualified_senders.m4
OLD_FILES+=usr/share/sendmail/cf/feature/accept_unresolvable_domains.m4
OLD_FILES+=usr/share/sendmail/cf/feature/access_db.m4
OLD_FILES+=usr/share/sendmail/cf/feature/allmasquerade.m4
OLD_FILES+=usr/share/sendmail/cf/feature/always_add_domain.m4
OLD_FILES+=usr/share/sendmail/cf/feature/authinfo.m4
OLD_FILES+=usr/share/sendmail/cf/feature/badmx.m4
OLD_FILES+=usr/share/sendmail/cf/feature/bcc.m4
OLD_FILES+=usr/share/sendmail/cf/feature/bestmx_is_local.m4
OLD_FILES+=usr/share/sendmail/cf/feature/bitdomain.m4
OLD_FILES+=usr/share/sendmail/cf/feature/blacklist_recipients.m4
OLD_FILES+=usr/share/sendmail/cf/feature/block_bad_helo.m4
OLD_FILES+=usr/share/sendmail/cf/feature/compat_check.m4
OLD_FILES+=usr/share/sendmail/cf/feature/conncontrol.m4
OLD_FILES+=usr/share/sendmail/cf/feature/delay_checks.m4
OLD_FILES+=usr/share/sendmail/cf/feature/dnsbl.m4
OLD_FILES+=usr/share/sendmail/cf/feature/domaintable.m4
OLD_FILES+=usr/share/sendmail/cf/feature/enhdnsbl.m4
OLD_FILES+=usr/share/sendmail/cf/feature/generics_entire_domain.m4
OLD_FILES+=usr/share/sendmail/cf/feature/genericstable.m4
OLD_FILES+=usr/share/sendmail/cf/feature/greet_pause.m4
OLD_FILES+=usr/share/sendmail/cf/feature/ldap_routing.m4
OLD_FILES+=usr/share/sendmail/cf/feature/limited_masquerade.m4
OLD_FILES+=usr/share/sendmail/cf/feature/local_lmtp.m4
OLD_FILES+=usr/share/sendmail/cf/feature/local_no_masquerade.m4
OLD_FILES+=usr/share/sendmail/cf/feature/local_procmail.m4
OLD_FILES+=usr/share/sendmail/cf/feature/lookupdotdomain.m4
OLD_FILES+=usr/share/sendmail/cf/feature/loose_relay_check.m4
OLD_FILES+=usr/share/sendmail/cf/feature/mailertable.m4
OLD_FILES+=usr/share/sendmail/cf/feature/masquerade_entire_domain.m4
OLD_FILES+=usr/share/sendmail/cf/feature/masquerade_envelope.m4
OLD_FILES+=usr/share/sendmail/cf/feature/msp.m4
OLD_FILES+=usr/share/sendmail/cf/feature/mtamark.m4
OLD_FILES+=usr/share/sendmail/cf/feature/no_default_msa.m4
OLD_FILES+=usr/share/sendmail/cf/feature/nocanonify.m4
OLD_FILES+=usr/share/sendmail/cf/feature/nopercenthack.m4
OLD_FILES+=usr/share/sendmail/cf/feature/notsticky.m4
OLD_FILES+=usr/share/sendmail/cf/feature/nouucp.m4
OLD_FILES+=usr/share/sendmail/cf/feature/nullclient.m4
OLD_FILES+=usr/share/sendmail/cf/feature/prefixmod.m4
OLD_FILES+=usr/share/sendmail/cf/feature/preserve_local_plus_detail.m4
OLD_FILES+=usr/share/sendmail/cf/feature/preserve_luser_host.m4
OLD_FILES+=usr/share/sendmail/cf/feature/promiscuous_relay.m4
OLD_FILES+=usr/share/sendmail/cf/feature/queuegroup.m4
OLD_FILES+=usr/share/sendmail/cf/feature/ratecontrol.m4
OLD_FILES+=usr/share/sendmail/cf/feature/redirect.m4
OLD_FILES+=usr/share/sendmail/cf/feature/relay_based_on_MX.m4
OLD_FILES+=usr/share/sendmail/cf/feature/relay_entire_domain.m4
OLD_FILES+=usr/share/sendmail/cf/feature/relay_hosts_only.m4
OLD_FILES+=usr/share/sendmail/cf/feature/relay_local_from.m4
OLD_FILES+=usr/share/sendmail/cf/feature/relay_mail_from.m4
OLD_FILES+=usr/share/sendmail/cf/feature/require_rdns.m4
OLD_FILES+=usr/share/sendmail/cf/feature/smrsh.m4
OLD_FILES+=usr/share/sendmail/cf/feature/stickyhost.m4
OLD_FILES+=usr/share/sendmail/cf/feature/tls_session_features.m4
OLD_FILES+=usr/share/sendmail/cf/feature/use_client_ptr.m4
OLD_FILES+=usr/share/sendmail/cf/feature/use_ct_file.m4
OLD_FILES+=usr/share/sendmail/cf/feature/use_cw_file.m4
OLD_FILES+=usr/share/sendmail/cf/feature/uucpdomain.m4
OLD_FILES+=usr/share/sendmail/cf/feature/virtuser_entire_domain.m4
OLD_FILES+=usr/share/sendmail/cf/feature/virtusertable.m4
OLD_DIRS+=usr/share/sendmail/cf/feature
OLD_FILES+=usr/share/sendmail/cf/hack/cssubdomain.m4
OLD_FILES+=usr/share/sendmail/cf/hack/xconnect.m4
OLD_DIRS+=usr/share/sendmail/cf/hack
OLD_FILES+=usr/share/sendmail/cf/m4/cf.m4
OLD_FILES+=usr/share/sendmail/cf/m4/cfhead.m4
OLD_FILES+=usr/share/sendmail/cf/m4/proto.m4
OLD_FILES+=usr/share/sendmail/cf/m4/version.m4
OLD_DIRS+=usr/share/sendmail/cf/m4
OLD_FILES+=usr/share/sendmail/cf/mailer/cyrus.m4
OLD_FILES+=usr/share/sendmail/cf/mailer/cyrusv2.m4
OLD_FILES+=usr/share/sendmail/cf/mailer/fax.m4
OLD_FILES+=usr/share/sendmail/cf/mailer/local.m4
OLD_FILES+=usr/share/sendmail/cf/mailer/mail11.m4
OLD_FILES+=usr/share/sendmail/cf/mailer/phquery.m4
OLD_FILES+=usr/share/sendmail/cf/mailer/pop.m4
OLD_FILES+=usr/share/sendmail/cf/mailer/procmail.m4
OLD_FILES+=usr/share/sendmail/cf/mailer/qpage.m4
OLD_FILES+=usr/share/sendmail/cf/mailer/smtp.m4
OLD_FILES+=usr/share/sendmail/cf/mailer/usenet.m4
OLD_FILES+=usr/share/sendmail/cf/mailer/uucp.m4
OLD_DIRS+=usr/share/sendmail/cf/mailer
OLD_FILES+=usr/share/sendmail/cf/ostype/a-ux.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/aix3.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/aix4.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/aix5.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/altos.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/amdahl-uts.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/bsd4.3.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/bsd4.4.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/bsdi.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/bsdi1.0.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/bsdi2.0.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/darwin.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/dgux.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/domainos.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/dragonfly.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/dynix3.2.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/freebsd4.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/freebsd5.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/freebsd6.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/gnu.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/hpux10.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/hpux11.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/hpux9.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/irix4.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/irix5.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/irix6.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/isc4.1.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/linux.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/maxion.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/mklinux.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/mpeix.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/nextstep.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/openbsd.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/osf1.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/powerux.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/ptx2.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/qnx.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/riscos4.5.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/sco-uw-2.1.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/sco3.2.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/sinix.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/solaris11.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/solaris2.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/solaris2.ml.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/solaris2.pre5.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/solaris8.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/sunos3.5.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/sunos4.1.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/svr4.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/ultrix4.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/unicos.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/unicosmk.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/unicosmp.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/unixware7.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/unknown.m4
OLD_FILES+=usr/share/sendmail/cf/ostype/uxpds.m4
OLD_DIRS+=usr/share/sendmail/cf/ostype
OLD_FILES+=usr/share/sendmail/cf/sendmail.schema
OLD_FILES+=usr/share/sendmail/cf/sh/makeinfo.sh
OLD_DIRS+=usr/share/sendmail/cf/sh
OLD_FILES+=usr/share/sendmail/cf/siteconfig/uucp.cogsci.m4
OLD_FILES+=usr/share/sendmail/cf/siteconfig/uucp.old.arpa.m4
OLD_FILES+=usr/share/sendmail/cf/siteconfig/uucp.ucbarpa.m4
OLD_FILES+=usr/share/sendmail/cf/siteconfig/uucp.ucbvax.m4
OLD_DIRS+=usr/share/sendmail/cf/siteconfig
OLD_DIRS+=usr/share/sendmail/cf
OLD_DIRS+=usr/share/sendmail
OLD_DIRS+=var/spool/clientmqueue
.endif
.if ${MK_SERVICESDB} == no
OLD_FILES+=var/db/services.db
.endif
.if ${MK_SHAREDOCS} == no
OLD_FILES+=usr/share/doc/pjdfstest/README
OLD_DIRS+=usr/share/doc/pjdfstest
.endif
.if ${MK_SYSCONS} == no
OLD_FILES+=usr/share/syscons/fonts/INDEX.fonts
OLD_FILES+=usr/share/syscons/fonts/armscii8-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/armscii8-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/armscii8-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/cp1251-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/cp1251-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/cp1251-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/cp437-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/cp437-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/cp437-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/cp437-thin-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/cp437-thin-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/cp850-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/cp850-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/cp850-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/cp850-thin-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/cp850-thin-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/cp865-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/cp865-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/cp865-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/cp865-thin-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/cp865-thin-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/cp866-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/cp866-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/cp866-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/cp866b-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/cp866c-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/cp866u-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/cp866u-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/cp866u-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/haik8-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/haik8-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/haik8-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/iso-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/iso-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/iso-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/iso-thin-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/iso02-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/iso02-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/iso02-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/iso04-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/iso04-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/iso04-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/iso04-vga9-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/iso04-vga9-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/iso04-vga9-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/iso04-vga9-wide-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/iso04-wide-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/iso05-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/iso05-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/iso05-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/iso07-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/iso07-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/iso07-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/iso08-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/iso08-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/iso08-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/iso09-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/iso15-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/iso15-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/iso15-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/iso15-thin-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/koi8-r-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/koi8-r-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/koi8-r-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/koi8-rb-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/koi8-rc-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/koi8-u-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/koi8-u-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/koi8-u-8x8.fnt
OLD_FILES+=usr/share/syscons/fonts/swiss-1131-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/swiss-1251-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/swiss-8x14.fnt
OLD_FILES+=usr/share/syscons/fonts/swiss-8x16.fnt
OLD_FILES+=usr/share/syscons/fonts/swiss-8x8.fnt
OLD_FILES+=usr/share/syscons/keymaps/INDEX.keymaps
OLD_FILES+=usr/share/syscons/keymaps/be.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/be.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/bg.bds.ctrlcaps.kbd
OLD_FILES+=usr/share/syscons/keymaps/bg.phonetic.ctrlcaps.kbd
OLD_FILES+=usr/share/syscons/keymaps/br275.cp850.kbd
OLD_FILES+=usr/share/syscons/keymaps/br275.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/br275.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/by.cp1131.kbd
OLD_FILES+=usr/share/syscons/keymaps/by.cp1251.kbd
OLD_FILES+=usr/share/syscons/keymaps/by.iso5.kbd
OLD_FILES+=usr/share/syscons/keymaps/ce.iso2.kbd
OLD_FILES+=usr/share/syscons/keymaps/colemak.iso15.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/cs.latin2.qwertz.kbd
OLD_FILES+=usr/share/syscons/keymaps/cz.iso2.kbd
OLD_FILES+=usr/share/syscons/keymaps/danish.cp865.kbd
OLD_FILES+=usr/share/syscons/keymaps/danish.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/danish.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/danish.iso.macbook.kbd
OLD_FILES+=usr/share/syscons/keymaps/dutch.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/eee_nordic.kbd
OLD_FILES+=usr/share/syscons/keymaps/el.iso07.kbd
OLD_FILES+=usr/share/syscons/keymaps/estonian.cp850.kbd
OLD_FILES+=usr/share/syscons/keymaps/estonian.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/estonian.iso15.kbd
OLD_FILES+=usr/share/syscons/keymaps/finnish.cp850.kbd
OLD_FILES+=usr/share/syscons/keymaps/finnish.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/fr.dvorak.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/fr.dvorak.kbd
OLD_FILES+=usr/share/syscons/keymaps/fr.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/fr.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/fr.macbook.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/fr_CA.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/german.cp850.kbd
OLD_FILES+=usr/share/syscons/keymaps/german.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/german.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/gr.elot.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/gr.us101.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/hr.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/hu.iso2.101keys.kbd
OLD_FILES+=usr/share/syscons/keymaps/hu.iso2.102keys.kbd
OLD_FILES+=usr/share/syscons/keymaps/hy.armscii-8.kbd
OLD_FILES+=usr/share/syscons/keymaps/icelandic.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/icelandic.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/it.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/iw.iso8.kbd
OLD_FILES+=usr/share/syscons/keymaps/jp.106.kbd
OLD_FILES+=usr/share/syscons/keymaps/jp.106x.kbd
OLD_FILES+=usr/share/syscons/keymaps/kk.pt154.io.kbd
OLD_FILES+=usr/share/syscons/keymaps/kk.pt154.kst.kbd
OLD_FILES+=usr/share/syscons/keymaps/latinamerican.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/latinamerican.kbd
OLD_FILES+=usr/share/syscons/keymaps/lt.iso4.kbd
OLD_FILES+=usr/share/syscons/keymaps/norwegian.dvorak.kbd
OLD_FILES+=usr/share/syscons/keymaps/norwegian.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/pl_PL.ISO8859-2.kbd
OLD_FILES+=usr/share/syscons/keymaps/pl_PL.dvorak.kbd
OLD_FILES+=usr/share/syscons/keymaps/pt.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/pt.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/ru.cp866.kbd
OLD_FILES+=usr/share/syscons/keymaps/ru.iso5.kbd
OLD_FILES+=usr/share/syscons/keymaps/ru.koi8-r.kbd
OLD_FILES+=usr/share/syscons/keymaps/ru.koi8-r.shift.kbd
OLD_FILES+=usr/share/syscons/keymaps/ru.koi8-r.win.kbd
OLD_FILES+=usr/share/syscons/keymaps/si.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/sk.iso2.kbd
OLD_FILES+=usr/share/syscons/keymaps/spanish.dvorak.kbd
OLD_FILES+=usr/share/syscons/keymaps/spanish.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/spanish.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/spanish.iso15.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/swedish.cp850.kbd
OLD_FILES+=usr/share/syscons/keymaps/swedish.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/swissfrench.cp850.kbd
OLD_FILES+=usr/share/syscons/keymaps/swissfrench.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/swissfrench.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/swissgerman.cp850.kbd
OLD_FILES+=usr/share/syscons/keymaps/swissgerman.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/swissgerman.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/swissgerman.macbook.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/tr.iso9.q.kbd
OLD_FILES+=usr/share/syscons/keymaps/ua.iso5.kbd
OLD_FILES+=usr/share/syscons/keymaps/ua.koi8-u.kbd
OLD_FILES+=usr/share/syscons/keymaps/ua.koi8-u.shift.alt.kbd
OLD_FILES+=usr/share/syscons/keymaps/uk.cp850-ctrl.kbd
OLD_FILES+=usr/share/syscons/keymaps/uk.cp850.kbd
OLD_FILES+=usr/share/syscons/keymaps/uk.dvorak.kbd
OLD_FILES+=usr/share/syscons/keymaps/uk.iso-ctrl.kbd
OLD_FILES+=usr/share/syscons/keymaps/uk.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/us.dvorak.kbd
OLD_FILES+=usr/share/syscons/keymaps/us.dvorakl.kbd
OLD_FILES+=usr/share/syscons/keymaps/us.dvorakp.kbd
OLD_FILES+=usr/share/syscons/keymaps/us.dvorakr.kbd
OLD_FILES+=usr/share/syscons/keymaps/us.dvorakx.kbd
OLD_FILES+=usr/share/syscons/keymaps/us.emacs.kbd
OLD_FILES+=usr/share/syscons/keymaps/us.iso.acc.kbd
OLD_FILES+=usr/share/syscons/keymaps/us.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/us.pc-ctrl.kbd
OLD_FILES+=usr/share/syscons/keymaps/us.unix.kbd
OLD_FILES+=usr/share/syscons/scrnmaps/armscii8-2haik8.scm
OLD_FILES+=usr/share/syscons/scrnmaps/iso-8859-1_to_cp437.scm
OLD_FILES+=usr/share/syscons/scrnmaps/iso-8859-4_for_vga9.scm
OLD_FILES+=usr/share/syscons/scrnmaps/iso-8859-7_to_cp437.scm
OLD_FILES+=usr/share/syscons/scrnmaps/koi8-r2cp866.scm
OLD_FILES+=usr/share/syscons/scrnmaps/koi8-u2cp866u.scm
OLD_FILES+=usr/share/syscons/scrnmaps/us-ascii_to_cp437.scm
OLD_DIRS+=usr/share/syscons/fonts
OLD_DIRS+=usr/share/syscons/scrnmaps
OLD_DIRS+=usr/share/syscons/keymaps
OLD_DIRS+=usr/share/syscons
.endif
.if ${MK_TALK} == no
OLD_FILES+=usr/bin/talk
OLD_FILES+=usr/libexec/ntalkd
OLD_FILES+=usr/share/man/man1/talk.1.gz
OLD_FILES+=usr/share/man/man8/talkd.8.gz
.endif
.if ${MK_TCSH} == no
OLD_FILES+=.cshrc
OLD_FILES+=etc/csh.cshrc
OLD_FILES+=etc/csh.login
OLD_FILES+=etc/csh.logout
OLD_FILES+=bin/csh
OLD_FILES+=bin/tcsh
OLD_FILES+=rescue/csh
OLD_FILES+=rescue/tcsh
OLD_FILES+=root/.cshrc
OLD_FILES+=root/.login
OLD_FILES+=usr/share/examples/etc/csh.cshrc
OLD_FILES+=usr/share/examples/etc/csh.login
OLD_FILES+=usr/share/examples/etc/csh.logout
OLD_FILES+=usr/share/examples/tcsh/complete.tcsh
OLD_FILES+=usr/share/examples/tcsh/csh-mode.el
OLD_DIRS+=usr/share/examples/tcsh
OLD_FILES+=usr/share/man/man1/csh.1.gz
OLD_FILES+=usr/share/man/man1/tcsh.1.gz
OLD_FILES+=usr/share/nls/de_AT.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/de_AT.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/de_AT.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/de_CH.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/de_CH.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/de_CH.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/de_DE.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/de_DE.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/el_GR.ISO8859-7/tcsh.cat
OLD_FILES+=usr/share/nls/el_GR.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/es_ES.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/es_ES.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/es_ES.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/et_EE.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/et_EE.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/fi_FI.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/fi_FI.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/fi_FI.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/fr_BE.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/fr_BE.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/fr_BE.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/fr_CA.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/fr_CA.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/fr_CA.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/fr_CH.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/fr_CH.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/fr_CH.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/fr_FR.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/fr_FR.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/it_CH.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/it_CH.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/it_CH.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/it_IT.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/it_IT.ISO8859-15/tcsh.cat
OLD_FILES+=usr/share/nls/it_IT.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/ja_JP.SJIS/tcsh.cat
OLD_FILES+=usr/share/nls/ja_JP.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/ja_JP.eucJP/tcsh.cat
OLD_FILES+=usr/share/nls/ru_RU.CP1251/tcsh.cat
OLD_FILES+=usr/share/nls/ru_RU.CP866/tcsh.cat
OLD_FILES+=usr/share/nls/ru_RU.ISO8859-5/tcsh.cat
OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/tcsh.cat
OLD_FILES+=usr/share/nls/ru_RU.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/uk_UA.ISO8859-5/tcsh.cat
OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/tcsh.cat
OLD_FILES+=usr/share/nls/uk_UA.UTF-8/tcsh.cat
.endif
.if ${MK_TELNET} == no
OLD_FILES+=etc/pam.d/telnetd
OLD_FILES+=usr/bin/telnet
OLD_FILES+=usr/libexec/telnetd
OLD_FILES+=usr/share/man/man1/telnet.1.gz
OLD_FILES+=usr/share/man/man8/telnetd.8.gz
.endif
.if ${MK_TESTS} == yes
OLD_FILES+=usr/bin/atf-sh
OLD_FILES+=usr/include/atf-c++/config.hpp
OLD_FILES+=usr/include/atf-c/config.h
OLD_FILES+=usr/lib/libatf-c++.a
OLD_FILES+=usr/lib/libatf-c++.so
OLD_LIBS+=usr/lib/libatf-c++.so.1
OLD_LIBS+=usr/lib/libatf-c++.so.2
OLD_FILES+=usr/lib/libatf-c++_p.a
OLD_FILES+=usr/lib/libatf-c.a
OLD_FILES+=usr/lib/libatf-c.so
OLD_LIBS+=usr/lib/libatf-c.so.1
OLD_FILES+=usr/lib/libatf-c_p.a
OLD_LIBS+=usr/lib/libprivateatf-c.so.0
OLD_LIBS+=usr/lib/libprivateatf-c++.so.1
OLD_FILES+=usr/libdata/pkgconfig/atf-c++.pc
OLD_FILES+=usr/libdata/pkgconfig/atf-c.pc
OLD_FILES+=usr/libdata/pkgconfig/atf-sh.pc
OLD_FILES+=usr/share/aclocal/atf-c++.m4
OLD_FILES+=usr/share/aclocal/atf-c.m4
OLD_FILES+=usr/share/aclocal/atf-common.m4
OLD_FILES+=usr/share/aclocal/atf-sh.m4
OLD_DIRS+=usr/share/aclocal
OLD_DIRS+=usr/tests/bin/chown
OLD_FILES+=usr/tests/bin/chown/Kyuafile
OLD_FILES+=usr/tests/bin/chown/chown-f_test
OLD_FILES+=usr/tests/bin/chown/units_basics
OLD_FILES+=usr/tests/bin/date/legacy_test
OLD_FILES+=usr/tests/bin/sh/legacy_test
OLD_FILES+=usr/tests/usr.bin/atf/Kyuafile
OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/Kyuafile
OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/atf_check_test
OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/config_test
OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/integration_test
OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/misc_helpers
OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/normalize_test
OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/tc_test
OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/tp_test
OLD_DIRS+=usr/tests/usr.bin/atf/atf-sh
OLD_DIRS+=usr/tests/usr.bin/atf
OLD_FILES+=usr/tests/lib/atf/libatf-c/test_helpers_test
OLD_FILES+=usr/tests/lib/atf/test-programs/fork_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/application_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/config_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/expand_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/parser_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/sanity_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/ui_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/env_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/exceptions_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/expand_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/fs_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/parser_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/process_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/sanity_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/pkg_config_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/text_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/ui_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/config_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/dynstr_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/env_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/fs_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/list_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/map_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/pkg_config_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/process_helpers
OLD_FILES+=usr/tests/lib/atf/libatf-c/process_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/sanity_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/text_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/user_test
.if ${MK_MAKE} == yes
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.3
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.4
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.5
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.6
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.7
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.3
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.4
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.5
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.6
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.7
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.3
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.4
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.5
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.6
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.7
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/libtest.a
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.3
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.4
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.5
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.6
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.7
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.3
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.4
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.5
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.6
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.7
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.3
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.4
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.5
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.6
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.7
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/libtest.a
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.3
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.4
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.5
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.6
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.7
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.3
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.4
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.5
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.6
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.7
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.3
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.4
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.5
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.6
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.7
OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/libtest.a
OLD_FILES+=usr/tests/usr.bin/make/archives/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/basic/t0/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/basic/t0/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/basic/t0/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/basic/t0/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/basic/t0/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/basic/t1/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/basic/t1/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/basic/t1/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/basic/t1/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/basic/t1/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/basic/t1/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/basic/t2/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/basic/t2/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/basic/t2/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/basic/t2/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/basic/t2/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/basic/t2/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/basic/t3/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/basic/t3/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/basic/t3/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/basic/t3/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/basic/t3/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/basic/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/execution/ellipsis/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/execution/ellipsis/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/execution/ellipsis/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/execution/ellipsis/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/execution/ellipsis/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/execution/ellipsis/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/execution/empty/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/execution/empty/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/execution/empty/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/execution/empty/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/execution/empty/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/execution/empty/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/execution/joberr/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/execution/joberr/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/execution/joberr/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/execution/joberr/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/execution/joberr/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/execution/joberr/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/execution/plus/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/execution/plus/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/execution/plus/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/execution/plus/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/execution/plus/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/execution/plus/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/execution/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/sh
OLD_FILES+=usr/tests/usr.bin/make/shell/meta/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/shell/meta/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/shell/meta/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/shell/meta/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/shell/meta/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/shell/meta/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/shell/meta/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/shell/meta/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/shell/meta/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/shell/meta/sh
OLD_FILES+=usr/tests/usr.bin/make/shell/path/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/shell/path/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/shell/path/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/shell/path/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/shell/path/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/shell/path/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/shell/path/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/shell/path/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/shell/path/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/shell/path/sh
OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/shell
OLD_FILES+=usr/tests/usr.bin/make/shell/replace/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/shell/replace/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/shell/replace/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/shell/replace/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/shell/replace/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/shell/replace/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/shell/replace/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/shell/replace/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/shell/replace/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/shell/replace/shell
OLD_FILES+=usr/tests/usr.bin/make/shell/select/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/shell/select/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/shell/select/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/shell/select/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/shell/select/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/shell/select/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/shell/select/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/shell/select/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/shell/select/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/shell/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/TEST1.a
OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/TEST1.a
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/TEST2.a
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/TEST1.a
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/TEST2.a
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/suffixes/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/syntax/directive-t0/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/syntax/directive-t0/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/syntax/directive-t0/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/syntax/directive-t0/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/syntax/directive-t0/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/syntax/directive-t0/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.status.3
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.status.4
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.status.5
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stderr.3
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stderr.4
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stderr.5
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stdout.3
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stdout.4
OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stdout.5
OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/syntax/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/1/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/1/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/1/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/1/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/1/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/1/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/mk/sys.mk
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/mk/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/1/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/1/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/1/cleanup
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/1/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/1/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/1/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/mk/sys.mk
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/mk/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/1/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/1/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/1/cleanup
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/1/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/1/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/1/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/mk/sys.mk
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/mk/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/sysmk/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_M/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_M/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_M/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_M/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_M/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_M/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.status.3
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.stderr.3
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.stdout.3
OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/expected.status.2
OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/expected.stderr.2
OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/expected.stdout.2
OLD_FILES+=usr/tests/usr.bin/make/variables/t0/legacy_test
OLD_FILES+=usr/tests/usr.bin/make/variables/t0/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/variables/t0/Makefile.test
OLD_FILES+=usr/tests/usr.bin/make/variables/t0/expected.status.1
OLD_FILES+=usr/tests/usr.bin/make/variables/t0/expected.stderr.1
OLD_FILES+=usr/tests/usr.bin/make/variables/t0/expected.stdout.1
OLD_FILES+=usr/tests/usr.bin/make/variables/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/Kyuafile
OLD_FILES+=usr/tests/usr.bin/make/common.sh
OLD_FILES+=usr/tests/usr.bin/make/test-new.mk
OLD_DIRS+=usr/tests/usr.bin/make/variables/t0
OLD_DIRS+=usr/tests/usr.bin/make/variables/opt_V
OLD_DIRS+=usr/tests/usr.bin/make/variables/modifier_t
OLD_DIRS+=usr/tests/usr.bin/make/variables/modifier_M
OLD_DIRS+=usr/tests/usr.bin/make/variables
OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t2/mk
OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t2/2/1
OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t2/2
OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t2
OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t1/mk
OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t1/2/1
OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t1/2
OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t1
OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t0/mk
OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t0/2/1
OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t0/2
OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t0
OLD_DIRS+=usr/tests/usr.bin/make/sysmk
OLD_DIRS+=usr/tests/usr.bin/make/syntax/semi
OLD_DIRS+=usr/tests/usr.bin/make/syntax/funny-targets
OLD_DIRS+=usr/tests/usr.bin/make/syntax/enl
OLD_DIRS+=usr/tests/usr.bin/make/syntax/directive-t0
OLD_DIRS+=usr/tests/usr.bin/make/syntax
OLD_DIRS+=usr/tests/usr.bin/make/suffixes/src_wild2
OLD_DIRS+=usr/tests/usr.bin/make/suffixes/src_wild1
OLD_DIRS+=usr/tests/usr.bin/make/suffixes/basic
OLD_DIRS+=usr/tests/usr.bin/make/suffixes
OLD_DIRS+=usr/tests/usr.bin/make/shell/select
OLD_DIRS+=usr/tests/usr.bin/make/shell/replace
OLD_DIRS+=usr/tests/usr.bin/make/shell/path_select
OLD_DIRS+=usr/tests/usr.bin/make/shell/path
OLD_DIRS+=usr/tests/usr.bin/make/shell/meta
OLD_DIRS+=usr/tests/usr.bin/make/shell/builtin
OLD_DIRS+=usr/tests/usr.bin/make/shell
OLD_DIRS+=usr/tests/usr.bin/make/execution/plus
OLD_DIRS+=usr/tests/usr.bin/make/execution/joberr
OLD_DIRS+=usr/tests/usr.bin/make/execution/empty
OLD_DIRS+=usr/tests/usr.bin/make/execution/ellipsis
OLD_DIRS+=usr/tests/usr.bin/make/execution
OLD_DIRS+=usr/tests/usr.bin/make/basic/t3
OLD_DIRS+=usr/tests/usr.bin/make/basic/t2
OLD_DIRS+=usr/tests/usr.bin/make/basic/t1
OLD_DIRS+=usr/tests/usr.bin/make/basic/t0
OLD_DIRS+=usr/tests/usr.bin/make/basic
OLD_DIRS+=usr/tests/usr.bin/make/archives/fmt_oldbsd
OLD_DIRS+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod
OLD_DIRS+=usr/tests/usr.bin/make/archives/fmt_44bsd
OLD_DIRS+=usr/tests/usr.bin/make/archives
OLD_DIRS+=usr/tests/usr.bin/make
OLD_FILES+=usr/tests/usr.bin/yacc/legacy_test
OLD_FILES+=usr/tests/usr.bin/yacc/regress.00.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.01.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.02.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.03.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.04.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.05.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.06.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.07.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.08.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.09.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.10.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.11.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.12.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.13.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.14.out
OLD_FILES+=usr/tests/usr.bin/yacc/regress.sh
OLD_FILES+=usr/tests/usr.bin/yacc/undefined.y
.endif
.else
# ATF libraries.
OLD_FILES+=etc/mtree/BSD.tests.dist
OLD_FILES+=usr/bin/atf-sh
OLD_DIRS+=usr/include/atf-c
OLD_FILES+=usr/include/atf-c/build.h
OLD_FILES+=usr/include/atf-c/check.h
OLD_FILES+=usr/include/atf-c/config.h
OLD_FILES+=usr/include/atf-c/defs.h
OLD_FILES+=usr/include/atf-c/error.h
OLD_FILES+=usr/include/atf-c/error_fwd.h
OLD_FILES+=usr/include/atf-c/macros.h
OLD_FILES+=usr/include/atf-c/tc.h
OLD_FILES+=usr/include/atf-c/tp.h
OLD_FILES+=usr/include/atf-c/utils.h
OLD_FILES+=usr/include/atf-c.h
OLD_DIRS+=usr/include/atf-c++
OLD_FILES+=usr/include/atf-c++/build.hpp
OLD_FILES+=usr/include/atf-c++/check.hpp
OLD_FILES+=usr/include/atf-c++/config.hpp
OLD_FILES+=usr/include/atf-c++/macros.hpp
OLD_FILES+=usr/include/atf-c++/tests.hpp
OLD_FILES+=usr/include/atf-c++/utils.hpp
OLD_FILES+=usr/include/atf-c++.hpp
OLD_FILES+=usr/lib/libatf-c_p.a
OLD_FILES+=usr/lib/libatf-c.so.1
OLD_FILES+=usr/lib/libatf-c.so
OLD_FILES+=usr/lib/libatf-c++.a
OLD_FILES+=usr/lib/libatf-c++_p.a
OLD_FILES+=usr/lib/libatf-c++.so.1
OLD_FILES+=usr/lib/libatf-c++.so
OLD_FILES+=usr/lib/libatf-c.a
OLD_FILES+=usr/libexec/atf-check
OLD_FILES+=usr/libexec/atf-sh
OLD_DIRS+=usr/share/atf
OLD_FILES+=usr/share/atf/libatf-sh.subr
OLD_DIRS+=usr/share/doc/atf
OLD_FILES+=usr/share/doc/atf/AUTHORS
OLD_FILES+=usr/share/doc/atf/COPYING
OLD_FILES+=usr/share/doc/atf/NEWS
OLD_FILES+=usr/share/doc/atf/README
OLD_FILES+=usr/share/doc/pjdfstest/README
OLD_FILES+=usr/share/man/man1/atf-check.1.gz
OLD_FILES+=usr/share/man/man1/atf-sh.1.gz
OLD_FILES+=usr/share/man/man1/atf-test-program.1.gz
OLD_FILES+=usr/share/man/man3/atf-c-api.3.gz
OLD_FILES+=usr/share/man/man3/atf-c++-api.3.gz
OLD_FILES+=usr/share/man/man3/atf-sh-api.3.gz
OLD_FILES+=usr/share/man/man3/atf-sh.3.gz
OLD_FILES+=usr/share/man/man4/atf-test-case.4.gz
OLD_FILES+=usr/share/man/man7/atf.7.gz
OLD_FILES+=usr/share/mk/atf.test.mk
OLD_FILES+=usr/share/mk/plain.test.mk
OLD_FILES+=usr/share/mk/suite.test.mk
OLD_FILES+=usr/share/mk/tap.test.mk
# Test suite.
. if exists(${DESTDIR}${TESTSBASE})
TESTS_DIRS!=find ${DESTDIR}${TESTSBASE} -type d | sed -e 's,^${DESTDIR}/,,'; echo
OLD_DIRS+=${TESTS_DIRS}
TESTS_FILES!=find ${DESTDIR}${TESTSBASE} \! -type d | sed -e 's,^${DESTDIR}/,,'; echo
OLD_FILES+=${TESTS_FILES}
. endif
.endif # Test suite.
.if ${MK_TESTS_SUPPORT} == no
OLD_FILES+=usr/bin/kyua
OLD_FILES+=usr/include/atf-c++.hpp
OLD_FILES+=usr/include/atf-c++/build.hpp
OLD_FILES+=usr/include/atf-c++/check.hpp
OLD_FILES+=usr/include/atf-c++/macros.hpp
OLD_FILES+=usr/include/atf-c++/tests.hpp
OLD_FILES+=usr/include/atf-c++/utils.hpp
OLD_FILES+=usr/include/atf-c.h
OLD_FILES+=usr/include/atf-c/build.h
OLD_FILES+=usr/include/atf-c/check.h
OLD_FILES+=usr/include/atf-c/defs.h
OLD_FILES+=usr/include/atf-c/error.h
OLD_FILES+=usr/include/atf-c/error_fwd.h
OLD_FILES+=usr/include/atf-c/macros.h
OLD_FILES+=usr/include/atf-c/tc.h
OLD_FILES+=usr/include/atf-c/tp.h
OLD_FILES+=usr/include/atf-c/utils.h
OLD_LIBS+=usr/lib/libprivateatf-c++.so.2
OLD_LIBS+=usr/lib/libprivateatf-c.so.1
OLD_FILES+=usr/share/examples/kyua/kyua.conf
OLD_FILES+=usr/share/examples/kyua/Kyuafile.top
OLD_FILES+=usr/share/kyua/misc/context.html
OLD_FILES+=usr/share/kyua/misc/index.html
OLD_FILES+=usr/share/kyua/misc/report.css
OLD_FILES+=usr/share/kyua/misc/test_result.html
OLD_FILES+=usr/share/kyua/store/migrate_v1_v2.sql
OLD_FILES+=usr/share/kyua/store/migrate_v2_v3.sql
OLD_FILES+=usr/share/kyua/store/schema_v3.sql
OLD_FILES+=usr/share/man/man1/kyua-about.1.gz
OLD_FILES+=usr/share/man/man1/kyua-config.1.gz
OLD_FILES+=usr/share/man/man1/kyua-db-exec.1.gz
OLD_FILES+=usr/share/man/man1/kyua-db-migrate.1.gz
OLD_FILES+=usr/share/man/man1/kyua-debug.1.gz
OLD_FILES+=usr/share/man/man1/kyua-help.1.gz
OLD_FILES+=usr/share/man/man1/kyua-list.1.gz
OLD_FILES+=usr/share/man/man1/kyua-report-html.1.gz
OLD_FILES+=usr/share/man/man1/kyua-report-junit.1.gz
OLD_FILES+=usr/share/man/man1/kyua-report.1.gz
OLD_FILES+=usr/share/man/man1/kyua-test.1.gz
OLD_FILES+=usr/share/man/man1/kyua.1.gz
OLD_FILES+=usr/share/man/man3/atf-c++.3.gz
OLD_FILES+=usr/share/man/man3/atf-c-api++.3.gz
OLD_FILES+=usr/share/man/man3/atf-c-api.3.gz
OLD_FILES+=usr/share/man/man3/atf-c.3.gz
OLD_FILES+=usr/share/man/man5/kyua.conf.5.gz
OLD_FILES+=usr/share/man/man5/kyuafile.5.gz
OLD_FILES+=usr/tests/lib/atf/Kyuafile
OLD_FILES+=usr/tests/lib/atf/libatf-c++/Kyuafile
OLD_FILES+=usr/tests/lib/atf/libatf-c++/atf_c++_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/build_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/check_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/Kyuafile
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/application_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/env_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/exceptions_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/fs_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/process_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/text_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/version_helper
OLD_FILES+=usr/tests/lib/atf/libatf-c++/macros_hpp_test.cpp
OLD_FILES+=usr/tests/lib/atf/libatf-c++/macros_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/tests_test
OLD_FILES+=usr/tests/lib/atf/libatf-c++/unused_test.cpp
OLD_FILES+=usr/tests/lib/atf/libatf-c++/utils_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/Kyuafile
OLD_FILES+=usr/tests/lib/atf/libatf-c/atf_c_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/build_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/check_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/Kyuafile
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/dynstr_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/env_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/fs_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/list_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/map_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/process_helpers
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/process_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/sanity_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/text_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/user_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/version_helper
OLD_FILES+=usr/tests/lib/atf/libatf-c/error_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/macros_h_test.c
OLD_FILES+=usr/tests/lib/atf/libatf-c/macros_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/tc_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/tp_test
OLD_FILES+=usr/tests/lib/atf/libatf-c/unused_test.c
OLD_FILES+=usr/tests/lib/atf/libatf-c/utils_test
OLD_FILES+=usr/tests/lib/atf/test-programs/Kyuafile
OLD_FILES+=usr/tests/lib/atf/test-programs/c_helpers
OLD_FILES+=usr/tests/lib/atf/test-programs/config_test
OLD_FILES+=usr/tests/lib/atf/test-programs/cpp_helpers
OLD_FILES+=usr/tests/lib/atf/test-programs/expect_test
OLD_FILES+=usr/tests/lib/atf/test-programs/meta_data_test
OLD_FILES+=usr/tests/lib/atf/test-programs/result_test
OLD_FILES+=usr/tests/lib/atf/test-programs/sh_helpers
OLD_FILES+=usr/tests/lib/atf/test-programs/srcdir_test
.endif
.if ${MK_TEXTPROC} == no
OLD_FILES+=usr/bin/checknr
OLD_FILES+=usr/bin/colcrt
OLD_FILES+=usr/bin/ul
OLD_FILES+=usr/share/man/man1/checknr.1.gz
OLD_FILES+=usr/share/man/man1/colcrt.1.gz
OLD_FILES+=usr/share/man/man1/ul.1.gz
.endif
.if ${MK_TFTP} == no
OLD_FILES+=usr/bin/tftp
OLD_FILES+=usr/libexec/tftpd
OLD_FILES+=usr/share/man/man1/tftp.1.gz
OLD_FILES+=usr/share/man/man8/tftpd.8.gz
.endif
.if ${MK_TOOLCHAIN} == no
OLD_FILES+=usr/bin/CC
OLD_FILES+=usr/bin/addr2line
OLD_FILES+=usr/bin/as
OLD_FILES+=usr/bin/byacc
OLD_FILES+=usr/bin/cc
OLD_FILES+=usr/bin/c88
OLD_FILES+=usr/bin/c++
OLD_FILES+=usr/bin/c++filt
OLD_FILES+=usr/bin/ld
OLD_FILES+=usr/bin/ld.bfd
OLD_FILES+=usr/bin/nm
OLD_FILES+=usr/bin/objcopy
OLD_FILES+=usr/bin/readelf
OLD_FILES+=usr/bin/size
OLD_FILES+=usr/bin/strip
OLD_FILES+=usr/bin/yacc
OLD_FILES+=usr/share/man/man1/addr2line.1.gz
OLD_FILES+=usr/share/man/man1/c++filt.1.gz
OLD_FILES+=usr/share/man/man1/nm.1.gz
OLD_FILES+=usr/share/man/man1/readelf.1.gz
OLD_FILES+=usr/share/man/man1/size.1.gz
OLD_FILES+=usr/share/man/man1/strip.1.gz
OLD_FILES+=usr/share/man/man1/objcopy.1.gz
# lib/libelf
OLD_FILES+=usr/share/man/man3/elf.3.gz
OLD_FILES+=usr/share/man/man3/elf_begin.3.gz
OLD_FILES+=usr/share/man/man3/elf_cntl.3.gz
OLD_FILES+=usr/share/man/man3/elf_end.3.gz
OLD_FILES+=usr/share/man/man3/elf_errmsg.3.gz
OLD_FILES+=usr/share/man/man3/elf_fill.3.gz
OLD_FILES+=usr/share/man/man3/elf_flagdata.3.gz
OLD_FILES+=usr/share/man/man3/elf_getarhdr.3.gz
OLD_FILES+=usr/share/man/man3/elf_getarsym.3.gz
OLD_FILES+=usr/share/man/man3/elf_getbase.3.gz
OLD_FILES+=usr/share/man/man3/elf_getdata.3.gz
OLD_FILES+=usr/share/man/man3/elf_getident.3.gz
OLD_FILES+=usr/share/man/man3/elf_getscn.3.gz
OLD_FILES+=usr/share/man/man3/elf_getphdrnum.3.gz
OLD_FILES+=usr/share/man/man3/elf_getphnum.3.gz
OLD_FILES+=usr/share/man/man3/elf_getshdrnum.3.gz
OLD_FILES+=usr/share/man/man3/elf_getshnum.3.gz
OLD_FILES+=usr/share/man/man3/elf_getshdrstrndx.3.gz
OLD_FILES+=usr/share/man/man3/elf_getshstrndx.3.gz
OLD_FILES+=usr/share/man/man3/elf_hash.3.gz
OLD_FILES+=usr/share/man/man3/elf_kind.3.gz
OLD_FILES+=usr/share/man/man3/elf_memory.3.gz
OLD_FILES+=usr/share/man/man3/elf_next.3.gz
OLD_FILES+=usr/share/man/man3/elf_open.3.gz
OLD_FILES+=usr/share/man/man3/elf_rawfile.3.gz
OLD_FILES+=usr/share/man/man3/elf_rand.3.gz
OLD_FILES+=usr/share/man/man3/elf_strptr.3.gz
OLD_FILES+=usr/share/man/man3/elf_update.3.gz
OLD_FILES+=usr/share/man/man3/elf_version.3.gz
OLD_FILES+=usr/share/man/man3/gelf.3.gz
OLD_FILES+=usr/share/man/man3/gelf_checksum.3.gz
OLD_FILES+=usr/share/man/man3/gelf_fsize.3.gz
OLD_FILES+=usr/share/man/man3/gelf_getcap.3.gz
OLD_FILES+=usr/share/man/man3/gelf_getclass.3.gz
OLD_FILES+=usr/share/man/man3/gelf_getdyn.3.gz
OLD_FILES+=usr/share/man/man3/gelf_getehdr.3.gz
OLD_FILES+=usr/share/man/man3/gelf_getmove.3.gz
OLD_FILES+=usr/share/man/man3/gelf_getphdr.3.gz
OLD_FILES+=usr/share/man/man3/gelf_getrel.3.gz
OLD_FILES+=usr/share/man/man3/gelf_getrela.3.gz
OLD_FILES+=usr/share/man/man3/gelf_getshdr.3.gz
OLD_FILES+=usr/share/man/man3/gelf_getsym.3.gz
OLD_FILES+=usr/share/man/man3/gelf_getsyminfo.3.gz
OLD_FILES+=usr/share/man/man3/gelf_getsymshndx.3.gz
OLD_FILES+=usr/share/man/man3/gelf_newehdr.3.gz
OLD_FILES+=usr/share/man/man3/gelf_newphdr.3.gz
OLD_FILES+=usr/share/man/man3/gelf_update_ehdr.3.gz
OLD_FILES+=usr/share/man/man3/gelf_xlatetof.3.gz
# lib/libelftc
OLD_FILES+=usr/share/man/man3/elftc.3.gz
OLD_FILES+=usr/share/man/man3/elftc_bfd_find_target.3.gz
OLD_FILES+=usr/share/man/man3/elftc_copyfile.3.gz
OLD_FILES+=usr/share/man/man3/elftc_demangle.3.gz
OLD_FILES+=usr/share/man/man3/elftc_reloc_type_str.3.gz
OLD_FILES+=usr/share/man/man3/elftc_set_timestamps.3.gz
OLD_FILES+=usr/share/man/man3/elftc_timestamp.3.gz
OLD_FILES+=usr/share/man/man3/elftc_string_table_create.3.gz
OLD_FILES+=usr/share/man/man3/elftc_version.3.gz
OLD_FILES+=usr/tests/usr.bin/yacc/Kyuafile
OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_calc1.y
OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_demo.y
OLD_FILES+=usr/tests/usr.bin/yacc/calc.y
OLD_FILES+=usr/tests/usr.bin/yacc/calc1.y
OLD_FILES+=usr/tests/usr.bin/yacc/calc2.y
OLD_FILES+=usr/tests/usr.bin/yacc/calc3.y
OLD_FILES+=usr/tests/usr.bin/yacc/code_calc.y
OLD_FILES+=usr/tests/usr.bin/yacc/code_debug.y
OLD_FILES+=usr/tests/usr.bin/yacc/code_error.y
OLD_FILES+=usr/tests/usr.bin/yacc/empty.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit1.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit2.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit3.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit4.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit5.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax1.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax10.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax11.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax12.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax13.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax14.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax15.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax16.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax17.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax18.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax19.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax2.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax20.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax21.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax22.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax23.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax24.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax25.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax26.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax27.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax3.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax4.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax5.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax6.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax7.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax7a.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax7b.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax8.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax8a.y
OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax9.y
OLD_FILES+=usr/tests/usr.bin/yacc/error.y
OLD_FILES+=usr/tests/usr.bin/yacc/grammar.y
OLD_FILES+=usr/tests/usr.bin/yacc/inherit0.y
OLD_FILES+=usr/tests/usr.bin/yacc/inherit1.y
OLD_FILES+=usr/tests/usr.bin/yacc/inherit2.y
OLD_FILES+=usr/tests/usr.bin/yacc/ok_syntax1.y
OLD_FILES+=usr/tests/usr.bin/yacc/pure_calc.y
OLD_FILES+=usr/tests/usr.bin/yacc/pure_error.y
OLD_FILES+=usr/tests/usr.bin/yacc/quote_calc.y
OLD_FILES+=usr/tests/usr.bin/yacc/quote_calc2.y
OLD_FILES+=usr/tests/usr.bin/yacc/quote_calc3.y
OLD_FILES+=usr/tests/usr.bin/yacc/quote_calc4.y
OLD_FILES+=usr/tests/usr.bin/yacc/run_test
OLD_FILES+=usr/tests/usr.bin/yacc/varsyntax_calc1.y
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/big_b.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/big_b.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/big_l.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/big_l.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc1.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc1.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc1.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc1.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc2.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc2.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc2.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc2.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc3.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc3.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc3.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc3.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_calc.code.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_calc.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_calc.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_calc.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_calc.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_error.code.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_error.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_error.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_error.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_error.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/empty.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/empty.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/empty.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/empty.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax1.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax1.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax1.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax1.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax10.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax10.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax10.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax10.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax11.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax11.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax11.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax11.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax12.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax12.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax12.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax12.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax13.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax13.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax13.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax13.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax14.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax14.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax14.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax14.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax15.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax15.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax15.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax15.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax16.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax16.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax16.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax16.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax17.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax17.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax17.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax17.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax18.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax18.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax18.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax18.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax19.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax19.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax19.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax19.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax2.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax2.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax2.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax2.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax20.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax20.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax20.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax20.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax21.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax21.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax21.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax21.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax22.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax22.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax22.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax22.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax23.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax23.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax23.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax23.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax24.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax24.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax24.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax24.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax25.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax25.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax25.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax25.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax26.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax26.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax26.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax26.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax27.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax27.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax27.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax27.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax3.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax3.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax3.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax3.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax4.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax4.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax4.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax4.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax5.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax5.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax5.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax5.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax6.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax6.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax6.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax6.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7a.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7a.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7a.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7a.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7b.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7b.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7b.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7b.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8a.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8a.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8a.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8a.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax9.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax9.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax9.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax9.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/error.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/error.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/error.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/error.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/grammar.dot
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/grammar.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/grammar.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/grammar.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/grammar.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/help.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/help.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_b_opt.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_b_opt.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_b_opt1.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_b_opt1.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_code_c.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_code_c.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_defines.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_defines.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_graph.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_graph.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_include.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_include.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_opts.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_opts.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_output.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_output.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_output1.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_output1.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_output2.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_output2.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_p_opt.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_p_opt.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_p_opt1.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_p_opt1.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_verbose.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_verbose.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/nostdin.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/nostdin.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/ok_syntax1.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/ok_syntax1.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/ok_syntax1.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/ok_syntax1.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_calc.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_calc.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_calc.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_calc.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_error.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_error.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_error.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_error.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc-s.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc-s.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc-s.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc-s.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2-s.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2-s.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2-s.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2-s.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3-s.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3-s.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3-s.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3-s.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4-s.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4-s.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4-s.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4-s.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/rename_debug.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/rename_debug.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/rename_debug.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/rename_debug.i
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/rename_debug.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/varsyntax_calc1.error
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/varsyntax_calc1.output
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/varsyntax_calc1.tab.c
OLD_FILES+=usr/tests/usr.bin/yacc/yacc/varsyntax_calc1.tab.h
OLD_FILES+=usr/tests/usr.bin/yacc/yacc_tests
OLD_DIRS+=usr/tests/usr.bin/yacc/yacc
OLD_DIRS+=usr/tests/usr.bin/yacc
.endif
.if ${MK_UNBOUND} == no
OLD_FILES+=etc/rc.d/local_unbound
OLD_FILES+=etc/unbound
OLD_FILES+=usr/lib/libprivateunbound.a
OLD_FILES+=usr/lib/libprivateunbound.so
OLD_LIBS+=usr/lib/libprivateunbound.so.5
OLD_FILES+=usr/lib/libprivateunbound_p.a
OLD_FILES+=usr/share/man/man5/local-unbound.conf.5.gz
OLD_FILES+=usr/share/man/man8/local-unbound-anchor.8.gz
OLD_FILES+=usr/share/man/man8/local-unbound-checkconf.8.gz
OLD_FILES+=usr/share/man/man8/local-unbound-control.8.gz
OLD_FILES+=usr/share/man/man8/local-unbound.8.gz
OLD_FILES+=usr/sbin/local-unbound-setup
OLD_FILES+=usr/sbin/local-unbound
OLD_FILES+=usr/sbin/local-unbound-anchor
OLD_FILES+=usr/sbin/local-unbound-checkconf
OLD_FILES+=usr/sbin/local-unbound-control
.endif
.if ${MK_USB} == no
OLD_FILES+=etc/devd/uath.conf
OLD_FILES+=etc/devd/uauth.conf
OLD_FILES+=etc/devd/ulpt.conf
OLD_FILES+=etc/devd/usb.conf
OLD_FILES+=usr/bin/usbhidaction
OLD_FILES+=usr/bin/usbhidctl
OLD_FILES+=usr/include/libusb.h
OLD_FILES+=usr/include/libusb20.h
OLD_FILES+=usr/include/libusb20_desc.h
OLD_FILES+=usr/include/usb.h
OLD_FILES+=usr/include/usbhid.h
OLD_FILES+=usr/lib/libusb.a
OLD_FILES+=usr/lib/libusb.so
OLD_LIBS+=usr/lib/libusb.so.3
OLD_FILES+=usr/lib/libusb_p.a
OLD_FILES+=usr/lib/libusbhid.a
OLD_FILES+=usr/lib/libusbhid.so
OLD_LIBS+=usr/lib/libusbhid.so.4
OLD_FILES+=usr/lib/libusbhid_p.a
OLD_FILES+=usr/libdata/pkgconfig/libusb-0.1.pc
OLD_FILES+=usr/libdata/pkgconfig/libusb-1.0.pc
OLD_FILES+=usr/libdata/pkgconfig/libusb-2.0.pc
OLD_FILES+=usr/sbin/uathload
OLD_FILES+=usr/sbin/uhsoctl
OLD_FILES+=usr/sbin/usbconfig
OLD_FILES+=usr/sbin/usbdump
OLD_FILES+=usr/share/examples/libusb20/Makefile
OLD_FILES+=usr/share/examples/libusb20/README
OLD_FILES+=usr/share/examples/libusb20/bulk.c
OLD_FILES+=usr/share/examples/libusb20/control.c
OLD_FILES+=usr/share/examples/libusb20/util.c
OLD_FILES+=usr/share/examples/libusb20/util.h
OLD_DIRS+=usr/share/examples/libusb20
OLD_FILES+=usr/share/firmware/ar5523.bin
OLD_FILES+=usr/share/man/man1/uhsoctl.1.gz
OLD_FILES+=usr/share/man/man1/usbhidaction.1.gz
OLD_FILES+=usr/share/man/man1/usbhidctl.1.gz
OLD_FILES+=usr/share/man/man3/hid_dispose_report_desc.3.gz
OLD_FILES+=usr/share/man/man3/hid_end_parse.3.gz
OLD_FILES+=usr/share/man/man3/hid_get_data.3.gz
OLD_FILES+=usr/share/man/man3/hid_get_item.3.gz
OLD_FILES+=usr/share/man/man3/hid_get_report_desc.3.gz
OLD_FILES+=usr/share/man/man3/hid_init.3.gz
OLD_FILES+=usr/share/man/man3/hid_locate.3.gz
OLD_FILES+=usr/share/man/man3/hid_report_size.3.gz
OLD_FILES+=usr/share/man/man3/hid_set_data.3.gz
OLD_FILES+=usr/share/man/man3/hid_start_parse.3.gz
OLD_FILES+=usr/share/man/man3/hid_usage_in_page.3.gz
OLD_FILES+=usr/share/man/man3/hid_usage_page.3.gz
OLD_FILES+=usr/share/man/man3/libusb.3.gz
OLD_FILES+=usr/share/man/man3/libusb20.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_be_add_dev_quirk.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_be_alloc_default.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_be_dequeue_device.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_be_device_foreach.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_be_enqueue_device.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_be_free.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_be_get_dev_quirk.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_be_get_quirk_name.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_be_get_template.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_be_remove_dev_quirk.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_be_set_template.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_desc_foreach.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_alloc.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_alloc_config.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_check_connected.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_close.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_detach_kernel_driver.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_free.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_address.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_backend_name.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_bus_number.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_config_index.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_debug.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_desc.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_device_desc.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_fd.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_iface_desc.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_info.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_mode.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_parent_address.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_parent_port.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_port_path.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_power_mode.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_power_usage.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_get_speed.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_kernel_driver_active.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_open.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_process.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_req_string_simple_sync.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_req_string_sync.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_request_sync.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_reset.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_set_alt_index.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_set_config_index.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_set_debug.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_set_power_mode.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_dev_wait_process.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_error_name.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_me_decode.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_me_encode.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_me_get_1.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_me_get_2.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_strerror.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_bulk_intr_sync.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_callback_wrapper.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_clear_stall_sync.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_close.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_drain.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_get_actual_frames.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_get_actual_length.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_get_length.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_get_max_frames.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_get_max_packet_length.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_get_max_total_length.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_get_pointer.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_get_priv_sc0.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_get_priv_sc1.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_get_status.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_get_time_complete.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_open.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_pending.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_set_buffer.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_set_callback.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_set_flags.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_set_length.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_set_priv_sc0.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_set_priv_sc1.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_set_timeout.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_set_total_frames.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_setup_bulk.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_setup_control.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_setup_intr.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_setup_isoc.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_start.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_stop.3.gz
OLD_FILES+=usr/share/man/man3/libusb20_tr_submit.3.gz
OLD_FILES+=usr/share/man/man3/libusb_alloc_transfer.3.gz
OLD_FILES+=usr/share/man/man3/libusb_attach_kernel_driver.3.gz
OLD_FILES+=usr/share/man/man3/libusb_bulk_transfer.3.gz
OLD_FILES+=usr/share/man/man3/libusb_cancel_transfer.3.gz
OLD_FILES+=usr/share/man/man3/libusb_check_connected.3.gz
OLD_FILES+=usr/share/man/man3/libusb_claim_interface.3.gz
OLD_FILES+=usr/share/man/man3/libusb_clear_halt.3.gz
OLD_FILES+=usr/share/man/man3/libusb_close.3.gz
OLD_FILES+=usr/share/man/man3/libusb_control_transfer.3.gz
OLD_FILES+=usr/share/man/man3/libusb_detach_kernel_driver.3.gz
OLD_FILES+=usr/share/man/man3/libusb_detach_kernel_driver_np.3.gz
OLD_FILES+=usr/share/man/man3/libusb_error_name.3.gz
OLD_FILES+=usr/share/man/man3/libusb_event_handler_active.3.gz
OLD_FILES+=usr/share/man/man3/libusb_event_handling_ok.3.gz
OLD_FILES+=usr/share/man/man3/libusb_exit.3.gz
OLD_FILES+=usr/share/man/man3/libusb_free_bos_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/libusb_free_config_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/libusb_free_device_list.3.gz
OLD_FILES+=usr/share/man/man3/libusb_free_ss_endpoint_comp.3.gz
OLD_FILES+=usr/share/man/man3/libusb_free_transfer.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_active_config_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_bus_number.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_config_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_config_descriptor_by_value.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_configuration.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_device.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_device_address.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_device_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_device_list.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_device_speed.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_driver.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_driver_np.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_max_iso_packet_size.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_max_packet_size.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_next_timeout.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_pollfds.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_string_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/libusb_get_string_descriptor_ascii.3.gz
OLD_FILES+=usr/share/man/man3/libusb_handle_events.3.gz
OLD_FILES+=usr/share/man/man3/libusb_handle_events_completed.3.gz
OLD_FILES+=usr/share/man/man3/libusb_handle_events_locked.3.gz
OLD_FILES+=usr/share/man/man3/libusb_handle_events_timeout.3.gz
OLD_FILES+=usr/share/man/man3/libusb_handle_events_timeout_completed.3.gz
OLD_FILES+=usr/share/man/man3/libusb_init.3.gz
OLD_FILES+=usr/share/man/man3/libusb_interrupt_transfer.3.gz
OLD_FILES+=usr/share/man/man3/libusb_kernel_driver_active.3.gz
OLD_FILES+=usr/share/man/man3/libusb_lock_event_waiters.3.gz
OLD_FILES+=usr/share/man/man3/libusb_lock_events.3.gz
OLD_FILES+=usr/share/man/man3/libusb_open.3.gz
OLD_FILES+=usr/share/man/man3/libusb_open_device_with_vid_pid.3.gz
OLD_FILES+=usr/share/man/man3/libusb_parse_bos_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/libusb_parse_ss_endpoint_comp.3.gz
OLD_FILES+=usr/share/man/man3/libusb_ref_device.3.gz
OLD_FILES+=usr/share/man/man3/libusb_release_interface.3.gz
OLD_FILES+=usr/share/man/man3/libusb_reset_device.3.gz
OLD_FILES+=usr/share/man/man3/libusb_set_configuration.3.gz
OLD_FILES+=usr/share/man/man3/libusb_set_debug.3.gz
OLD_FILES+=usr/share/man/man3/libusb_set_interface_alt_setting.3.gz
OLD_FILES+=usr/share/man/man3/libusb_set_pollfd_notifiers.3.gz
OLD_FILES+=usr/share/man/man3/libusb_strerror.3.gz
OLD_FILES+=usr/share/man/man3/libusb_submit_transfer.3.gz
OLD_FILES+=usr/share/man/man3/libusb_try_lock_events.3.gz
OLD_FILES+=usr/share/man/man3/libusb_unlock_event_waiters.3.gz
OLD_FILES+=usr/share/man/man3/libusb_unlock_events.3.gz
OLD_FILES+=usr/share/man/man3/libusb_unref_device.3.gz
OLD_FILES+=usr/share/man/man3/libusb_wait_for_event.3.gz
OLD_FILES+=usr/share/man/man3/libusbhid.3.gz
OLD_FILES+=usr/share/man/man3/usb.3.gz
OLD_FILES+=usr/share/man/man3/usb_bulk_read.3.gz
OLD_FILES+=usr/share/man/man3/usb_bulk_write.3.gz
OLD_FILES+=usr/share/man/man3/usb_check_connected.3.gz
OLD_FILES+=usr/share/man/man3/usb_claim_interface.3.gz
OLD_FILES+=usr/share/man/man3/usb_clear_halt.3.gz
OLD_FILES+=usr/share/man/man3/usb_close.3.gz
OLD_FILES+=usr/share/man/man3/usb_control_msg.3.gz
OLD_FILES+=usr/share/man/man3/usb_destroy_configuration.3.gz
OLD_FILES+=usr/share/man/man3/usb_device.3.gz
OLD_FILES+=usr/share/man/man3/usb_fetch_and_parse_descriptors.3.gz
OLD_FILES+=usr/share/man/man3/usb_find_busses.3.gz
OLD_FILES+=usr/share/man/man3/usb_find_devices.3.gz
OLD_FILES+=usr/share/man/man3/usb_get_busses.3.gz
OLD_FILES+=usr/share/man/man3/usb_get_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/usb_get_descriptor_by_endpoint.3.gz
OLD_FILES+=usr/share/man/man3/usb_get_string.3.gz
OLD_FILES+=usr/share/man/man3/usb_get_string_simple.3.gz
OLD_FILES+=usr/share/man/man3/usb_init.3.gz
OLD_FILES+=usr/share/man/man3/usb_interrupt_read.3.gz
OLD_FILES+=usr/share/man/man3/usb_interrupt_write.3.gz
OLD_FILES+=usr/share/man/man3/usb_open.3.gz
OLD_FILES+=usr/share/man/man3/usb_parse_configuration.3.gz
OLD_FILES+=usr/share/man/man3/usb_parse_descriptor.3.gz
OLD_FILES+=usr/share/man/man3/usb_release_interface.3.gz
OLD_FILES+=usr/share/man/man3/usb_reset.3.gz
OLD_FILES+=usr/share/man/man3/usb_resetep.3.gz
OLD_FILES+=usr/share/man/man3/usb_set_altinterface.3.gz
OLD_FILES+=usr/share/man/man3/usb_set_configuration.3.gz
OLD_FILES+=usr/share/man/man3/usb_set_debug.3.gz
OLD_FILES+=usr/share/man/man3/usb_strerror.3.gz
OLD_FILES+=usr/share/man/man3/usbhid.3.gz
OLD_FILES+=usr/share/man/man4/if_otus.4.gz
OLD_FILES+=usr/share/man/man4/if_rsu.4.gz
OLD_FILES+=usr/share/man/man4/if_rtwn_usb.4.gz
OLD_FILES+=usr/share/man/man4/if_rum.4.gz
OLD_FILES+=usr/share/man/man4/if_run.4.gz
OLD_FILES+=usr/share/man/man4/if_zyd.4.gz
OLD_FILES+=usr/share/man/man4/otus.4.gz
OLD_FILES+=usr/share/man/man4/otusfw.4.gz
OLD_FILES+=usr/share/man/man4/rsu.4.gz
OLD_FILES+=usr/share/man/man4/rsufw.4.gz
OLD_FILES+=usr/share/man/man4/rtwn_usb.4.gz
OLD_FILES+=usr/share/man/man4/rum.4.gz
OLD_FILES+=usr/share/man/man4/run.4.gz
OLD_FILES+=usr/share/man/man4/runfw.4.gz
OLD_FILES+=usr/share/man/man4/u3g.4.gz
OLD_FILES+=usr/share/man/man4/u3gstub.4.gz
OLD_FILES+=usr/share/man/man4/uark.4.gz
OLD_FILES+=usr/share/man/man4/uart.4.gz
OLD_FILES+=usr/share/man/man4/uath.4.gz
OLD_FILES+=usr/share/man/man4/ubsa.4.gz
OLD_FILES+=usr/share/man/man4/ubser.4.gz
OLD_FILES+=usr/share/man/man4/ubtbcmfw.4.gz
OLD_FILES+=usr/share/man/man4/uchcom.4.gz
OLD_FILES+=usr/share/man/man4/ucom.4.gz
OLD_FILES+=usr/share/man/man4/ucycom.4.gz
OLD_FILES+=usr/share/man/man4/udav.4.gz
OLD_FILES+=usr/share/man/man4/udbp.4.gz
OLD_FILES+=usr/share/man/man4/uep.4.gz
OLD_FILES+=usr/share/man/man4/ufm.4.gz
OLD_FILES+=usr/share/man/man4/ufoma.4.gz
OLD_FILES+=usr/share/man/man4/uftdi.4.gz
OLD_FILES+=usr/share/man/man4/ugen.4.gz
OLD_FILES+=usr/share/man/man4/uhci.4.gz
OLD_FILES+=usr/share/man/man4/uhid.4.gz
OLD_FILES+=usr/share/man/man4/uhso.4.gz
OLD_FILES+=usr/share/man/man4/uipaq.4.gz
OLD_FILES+=usr/share/man/man4/ukbd.4.gz
OLD_FILES+=usr/share/man/man4/uled.4.gz
OLD_FILES+=usr/share/man/man4/ulpt.4.gz
OLD_FILES+=usr/share/man/man4/umass.4.gz
OLD_FILES+=usr/share/man/man4/umcs.4.gz
OLD_FILES+=usr/share/man/man4/umct.4.gz
OLD_FILES+=usr/share/man/man4/umodem.4.gz
OLD_FILES+=usr/share/man/man4/umoscom.4.gz
OLD_FILES+=usr/share/man/man4/ums.4.gz
OLD_FILES+=usr/share/man/man4/unix.4.gz
OLD_FILES+=usr/share/man/man4/upgt.4.gz
OLD_FILES+=usr/share/man/man4/uplcom.4.gz
OLD_FILES+=usr/share/man/man4/ural.4.gz
OLD_FILES+=usr/share/man/man4/urio.4.gz
OLD_FILES+=usr/share/man/man4/urndis.4.gz
OLD_FILES+=usr/share/man/man4/urtw.4.gz
OLD_FILES+=usr/share/man/man4/usb.4.gz
OLD_FILES+=usr/share/man/man4/usb_quirk.4.gz
OLD_FILES+=usr/share/man/man4/usb_template.4.gz
OLD_FILES+=usr/share/man/man4/usfs.4.gz
OLD_FILES+=usr/share/man/man4/uslcom.4.gz
OLD_FILES+=usr/share/man/man4/uvisor.4.gz
OLD_FILES+=usr/share/man/man4/uvscom.4.gz
OLD_FILES+=usr/share/man/man4/zyd.4.gz
OLD_FILES+=usr/share/man/man8/uathload.8.gz
OLD_FILES+=usr/share/man/man8/usbconfig.8.gz
OLD_FILES+=usr/share/man/man8/usbdump.8.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_alloc_buffer.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_attach.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_detach.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_free_buffer.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_get_data.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_get_data_buffer.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_get_data_error.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_get_data_linear.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_put_bytes_max.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_put_data.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_put_data_buffer.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_put_data_error.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_put_data_linear.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_reset.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_softc.9.gz
OLD_FILES+=usr/share/man/man9/usb_fifo_wakeup.9.gz
OLD_FILES+=usr/share/man/man9/usbd_do_request.9.gz
OLD_FILES+=usr/share/man/man9/usbd_do_request_flags.9.gz
OLD_FILES+=usr/share/man/man9/usbd_errstr.9.gz
OLD_FILES+=usr/share/man/man9/usbd_lookup_id_by_info.9.gz
OLD_FILES+=usr/share/man/man9/usbd_lookup_id_by_uaa.9.gz
OLD_FILES+=usr/share/man/man9/usbd_transfer_clear_stall.9.gz
OLD_FILES+=usr/share/man/man9/usbd_transfer_drain.9.gz
OLD_FILES+=usr/share/man/man9/usbd_transfer_pending.9.gz
OLD_FILES+=usr/share/man/man9/usbd_transfer_poll.9.gz
OLD_FILES+=usr/share/man/man9/usbd_transfer_setup.9.gz
OLD_FILES+=usr/share/man/man9/usbd_transfer_start.9.gz
OLD_FILES+=usr/share/man/man9/usbd_transfer_stop.9.gz
OLD_FILES+=usr/share/man/man9/usbd_transfer_submit.9.gz
OLD_FILES+=usr/share/man/man9/usbd_transfer_unsetup.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_clr_flag.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_frame_data.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_frame_len.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_get_frame.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_get_priv.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_is_stalled.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_max_framelen.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_max_frames.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_max_len.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_set_flag.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_set_frame_data.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_set_frame_len.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_set_frame_offset.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_set_frames.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_set_interval.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_set_priv.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_set_stall.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_set_timeout.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_softc.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_state.9.gz
OLD_FILES+=usr/share/man/man9/usbd_xfer_status.9.gz
OLD_FILES+=usr/share/man/man9/usbdi.9.gz
OLD_FILES+=usr/share/misc/usb_hid_usages
OLD_FILES+=usr/share/misc/usbdevs
.endif
.if ${MK_UTMPX} == no
OLD_FILES+=etc/periodic/monthly/200.accounting
OLD_FILES+=etc/rc.d/utx
OLD_FILES+=usr/bin/last
OLD_FILES+=usr/bin/users
OLD_FILES+=usr/bin/who
OLD_FILES+=usr/sbin/ac
OLD_FILES+=usr/sbin/lastlogin
OLD_FILES+=usr/sbin/utx
OLD_FILES+=usr/share/man/man1/last.1.gz
OLD_FILES+=usr/share/man/man1/users.1.gz
OLD_FILES+=usr/share/man/man1/who.1.gz
OLD_FILES+=usr/share/man/man8/ac.8.gz
OLD_FILES+=usr/share/man/man8/lastlogin.8.gz
OLD_FILES+=usr/share/man/man8/utx.8.gz
.endif
.if ${MK_VI} == no
OLD_FILES+=etc/rc.d/virecover
OLD_FILES+=rescue/ex
OLD_FILES+=rescue/vi
OLD_FILES+=usr/bin/ex
OLD_FILES+=usr/bin/nex
OLD_FILES+=usr/bin/nvi
OLD_FILES+=usr/bin/nview
OLD_FILES+=usr/bin/vi
OLD_FILES+=usr/bin/view
OLD_FILES+=usr/share/man/man1/ex.1.gz
OLD_FILES+=usr/share/man/man1/nex.1.gz
OLD_FILES+=usr/share/man/man1/nvi.1.gz
OLD_FILES+=usr/share/man/man1/nview.1.gz
OLD_FILES+=usr/share/man/man1/vi.1.gz
OLD_FILES+=usr/share/man/man1/view.1.gz
. if exists(${DESTDIR}/usr/share/vi)
VI_DIRS!=find ${DESTDIR}/usr/share/vi -type d \
| sed -e 's,^${DESTDIR}/,,'; echo
VI_FILES!=find ${DESTDIR}/usr/share/vi \! -type d \
| sed -e 's,^${DESTDIR}/,,'; echo
OLD_DIRS+=${VI_DIRS}
OLD_FILES+=${VI_FILES}
. endif
.endif
.if ${MK_WIRELESS} == no
OLD_FILES+=etc/regdomain.xml
OLD_FILES+=etc/rc.d/hostapd
OLD_FILES+=etc/rc.d/wpa_supplicant
OLD_FILES+=usr/sbin/ancontrol
OLD_FILES+=usr/sbin/hostapd
OLD_FILES+=usr/sbin/hostapd_cli
OLD_FILES+=usr/sbin/ndis_events
OLD_FILES+=usr/sbin/wlandebug
OLD_FILES+=usr/sbin/wpa_cli
OLD_FILES+=usr/sbin/wpa_passphrase
OLD_FILES+=usr/sbin/wpa_supplicant
OLD_FILES+=usr/share/examples/etc/regdomain.xml
OLD_FILES+=usr/share/examples/etc/wpa_supplicant.conf
OLD_FILES+=usr/share/examples/hostapd/hostapd.conf
OLD_FILES+=usr/share/examples/hostapd/hostapd.eap_user
OLD_FILES+=usr/share/examples/hostapd/hostapd.wpa_psk
OLD_DIRS+=usr/share/examples/hostapd
OLD_FILES+=usr/share/man/man5/hostapd.conf.5.gz
OLD_FILES+=usr/share/man/man5/wpa_supplicant.conf.5.gz
OLD_FILES+=usr/share/man/man8/ancontrol.8.gz
OLD_FILES+=usr/share/man/man8/hostapd.8.gz
OLD_FILES+=usr/share/man/man8/hostapd_cli.8.gz
OLD_FILES+=usr/share/man/man8/ndis_events.8.gz
OLD_FILES+=usr/share/man/man8/wlandebug.8.gz
OLD_FILES+=usr/share/man/man8/wpa_cli.8.gz
OLD_FILES+=usr/share/man/man8/wpa_passphrase.8.gz
OLD_FILES+=usr/share/man/man8/wpa_supplicant.8.gz
OLD_FILES+=usr/lib/snmp_wlan.so
OLD_LIBS+=usr/lib/snmp_wlan.so.6
# bsnmp module
OLD_FILES+=usr/share/man/man3/snmp_wlan.3.gz
OLD_FILES+=usr/share/snmp/defs/wlan_tree.def
OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-WIRELESS-MIB.txt
.endif
.if ${MK_SVNLITE} == no || ${MK_SVN} == yes
OLD_FILES+=usr/bin/svnlite
OLD_FILES+=usr/bin/svnliteadmin
OLD_FILES+=usr/bin/svnlitebench
OLD_FILES+=usr/bin/svnlitedumpfilter
OLD_FILES+=usr/bin/svnlitefsfs
OLD_FILES+=usr/bin/svnlitelook
OLD_FILES+=usr/bin/svnlitemucc
OLD_FILES+=usr/bin/svnliterdump
OLD_FILES+=usr/bin/svnliteserve
OLD_FILES+=usr/bin/svnlitesync
OLD_FILES+=usr/bin/svnliteversion
OLD_FILES+=usr/share/man/man1/svnlite.1.gz
.endif
.if ${MK_SVN} == no
OLD_FILES+=usr/bin/svn
OLD_FILES+=usr/bin/svnadmin
OLD_FILES+=usr/bin/svnbench
OLD_FILES+=usr/bin/svndumpfilter
OLD_FILES+=usr/bin/svnfsfs
OLD_FILES+=usr/bin/svnlook
OLD_FILES+=usr/bin/svnmucc
OLD_FILES+=usr/bin/svnrdump
OLD_FILES+=usr/bin/svnserve
OLD_FILES+=usr/bin/svnsync
OLD_FILES+=usr/bin/svnversion
.endif
.if ${MK_HYPERV} == no
OLD_FILES+=etc/devd/hyperv.conf
OLD_FILES+=usr/libexec/hyperv/hv_set_ifconfig
OLD_FILES+=usr/libexec/hyperv/hv_get_dns_info
OLD_FILES+=usr/libexec/hyperv/hv_get_dhcp_info
OLD_FILES+=usr/sbin/hv_kvp_daemon
OLD_FILES+=usr/sbin/hv_vss_daemon
OLD_FILES+=usr/share/man/man8/hv_kvp_daemon.8.gz
.endif
.if ${MK_ZONEINFO} == no
OLD_FILES+=usr/share/zoneinfo/Africa/Abidjan
OLD_FILES+=usr/share/zoneinfo/Africa/Accra
OLD_FILES+=usr/share/zoneinfo/Africa/Addis_Ababa
OLD_FILES+=usr/share/zoneinfo/Africa/Algiers
OLD_FILES+=usr/share/zoneinfo/Africa/Asmara
OLD_FILES+=usr/share/zoneinfo/Africa/Bamako
OLD_FILES+=usr/share/zoneinfo/Africa/Bangui
OLD_FILES+=usr/share/zoneinfo/Africa/Banjul
OLD_FILES+=usr/share/zoneinfo/Africa/Bissau
OLD_FILES+=usr/share/zoneinfo/Africa/Blantyre
OLD_FILES+=usr/share/zoneinfo/Africa/Brazzaville
OLD_FILES+=usr/share/zoneinfo/Africa/Bujumbura
OLD_FILES+=usr/share/zoneinfo/Africa/Cairo
OLD_FILES+=usr/share/zoneinfo/Africa/Casablanca
OLD_FILES+=usr/share/zoneinfo/Africa/Ceuta
OLD_FILES+=usr/share/zoneinfo/Africa/Conakry
OLD_FILES+=usr/share/zoneinfo/Africa/Dakar
OLD_FILES+=usr/share/zoneinfo/Africa/Dar_es_Salaam
OLD_FILES+=usr/share/zoneinfo/Africa/Djibouti
OLD_FILES+=usr/share/zoneinfo/Africa/Douala
OLD_FILES+=usr/share/zoneinfo/Africa/El_Aaiun
OLD_FILES+=usr/share/zoneinfo/Africa/Freetown
OLD_FILES+=usr/share/zoneinfo/Africa/Gaborone
OLD_FILES+=usr/share/zoneinfo/Africa/Harare
OLD_FILES+=usr/share/zoneinfo/Africa/Johannesburg
OLD_FILES+=usr/share/zoneinfo/Africa/Juba
OLD_FILES+=usr/share/zoneinfo/Africa/Kampala
OLD_FILES+=usr/share/zoneinfo/Africa/Khartoum
OLD_FILES+=usr/share/zoneinfo/Africa/Kigali
OLD_FILES+=usr/share/zoneinfo/Africa/Kinshasa
OLD_FILES+=usr/share/zoneinfo/Africa/Lagos
OLD_FILES+=usr/share/zoneinfo/Africa/Libreville
OLD_FILES+=usr/share/zoneinfo/Africa/Lome
OLD_FILES+=usr/share/zoneinfo/Africa/Luanda
OLD_FILES+=usr/share/zoneinfo/Africa/Lubumbashi
OLD_FILES+=usr/share/zoneinfo/Africa/Lusaka
OLD_FILES+=usr/share/zoneinfo/Africa/Malabo
OLD_FILES+=usr/share/zoneinfo/Africa/Maputo
OLD_FILES+=usr/share/zoneinfo/Africa/Maseru
OLD_FILES+=usr/share/zoneinfo/Africa/Mbabane
OLD_FILES+=usr/share/zoneinfo/Africa/Mogadishu
OLD_FILES+=usr/share/zoneinfo/Africa/Monrovia
OLD_FILES+=usr/share/zoneinfo/Africa/Nairobi
OLD_FILES+=usr/share/zoneinfo/Africa/Ndjamena
OLD_FILES+=usr/share/zoneinfo/Africa/Niamey
OLD_FILES+=usr/share/zoneinfo/Africa/Nouakchott
OLD_FILES+=usr/share/zoneinfo/Africa/Ouagadougou
OLD_FILES+=usr/share/zoneinfo/Africa/Porto-Novo
OLD_FILES+=usr/share/zoneinfo/Africa/Sao_Tome
OLD_FILES+=usr/share/zoneinfo/Africa/Tripoli
OLD_FILES+=usr/share/zoneinfo/Africa/Tunis
OLD_FILES+=usr/share/zoneinfo/Africa/Windhoek
OLD_FILES+=usr/share/zoneinfo/America/Adak
OLD_FILES+=usr/share/zoneinfo/America/Anchorage
OLD_FILES+=usr/share/zoneinfo/America/Anguilla
OLD_FILES+=usr/share/zoneinfo/America/Antigua
OLD_FILES+=usr/share/zoneinfo/America/Araguaina
OLD_FILES+=usr/share/zoneinfo/America/Argentina/Buenos_Aires
OLD_FILES+=usr/share/zoneinfo/America/Argentina/Catamarca
OLD_FILES+=usr/share/zoneinfo/America/Argentina/Cordoba
OLD_FILES+=usr/share/zoneinfo/America/Argentina/Jujuy
OLD_FILES+=usr/share/zoneinfo/America/Argentina/La_Rioja
OLD_FILES+=usr/share/zoneinfo/America/Argentina/Mendoza
OLD_FILES+=usr/share/zoneinfo/America/Argentina/Rio_Gallegos
OLD_FILES+=usr/share/zoneinfo/America/Argentina/Salta
OLD_FILES+=usr/share/zoneinfo/America/Argentina/San_Juan
OLD_FILES+=usr/share/zoneinfo/America/Argentina/San_Luis
OLD_FILES+=usr/share/zoneinfo/America/Argentina/Tucuman
OLD_FILES+=usr/share/zoneinfo/America/Argentina/Ushuaia
OLD_FILES+=usr/share/zoneinfo/America/Aruba
OLD_FILES+=usr/share/zoneinfo/America/Asuncion
OLD_FILES+=usr/share/zoneinfo/America/Atikokan
OLD_FILES+=usr/share/zoneinfo/America/Bahia
OLD_FILES+=usr/share/zoneinfo/America/Bahia_Banderas
OLD_FILES+=usr/share/zoneinfo/America/Barbados
OLD_FILES+=usr/share/zoneinfo/America/Belem
OLD_FILES+=usr/share/zoneinfo/America/Belize
OLD_FILES+=usr/share/zoneinfo/America/Blanc-Sablon
OLD_FILES+=usr/share/zoneinfo/America/Boa_Vista
OLD_FILES+=usr/share/zoneinfo/America/Bogota
OLD_FILES+=usr/share/zoneinfo/America/Boise
OLD_FILES+=usr/share/zoneinfo/America/Cambridge_Bay
OLD_FILES+=usr/share/zoneinfo/America/Campo_Grande
OLD_FILES+=usr/share/zoneinfo/America/Cancun
OLD_FILES+=usr/share/zoneinfo/America/Caracas
OLD_FILES+=usr/share/zoneinfo/America/Cayenne
OLD_FILES+=usr/share/zoneinfo/America/Cayman
OLD_FILES+=usr/share/zoneinfo/America/Chicago
OLD_FILES+=usr/share/zoneinfo/America/Chihuahua
OLD_FILES+=usr/share/zoneinfo/America/Ciudad_Juarez
OLD_FILES+=usr/share/zoneinfo/America/Costa_Rica
OLD_FILES+=usr/share/zoneinfo/America/Creston
OLD_FILES+=usr/share/zoneinfo/America/Cuiaba
OLD_FILES+=usr/share/zoneinfo/America/Curacao
OLD_FILES+=usr/share/zoneinfo/America/Danmarkshavn
OLD_FILES+=usr/share/zoneinfo/America/Dawson
OLD_FILES+=usr/share/zoneinfo/America/Dawson_Creek
OLD_FILES+=usr/share/zoneinfo/America/Denver
OLD_FILES+=usr/share/zoneinfo/America/Detroit
OLD_FILES+=usr/share/zoneinfo/America/Dominica
OLD_FILES+=usr/share/zoneinfo/America/Edmonton
OLD_FILES+=usr/share/zoneinfo/America/Eirunepe
OLD_FILES+=usr/share/zoneinfo/America/El_Salvador
OLD_FILES+=usr/share/zoneinfo/America/Fortaleza
OLD_FILES+=usr/share/zoneinfo/America/Glace_Bay
OLD_FILES+=usr/share/zoneinfo/America/Godthab
OLD_FILES+=usr/share/zoneinfo/America/Goose_Bay
OLD_FILES+=usr/share/zoneinfo/America/Grand_Turk
OLD_FILES+=usr/share/zoneinfo/America/Grenada
OLD_FILES+=usr/share/zoneinfo/America/Guadeloupe
OLD_FILES+=usr/share/zoneinfo/America/Guatemala
OLD_FILES+=usr/share/zoneinfo/America/Guayaquil
OLD_FILES+=usr/share/zoneinfo/America/Guyana
OLD_FILES+=usr/share/zoneinfo/America/Halifax
OLD_FILES+=usr/share/zoneinfo/America/Havana
OLD_FILES+=usr/share/zoneinfo/America/Hermosillo
OLD_FILES+=usr/share/zoneinfo/America/Indiana/Indianapolis
OLD_FILES+=usr/share/zoneinfo/America/Indiana/Knox
OLD_FILES+=usr/share/zoneinfo/America/Indiana/Marengo
OLD_FILES+=usr/share/zoneinfo/America/Indiana/Petersburg
OLD_FILES+=usr/share/zoneinfo/America/Indiana/Tell_City
OLD_FILES+=usr/share/zoneinfo/America/Indiana/Vevay
OLD_FILES+=usr/share/zoneinfo/America/Indiana/Vincennes
OLD_FILES+=usr/share/zoneinfo/America/Indiana/Winamac
OLD_FILES+=usr/share/zoneinfo/America/Inuvik
OLD_FILES+=usr/share/zoneinfo/America/Iqaluit
OLD_FILES+=usr/share/zoneinfo/America/Jamaica
OLD_FILES+=usr/share/zoneinfo/America/Juneau
OLD_FILES+=usr/share/zoneinfo/America/Kentucky/Louisville
OLD_FILES+=usr/share/zoneinfo/America/Kentucky/Monticello
OLD_FILES+=usr/share/zoneinfo/America/Kralendijk
OLD_FILES+=usr/share/zoneinfo/America/La_Paz
OLD_FILES+=usr/share/zoneinfo/America/Lima
OLD_FILES+=usr/share/zoneinfo/America/Los_Angeles
OLD_FILES+=usr/share/zoneinfo/America/Lower_Princes
OLD_FILES+=usr/share/zoneinfo/America/Maceio
OLD_FILES+=usr/share/zoneinfo/America/Managua
OLD_FILES+=usr/share/zoneinfo/America/Manaus
OLD_FILES+=usr/share/zoneinfo/America/Marigot
OLD_FILES+=usr/share/zoneinfo/America/Martinique
OLD_FILES+=usr/share/zoneinfo/America/Matamoros
OLD_FILES+=usr/share/zoneinfo/America/Mazatlan
OLD_FILES+=usr/share/zoneinfo/America/Menominee
OLD_FILES+=usr/share/zoneinfo/America/Merida
OLD_FILES+=usr/share/zoneinfo/America/Metlakatla
OLD_FILES+=usr/share/zoneinfo/America/Mexico_City
OLD_FILES+=usr/share/zoneinfo/America/Miquelon
OLD_FILES+=usr/share/zoneinfo/America/Moncton
OLD_FILES+=usr/share/zoneinfo/America/Monterrey
OLD_FILES+=usr/share/zoneinfo/America/Montevideo
OLD_FILES+=usr/share/zoneinfo/America/Montreal
OLD_FILES+=usr/share/zoneinfo/America/Montserrat
OLD_FILES+=usr/share/zoneinfo/America/Nassau
OLD_FILES+=usr/share/zoneinfo/America/New_York
OLD_FILES+=usr/share/zoneinfo/America/Nipigon
OLD_FILES+=usr/share/zoneinfo/America/Nome
OLD_FILES+=usr/share/zoneinfo/America/Noronha
OLD_FILES+=usr/share/zoneinfo/America/North_Dakota/Beulah
OLD_FILES+=usr/share/zoneinfo/America/North_Dakota/Center
OLD_FILES+=usr/share/zoneinfo/America/North_Dakota/New_Salem
OLD_FILES+=usr/share/zoneinfo/America/Ojinaga
OLD_FILES+=usr/share/zoneinfo/America/Panama
OLD_FILES+=usr/share/zoneinfo/America/Pangnirtung
OLD_FILES+=usr/share/zoneinfo/America/Paramaribo
OLD_FILES+=usr/share/zoneinfo/America/Phoenix
OLD_FILES+=usr/share/zoneinfo/America/Port-au-Prince
OLD_FILES+=usr/share/zoneinfo/America/Port_of_Spain
OLD_FILES+=usr/share/zoneinfo/America/Porto_Velho
OLD_FILES+=usr/share/zoneinfo/America/Puerto_Rico
OLD_FILES+=usr/share/zoneinfo/America/Rainy_River
OLD_FILES+=usr/share/zoneinfo/America/Rankin_Inlet
OLD_FILES+=usr/share/zoneinfo/America/Recife
OLD_FILES+=usr/share/zoneinfo/America/Regina
OLD_FILES+=usr/share/zoneinfo/America/Resolute
OLD_FILES+=usr/share/zoneinfo/America/Rio_Branco
OLD_FILES+=usr/share/zoneinfo/America/Santa_Isabel
OLD_FILES+=usr/share/zoneinfo/America/Santarem
OLD_FILES+=usr/share/zoneinfo/America/Santiago
OLD_FILES+=usr/share/zoneinfo/America/Santo_Domingo
OLD_FILES+=usr/share/zoneinfo/America/Sao_Paulo
OLD_FILES+=usr/share/zoneinfo/America/Scoresbysund
OLD_FILES+=usr/share/zoneinfo/America/Sitka
OLD_FILES+=usr/share/zoneinfo/America/St_Barthelemy
OLD_FILES+=usr/share/zoneinfo/America/St_Johns
OLD_FILES+=usr/share/zoneinfo/America/St_Kitts
OLD_FILES+=usr/share/zoneinfo/America/St_Lucia
OLD_FILES+=usr/share/zoneinfo/America/St_Thomas
OLD_FILES+=usr/share/zoneinfo/America/St_Vincent
OLD_FILES+=usr/share/zoneinfo/America/Swift_Current
OLD_FILES+=usr/share/zoneinfo/America/Tegucigalpa
OLD_FILES+=usr/share/zoneinfo/America/Thule
OLD_FILES+=usr/share/zoneinfo/America/Thunder_Bay
OLD_FILES+=usr/share/zoneinfo/America/Tijuana
OLD_FILES+=usr/share/zoneinfo/America/Toronto
OLD_FILES+=usr/share/zoneinfo/America/Tortola
OLD_FILES+=usr/share/zoneinfo/America/Vancouver
OLD_FILES+=usr/share/zoneinfo/America/Whitehorse
OLD_FILES+=usr/share/zoneinfo/America/Winnipeg
OLD_FILES+=usr/share/zoneinfo/America/Yakutat
OLD_FILES+=usr/share/zoneinfo/America/Yellowknife
OLD_FILES+=usr/share/zoneinfo/Antarctica/Casey
OLD_FILES+=usr/share/zoneinfo/Antarctica/Davis
OLD_FILES+=usr/share/zoneinfo/Antarctica/DumontDUrville
OLD_FILES+=usr/share/zoneinfo/Antarctica/Macquarie
OLD_FILES+=usr/share/zoneinfo/Antarctica/Mawson
OLD_FILES+=usr/share/zoneinfo/Antarctica/McMurdo
OLD_FILES+=usr/share/zoneinfo/Antarctica/Palmer
OLD_FILES+=usr/share/zoneinfo/Antarctica/Rothera
OLD_FILES+=usr/share/zoneinfo/Antarctica/Syowa
OLD_FILES+=usr/share/zoneinfo/Antarctica/Troll
OLD_FILES+=usr/share/zoneinfo/Antarctica/Vostok
OLD_FILES+=usr/share/zoneinfo/Arctic/Longyearbyen
OLD_FILES+=usr/share/zoneinfo/Asia/Aden
OLD_FILES+=usr/share/zoneinfo/Asia/Almaty
OLD_FILES+=usr/share/zoneinfo/Asia/Amman
OLD_FILES+=usr/share/zoneinfo/Asia/Anadyr
OLD_FILES+=usr/share/zoneinfo/Asia/Aqtau
OLD_FILES+=usr/share/zoneinfo/Asia/Aqtobe
OLD_FILES+=usr/share/zoneinfo/Asia/Ashgabat
OLD_FILES+=usr/share/zoneinfo/Asia/Baghdad
OLD_FILES+=usr/share/zoneinfo/Asia/Bahrain
OLD_FILES+=usr/share/zoneinfo/Asia/Baku
OLD_FILES+=usr/share/zoneinfo/Asia/Bangkok
OLD_FILES+=usr/share/zoneinfo/Asia/Beirut
OLD_FILES+=usr/share/zoneinfo/Asia/Bishkek
OLD_FILES+=usr/share/zoneinfo/Asia/Brunei
OLD_FILES+=usr/share/zoneinfo/Asia/Chita
OLD_FILES+=usr/share/zoneinfo/Asia/Choibalsan
OLD_FILES+=usr/share/zoneinfo/Asia/Colombo
OLD_FILES+=usr/share/zoneinfo/Asia/Damascus
OLD_FILES+=usr/share/zoneinfo/Asia/Dhaka
OLD_FILES+=usr/share/zoneinfo/Asia/Dili
OLD_FILES+=usr/share/zoneinfo/Asia/Dubai
OLD_FILES+=usr/share/zoneinfo/Asia/Dushanbe
OLD_FILES+=usr/share/zoneinfo/Asia/Gaza
OLD_FILES+=usr/share/zoneinfo/Asia/Hebron
OLD_FILES+=usr/share/zoneinfo/Asia/Ho_Chi_Minh
OLD_FILES+=usr/share/zoneinfo/Asia/Hong_Kong
OLD_FILES+=usr/share/zoneinfo/Asia/Hovd
OLD_FILES+=usr/share/zoneinfo/Asia/Irkutsk
OLD_FILES+=usr/share/zoneinfo/Asia/Istanbul
OLD_FILES+=usr/share/zoneinfo/Asia/Jakarta
OLD_FILES+=usr/share/zoneinfo/Asia/Jayapura
OLD_FILES+=usr/share/zoneinfo/Asia/Jerusalem
OLD_FILES+=usr/share/zoneinfo/Asia/Kabul
OLD_FILES+=usr/share/zoneinfo/Asia/Kamchatka
OLD_FILES+=usr/share/zoneinfo/Asia/Karachi
OLD_FILES+=usr/share/zoneinfo/Asia/Kathmandu
OLD_FILES+=usr/share/zoneinfo/Asia/Khandyga
OLD_FILES+=usr/share/zoneinfo/Asia/Kolkata
OLD_FILES+=usr/share/zoneinfo/Asia/Krasnoyarsk
OLD_FILES+=usr/share/zoneinfo/Asia/Kuala_Lumpur
OLD_FILES+=usr/share/zoneinfo/Asia/Kuching
OLD_FILES+=usr/share/zoneinfo/Asia/Kuwait
OLD_FILES+=usr/share/zoneinfo/Asia/Macau
OLD_FILES+=usr/share/zoneinfo/Asia/Magadan
OLD_FILES+=usr/share/zoneinfo/Asia/Makassar
OLD_FILES+=usr/share/zoneinfo/Asia/Manila
OLD_FILES+=usr/share/zoneinfo/Asia/Muscat
OLD_FILES+=usr/share/zoneinfo/Asia/Nicosia
OLD_FILES+=usr/share/zoneinfo/Asia/Novokuznetsk
OLD_FILES+=usr/share/zoneinfo/Asia/Novosibirsk
OLD_FILES+=usr/share/zoneinfo/Asia/Omsk
OLD_FILES+=usr/share/zoneinfo/Asia/Oral
OLD_FILES+=usr/share/zoneinfo/Asia/Phnom_Penh
OLD_FILES+=usr/share/zoneinfo/Asia/Pontianak
OLD_FILES+=usr/share/zoneinfo/Asia/Pyongyang
OLD_FILES+=usr/share/zoneinfo/Asia/Qatar
OLD_FILES+=usr/share/zoneinfo/Asia/Qyzylorda
OLD_FILES+=usr/share/zoneinfo/Asia/Rangoon
OLD_FILES+=usr/share/zoneinfo/Asia/Riyadh
OLD_FILES+=usr/share/zoneinfo/Asia/Sakhalin
OLD_FILES+=usr/share/zoneinfo/Asia/Samarkand
OLD_FILES+=usr/share/zoneinfo/Asia/Seoul
OLD_FILES+=usr/share/zoneinfo/Asia/Shanghai
OLD_FILES+=usr/share/zoneinfo/Asia/Singapore
OLD_FILES+=usr/share/zoneinfo/Asia/Srednekolymsk
OLD_FILES+=usr/share/zoneinfo/Asia/Taipei
OLD_FILES+=usr/share/zoneinfo/Asia/Tashkent
OLD_FILES+=usr/share/zoneinfo/Asia/Tbilisi
OLD_FILES+=usr/share/zoneinfo/Asia/Tehran
OLD_FILES+=usr/share/zoneinfo/Asia/Thimphu
OLD_FILES+=usr/share/zoneinfo/Asia/Tokyo
OLD_FILES+=usr/share/zoneinfo/Asia/Ulaanbaatar
OLD_FILES+=usr/share/zoneinfo/Asia/Urumqi
OLD_FILES+=usr/share/zoneinfo/Asia/Ust-Nera
OLD_FILES+=usr/share/zoneinfo/Asia/Vientiane
OLD_FILES+=usr/share/zoneinfo/Asia/Vladivostok
OLD_FILES+=usr/share/zoneinfo/Asia/Yakutsk
OLD_FILES+=usr/share/zoneinfo/Asia/Yekaterinburg
OLD_FILES+=usr/share/zoneinfo/Asia/Yerevan
OLD_FILES+=usr/share/zoneinfo/Atlantic/Azores
OLD_FILES+=usr/share/zoneinfo/Atlantic/Bermuda
OLD_FILES+=usr/share/zoneinfo/Atlantic/Canary
OLD_FILES+=usr/share/zoneinfo/Atlantic/Cape_Verde
OLD_FILES+=usr/share/zoneinfo/Atlantic/Faroe
OLD_FILES+=usr/share/zoneinfo/Atlantic/Madeira
OLD_FILES+=usr/share/zoneinfo/Atlantic/Reykjavik
OLD_FILES+=usr/share/zoneinfo/Atlantic/South_Georgia
OLD_FILES+=usr/share/zoneinfo/Atlantic/St_Helena
OLD_FILES+=usr/share/zoneinfo/Atlantic/Stanley
OLD_FILES+=usr/share/zoneinfo/Australia/Adelaide
OLD_FILES+=usr/share/zoneinfo/Australia/Brisbane
OLD_FILES+=usr/share/zoneinfo/Australia/Broken_Hill
OLD_FILES+=usr/share/zoneinfo/Australia/Currie
OLD_FILES+=usr/share/zoneinfo/Australia/Darwin
OLD_FILES+=usr/share/zoneinfo/Australia/Eucla
OLD_FILES+=usr/share/zoneinfo/Australia/Hobart
OLD_FILES+=usr/share/zoneinfo/Australia/Lindeman
OLD_FILES+=usr/share/zoneinfo/Australia/Lord_Howe
OLD_FILES+=usr/share/zoneinfo/Australia/Melbourne
OLD_FILES+=usr/share/zoneinfo/Australia/Perth
OLD_FILES+=usr/share/zoneinfo/Australia/Sydney
OLD_FILES+=usr/share/zoneinfo/CET
OLD_FILES+=usr/share/zoneinfo/CST6CDT
OLD_FILES+=usr/share/zoneinfo/EET
OLD_FILES+=usr/share/zoneinfo/EST
OLD_FILES+=usr/share/zoneinfo/EST5EDT
OLD_FILES+=usr/share/zoneinfo/Etc/GMT
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+0
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+1
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+10
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+11
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+12
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+2
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+3
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+4
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+5
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+6
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+7
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+8
OLD_FILES+=usr/share/zoneinfo/Etc/GMT+9
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-0
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-1
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-10
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-11
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-12
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-13
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-14
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-2
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-3
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-4
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-5
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-6
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-7
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-8
OLD_FILES+=usr/share/zoneinfo/Etc/GMT-9
OLD_FILES+=usr/share/zoneinfo/Etc/GMT0
OLD_FILES+=usr/share/zoneinfo/Etc/Greenwich
OLD_FILES+=usr/share/zoneinfo/Etc/UCT
OLD_FILES+=usr/share/zoneinfo/Etc/UTC
OLD_FILES+=usr/share/zoneinfo/Etc/Universal
OLD_FILES+=usr/share/zoneinfo/Etc/Zulu
OLD_FILES+=usr/share/zoneinfo/Europe/Amsterdam
OLD_FILES+=usr/share/zoneinfo/Europe/Andorra
OLD_FILES+=usr/share/zoneinfo/Europe/Athens
OLD_FILES+=usr/share/zoneinfo/Europe/Belgrade
OLD_FILES+=usr/share/zoneinfo/Europe/Berlin
OLD_FILES+=usr/share/zoneinfo/Europe/Bratislava
OLD_FILES+=usr/share/zoneinfo/Europe/Brussels
OLD_FILES+=usr/share/zoneinfo/Europe/Bucharest
OLD_FILES+=usr/share/zoneinfo/Europe/Budapest
OLD_FILES+=usr/share/zoneinfo/Europe/Busingen
OLD_FILES+=usr/share/zoneinfo/Europe/Chisinau
OLD_FILES+=usr/share/zoneinfo/Europe/Copenhagen
OLD_FILES+=usr/share/zoneinfo/Europe/Dublin
OLD_FILES+=usr/share/zoneinfo/Europe/Gibraltar
OLD_FILES+=usr/share/zoneinfo/Europe/Guernsey
OLD_FILES+=usr/share/zoneinfo/Europe/Helsinki
OLD_FILES+=usr/share/zoneinfo/Europe/Isle_of_Man
OLD_FILES+=usr/share/zoneinfo/Europe/Istanbul
OLD_FILES+=usr/share/zoneinfo/Europe/Jersey
OLD_FILES+=usr/share/zoneinfo/Europe/Kaliningrad
OLD_FILES+=usr/share/zoneinfo/Europe/Kiev
OLD_FILES+=usr/share/zoneinfo/Europe/Lisbon
OLD_FILES+=usr/share/zoneinfo/Europe/Ljubljana
OLD_FILES+=usr/share/zoneinfo/Europe/London
OLD_FILES+=usr/share/zoneinfo/Europe/Luxembourg
OLD_FILES+=usr/share/zoneinfo/Europe/Madrid
OLD_FILES+=usr/share/zoneinfo/Europe/Malta
OLD_FILES+=usr/share/zoneinfo/Europe/Mariehamn
OLD_FILES+=usr/share/zoneinfo/Europe/Minsk
OLD_FILES+=usr/share/zoneinfo/Europe/Monaco
OLD_FILES+=usr/share/zoneinfo/Europe/Moscow
OLD_FILES+=usr/share/zoneinfo/Europe/Nicosia
OLD_FILES+=usr/share/zoneinfo/Europe/Oslo
OLD_FILES+=usr/share/zoneinfo/Europe/Paris
OLD_FILES+=usr/share/zoneinfo/Europe/Podgorica
OLD_FILES+=usr/share/zoneinfo/Europe/Prague
OLD_FILES+=usr/share/zoneinfo/Europe/Riga
OLD_FILES+=usr/share/zoneinfo/Europe/Rome
OLD_FILES+=usr/share/zoneinfo/Europe/Samara
OLD_FILES+=usr/share/zoneinfo/Europe/San_Marino
OLD_FILES+=usr/share/zoneinfo/Europe/Sarajevo
OLD_FILES+=usr/share/zoneinfo/Europe/Simferopol
OLD_FILES+=usr/share/zoneinfo/Europe/Skopje
OLD_FILES+=usr/share/zoneinfo/Europe/Sofia
OLD_FILES+=usr/share/zoneinfo/Europe/Stockholm
OLD_FILES+=usr/share/zoneinfo/Europe/Tallinn
OLD_FILES+=usr/share/zoneinfo/Europe/Tirane
OLD_FILES+=usr/share/zoneinfo/Europe/Uzhgorod
OLD_FILES+=usr/share/zoneinfo/Europe/Vaduz
OLD_FILES+=usr/share/zoneinfo/Europe/Vatican
OLD_FILES+=usr/share/zoneinfo/Europe/Vienna
OLD_FILES+=usr/share/zoneinfo/Europe/Vilnius
OLD_FILES+=usr/share/zoneinfo/Europe/Volgograd
OLD_FILES+=usr/share/zoneinfo/Europe/Warsaw
OLD_FILES+=usr/share/zoneinfo/Europe/Zagreb
OLD_FILES+=usr/share/zoneinfo/Europe/Zaporozhye
OLD_FILES+=usr/share/zoneinfo/Europe/Zurich
OLD_FILES+=usr/share/zoneinfo/Factory
OLD_FILES+=usr/share/zoneinfo/HST
OLD_FILES+=usr/share/zoneinfo/Indian/Antananarivo
OLD_FILES+=usr/share/zoneinfo/Indian/Chagos
OLD_FILES+=usr/share/zoneinfo/Indian/Christmas
OLD_FILES+=usr/share/zoneinfo/Indian/Cocos
OLD_FILES+=usr/share/zoneinfo/Indian/Comoro
OLD_FILES+=usr/share/zoneinfo/Indian/Kerguelen
OLD_FILES+=usr/share/zoneinfo/Indian/Mahe
OLD_FILES+=usr/share/zoneinfo/Indian/Maldives
OLD_FILES+=usr/share/zoneinfo/Indian/Mauritius
OLD_FILES+=usr/share/zoneinfo/Indian/Mayotte
OLD_FILES+=usr/share/zoneinfo/Indian/Reunion
OLD_FILES+=usr/share/zoneinfo/MET
OLD_FILES+=usr/share/zoneinfo/MST
OLD_FILES+=usr/share/zoneinfo/MST7MDT
OLD_FILES+=usr/share/zoneinfo/PST8PDT
OLD_FILES+=usr/share/zoneinfo/Pacific/Apia
OLD_FILES+=usr/share/zoneinfo/Pacific/Auckland
OLD_FILES+=usr/share/zoneinfo/Pacific/Bougainville
OLD_FILES+=usr/share/zoneinfo/Pacific/Chatham
OLD_FILES+=usr/share/zoneinfo/Pacific/Chuuk
OLD_FILES+=usr/share/zoneinfo/Pacific/Easter
OLD_FILES+=usr/share/zoneinfo/Pacific/Efate
OLD_FILES+=usr/share/zoneinfo/Pacific/Enderbury
OLD_FILES+=usr/share/zoneinfo/Pacific/Fakaofo
OLD_FILES+=usr/share/zoneinfo/Pacific/Fiji
OLD_FILES+=usr/share/zoneinfo/Pacific/Funafuti
OLD_FILES+=usr/share/zoneinfo/Pacific/Galapagos
OLD_FILES+=usr/share/zoneinfo/Pacific/Gambier
OLD_FILES+=usr/share/zoneinfo/Pacific/Guadalcanal
OLD_FILES+=usr/share/zoneinfo/Pacific/Guam
OLD_FILES+=usr/share/zoneinfo/Pacific/Honolulu
OLD_FILES+=usr/share/zoneinfo/Pacific/Johnston
OLD_FILES+=usr/share/zoneinfo/Pacific/Kiritimati
OLD_FILES+=usr/share/zoneinfo/Pacific/Kosrae
OLD_FILES+=usr/share/zoneinfo/Pacific/Kwajalein
OLD_FILES+=usr/share/zoneinfo/Pacific/Majuro
OLD_FILES+=usr/share/zoneinfo/Pacific/Marquesas
OLD_FILES+=usr/share/zoneinfo/Pacific/Midway
OLD_FILES+=usr/share/zoneinfo/Pacific/Nauru
OLD_FILES+=usr/share/zoneinfo/Pacific/Niue
OLD_FILES+=usr/share/zoneinfo/Pacific/Norfolk
OLD_FILES+=usr/share/zoneinfo/Pacific/Noumea
OLD_FILES+=usr/share/zoneinfo/Pacific/Pago_Pago
OLD_FILES+=usr/share/zoneinfo/Pacific/Palau
OLD_FILES+=usr/share/zoneinfo/Pacific/Pitcairn
OLD_FILES+=usr/share/zoneinfo/Pacific/Pohnpei
OLD_FILES+=usr/share/zoneinfo/Pacific/Port_Moresby
OLD_FILES+=usr/share/zoneinfo/Pacific/Rarotonga
OLD_FILES+=usr/share/zoneinfo/Pacific/Saipan
OLD_FILES+=usr/share/zoneinfo/Pacific/Tahiti
OLD_FILES+=usr/share/zoneinfo/Pacific/Tarawa
OLD_FILES+=usr/share/zoneinfo/Pacific/Tongatapu
OLD_FILES+=usr/share/zoneinfo/Pacific/Wake
OLD_FILES+=usr/share/zoneinfo/Pacific/Wallis
OLD_FILES+=usr/share/zoneinfo/UTC
OLD_FILES+=usr/share/zoneinfo/WET
OLD_FILES+=usr/share/zoneinfo/posixrules
OLD_FILES+=usr/share/zoneinfo/zone.tab
.endif

File Metadata

Mime Type
application/octet-stream
Expires
Tue, Jul 9, 7:58 PM (1 d, 23 h)
Storage Engine
chunks
Storage Format
Chunks
Storage Handle
AkENXvtZVvju
Default Alt Text
(4 MB)

Event Timeline