Page MenuHomeFreeBSD

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
Index: stable/11/ObsoleteFiles.inc
===================================================================
--- stable/11/ObsoleteFiles.inc (revision 350258)
+++ stable/11/ObsoleteFiles.inc (revision 350259)
@@ -1,9537 +1,9687 @@
#
# $FreeBSD$
#
# This file lists old files (OLD_FILES), libraries (OLD_LIBS) and
# directories (OLD_DIRS) which should get removed at an update. Recently
# removed entries first (with the date as a comment). Dynamic libraries are
# special cased (OLD_LIBS). Static libraries or the generic links to
# the dynamic libraries (lib*.so) should (if you don't know why to make an
# exception, make this a "must") be viewed as normal files (OLD_FILES).
#
# In case of a complete directory hierarchy the sorting is in depth first
# order.
#
# The file is partitioned: OLD_FILES first, then OLD_LIBS and OLD_DIRS last.
#
# 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 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 OLD_DIRS check-old | \
# xargs -n1 | sort | uniq -d;
# done
+# 20190723: 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
# 20190416: new libc++ import which bumps version from 7.0.1 to 8.0.0.
OLD_FILES+=usr/include/c++/v1/experimental/dynarray
# 20190416: 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
# 20190216: 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
# 20180812: move of libmlx5.so.1 and libibverbs.so.1
OLD_LIBS+=usr/lib/libmlx5.so.1
OLD_LIBS+=usr/lib/libibverbs.so.1
# 20180714: 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
# 20180613: 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
# 20180513: 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
# 20180331: 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
# 20180213: remove c_rehash(1)
OLD_FILES+=usr/share/openssl/man/man1/c_rehash.1.gz
# 20180212: Obsolete forth files
OLD_FILES+=boot/efi.4th
OLD_FILES+=boot/pcibios.4th
# 20180212: 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
# 20180202: Convert 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
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
# 20171226: 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
# 20171204: Move fdformat man page from volume 1 to volume 8.
OLD_FILES+=usr/share/man/man1/fdformat.1.gz
# 20170926: 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
# 20170802: ksyms(4) ioctl interface was removed
OLD_FILES+=usr/include/sys/ksyms.h
# 20170620: remove stale manpage
OLD_FILES+=usr/share/man/man2/cap_rights_get.2.gz
# 20170610: chown-f_test replaced by chown_test
OLD_FILES+=usr/tests/usr.sbin/chown/chown-f_test
# 20170531: remove pcap-int.h
OLD_FILES+=usr/include/pcap-int.h
# 20170402: 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
# 20170402: 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
# 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/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_lock
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_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
# 20170308: rename some tests
OLD_FILES+=usr/tests/bin/pwait/pwait
OLD_FILES+=usr/tests/usr.bin/timeout/timeout
# 20170214: 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
# 20170211: libarchive ACL pax test renamed to test_acl_pax_posix1e.tar.uu
OLD_FILES+=usr/tests/lib/libarchive/test_acl_pax.tar.uu
# 20170206: merged projects/ipsec
OLD_FILES+=usr/include/netinet/ip_ipsec.h
OLD_FILES+=usr/include/netinet6/ip6_ipsec.h
# 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_LIBS+=usr/lib/libbsnmptools.so
# 20170112: sysdecode_getfsstat_flags() renamed to sysdecode_getfsstat_mode()
OLD_FILES+=usr/share/man/man3/sysdecode_getfsstat_flags.3.gz
# 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
# 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
# 20161015: remove link to removed m_getclr(9) macro
OLD_FILES+=usr/share/man/man9/m_getclr.9.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
# 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
OLD_LIBS+=usr/lib32/libpam.so.5
OLD_LIBS+=usr/lib32/pam_chroot.so.5
OLD_LIBS+=usr/lib32/pam_deny.so.5
OLD_LIBS+=usr/lib32/pam_echo.so.5
OLD_LIBS+=usr/lib32/pam_exec.so.5
OLD_LIBS+=usr/lib32/pam_ftpusers.so.5
OLD_LIBS+=usr/lib32/pam_group.so.5
OLD_LIBS+=usr/lib32/pam_guest.so.5
OLD_LIBS+=usr/lib32/pam_krb5.so.5
OLD_LIBS+=usr/lib32/pam_ksu.so.5
OLD_LIBS+=usr/lib32/pam_lastlog.so.5
OLD_LIBS+=usr/lib32/pam_login_access.so.5
OLD_LIBS+=usr/lib32/pam_nologin.so.5
OLD_LIBS+=usr/lib32/pam_opie.so.5
OLD_LIBS+=usr/lib32/pam_opieaccess.so.5
OLD_LIBS+=usr/lib32/pam_passwdqc.so.5
OLD_LIBS+=usr/lib32/pam_permit.so.5
OLD_LIBS+=usr/lib32/pam_radius.so.5
OLD_LIBS+=usr/lib32/pam_rhosts.so.5
OLD_LIBS+=usr/lib32/pam_rootok.so.5
OLD_LIBS+=usr/lib32/pam_securetty.so.5
OLD_LIBS+=usr/lib32/pam_self.so.5
OLD_LIBS+=usr/lib32/pam_ssh.so.5
OLD_LIBS+=usr/lib32/pam_tacplus.so.5
OLD_LIBS+=usr/lib32/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/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
# 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
# 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
OLD_LIBS+=usr/lib32/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
# 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
OLD_FILES+=usr/lib32/libcapsicum.a
OLD_FILES+=usr/lib32/libcapsicum.so
OLD_LIBS+=usr/lib32/libcapsicum.so.0
OLD_FILES+=usr/lib32/libcapsicum_p.a
# 20160223: functionality from mkulzma(1) merged into mkuzip(1)
OLD_FILES+=usr/bin/mkulzma
# 20160211: Remove obsolete unbound-control-setup
OLD_FILES+=usr/sbin/unbound-control-setup
# 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
# 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)
OLD_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
OLD_LIBS+=usr/lib32/libcrypto.so.7
OLD_LIBS+=usr/lib32/libssl.so.7
# 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
OLD_LIBS+=usr/lib32/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
OLD_FILES+=usr/lib32/libheimsqlite.a
OLD_FILES+=usr/lib32/libheimsqlite.so
OLD_LIBS+=usr/lib32/libheimsqlite.so.11
OLD_FILES+=usr/lib32/libheimsqlite_p.a
# 20150518: tzdata2015c update
OLD_FILES+=usr/share/zoneinfo/America/Montreal
# 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_LIBS+=usr/lib32/private/libatf-c++.so.2
OLD_LIBS+=usr/lib32/private/libbsdstat.so.1
OLD_LIBS+=usr/lib32/private/libheimipcs.so.11
OLD_LIBS+=usr/lib32/private/libsqlite3.so.0
OLD_LIBS+=usr/lib32/private/libunbound.so.5
OLD_LIBS+=usr/lib32/private/libatf-c.so.1
OLD_LIBS+=usr/lib32/private/libheimipcc.so.11
OLD_LIBS+=usr/lib32/private/libldns.so.5
OLD_LIBS+=usr/lib32/private/libssh.so.5
OLD_LIBS+=usr/lib32/private/libucl.so.1
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/lib/libgpib_p.a
OLD_FILES+=usr/lib32/libgpib.a
OLD_FILES+=usr/lib32/libgpib_p.a
OLD_FILES+=usr/lib32/libgpib.so
OLD_LIBS+=usr/lib32/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
OLD_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+=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
OLD_LIBS+=usr/lib32/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
OLD_LIBS+=usr/lib/libnv.so.0
# 20140829: rc.d/kerberos removed
OLD_FILES+=etc/rc.d/kerberos
# 20140827: tzdata2014f import
OLD_FILES+=usr/share/zoneinfo/Asia/Chongqing
OLD_FILES+=usr/share/zoneinfo/Asia/Harbin
OLD_FILES+=usr/share/zoneinfo/Asia/Kashgar
# 20140814: libopie version bump
OLD_LIBS+=usr/lib/libopie.so.7
OLD_LIBS+=usr/lib32/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/lib32/private/libatf-c.a
OLD_FILES+=usr/lib32/private/libatf-c.so
OLD_FILES+=usr/lib32/private/libatf-c_p.a
OLD_FILES+=usr/lib32/private/libatf-c++.a
OLD_FILES+=usr/lib32/private/libatf-c++.so
OLD_FILES+=usr/lib32/private/libatf-c++_p.a
OLD_FILES+=usr/lib32/private/libbsdstat.a
OLD_FILES+=usr/lib32/private/libbsdstat.so
OLD_FILES+=usr/lib32/private/libbsdstat_p.a
OLD_FILES+=usr/lib32/private/libheimipcc.a
OLD_FILES+=usr/lib32/private/libheimipcc.so
OLD_FILES+=usr/lib32/private/libheimipcc_p.a
OLD_FILES+=usr/lib32/private/libheimipcs.a
OLD_FILES+=usr/lib32/private/libheimipcs.so
OLD_FILES+=usr/lib32/private/libheimipcs_p.a
OLD_FILES+=usr/lib32/private/libldns.a
OLD_FILES+=usr/lib32/private/libldns.so
OLD_FILES+=usr/lib32/private/libldns_p.a
OLD_FILES+=usr/lib32/private/libssh.a
OLD_FILES+=usr/lib32/private/libssh.so
OLD_FILES+=usr/lib32/private/libssh_p.a
OLD_FILES+=usr/lib32/private/libunbound.a
OLD_FILES+=usr/lib32/private/libunbound.so
OLD_FILES+=usr/lib32/private/libunbound_p.a
OLD_FILES+=usr/lib32/private/libucl.a
OLD_FILES+=usr/lib32/private/libucl.so
OLD_FILES+=usr/lib32/private/libucl_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/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
OLD_LIBS+=usr/lib32/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/lib32/libhistory.a
OLD_FILES+=usr/lib32/libhistory.so
OLD_LIBS+=usr/lib32/libhistory.so.8
OLD_FILES+=usr/lib32/libhistory_p.a
OLD_FILES+=usr/lib32/libreadline.a
OLD_FILES+=usr/lib32/libreadline.so
OLD_LIBS+=usr/lib32/libreadline.so.8
OLD_FILES+=usr/lib32/libreadline_p.a
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
OLD_FILES+=usr/lib32/libssp_p.a
OLD_FILES+=usr/lib32/libstand_p.a
# 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/lib32/libipx.a
OLD_FILES+=usr/lib32/libipx.so
OLD_LIBS+=usr/lib32/libipx.so.5
OLD_FILES+=usr/lib32/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
OLD_FILES+=usr/lib32/private/libyaml.a
OLD_FILES+=usr/lib32/private/libyaml.so
OLD_LIBS+=usr/lib32/private/libyaml.so.1
OLD_FILES+=usr/lib32/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_FILES+=usr/share/man/man1/llvm-ranlib.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/lib32/libelf.so.1
OLD_LIBS+=usr/lib/libdwarf.so.3
OLD_LIBS+=usr/lib32/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 usr/lib32/libcam.so.6
# 20131202: libcapsicum and libcasper moved to /lib/
OLD_LIBS+=usr/lib/libcapsicum.so.0
OLD_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
# 20131105: tzdata 2013h import
OLD_FILES+=usr/share/zoneinfo/America/Shiprock
OLD_FILES+=usr/share/zoneinfo/Antarctica/South_Pole
# 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_FILES+=usr/lib/libiconv.so.3
OLD_FILES+=usr/lib/libiconv_p.a
OLD_FILES+=usr/lib32/libiconv.a
OLD_FILES+=usr/lib32/libiconv.so
OLD_FILES+=usr/lib32/libiconv.so.3
OLD_FILES+=usr/lib32/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/lib32/libbsdyml.a
OLD_FILES+=usr/lib32/libbsdyml.so
OLD_LIBS+=usr/lib32/libbsdyml.so.0
OLD_FILES+=usr/lib32/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
# 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
OLD_FILES+=usr/lib32/libssh.a
OLD_FILES+=usr/lib32/libssh.so
OLD_LIBS+=usr/lib32/libssh.so.5
OLD_FILES+=usr/lib32/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
OLD_LIBS+=usr/lib32/libkvm.so.5
# 20130623: dialog update from 1.1 to 1.2
OLD_LIBS+=usr/lib/libdialog.so.7
OLD_LIBS+=usr/lib32/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
OLD_FILES+=usr/lib32/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/lib32/libncp.a
OLD_FILES+=usr/lib32/libncp.so
OLD_LIBS+=usr/lib32/libncp.so.4
OLD_FILES+=usr/lib32/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
# 20130110: bsd.compat.mk removed
OLD_FILES+=usr/share/mk/bsd.compat.mk
# 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 usr/lib32/libdisk.a
# 20121230: remove wrongly created directories for auditdistd
OLD_DIRS+=var/dist
OLD_DIRS+=var/remote
# 20121114: zpool-features manual page moved from section 5 to 7
OLD_FILES+=usr/share/man/man5/zpool-features.5.gz
# 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_LIBS+=usr/lib32/libcrypto.so.6
OLD_LIBS+=usr/lib32/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/md2.h
OLD_FILES+=usr/include/openssl/pq_compat.h
OLD_FILES+=usr/include/openssl/store.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_LIBS+=usr/lib32/libmd.so.5
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_LIBS+=usr/lib32/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 \
usr/lib32/libasn1.so.10 \
usr/lib32/libhdb.so.10 \
usr/lib32/libheimntlm.so.10 \
usr/lib32/libhx509.so.10 \
usr/lib32/libkadm5clnt.so.10 \
usr/lib32/libkadm5srv.so.10 \
usr/lib32/libkafs5.so.10 \
usr/lib32/libkrb5.so.10 \
usr/lib32/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
OLD_LIBS+=usr/lib32/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
OLD_FILES+=usr/lib32/libodialog.a
OLD_FILES+=usr/lib32/libodialog.so
OLD_LIBS+=usr/lib32/libodialog.so.7
OLD_FILES+=usr/lib32/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/lib32/libftpio.a
OLD_FILES+=usr/lib32/libftpio.so
OLD_LIBS+=usr/lib32/libftpio.so.8
OLD_FILES+=usr/lib32/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
OLD_LIBS+=usr/lib32/libcam.so.5
OLD_LIBS+=usr/lib32/libpcap.so.7
OLD_LIBS+=usr/lib32/libufs.so.5
OLD_LIBS+=usr/lib32/libbsnmp.so.5
OLD_LIBS+=usr/lib32/libdwarf.so.2
OLD_LIBS+=usr/lib32/libopie.so.6
OLD_LIBS+=usr/lib32/librtld_db.so.1
OLD_LIBS+=usr/lib32/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
OLD_FILES+=usr/lib32/libpkg.a
OLD_FILES+=usr/lib32/libpkg.so
OLD_LIBS+=usr/lib32/libpkg.so.0
OLD_FILES+=usr/lib32/libpkg_p.a
# 20110517: libsbuf version bump
OLD_LIBS+=lib/libsbuf.so.5
OLD_LIBS+=usr/lib32/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
OLD_FILES+=usr/lib32/libobjc.a
OLD_FILES+=usr/lib32/libobjc.so
OLD_FILES+=usr/lib32/libobjc_p.a
OLD_LIBS+=usr/lib32/libobjc.so.4
# 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
# 20100801: tzdata2010k import
OLD_FILES+=usr/share/zoneinfo/Pacific/Ponape
OLD_FILES+=usr/share/zoneinfo/Pacific/Truk
# 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
OLD_LIBS+=usr/lib32/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
OLD_LIBS+=usr/lib32/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
OLD_LIBS+=usr/lib32/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
# 20091117: usr/share/zoneinfo/GMT link removed
OLD_FILES+=usr/share/zoneinfo/GMT
# 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
OLD_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
OLD_LIBS+=usr/lib32/libalias.so.6
OLD_LIBS+=usr/lib32/libarchive.so.4
OLD_LIBS+=usr/lib32/libauditd.so.4
OLD_LIBS+=usr/lib32/libavl.so.1
OLD_LIBS+=usr/lib32/libbegemot.so.3
OLD_LIBS+=usr/lib32/libbluetooth.so.3
OLD_LIBS+=usr/lib32/libbsdxml.so.3
OLD_LIBS+=usr/lib32/libbsm.so.2
OLD_LIBS+=usr/lib32/libbsnmp.so.4
OLD_LIBS+=usr/lib32/libbz2.so.3
OLD_LIBS+=usr/lib32/libcalendar.so.4
OLD_LIBS+=usr/lib32/libcam.so.4
OLD_LIBS+=usr/lib32/libcom_err.so.4
OLD_LIBS+=usr/lib32/libcrypt.so.4
OLD_LIBS+=usr/lib32/libcrypto.so.5
OLD_LIBS+=usr/lib32/libctf.so.1
OLD_LIBS+=usr/lib32/libdevinfo.so.4
OLD_LIBS+=usr/lib32/libdevstat.so.6
OLD_LIBS+=usr/lib32/libdialog.so.6
OLD_LIBS+=usr/lib32/libdtrace.so.1
OLD_LIBS+=usr/lib32/libdwarf.so.1
OLD_LIBS+=usr/lib32/libedit.so.6
OLD_LIBS+=usr/lib32/libfetch.so.5
OLD_LIBS+=usr/lib32/libform.so.4
OLD_LIBS+=usr/lib32/libformw.so.4
OLD_LIBS+=usr/lib32/libftpio.so.7
OLD_LIBS+=usr/lib32/libgeom.so.4
OLD_LIBS+=usr/lib32/libgnuregex.so.4
OLD_LIBS+=usr/lib32/libgpib.so.2
OLD_LIBS+=usr/lib32/libhistory.so.7
OLD_LIBS+=usr/lib32/libipsec.so.3
OLD_LIBS+=usr/lib32/libipx.so.4
OLD_LIBS+=usr/lib32/libkiconv.so.3
OLD_LIBS+=usr/lib32/libkvm.so.4
OLD_LIBS+=usr/lib32/libmagic.so.3
OLD_LIBS+=usr/lib32/libmd.so.4
OLD_LIBS+=usr/lib32/libmemstat.so.2
OLD_LIBS+=usr/lib32/libmenu.so.4
OLD_LIBS+=usr/lib32/libmenuw.so.4
OLD_LIBS+=usr/lib32/libmilter.so.4
OLD_LIBS+=usr/lib32/libncp.so.3
OLD_LIBS+=usr/lib32/libncurses.so.7
OLD_LIBS+=usr/lib32/libncursesw.so.7
OLD_LIBS+=usr/lib32/libnetgraph.so.3
OLD_LIBS+=usr/lib32/libngatm.so.3
OLD_LIBS+=usr/lib32/libnvpair.so.1
OLD_LIBS+=usr/lib32/libobjc.so.3
OLD_LIBS+=usr/lib32/libopie.so.5
OLD_LIBS+=usr/lib32/libpam.so.4
OLD_LIBS+=usr/lib32/libpanel.so.4
OLD_LIBS+=usr/lib32/libpanelw.so.4
OLD_LIBS+=usr/lib32/libpcap.so.6
OLD_LIBS+=usr/lib32/libpmc.so.4
OLD_LIBS+=usr/lib32/libproc.so.1
OLD_LIBS+=usr/lib32/libradius.so.3
OLD_LIBS+=usr/lib32/libreadline.so.7
OLD_LIBS+=usr/lib32/librpcsvc.so.4
OLD_LIBS+=usr/lib32/libsbuf.so.4
OLD_LIBS+=usr/lib32/libsdp.so.3
OLD_LIBS+=usr/lib32/libsmb.so.3
OLD_LIBS+=usr/lib32/libssh.so.4
OLD_LIBS+=usr/lib32/libssl.so.5
OLD_LIBS+=usr/lib32/libtacplus.so.3
OLD_LIBS+=usr/lib32/libufs.so.4
OLD_LIBS+=usr/lib32/libugidfw.so.3
OLD_LIBS+=usr/lib32/libumem.so.1
OLD_LIBS+=usr/lib32/libusb.so.1
OLD_LIBS+=usr/lib32/libusbhid.so.3
OLD_LIBS+=usr/lib32/libutil.so.7
OLD_LIBS+=usr/lib32/libuutil.so.1
OLD_LIBS+=usr/lib32/libvgl.so.5
OLD_LIBS+=usr/lib32/libwrap.so.5
OLD_LIBS+=usr/lib32/libypclnt.so.3
OLD_LIBS+=usr/lib32/libz.so.4
OLD_LIBS+=usr/lib32/libzfs.so.1
OLD_LIBS+=usr/lib32/libzpool.so.1
OLD_LIBS+=usr/lib32/pam_chroot.so.4
OLD_LIBS+=usr/lib32/pam_deny.so.4
OLD_LIBS+=usr/lib32/pam_echo.so.4
OLD_LIBS+=usr/lib32/pam_exec.so.4
OLD_LIBS+=usr/lib32/pam_ftpusers.so.4
OLD_LIBS+=usr/lib32/pam_group.so.4
OLD_LIBS+=usr/lib32/pam_guest.so.4
OLD_LIBS+=usr/lib32/pam_krb5.so.4
OLD_LIBS+=usr/lib32/pam_ksu.so.4
OLD_LIBS+=usr/lib32/pam_lastlog.so.4
OLD_LIBS+=usr/lib32/pam_login_access.so.4
OLD_LIBS+=usr/lib32/pam_nologin.so.4
OLD_LIBS+=usr/lib32/pam_opie.so.4
OLD_LIBS+=usr/lib32/pam_opieaccess.so.4
OLD_LIBS+=usr/lib32/pam_passwdqc.so.4
OLD_LIBS+=usr/lib32/pam_permit.so.4
OLD_LIBS+=usr/lib32/pam_radius.so.4
OLD_LIBS+=usr/lib32/pam_rhosts.so.4
OLD_LIBS+=usr/lib32/pam_rootok.so.4
OLD_LIBS+=usr/lib32/pam_securetty.so.4
OLD_LIBS+=usr/lib32/pam_self.so.4
OLD_LIBS+=usr/lib32/pam_ssh.so.4
OLD_LIBS+=usr/lib32/pam_tacplus.so.4
OLD_LIBS+=usr/lib32/pam_unix.so.4
# 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
OLD_LIBS+=usr/lib32/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
OLD_LIBS+=usr/lib32/libusb20.so.1
OLD_FILES+=usr/lib32/libusb20.a
OLD_FILES+=usr/lib32/libusb20.so
OLD_FILES+=usr/lib32/libusb20_p.a
# 20090226: libmp(3) functions renamed
OLD_LIBS+=usr/lib/libmp.so.6
OLD_LIBS+=usr/lib32/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
# 20090122: tzdata2009a import
OLD_FILES+=usr/share/zoneinfo/Asia/Katmandu
# 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
OLD_LIBS+=usr/lib32/libgssapi.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
# 20080325: tzdata2008b import
OLD_FILES+=usr/share/zoneinfo/Asia/Calcutta
OLD_FILES+=usr/share/zoneinfo/Asia/Saigon
# 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
OLD_FILES+=usr/lib32/libkse.so
OLD_LIBS+=usr/lib32/libkse.so.3
# 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
OLD_FILES+=usr/lib32/libkse.a
OLD_FILES+=usr/lib32/libkse_p.a
OLD_FILES+=usr/lib32/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_LIBS+=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
OLD_FILES+=usr/lib32/libatm.a
OLD_FILES+=usr/lib32/libatm.so
OLD_LIBS+=usr/lib32/libatm.so.5
OLD_FILES+=usr/lib32/libatm_p.a
# 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
OLD_LIBS+=usr/lib32/libalias.so.5
OLD_LIBS+=usr/lib32/libbsnmp.so.3
OLD_LIBS+=usr/lib32/libdialog.so.5
OLD_LIBS+=usr/lib32/libgnuregex.so.3
OLD_LIBS+=usr/lib32/libhistory.so.6
OLD_LIBS+=usr/lib32/libncurses.so.6
OLD_LIBS+=usr/lib32/libncursesw.so.6
OLD_LIBS+=usr/lib32/libpam.so.3
OLD_LIBS+=usr/lib32/libreadline.so.6
OLD_LIBS+=usr/lib32/libssh.so.3
OLD_LIBS+=usr/lib32/pam_chroot.so.3
OLD_LIBS+=usr/lib32/pam_deny.so.3
OLD_LIBS+=usr/lib32/pam_echo.so.3
OLD_LIBS+=usr/lib32/pam_exec.so.3
OLD_LIBS+=usr/lib32/pam_ftpusers.so.3
OLD_LIBS+=usr/lib32/pam_group.so.3
OLD_LIBS+=usr/lib32/pam_guest.so.3
OLD_LIBS+=usr/lib32/pam_krb5.so.3
OLD_LIBS+=usr/lib32/pam_ksu.so.3
OLD_LIBS+=usr/lib32/pam_lastlog.so.3
OLD_LIBS+=usr/lib32/pam_login_access.so.3
OLD_LIBS+=usr/lib32/pam_nologin.so.3
OLD_LIBS+=usr/lib32/pam_opie.so.3
OLD_LIBS+=usr/lib32/pam_opieaccess.so.3
OLD_LIBS+=usr/lib32/pam_passwdqc.so.3
OLD_LIBS+=usr/lib32/pam_permit.so.3
OLD_LIBS+=usr/lib32/pam_radius.so.3
OLD_LIBS+=usr/lib32/pam_rhosts.so.3
OLD_LIBS+=usr/lib32/pam_rootok.so.3
OLD_LIBS+=usr/lib32/pam_securetty.so.3
OLD_LIBS+=usr/lib32/pam_self.so.3
OLD_LIBS+=usr/lib32/pam_ssh.so.3
OLD_LIBS+=usr/lib32/pam_tacplus.so.3
OLD_LIBS+=usr/lib32/pam_unix.so.3
# 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
OLD_LIBS+=usr/lib32/libatm.so.4
OLD_LIBS+=usr/lib32/libbegemot.so.2
OLD_LIBS+=usr/lib32/libbluetooth.so.2
OLD_LIBS+=usr/lib32/libbsdxml.so.2
OLD_LIBS+=usr/lib32/libbsm.so.1
OLD_LIBS+=usr/lib32/libbz2.so.2
OLD_LIBS+=usr/lib32/libcalendar.so.3
OLD_LIBS+=usr/lib32/libcam.so.3
OLD_LIBS+=usr/lib32/libcom_err.so.3
OLD_LIBS+=usr/lib32/libcrypt.so.3
OLD_LIBS+=usr/lib32/libdevinfo.so.3
OLD_LIBS+=usr/lib32/libdevstat.so.5
OLD_LIBS+=usr/lib32/libedit.so.5
OLD_LIBS+=usr/lib32/libfetch.so.4
OLD_LIBS+=usr/lib32/libform.so.3
OLD_LIBS+=usr/lib32/libformw.so.3
OLD_LIBS+=usr/lib32/libftpio.so.6
OLD_LIBS+=usr/lib32/libgeom.so.3
OLD_LIBS+=usr/lib32/libgpib.so.1
OLD_LIBS+=usr/lib32/libipsec.so.2
OLD_LIBS+=usr/lib32/libipx.so.3
OLD_LIBS+=usr/lib32/libkiconv.so.2
OLD_LIBS+=usr/lib32/libkse.so.2
OLD_LIBS+=usr/lib32/libkvm.so.3
OLD_LIBS+=usr/lib32/libm.so.4
OLD_LIBS+=usr/lib32/libmagic.so.2
OLD_LIBS+=usr/lib32/libmd.so.3
OLD_LIBS+=usr/lib32/libmemstat.so.1
OLD_LIBS+=usr/lib32/libmenu.so.3
OLD_LIBS+=usr/lib32/libmenuw.so.3
OLD_LIBS+=usr/lib32/libmilter.so.3
OLD_LIBS+=usr/lib32/libmp.so.5
OLD_LIBS+=usr/lib32/libncp.so.2
OLD_LIBS+=usr/lib32/libnetgraph.so.2
OLD_LIBS+=usr/lib32/libngatm.so.2
OLD_LIBS+=usr/lib32/libopie.so.4
OLD_LIBS+=usr/lib32/libpanel.so.3
OLD_LIBS+=usr/lib32/libpanelw.so.3
OLD_LIBS+=usr/lib32/libpcap.so.4
OLD_LIBS+=usr/lib32/libpmc.so.3
OLD_LIBS+=usr/lib32/libpthread.so.2
OLD_LIBS+=usr/lib32/libradius.so.2
OLD_LIBS+=usr/lib32/librpcsvc.so.3
OLD_LIBS+=usr/lib32/libsbuf.so.3
OLD_LIBS+=usr/lib32/libsdp.so.2
OLD_LIBS+=usr/lib32/libsmb.so.2
OLD_LIBS+=usr/lib32/libstdc++.so.5
OLD_LIBS+=usr/lib32/libtacplus.so.2
OLD_LIBS+=usr/lib32/libthr.so.2
OLD_LIBS+=usr/lib32/libthread_db.so.2
OLD_LIBS+=usr/lib32/libufs.so.3
OLD_LIBS+=usr/lib32/libugidfw.so.2
OLD_LIBS+=usr/lib32/libusbhid.so.2
OLD_LIBS+=usr/lib32/libutil.so.6
OLD_LIBS+=usr/lib32/libvgl.so.4
OLD_LIBS+=usr/lib32/libwrap.so.4
OLD_LIBS+=usr/lib32/libypclnt.so.2
OLD_LIBS+=usr/lib32/libz.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
OLD_LIBS+=usr/lib32/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
OLD_FILES+=usr/lib32/libmytinfo.a
OLD_FILES+=usr/lib32/libmytinfo.so
OLD_FILES+=usr/lib32/libmytinfo_p.a
OLD_FILES+=usr/lib32/libmytinfow.a
OLD_FILES+=usr/lib32/libmytinfow.so
OLD_FILES+=usr/lib32/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
# 20061201: remove symlink to *.so.4 libalias modules
OLD_FILES+=usr/lib/libalias_cuseeme.so
OLD_FILES+=usr/lib/libalias_dummy.so
OLD_FILES+=usr/lib/libalias_ftp.so
OLD_FILES+=usr/lib/libalias_irc.so
OLD_FILES+=usr/lib/libalias_nbt.so
OLD_FILES+=usr/lib/libalias_pptp.so
OLD_FILES+=usr/lib/libalias_skinny.so
OLD_FILES+=usr/lib/libalias_smedia.so
# 20061201: remove old *.so.4 libalias modules
OLD_FILES+=lib/libalias_cuseeme.so.4
OLD_FILES+=lib/libalias_dummy.so.4
OLD_FILES+=lib/libalias_ftp.so.4
OLD_FILES+=lib/libalias_irc.so.4
OLD_FILES+=lib/libalias_nbt.so.4
OLD_FILES+=lib/libalias_pptp.so.4
OLD_FILES+=lib/libalias_skinny.so.4
OLD_FILES+=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_FILES+=lib/geom/geom_concat.so.1
OLD_FILES+=lib/geom/geom_label.so.1
OLD_FILES+=lib/geom/geom_nop.so.1
OLD_FILES+=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
# 199911XX
OLD_FILES+=usr/sbin/ipfstat
OLD_FILES+=usr/sbin/ipmon
OLD_FILES+=usr/sbin/ipnat
OLD_FILES+=usr/sbin/bad144
OLD_FILES+=usr/sbin/wormcontrol
OLD_FILES+=usr/sbin/named-bootconf
OLD_FILES+=usr/sbin/kvm_mkdb
OLD_FILES+=usr/sbin/keyadmin
# 199909XX
OLD_FILES+=usr/lib/libdesrypt_p.a
OLD_FILES+=sbin/ft
# 199903XX
OLD_FILES+=sbin/modload
OLD_FILES+=sbin/modunload
OLD_FILES+=usr/sbin/natd
# 199812XX
OLD_FILES+=sbin/dset
# 199809XX
OLD_FILES+=sbin/scsi
OLD_FILES+=sbin/scsiformat
OLD_FILES+=usr/sbin/ncrcontrol
OLD_FILES+=usr/sbin/tickadj
# 199806XX
OLD_FILES+=usr/sbin/mkdosfs
# 199801XX
OLD_FILES+=sbin/mount_lfs
OLD_FILES+=sbin/newlfs
OLD_FILES+=sbin/dumplfs
OLD_FILES+=usr/sbin/qcamcontrol
OLD_FILES+=usr/sbin/supscan
# 1997XXXX
OLD_FILES+=usr/sbin/sysctl
OLD_FILES+=usr/sbin/ctm_scan
OLD_FILES+=usr/sbin/addgroup
OLD_FILES+=usr/sbin/rmgroup
# 1996XXXX
OLD_FILES+=sbin/rdisc
OLD_FILES+=usr/sbin/cdplay
OLD_FILES+=usr/sbin/supfilesrv
OLD_FILES+=usr/sbin/routed
OLD_FILES+=usr/sbin/lsdev
OLD_FILES+=usr/sbin/yppasswdd
## 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/bin/sperl5
OLD_FILES+=usr/bin/perl5.6.0
OLD_FILES+=usr/bin/sperl5.6.0
OLD_FILES+=usr/bin/perlbc
OLD_FILES+=usr/bin/perl5.00503
OLD_FILES+=usr/bin/sperl5.00503
OLD_FILES+=usr/bin/perlbug
OLD_FILES+=usr/bin/perlcc
OLD_FILES+=usr/bin/perldoc
OLD_FILES+=usr/bin/suidperl
OLD_FILES+=usr/lib/pam_ftp.so
OLD_FILES+=usr/libdata/perl/5.00503/CGI/Apache.pm
OLD_FILES+=usr/libdata/perl/5.00503/CGI/Carp.pm
OLD_FILES+=usr/libdata/perl/5.00503/CGI/Cookie.pm
OLD_FILES+=usr/libdata/perl/5.00503/CGI/Fast.pm
OLD_FILES+=usr/libdata/perl/5.00503/CGI/Push.pm
OLD_FILES+=usr/libdata/perl/5.00503/CGI/Switch.pm
OLD_FILES+=usr/libdata/perl/5.00503/CPAN/FirstTime.pm
OLD_FILES+=usr/libdata/perl/5.00503/CPAN/Nox.pm
OLD_FILES+=usr/libdata/perl/5.00503/Class/Struct.pm
OLD_FILES+=usr/libdata/perl/5.00503/Devel/SelfStubber.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/Command.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/Embed.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/Install.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/Installed.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/Liblist.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/MM_OS2.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/MM_Unix.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/MM_VMS.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/MM_Win32.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/MakeMaker.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/Manifest.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/Mkbootstrap.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/Mksymlists.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/Packlist.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/inst
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/testlib.pm
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/typemap
OLD_FILES+=usr/libdata/perl/5.00503/ExtUtils/xsubpp
OLD_FILES+=usr/libdata/perl/5.00503/File/Spec/Mac.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/Spec/OS2.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/Spec/Unix.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/Spec/VMS.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/Spec/Win32.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/Basename.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/CheckTree.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/Compare.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/Copy.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/DosGlob.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/Find.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/Path.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/Spec.pm
OLD_FILES+=usr/libdata/perl/5.00503/File/stat.pm
OLD_FILES+=usr/libdata/perl/5.00503/Getopt/Long.pm
OLD_FILES+=usr/libdata/perl/5.00503/Getopt/Std.pm
OLD_FILES+=usr/libdata/perl/5.00503/I18N/Collate.pm
OLD_FILES+=usr/libdata/perl/5.00503/IPC/Open2.pm
OLD_FILES+=usr/libdata/perl/5.00503/IPC/Open3.pm
OLD_FILES+=usr/libdata/perl/5.00503/Math/BigFloat.pm
OLD_FILES+=usr/libdata/perl/5.00503/Math/BigInt.pm
OLD_FILES+=usr/libdata/perl/5.00503/Math/Complex.pm
OLD_FILES+=usr/libdata/perl/5.00503/Math/Trig.pm
OLD_FILES+=usr/libdata/perl/5.00503/Net/Ping.pm
OLD_FILES+=usr/libdata/perl/5.00503/Net/hostent.pm
OLD_FILES+=usr/libdata/perl/5.00503/Net/netent.pm
OLD_FILES+=usr/libdata/perl/5.00503/Net/protoent.pm
OLD_FILES+=usr/libdata/perl/5.00503/Net/servent.pm
OLD_FILES+=usr/libdata/perl/5.00503/Pod/Functions.pm
OLD_FILES+=usr/libdata/perl/5.00503/Pod/Html.pm
OLD_FILES+=usr/libdata/perl/5.00503/Pod/Text.pm
OLD_FILES+=usr/libdata/perl/5.00503/Search/Dict.pm
OLD_FILES+=usr/libdata/perl/5.00503/Sys/Hostname.pm
OLD_FILES+=usr/libdata/perl/5.00503/Sys/Syslog.pm
OLD_FILES+=usr/libdata/perl/5.00503/Term/Cap.pm
OLD_FILES+=usr/libdata/perl/5.00503/Term/Complete.pm
OLD_FILES+=usr/libdata/perl/5.00503/Term/ReadLine.pm
OLD_FILES+=usr/libdata/perl/5.00503/Test/Harness.pm
OLD_FILES+=usr/libdata/perl/5.00503/Text/Abbrev.pm
OLD_FILES+=usr/libdata/perl/5.00503/Text/ParseWords.pm
OLD_FILES+=usr/libdata/perl/5.00503/Text/Soundex.pm
OLD_FILES+=usr/libdata/perl/5.00503/Text/Tabs.pm
OLD_FILES+=usr/libdata/perl/5.00503/Text/Wrap.pm
OLD_FILES+=usr/libdata/perl/5.00503/Tie/Array.pm
OLD_FILES+=usr/libdata/perl/5.00503/Tie/Handle.pm
OLD_FILES+=usr/libdata/perl/5.00503/Tie/Hash.pm
OLD_FILES+=usr/libdata/perl/5.00503/Tie/RefHash.pm
OLD_FILES+=usr/libdata/perl/5.00503/Tie/Scalar.pm
OLD_FILES+=usr/libdata/perl/5.00503/Tie/SubstrHash.pm
OLD_FILES+=usr/libdata/perl/5.00503/Time/Local.pm
OLD_FILES+=usr/libdata/perl/5.00503/Time/gmtime.pm
OLD_FILES+=usr/libdata/perl/5.00503/Time/localtime.pm
OLD_FILES+=usr/libdata/perl/5.00503/Time/tm.pm
OLD_FILES+=usr/libdata/perl/5.00503/User/grent.pm
OLD_FILES+=usr/libdata/perl/5.00503/User/pwent.pm
OLD_FILES+=usr/libdata/perl/5.00503/auto/Getopt/Long/GetOptions.al
OLD_FILES+=usr/libdata/perl/5.00503/auto/Getopt/Long/FindOption.al
OLD_FILES+=usr/libdata/perl/5.00503/auto/Getopt/Long/Configure.al
OLD_FILES+=usr/libdata/perl/5.00503/auto/Getopt/Long/config.al
OLD_FILES+=usr/libdata/perl/5.00503/auto/Getopt/Long/Croak.al
OLD_FILES+=usr/libdata/perl/5.00503/auto/Getopt/Long/autosplit.ix
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/Deparse.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/CC.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/Debug.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/Showlex.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/makeliblinks
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/Bblock.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/cc_harness
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/Bytecode.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/Stackobj.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/Xref.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/Lint.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/Asmdata.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/Assembler.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/Disassembler.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/disassemble
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/assemble
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/Terse.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B/C.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/EXTERN.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/INTERN.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/XSUB.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/XSlock.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/av.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/bytecode.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/byterun.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/cc_runtime.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/config.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/cop.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/cv.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/dosish.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/embed.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/embedvar.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/fakethr.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/form.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/gv.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/handy.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/hv.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/intrpvar.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/iperlsys.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/keywords.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/mg.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/nostdio.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/objXSUB.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/objpp.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/op.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/opcode.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/patchlevel.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/perl.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/perlio.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/perlsdio.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/perlsfio.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/perlvars.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/perly.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/pp.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/pp_proto.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/proto.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/regcomp.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/regexp.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/regnodes.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/scope.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/sv.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/thrdvar.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/thread.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/unixish.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/CORE/util.h
OLD_FILES+=usr/libdata/perl/5.00503/mach/Data/Dumper.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/IO/File.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/IO/Select.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/IO/Socket.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/IO/Handle.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/IO/Seekable.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/IO/Pipe.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/IPC/SysV.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/IPC/Msg.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/IPC/Semaphore.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/B/B.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/B/B.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/B/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/DB_File/autosplit.ix
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/DB_File/DB_File.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/DB_File/DB_File.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/DB_File/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Data/Dumper/Dumper.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Data/Dumper/Dumper.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Data/Dumper/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/DynaLoader/.exists
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/DynaLoader/dl_findfile.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/DynaLoader/dl_expandspec.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/DynaLoader/dl_find_symbol_anywhere.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/DynaLoader/autosplit.ix
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/DynaLoader/DynaLoader.a
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/DynaLoader/extralibs.ld
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Fcntl/Fcntl.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Fcntl/Fcntl.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Fcntl/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/IO/IO.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/IO/IO.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/IO/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/IPC/SysV/SysV.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/IPC/SysV/SysV.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/IPC/SysV/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/NDBM_File/NDBM_File.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/NDBM_File/NDBM_File.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/NDBM_File/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Opcode/Opcode.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Opcode/Opcode.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Opcode/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/assert.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/tolower.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/toupper.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/closedir.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/opendir.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/readdir.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/rewinddir.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/errno.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/creat.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fcntl.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getgrgid.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getgrnam.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/atan2.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/cos.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/exp.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fabs.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/log.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/pow.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/sin.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/sqrt.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getpwnam.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getpwuid.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/longjmp.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/setjmp.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/kill.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/feof.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/siglongjmp.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/sigsetjmp.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/raise.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/offsetof.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/clearerr.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fclose.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fdopen.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fgetc.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fgets.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fileno.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fopen.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fprintf.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fputc.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fputs.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fread.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/freopen.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fscanf.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fseek.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/ferror.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fflush.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fgetpos.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fsetpos.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/ftell.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fwrite.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getc.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getchar.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/gets.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/perror.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/printf.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/putc.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/putchar.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/puts.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/remove.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/rename.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/rewind.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/scanf.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/sprintf.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/sscanf.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/tmpfile.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/ungetc.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/vfprintf.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/vprintf.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/vsprintf.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/abs.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/atexit.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/atof.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/atoi.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/atol.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/bsearch.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/calloc.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/div.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/exit.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/free.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getenv.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/labs.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/ldiv.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/malloc.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/qsort.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/rand.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/realloc.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/srand.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/system.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/memchr.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/memcmp.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/memcpy.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/memmove.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/memset.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strcat.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strchr.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strcmp.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strcpy.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strcspn.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strerror.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strlen.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strncat.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strncmp.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strncpy.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strpbrk.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strrchr.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strspn.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strstr.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/strtok.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/chmod.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fstat.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/mkdir.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/stat.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/umask.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/wait.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/waitpid.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/gmtime.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/localtime.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/time.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/alarm.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/chdir.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/chown.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/execl.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/execle.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/execlp.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/execv.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/execve.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/execvp.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/fork.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getcwd.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getegid.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/geteuid.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getgid.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getgroups.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getlogin.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getpgrp.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getpid.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getppid.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/getuid.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/isatty.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/link.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/rmdir.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/setbuf.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/setgid.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/setuid.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/setvbuf.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/sleep.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/unlink.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/utime.al
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/autosplit.ix
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/POSIX.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/POSIX.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/POSIX/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/SDBM_File/SDBM_File.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/SDBM_File/SDBM_File.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/SDBM_File/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Socket/Socket.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Socket/Socket.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Socket/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/attrs/attrs.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/attrs/attrs.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/attrs/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/re/re.so
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/re/re.bs
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/re/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/sdbm/extralibs.ld
OLD_FILES+=usr/libdata/perl/5.00503/mach/auto/Errno/.packlist
OLD_FILES+=usr/libdata/perl/5.00503/mach/Config.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/B.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/O.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/perllocal.pod
OLD_FILES+=usr/libdata/perl/5.00503/mach/DB_File.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/Errno.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/Fcntl.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/IO.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/NDBM_File.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/Safe.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/Opcode.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/ops.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/POSIX.pod
OLD_FILES+=usr/libdata/perl/5.00503/mach/POSIX.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/SDBM_File.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/Socket.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/attrs.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/re.pm
OLD_FILES+=usr/libdata/perl/5.00503/mach/_h2ph_pre.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/a.out.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/cam/cam.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/cam/cam_ccb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/cam/cam_debug.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/cam/cam_extend.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/cam/cam_periph.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/cam/cam_queue.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/cam/cam_sim.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/cam/cam_xpt.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/cam/cam_xpt_periph.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/cam/cam_xpt_sim.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/aio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/alias.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/assert.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/bitstring.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/calendar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/camlib.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/com_err.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/com_right.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ctype.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/curses.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/db.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/des.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/devstat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/dialog.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/dirent.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/disktab.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/dlfcn.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/elf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/err.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/errno.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/eti.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/fcntl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/fetch.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/float.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/floatingpoint.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/fnmatch.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/form.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/fstab.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ftpio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/fts.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/glob.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/gmp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/gnuregex.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/grp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/histedit.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ieeefp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ifaddrs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/inttypes.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/iso646.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/kvm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/libatm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/libdisk.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/libgen.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/libusb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/libutil.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/limits.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/link.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/linker_set.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/locale.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/login_cap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/malloc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/FlexLexer.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/PlotFile.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/SFile.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/_G_config.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/algo.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/algobase.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/alloc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/builtinbuf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/bvector.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/complex.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/defalloc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/deque.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/editbuf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/floatio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/fstream.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/function.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/hash_map.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/hash_set.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/hashtable.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/heap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/indstream.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/iolibio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/iomanip.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/list.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/iostdio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/iostream.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/iostreamP.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/istream.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/iterator.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/libio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/libioP.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/map.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/multimap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/multiset.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/new.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/ostream.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/pair.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/parsestream.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/pfstream.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/procbuf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/pthread_alloc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/rope.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/ropeimpl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/set.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/slist.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stack.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stdiostream.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_algo.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/tree.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_algobase.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_alloc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_bvector.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_config.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_construct.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_deque.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_function.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_hash_fun.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_hash_map.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_hash_set.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_hashtable.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_heap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_iterator.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_list.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_map.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_multimap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_multiset.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_numeric.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_pair.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_queue.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_raw_storage_iter.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_relops.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_rope.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_set.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_slist.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_stack.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_tempbuf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_tree.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_uninitialized.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stl_vector.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/stream.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/streambuf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/strfile.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/strstream.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/tempbuf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/type_traits.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g++/vector.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/math.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/md2.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/md4.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/md5.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/memory.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/menu.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/mp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/mpool.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/mqueue.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ncurses.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ndbm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netdb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nl_types.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nlist.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objformat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/opie.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/osreldate.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/panel.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/paths.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pcap-int.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pcap-namedb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pcap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/poll.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pthread.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pthread_np.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pwd.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/radlib.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ranlib.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/regex.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/regexp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/resolv.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ripemd.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rune.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/runetype.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sched.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/search.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/semaphore.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/setjmp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sgtty.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sha.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/signal.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/skey.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/stab.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/stand.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/stdarg.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/stddef.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/stdio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/stdlib.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/strhash.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/string.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/stringlist.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/strings.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/struct.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sysexits.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/syslog.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/taclib.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/tar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/tcpd.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/term.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/termcap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/termios.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/time.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/timers.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ttyent.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ucontext.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/unctrl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/unistd.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/utime.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/utmp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/values.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/varargs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vgl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vis.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/zconf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/zlib.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/arpa/ftp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/arpa/inet.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/arpa/nameser.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/arpa/nameser_compat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/arpa/telnet.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/arpa/tftp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/isc/assertions.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/isc/ctl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/isc/dst.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/isc/eventlib.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/isc/heap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/isc/irpmarshall.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/isc/logging.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/isc/memcluster.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/isc/misc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/isc/tree.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/isc/list.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/ansi.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/apic.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/apm_bios.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/apm_segments.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/asc_ioctl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/asm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/asmacros.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/asnames.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/atomic.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/bootinfo.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/bus.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/bus_at386.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/bus_memio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/bus_pc98.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/bus_pio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/bus_pio_ind.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/cdk.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/clock.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/comstats.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/console.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/cpu.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/cpufunc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/cputypes.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/cronyx.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/db_machdep.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/dvcfg.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/elf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/endian.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/exec.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/float.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/floatingpoint.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/frame.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/globaldata.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/globals.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/gsc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/i4b_cause.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/i4b_debug.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/i4b_ioctl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/i4b_rbch_ioctl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/i4b_tel_ioctl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/i4b_trace.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/ieeefp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/if_wavelan_ieee.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/if_wl_wavelan.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/iic.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/in_cksum.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/ioctl_bt848.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/ioctl_ctx.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/ioctl_fd.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/ioctl_meteor.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/ipl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/joystick.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/limits.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/lock.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/md_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/mouse.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/mpapic.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/mtpr.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/bus_dma.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/npx.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/param.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/pcaudioio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/pcb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/pcb_ext.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/pcvt_ioctl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/perfmon.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/physio_proc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/pmap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/proc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/profile.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/psl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/ptrace.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/reg.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/reloc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/resource.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/segments.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/setjmp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/sigframe.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/signal.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/smb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/smp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/smptests.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/soundcard.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/speaker.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/specialreg.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/spigot.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/stdarg.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/sysarch.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/trap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/tss.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/types.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/uc_device.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/ucontext.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/ultrasound.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/varargs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/vm86.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/vmparam.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/wtio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/i4b_isppp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/machine/pci_cfgreg.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/msdosfs/bootsect.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/msdosfs/bpb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/msdosfs/denode.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/msdosfs/direntry.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/msdosfs/fat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/msdosfs/msdosfsmount.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/bpf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/bpf_compat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/bpfdesc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/bridge.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/ethernet.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/hostcache.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_arp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_atm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_dl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_gif.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_ieee80211.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_llc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_media.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_mib.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_ppp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_pppvar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_slvar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_sppp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_stf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_tap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_tapvar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_tun.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/slip.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_tunvar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_types.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_vlan_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/intrq.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/iso88025.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/net_osdep.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/netisr.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/pfkeyv2.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/ppp_comp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/ppp_defs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/radix.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/raw_cb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/route.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/slcompress.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/zlib.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_faith.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_arc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/net/if_gre.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/krpc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/nfs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/nfsdiskless.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/nfsm_subs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/nfsmount.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/nfsnode.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/nfsproto.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/nfsrtt.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/nfsrvcache.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/nfsv2.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/nqnfs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/rpcv2.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nfs/xdr_subs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatalk/aarp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatalk/at.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatalk/at_extern.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatalk/at_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatalk/ddp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatalk/ddp_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatalk/endian.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatalk/phase2.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/atm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/atm_cm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/atm_if.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/atm_ioctl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/atm_pcb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/atm_sap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/atm_sigmgr.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/atm_stack.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/atm_sys.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/atm_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/atm_vc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/kern_include.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/port.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netatm/queue.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/netgraph.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_UI.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_async.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_bpf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_bridge.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_cisco.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_echo.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_ether.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_frame_relay.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_hole.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_iface.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_ksocket.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_lmi.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_message.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_mppc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_one2many.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_parse.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_ppp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_pppoe.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_pptpgre.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_rfc1490.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_sample.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_socket.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_socketvar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_tee.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_tty.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_vjc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_eiface.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_etf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_device.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_l2tp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netgraph/ng_fec.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/icmp6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/icmp_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/if_atm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/if_ether.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/if_fddi.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/igmp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/igmp_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/in.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/in_gif.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/in_hostcache.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/in_pcb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/in_systm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/in_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_auth.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_compat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_dummynet.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_ecn.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_encap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_fil.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_flow.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_frag.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_fw.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_icmp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_mroute.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_nat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_proxy.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_state.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ipl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ipprotosw.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/tcp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/tcp_debug.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/tcp_fsm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/tcp_seq.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/tcp_timer.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/tcp_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/tcpip.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/udp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/udp_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_fw2.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet/ip_gre.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/ah.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/ah6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/esp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/esp6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/icmp6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/in6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/in6_gif.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/in6_ifattach.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/in6_pcb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/in6_prefix.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/in6_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/ip6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/ip6_ecn.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/ip6_fw.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/ip6_mroute.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/ip6_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/ip6protosw.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/ipcomp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/ipcomp6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/ipsec.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/ipsec6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/mld6_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/nd6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/pim6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/pim6_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/scope6_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/tcp6_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/udp6_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/esp_rijndael.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netinet6/raw_ip6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipx/ipx.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipx/ipx_if.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipx/ipx_ip.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipx/ipx_pcb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipx/ipx_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipx/spx.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipx/spx_debug.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipx/spx_timer.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipx/spx_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netkey/key.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netkey/key_debug.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netkey/key_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netkey/keydb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netkey/keysock.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netnatm/natm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/ncp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/ncp_cfg.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/ncp_conn.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/ncp_file.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/ncp_lib.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/ncp_ncp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/ncp_nls.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/ncp_rcfile.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/ncp_rq.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/ncp_sock.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/ncp_subr.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/ncp_user.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netncp/nwerror.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netns/idp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netns/idp_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netns/ns.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netns/ns_error.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netns/ns_if.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netns/ns_pcb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netns/sp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netns/spidp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netns/spp_debug.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netns/spp_timer.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netns/spp_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ntfs/ntfs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ntfs/ntfs_compr.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ntfs/ntfs_ihash.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ntfs/ntfs_inode.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ntfs/ntfs_subr.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ntfs/ntfs_vfsops.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ntfs/ntfsmount.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nwfs/nwfs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nwfs/nwfs_mount.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nwfs/nwfs_node.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/nwfs/nwfs_subr.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objc/NXConstStr.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objc/Object.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objc/Protocol.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objc/encoding.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objc/hash.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objc/objc-api.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objc/objc-list.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objc/objc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objc/runtime.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objc/sarray.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objc/thr.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/objc/typedstream.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/asn1.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/asn1_mac.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/bio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/blowfish.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/bn.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/buffer.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/cast.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/comp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/conf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/conf_api.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/crypto.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/des.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/dh.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/dsa.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/dso.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/e_os.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/e_os2.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ebcdic.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/err.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/evp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/hmac.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/lhash.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/md2.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/md4.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/md5.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/mdc2.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/obj_mac.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/objects.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/opensslconf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/opensslv.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/pem.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/pem2.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/pkcs12.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/pkcs7.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/rand.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/rc2.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/rc4.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/rc5.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ripemd.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/rsa.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/safestack.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/sha.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ssl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ssl2.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ssl23.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ssl3.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ssl_locl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/stack.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/symhacks.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/tls1.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/tmdiff.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/txt_db.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/x509.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/x509_vfy.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/x509v3.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/idea.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/aes.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/asn1t.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/cryptlib.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/des_old.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ec.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/engine.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/krb5_asn.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/kssl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ocsp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ossl_typ.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ui.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ui_compat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/aes_locl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/eng_int.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/hw_4758_cca_err.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/hw_aep_err.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/hw_atalla_err.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/hw_cswift_err.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/hw_ncipher_err.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/hw_nuron_err.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/hw_sureware_err.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/hw_ubsec_err.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/openssl/ui_locl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pccard/cardinfo.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pccard/cis.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pccard/driver.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pccard/i82365.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pccard/pccard_nbk.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pccard/slot.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pccard/meciareg.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pccard/pcic_pci.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/pccard/pcicvar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/posix4/aio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/posix4/mqueue.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/posix4/posix4.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/posix4/sched.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/posix4/semaphore.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/protocols/dumprestore.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/protocols/routed.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/protocols/rwhod.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/protocols/talkd.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/protocols/timed.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/readline/chardefs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/readline/history.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/readline/keymaps.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/readline/readline.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/readline/rlconf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/readline/rlstdc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/readline/tilde.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/auth.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/auth_des.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/auth_unix.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/clnt.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/des.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/des_crypt.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/key_prot.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/pmap_clnt.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/pmap_prot.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/pmap_rmt.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/rpc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/rpc_com.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/rpc_msg.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/svc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/svc_auth.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/types.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpc/xdr.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/bootparam_prot.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/crypt.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/key_prot.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/klm_prot.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/mount.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/nfs_prot.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/nis.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/nis_cache.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/nis_callback.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/nis_db.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/nis_tags.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/nislib.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/nlm_prot.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/rex.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/rnusers.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/rquota.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/rstat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/rwall.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/sm_inter.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/spray.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/yp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/yp_prot.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/ypclnt.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/yppasswd.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/ypupdate_prot.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/rpcsvc/ypxfrd.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/security/_pam_compat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/security/_pam_macros.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/security/_pam_types.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/security/pam_appl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/security/pam_malloc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/security/pam_misc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/security/pam_mod_misc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/security/pam_modules.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ss/mit-sipb-copyright.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ss/ss.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/ss/ss_err.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/_posix.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ata.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/acct.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/acl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/agpio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/aio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/assym.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/blist.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/buf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/bus.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/bus_private.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/callout.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ccdvar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/cdefs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/cdio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/cdrio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/chio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/clist.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/endian.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/conf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/cons.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/consio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/copyright.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ctype.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/dir.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/dataacq.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/link_elf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/device_port.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/devicestat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/dirent.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/disk.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/disklabel.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/diskslice.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/dkstat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/dmap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/domain.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/dvdio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/elf32.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/elf64.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/elf_common.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/elf_generic.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/errno.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/event.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/eventhandler.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/eventvar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/exec.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/extattr.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/fbio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/fcntl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/file.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/filedesc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/filio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/gmon.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/imgact.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/imgact_aout.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/imgact_elf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/inflate.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/interrupt.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/inttypes.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ioccom.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ioctl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ioctl_compat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ipc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/jail.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/joystick.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/kbio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/kernel.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/kthread.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ktrace.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/libkern.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/linker.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/linker_set.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/lock.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/lockf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/malloc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/mbuf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/md5.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/memrange.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/mman.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/module.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/mount.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/msg.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/msgbuf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/mtio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/namei.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/param.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/pciio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/pioctl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/pipe.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/poll.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/proc.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/procfs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/protosw.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ptio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ptrace.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/queue.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/random.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/reboot.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/resource.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/resourcevar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/rman.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/rtprio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/sbuf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/select.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/sem.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/shm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/signal.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/signalvar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/snoop.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/socket.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/socketvar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/sockio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/soundcard.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/stat.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/syscall-hide.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/syscall.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/sysctl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/sysent.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/syslimits.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/syslog.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/sysproto.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/systm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/taskqueue.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/termios.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/time.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/timeb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/timepps.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/timers.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/times.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/timex.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/tprintf.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/tty.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ttychars.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ttycom.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ttydefaults.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ttydev.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/types.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ucontext.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/ucred.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/uio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/un.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/unistd.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/unpcb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/user.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/utsname.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/vmmeter.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/vnioctl.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/vnode.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/wait.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/wormio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/xrpuio.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/kobj.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/link_aout.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/nlist_aout.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/mchain.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/fnv_hash.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/iconv.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/sys/md4.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/pmap.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/swap_pager.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/vm.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/vm_extern.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/vm_kern.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/vm_map.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/vm_object.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/vm_page.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/vm_pageout.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/vm_pager.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/vm_param.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/vm_zone.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/vm/vnode_pager.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/complex.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/stdbool.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/langinfo.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netsmb/netbios.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netsmb/smb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netsmb/smb_conn.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netsmb/smb_dev.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netsmb/smb_rq.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netsmb/smb_subr.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netsmb/smb_tran.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netsmb/smb_trantcp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/g2c.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/telnet.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/elf-hints.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/libusbhid.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/radlib_vs.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/readpassphrase.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/wchar.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/wctype.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/crypto/cast.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/crypto/castsb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/crypto/cryptodev.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/crypto/cryptosoft.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/crypto/deflate.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/crypto/rijndael.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/crypto/rmd160.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/crypto/skipjack.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/crypto/xform.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/ah.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/ah_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/esp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/esp_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/ipcomp.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/ipcomp_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/ipip_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/ipsec.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/ipsec6.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/key.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/key_debug.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/key_var.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/keydb.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/keysock.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/netipsec/xform.ph
OLD_FILES+=usr/libdata/perl/5.00503/mach/bzlib.ph
OLD_FILES+=usr/libdata/perl/5.00503/pod/perl.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perl5004delta.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlapio.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlbook.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlbot.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlcall.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perldata.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perldebug.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perldelta.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perldiag.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perldsc.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlembed.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlfaq.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlfaq1.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlfaq2.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlfaq3.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlfaq4.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlfaq5.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlfaq6.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlfaq7.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlipc.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlfaq8.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlfaq9.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlform.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlfunc.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlguts.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlhist.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perllocale.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perllol.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlmod.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlmodinstall.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlmodlib.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlobj.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlop.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlopentut.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlpod.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlport.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlre.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlref.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlreftut.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlrun.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlsec.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlstyle.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlsub.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlsyn.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlthrtut.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perltie.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perltoc.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perltoot.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perltrap.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlvar.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlxs.pod
OLD_FILES+=usr/libdata/perl/5.00503/pod/perlxstut.pod
OLD_FILES+=usr/libdata/perl/5.00503/AnyDBM_File.pm
OLD_FILES+=usr/libdata/perl/5.00503/AutoLoader.pm
OLD_FILES+=usr/libdata/perl/5.00503/AutoSplit.pm
OLD_FILES+=usr/libdata/perl/5.00503/Benchmark.pm
OLD_FILES+=usr/libdata/perl/5.00503/CGI.pm
OLD_FILES+=usr/libdata/perl/5.00503/CPAN.pm
OLD_FILES+=usr/libdata/perl/5.00503/Carp.pm
OLD_FILES+=usr/libdata/perl/5.00503/Cwd.pm
OLD_FILES+=usr/libdata/perl/5.00503/DirHandle.pm
OLD_FILES+=usr/libdata/perl/5.00503/Dumpvalue.pm
OLD_FILES+=usr/libdata/perl/5.00503/English.pm
OLD_FILES+=usr/libdata/perl/5.00503/Env.pm
OLD_FILES+=usr/libdata/perl/5.00503/Exporter.pm
OLD_FILES+=usr/libdata/perl/5.00503/Fatal.pm
OLD_FILES+=usr/libdata/perl/5.00503/FileCache.pm
OLD_FILES+=usr/libdata/perl/5.00503/FileHandle.pm
OLD_FILES+=usr/libdata/perl/5.00503/FindBin.pm
OLD_FILES+=usr/libdata/perl/5.00503/SelectSaver.pm
OLD_FILES+=usr/libdata/perl/5.00503/SelfLoader.pm
OLD_FILES+=usr/libdata/perl/5.00503/Shell.pm
OLD_FILES+=usr/libdata/perl/5.00503/Symbol.pm
OLD_FILES+=usr/libdata/perl/5.00503/Test.pm
OLD_FILES+=usr/libdata/perl/5.00503/abbrev.pl
OLD_FILES+=usr/libdata/perl/5.00503/UNIVERSAL.pm
OLD_FILES+=usr/libdata/perl/5.00503/assert.pl
OLD_FILES+=usr/libdata/perl/5.00503/autouse.pm
OLD_FILES+=usr/libdata/perl/5.00503/base.pm
OLD_FILES+=usr/libdata/perl/5.00503/bigfloat.pl
OLD_FILES+=usr/libdata/perl/5.00503/bigint.pl
OLD_FILES+=usr/libdata/perl/5.00503/bigrat.pl
OLD_FILES+=usr/libdata/perl/5.00503/blib.pm
OLD_FILES+=usr/libdata/perl/5.00503/cacheout.pl
OLD_FILES+=usr/libdata/perl/5.00503/chat2.pl
OLD_FILES+=usr/libdata/perl/5.00503/complete.pl
OLD_FILES+=usr/libdata/perl/5.00503/constant.pm
OLD_FILES+=usr/libdata/perl/5.00503/ctime.pl
OLD_FILES+=usr/libdata/perl/5.00503/diagnostics.pm
OLD_FILES+=usr/libdata/perl/5.00503/dotsh.pl
OLD_FILES+=usr/libdata/perl/5.00503/dumpvar.pl
OLD_FILES+=usr/libdata/perl/5.00503/exceptions.pl
OLD_FILES+=usr/libdata/perl/5.00503/fastcwd.pl
OLD_FILES+=usr/libdata/perl/5.00503/fields.pm
OLD_FILES+=usr/libdata/perl/5.00503/find.pl
OLD_FILES+=usr/libdata/perl/5.00503/finddepth.pl
OLD_FILES+=usr/libdata/perl/5.00503/flush.pl
OLD_FILES+=usr/libdata/perl/5.00503/ftp.pl
OLD_FILES+=usr/libdata/perl/5.00503/getcwd.pl
OLD_FILES+=usr/libdata/perl/5.00503/getopt.pl
OLD_FILES+=usr/libdata/perl/5.00503/getopts.pl
OLD_FILES+=usr/libdata/perl/5.00503/hostname.pl
OLD_FILES+=usr/libdata/perl/5.00503/importenv.pl
OLD_FILES+=usr/libdata/perl/5.00503/integer.pm
OLD_FILES+=usr/libdata/perl/5.00503/less.pm
OLD_FILES+=usr/libdata/perl/5.00503/lib.pm
OLD_FILES+=usr/libdata/perl/5.00503/locale.pm
OLD_FILES+=usr/libdata/perl/5.00503/look.pl
OLD_FILES+=usr/libdata/perl/5.00503/newgetopt.pl
OLD_FILES+=usr/libdata/perl/5.00503/open2.pl
OLD_FILES+=usr/libdata/perl/5.00503/open3.pl
OLD_FILES+=usr/libdata/perl/5.00503/overload.pm
OLD_FILES+=usr/libdata/perl/5.00503/perl5db.pl
OLD_FILES+=usr/libdata/perl/5.00503/pwd.pl
OLD_FILES+=usr/libdata/perl/5.00503/shellwords.pl
OLD_FILES+=usr/libdata/perl/5.00503/sigtrap.pm
OLD_FILES+=usr/libdata/perl/5.00503/stat.pl
OLD_FILES+=usr/libdata/perl/5.00503/strict.pm
OLD_FILES+=usr/libdata/perl/5.00503/subs.pm
OLD_FILES+=usr/libdata/perl/5.00503/syslog.pl
OLD_FILES+=usr/libdata/perl/5.00503/tainted.pl
OLD_FILES+=usr/libdata/perl/5.00503/termcap.pl
OLD_FILES+=usr/libdata/perl/5.00503/timelocal.pl
OLD_FILES+=usr/libdata/perl/5.00503/validate.pl
OLD_FILES+=usr/libdata/perl/5.00503/vars.pm
OLD_FILES+=usr/libdata/perl/5.00503/re.pm
OLD_FILES+=usr/libdata/perl/5.00503/Config.pm
OLD_FILES+=usr/libdata/perl/5.00503/.exists
OLD_FILES+=usr/libdata/perl/5.00503/DynaLoader.pm
OLD_FILES+=usr/share/perl/man/man3/AnyDBM_File.3.gz
OLD_FILES+=usr/share/perl/man/man3/AutoLoader.3.gz
OLD_FILES+=usr/share/perl/man/man3/AutoSplit.3.gz
OLD_FILES+=usr/share/perl/man/man3/B.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Asmdata.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Assembler.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Bblock.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Bytecode.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::C.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::CC.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Debug.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Deparse.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Disassembler.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Lint.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Showlex.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Stackobj.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Terse.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Xref.3.gz
OLD_FILES+=usr/share/perl/man/man3/Benchmark.3.gz
OLD_FILES+=usr/share/perl/man/man3/CGI.3.gz
OLD_FILES+=usr/share/perl/man/man3/CGI::Apache.3.gz
OLD_FILES+=usr/share/perl/man/man3/CGI::Carp.3.gz
OLD_FILES+=usr/share/perl/man/man3/CGI::Cookie.3.gz
OLD_FILES+=usr/share/perl/man/man3/CGI::Fast.3.gz
OLD_FILES+=usr/share/perl/man/man3/CGI::Push.3.gz
OLD_FILES+=usr/share/perl/man/man3/CGI::Switch.3.gz
OLD_FILES+=usr/share/perl/man/man3/CPAN.3.gz
OLD_FILES+=usr/share/perl/man/man3/CPAN::FirstTime.3.gz
OLD_FILES+=usr/share/perl/man/man3/CPAN::Nox.3.gz
OLD_FILES+=usr/share/perl/man/man3/Carp.3.gz
OLD_FILES+=usr/share/perl/man/man3/Class::Struct.3.gz
OLD_FILES+=usr/share/perl/man/man3/Config.3.gz
OLD_FILES+=usr/share/perl/man/man3/Cwd.3.gz
OLD_FILES+=usr/share/perl/man/man3/DB_File.3.gz
OLD_FILES+=usr/share/perl/man/man3/Data::Dumper.3.gz
OLD_FILES+=usr/share/perl/man/man3/Devel::SelfStubber.3.gz
OLD_FILES+=usr/share/perl/man/man3/DirHandle.3.gz
OLD_FILES+=usr/share/perl/man/man3/Dumpvalue.3.gz
OLD_FILES+=usr/share/perl/man/man3/DynaLoader.3.gz
OLD_FILES+=usr/share/perl/man/man3/English.3.gz
OLD_FILES+=usr/share/perl/man/man3/Env.3.gz
OLD_FILES+=usr/share/perl/man/man3/Exporter.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::Command.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::Embed.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::Install.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::Installed.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::Liblist.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::MM_OS2.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::MM_Unix.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::MM_VMS.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::MM_Win32.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::MakeMaker.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::Manifest.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::Mkbootstrap.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::Mksymlists.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::Packlist.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::testlib.3.gz
OLD_FILES+=usr/share/perl/man/man3/Fatal.3.gz
OLD_FILES+=usr/share/perl/man/man3/Fcntl.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::Basename.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::CheckTree.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::Compare.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::Copy.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::DosGlob.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::Find.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::Path.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::Spec.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::Spec::Mac.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::Spec::OS2.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::Spec::Unix.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::Spec::VMS.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::Spec::Win32.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::stat.3.gz
OLD_FILES+=usr/share/perl/man/man3/FileCache.3.gz
OLD_FILES+=usr/share/perl/man/man3/IO.3.gz
OLD_FILES+=usr/share/perl/man/man3/FileHandle.3.gz
OLD_FILES+=usr/share/perl/man/man3/FindBin.3.gz
OLD_FILES+=usr/share/perl/man/man3/GDBM_File.3.gz
OLD_FILES+=usr/share/perl/man/man3/Getopt::Long.3.gz
OLD_FILES+=usr/share/perl/man/man3/Getopt::Std.3.gz
OLD_FILES+=usr/share/perl/man/man3/I18N::Collate.3.gz
OLD_FILES+=usr/share/perl/man/man3/IO::File.3.gz
OLD_FILES+=usr/share/perl/man/man3/IO::Handle.3.gz
OLD_FILES+=usr/share/perl/man/man3/IO::Pipe.3.gz
OLD_FILES+=usr/share/perl/man/man3/IO::Seekable.3.gz
OLD_FILES+=usr/share/perl/man/man3/IO::Select.3.gz
OLD_FILES+=usr/share/perl/man/man3/IO::Socket.3.gz
OLD_FILES+=usr/share/perl/man/man3/IPC::Msg.3.gz
OLD_FILES+=usr/share/perl/man/man3/IPC::Open2.3.gz
OLD_FILES+=usr/share/perl/man/man3/IPC::Open3.3.gz
OLD_FILES+=usr/share/perl/man/man3/IPC::Semaphore.3.gz
OLD_FILES+=usr/share/perl/man/man3/IPC::SysV.3.gz
OLD_FILES+=usr/share/perl/man/man3/Math::BigFloat.3.gz
OLD_FILES+=usr/share/perl/man/man3/Math::BigInt.3.gz
OLD_FILES+=usr/share/perl/man/man3/Math::Complex.3.gz
OLD_FILES+=usr/share/perl/man/man3/Math::Trig.3.gz
OLD_FILES+=usr/share/perl/man/man3/NDBM_File.3.gz
OLD_FILES+=usr/share/perl/man/man3/Net::Ping.3.gz
OLD_FILES+=usr/share/perl/man/man3/Net::hostent.3.gz
OLD_FILES+=usr/share/perl/man/man3/Net::netent.3.gz
OLD_FILES+=usr/share/perl/man/man3/Net::protoent.3.gz
OLD_FILES+=usr/share/perl/man/man3/Net::servent.3.gz
OLD_FILES+=usr/share/perl/man/man3/O.3.gz
OLD_FILES+=usr/share/perl/man/man3/ODBM_File.3.gz
OLD_FILES+=usr/share/perl/man/man3/Opcode.3.gz
OLD_FILES+=usr/share/perl/man/man3/POSIX.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::Html.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::Text.3.gz
OLD_FILES+=usr/share/perl/man/man3/SDBM_File.3.gz
OLD_FILES+=usr/share/perl/man/man3/Safe.3.gz
OLD_FILES+=usr/share/perl/man/man3/Search::Dict.3.gz
OLD_FILES+=usr/share/perl/man/man3/SelectSaver.3.gz
OLD_FILES+=usr/share/perl/man/man3/SelfLoader.3.gz
OLD_FILES+=usr/share/perl/man/man3/Shell.3.gz
OLD_FILES+=usr/share/perl/man/man3/Socket.3.gz
OLD_FILES+=usr/share/perl/man/man3/Symbol.3.gz
OLD_FILES+=usr/share/perl/man/man3/re.3.gz
OLD_FILES+=usr/share/perl/man/man3/Sys::Hostname.3.gz
OLD_FILES+=usr/share/perl/man/man3/Sys::Syslog.3.gz
OLD_FILES+=usr/share/perl/man/man3/Term::Cap.3.gz
OLD_FILES+=usr/share/perl/man/man3/Term::Complete.3.gz
OLD_FILES+=usr/share/perl/man/man3/Term::ReadLine.3.gz
OLD_FILES+=usr/share/perl/man/man3/Test.3.gz
OLD_FILES+=usr/share/perl/man/man3/Test::Harness.3.gz
OLD_FILES+=usr/share/perl/man/man3/Text::Abbrev.3.gz
OLD_FILES+=usr/share/perl/man/man3/Text::ParseWords.3.gz
OLD_FILES+=usr/share/perl/man/man3/Text::Soundex.3.gz
OLD_FILES+=usr/share/perl/man/man3/Text::Tabs.3.gz
OLD_FILES+=usr/share/perl/man/man3/Text::Wrap.3.gz
OLD_FILES+=usr/share/perl/man/man3/Thread.3.gz
OLD_FILES+=usr/share/perl/man/man3/Thread::Queue.3.gz
OLD_FILES+=usr/share/perl/man/man3/Thread::Semaphore.3.gz
OLD_FILES+=usr/share/perl/man/man3/Thread::Signal.3.gz
OLD_FILES+=usr/share/perl/man/man3/Thread::Specific.3.gz
OLD_FILES+=usr/share/perl/man/man3/Tie::Array.3.gz
OLD_FILES+=usr/share/perl/man/man3/Tie::Handle.3.gz
OLD_FILES+=usr/share/perl/man/man3/Tie::Hash.3.gz
OLD_FILES+=usr/share/perl/man/man3/Tie::RefHash.3.gz
OLD_FILES+=usr/share/perl/man/man3/Tie::Scalar.3.gz
OLD_FILES+=usr/share/perl/man/man3/Tie::SubstrHash.3.gz
OLD_FILES+=usr/share/perl/man/man3/Time::Local.3.gz
OLD_FILES+=usr/share/perl/man/man3/Time::gmtime.3.gz
OLD_FILES+=usr/share/perl/man/man3/Time::localtime.3.gz
OLD_FILES+=usr/share/perl/man/man3/Time::tm.3.gz
OLD_FILES+=usr/share/perl/man/man3/UNIVERSAL.3.gz
OLD_FILES+=usr/share/perl/man/man3/User::grent.3.gz
OLD_FILES+=usr/share/perl/man/man3/User::pwent.3.gz
OLD_FILES+=usr/share/perl/man/man3/attrs.3.gz
OLD_FILES+=usr/share/perl/man/man3/autouse.3.gz
OLD_FILES+=usr/share/perl/man/man3/base.3.gz
OLD_FILES+=usr/share/perl/man/man3/blib.3.gz
OLD_FILES+=usr/share/perl/man/man3/constant.3.gz
OLD_FILES+=usr/share/perl/man/man3/diagnostics.3.gz
OLD_FILES+=usr/share/perl/man/man3/fields.3.gz
OLD_FILES+=usr/share/perl/man/man3/integer.3.gz
OLD_FILES+=usr/share/perl/man/man3/less.3.gz
OLD_FILES+=usr/share/perl/man/man3/lib.3.gz
OLD_FILES+=usr/share/perl/man/man3/locale.3.gz
OLD_FILES+=usr/share/perl/man/man3/ops.3.gz
OLD_FILES+=usr/share/perl/man/man3/overload.3.gz
OLD_FILES+=usr/share/perl/man/man3/sigtrap.3.gz
OLD_FILES+=usr/share/perl/man/man3/strict.3.gz
OLD_FILES+=usr/share/perl/man/man3/subs.3.gz
OLD_FILES+=usr/share/perl/man/man3/vars.3.gz
OLD_FILES+=usr/share/perl/man/man3/B::Stash.3.gz
OLD_FILES+=usr/share/perl/man/man3/ByteLoader.3.gz
OLD_FILES+=usr/share/perl/man/man3/CGI::Pretty.3.gz
OLD_FILES+=usr/share/perl/man/man3/Carp::Heavy.3.gz
OLD_FILES+=usr/share/perl/man/man3/DB.3.gz
OLD_FILES+=usr/share/perl/man/man3/DProf::DProf.3.gz
OLD_FILES+=usr/share/perl/man/man3/Exporter::Heavy.3.gz
OLD_FILES+=usr/share/perl/man/man3/ExtUtils::MM_Cygwin.3.gz
OLD_FILES+=usr/share/perl/man/man3/File::Glob.3.gz
OLD_FILES+=usr/share/perl/man/man3/Glob::Glob.3.gz
OLD_FILES+=usr/share/perl/man/man3/Hostname::Hostname.3.gz
OLD_FILES+=usr/share/perl/man/man3/IO::Dir.3.gz
OLD_FILES+=usr/share/perl/man/man3/IO::Poll.3.gz
OLD_FILES+=usr/share/perl/man/man3/IO::Socket::INET.3.gz
OLD_FILES+=usr/share/perl/man/man3/IO::Socket::UNIX.3.gz
OLD_FILES+=usr/share/perl/man/man3/Peek::Peek.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::Checker.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::Find.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::InputObjects.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::Man.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::ParseUtils.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::Parser.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::Plainer.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::Select.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::Text::Color.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::Text::Termcap.3.gz
OLD_FILES+=usr/share/perl/man/man3/Pod::Usage.3.gz
OLD_FILES+=usr/share/perl/man/man3/Syslog::Syslog.3.gz
OLD_FILES+=usr/share/perl/man/man3/Term::ANSIColor.3.gz
OLD_FILES+=usr/share/perl/man/man3/XSLoader.3.gz
OLD_FILES+=usr/share/perl/man/man3/attributes.3.gz
OLD_FILES+=usr/share/perl/man/man3/bytes.3.gz
OLD_FILES+=usr/share/perl/man/man3/charnames.3.gz
OLD_FILES+=usr/share/perl/man/man3/filetest.3.gz
OLD_FILES+=usr/share/perl/man/man3/open.3.gz
OLD_FILES+=usr/share/perl/man/man3/utf8.3.gz
OLD_FILES+=usr/share/perl/man/man3/warnings.3.gz
OLD_FILES+=usr/share/perl/man/man3/warnings::register.3.gz
OLD_FILES+=usr/share/perl/man/whatis
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/perl.1.gz
OLD_FILES+=usr/share/man/man1/perl5004delta.1.gz
OLD_FILES+=usr/share/man/man1/perlapio.1.gz
OLD_FILES+=usr/share/man/man1/perlbook.1.gz
OLD_FILES+=usr/share/man/man1/perlbot.1.gz
OLD_FILES+=usr/share/man/man1/perlcall.1.gz
OLD_FILES+=usr/share/man/man1/perldata.1.gz
OLD_FILES+=usr/share/man/man1/perldebug.1.gz
OLD_FILES+=usr/share/man/man1/perldelta.1.gz
OLD_FILES+=usr/share/man/man1/perldiag.1.gz
OLD_FILES+=usr/share/man/man1/perldsc.1.gz
OLD_FILES+=usr/share/man/man1/perlembed.1.gz
OLD_FILES+=usr/share/man/man1/perlfaq.1.gz
OLD_FILES+=usr/share/man/man1/perlfaq1.1.gz
OLD_FILES+=usr/share/man/man1/perlfaq2.1.gz
OLD_FILES+=usr/share/man/man1/perlfaq3.1.gz
OLD_FILES+=usr/share/man/man1/perlfaq4.1.gz
OLD_FILES+=usr/share/man/man1/perlfaq5.1.gz
OLD_FILES+=usr/share/man/man1/perlfaq6.1.gz
OLD_FILES+=usr/share/man/man1/perlfaq7.1.gz
OLD_FILES+=usr/share/man/man1/perlfaq8.1.gz
OLD_FILES+=usr/share/man/man1/perlfaq9.1.gz
OLD_FILES+=usr/share/man/man1/perlform.1.gz
OLD_FILES+=usr/share/man/man1/perlfunc.1.gz
OLD_FILES+=usr/share/man/man1/perlguts.1.gz
OLD_FILES+=usr/share/man/man1/perlhist.1.gz
OLD_FILES+=usr/share/man/man1/perlipc.1.gz
OLD_FILES+=usr/share/man/man1/perllocale.1.gz
OLD_FILES+=usr/share/man/man1/perllol.1.gz
OLD_FILES+=usr/share/man/man1/perlmod.1.gz
OLD_FILES+=usr/share/man/man1/perlmodinstall.1.gz
OLD_FILES+=usr/share/man/man1/perlmodlib.1.gz
OLD_FILES+=usr/share/man/man1/perlobj.1.gz
OLD_FILES+=usr/share/man/man1/perlop.1.gz
OLD_FILES+=usr/share/man/man1/perlopentut.1.gz
OLD_FILES+=usr/share/man/man1/perlpod.1.gz
OLD_FILES+=usr/share/man/man1/perlport.1.gz
OLD_FILES+=usr/share/man/man1/perlre.1.gz
OLD_FILES+=usr/share/man/man1/perlref.1.gz
OLD_FILES+=usr/share/man/man1/perlreftut.1.gz
OLD_FILES+=usr/share/man/man1/perlrun.1.gz
OLD_FILES+=usr/share/man/man1/perlsec.1.gz
OLD_FILES+=usr/share/man/man1/perlstyle.1.gz
OLD_FILES+=usr/share/man/man1/perlsub.1.gz
OLD_FILES+=usr/share/man/man1/perlsyn.1.gz
OLD_FILES+=usr/share/man/man1/perlthrtut.1.gz
OLD_FILES+=usr/share/man/man1/perltie.1.gz
OLD_FILES+=usr/share/man/man1/perltoc.1.gz
OLD_FILES+=usr/share/man/man1/perltoot.1.gz
OLD_FILES+=usr/share/man/man1/perltrap.1.gz
OLD_FILES+=usr/share/man/man1/perlvar.1.gz
OLD_FILES+=usr/share/man/man1/perlxs.1.gz
OLD_FILES+=usr/share/man/man1/perlxstut.1.gz
OLD_FILES+=usr/share/man/man1/perlbug.1.gz
OLD_FILES+=usr/share/man/man1/perlcc.1.gz
OLD_FILES+=usr/share/man/man1/perldoc.1.gz
OLD_FILES+=usr/share/man/man1/perl5005delta.1.gz
OLD_FILES+=usr/share/man/man1/perlfork.1.gz
OLD_FILES+=usr/share/man/man1/perlboot.1.gz
OLD_FILES+=usr/share/man/man1/perltootc.1.gz
OLD_FILES+=usr/share/man/man1/perldbmfilter.1.gz
OLD_FILES+=usr/share/man/man1/perldebguts.1.gz
OLD_FILES+=usr/share/man/man1/perlnumber.1.gz
OLD_FILES+=usr/share/man/man1/perlcompile.1.gz
OLD_FILES+=usr/share/man/man1/perltodo.1.gz
OLD_FILES+=usr/share/man/man1/perlapi.1.gz
OLD_FILES+=usr/share/man/man1/perlintern.1.gz
OLD_FILES+=usr/share/man/man1/perlhack.1.gz
OLD_FILES+=usr/share/man/man1/perlbc.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/pthread_mutexattr_getpshared.3.gz
OLD_FILES+=usr/share/man/man3/pthread_mutexattr_setpshared.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/man7/style.perl.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/man/ja/man1/perl.1.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/Africa/Timbuktu
OLD_FILES+=usr/share/zoneinfo/Africa/Asmera
OLD_FILES+=usr/share/zoneinfo/America/Buenos_Aires
OLD_FILES+=usr/share/zoneinfo/America/Cordoba
OLD_FILES+=usr/share/zoneinfo/America/Jujuy
OLD_FILES+=usr/share/zoneinfo/America/Catamarca
OLD_FILES+=usr/share/zoneinfo/America/Mendoza
OLD_FILES+=usr/share/zoneinfo/America/Indianapolis
OLD_FILES+=usr/share/zoneinfo/America/Louisville
OLD_FILES+=usr/share/zoneinfo/America/Argentina/ComodRivadavia
OLD_FILES+=usr/share/zoneinfo/Atlantic/Faeroe
OLD_FILES+=usr/share/zoneinfo/Europe/Belfast
OLD_FILES+=usr/share/zoneinfo/Pacific/Yap
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_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"
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
# 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
OLD_LIBS+=usr/lib32/libgssapi.so.8
OLD_LIBS+=usr/lib32/libobjc.so.2
# 20070519: GCC 4.2
OLD_LIBS+=usr/lib/libg2c.a
OLD_LIBS+=usr/lib/libg2c.so
OLD_LIBS+=usr/lib/libg2c.so.2
OLD_LIBS+=usr/lib/libg2c_p.a
OLD_LIBS+=usr/lib/libgcc_pic.a
OLD_LIBS+=usr/lib32/libg2c.a
OLD_LIBS+=usr/lib32/libg2c.so
OLD_LIBS+=usr/lib32/libg2c.so.2
OLD_LIBS+=usr/lib32/libg2c_p.a
OLD_LIBS+=usr/lib32/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
OLD_LIBS+=usr/lib32/libcrypto.so.4
OLD_LIBS+=usr/lib32/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
OLD_LIBS+=usr/lib32/libatm.so.3
OLD_LIBS+=usr/lib32/libc.so.6
OLD_LIBS+=usr/lib32/libutil.so.5
# 20060413: shared library moved to /usr/lib
OLD_LIBS+=lib/libgpib.so.1
# 20060413: libpcap.so.4 moved to /lib/
OLD_LIBS+=usr/lib/libpcap.so.4
# 20060412: libpthread.so.2 moved to /lib/
OLD_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_LIBS+=usr/lib/libc_r.a
OLD_LIBS+=usr/lib/libc_r.so
OLD_LIBS+=usr/lib/libc_r.so.7
OLD_LIBS+=usr/lib/libc_r_p.a
OLD_LIBS+=usr/lib32/libc_r.a
OLD_LIBS+=usr/lib32/libc_r.so
OLD_LIBS+=usr/lib32/libc_r.so.7
OLD_LIBS+=usr/lib32/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.
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
# 19991216
OLD_FILES+=usr/sbin/xntpdc
# 199909XX
OLD_LIBS+=usr/lib/libc_r.so.3
# ???
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/lib32/libarchive.so.2
OLD_LIBS+=usr/lib32/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
# 20131013: Removal of the ATF tools
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
# 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"
Index: stable/11/UPDATING
===================================================================
--- stable/11/UPDATING (revision 350258)
+++ stable/11/UPDATING (revision 350259)
@@ -1,1856 +1,1862 @@
Updating Information for FreeBSD current users.
This file is maintained and copyrighted by M. Warner Losh <imp@freebsd.org>.
See end of file for further details. For commonly done items, please see the
COMMON ITEMS: section later in the file. These instructions assume that you
basically know what you are doing. If not, then please consult the FreeBSD
handbook:
https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/makeworld.html
Items affecting the ports and packages system can be found in
/usr/ports/UPDATING. Please read that file before running portupgrade.
NOTE: FreeBSD has switched from gcc to clang. If you have trouble bootstrapping
from older versions of FreeBSD, try WITHOUT_CLANG and WITH_GCC to bootstrap to
the tip of head, and then rebuild without this option. The bootstrap process
from older version of current across the gcc/clang cutover is a bit fragile.
+20190723:
+ Clang, llvm, lld, lldb, compiler-rt, libc++, libunwind and openmp have
+ been upgraded to 8.0.1. Please see the 20141231 entry below for
+ information about prerequisites and upgrading, if you are not already
+ using clang 3.5.0 or higher.
+
20190426:
CARP now sets DSCP value CS7(Network Traffic) in the flowlabel field
of packets by default instead of only setting TOS_LOWDELAY in IPv4,
which was deprecated in 1998. Original behavior can be restored by
setting sysctl net.inet.carp.dscp=4.
20190416:
Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to
8.0.0. Please see the 20141231 entry below for information about
prerequisites and upgrading, if you are not already using clang 3.5.0
or higher.
20190226:
geom_uzip(4) depends on the new module xz. If geom_uzip is statically
compiled into your custom kernel, add 'device xz' statement to the
kernel config.
20190220:
Co-existance for Forth and Lua interpreters in bootloaders has now been
merged to ease testing of lualoader. LOADER_DEFAULT_INTERP, documented
in build(7), may be used to control which interpreter flavor is used in
the default loader to be installed. For systems where Lua and Forth
coexist, this switch can also be made on a running system by creating a
link from /boot/loader{,.efi} to /boot/loader_${flavor}{,.efi} rather
than requiring a rebuild.
The default flavor in this branch will remain Forth. As indicated in
the 20190216 UPDATING entry, booting is a complex environment; it would
be prudent to assume that lualoader may not work for your setup and make
provisions for backup boot methods.
20190220:
zfsloader's functionality has now been folded into loader.
zfsloader is no longer necesasary once you've updated your
boot blocks. For a transition period, we will install a
hardlink for zfsloader to loader to allow a smooth transition
until the boot blocks can be updated (hard link because old
zfs boot blocks don't understand symlinks).
20190216:
Lualoader has been merged to facilitate testing on this branch. It's
purely opt-in for now by building WITH_LOADER_LUA and WITHOUT_FORTH in
/etc/src.conf, but co-existance will come shortly. Booting is a complex
environment and test coverage for Lua-enabled loaders has been thin, so
it would be prudent to assume it might not work and make provisions for
backup boot methods.
20190216:
Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to
7.0.1. Please see the 20141231 entry below for information about
prerequisites and upgrading, if you are not already using clang 3.5.0
or higher.
20181228:
r342562 modifies the NFSv4 server so that it obeys vfs.nfsd.nfs_privport
in the same as it is applied to NFSv2 and 3. This implies that NFSv4
servers that have vfs.nfsd.nfs_privport set will only allow mounts
from clients using a reserved port#. Since both the FreeBSD and Linux
NFSv4 clients use reserved port#s by default, this should not affect
most NFSv4 mounts.
20181107:
The '%I' format in the kern.corefile sysctl limits the number of
core files that a process can generate to the number stored in the
debug.ncores sysctl. The '%I' format is replaced by the single digit
index. Previously, if all indexes were taken the kernel would overwrite
only a core file with the highest index in a filename.
Currently the system will create a new core file if there is a free
index or if all slots are taken it will overwrite the oldest one.
20180818:
WITH_OFED option now only enables the build for the OFED libraries
and some fundamental client utilities. OpenSM and rest of the
debugging tools are enabled by WITH_OFED_EXTRA build switch.
WITH_OFED is turned on by default on amd64.
20180714:
Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to
6.0.1. Please see the 20141231 entry below for information about
prerequisites and upgrading, if you are not already using clang 3.5.0
or higher.
20180601:
The releng/11.2 branch has been created from stable/11@r334458.
20180504:
The tz database (tzdb) has been updated to 2018e. This version more
correctly models time stamps in time zones with negative DST such as
Europe/Dublin (from 1971 on), Europe/Prague (1946/7), and
Africa/Windhoek (1994/2017). This does not affect the UT offsets, only
time zone abbreviations and the tm_isdst flag.
20180409:
The use of RSS hash from the network card aka flowid has been
disabled by default for lagg(4) as it's currently incompatible with
the lacp and loadbalance protocols.
This can be re-enabled by setting the following in loader.conf:
net.link.lagg.default_use_flowid="1"
20180331:
Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to
6.0.0. Please see the 20141231 entry below for information about
prerequisites and upgrading, if you are not already using clang 3.5.0
or higher.
20180211:
The LOADER_FIREWIRE_SUPPORT build variable as been renamed to
WITH/OUT_LOADER_FIREWIRE. LOADER_{NO_,}GELI_SUPPORT has been renamed
to WITH/OUT_LOADER_GELI.
20180210:
The geli password typed at boot is now hidden. To restore the previous
behavior, see geli(8) for configuration options.
The SW_WATCHDOG option is no longer necessary to enable the
hardclock-based software watchdog if no hardware watchdog is
configured. As before, SW_WATCHDOG will cause the software
watchdog to be enabled even if a hardware watchdog is configured.
20180108:
lint(1) binaries and library are no longer built by default. To
enable building them, define WITH_LINT in src.conf. If you are using
a FreeBSD 12 or later system to build 11-stable, you may need to
install a lint(1) binary to use WITH_LINT.
20171003:
When building multiple kernels using KERNCONF, non-existent KERNCONF
files will produce an error and buildkernel will fail. Previously
missing KERNCONF files silently failed giving no indication as to
why, only to subsequently discover during installkernel that the
desired kernel was never built in the first place.
20170926:
Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 5.0.0.
Please see the 20141231 entry below for information about prerequisites
and upgrading, if you are not already using clang 3.5.0 or higher.
20170822:
Since the switch to GPT disk labels, fsck for UFS/FFS has been
unable to automatically find alternate superblocks. As of r322806,
the information needed to find alternate superblocks has been
moved to the end of the area reserved for the boot block.
Filesystems created with a newfs of this vintage or later
will create the recovery information. If you have a filesystem
created prior to this change and wish to have a recovery block
created for your filesystem, you can do so by running fsck in
forground mode (i.e., do not use the -p or -y options). As it
starts, fsck will ask ``SAVE DATA TO FIND ALTERNATE SUPERBLOCKS''
to which you should answer yes.
20170629:
The releng/11.1 branch has been created from stable/11@r320475.
20170518:
arm64 builds now use the base system LLD 4.0.0 linker by default,
instead of requiring that the aarch64-binutils port or package be
installed. To continue using aarch64-binutils, set
CROSS_BINUTILS_PREFIX=/usr/local/aarch64-freebsd/bin .
20170529:
The ctl.ko module no longer implements the iSCSI target frontend:
cfiscsi.ko does instead.
If building cfiscsi.ko as a kernel module, the module can be loaded
via one of the following methods:
- `cfiscsi_load="YES"` in loader.conf(5).
- Add `cfiscsi` to `$kld_list` in rc.conf(5).
- ctladm(8)/ctld(8), when compiled with iSCSI support
(`WITH_ISCSI=yes` in src.conf(5))
Please see cfiscsi(4) for more details.
20170511:
The mmcsd.ko module now additionally depends on geom_flashmap.ko.
Also, mmc.ko and mmcsd.ko need to be a matching pair built from the
same source (previously, the dependency of mmcsd.ko on mmc.ko was
missing, but mmcsd.ko now will refuse to load if it is incompatible
with mmc.ko).
20170414:
Binds and sends to the loopback addresses, IPv6 and IPv4, will now
use any explicitly assigned loopback address available in the jail
instead of using the first assigned address of the jail.
20170413:
As of r316810 for ipfilter, keep frags is no longer assumed when
keep state is specified in a rule. r316810 aligns ipfilter with
documentation in man pages separating keep frags from keep state.
This allows keep state to specified without forcing keep frags
and allows keep frags to be specified independently of keep state.
To maintain previous behaviour, also specify keep frags with
keep state (as documented in ipf.conf.5).
20170402:
Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 4.0.0.
Please see the 20141231 entry below for information about prerequisites
and upgrading, if you are not already using clang 3.5.0 or higher.
20170323:
The code that provides support for ZFS .zfs/ directory functionality
has been reimplemented. It's not possible now to create a snapshot
by mkdir under .zfs/snapshot/. That should be the only user visible
change.
20170319:
Many changes in the IPsec code have been merged from the FreeBSD-CURRENT
branch. The IPSEC_FILTERTUNNEL kernel option is removed in favour of
corresponding sysctl. The IPSEC_NAT_T kernel option is also removed,
and now NAT-T is supported by default. Security associations now use
the single namespace for SPI allocation, so if you use several manually
configured security associations with the same SPI, this configuration
needs modification.
20161217:
Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 3.9.1.
Please see the 20141231 entry below for information about prerequisites
and upgrading, if you are not already using clang 3.5.0 or higher.
20161124:
Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 3.9.0.
Please see the 20141231 entry below for information about prerequisites
and upgrading, if you are not already using clang 3.5.0 or higher.
20161119:
The layout of the pmap structure has changed for powerpc to put the pmap
statistics at the front for all CPU variations. libkvm(3) and all tools
that link against it need to be recompiled.
20161030:
isl(4) and cyapa(4) drivers now require a new driver,
chromebook_platform(4), to work properly on Chromebook-class hardware.
On other types of hardware the drivers may need to be configured using
device hints. Please see the corresponding manual pages for details.
20161210:
Relocatable object files with the extension of .So have been renamed
to use an extension of .pico instead. The purpose of this change is
to avoid a name clash with shared libraries on case-insensitive file
systems. On those file systems, foo.So is the same file as foo.so.
20160811:
The releng/11.0 branch has been created from stable/11@r303970.
20160708:
The stable/11 branch has been created from head@r302406.
20160622:
The libc stub for the pipe(2) system call has been replaced with
a wrapper that calls the pipe2(2) system call and the pipe(2)
system call is now only implemented by the kernels that include
"options COMPAT_FREEBSD10" in their config file (this is the
default). Users should ensure that this option is enabled in
their kernel or upgrade userspace to r302092 before upgrading their
kernel.
20160527:
CAM will now strip leading spaces from SCSI disks' serial numbers.
This will effect users who create UFS filesystems on SCSI disks using
those disk's diskid device nodes. For example, if /etc/fstab
previously contained a line like
"/dev/diskid/DISK-%20%20%20%20%20%20%20ABCDEFG0123456", you should
change it to "/dev/diskid/DISK-ABCDEFG0123456". Users of geom
transforms like gmirror may also be affected. ZFS users should
generally be fine.
20160523:
The bitstring(3) API has been updated with new functionality and
improved performance. But it is binary-incompatible with the old API.
Objects built with the new headers may not be linked against objects
built with the old headers.
20160520:
The brk and sbrk functions have been removed from libc on arm64.
Binutils from ports has been updated to not link to these
functions and should be updated to the latest version before
installing a new libc.
20160517:
The armv6 port now defaults to hard float ABI. Limited support
for running both hardfloat and soft float on the same system
is available using the libraries installed with -DWITH_LIBSOFT.
This has only been tested as an upgrade path for installworld
and packages may fail or need manual intervention to run. New
packages will be needed.
To update an existing self-hosted armv6hf system, you must add
TARGET_ARCH=armv6 on the make command line for both the build
and the install steps.
20160510:
Kernel modules compiled outside of a kernel build now default to
installing to /boot/modules instead of /boot/kernel. Many kernel
modules built this way (such as those in ports) already overrode
KMODDIR explicitly to install into /boot/modules. However,
manually building and installing a module from /sys/modules will
now install to /boot/modules instead of /boot/kernel.
20160414:
The CAM I/O scheduler has been committed to the kernel. There should be
no user visible impact. This does enable NCQ Trim on ada SSDs. While the
list of known rogues that claim support for this but actually corrupt
data is believed to be complete, be on the lookout for data
corruption. The known rogue list is believed to be complete:
o Crucial MX100, M550 drives with MU01 firmware.
o Micron M510 and M550 drives with MU01 firmware.
o Micron M500 prior to MU07 firmware
o Samsung 830, 840, and 850 all firmwares
o FCCT M500 all firmwares
Crucial has firmware http://www.crucial.com/usa/en/support-ssd-firmware
with working NCQ TRIM. For Micron branded drives, see your sales rep for
updated firmware. Black listed drives will work correctly because these
drives work correctly so long as no NCQ TRIMs are sent to them. Given
this list is the same as found in Linux, it's believed there are no
other rogues in the market place. All other models from the above
vendors work.
To be safe, if you are at all concerned, you can quirk each of your
drives to prevent NCQ from being sent by setting:
kern.cam.ada.X.quirks="0x2"
in loader.conf. If the drive requires the 4k sector quirk, set the
quirks entry to 0x3.
20160330:
The FAST_DEPEND build option has been removed and its functionality is
now the one true way. The old mkdep(1) style of 'make depend' has
been removed. See 20160311 for further details.
20160317:
Resource range types have grown from unsigned long to uintmax_t. All
drivers, and anything using libdevinfo, need to be recompiled.
20160311:
WITH_FAST_DEPEND is now enabled by default for in-tree and out-of-tree
builds. It no longer runs mkdep(1) during 'make depend', and the
'make depend' stage can safely be skipped now as it is auto ran
when building 'make all' and will generate all SRCS and DPSRCS before
building anything else. Dependencies are gathered at compile time with
-MF flags kept in separate .depend files per object file. Users should
run 'make cleandepend' once if using -DNO_CLEAN to clean out older
stale .depend files.
20160306:
On amd64, clang 3.8.0 can now insert sections of type AMD64_UNWIND into
kernel modules. Therefore, if you load any kernel modules at boot time,
please install the boot loaders after you install the kernel, but before
rebooting, e.g.:
make buildworld
make kernel KERNCONF=YOUR_KERNEL_HERE
make -C sys/boot install
<reboot in single user>
Then follow the usual steps, described in the General Notes section,
below.
20160305:
Clang, llvm, lldb and compiler-rt have been upgraded to 3.8.0. Please
see the 20141231 entry below for information about prerequisites and
upgrading, if you are not already using clang 3.5.0 or higher.
20160301:
The AIO subsystem is now a standard part of the kernel. The
VFS_AIO kernel option and aio.ko kernel module have been removed.
Due to stability concerns, asynchronous I/O requests are only
permitted on sockets and raw disks by default. To enable
asynchronous I/O requests on all file types, set the
vfs.aio.enable_unsafe sysctl to a non-zero value.
20160226:
The ELF object manipulation tool objcopy is now provided by the
ELF Tool Chain project rather than by GNU binutils. It should be a
drop-in replacement, with the addition of arm64 support. The
(temporary) src.conf knob WITHOUT_ELFCOPY_AS_OBJCOPY knob may be set
to obtain the GNU version if necessary.
20160129:
Building ZFS pools on top of zvols is prohibited by default. That
feature has never worked safely; it's always been prone to deadlocks.
Using a zvol as the backing store for a VM guest's virtual disk will
still work, even if the guest is using ZFS. Legacy behavior can be
restored by setting vfs.zfs.vol.recursive=1.
20160119:
The NONE and HPN patches has been removed from OpenSSH. They are
still available in the security/openssh-portable port.
20160113:
With the addition of ypldap(8), a new _ypldap user is now required
during installworld. "mergemaster -p" can be used to add the user
prior to installworld, as documented in the handbook.
20151216:
The tftp loader (pxeboot) now uses the option root-path directive. As a
consequence it no longer looks for a pxeboot.4th file on the tftp
server. Instead it uses the regular /boot infrastructure as with the
other loaders.
20151211:
The code to start recording plug and play data into the modules has
been committed. While the old tools will properly build a new kernel,
a number of warnings about "unknown metadata record 4" will be produced
for an older kldxref. To avoid such warnings, make sure to rebuild
the kernel toolchain (or world). Make sure that you have r292078 or
later when trying to build 292077 or later before rebuilding.
20151207:
Debug data files are now built by default with 'make buildworld' and
installed with 'make installworld'. This facilitates debugging but
requires more disk space both during the build and for the installed
world. Debug files may be disabled by setting WITHOUT_DEBUG_FILES=yes
in src.conf(5).
20151130:
r291527 changed the internal interface between the nfsd.ko and
nfscommon.ko modules. As such, they must both be upgraded to-gether.
__FreeBSD_version has been bumped because of this.
20151108:
Add support for unicode collation strings leads to a change of
order of files listed by ls(1) for example. To get back to the old
behaviour, set LC_COLLATE environment variable to "C".
Databases administrators will need to reindex their databases given
collation results will be different.
Due to a bug in install(1) it is recommended to remove the ancient
locales before running make installworld.
rm -rf /usr/share/locale/*
20151030:
The OpenSSL has been upgraded to 1.0.2d. Any binaries requiring
libcrypto.so.7 or libssl.so.7 must be recompiled.
20151020:
Qlogic 24xx/25xx firmware images were updated from 5.5.0 to 7.3.0.
Kernel modules isp_2400_multi and isp_2500_multi were removed and
should be replaced with isp_2400 and isp_2500 modules respectively.
20151017:
The build previously allowed using 'make -n' to not recurse into
sub-directories while showing what commands would be executed, and
'make -n -n' to recursively show commands. Now 'make -n' will recurse
and 'make -N' will not.
20151012:
If you specify SENDMAIL_MC or SENDMAIL_CF in make.conf, mergemaster
and etcupdate will now use this file. A custom sendmail.cf is now
updated via this mechanism rather than via installworld. If you had
excluded sendmail.cf in mergemaster.rc or etcupdate.conf, you may
want to remove the exclusion or change it to "always install".
/etc/mail/sendmail.cf is now managed the same way regardless of
whether SENDMAIL_MC/SENDMAIL_CF is used. If you are not using
SENDMAIL_MC/SENDMAIL_CF there should be no change in behavior.
20151011:
Compatibility shims for legacy ATA device names have been removed.
It includes ATA_STATIC_ID kernel option, kern.cam.ada.legacy_aliases
and kern.geom.raid.legacy_aliases loader tunables, kern.devalias.*
environment variables, /dev/ad* and /dev/ar* symbolic links.
20151006:
Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 3.7.0.
Please see the 20141231 entry below for information about prerequisites
and upgrading, if you are not already using clang 3.5.0 or higher.
20150924:
Kernel debug files have been moved to /usr/lib/debug/boot/kernel/,
and renamed from .symbols to .debug. This reduces the size requirements
on the boot partition or file system and provides consistency with
userland debug files.
When using the supported kernel installation method the
/usr/lib/debug/boot/kernel directory will be renamed (to kernel.old)
as is done with /boot/kernel.
Developers wishing to maintain the historical behavior of installing
debug files in /boot/kernel/ can set KERN_DEBUGDIR="" in src.conf(5).
20150827:
The wireless drivers had undergone changes that remove the 'parent
interface' from the ifconfig -l output. The rc.d network scripts
used to check presence of a parent interface in the list, so old
scripts would fail to start wireless networking. Thus, etcupdate(3)
or mergemaster(8) run is required after kernel update, to update your
rc.d scripts in /etc.
20150827:
pf no longer supports 'scrub fragment crop' or 'scrub fragment drop-ovl'
These configurations are now automatically interpreted as
'scrub fragment reassemble'.
20150817:
Kernel-loadable modules for the random(4) device are back. To use
them, the kernel must have
device random
options RANDOM_LOADABLE
kldload(8) can then be used to load random_fortuna.ko
or random_yarrow.ko. Please note that due to the indirect
function calls that the loadable modules need to provide,
the build-in variants will be slightly more efficient.
The random(4) kernel option RANDOM_DUMMY has been retired due to
unpopularity. It was not all that useful anyway.
20150813:
The WITHOUT_ELFTOOLCHAIN_TOOLS src.conf(5) knob has been retired.
Control over building the ELF Tool Chain tools is now provided by
the WITHOUT_TOOLCHAIN knob.
20150810:
The polarity of Pulse Per Second (PPS) capture events with the
uart(4) driver has been corrected. Prior to this change the PPS
"assert" event corresponded to the trailing edge of a positive PPS
pulse and the "clear" event was the leading edge of the next pulse.
As the width of a PPS pulse in a typical GPS receiver is on the
order of 1 millisecond, most users will not notice any significant
difference with this change.
Anyone who has compensated for the historical polarity reversal by
configuring a negative offset equal to the pulse width will need to
remove that workaround.
20150809:
The default group assigned to /dev/dri entries has been changed
from 'wheel' to 'video' with the id of '44'. If you want to have
access to the dri devices please add yourself to the video group
with:
# pw groupmod video -m $USER
20150806:
The menu.rc and loader.rc files will now be replaced during
upgrades. Please migrate local changes to menu.rc.local and
loader.rc.local instead.
20150805:
GNU Binutils versions of addr2line, c++filt, nm, readelf, size,
strings and strip have been removed. The src.conf(5) knob
WITHOUT_ELFTOOLCHAIN_TOOLS no longer provides the binutils tools.
20150728:
As ZFS requires more kernel stack pages than is the default on some
architectures e.g. i386, it now warns if KSTACK_PAGES is less than
ZFS_MIN_KSTACK_PAGES (which is 4 at the time of writing).
Please consider using 'options KSTACK_PAGES=X' where X is greater
than or equal to ZFS_MIN_KSTACK_PAGES i.e. 4 in such configurations.
20150706:
sendmail has been updated to 8.15.2. Starting with FreeBSD 11.0
and sendmail 8.15, sendmail uses uncompressed IPv6 addresses by
default, i.e., they will not contain "::". For example, instead
of ::1, it will be 0:0:0:0:0:0:0:1. This permits a zero subnet
to have a more specific match, such as different map entries for
IPv6:0:0 vs IPv6:0. This change requires that configuration
data (including maps, files, classes, custom ruleset, etc.) must
use the same format, so make certain such configuration data is
upgrading. As a very simple check search for patterns like
'IPv6:[0-9a-fA-F:]*::' and 'IPv6::'. To return to the old
behavior, set the m4 option confUSE_COMPRESSED_IPV6_ADDRESSES or
the cf option UseCompressedIPv6Addresses.
20150630:
The default kernel entropy-processing algorithm is now
Fortuna, replacing Yarrow.
Assuming you have 'device random' in your kernel config
file, the configurations allow a kernel option to override
this default. You may choose *ONE* of:
options RANDOM_YARROW # Legacy /dev/random algorithm.
options RANDOM_DUMMY # Blocking-only driver.
If you have neither, you get Fortuna. For most people,
read no further, Fortuna will give a /dev/random that works
like it always used to, and the difference will be irrelevant.
If you remove 'device random', you get *NO* kernel-processed
entropy at all. This may be acceptable to folks building
embedded systems, but has complications. Carry on reading,
and it is assumed you know what you need.
*PLEASE* read random(4) and random(9) if you are in the
habit of tweaking kernel configs, and/or if you are a member
of the embedded community, wanting specific and not-usual
behaviour from your security subsystems.
NOTE!! If you use RANDOM_DUMMY and/or have no 'device
random', you will NOT have a functioning /dev/random, and
many cryptographic features will not work, including SSH.
You may also find strange behaviour from the random(3) set
of library functions, in particular sranddev(3), srandomdev(3)
and arc4random(3). The reason for this is that the KERN_ARND
sysctl only returns entropy if it thinks it has some to
share, and with RANDOM_DUMMY or no 'device random' this
will never happen.
20150623:
An additional fix for the issue described in the 20150614 sendmail
entry below has been been committed in revision 284717.
20150616:
FreeBSD's old make (fmake) has been removed from the system. It is
available as the devel/fmake port or via pkg install fmake.
20150615:
The fix for the issue described in the 20150614 sendmail entry
below has been been committed in revision 284436. The work
around described in that entry is no longer needed unless the
default setting is overridden by a confDH_PARAMETERS configuration
setting of '5' or pointing to a 512 bit DH parameter file.
20150614:
ALLOW_DEPRECATED_ATF_TOOLS/ATFFILE support has been removed from
atf.test.mk (included from bsd.test.mk). Please upgrade devel/atf
and devel/kyua to version 0.20+ and adjust any calling code to work
with Kyuafile and kyua.
20150614:
The import of openssl to address the FreeBSD-SA-15:10.openssl
security advisory includes a change which rejects handshakes
with DH parameters below 768 bits. sendmail releases prior
to 8.15.2 (not yet released), defaulted to a 512 bit
DH parameter setting for client connections. To work around
this interoperability, sendmail can be configured to use a
2048 bit DH parameter by:
1. Edit /etc/mail/`hostname`.mc
2. If a setting for confDH_PARAMETERS does not exist or
exists and is set to a string beginning with '5',
replace it with '2'.
3. If a setting for confDH_PARAMETERS exists and is set to
a file path, create a new file with:
openssl dhparam -out /path/to/file 2048
4. Rebuild the .cf file:
cd /etc/mail/; make; make install
5. Restart sendmail:
cd /etc/mail/; make restart
A sendmail patch is coming, at which time this file will be
updated.
20150604:
Generation of legacy formatted entries have been disabled by default
in pwd_mkdb(8), as all base system consumers of the legacy formatted
entries were converted to use the new format by default when the new,
machine independent format have been added and supported since FreeBSD
5.x.
Please see the pwd_mkdb(8) manual page for further details.
20150525:
Clang and llvm have been upgraded to 3.6.1 release. Please see the
20141231 entry below for information about prerequisites and upgrading,
if you are not already using 3.5.0 or higher.
20150521:
TI platform code switched to using vendor DTS files and this update
may break existing systems running on Beaglebone, Beaglebone Black,
and Pandaboard:
- dtb files should be regenerated/reinstalled. Filenames are the
same but content is different now
- GPIO addressing was changed, now each GPIO bank (32 pins per bank)
has its own /dev/gpiocX device, e.g. pin 121 on /dev/gpioc0 in old
addressing scheme is now pin 25 on /dev/gpioc3.
- Pandaboard: /etc/ttys should be updated, serial console device is
now /dev/ttyu2, not /dev/ttyu0
20150501:
soelim(1) from gnu/usr.bin/groff has been replaced by usr.bin/soelim.
If you need the GNU extension from groff soelim(1), install groff
from package: pkg install groff, or via ports: textproc/groff.
20150423:
chmod, chflags, chown and chgrp now affect symlinks in -R mode as
defined in symlink(7); previously symlinks were silently ignored.
20150415:
The const qualifier has been removed from iconv(3) to comply with
POSIX. The ports tree is aware of this from r384038 onwards.
20150416:
Libraries specified by LIBADD in Makefiles must have a corresponding
DPADD_<lib> variable to ensure correct dependencies. This is now
enforced in src.libnames.mk.
20150324:
From legacy ata(4) driver was removed support for SATA controllers
supported by more functional drivers ahci(4), siis(4) and mvs(4).
Kernel modules ataahci and ataadaptec were removed completely,
replaced by ahci and mvs modules respectively.
20150315:
Clang, llvm and lldb have been upgraded to 3.6.0 release. Please see
the 20141231 entry below for information about prerequisites and
upgrading, if you are not already using 3.5.0 or higher.
20150307:
The 32-bit PowerPC kernel has been changed to a position-independent
executable. This can only be booted with a version of loader(8)
newer than January 31, 2015, so make sure to update both world and
kernel before rebooting.
20150217:
If you are running a -CURRENT kernel since r273872 (Oct 30th, 2014),
but before r278950, the RNG was not seeded properly. Immediately
upgrade the kernel to r278950 or later and regenerate any keys (e.g.
ssh keys or openssl keys) that were generated w/ a kernel from that
range. This does not affect programs that directly used /dev/random
or /dev/urandom. All userland uses of arc4random(3) are affected.
20150210:
The autofs(4) ABI was changed in order to restore binary compatibility
with 10.1-RELEASE. The automountd(8) daemon needs to be rebuilt to work
with the new kernel.
20150131:
The powerpc64 kernel has been changed to a position-independent
executable. This can only be booted with a new version of loader(8),
so make sure to update both world and kernel before rebooting.
20150118:
Clang and llvm have been upgraded to 3.5.1 release. This is a bugfix
only release, no new features have been added. Please see the 20141231
entry below for information about prerequisites and upgrading, if you
are not already using 3.5.0.
20150107:
ELF tools addr2line, elfcopy (strip), nm, size, and strings are now
taken from the ELF Tool Chain project rather than GNU binutils. They
should be drop-in replacements, with the addition of arm64 support.
The WITHOUT_ELFTOOLCHAIN_TOOLS= knob may be used to obtain the
binutils tools, if necessary. See 20150805 for updated information.
20150105:
The default Unbound configuration now enables remote control
using a local socket. Users who have already enabled the
local_unbound service should regenerate their configuration
by running "service local_unbound setup" as root.
20150102:
The GNU texinfo and GNU info pages have been removed.
To be able to view GNU info pages please install texinfo from ports.
20141231:
Clang, llvm and lldb have been upgraded to 3.5.0 release.
As of this release, a prerequisite for building clang, llvm and lldb is
a C++11 capable compiler and C++11 standard library. This means that to
be able to successfully build the cross-tools stage of buildworld, with
clang as the bootstrap compiler, your system compiler or cross compiler
should either be clang 3.3 or later, or gcc 4.8 or later, and your
system C++ library should be libc++, or libdstdc++ from gcc 4.8 or
later.
On any standard FreeBSD 10.x or 11.x installation, where clang and
libc++ are on by default (that is, on x86 or arm), this should work out
of the box.
On 9.x installations where clang is enabled by default, e.g. on x86 and
powerpc, libc++ will not be enabled by default, so libc++ should be
built (with clang) and installed first. If both clang and libc++ are
missing, build clang first, then use it to build libc++.
On 8.x and earlier installations, upgrade to 9.x first, and then follow
the instructions for 9.x above.
Sparc64 and mips users are unaffected, as they still use gcc 4.2.1 by
default, and do not build clang.
Many embedded systems are resource constrained, and will not be able to
build clang in a reasonable time, or in some cases at all. In those
cases, cross building bootable systems on amd64 is a workaround.
This new version of clang introduces a number of new warnings, of which
the following are most likely to appear:
-Wabsolute-value
This warns in two cases, for both C and C++:
* When the code is trying to take the absolute value of an unsigned
quantity, which is effectively a no-op, and almost never what was
intended. The code should be fixed, if at all possible. If you are
sure that the unsigned quantity can be safely cast to signed, without
loss of information or undefined behavior, you can add an explicit
cast, or disable the warning.
* When the code is trying to take an absolute value, but the called
abs() variant is for the wrong type, which can lead to truncation.
If you want to disable the warning instead of fixing the code, please
make sure that truncation will not occur, or it might lead to unwanted
side-effects.
-Wtautological-undefined-compare and
-Wundefined-bool-conversion
These warn when C++ code is trying to compare 'this' against NULL, while
'this' should never be NULL in well-defined C++ code. However, there is
some legacy (pre C++11) code out there, which actively abuses this
feature, which was less strictly defined in previous C++ versions.
Squid and openjdk do this, for example. The warning can be turned off
for C++98 and earlier, but compiling the code in C++11 mode might result
in unexpected behavior; for example, the parts of the program that are
unreachable could be optimized away.
20141222:
The old NFS client and server (kernel options NFSCLIENT, NFSSERVER)
kernel sources have been removed. The .h files remain, since some
utilities include them. This will need to be fixed later.
If "mount -t oldnfs ..." is attempted, it will fail.
If the "-o" option on mountd(8), nfsd(8) or nfsstat(1) is used,
the utilities will report errors.
20141121:
The handling of LOCAL_LIB_DIRS has been altered to skip addition of
directories to top level SUBDIR variable when their parent
directory is included in LOCAL_DIRS. Users with build systems with
such hierarchies and without SUBDIR entries in the parent
directory Makefiles should add them or add the directories to
LOCAL_DIRS.
20141109:
faith(4) and faithd(8) have been removed from the base system. Faith
has been obsolete for a very long time.
20141104:
vt(4), the new console driver, is enabled by default. It brings
support for Unicode and double-width characters, as well as
support for UEFI and integration with the KMS kernel video
drivers.
You may need to update your console settings in /etc/rc.conf,
most probably the keymap. During boot, /etc/rc.d/syscons will
indicate what you need to do.
vt(4) still has issues and lacks some features compared to
syscons(4). See the wiki for up-to-date information:
https://wiki.freebsd.org/Newcons
If you want to keep using syscons(4), you can do so by adding
the following line to /boot/loader.conf:
kern.vty=sc
20141102:
pjdfstest has been integrated into kyua as an opt-in test suite.
Please see share/doc/pjdfstest/README for more details on how to
execute it.
20141009:
gperf has been removed from the base system for architectures
that use clang. Ports that require gperf will obtain it from the
devel/gperf port.
20140923:
pjdfstest has been moved from tools/regression/pjdfstest to
contrib/pjdfstest .
20140922:
At svn r271982, The default linux compat kernel ABI has been adjusted
to 2.6.18 in support of the linux-c6 compat ports infrastructure
update. If you wish to continue using the linux-f10 compat ports,
add compat.linux.osrelease=2.6.16 to your local sysctl.conf. Users are
encouraged to update their linux-compat packages to linux-c6 during
their next update cycle.
20140729:
The ofwfb driver, used to provide a graphics console on PowerPC when
using vt(4), no longer allows mmap() of all physical memory. This
will prevent Xorg on PowerPC with some ATI graphics cards from
initializing properly unless x11-servers/xorg-server is updated to
1.12.4_8 or newer.
20140723:
The xdev targets have been converted to using TARGET and
TARGET_ARCH instead of XDEV and XDEV_ARCH.
20140719:
The default unbound configuration has been modified to address
issues with reverse lookups on networks that use private
address ranges. If you use the local_unbound service, run
"service local_unbound setup" as root to regenerate your
configuration, then "service local_unbound reload" to load the
new configuration.
20140709:
The GNU texinfo and GNU info pages are not built and installed
anymore, WITH_INFO knob has been added to allow to built and install
them again.
UPDATE: see 20150102 entry on texinfo's removal
20140708:
The GNU readline library is now an INTERNALLIB - that is, it is
statically linked into consumers (GDB and variants) in the base
system, and the shared library is no longer installed. The
devel/readline port is available for third party software that
requires readline.
20140702:
The Itanium architecture (ia64) has been removed from the list of
known architectures. This is the first step in the removal of the
architecture.
20140701:
Commit r268115 has added NFSv4.1 server support, merged from
projects/nfsv4.1-server. Since this includes changes to the
internal interfaces between the NFS related modules, a full
build of the kernel and modules will be necessary.
__FreeBSD_version has been bumped.
20140629:
The WITHOUT_VT_SUPPORT kernel config knob has been renamed
WITHOUT_VT. (The other _SUPPORT knobs have a consistent meaning
which differs from the behaviour controlled by this knob.)
20140619:
Maximal length of the serial number in CTL was increased from 16 to
64 chars, that breaks ABI. All CTL-related tools, such as ctladm
and ctld, need to be rebuilt to work with a new kernel.
20140606:
The libatf-c and libatf-c++ major versions were downgraded to 0 and
1 respectively to match the upstream numbers. They were out of
sync because, when they were originally added to FreeBSD, the
upstream versions were not respected. These libraries are private
and not yet built by default, so renumbering them should be a
non-issue. However, unclean source trees will yield broken test
programs once the operator executes "make delete-old-libs" after a
"make installworld".
Additionally, the atf-sh binary was made private by moving it into
/usr/libexec/. Already-built shell test programs will keep the
path to the old binary so they will break after "make delete-old"
is run.
If you are using WITH_TESTS=yes (not the default), wipe the object
tree and rebuild from scratch to prevent spurious test failures.
This is only needed once: the misnumbered libraries and misplaced
binaries have been added to OptionalObsoleteFiles.inc so they will
be removed during a clean upgrade.
20140512:
Clang and llvm have been upgraded to 3.4.1 release.
20140508:
We bogusly installed src.opts.mk in /usr/share/mk. This file should
be removed to avoid issues in the future (and has been added to
ObsoleteFiles.inc).
20140505:
/etc/src.conf now affects only builds of the FreeBSD src tree. In the
past, it affected all builds that used the bsd.*.mk files. The old
behavior was a bug, but people may have relied upon it. To get this
behavior back, you can .include /etc/src.conf from /etc/make.conf
(which is still global and isn't changed). This also changes the
behavior of incremental builds inside the tree of individual
directories. Set MAKESYSPATH to ".../share/mk" to do that.
Although this has survived make universe and some upgrade scenarios,
other upgrade scenarios may have broken. At least one form of
temporary breakage was fixed with MAKESYSPATH settings for buildworld
as well... In cases where MAKESYSPATH isn't working with this
setting, you'll need to set it to the full path to your tree.
One side effect of all this cleaning up is that bsd.compiler.mk
is no longer implicitly included by bsd.own.mk. If you wish to
use COMPILER_TYPE, you must now explicitly include bsd.compiler.mk
as well.
20140430:
The lindev device has been removed since /dev/full has been made a
standard device. __FreeBSD_version has been bumped.
20140424:
The knob WITHOUT_VI was added to the base system, which controls
building ex(1), vi(1), etc. Older releases of FreeBSD required ex(1)
in order to reorder files share/termcap and didn't build ex(1) as a
build tool, so building/installing with WITH_VI is highly advised for
build hosts for older releases.
This issue has been fixed in stable/9 and stable/10 in r277022 and
r276991, respectively.
20140418:
The YES_HESIOD knob has been removed. It has been obsolete for
a decade. Please move to using WITH_HESIOD instead or your builds
will silently lack HESIOD.
20140405:
The uart(4) driver has been changed with respect to its handling
of the low-level console. Previously the uart(4) driver prevented
any process from changing the baudrate or the CLOCAL and HUPCL
control flags. By removing the restrictions, operators can make
changes to the serial console port without having to reboot.
However, when getty(8) is started on the serial device that is
associated with the low-level console, a misconfigured terminal
line in /etc/ttys will now have a real impact.
Before upgrading the kernel, make sure that /etc/ttys has the
serial console device configured as 3wire without baudrate to
preserve the previous behaviour. E.g:
ttyu0 "/usr/libexec/getty 3wire" vt100 on secure
20140306:
Support for libwrap (TCP wrappers) in rpcbind was disabled by default
to improve performance. To re-enable it, if needed, run rpcbind
with command line option -W.
20140226:
Switched back to the GPL dtc compiler due to updates in the upstream
dts files not being supported by the BSDL dtc compiler. You will need
to rebuild your kernel toolchain to pick up the new compiler. Core dumps
may result while building dtb files during a kernel build if you fail
to do so. Set WITHOUT_GPL_DTC if you require the BSDL compiler.
20140216:
Clang and llvm have been upgraded to 3.4 release.
20140216:
The nve(4) driver has been removed. Please use the nfe(4) driver
for NVIDIA nForce MCP Ethernet adapters instead.
20140212:
An ABI incompatibility crept into the libc++ 3.4 import in r261283.
This could cause certain C++ applications using shared libraries built
against the previous version of libc++ to crash. The incompatibility
has now been fixed, but any C++ applications or shared libraries built
between r261283 and r261801 should be recompiled.
20140204:
OpenSSH will now ignore errors caused by kernel lacking of Capsicum
capability mode support. Please note that enabling the feature in
kernel is still highly recommended.
20140131:
OpenSSH is now built with sandbox support, and will use sandbox as
the default privilege separation method. This requires Capsicum
capability mode support in kernel.
20140128:
The libelf and libdwarf libraries have been updated to newer
versions from upstream. Shared library version numbers for
these two libraries were bumped. Any ports or binaries
requiring these two libraries should be recompiled.
__FreeBSD_version is bumped to 1100006.
20140110:
If a Makefile in a tests/ directory was auto-generating a Kyuafile
instead of providing an explicit one, this would prevent such
Makefile from providing its own Kyuafile in the future during
NO_CLEAN builds. This has been fixed in the Makefiles but manual
intervention is needed to clean an objdir if you use NO_CLEAN:
# find /usr/obj -name Kyuafile | xargs rm -f
20131213:
The behavior of gss_pseudo_random() for the krb5 mechanism
has changed, for applications requesting a longer random string
than produced by the underlying enctype's pseudo-random() function.
In particular, the random string produced from a session key of
enctype aes256-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 will
be different at the 17th octet and later, after this change.
The counter used in the PRF+ construction is now encoded as a
big-endian integer in accordance with RFC 4402.
__FreeBSD_version is bumped to 1100004.
20131108:
The WITHOUT_ATF build knob has been removed and its functionality
has been subsumed into the more generic WITHOUT_TESTS. If you were
using the former to disable the build of the ATF libraries, you
should change your settings to use the latter.
20131025:
The default version of mtree is nmtree which is obtained from
NetBSD. The output is generally the same, but may vary
slightly. If you found you need identical output adding
"-F freebsd9" to the command line should do the trick. For the
time being, the old mtree is available as fmtree.
20131014:
libbsdyml has been renamed to libyaml and moved to /usr/lib/private.
This will break ports-mgmt/pkg. Rebuild the port, or upgrade to pkg
1.1.4_8 and verify bsdyml not linked in, before running "make
delete-old-libs":
# make -C /usr/ports/ports-mgmt/pkg build deinstall install clean
or
# pkg install pkg; ldd /usr/local/sbin/pkg | grep bsdyml
20131010:
The stable/10 branch has been created in subversion from head
revision r256279.
20131010:
The rc.d/jail script has been updated to support jail(8)
configuration file. The "jail_<jname>_*" rc.conf(5) variables
for per-jail configuration are automatically converted to
/var/run/jail.<jname>.conf before the jail(8) utility is invoked.
This is transparently backward compatible. See below about some
incompatibilities and rc.conf(5) manual page for more details.
These variables are now deprecated in favor of jail(8) configuration
file. One can use "rc.d/jail config <jname>" command to generate
a jail(8) configuration file in /var/run/jail.<jname>.conf without
running the jail(8) utility. The default pathname of the
configuration file is /etc/jail.conf and can be specified by
using $jail_conf or $jail_<jname>_conf variables.
Please note that jail_devfs_ruleset accepts an integer at
this moment. Please consider to rewrite the ruleset name
with an integer.
20130930:
BIND has been removed from the base system. If all you need
is a local resolver, simply enable and start the local_unbound
service instead. Otherwise, several versions of BIND are
available in the ports tree. The dns/bind99 port is one example.
With this change, nslookup(1) and dig(1) are no longer in the base
system. Users should instead use host(1) and drill(1) which are
in the base system. Alternatively, nslookup and dig can
be obtained by installing the dns/bind-tools port.
20130916:
With the addition of unbound(8), a new unbound user is now
required during installworld. "mergemaster -p" can be used to
add the user prior to installworld, as documented in the handbook.
20130911:
OpenSSH is now built with DNSSEC support, and will by default
silently trust signed SSHFP records. This can be controlled with
the VerifyHostKeyDNS client configuration setting. DNSSEC support
can be disabled entirely with the WITHOUT_LDNS option in src.conf.
20130906:
The GNU Compiler Collection and C++ standard library (libstdc++)
are no longer built by default on platforms where clang is the system
compiler. You can enable them with the WITH_GCC and WITH_GNUCXX
options in src.conf.
20130905:
The PROCDESC kernel option is now part of the GENERIC kernel
configuration and is required for the rwhod(8) to work.
If you are using custom kernel configuration, you should include
'options PROCDESC'.
20130905:
The API and ABI related to the Capsicum framework was modified
in backward incompatible way. The userland libraries and programs
have to be recompiled to work with the new kernel. This includes the
following libraries and programs, but the whole buildworld is
advised: libc, libprocstat, dhclient, tcpdump, hastd, hastctl,
kdump, procstat, rwho, rwhod, uniq.
20130903:
AES-NI intrinsic support has been added to gcc. The AES-NI module
has been updated to use this support. A new gcc is required to build
the aesni module on both i386 and amd64.
20130821:
The PADLOCK_RNG and RDRAND_RNG kernel options are now devices.
Thus "device padlock_rng" and "device rdrand_rng" should be
used instead of "options PADLOCK_RNG" & "options RDRAND_RNG".
20130813:
WITH_ICONV has been split into two feature sets. WITH_ICONV now
enables just the iconv* functionality and is now on by default.
WITH_LIBICONV_COMPAT enables the libiconv api and link time
compatibility. Set WITHOUT_ICONV to build the old way.
If you have been using WITH_ICONV before, you will very likely
need to turn on WITH_LIBICONV_COMPAT.
20130806:
INVARIANTS option now enables DEBUG for code with OpenSolaris and
Illumos origin, including ZFS. If you have INVARIANTS in your
kernel configuration, then there is no need to set DEBUG or ZFS_DEBUG
explicitly.
DEBUG used to enable witness(9) tracking of OpenSolaris (mostly ZFS)
locks if WITNESS option was set. Because that generated a lot of
witness(9) reports and all of them were believed to be false
positives, this is no longer done. New option OPENSOLARIS_WITNESS
can be used to achieve the previous behavior.
20130806:
Timer values in IPv6 data structures now use time_uptime instead
of time_second. Although this is not a user-visible functional
change, userland utilities which directly use them---ndp(8),
rtadvd(8), and rtsold(8) in the base system---need to be updated
to r253970 or later.
20130802:
find -delete can now delete the pathnames given as arguments,
instead of only files found below them or if the pathname did
not contain any slashes. Formerly, the following error message
would result:
find: -delete: <path>: relative path potentially not safe
Deleting the pathnames given as arguments can be prevented
without error messages using -mindepth 1 or by changing
directory and passing "." as argument to find. This works in the
old as well as the new version of find.
20130726:
Behavior of devfs rules path matching has been changed.
Pattern is now always matched against fully qualified devfs
path and slash characters must be explicitly matched by
slashes in pattern (FNM_PATHNAME). Rulesets involving devfs
subdirectories must be reviewed.
20130716:
The default ARM ABI has changed to the ARM EABI. The old ABI is
incompatible with the ARM EABI and all programs and modules will
need to be rebuilt to work with a new kernel.
To keep using the old ABI ensure the WITHOUT_ARM_EABI knob is set.
NOTE: Support for the old ABI will be removed in the future and
users are advised to upgrade.
20130709:
pkg_install has been disconnected from the build if you really need it
you should add WITH_PKGTOOLS in your src.conf(5).
20130709:
Most of network statistics structures were changed to be able
keep 64-bits counters. Thus all tools, that work with networking
statistics, must be rebuilt (netstat(1), bsnmpd(1), etc.)
20130618:
Fix a bug that allowed a tracing process (e.g. gdb) to write
to a memory-mapped file in the traced process's address space
even if neither the traced process nor the tracing process had
write access to that file.
20130615:
CVS has been removed from the base system. An exact copy
of the code is available from the devel/cvs port.
20130613:
Some people report the following error after the switch to bmake:
make: illegal option -- J
usage: make [-BPSXeiknpqrstv] [-C directory] [-D variable]
...
*** [buildworld] Error code 2
this likely due to an old instance of make in
${MAKEPATH} (${MAKEOBJDIRPREFIX}${.CURDIR}/make.${MACHINE})
which src/Makefile will use that blindly, if it exists, so if
you see the above error:
rm -rf `make -V MAKEPATH`
should resolve it.
20130516:
Use bmake by default.
Whereas before one could choose to build with bmake via
-DWITH_BMAKE one must now use -DWITHOUT_BMAKE to use the old
make. The goal is to remove these knobs for 10-RELEASE.
It is worth noting that bmake (like gmake) treats the command
line as the unit of failure, rather than statements within the
command line. Thus '(cd some/where && dosomething)' is safer
than 'cd some/where; dosomething'. The '()' allows consistent
behavior in parallel build.
20130429:
Fix a bug that allows NFS clients to issue READDIR on files.
20130426:
The WITHOUT_IDEA option has been removed because
the IDEA patent expired.
20130426:
The sysctl which controls TRIM support under ZFS has been renamed
from vfs.zfs.trim_disable -> vfs.zfs.trim.enabled and has been
enabled by default.
20130425:
The mergemaster command now uses the default MAKEOBJDIRPREFIX
rather than creating it's own in the temporary directory in
order allow access to bootstrapped versions of tools such as
install and mtree. When upgrading from version of FreeBSD where
the install command does not support -l, you will need to
install a new mergemaster command if mergemaster -p is required.
This can be accomplished with the command (cd src/usr.sbin/mergemaster
&& make install).
20130404:
Legacy ATA stack, disabled and replaced by new CAM-based one since
FreeBSD 9.0, completely removed from the sources. Kernel modules
atadisk and atapi*, user-level tools atacontrol and burncd are
removed. Kernel option `options ATA_CAM` is now permanently enabled
and removed.
20130319:
SOCK_CLOEXEC and SOCK_NONBLOCK flags have been added to socket(2)
and socketpair(2). Software, in particular Kerberos, may
automatically detect and use these during building. The resulting
binaries will not work on older kernels.
20130308:
CTL_DISABLE has also been added to the sparc64 GENERIC (for further
information, see the respective 20130304 entry).
20130304:
Recent commits to callout(9) changed the size of struct callout,
so the KBI is probably heavily disturbed. Also, some functions
in callout(9)/sleep(9)/sleepqueue(9)/condvar(9) KPIs were replaced
by macros. Every kernel module using it won't load, so rebuild
is requested.
The ctl device has been re-enabled in GENERIC for i386 and amd64,
but does not initialize by default (because of the new CTL_DISABLE
option) to save memory. To re-enable it, remove the CTL_DISABLE
option from the kernel config file or set kern.cam.ctl.disable=0
in /boot/loader.conf.
20130301:
The ctl device has been disabled in GENERIC for i386 and amd64.
This was done due to the extra memory being allocated at system
initialisation time by the ctl driver which was only used if
a CAM target device was created. This makes a FreeBSD system
unusable on 128MB or less of RAM.
20130208:
A new compression method (lz4) has been merged to -HEAD. Please
refer to zpool-features(7) for more information.
Please refer to the "ZFS notes" section of this file for information
on upgrading boot ZFS pools.
20130129:
A BSD-licensed patch(1) variant has been added and is installed
as bsdpatch, being the GNU version the default patch.
To inverse the logic and use the BSD-licensed one as default,
while having the GNU version installed as gnupatch, rebuild
and install world with the WITH_BSD_PATCH knob set.
20130121:
Due to the use of the new -l option to install(1) during build
and install, you must take care not to directly set the INSTALL
make variable in your /etc/make.conf, /etc/src.conf, or on the
command line. If you wish to use the -C flag for all installs
you may be able to add INSTALL+=-C to /etc/make.conf or
/etc/src.conf.
20130118:
The install(1) option -M has changed meaning and now takes an
argument that is a file or path to append logs to. In the
unlikely event that -M was the last option on the command line
and the command line contained at least two files and a target
directory the first file will have logs appended to it. The -M
option served little practical purpose in the last decade so its
use is expected to be extremely rare.
20121223:
After switching to Clang as the default compiler some users of ZFS
on i386 systems started to experience stack overflow kernel panics.
Please consider using 'options KSTACK_PAGES=4' in such configurations.
20121222:
GEOM_LABEL now mangles label names read from file system metadata.
Mangling affect labels containing spaces, non-printable characters,
'%' or '"'. Device names in /etc/fstab and other places may need to
be updated.
20121217:
By default, only the 10 most recent kernel dumps will be saved. To
restore the previous behaviour (no limit on the number of kernel dumps
stored in the dump directory) add the following line to /etc/rc.conf:
savecore_flags=""
20121201:
With the addition of auditdistd(8), a new auditdistd user is now
required during installworld. "mergemaster -p" can be used to
add the user prior to installworld, as documented in the handbook.
20121117:
The sin6_scope_id member variable in struct sockaddr_in6 is now
filled by the kernel before passing the structure to the userland via
sysctl or routing socket. This means the KAME-specific embedded scope
id in sin6_addr.s6_addr[2] is always cleared in userland application.
This behavior can be controlled by net.inet6.ip6.deembed_scopeid.
__FreeBSD_version is bumped to 1000025.
20121105:
On i386 and amd64 systems WITH_CLANG_IS_CC is now the default.
This means that the world and kernel will be compiled with clang
and that clang will be installed as /usr/bin/cc, /usr/bin/c++,
and /usr/bin/cpp. To disable this behavior and revert to building
with gcc, compile with WITHOUT_CLANG_IS_CC. Really old versions
of current may need to bootstrap WITHOUT_CLANG first if the clang
build fails (its compatibility window doesn't extend to the 9 stable
branch point).
20121102:
The IPFIREWALL_FORWARD kernel option has been removed. Its
functionality now turned on by default.
20121023:
The ZERO_COPY_SOCKET kernel option has been removed and
split into SOCKET_SEND_COW and SOCKET_RECV_PFLIP.
NB: SOCKET_SEND_COW uses the VM page based copy-on-write
mechanism which is not safe and may result in kernel crashes.
NB: The SOCKET_RECV_PFLIP mechanism is useless as no current
driver supports disposeable external page sized mbuf storage.
Proper replacements for both zero-copy mechanisms are under
consideration and will eventually lead to complete removal
of the two kernel options.
20121023:
The IPv4 network stack has been converted to network byte
order. The following modules need to be recompiled together
with kernel: carp(4), divert(4), gif(4), siftr(4), gre(4),
pf(4), ipfw(4), ng_ipfw(4), stf(4).
20121022:
Support for non-MPSAFE filesystems was removed from VFS. The
VFS_VERSION was bumped, all filesystem modules shall be
recompiled.
20121018:
All the non-MPSAFE filesystems have been disconnected from
the build. The full list includes: codafs, hpfs, ntfs, nwfs,
portalfs, smbfs, xfs.
20121016:
The interface cloning API and ABI has changed. The following
modules need to be recompiled together with kernel:
ipfw(4), pfsync(4), pflog(4), usb(4), wlan(4), stf(4),
vlan(4), disc(4), edsc(4), if_bridge(4), gif(4), tap(4),
faith(4), epair(4), enc(4), tun(4), if_lagg(4), gre(4).
20121015:
The sdhci driver was split in two parts: sdhci (generic SD Host
Controller logic) and sdhci_pci (actual hardware driver).
No kernel config modifications are required, but if you
load sdhc as a module you must switch to sdhci_pci instead.
20121014:
Import the FUSE kernel and userland support into base system.
20121013:
The GNU sort(1) program has been removed since the BSD-licensed
sort(1) has been the default for quite some time and no serious
problems have been reported. The corresponding WITH_GNU_SORT
knob has also gone.
20121006:
The pfil(9) API/ABI for AF_INET family has been changed. Packet
filtering modules: pf(4), ipfw(4), ipfilter(4) need to be recompiled
with new kernel.
20121001:
The net80211(4) ABI has been changed to allow for improved driver
PS-POLL and power-save support. All wireless drivers need to be
recompiled to work with the new kernel.
20120913:
The random(4) support for the VIA hardware random number
generator (`PADLOCK') is no longer enabled unconditionally.
Add the padlock_rng device in the custom kernel config if
needed. The GENERIC kernels on i386 and amd64 do include the
device, so the change only affects the custom kernel
configurations.
20120908:
The pf(4) packet filter ABI has been changed. pfctl(8) and
snmp_pf module need to be recompiled to work with new kernel.
20120828:
A new ZFS feature flag "com.delphix:empty_bpobj" has been merged
to -HEAD. Pools that have empty_bpobj in active state can not be
imported read-write with ZFS implementations that do not support
this feature. For more information read the zpool-features(5)
manual page.
20120727:
The sparc64 ZFS loader has been changed to no longer try to auto-
detect ZFS providers based on diskN aliases but now requires these
to be explicitly listed in the OFW boot-device environment variable.
20120712:
The OpenSSL has been upgraded to 1.0.1c. Any binaries requiring
libcrypto.so.6 or libssl.so.6 must be recompiled. Also, there are
configuration changes. Make sure to merge /etc/ssl/openssl.cnf.
20120712:
The following sysctls and tunables have been renamed for consistency
with other variables:
kern.cam.da.da_send_ordered -> kern.cam.da.send_ordered
kern.cam.ada.ada_send_ordered -> kern.cam.ada.send_ordered
20120628:
The sort utility has been replaced with BSD sort. For now, GNU sort
is also available as "gnusort" or the default can be set back to
GNU sort by setting WITH_GNU_SORT. In this case, BSD sort will be
installed as "bsdsort".
20120611:
A new version of ZFS (pool version 5000) has been merged to -HEAD.
Starting with this version the old system of ZFS pool versioning
is superseded by "feature flags". This concept enables forward
compatibility against certain future changes in functionality of ZFS
pools. The first read-only compatible "feature flag" for ZFS pools
is named "com.delphix:async_destroy". For more information
read the new zpool-features(5) manual page.
Please refer to the "ZFS notes" section of this file for information
on upgrading boot ZFS pools.
20120417:
The malloc(3) implementation embedded in libc now uses sources imported
as contrib/jemalloc. The most disruptive API change is to
/etc/malloc.conf. If your system has an old-style /etc/malloc.conf,
delete it prior to installworld, and optionally re-create it using the
new format after rebooting. See malloc.conf(5) for details
(specifically the TUNING section and the "opt.*" entries in the MALLCTL
NAMESPACE section).
20120328:
Big-endian MIPS TARGET_ARCH values no longer end in "eb". mips64eb
is now spelled mips64. mipsn32eb is now spelled mipsn32. mipseb is
now spelled mips. This is to aid compatibility with third-party
software that expects this naming scheme in uname(3). Little-endian
settings are unchanged. If you are updating a big-endian mips64 machine
from before this change, you may need to set MACHINE_ARCH=mips64 in
your environment before the new build system will recognize your machine.
20120306:
Disable by default the option VFS_ALLOW_NONMPSAFE for all supported
platforms.
20120229:
Now unix domain sockets behave "as expected" on nullfs(5). Previously
nullfs(5) did not pass through all behaviours to the underlying layer,
as a result if we bound to a socket on the lower layer we could connect
only to the lower path; if we bound to the upper layer we could connect
only to the upper path. The new behavior is one can connect to both the
lower and the upper paths regardless what layer path one binds to.
20120211:
The getifaddrs upgrade path broken with 20111215 has been restored.
If you have upgraded in between 20111215 and 20120209 you need to
recompile libc again with your kernel. You still need to recompile
world to be able to configure CARP but this restriction already
comes from 20111215.
20120114:
The set_rcvar() function has been removed from /etc/rc.subr. All
base and ports rc.d scripts have been updated, so if you have a
port installed with a script in /usr/local/etc/rc.d you can either
hand-edit the rcvar= line, or reinstall the port.
An easy way to handle the mass-update of /etc/rc.d:
rm /etc/rc.d/* && mergemaster -i
20120109:
panic(9) now stops other CPUs in the SMP systems, disables interrupts
on the current CPU and prevents other threads from running.
This behavior can be reverted using the kern.stop_scheduler_on_panic
tunable/sysctl.
The new behavior can be incompatible with kern.sync_on_panic.
20111215:
The carp(4) facility has been changed significantly. Configuration
of the CARP protocol via ifconfig(8) has changed, as well as format
of CARP events submitted to devd(8) has changed. See manual pages
for more information. The arpbalance feature of carp(4) is currently
not supported anymore.
Size of struct in_aliasreq, struct in6_aliasreq has changed. User
utilities using SIOCAIFADDR, SIOCAIFADDR_IN6, e.g. ifconfig(8),
need to be recompiled.
20111122:
The acpi_wmi(4) status device /dev/wmistat has been renamed to
/dev/wmistat0.
20111108:
The option VFS_ALLOW_NONMPSAFE option has been added in order to
explicitely support non-MPSAFE filesystems.
It is on by default for all supported platform at this present
time.
20111101:
The broken amd(4) driver has been replaced with esp(4) in the amd64,
i386 and pc98 GENERIC kernel configuration files.
20110930:
sysinstall has been removed
20110923:
The stable/9 branch created in subversion. This corresponds to the
RELENG_9 branch in CVS.
COMMON ITEMS:
General Notes
-------------
Avoid using make -j when upgrading. While generally safe, there are
sometimes problems using -j to upgrade. If your upgrade fails with
-j, please try again without -j. From time to time in the past there
have been problems using -j with buildworld and/or installworld. This
is especially true when upgrading between "distant" versions (eg one
that cross a major release boundary or several minor releases, or when
several months have passed on the -current branch).
Sometimes, obscure build problems are the result of environment
poisoning. This can happen because the make utility reads its
environment when searching for values for global variables. To run
your build attempts in an "environmental clean room", prefix all make
commands with 'env -i '. See the env(1) manual page for more details.
When upgrading from one major version to another it is generally best
to upgrade to the latest code in the currently installed branch first,
then do an upgrade to the new branch. This is the best-tested upgrade
path, and has the highest probability of being successful. Please try
this approach before reporting problems with a major version upgrade.
When upgrading a live system, having a root shell around before
installing anything can help undo problems. Not having a root shell
around can lead to problems if pam has changed too much from your
starting point to allow continued authentication after the upgrade.
This file should be read as a log of events. When a later event changes
information of a prior event, the prior event should not be deleted.
Instead, a pointer to the entry with the new information should be
placed in the old entry. Readers of this file should also sanity check
older entries before relying on them blindly. Authors of new entries
should write them with this in mind.
ZFS notes
---------
When upgrading the boot ZFS pool to a new version, always follow
these two steps:
1.) recompile and reinstall the ZFS boot loader and boot block
(this is part of "make buildworld" and "make installworld")
2.) update the ZFS boot block on your boot drive
The following example updates the ZFS boot block on the first
partition (freebsd-boot) of a GPT partitioned drive ada0:
"gpart bootcode -p /boot/gptzfsboot -i 1 ada0"
Non-boot pools do not need these updates.
To build a kernel
-----------------
If you are updating from a prior version of FreeBSD (even one just
a few days old), you should follow this procedure. It is the most
failsafe as it uses a /usr/obj tree with a fresh mini-buildworld,
make kernel-toolchain
make -DALWAYS_CHECK_MAKE buildkernel KERNCONF=YOUR_KERNEL_HERE
make -DALWAYS_CHECK_MAKE installkernel KERNCONF=YOUR_KERNEL_HERE
To test a kernel once
---------------------
If you just want to boot a kernel once (because you are not sure
if it works, or if you want to boot a known bad kernel to provide
debugging information) run
make installkernel KERNCONF=YOUR_KERNEL_HERE KODIR=/boot/testkernel
nextboot -k testkernel
To just build a kernel when you know that it won't mess you up
--------------------------------------------------------------
This assumes you are already running a CURRENT system. Replace
${arch} with the architecture of your machine (e.g. "i386",
"arm", "amd64", "ia64", "pc98", "sparc64", "powerpc", "mips", etc).
cd src/sys/${arch}/conf
config KERNEL_NAME_HERE
cd ../compile/KERNEL_NAME_HERE
make depend
make
make install
If this fails, go to the "To build a kernel" section.
To rebuild everything and install it on the current system.
-----------------------------------------------------------
# Note: sometimes if you are running current you gotta do more than
# is listed here if you are upgrading from a really old current.
<make sure you have good level 0 dumps>
make buildworld
make kernel KERNCONF=YOUR_KERNEL_HERE
[1]
<reboot in single user> [3]
mergemaster -Fp [5]
make installworld
mergemaster -Fi [4]
make delete-old [6]
<reboot>
To cross-install current onto a separate partition
--------------------------------------------------
# In this approach we use a separate partition to hold
# current's root, 'usr', and 'var' directories. A partition
# holding "/", "/usr" and "/var" should be about 2GB in
# size.
<make sure you have good level 0 dumps>
<boot into -stable>
make buildworld
make buildkernel KERNCONF=YOUR_KERNEL_HERE
<maybe newfs current's root partition>
<mount current's root partition on directory ${CURRENT_ROOT}>
make installworld DESTDIR=${CURRENT_ROOT} -DDB_FROM_SRC
make distribution DESTDIR=${CURRENT_ROOT} # if newfs'd
make installkernel KERNCONF=YOUR_KERNEL_HERE DESTDIR=${CURRENT_ROOT}
cp /etc/fstab ${CURRENT_ROOT}/etc/fstab # if newfs'd
<edit ${CURRENT_ROOT}/etc/fstab to mount "/" from the correct partition>
<reboot into current>
<do a "native" rebuild/install as described in the previous section>
<maybe install compatibility libraries from ports/misc/compat*>
<reboot>
To upgrade in-place from stable to current
----------------------------------------------
<make sure you have good level 0 dumps>
make buildworld [9]
make kernel KERNCONF=YOUR_KERNEL_HERE [8]
[1]
<reboot in single user> [3]
mergemaster -Fp [5]
make installworld
mergemaster -Fi [4]
make delete-old [6]
<reboot>
Make sure that you've read the UPDATING file to understand the
tweaks to various things you need. At this point in the life
cycle of current, things change often and you are on your own
to cope. The defaults can also change, so please read ALL of
the UPDATING entries.
Also, if you are tracking -current, you must be subscribed to
freebsd-current@freebsd.org. Make sure that before you update
your sources that you have read and understood all the recent
messages there. If in doubt, please track -stable which has
much fewer pitfalls.
[1] If you have third party modules, such as vmware, you
should disable them at this point so they don't crash your
system on reboot.
[3] From the bootblocks, boot -s, and then do
fsck -p
mount -u /
mount -a
cd src
adjkerntz -i # if CMOS is wall time
Also, when doing a major release upgrade, it is required that
you boot into single user mode to do the installworld.
[4] Note: This step is non-optional. Failure to do this step
can result in a significant reduction in the functionality of the
system. Attempting to do it by hand is not recommended and those
that pursue this avenue should read this file carefully, as well
as the archives of freebsd-current and freebsd-hackers mailing lists
for potential gotchas. The -U option is also useful to consider.
See mergemaster(8) for more information.
[5] Usually this step is a noop. However, from time to time
you may need to do this if you get unknown user in the following
step. It never hurts to do it all the time. You may need to
install a new mergemaster (cd src/usr.sbin/mergemaster && make
install) after the buildworld before this step if you last updated
from current before 20130425 or from -stable before 20130430.
[6] This only deletes old files and directories. Old libraries
can be deleted by "make delete-old-libs", but you have to make
sure that no program is using those libraries anymore.
[8] The new kernel must be able to run existing binaries used by
an installworld. When upgrading across major versions, the new
kernel's configuration must include the correct COMPAT_FREEBSD<n>
option for existing binaries (e.g. COMPAT_FREEBSD11 to run 11.x
binaries). Failure to do so may leave you with a system that is
hard to boot to recover. A GENERIC kernel will include suitable
compatibility options to run binaries from older branches.
Make sure that you merge any new devices from GENERIC since the
last time you updated your kernel config file.
[9] When checking out sources, you must include the -P flag to have
cvs prune empty directories.
If CPUTYPE is defined in your /etc/make.conf, make sure to use the
"?=" instead of the "=" assignment operator, so that buildworld can
override the CPUTYPE if it needs to.
MAKEOBJDIRPREFIX must be defined in an environment variable, and
not on the command line, or in /etc/make.conf. buildworld will
warn if it is improperly defined.
FORMAT:
This file contains a list, in reverse chronological order, of major
breakages in tracking -current. It is not guaranteed to be a complete
list of such breakages, and only contains entries since September 23, 2011.
If you need to see UPDATING entries from before that date, you will need
to fetch an UPDATING file from an older FreeBSD release.
Copyright information:
Copyright 1998-2009 M. Warner Losh. All Rights Reserved.
Redistribution, publication, translation and use, with or without
modification, in full or in part, in any form or format of this
document are permitted without further permission from the author.
THIS DOCUMENT IS PROVIDED BY WARNER LOSH ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL WARNER LOSH BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Contact Warner Losh if you have any questions about your use of
this document.
$FreeBSD$
Index: stable/11/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc
===================================================================
--- stable/11/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc (revision 350258)
+++ stable/11/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc (revision 350259)
@@ -1,2344 +1,2346 @@
//===-- sanitizer_platform_limits_netbsd.cc -------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of Sanitizer common code.
//
// Sizes and layouts of platform-specific NetBSD data structures.
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
#if SANITIZER_NETBSD
#define _KMEMUSER
#define RAY_DO_SIGLEV
// clang-format off
#include <sys/param.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/disk.h>
#include <sys/disklabel.h>
#include <sys/mount.h>
#include <sys/agpio.h>
#include <sys/ataio.h>
#include <sys/audioio.h>
#include <sys/cdbr.h>
#include <sys/cdio.h>
#include <sys/chio.h>
#include <sys/clockctl.h>
#include <sys/cpuio.h>
#include <sys/dkio.h>
#include <sys/drvctlio.h>
#include <sys/dvdio.h>
#include <sys/envsys.h>
#include <sys/event.h>
#include <sys/fdio.h>
#include <sys/filio.h>
#include <sys/gpio.h>
#include <sys/ioctl.h>
#include <sys/ioctl_compat.h>
#include <sys/joystick.h>
#include <sys/ksyms.h>
#include <sys/lua.h>
#include <sys/midiio.h>
#include <sys/mtio.h>
#include <sys/power.h>
#include <sys/radioio.h>
#include <sys/rndio.h>
#include <sys/scanio.h>
#include <sys/scsiio.h>
#include <sys/sockio.h>
#include <sys/timepps.h>
#include <sys/ttycom.h>
#include <sys/verified_exec.h>
#include <sys/videoio.h>
#include <sys/wdog.h>
#include <sys/event.h>
#include <sys/filio.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/module.h>
#include <sys/mount.h>
#include <sys/mqueue.h>
#include <sys/msg.h>
#include <sys/mtio.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/sem.h>
#include <sys/sha1.h>
#include <sys/sha2.h>
#include <sys/shm.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/soundcard.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/times.h>
#include <sys/timespec.h>
#include <sys/timex.h>
#include <sys/types.h>
#include <sys/ucontext.h>
#include <sys/utsname.h>
#include <altq/altq.h>
#include <altq/altq_afmap.h>
#include <altq/altq_blue.h>
#include <altq/altq_cbq.h>
#include <altq/altq_cdnr.h>
#include <altq/altq_fifoq.h>
#include <altq/altq_hfsc.h>
#include <altq/altq_jobs.h>
#include <altq/altq_priq.h>
#include <altq/altq_red.h>
#include <altq/altq_rio.h>
#include <altq/altq_wfq.h>
#include <arpa/inet.h>
#include <crypto/cryptodev.h>
#include <dev/apm/apmio.h>
#include <dev/dm/netbsd-dm.h>
#include <dev/dmover/dmover_io.h>
#include <dev/dtv/dtvio_demux.h>
#include <dev/dtv/dtvio_frontend.h>
#include <dev/filemon/filemon.h>
#include <dev/hdaudio/hdaudioio.h>
#include <dev/hdmicec/hdmicecio.h>
#include <dev/hpc/hpcfbio.h>
#include <dev/i2o/iopio.h>
#include <dev/ic/athioctl.h>
#include <dev/ic/bt8xx.h>
#include <dev/ic/icp_ioctl.h>
#include <dev/ic/isp_ioctl.h>
#include <dev/ic/mlxio.h>
#include <dev/ic/qemufwcfgio.h>
#include <dev/ic/nvmeio.h>
#include <dev/ir/irdaio.h>
#include <dev/isa/isvio.h>
#include <dev/isa/wtreg.h>
#include <dev/iscsi/iscsi_ioctl.h>
+#if 0
#include <dev/nvmm/nvmm_ioctl.h>
+#endif
#include <dev/ofw/openfirmio.h>
#include <dev/pci/amrio.h>
#include <dev/pci/mlyreg.h>
#include <dev/pci/mlyio.h>
#include <dev/pci/pciio.h>
#include <dev/pci/tweio.h>
#include <dev/pcmcia/if_cnwioctl.h>
#include <net/bpf.h>
#include <net/if_gre.h>
#include <net/ppp_defs.h>
#include <net/if_ppp.h>
#include <net/if_pppoe.h>
#include <net/if_sppp.h>
#include <net/if_srt.h>
#include <net/if_tap.h>
#include <net/if_tun.h>
#include <net/npf.h>
#include <net/pfvar.h>
#include <net/slip.h>
#include <netbt/hci.h>
#include <netinet/ip_compat.h>
#include <netinet/ip_fil.h>
#include <netinet/ip_nat.h>
#include <netinet/ip_proxy.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
#include <netsmb/smb_dev.h>
#include <dev/biovar.h>
#include <dev/bluetooth/btdev.h>
#include <dev/bluetooth/btsco.h>
#include <dev/ccdvar.h>
#include <dev/cgdvar.h>
#include <dev/fssvar.h>
#include <dev/kttcpio.h>
#include <dev/lockstat.h>
#include <dev/md.h>
#include <net/if_ether.h>
#include <dev/pcmcia/if_rayreg.h>
#include <stdio.h>
#include <dev/raidframe/raidframeio.h>
#include <dev/sbus/mbppio.h>
#include <dev/scsipi/ses.h>
#include <dev/spkrio.h>
#include <dev/sun/disklabel.h>
#include <dev/sun/fbio.h>
#include <dev/sun/kbio.h>
#include <dev/sun/vuid_event.h>
#include <dev/tc/sticio.h>
#include <dev/usb/ukyopon.h>
#include <dev/usb/urio.h>
#include <dev/usb/usb.h>
#include <dev/usb/utoppy.h>
#include <dev/vme/xio.h>
#include <dev/vndvar.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplay_usl_io.h>
#include <fs/autofs/autofs_ioctl.h>
#include <dirent.h>
#include <glob.h>
#include <grp.h>
#include <ifaddrs.h>
#include <limits.h>
#include <link_elf.h>
#include <net/if.h>
#include <net/route.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip_mroute.h>
#include <netinet/sctp_uio.h>
#include <poll.h>
#include <pthread.h>
#include <pwd.h>
#include <semaphore.h>
#include <signal.h>
#include <stddef.h>
#include <md2.h>
#include <md4.h>
#include <md5.h>
#include <rmd160.h>
#include <soundcard.h>
#include <term.h>
#include <termios.h>
#include <time.h>
#include <ttyent.h>
#include <utime.h>
#include <utmp.h>
#include <utmpx.h>
#include <vis.h>
#include <wchar.h>
#include <wordexp.h>
#include <ttyent.h>
#include <fts.h>
#include <regex.h>
#include <fstab.h>
#include <stringlist.h>
// clang-format on
// Include these after system headers to avoid name clashes and ambiguities.
#include "sanitizer_internal_defs.h"
#include "sanitizer_platform_limits_netbsd.h"
namespace __sanitizer {
unsigned struct_utsname_sz = sizeof(struct utsname);
unsigned struct_stat_sz = sizeof(struct stat);
unsigned struct_rusage_sz = sizeof(struct rusage);
unsigned struct_tm_sz = sizeof(struct tm);
unsigned struct_passwd_sz = sizeof(struct passwd);
unsigned struct_group_sz = sizeof(struct group);
unsigned siginfo_t_sz = sizeof(siginfo_t);
unsigned struct_sigaction_sz = sizeof(struct sigaction);
unsigned struct_itimerval_sz = sizeof(struct itimerval);
unsigned pthread_t_sz = sizeof(pthread_t);
unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
unsigned pthread_cond_t_sz = sizeof(pthread_cond_t);
unsigned pid_t_sz = sizeof(pid_t);
unsigned timeval_sz = sizeof(timeval);
unsigned uid_t_sz = sizeof(uid_t);
unsigned gid_t_sz = sizeof(gid_t);
unsigned mbstate_t_sz = sizeof(mbstate_t);
unsigned sigset_t_sz = sizeof(sigset_t);
unsigned struct_timezone_sz = sizeof(struct timezone);
unsigned struct_tms_sz = sizeof(struct tms);
unsigned struct_sigevent_sz = sizeof(struct sigevent);
unsigned struct_sched_param_sz = sizeof(struct sched_param);
unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
unsigned ucontext_t_sz = sizeof(ucontext_t);
unsigned struct_rlimit_sz = sizeof(struct rlimit);
unsigned struct_timespec_sz = sizeof(struct timespec);
unsigned struct_sembuf_sz = sizeof(struct sembuf);
unsigned struct_kevent_sz = sizeof(struct kevent);
unsigned struct_FTS_sz = sizeof(FTS);
unsigned struct_FTSENT_sz = sizeof(FTSENT);
unsigned struct_regex_sz = sizeof(regex_t);
unsigned struct_regmatch_sz = sizeof(regmatch_t);
unsigned struct_fstab_sz = sizeof(struct fstab);
unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
unsigned struct_timex_sz = sizeof(struct timex);
unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
unsigned struct_statvfs_sz = sizeof(struct statvfs);
unsigned struct_sigaltstack_sz = sizeof(stack_t);
const uptr sig_ign = (uptr)SIG_IGN;
const uptr sig_dfl = (uptr)SIG_DFL;
const uptr sig_err = (uptr)SIG_ERR;
const uptr sa_siginfo = (uptr)SA_SIGINFO;
const unsigned long __sanitizer_bufsiz = BUFSIZ;
int ptrace_pt_io = PT_IO;
int ptrace_pt_lwpinfo = PT_LWPINFO;
int ptrace_pt_set_event_mask = PT_SET_EVENT_MASK;
int ptrace_pt_get_event_mask = PT_GET_EVENT_MASK;
int ptrace_pt_get_process_state = PT_GET_PROCESS_STATE;
int ptrace_pt_set_siginfo = PT_SET_SIGINFO;
int ptrace_pt_get_siginfo = PT_GET_SIGINFO;
int ptrace_piod_read_d = PIOD_READ_D;
int ptrace_piod_write_d = PIOD_WRITE_D;
int ptrace_piod_read_i = PIOD_READ_I;
int ptrace_piod_write_i = PIOD_WRITE_I;
int ptrace_piod_read_auxv = PIOD_READ_AUXV;
#if defined(PT_SETREGS) && defined(PT_GETREGS)
int ptrace_pt_setregs = PT_SETREGS;
int ptrace_pt_getregs = PT_GETREGS;
#else
int ptrace_pt_setregs = -1;
int ptrace_pt_getregs = -1;
#endif
#if defined(PT_SETFPREGS) && defined(PT_GETFPREGS)
int ptrace_pt_setfpregs = PT_SETFPREGS;
int ptrace_pt_getfpregs = PT_GETFPREGS;
#else
int ptrace_pt_setfpregs = -1;
int ptrace_pt_getfpregs = -1;
#endif
#if defined(PT_SETDBREGS) && defined(PT_GETDBREGS)
int ptrace_pt_setdbregs = PT_SETDBREGS;
int ptrace_pt_getdbregs = PT_GETDBREGS;
#else
int ptrace_pt_setdbregs = -1;
int ptrace_pt_getdbregs = -1;
#endif
unsigned struct_ptrace_ptrace_io_desc_struct_sz = sizeof(struct ptrace_io_desc);
unsigned struct_ptrace_ptrace_lwpinfo_struct_sz = sizeof(struct ptrace_lwpinfo);
unsigned struct_ptrace_ptrace_event_struct_sz = sizeof(ptrace_event_t);
unsigned struct_ptrace_ptrace_siginfo_struct_sz = sizeof(ptrace_siginfo_t);
#if defined(PT_SETREGS)
unsigned struct_ptrace_reg_struct_sz = sizeof(struct reg);
#else
unsigned struct_ptrace_reg_struct_sz = -1;
#endif
#if defined(PT_SETFPREGS)
unsigned struct_ptrace_fpreg_struct_sz = sizeof(struct fpreg);
#else
unsigned struct_ptrace_fpreg_struct_sz = -1;
#endif
#if defined(PT_SETDBREGS)
unsigned struct_ptrace_dbreg_struct_sz = sizeof(struct dbreg);
#else
unsigned struct_ptrace_dbreg_struct_sz = -1;
#endif
int shmctl_ipc_stat = (int)IPC_STAT;
unsigned struct_utmp_sz = sizeof(struct utmp);
unsigned struct_utmpx_sz = sizeof(struct utmpx);
int map_fixed = MAP_FIXED;
int af_inet = (int)AF_INET;
int af_inet6 = (int)AF_INET6;
uptr __sanitizer_in_addr_sz(int af) {
if (af == AF_INET)
return sizeof(struct in_addr);
else if (af == AF_INET6)
return sizeof(struct in6_addr);
else
return 0;
}
unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
int glob_nomatch = GLOB_NOMATCH;
int glob_altdirfunc = GLOB_ALTDIRFUNC;
unsigned path_max = PATH_MAX;
int struct_ttyent_sz = sizeof(struct ttyent);
struct __sanitizer_nvlist_ref_t {
void *buf;
uptr len;
int flags;
};
typedef __sanitizer_nvlist_ref_t nvlist_ref_t;
// ioctl arguments
unsigned struct_altqreq_sz = sizeof(altqreq);
unsigned struct_amr_user_ioctl_sz = sizeof(amr_user_ioctl);
unsigned struct_ap_control_sz = sizeof(ap_control);
unsigned struct_apm_ctl_sz = sizeof(apm_ctl);
unsigned struct_apm_event_info_sz = sizeof(apm_event_info);
unsigned struct_apm_power_info_sz = sizeof(apm_power_info);
unsigned struct_atabusiodetach_args_sz = sizeof(atabusiodetach_args);
unsigned struct_atabusioscan_args_sz = sizeof(atabusioscan_args);
unsigned struct_ath_diag_sz = sizeof(ath_diag);
unsigned struct_atm_flowmap_sz = sizeof(atm_flowmap);
unsigned struct_audio_buf_info_sz = sizeof(audio_buf_info);
unsigned struct_audio_device_sz = sizeof(audio_device);
unsigned struct_audio_encoding_sz = sizeof(audio_encoding);
unsigned struct_audio_info_sz = sizeof(audio_info);
unsigned struct_audio_offset_sz = sizeof(audio_offset);
unsigned struct_bio_locate_sz = sizeof(bio_locate);
unsigned struct_bioc_alarm_sz = sizeof(bioc_alarm);
unsigned struct_bioc_blink_sz = sizeof(bioc_blink);
unsigned struct_bioc_disk_sz = sizeof(bioc_disk);
unsigned struct_bioc_inq_sz = sizeof(bioc_inq);
unsigned struct_bioc_setstate_sz = sizeof(bioc_setstate);
unsigned struct_bioc_vol_sz = sizeof(bioc_vol);
unsigned struct_bioc_volops_sz = sizeof(bioc_volops);
unsigned struct_bktr_chnlset_sz = sizeof(bktr_chnlset);
unsigned struct_bktr_remote_sz = sizeof(bktr_remote);
unsigned struct_blue_conf_sz = sizeof(blue_conf);
unsigned struct_blue_interface_sz = sizeof(blue_interface);
unsigned struct_blue_stats_sz = sizeof(blue_stats);
unsigned struct_bpf_dltlist_sz = sizeof(bpf_dltlist);
unsigned struct_bpf_program_sz = sizeof(bpf_program);
unsigned struct_bpf_stat_old_sz = sizeof(bpf_stat_old);
unsigned struct_bpf_stat_sz = sizeof(bpf_stat);
unsigned struct_bpf_version_sz = sizeof(bpf_version);
unsigned struct_btreq_sz = sizeof(btreq);
unsigned struct_btsco_info_sz = sizeof(btsco_info);
unsigned struct_buffmem_desc_sz = sizeof(buffmem_desc);
unsigned struct_cbq_add_class_sz = sizeof(cbq_add_class);
unsigned struct_cbq_add_filter_sz = sizeof(cbq_add_filter);
unsigned struct_cbq_delete_class_sz = sizeof(cbq_delete_class);
unsigned struct_cbq_delete_filter_sz = sizeof(cbq_delete_filter);
unsigned struct_cbq_getstats_sz = sizeof(cbq_getstats);
unsigned struct_cbq_interface_sz = sizeof(cbq_interface);
unsigned struct_cbq_modify_class_sz = sizeof(cbq_modify_class);
unsigned struct_ccd_ioctl_sz = sizeof(ccd_ioctl);
unsigned struct_cdnr_add_element_sz = sizeof(cdnr_add_element);
unsigned struct_cdnr_add_filter_sz = sizeof(cdnr_add_filter);
unsigned struct_cdnr_add_tbmeter_sz = sizeof(cdnr_add_tbmeter);
unsigned struct_cdnr_add_trtcm_sz = sizeof(cdnr_add_trtcm);
unsigned struct_cdnr_add_tswtcm_sz = sizeof(cdnr_add_tswtcm);
unsigned struct_cdnr_delete_element_sz = sizeof(cdnr_delete_element);
unsigned struct_cdnr_delete_filter_sz = sizeof(cdnr_delete_filter);
unsigned struct_cdnr_get_stats_sz = sizeof(cdnr_get_stats);
unsigned struct_cdnr_interface_sz = sizeof(cdnr_interface);
unsigned struct_cdnr_modify_tbmeter_sz = sizeof(cdnr_modify_tbmeter);
unsigned struct_cdnr_modify_trtcm_sz = sizeof(cdnr_modify_trtcm);
unsigned struct_cdnr_modify_tswtcm_sz = sizeof(cdnr_modify_tswtcm);
unsigned struct_cdnr_tbmeter_stats_sz = sizeof(cdnr_tbmeter_stats);
unsigned struct_cdnr_tcm_stats_sz = sizeof(cdnr_tcm_stats);
unsigned struct_cgd_ioctl_sz = sizeof(cgd_ioctl);
unsigned struct_cgd_user_sz = sizeof(cgd_user);
unsigned struct_changer_element_status_request_sz =
sizeof(changer_element_status_request);
unsigned struct_changer_exchange_request_sz = sizeof(changer_exchange_request);
unsigned struct_changer_move_request_sz = sizeof(changer_move_request);
unsigned struct_changer_params_sz = sizeof(changer_params);
unsigned struct_changer_position_request_sz = sizeof(changer_position_request);
unsigned struct_changer_set_voltag_request_sz =
sizeof(changer_set_voltag_request);
unsigned struct_clockctl_adjtime_sz = sizeof(clockctl_adjtime);
unsigned struct_clockctl_clock_settime_sz = sizeof(clockctl_clock_settime);
unsigned struct_clockctl_ntp_adjtime_sz = sizeof(clockctl_ntp_adjtime);
unsigned struct_clockctl_settimeofday_sz = sizeof(clockctl_settimeofday);
unsigned struct_cnwistats_sz = sizeof(cnwistats);
unsigned struct_cnwitrail_sz = sizeof(cnwitrail);
unsigned struct_cnwstatus_sz = sizeof(cnwstatus);
unsigned struct_count_info_sz = sizeof(count_info);
unsigned struct_cpu_ucode_sz = sizeof(cpu_ucode);
unsigned struct_cpu_ucode_version_sz = sizeof(cpu_ucode_version);
unsigned struct_crypt_kop_sz = sizeof(crypt_kop);
unsigned struct_crypt_mkop_sz = sizeof(crypt_mkop);
unsigned struct_crypt_mop_sz = sizeof(crypt_mop);
unsigned struct_crypt_op_sz = sizeof(crypt_op);
unsigned struct_crypt_result_sz = sizeof(crypt_result);
unsigned struct_crypt_sfop_sz = sizeof(crypt_sfop);
unsigned struct_crypt_sgop_sz = sizeof(crypt_sgop);
unsigned struct_cryptret_sz = sizeof(cryptret);
unsigned struct_devdetachargs_sz = sizeof(devdetachargs);
unsigned struct_devlistargs_sz = sizeof(devlistargs);
unsigned struct_devpmargs_sz = sizeof(devpmargs);
unsigned struct_devrescanargs_sz = sizeof(devrescanargs);
unsigned struct_disk_badsecinfo_sz = sizeof(disk_badsecinfo);
unsigned struct_disk_strategy_sz = sizeof(disk_strategy);
unsigned struct_disklabel_sz = sizeof(disklabel);
unsigned struct_dkbad_sz = sizeof(dkbad);
unsigned struct_dkwedge_info_sz = sizeof(dkwedge_info);
unsigned struct_dkwedge_list_sz = sizeof(dkwedge_list);
unsigned struct_dmio_setfunc_sz = sizeof(dmio_setfunc);
unsigned struct_dmx_pes_filter_params_sz = sizeof(dmx_pes_filter_params);
unsigned struct_dmx_sct_filter_params_sz = sizeof(dmx_sct_filter_params);
unsigned struct_dmx_stc_sz = sizeof(dmx_stc);
unsigned struct_dvb_diseqc_master_cmd_sz = sizeof(dvb_diseqc_master_cmd);
unsigned struct_dvb_diseqc_slave_reply_sz = sizeof(dvb_diseqc_slave_reply);
unsigned struct_dvb_frontend_event_sz = sizeof(dvb_frontend_event);
unsigned struct_dvb_frontend_info_sz = sizeof(dvb_frontend_info);
unsigned struct_dvb_frontend_parameters_sz = sizeof(dvb_frontend_parameters);
unsigned struct_eccapreq_sz = sizeof(eccapreq);
unsigned struct_fbcmap_sz = sizeof(fbcmap);
unsigned struct_fbcurpos_sz = sizeof(fbcurpos);
unsigned struct_fbcursor_sz = sizeof(fbcursor);
unsigned struct_fbgattr_sz = sizeof(fbgattr);
unsigned struct_fbsattr_sz = sizeof(fbsattr);
unsigned struct_fbtype_sz = sizeof(fbtype);
unsigned struct_fdformat_cmd_sz = sizeof(fdformat_cmd);
unsigned struct_fdformat_parms_sz = sizeof(fdformat_parms);
unsigned struct_fifoq_conf_sz = sizeof(fifoq_conf);
unsigned struct_fifoq_getstats_sz = sizeof(fifoq_getstats);
unsigned struct_fifoq_interface_sz = sizeof(fifoq_interface);
unsigned struct_format_op_sz = sizeof(format_op);
unsigned struct_fss_get_sz = sizeof(fss_get);
unsigned struct_fss_set_sz = sizeof(fss_set);
unsigned struct_gpio_attach_sz = sizeof(gpio_attach);
unsigned struct_gpio_info_sz = sizeof(gpio_info);
unsigned struct_gpio_req_sz = sizeof(gpio_req);
unsigned struct_gpio_set_sz = sizeof(gpio_set);
unsigned struct_hfsc_add_class_sz = sizeof(hfsc_add_class);
unsigned struct_hfsc_add_filter_sz = sizeof(hfsc_add_filter);
unsigned struct_hfsc_attach_sz = sizeof(hfsc_attach);
unsigned struct_hfsc_class_stats_sz = sizeof(hfsc_class_stats);
unsigned struct_hfsc_delete_class_sz = sizeof(hfsc_delete_class);
unsigned struct_hfsc_delete_filter_sz = sizeof(hfsc_delete_filter);
unsigned struct_hfsc_interface_sz = sizeof(hfsc_interface);
unsigned struct_hfsc_modify_class_sz = sizeof(hfsc_modify_class);
unsigned struct_hpcfb_dsp_op_sz = sizeof(hpcfb_dsp_op);
unsigned struct_hpcfb_dspconf_sz = sizeof(hpcfb_dspconf);
unsigned struct_hpcfb_fbconf_sz = sizeof(hpcfb_fbconf);
unsigned struct_if_addrprefreq_sz = sizeof(if_addrprefreq);
unsigned struct_if_clonereq_sz = sizeof(if_clonereq);
unsigned struct_if_laddrreq_sz = sizeof(if_laddrreq);
unsigned struct_ifaddr_sz = sizeof(ifaddr);
unsigned struct_ifaliasreq_sz = sizeof(ifaliasreq);
unsigned struct_ifcapreq_sz = sizeof(ifcapreq);
unsigned struct_ifconf_sz = sizeof(ifconf);
unsigned struct_ifdatareq_sz = sizeof(ifdatareq);
unsigned struct_ifdrv_sz = sizeof(ifdrv);
unsigned struct_ifmediareq_sz = sizeof(ifmediareq);
unsigned struct_ifpppcstatsreq_sz = sizeof(ifpppcstatsreq);
unsigned struct_ifpppstatsreq_sz = sizeof(ifpppstatsreq);
unsigned struct_ifreq_sz = sizeof(ifreq);
unsigned struct_in6_addrpolicy_sz = sizeof(in6_addrpolicy);
unsigned struct_in6_ndireq_sz = sizeof(in6_ndireq);
unsigned struct_ioc_load_unload_sz = sizeof(ioc_load_unload);
unsigned struct_ioc_patch_sz = sizeof(ioc_patch);
unsigned struct_ioc_play_blocks_sz = sizeof(ioc_play_blocks);
unsigned struct_ioc_play_msf_sz = sizeof(ioc_play_msf);
unsigned struct_ioc_play_track_sz = sizeof(ioc_play_track);
unsigned struct_ioc_read_subchannel_sz = sizeof(ioc_read_subchannel);
unsigned struct_ioc_read_toc_entry_sz = sizeof(ioc_read_toc_entry);
unsigned struct_ioc_toc_header_sz = sizeof(ioc_toc_header);
unsigned struct_ioc_vol_sz = sizeof(ioc_vol);
unsigned struct_ioctl_pt_sz = sizeof(ioctl_pt);
unsigned struct_ioppt_sz = sizeof(ioppt);
unsigned struct_iovec_sz = sizeof(iovec);
unsigned struct_ipfobj_sz = sizeof(ipfobj);
unsigned struct_irda_params_sz = sizeof(irda_params);
unsigned struct_isp_fc_device_sz = sizeof(isp_fc_device);
unsigned struct_isp_fc_tsk_mgmt_sz = sizeof(isp_fc_tsk_mgmt);
unsigned struct_isp_hba_device_sz = sizeof(isp_hba_device);
unsigned struct_isv_cmd_sz = sizeof(isv_cmd);
unsigned struct_jobs_add_class_sz = sizeof(jobs_add_class);
unsigned struct_jobs_add_filter_sz = sizeof(jobs_add_filter);
unsigned struct_jobs_attach_sz = sizeof(jobs_attach);
unsigned struct_jobs_class_stats_sz = sizeof(jobs_class_stats);
unsigned struct_jobs_delete_class_sz = sizeof(jobs_delete_class);
unsigned struct_jobs_delete_filter_sz = sizeof(jobs_delete_filter);
unsigned struct_jobs_interface_sz = sizeof(jobs_interface);
unsigned struct_jobs_modify_class_sz = sizeof(jobs_modify_class);
unsigned struct_kbentry_sz = sizeof(kbentry);
unsigned struct_kfilter_mapping_sz = sizeof(kfilter_mapping);
unsigned struct_kiockeymap_sz = sizeof(kiockeymap);
unsigned struct_ksyms_gsymbol_sz = sizeof(ksyms_gsymbol);
unsigned struct_ksyms_gvalue_sz = sizeof(ksyms_gvalue);
unsigned struct_ksyms_ogsymbol_sz = sizeof(ksyms_ogsymbol);
unsigned struct_kttcp_io_args_sz = sizeof(kttcp_io_args);
unsigned struct_ltchars_sz = sizeof(ltchars);
unsigned struct_lua_create_sz = sizeof(struct lua_create);
unsigned struct_lua_info_sz = sizeof(struct lua_info);
unsigned struct_lua_load_sz = sizeof(struct lua_load);
unsigned struct_lua_require_sz = sizeof(lua_require);
unsigned struct_mbpp_param_sz = sizeof(mbpp_param);
unsigned struct_md_conf_sz = sizeof(md_conf);
unsigned struct_meteor_capframe_sz = sizeof(meteor_capframe);
unsigned struct_meteor_counts_sz = sizeof(meteor_counts);
unsigned struct_meteor_geomet_sz = sizeof(meteor_geomet);
unsigned struct_meteor_pixfmt_sz = sizeof(meteor_pixfmt);
unsigned struct_meteor_video_sz = sizeof(meteor_video);
unsigned struct_mlx_cinfo_sz = sizeof(mlx_cinfo);
unsigned struct_mlx_pause_sz = sizeof(mlx_pause);
unsigned struct_mlx_rebuild_request_sz = sizeof(mlx_rebuild_request);
unsigned struct_mlx_rebuild_status_sz = sizeof(mlx_rebuild_status);
unsigned struct_mlx_usercommand_sz = sizeof(mlx_usercommand);
unsigned struct_mly_user_command_sz = sizeof(mly_user_command);
unsigned struct_mly_user_health_sz = sizeof(mly_user_health);
unsigned struct_mtget_sz = sizeof(mtget);
unsigned struct_mtop_sz = sizeof(mtop);
unsigned struct_npf_ioctl_table_sz = sizeof(npf_ioctl_table);
unsigned struct_npioctl_sz = sizeof(npioctl);
unsigned struct_nvme_pt_command_sz = sizeof(nvme_pt_command);
unsigned struct_ochanger_element_status_request_sz =
sizeof(ochanger_element_status_request);
unsigned struct_ofiocdesc_sz = sizeof(ofiocdesc);
unsigned struct_okiockey_sz = sizeof(okiockey);
unsigned struct_ortentry_sz = sizeof(ortentry);
unsigned struct_oscsi_addr_sz = sizeof(oscsi_addr);
unsigned struct_oss_audioinfo_sz = sizeof(oss_audioinfo);
unsigned struct_oss_sysinfo_sz = sizeof(oss_sysinfo);
unsigned struct_pciio_bdf_cfgreg_sz = sizeof(pciio_bdf_cfgreg);
unsigned struct_pciio_businfo_sz = sizeof(pciio_businfo);
unsigned struct_pciio_cfgreg_sz = sizeof(pciio_cfgreg);
unsigned struct_pciio_drvname_sz = sizeof(pciio_drvname);
unsigned struct_pciio_drvnameonbus_sz = sizeof(pciio_drvnameonbus);
unsigned struct_pcvtid_sz = sizeof(pcvtid);
unsigned struct_pf_osfp_ioctl_sz = sizeof(pf_osfp_ioctl);
unsigned struct_pf_status_sz = sizeof(pf_status);
unsigned struct_pfioc_altq_sz = sizeof(pfioc_altq);
unsigned struct_pfioc_if_sz = sizeof(pfioc_if);
unsigned struct_pfioc_iface_sz = sizeof(pfioc_iface);
unsigned struct_pfioc_limit_sz = sizeof(pfioc_limit);
unsigned struct_pfioc_natlook_sz = sizeof(pfioc_natlook);
unsigned struct_pfioc_pooladdr_sz = sizeof(pfioc_pooladdr);
unsigned struct_pfioc_qstats_sz = sizeof(pfioc_qstats);
unsigned struct_pfioc_rule_sz = sizeof(pfioc_rule);
unsigned struct_pfioc_ruleset_sz = sizeof(pfioc_ruleset);
unsigned struct_pfioc_src_node_kill_sz = sizeof(pfioc_src_node_kill);
unsigned struct_pfioc_src_nodes_sz = sizeof(pfioc_src_nodes);
unsigned struct_pfioc_state_kill_sz = sizeof(pfioc_state_kill);
unsigned struct_pfioc_state_sz = sizeof(pfioc_state);
unsigned struct_pfioc_states_sz = sizeof(pfioc_states);
unsigned struct_pfioc_table_sz = sizeof(pfioc_table);
unsigned struct_pfioc_tm_sz = sizeof(pfioc_tm);
unsigned struct_pfioc_trans_sz = sizeof(pfioc_trans);
unsigned struct_plistref_sz = sizeof(plistref);
unsigned struct_power_type_sz = sizeof(power_type);
unsigned struct_ppp_idle_sz = sizeof(ppp_idle);
unsigned struct_ppp_option_data_sz = sizeof(ppp_option_data);
unsigned struct_ppp_rawin_sz = sizeof(ppp_rawin);
unsigned struct_pppoeconnectionstate_sz = sizeof(pppoeconnectionstate);
unsigned struct_pppoediscparms_sz = sizeof(pppoediscparms);
unsigned struct_priq_add_class_sz = sizeof(priq_add_class);
unsigned struct_priq_add_filter_sz = sizeof(priq_add_filter);
unsigned struct_priq_class_stats_sz = sizeof(priq_class_stats);
unsigned struct_priq_delete_class_sz = sizeof(priq_delete_class);
unsigned struct_priq_delete_filter_sz = sizeof(priq_delete_filter);
unsigned struct_priq_interface_sz = sizeof(priq_interface);
unsigned struct_priq_modify_class_sz = sizeof(priq_modify_class);
unsigned struct_ptmget_sz = sizeof(ptmget);
unsigned struct_radio_info_sz = sizeof(radio_info);
unsigned struct_red_conf_sz = sizeof(red_conf);
unsigned struct_red_interface_sz = sizeof(red_interface);
unsigned struct_red_stats_sz = sizeof(red_stats);
unsigned struct_redparams_sz = sizeof(redparams);
unsigned struct_rf_pmparams_sz = sizeof(rf_pmparams);
unsigned struct_rf_pmstat_sz = sizeof(rf_pmstat);
unsigned struct_rf_recon_req_sz = sizeof(rf_recon_req);
unsigned struct_rio_conf_sz = sizeof(rio_conf);
unsigned struct_rio_interface_sz = sizeof(rio_interface);
unsigned struct_rio_stats_sz = sizeof(rio_stats);
unsigned struct_scan_io_sz = sizeof(scan_io);
unsigned struct_scbusaccel_args_sz = sizeof(scbusaccel_args);
unsigned struct_scbusiodetach_args_sz = sizeof(scbusiodetach_args);
unsigned struct_scbusioscan_args_sz = sizeof(scbusioscan_args);
unsigned struct_scsi_addr_sz = sizeof(scsi_addr);
unsigned struct_seq_event_rec_sz = sizeof(seq_event_rec);
unsigned struct_session_op_sz = sizeof(session_op);
unsigned struct_sgttyb_sz = sizeof(sgttyb);
unsigned struct_sioc_sg_req_sz = sizeof(sioc_sg_req);
unsigned struct_sioc_vif_req_sz = sizeof(sioc_vif_req);
unsigned struct_smbioc_flags_sz = sizeof(smbioc_flags);
unsigned struct_smbioc_lookup_sz = sizeof(smbioc_lookup);
unsigned struct_smbioc_oshare_sz = sizeof(smbioc_oshare);
unsigned struct_smbioc_ossn_sz = sizeof(smbioc_ossn);
unsigned struct_smbioc_rq_sz = sizeof(smbioc_rq);
unsigned struct_smbioc_rw_sz = sizeof(smbioc_rw);
unsigned struct_spppauthcfg_sz = sizeof(spppauthcfg);
unsigned struct_spppauthfailuresettings_sz = sizeof(spppauthfailuresettings);
unsigned struct_spppauthfailurestats_sz = sizeof(spppauthfailurestats);
unsigned struct_spppdnsaddrs_sz = sizeof(spppdnsaddrs);
unsigned struct_spppdnssettings_sz = sizeof(spppdnssettings);
unsigned struct_spppidletimeout_sz = sizeof(spppidletimeout);
unsigned struct_spppkeepalivesettings_sz = sizeof(spppkeepalivesettings);
unsigned struct_sppplcpcfg_sz = sizeof(sppplcpcfg);
unsigned struct_spppstatus_sz = sizeof(spppstatus);
unsigned struct_spppstatusncp_sz = sizeof(spppstatusncp);
unsigned struct_srt_rt_sz = sizeof(srt_rt);
unsigned struct_stic_xinfo_sz = sizeof(stic_xinfo);
unsigned struct_sun_dkctlr_sz = sizeof(sun_dkctlr);
unsigned struct_sun_dkgeom_sz = sizeof(sun_dkgeom);
unsigned struct_sun_dkpart_sz = sizeof(sun_dkpart);
unsigned struct_synth_info_sz = sizeof(synth_info);
unsigned struct_tbrreq_sz = sizeof(tbrreq);
unsigned struct_tchars_sz = sizeof(tchars);
unsigned struct_termios_sz = sizeof(termios);
unsigned struct_timeval_sz = sizeof(timeval);
unsigned struct_twe_drivecommand_sz = sizeof(twe_drivecommand);
unsigned struct_twe_paramcommand_sz = sizeof(twe_paramcommand);
unsigned struct_twe_usercommand_sz = sizeof(twe_usercommand);
unsigned struct_ukyopon_identify_sz = sizeof(ukyopon_identify);
unsigned struct_urio_command_sz = sizeof(urio_command);
unsigned struct_usb_alt_interface_sz = sizeof(usb_alt_interface);
unsigned struct_usb_bulk_ra_wb_opt_sz = sizeof(usb_bulk_ra_wb_opt);
unsigned struct_usb_config_desc_sz = sizeof(usb_config_desc);
unsigned struct_usb_ctl_report_desc_sz = sizeof(usb_ctl_report_desc);
unsigned struct_usb_ctl_report_sz = sizeof(usb_ctl_report);
unsigned struct_usb_ctl_request_sz = sizeof(usb_ctl_request);
unsigned struct_autofs_daemon_request_sz = sizeof(autofs_daemon_request);
unsigned struct_autofs_daemon_done_sz = sizeof(autofs_daemon_done);
unsigned struct_sctp_connectx_addrs_sz = sizeof(sctp_connectx_addrs);
unsigned struct_usb_device_info_old_sz = sizeof(usb_device_info_old);
unsigned struct_usb_device_info_sz = sizeof(usb_device_info);
unsigned struct_usb_device_stats_sz = sizeof(usb_device_stats);
unsigned struct_usb_endpoint_desc_sz = sizeof(usb_endpoint_desc);
unsigned struct_usb_full_desc_sz = sizeof(usb_full_desc);
unsigned struct_usb_interface_desc_sz = sizeof(usb_interface_desc);
unsigned struct_usb_string_desc_sz = sizeof(usb_string_desc);
unsigned struct_utoppy_readfile_sz = sizeof(utoppy_readfile);
unsigned struct_utoppy_rename_sz = sizeof(utoppy_rename);
unsigned struct_utoppy_stats_sz = sizeof(utoppy_stats);
unsigned struct_utoppy_writefile_sz = sizeof(utoppy_writefile);
unsigned struct_v4l2_audio_sz = sizeof(v4l2_audio);
unsigned struct_v4l2_audioout_sz = sizeof(v4l2_audioout);
unsigned struct_v4l2_buffer_sz = sizeof(v4l2_buffer);
unsigned struct_v4l2_capability_sz = sizeof(v4l2_capability);
unsigned struct_v4l2_control_sz = sizeof(v4l2_control);
unsigned struct_v4l2_crop_sz = sizeof(v4l2_crop);
unsigned struct_v4l2_cropcap_sz = sizeof(v4l2_cropcap);
unsigned struct_v4l2_fmtdesc_sz = sizeof(v4l2_fmtdesc);
unsigned struct_v4l2_format_sz = sizeof(v4l2_format);
unsigned struct_v4l2_framebuffer_sz = sizeof(v4l2_framebuffer);
unsigned struct_v4l2_frequency_sz = sizeof(v4l2_frequency);
unsigned struct_v4l2_frmivalenum_sz = sizeof(v4l2_frmivalenum);
unsigned struct_v4l2_frmsizeenum_sz = sizeof(v4l2_frmsizeenum);
unsigned struct_v4l2_input_sz = sizeof(v4l2_input);
unsigned struct_v4l2_jpegcompression_sz = sizeof(v4l2_jpegcompression);
unsigned struct_v4l2_modulator_sz = sizeof(v4l2_modulator);
unsigned struct_v4l2_output_sz = sizeof(v4l2_output);
unsigned struct_v4l2_queryctrl_sz = sizeof(v4l2_queryctrl);
unsigned struct_v4l2_querymenu_sz = sizeof(v4l2_querymenu);
unsigned struct_v4l2_requestbuffers_sz = sizeof(v4l2_requestbuffers);
unsigned struct_v4l2_standard_sz = sizeof(v4l2_standard);
unsigned struct_v4l2_streamparm_sz = sizeof(v4l2_streamparm);
unsigned struct_v4l2_tuner_sz = sizeof(v4l2_tuner);
unsigned struct_vnd_ioctl_sz = sizeof(vnd_ioctl);
unsigned struct_vnd_user_sz = sizeof(vnd_user);
unsigned struct_vt_stat_sz = sizeof(vt_stat);
unsigned struct_wdog_conf_sz = sizeof(wdog_conf);
unsigned struct_wdog_mode_sz = sizeof(wdog_mode);
unsigned struct_wfq_conf_sz = sizeof(wfq_conf);
unsigned struct_wfq_getqid_sz = sizeof(wfq_getqid);
unsigned struct_wfq_getstats_sz = sizeof(wfq_getstats);
unsigned struct_wfq_interface_sz = sizeof(wfq_interface);
unsigned struct_wfq_setweight_sz = sizeof(wfq_setweight);
unsigned struct_winsize_sz = sizeof(winsize);
unsigned struct_wscons_event_sz = sizeof(wscons_event);
unsigned struct_wsdisplay_addscreendata_sz = sizeof(wsdisplay_addscreendata);
unsigned struct_wsdisplay_char_sz = sizeof(wsdisplay_char);
unsigned struct_wsdisplay_cmap_sz = sizeof(wsdisplay_cmap);
unsigned struct_wsdisplay_curpos_sz = sizeof(wsdisplay_curpos);
unsigned struct_wsdisplay_cursor_sz = sizeof(wsdisplay_cursor);
unsigned struct_wsdisplay_delscreendata_sz = sizeof(wsdisplay_delscreendata);
unsigned struct_wsdisplay_fbinfo_sz = sizeof(wsdisplay_fbinfo);
unsigned struct_wsdisplay_font_sz = sizeof(wsdisplay_font);
unsigned struct_wsdisplay_kbddata_sz = sizeof(wsdisplay_kbddata);
unsigned struct_wsdisplay_msgattrs_sz = sizeof(wsdisplay_msgattrs);
unsigned struct_wsdisplay_param_sz = sizeof(wsdisplay_param);
unsigned struct_wsdisplay_scroll_data_sz = sizeof(wsdisplay_scroll_data);
unsigned struct_wsdisplay_usefontdata_sz = sizeof(wsdisplay_usefontdata);
unsigned struct_wsdisplayio_blit_sz = sizeof(wsdisplayio_blit);
unsigned struct_wsdisplayio_bus_id_sz = sizeof(wsdisplayio_bus_id);
unsigned struct_wsdisplayio_edid_info_sz = sizeof(wsdisplayio_edid_info);
unsigned struct_wsdisplayio_fbinfo_sz = sizeof(wsdisplayio_fbinfo);
unsigned struct_wskbd_bell_data_sz = sizeof(wskbd_bell_data);
unsigned struct_wskbd_keyrepeat_data_sz = sizeof(wskbd_keyrepeat_data);
unsigned struct_wskbd_map_data_sz = sizeof(wskbd_map_data);
unsigned struct_wskbd_scroll_data_sz = sizeof(wskbd_scroll_data);
unsigned struct_wsmouse_calibcoords_sz = sizeof(wsmouse_calibcoords);
unsigned struct_wsmouse_id_sz = sizeof(wsmouse_id);
unsigned struct_wsmouse_repeat_sz = sizeof(wsmouse_repeat);
unsigned struct_wsmux_device_list_sz = sizeof(wsmux_device_list);
unsigned struct_wsmux_device_sz = sizeof(wsmux_device);
unsigned struct_xd_iocmd_sz = sizeof(xd_iocmd);
unsigned struct_scsireq_sz = sizeof(struct scsireq);
unsigned struct_tone_sz = sizeof(tone_t);
unsigned union_twe_statrequest_sz = sizeof(union twe_statrequest);
unsigned struct_usb_device_descriptor_sz = sizeof(usb_device_descriptor_t);
unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
unsigned struct__old_mixer_info_sz = sizeof(struct _old_mixer_info);
unsigned struct__agp_allocate_sz = sizeof(struct _agp_allocate);
unsigned struct__agp_bind_sz = sizeof(struct _agp_bind);
unsigned struct__agp_info_sz = sizeof(struct _agp_info);
unsigned struct__agp_setup_sz = sizeof(struct _agp_setup);
unsigned struct__agp_unbind_sz = sizeof(struct _agp_unbind);
unsigned struct_atareq_sz = sizeof(struct atareq);
unsigned struct_cpustate_sz = sizeof(struct cpustate);
unsigned struct_dmx_caps_sz = sizeof(struct dmx_caps);
unsigned enum_dmx_source_sz = sizeof(dmx_source_t);
unsigned union_dvd_authinfo_sz = sizeof(dvd_authinfo);
unsigned union_dvd_struct_sz = sizeof(dvd_struct);
unsigned enum_v4l2_priority_sz = sizeof(enum v4l2_priority);
unsigned struct_envsys_basic_info_sz = sizeof(struct envsys_basic_info);
unsigned struct_envsys_tre_data_sz = sizeof(struct envsys_tre_data);
unsigned enum_fe_sec_mini_cmd_sz = sizeof(enum fe_sec_mini_cmd);
unsigned enum_fe_sec_tone_mode_sz = sizeof(enum fe_sec_tone_mode);
unsigned enum_fe_sec_voltage_sz = sizeof(enum fe_sec_voltage);
unsigned enum_fe_status_sz = sizeof(enum fe_status);
unsigned struct_gdt_ctrt_sz = sizeof(struct gdt_ctrt);
unsigned struct_gdt_event_sz = sizeof(struct gdt_event);
unsigned struct_gdt_osv_sz = sizeof(struct gdt_osv);
unsigned struct_gdt_rescan_sz = sizeof(struct gdt_rescan);
unsigned struct_gdt_statist_sz = sizeof(struct gdt_statist);
unsigned struct_gdt_ucmd_sz = sizeof(struct gdt_ucmd);
unsigned struct_iscsi_conn_status_parameters_sz =
sizeof(iscsi_conn_status_parameters_t);
unsigned struct_iscsi_get_version_parameters_sz =
sizeof(iscsi_get_version_parameters_t);
unsigned struct_iscsi_iocommand_parameters_sz =
sizeof(iscsi_iocommand_parameters_t);
unsigned struct_iscsi_login_parameters_sz = sizeof(iscsi_login_parameters_t);
unsigned struct_iscsi_logout_parameters_sz = sizeof(iscsi_logout_parameters_t);
unsigned struct_iscsi_register_event_parameters_sz =
sizeof(iscsi_register_event_parameters_t);
unsigned struct_iscsi_remove_parameters_sz = sizeof(iscsi_remove_parameters_t);
unsigned struct_iscsi_send_targets_parameters_sz =
sizeof(iscsi_send_targets_parameters_t);
unsigned struct_iscsi_set_node_name_parameters_sz =
sizeof(iscsi_set_node_name_parameters_t);
unsigned struct_iscsi_wait_event_parameters_sz =
sizeof(iscsi_wait_event_parameters_t);
unsigned struct_isp_stats_sz = sizeof(isp_stats_t);
unsigned struct_lsenable_sz = sizeof(struct lsenable);
unsigned struct_lsdisable_sz = sizeof(struct lsdisable);
unsigned struct_mixer_ctrl_sz = sizeof(struct mixer_ctrl);
unsigned struct_mixer_devinfo_sz = sizeof(struct mixer_devinfo);
unsigned struct_mpu_command_rec_sz = sizeof(mpu_command_rec);
unsigned struct_rndstat_sz = sizeof(rndstat_t);
unsigned struct_rndstat_name_sz = sizeof(rndstat_name_t);
unsigned struct_rndctl_sz = sizeof(rndctl_t);
unsigned struct_rnddata_sz = sizeof(rnddata_t);
unsigned struct_rndpoolstat_sz = sizeof(rndpoolstat_t);
unsigned struct_rndstat_est_sz = sizeof(rndstat_est_t);
unsigned struct_rndstat_est_name_sz = sizeof(rndstat_est_name_t);
unsigned struct_pps_params_sz = sizeof(pps_params_t);
unsigned struct_pps_info_sz = sizeof(pps_info_t);
unsigned struct_mixer_info_sz = sizeof(struct mixer_info);
unsigned struct_RF_SparetWait_sz = sizeof(RF_SparetWait_t);
unsigned struct_RF_ComponentLabel_sz = sizeof(RF_ComponentLabel_t);
unsigned struct_RF_SingleComponent_sz = sizeof(RF_SingleComponent_t);
unsigned struct_RF_ProgressInfo_sz = sizeof(RF_ProgressInfo_t);
unsigned struct_nvlist_ref_sz = sizeof(struct __sanitizer_nvlist_ref_t);
unsigned struct_StringList_sz = sizeof(StringList);
const unsigned IOCTL_NOT_PRESENT = 0;
unsigned IOCTL_AFM_ADDFMAP = AFM_ADDFMAP;
unsigned IOCTL_AFM_DELFMAP = AFM_DELFMAP;
unsigned IOCTL_AFM_CLEANFMAP = AFM_CLEANFMAP;
unsigned IOCTL_AFM_GETFMAP = AFM_GETFMAP;
unsigned IOCTL_ALTQGTYPE = ALTQGTYPE;
unsigned IOCTL_ALTQTBRSET = ALTQTBRSET;
unsigned IOCTL_ALTQTBRGET = ALTQTBRGET;
unsigned IOCTL_BLUE_IF_ATTACH = BLUE_IF_ATTACH;
unsigned IOCTL_BLUE_IF_DETACH = BLUE_IF_DETACH;
unsigned IOCTL_BLUE_ENABLE = BLUE_ENABLE;
unsigned IOCTL_BLUE_DISABLE = BLUE_DISABLE;
unsigned IOCTL_BLUE_CONFIG = BLUE_CONFIG;
unsigned IOCTL_BLUE_GETSTATS = BLUE_GETSTATS;
unsigned IOCTL_CBQ_IF_ATTACH = CBQ_IF_ATTACH;
unsigned IOCTL_CBQ_IF_DETACH = CBQ_IF_DETACH;
unsigned IOCTL_CBQ_ENABLE = CBQ_ENABLE;
unsigned IOCTL_CBQ_DISABLE = CBQ_DISABLE;
unsigned IOCTL_CBQ_CLEAR_HIERARCHY = CBQ_CLEAR_HIERARCHY;
unsigned IOCTL_CBQ_ADD_CLASS = CBQ_ADD_CLASS;
unsigned IOCTL_CBQ_DEL_CLASS = CBQ_DEL_CLASS;
unsigned IOCTL_CBQ_MODIFY_CLASS = CBQ_MODIFY_CLASS;
unsigned IOCTL_CBQ_ADD_FILTER = CBQ_ADD_FILTER;
unsigned IOCTL_CBQ_DEL_FILTER = CBQ_DEL_FILTER;
unsigned IOCTL_CBQ_GETSTATS = CBQ_GETSTATS;
unsigned IOCTL_CDNR_IF_ATTACH = CDNR_IF_ATTACH;
unsigned IOCTL_CDNR_IF_DETACH = CDNR_IF_DETACH;
unsigned IOCTL_CDNR_ENABLE = CDNR_ENABLE;
unsigned IOCTL_CDNR_DISABLE = CDNR_DISABLE;
unsigned IOCTL_CDNR_ADD_FILTER = CDNR_ADD_FILTER;
unsigned IOCTL_CDNR_DEL_FILTER = CDNR_DEL_FILTER;
unsigned IOCTL_CDNR_GETSTATS = CDNR_GETSTATS;
unsigned IOCTL_CDNR_ADD_ELEM = CDNR_ADD_ELEM;
unsigned IOCTL_CDNR_DEL_ELEM = CDNR_DEL_ELEM;
unsigned IOCTL_CDNR_ADD_TBM = CDNR_ADD_TBM;
unsigned IOCTL_CDNR_MOD_TBM = CDNR_MOD_TBM;
unsigned IOCTL_CDNR_TBM_STATS = CDNR_TBM_STATS;
unsigned IOCTL_CDNR_ADD_TCM = CDNR_ADD_TCM;
unsigned IOCTL_CDNR_MOD_TCM = CDNR_MOD_TCM;
unsigned IOCTL_CDNR_TCM_STATS = CDNR_TCM_STATS;
unsigned IOCTL_CDNR_ADD_TSW = CDNR_ADD_TSW;
unsigned IOCTL_CDNR_MOD_TSW = CDNR_MOD_TSW;
unsigned IOCTL_FIFOQ_IF_ATTACH = FIFOQ_IF_ATTACH;
unsigned IOCTL_FIFOQ_IF_DETACH = FIFOQ_IF_DETACH;
unsigned IOCTL_FIFOQ_ENABLE = FIFOQ_ENABLE;
unsigned IOCTL_FIFOQ_DISABLE = FIFOQ_DISABLE;
unsigned IOCTL_FIFOQ_CONFIG = FIFOQ_CONFIG;
unsigned IOCTL_FIFOQ_GETSTATS = FIFOQ_GETSTATS;
unsigned IOCTL_HFSC_IF_ATTACH = HFSC_IF_ATTACH;
unsigned IOCTL_HFSC_IF_DETACH = HFSC_IF_DETACH;
unsigned IOCTL_HFSC_ENABLE = HFSC_ENABLE;
unsigned IOCTL_HFSC_DISABLE = HFSC_DISABLE;
unsigned IOCTL_HFSC_CLEAR_HIERARCHY = HFSC_CLEAR_HIERARCHY;
unsigned IOCTL_HFSC_ADD_CLASS = HFSC_ADD_CLASS;
unsigned IOCTL_HFSC_DEL_CLASS = HFSC_DEL_CLASS;
unsigned IOCTL_HFSC_MOD_CLASS = HFSC_MOD_CLASS;
unsigned IOCTL_HFSC_ADD_FILTER = HFSC_ADD_FILTER;
unsigned IOCTL_HFSC_DEL_FILTER = HFSC_DEL_FILTER;
unsigned IOCTL_HFSC_GETSTATS = HFSC_GETSTATS;
unsigned IOCTL_JOBS_IF_ATTACH = JOBS_IF_ATTACH;
unsigned IOCTL_JOBS_IF_DETACH = JOBS_IF_DETACH;
unsigned IOCTL_JOBS_ENABLE = JOBS_ENABLE;
unsigned IOCTL_JOBS_DISABLE = JOBS_DISABLE;
unsigned IOCTL_JOBS_CLEAR = JOBS_CLEAR;
unsigned IOCTL_JOBS_ADD_CLASS = JOBS_ADD_CLASS;
unsigned IOCTL_JOBS_DEL_CLASS = JOBS_DEL_CLASS;
unsigned IOCTL_JOBS_MOD_CLASS = JOBS_MOD_CLASS;
unsigned IOCTL_JOBS_ADD_FILTER = JOBS_ADD_FILTER;
unsigned IOCTL_JOBS_DEL_FILTER = JOBS_DEL_FILTER;
unsigned IOCTL_JOBS_GETSTATS = JOBS_GETSTATS;
unsigned IOCTL_PRIQ_IF_ATTACH = PRIQ_IF_ATTACH;
unsigned IOCTL_PRIQ_IF_DETACH = PRIQ_IF_DETACH;
unsigned IOCTL_PRIQ_ENABLE = PRIQ_ENABLE;
unsigned IOCTL_PRIQ_DISABLE = PRIQ_DISABLE;
unsigned IOCTL_PRIQ_CLEAR = PRIQ_CLEAR;
unsigned IOCTL_PRIQ_ADD_CLASS = PRIQ_ADD_CLASS;
unsigned IOCTL_PRIQ_DEL_CLASS = PRIQ_DEL_CLASS;
unsigned IOCTL_PRIQ_MOD_CLASS = PRIQ_MOD_CLASS;
unsigned IOCTL_PRIQ_ADD_FILTER = PRIQ_ADD_FILTER;
unsigned IOCTL_PRIQ_DEL_FILTER = PRIQ_DEL_FILTER;
unsigned IOCTL_PRIQ_GETSTATS = PRIQ_GETSTATS;
unsigned IOCTL_RED_IF_ATTACH = RED_IF_ATTACH;
unsigned IOCTL_RED_IF_DETACH = RED_IF_DETACH;
unsigned IOCTL_RED_ENABLE = RED_ENABLE;
unsigned IOCTL_RED_DISABLE = RED_DISABLE;
unsigned IOCTL_RED_CONFIG = RED_CONFIG;
unsigned IOCTL_RED_GETSTATS = RED_GETSTATS;
unsigned IOCTL_RED_SETDEFAULTS = RED_SETDEFAULTS;
unsigned IOCTL_RIO_IF_ATTACH = RIO_IF_ATTACH;
unsigned IOCTL_RIO_IF_DETACH = RIO_IF_DETACH;
unsigned IOCTL_RIO_ENABLE = RIO_ENABLE;
unsigned IOCTL_RIO_DISABLE = RIO_DISABLE;
unsigned IOCTL_RIO_CONFIG = RIO_CONFIG;
unsigned IOCTL_RIO_GETSTATS = RIO_GETSTATS;
unsigned IOCTL_RIO_SETDEFAULTS = RIO_SETDEFAULTS;
unsigned IOCTL_WFQ_IF_ATTACH = WFQ_IF_ATTACH;
unsigned IOCTL_WFQ_IF_DETACH = WFQ_IF_DETACH;
unsigned IOCTL_WFQ_ENABLE = WFQ_ENABLE;
unsigned IOCTL_WFQ_DISABLE = WFQ_DISABLE;
unsigned IOCTL_WFQ_CONFIG = WFQ_CONFIG;
unsigned IOCTL_WFQ_GET_STATS = WFQ_GET_STATS;
unsigned IOCTL_WFQ_GET_QID = WFQ_GET_QID;
unsigned IOCTL_WFQ_SET_WEIGHT = WFQ_SET_WEIGHT;
unsigned IOCTL_CRIOGET = CRIOGET;
unsigned IOCTL_CIOCFSESSION = CIOCFSESSION;
unsigned IOCTL_CIOCKEY = CIOCKEY;
unsigned IOCTL_CIOCNFKEYM = CIOCNFKEYM;
unsigned IOCTL_CIOCNFSESSION = CIOCNFSESSION;
unsigned IOCTL_CIOCNCRYPTRETM = CIOCNCRYPTRETM;
unsigned IOCTL_CIOCNCRYPTRET = CIOCNCRYPTRET;
unsigned IOCTL_CIOCGSESSION = CIOCGSESSION;
unsigned IOCTL_CIOCNGSESSION = CIOCNGSESSION;
unsigned IOCTL_CIOCCRYPT = CIOCCRYPT;
unsigned IOCTL_CIOCNCRYPTM = CIOCNCRYPTM;
unsigned IOCTL_CIOCASYMFEAT = CIOCASYMFEAT;
unsigned IOCTL_APM_IOC_REJECT = APM_IOC_REJECT;
unsigned IOCTL_APM_IOC_STANDBY = APM_IOC_STANDBY;
unsigned IOCTL_APM_IOC_SUSPEND = APM_IOC_SUSPEND;
unsigned IOCTL_OAPM_IOC_GETPOWER = OAPM_IOC_GETPOWER;
unsigned IOCTL_APM_IOC_GETPOWER = APM_IOC_GETPOWER;
unsigned IOCTL_APM_IOC_NEXTEVENT = APM_IOC_NEXTEVENT;
unsigned IOCTL_APM_IOC_DEV_CTL = APM_IOC_DEV_CTL;
unsigned IOCTL_NETBSD_DM_IOCTL = NETBSD_DM_IOCTL;
unsigned IOCTL_DMIO_SETFUNC = DMIO_SETFUNC;
unsigned IOCTL_DMX_START = DMX_START;
unsigned IOCTL_DMX_STOP = DMX_STOP;
unsigned IOCTL_DMX_SET_FILTER = DMX_SET_FILTER;
unsigned IOCTL_DMX_SET_PES_FILTER = DMX_SET_PES_FILTER;
unsigned IOCTL_DMX_SET_BUFFER_SIZE = DMX_SET_BUFFER_SIZE;
unsigned IOCTL_DMX_GET_STC = DMX_GET_STC;
unsigned IOCTL_DMX_ADD_PID = DMX_ADD_PID;
unsigned IOCTL_DMX_REMOVE_PID = DMX_REMOVE_PID;
unsigned IOCTL_DMX_GET_CAPS = DMX_GET_CAPS;
unsigned IOCTL_DMX_SET_SOURCE = DMX_SET_SOURCE;
unsigned IOCTL_FE_READ_STATUS = FE_READ_STATUS;
unsigned IOCTL_FE_READ_BER = FE_READ_BER;
unsigned IOCTL_FE_READ_SNR = FE_READ_SNR;
unsigned IOCTL_FE_READ_SIGNAL_STRENGTH = FE_READ_SIGNAL_STRENGTH;
unsigned IOCTL_FE_READ_UNCORRECTED_BLOCKS = FE_READ_UNCORRECTED_BLOCKS;
unsigned IOCTL_FE_SET_FRONTEND = FE_SET_FRONTEND;
unsigned IOCTL_FE_GET_FRONTEND = FE_GET_FRONTEND;
unsigned IOCTL_FE_GET_EVENT = FE_GET_EVENT;
unsigned IOCTL_FE_GET_INFO = FE_GET_INFO;
unsigned IOCTL_FE_DISEQC_RESET_OVERLOAD = FE_DISEQC_RESET_OVERLOAD;
unsigned IOCTL_FE_DISEQC_SEND_MASTER_CMD = FE_DISEQC_SEND_MASTER_CMD;
unsigned IOCTL_FE_DISEQC_RECV_SLAVE_REPLY = FE_DISEQC_RECV_SLAVE_REPLY;
unsigned IOCTL_FE_DISEQC_SEND_BURST = FE_DISEQC_SEND_BURST;
unsigned IOCTL_FE_SET_TONE = FE_SET_TONE;
unsigned IOCTL_FE_SET_VOLTAGE = FE_SET_VOLTAGE;
unsigned IOCTL_FE_ENABLE_HIGH_LNB_VOLTAGE = FE_ENABLE_HIGH_LNB_VOLTAGE;
unsigned IOCTL_FE_SET_FRONTEND_TUNE_MODE = FE_SET_FRONTEND_TUNE_MODE;
unsigned IOCTL_FE_DISHNETWORK_SEND_LEGACY_CMD = FE_DISHNETWORK_SEND_LEGACY_CMD;
unsigned IOCTL_FILEMON_SET_FD = FILEMON_SET_FD;
unsigned IOCTL_FILEMON_SET_PID = FILEMON_SET_PID;
unsigned IOCTL_HDAUDIO_FGRP_INFO = HDAUDIO_FGRP_INFO;
unsigned IOCTL_HDAUDIO_FGRP_GETCONFIG = HDAUDIO_FGRP_GETCONFIG;
unsigned IOCTL_HDAUDIO_FGRP_SETCONFIG = HDAUDIO_FGRP_SETCONFIG;
unsigned IOCTL_HDAUDIO_FGRP_WIDGET_INFO = HDAUDIO_FGRP_WIDGET_INFO;
unsigned IOCTL_HDAUDIO_FGRP_CODEC_INFO = HDAUDIO_FGRP_CODEC_INFO;
unsigned IOCTL_HDAUDIO_AFG_WIDGET_INFO = HDAUDIO_AFG_WIDGET_INFO;
unsigned IOCTL_HDAUDIO_AFG_CODEC_INFO = HDAUDIO_AFG_CODEC_INFO;
unsigned IOCTL_CEC_GET_PHYS_ADDR = CEC_GET_PHYS_ADDR;
unsigned IOCTL_CEC_GET_LOG_ADDRS = CEC_GET_LOG_ADDRS;
unsigned IOCTL_CEC_SET_LOG_ADDRS = CEC_SET_LOG_ADDRS;
unsigned IOCTL_CEC_GET_VENDOR_ID = CEC_GET_VENDOR_ID;
unsigned IOCTL_HPCFBIO_GCONF = HPCFBIO_GCONF;
unsigned IOCTL_HPCFBIO_SCONF = HPCFBIO_SCONF;
unsigned IOCTL_HPCFBIO_GDSPCONF = HPCFBIO_GDSPCONF;
unsigned IOCTL_HPCFBIO_SDSPCONF = HPCFBIO_SDSPCONF;
unsigned IOCTL_HPCFBIO_GOP = HPCFBIO_GOP;
unsigned IOCTL_HPCFBIO_SOP = HPCFBIO_SOP;
unsigned IOCTL_IOPIOCPT = IOPIOCPT;
unsigned IOCTL_IOPIOCGLCT = IOPIOCGLCT;
unsigned IOCTL_IOPIOCGSTATUS = IOPIOCGSTATUS;
unsigned IOCTL_IOPIOCRECONFIG = IOPIOCRECONFIG;
unsigned IOCTL_IOPIOCGTIDMAP = IOPIOCGTIDMAP;
unsigned IOCTL_SIOCGATHSTATS = SIOCGATHSTATS;
unsigned IOCTL_SIOCGATHDIAG = SIOCGATHDIAG;
unsigned IOCTL_METEORCAPTUR = METEORCAPTUR;
unsigned IOCTL_METEORCAPFRM = METEORCAPFRM;
unsigned IOCTL_METEORSETGEO = METEORSETGEO;
unsigned IOCTL_METEORGETGEO = METEORGETGEO;
unsigned IOCTL_METEORSTATUS = METEORSTATUS;
unsigned IOCTL_METEORSHUE = METEORSHUE;
unsigned IOCTL_METEORGHUE = METEORGHUE;
unsigned IOCTL_METEORSFMT = METEORSFMT;
unsigned IOCTL_METEORGFMT = METEORGFMT;
unsigned IOCTL_METEORSINPUT = METEORSINPUT;
unsigned IOCTL_METEORGINPUT = METEORGINPUT;
unsigned IOCTL_METEORSCHCV = METEORSCHCV;
unsigned IOCTL_METEORGCHCV = METEORGCHCV;
unsigned IOCTL_METEORSCOUNT = METEORSCOUNT;
unsigned IOCTL_METEORGCOUNT = METEORGCOUNT;
unsigned IOCTL_METEORSFPS = METEORSFPS;
unsigned IOCTL_METEORGFPS = METEORGFPS;
unsigned IOCTL_METEORSSIGNAL = METEORSSIGNAL;
unsigned IOCTL_METEORGSIGNAL = METEORGSIGNAL;
unsigned IOCTL_METEORSVIDEO = METEORSVIDEO;
unsigned IOCTL_METEORGVIDEO = METEORGVIDEO;
unsigned IOCTL_METEORSBRIG = METEORSBRIG;
unsigned IOCTL_METEORGBRIG = METEORGBRIG;
unsigned IOCTL_METEORSCSAT = METEORSCSAT;
unsigned IOCTL_METEORGCSAT = METEORGCSAT;
unsigned IOCTL_METEORSCONT = METEORSCONT;
unsigned IOCTL_METEORGCONT = METEORGCONT;
unsigned IOCTL_METEORSHWS = METEORSHWS;
unsigned IOCTL_METEORGHWS = METEORGHWS;
unsigned IOCTL_METEORSVWS = METEORSVWS;
unsigned IOCTL_METEORGVWS = METEORGVWS;
unsigned IOCTL_METEORSTS = METEORSTS;
unsigned IOCTL_METEORGTS = METEORGTS;
unsigned IOCTL_TVTUNER_SETCHNL = TVTUNER_SETCHNL;
unsigned IOCTL_TVTUNER_GETCHNL = TVTUNER_GETCHNL;
unsigned IOCTL_TVTUNER_SETTYPE = TVTUNER_SETTYPE;
unsigned IOCTL_TVTUNER_GETTYPE = TVTUNER_GETTYPE;
unsigned IOCTL_TVTUNER_GETSTATUS = TVTUNER_GETSTATUS;
unsigned IOCTL_TVTUNER_SETFREQ = TVTUNER_SETFREQ;
unsigned IOCTL_TVTUNER_GETFREQ = TVTUNER_GETFREQ;
unsigned IOCTL_TVTUNER_SETAFC = TVTUNER_SETAFC;
unsigned IOCTL_TVTUNER_GETAFC = TVTUNER_GETAFC;
unsigned IOCTL_RADIO_SETMODE = RADIO_SETMODE;
unsigned IOCTL_RADIO_GETMODE = RADIO_GETMODE;
unsigned IOCTL_RADIO_SETFREQ = RADIO_SETFREQ;
unsigned IOCTL_RADIO_GETFREQ = RADIO_GETFREQ;
unsigned IOCTL_METEORSACTPIXFMT = METEORSACTPIXFMT;
unsigned IOCTL_METEORGACTPIXFMT = METEORGACTPIXFMT;
unsigned IOCTL_METEORGSUPPIXFMT = METEORGSUPPIXFMT;
unsigned IOCTL_TVTUNER_GETCHNLSET = TVTUNER_GETCHNLSET;
unsigned IOCTL_REMOTE_GETKEY = REMOTE_GETKEY;
unsigned IOCTL_GDT_IOCTL_GENERAL = GDT_IOCTL_GENERAL;
unsigned IOCTL_GDT_IOCTL_DRVERS = GDT_IOCTL_DRVERS;
unsigned IOCTL_GDT_IOCTL_CTRTYPE = GDT_IOCTL_CTRTYPE;
unsigned IOCTL_GDT_IOCTL_OSVERS = GDT_IOCTL_OSVERS;
unsigned IOCTL_GDT_IOCTL_CTRCNT = GDT_IOCTL_CTRCNT;
unsigned IOCTL_GDT_IOCTL_EVENT = GDT_IOCTL_EVENT;
unsigned IOCTL_GDT_IOCTL_STATIST = GDT_IOCTL_STATIST;
unsigned IOCTL_GDT_IOCTL_RESCAN = GDT_IOCTL_RESCAN;
unsigned IOCTL_ISP_SDBLEV = ISP_SDBLEV;
unsigned IOCTL_ISP_RESETHBA = ISP_RESETHBA;
unsigned IOCTL_ISP_RESCAN = ISP_RESCAN;
unsigned IOCTL_ISP_SETROLE = ISP_SETROLE;
unsigned IOCTL_ISP_GETROLE = ISP_GETROLE;
unsigned IOCTL_ISP_GET_STATS = ISP_GET_STATS;
unsigned IOCTL_ISP_CLR_STATS = ISP_CLR_STATS;
unsigned IOCTL_ISP_FC_LIP = ISP_FC_LIP;
unsigned IOCTL_ISP_FC_GETDINFO = ISP_FC_GETDINFO;
unsigned IOCTL_ISP_GET_FW_CRASH_DUMP = ISP_GET_FW_CRASH_DUMP;
unsigned IOCTL_ISP_FORCE_CRASH_DUMP = ISP_FORCE_CRASH_DUMP;
unsigned IOCTL_ISP_FC_GETHINFO = ISP_FC_GETHINFO;
unsigned IOCTL_ISP_TSK_MGMT = ISP_TSK_MGMT;
unsigned IOCTL_ISP_FC_GETDLIST = ISP_FC_GETDLIST;
unsigned IOCTL_MLXD_STATUS = MLXD_STATUS;
unsigned IOCTL_MLXD_CHECKASYNC = MLXD_CHECKASYNC;
unsigned IOCTL_MLXD_DETACH = MLXD_DETACH;
unsigned IOCTL_MLX_RESCAN_DRIVES = MLX_RESCAN_DRIVES;
unsigned IOCTL_MLX_PAUSE_CHANNEL = MLX_PAUSE_CHANNEL;
unsigned IOCTL_MLX_COMMAND = MLX_COMMAND;
unsigned IOCTL_MLX_REBUILDASYNC = MLX_REBUILDASYNC;
unsigned IOCTL_MLX_REBUILDSTAT = MLX_REBUILDSTAT;
unsigned IOCTL_MLX_GET_SYSDRIVE = MLX_GET_SYSDRIVE;
unsigned IOCTL_MLX_GET_CINFO = MLX_GET_CINFO;
unsigned IOCTL_NVME_PASSTHROUGH_CMD = NVME_PASSTHROUGH_CMD;
unsigned IOCTL_FWCFGIO_SET_INDEX = FWCFGIO_SET_INDEX;
unsigned IOCTL_IRDA_RESET_PARAMS = IRDA_RESET_PARAMS;
unsigned IOCTL_IRDA_SET_PARAMS = IRDA_SET_PARAMS;
unsigned IOCTL_IRDA_GET_SPEEDMASK = IRDA_GET_SPEEDMASK;
unsigned IOCTL_IRDA_GET_TURNAROUNDMASK = IRDA_GET_TURNAROUNDMASK;
unsigned IOCTL_IRFRAMETTY_GET_DEVICE = IRFRAMETTY_GET_DEVICE;
unsigned IOCTL_IRFRAMETTY_GET_DONGLE = IRFRAMETTY_GET_DONGLE;
unsigned IOCTL_IRFRAMETTY_SET_DONGLE = IRFRAMETTY_SET_DONGLE;
unsigned IOCTL_ISV_CMD = ISV_CMD;
unsigned IOCTL_WTQICMD = WTQICMD;
unsigned IOCTL_ISCSI_GET_VERSION = ISCSI_GET_VERSION;
unsigned IOCTL_ISCSI_LOGIN = ISCSI_LOGIN;
unsigned IOCTL_ISCSI_LOGOUT = ISCSI_LOGOUT;
unsigned IOCTL_ISCSI_ADD_CONNECTION = ISCSI_ADD_CONNECTION;
unsigned IOCTL_ISCSI_RESTORE_CONNECTION = ISCSI_RESTORE_CONNECTION;
unsigned IOCTL_ISCSI_REMOVE_CONNECTION = ISCSI_REMOVE_CONNECTION;
unsigned IOCTL_ISCSI_CONNECTION_STATUS = ISCSI_CONNECTION_STATUS;
unsigned IOCTL_ISCSI_SEND_TARGETS = ISCSI_SEND_TARGETS;
unsigned IOCTL_ISCSI_SET_NODE_NAME = ISCSI_SET_NODE_NAME;
unsigned IOCTL_ISCSI_IO_COMMAND = ISCSI_IO_COMMAND;
unsigned IOCTL_ISCSI_REGISTER_EVENT = ISCSI_REGISTER_EVENT;
unsigned IOCTL_ISCSI_DEREGISTER_EVENT = ISCSI_DEREGISTER_EVENT;
unsigned IOCTL_ISCSI_WAIT_EVENT = ISCSI_WAIT_EVENT;
unsigned IOCTL_ISCSI_POLL_EVENT = ISCSI_POLL_EVENT;
unsigned IOCTL_OFIOCGET = OFIOCGET;
unsigned IOCTL_OFIOCSET = OFIOCSET;
unsigned IOCTL_OFIOCNEXTPROP = OFIOCNEXTPROP;
unsigned IOCTL_OFIOCGETOPTNODE = OFIOCGETOPTNODE;
unsigned IOCTL_OFIOCGETNEXT = OFIOCGETNEXT;
unsigned IOCTL_OFIOCGETCHILD = OFIOCGETCHILD;
unsigned IOCTL_OFIOCFINDDEVICE = OFIOCFINDDEVICE;
unsigned IOCTL_AMR_IO_VERSION = AMR_IO_VERSION;
unsigned IOCTL_AMR_IO_COMMAND = AMR_IO_COMMAND;
unsigned IOCTL_MLYIO_COMMAND = MLYIO_COMMAND;
unsigned IOCTL_MLYIO_HEALTH = MLYIO_HEALTH;
unsigned IOCTL_PCI_IOC_CFGREAD = PCI_IOC_CFGREAD;
unsigned IOCTL_PCI_IOC_CFGWRITE = PCI_IOC_CFGWRITE;
unsigned IOCTL_PCI_IOC_BDF_CFGREAD = PCI_IOC_BDF_CFGREAD;
unsigned IOCTL_PCI_IOC_BDF_CFGWRITE = PCI_IOC_BDF_CFGWRITE;
unsigned IOCTL_PCI_IOC_BUSINFO = PCI_IOC_BUSINFO;
unsigned IOCTL_PCI_IOC_DRVNAME = PCI_IOC_DRVNAME;
unsigned IOCTL_PCI_IOC_DRVNAMEONBUS = PCI_IOC_DRVNAMEONBUS;
unsigned IOCTL_TWEIO_COMMAND = TWEIO_COMMAND;
unsigned IOCTL_TWEIO_STATS = TWEIO_STATS;
unsigned IOCTL_TWEIO_AEN_POLL = TWEIO_AEN_POLL;
unsigned IOCTL_TWEIO_AEN_WAIT = TWEIO_AEN_WAIT;
unsigned IOCTL_TWEIO_SET_PARAM = TWEIO_SET_PARAM;
unsigned IOCTL_TWEIO_GET_PARAM = TWEIO_GET_PARAM;
unsigned IOCTL_TWEIO_RESET = TWEIO_RESET;
unsigned IOCTL_TWEIO_ADD_UNIT = TWEIO_ADD_UNIT;
unsigned IOCTL_TWEIO_DEL_UNIT = TWEIO_DEL_UNIT;
unsigned IOCTL_SIOCSCNWDOMAIN = SIOCSCNWDOMAIN;
unsigned IOCTL_SIOCGCNWDOMAIN = SIOCGCNWDOMAIN;
unsigned IOCTL_SIOCSCNWKEY = SIOCSCNWKEY;
unsigned IOCTL_SIOCGCNWSTATUS = SIOCGCNWSTATUS;
unsigned IOCTL_SIOCGCNWSTATS = SIOCGCNWSTATS;
unsigned IOCTL_SIOCGCNWTRAIL = SIOCGCNWTRAIL;
unsigned IOCTL_SIOCGRAYSIGLEV = SIOCGRAYSIGLEV;
unsigned IOCTL_RAIDFRAME_SHUTDOWN = RAIDFRAME_SHUTDOWN;
unsigned IOCTL_RAIDFRAME_TUR = RAIDFRAME_TUR;
unsigned IOCTL_RAIDFRAME_FAIL_DISK = RAIDFRAME_FAIL_DISK;
unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS = RAIDFRAME_CHECK_RECON_STATUS;
unsigned IOCTL_RAIDFRAME_REWRITEPARITY = RAIDFRAME_REWRITEPARITY;
unsigned IOCTL_RAIDFRAME_COPYBACK = RAIDFRAME_COPYBACK;
unsigned IOCTL_RAIDFRAME_SPARET_WAIT = RAIDFRAME_SPARET_WAIT;
unsigned IOCTL_RAIDFRAME_SEND_SPARET = RAIDFRAME_SEND_SPARET;
unsigned IOCTL_RAIDFRAME_ABORT_SPARET_WAIT = RAIDFRAME_ABORT_SPARET_WAIT;
unsigned IOCTL_RAIDFRAME_START_ATRACE = RAIDFRAME_START_ATRACE;
unsigned IOCTL_RAIDFRAME_STOP_ATRACE = RAIDFRAME_STOP_ATRACE;
unsigned IOCTL_RAIDFRAME_GET_SIZE = RAIDFRAME_GET_SIZE;
unsigned IOCTL_RAIDFRAME_RESET_ACCTOTALS = RAIDFRAME_RESET_ACCTOTALS;
unsigned IOCTL_RAIDFRAME_KEEP_ACCTOTALS = RAIDFRAME_KEEP_ACCTOTALS;
unsigned IOCTL_RAIDFRAME_GET_COMPONENT_LABEL = RAIDFRAME_GET_COMPONENT_LABEL;
unsigned IOCTL_RAIDFRAME_SET_COMPONENT_LABEL = RAIDFRAME_SET_COMPONENT_LABEL;
unsigned IOCTL_RAIDFRAME_INIT_LABELS = RAIDFRAME_INIT_LABELS;
unsigned IOCTL_RAIDFRAME_ADD_HOT_SPARE = RAIDFRAME_ADD_HOT_SPARE;
unsigned IOCTL_RAIDFRAME_REMOVE_HOT_SPARE = RAIDFRAME_REMOVE_HOT_SPARE;
unsigned IOCTL_RAIDFRAME_REBUILD_IN_PLACE = RAIDFRAME_REBUILD_IN_PLACE;
unsigned IOCTL_RAIDFRAME_CHECK_PARITY = RAIDFRAME_CHECK_PARITY;
unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS =
RAIDFRAME_CHECK_PARITYREWRITE_STATUS;
unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS =
RAIDFRAME_CHECK_COPYBACK_STATUS;
unsigned IOCTL_RAIDFRAME_SET_AUTOCONFIG = RAIDFRAME_SET_AUTOCONFIG;
unsigned IOCTL_RAIDFRAME_SET_ROOT = RAIDFRAME_SET_ROOT;
unsigned IOCTL_RAIDFRAME_DELETE_COMPONENT = RAIDFRAME_DELETE_COMPONENT;
unsigned IOCTL_RAIDFRAME_INCORPORATE_HOT_SPARE =
RAIDFRAME_INCORPORATE_HOT_SPARE;
unsigned IOCTL_RAIDFRAME_CHECK_RECON_STATUS_EXT =
RAIDFRAME_CHECK_RECON_STATUS_EXT;
unsigned IOCTL_RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT =
RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT;
unsigned IOCTL_RAIDFRAME_CHECK_COPYBACK_STATUS_EXT =
RAIDFRAME_CHECK_COPYBACK_STATUS_EXT;
unsigned IOCTL_RAIDFRAME_CONFIGURE = RAIDFRAME_CONFIGURE;
unsigned IOCTL_RAIDFRAME_GET_INFO = RAIDFRAME_GET_INFO;
unsigned IOCTL_RAIDFRAME_PARITYMAP_STATUS = RAIDFRAME_PARITYMAP_STATUS;
unsigned IOCTL_RAIDFRAME_PARITYMAP_GET_DISABLE =
RAIDFRAME_PARITYMAP_GET_DISABLE;
unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_DISABLE =
RAIDFRAME_PARITYMAP_SET_DISABLE;
unsigned IOCTL_RAIDFRAME_PARITYMAP_SET_PARAMS = RAIDFRAME_PARITYMAP_SET_PARAMS;
unsigned IOCTL_RAIDFRAME_SET_LAST_UNIT = RAIDFRAME_SET_LAST_UNIT;
unsigned IOCTL_MBPPIOCSPARAM = MBPPIOCSPARAM;
unsigned IOCTL_MBPPIOCGPARAM = MBPPIOCGPARAM;
unsigned IOCTL_MBPPIOCGSTAT = MBPPIOCGSTAT;
unsigned IOCTL_SESIOC_GETNOBJ = SESIOC_GETNOBJ;
unsigned IOCTL_SESIOC_GETOBJMAP = SESIOC_GETOBJMAP;
unsigned IOCTL_SESIOC_GETENCSTAT = SESIOC_GETENCSTAT;
unsigned IOCTL_SESIOC_SETENCSTAT = SESIOC_SETENCSTAT;
unsigned IOCTL_SESIOC_GETOBJSTAT = SESIOC_GETOBJSTAT;
unsigned IOCTL_SESIOC_SETOBJSTAT = SESIOC_SETOBJSTAT;
unsigned IOCTL_SESIOC_GETTEXT = SESIOC_GETTEXT;
unsigned IOCTL_SESIOC_INIT = SESIOC_INIT;
unsigned IOCTL_SUN_DKIOCGGEOM = SUN_DKIOCGGEOM;
unsigned IOCTL_SUN_DKIOCINFO = SUN_DKIOCINFO;
unsigned IOCTL_SUN_DKIOCGPART = SUN_DKIOCGPART;
unsigned IOCTL_FBIOGTYPE = FBIOGTYPE;
unsigned IOCTL_FBIOPUTCMAP = FBIOPUTCMAP;
unsigned IOCTL_FBIOGETCMAP = FBIOGETCMAP;
unsigned IOCTL_FBIOGATTR = FBIOGATTR;
unsigned IOCTL_FBIOSVIDEO = FBIOSVIDEO;
unsigned IOCTL_FBIOGVIDEO = FBIOGVIDEO;
unsigned IOCTL_FBIOSCURSOR = FBIOSCURSOR;
unsigned IOCTL_FBIOGCURSOR = FBIOGCURSOR;
unsigned IOCTL_FBIOSCURPOS = FBIOSCURPOS;
unsigned IOCTL_FBIOGCURPOS = FBIOGCURPOS;
unsigned IOCTL_FBIOGCURMAX = FBIOGCURMAX;
unsigned IOCTL_KIOCTRANS = KIOCTRANS;
unsigned IOCTL_KIOCSETKEY = KIOCSETKEY;
unsigned IOCTL_KIOCGETKEY = KIOCGETKEY;
unsigned IOCTL_KIOCGTRANS = KIOCGTRANS;
unsigned IOCTL_KIOCCMD = KIOCCMD;
unsigned IOCTL_KIOCTYPE = KIOCTYPE;
unsigned IOCTL_KIOCSDIRECT = KIOCSDIRECT;
unsigned IOCTL_KIOCSKEY = KIOCSKEY;
unsigned IOCTL_KIOCGKEY = KIOCGKEY;
unsigned IOCTL_KIOCSLED = KIOCSLED;
unsigned IOCTL_KIOCGLED = KIOCGLED;
unsigned IOCTL_KIOCLAYOUT = KIOCLAYOUT;
unsigned IOCTL_VUIDSFORMAT = VUIDSFORMAT;
unsigned IOCTL_VUIDGFORMAT = VUIDGFORMAT;
unsigned IOCTL_STICIO_GXINFO = STICIO_GXINFO;
unsigned IOCTL_STICIO_RESET = STICIO_RESET;
unsigned IOCTL_STICIO_STARTQ = STICIO_STARTQ;
unsigned IOCTL_STICIO_STOPQ = STICIO_STOPQ;
unsigned IOCTL_UKYOPON_IDENTIFY = UKYOPON_IDENTIFY;
unsigned IOCTL_URIO_SEND_COMMAND = URIO_SEND_COMMAND;
unsigned IOCTL_URIO_RECV_COMMAND = URIO_RECV_COMMAND;
unsigned IOCTL_USB_REQUEST = USB_REQUEST;
unsigned IOCTL_USB_SETDEBUG = USB_SETDEBUG;
unsigned IOCTL_USB_DISCOVER = USB_DISCOVER;
unsigned IOCTL_USB_DEVICEINFO = USB_DEVICEINFO;
unsigned IOCTL_USB_DEVICEINFO_OLD = USB_DEVICEINFO_OLD;
unsigned IOCTL_USB_DEVICESTATS = USB_DEVICESTATS;
unsigned IOCTL_USB_GET_REPORT_DESC = USB_GET_REPORT_DESC;
unsigned IOCTL_USB_SET_IMMED = USB_SET_IMMED;
unsigned IOCTL_USB_GET_REPORT = USB_GET_REPORT;
unsigned IOCTL_USB_SET_REPORT = USB_SET_REPORT;
unsigned IOCTL_USB_GET_REPORT_ID = USB_GET_REPORT_ID;
unsigned IOCTL_USB_GET_CONFIG = USB_GET_CONFIG;
unsigned IOCTL_USB_SET_CONFIG = USB_SET_CONFIG;
unsigned IOCTL_USB_GET_ALTINTERFACE = USB_GET_ALTINTERFACE;
unsigned IOCTL_USB_SET_ALTINTERFACE = USB_SET_ALTINTERFACE;
unsigned IOCTL_USB_GET_NO_ALT = USB_GET_NO_ALT;
unsigned IOCTL_USB_GET_DEVICE_DESC = USB_GET_DEVICE_DESC;
unsigned IOCTL_USB_GET_CONFIG_DESC = USB_GET_CONFIG_DESC;
unsigned IOCTL_USB_GET_INTERFACE_DESC = USB_GET_INTERFACE_DESC;
unsigned IOCTL_USB_GET_ENDPOINT_DESC = USB_GET_ENDPOINT_DESC;
unsigned IOCTL_USB_GET_FULL_DESC = USB_GET_FULL_DESC;
unsigned IOCTL_USB_GET_STRING_DESC = USB_GET_STRING_DESC;
unsigned IOCTL_USB_DO_REQUEST = USB_DO_REQUEST;
unsigned IOCTL_USB_GET_DEVICEINFO = USB_GET_DEVICEINFO;
unsigned IOCTL_USB_GET_DEVICEINFO_OLD = USB_GET_DEVICEINFO_OLD;
unsigned IOCTL_USB_SET_SHORT_XFER = USB_SET_SHORT_XFER;
unsigned IOCTL_USB_SET_TIMEOUT = USB_SET_TIMEOUT;
unsigned IOCTL_USB_SET_BULK_RA = USB_SET_BULK_RA;
unsigned IOCTL_USB_SET_BULK_WB = USB_SET_BULK_WB;
unsigned IOCTL_USB_SET_BULK_RA_OPT = USB_SET_BULK_RA_OPT;
unsigned IOCTL_USB_SET_BULK_WB_OPT = USB_SET_BULK_WB_OPT;
unsigned IOCTL_USB_GET_CM_OVER_DATA = USB_GET_CM_OVER_DATA;
unsigned IOCTL_USB_SET_CM_OVER_DATA = USB_SET_CM_OVER_DATA;
unsigned IOCTL_UTOPPYIOTURBO = UTOPPYIOTURBO;
unsigned IOCTL_UTOPPYIOCANCEL = UTOPPYIOCANCEL;
unsigned IOCTL_UTOPPYIOREBOOT = UTOPPYIOREBOOT;
unsigned IOCTL_UTOPPYIOSTATS = UTOPPYIOSTATS;
unsigned IOCTL_UTOPPYIORENAME = UTOPPYIORENAME;
unsigned IOCTL_UTOPPYIOMKDIR = UTOPPYIOMKDIR;
unsigned IOCTL_UTOPPYIODELETE = UTOPPYIODELETE;
unsigned IOCTL_UTOPPYIOREADDIR = UTOPPYIOREADDIR;
unsigned IOCTL_UTOPPYIOREADFILE = UTOPPYIOREADFILE;
unsigned IOCTL_UTOPPYIOWRITEFILE = UTOPPYIOWRITEFILE;
unsigned IOCTL_DIOSXDCMD = DIOSXDCMD;
unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
unsigned IOCTL_VT_SETMODE = VT_SETMODE;
unsigned IOCTL_VT_GETMODE = VT_GETMODE;
unsigned IOCTL_VT_RELDISP = VT_RELDISP;
unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
unsigned IOCTL_VT_GETACTIVE = VT_GETACTIVE;
unsigned IOCTL_VT_GETSTATE = VT_GETSTATE;
unsigned IOCTL_KDGETKBENT = KDGETKBENT;
unsigned IOCTL_KDGKBMODE = KDGKBMODE;
unsigned IOCTL_KDSKBMODE = KDSKBMODE;
unsigned IOCTL_KDMKTONE = KDMKTONE;
unsigned IOCTL_KDSETMODE = KDSETMODE;
unsigned IOCTL_KDENABIO = KDENABIO;
unsigned IOCTL_KDDISABIO = KDDISABIO;
unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
unsigned IOCTL_KDGETLED = KDGETLED;
unsigned IOCTL_KDSETLED = KDSETLED;
unsigned IOCTL_KDSETRAD = KDSETRAD;
unsigned IOCTL_VGAPCVTID = VGAPCVTID;
unsigned IOCTL_CONS_GETVERS = CONS_GETVERS;
unsigned IOCTL_WSKBDIO_GTYPE = WSKBDIO_GTYPE;
unsigned IOCTL_WSKBDIO_BELL = WSKBDIO_BELL;
unsigned IOCTL_WSKBDIO_COMPLEXBELL = WSKBDIO_COMPLEXBELL;
unsigned IOCTL_WSKBDIO_SETBELL = WSKBDIO_SETBELL;
unsigned IOCTL_WSKBDIO_GETBELL = WSKBDIO_GETBELL;
unsigned IOCTL_WSKBDIO_SETDEFAULTBELL = WSKBDIO_SETDEFAULTBELL;
unsigned IOCTL_WSKBDIO_GETDEFAULTBELL = WSKBDIO_GETDEFAULTBELL;
unsigned IOCTL_WSKBDIO_SETKEYREPEAT = WSKBDIO_SETKEYREPEAT;
unsigned IOCTL_WSKBDIO_GETKEYREPEAT = WSKBDIO_GETKEYREPEAT;
unsigned IOCTL_WSKBDIO_SETDEFAULTKEYREPEAT = WSKBDIO_SETDEFAULTKEYREPEAT;
unsigned IOCTL_WSKBDIO_GETDEFAULTKEYREPEAT = WSKBDIO_GETDEFAULTKEYREPEAT;
unsigned IOCTL_WSKBDIO_SETLEDS = WSKBDIO_SETLEDS;
unsigned IOCTL_WSKBDIO_GETLEDS = WSKBDIO_GETLEDS;
unsigned IOCTL_WSKBDIO_GETMAP = WSKBDIO_GETMAP;
unsigned IOCTL_WSKBDIO_SETMAP = WSKBDIO_SETMAP;
unsigned IOCTL_WSKBDIO_GETENCODING = WSKBDIO_GETENCODING;
unsigned IOCTL_WSKBDIO_SETENCODING = WSKBDIO_SETENCODING;
unsigned IOCTL_WSKBDIO_SETMODE = WSKBDIO_SETMODE;
unsigned IOCTL_WSKBDIO_GETMODE = WSKBDIO_GETMODE;
unsigned IOCTL_WSKBDIO_SETKEYCLICK = WSKBDIO_SETKEYCLICK;
unsigned IOCTL_WSKBDIO_GETKEYCLICK = WSKBDIO_GETKEYCLICK;
unsigned IOCTL_WSKBDIO_GETSCROLL = WSKBDIO_GETSCROLL;
unsigned IOCTL_WSKBDIO_SETSCROLL = WSKBDIO_SETSCROLL;
unsigned IOCTL_WSKBDIO_SETVERSION = WSKBDIO_SETVERSION;
unsigned IOCTL_WSMOUSEIO_GTYPE = WSMOUSEIO_GTYPE;
unsigned IOCTL_WSMOUSEIO_SRES = WSMOUSEIO_SRES;
unsigned IOCTL_WSMOUSEIO_SSCALE = WSMOUSEIO_SSCALE;
unsigned IOCTL_WSMOUSEIO_SRATE = WSMOUSEIO_SRATE;
unsigned IOCTL_WSMOUSEIO_SCALIBCOORDS = WSMOUSEIO_SCALIBCOORDS;
unsigned IOCTL_WSMOUSEIO_GCALIBCOORDS = WSMOUSEIO_GCALIBCOORDS;
unsigned IOCTL_WSMOUSEIO_GETID = WSMOUSEIO_GETID;
unsigned IOCTL_WSMOUSEIO_GETREPEAT = WSMOUSEIO_GETREPEAT;
unsigned IOCTL_WSMOUSEIO_SETREPEAT = WSMOUSEIO_SETREPEAT;
unsigned IOCTL_WSMOUSEIO_SETVERSION = WSMOUSEIO_SETVERSION;
unsigned IOCTL_WSDISPLAYIO_GTYPE = WSDISPLAYIO_GTYPE;
unsigned IOCTL_WSDISPLAYIO_GINFO = WSDISPLAYIO_GINFO;
unsigned IOCTL_WSDISPLAYIO_GETCMAP = WSDISPLAYIO_GETCMAP;
unsigned IOCTL_WSDISPLAYIO_PUTCMAP = WSDISPLAYIO_PUTCMAP;
unsigned IOCTL_WSDISPLAYIO_GVIDEO = WSDISPLAYIO_GVIDEO;
unsigned IOCTL_WSDISPLAYIO_SVIDEO = WSDISPLAYIO_SVIDEO;
unsigned IOCTL_WSDISPLAYIO_GCURPOS = WSDISPLAYIO_GCURPOS;
unsigned IOCTL_WSDISPLAYIO_SCURPOS = WSDISPLAYIO_SCURPOS;
unsigned IOCTL_WSDISPLAYIO_GCURMAX = WSDISPLAYIO_GCURMAX;
unsigned IOCTL_WSDISPLAYIO_GCURSOR = WSDISPLAYIO_GCURSOR;
unsigned IOCTL_WSDISPLAYIO_SCURSOR = WSDISPLAYIO_SCURSOR;
unsigned IOCTL_WSDISPLAYIO_GMODE = WSDISPLAYIO_GMODE;
unsigned IOCTL_WSDISPLAYIO_SMODE = WSDISPLAYIO_SMODE;
unsigned IOCTL_WSDISPLAYIO_LDFONT = WSDISPLAYIO_LDFONT;
unsigned IOCTL_WSDISPLAYIO_ADDSCREEN = WSDISPLAYIO_ADDSCREEN;
unsigned IOCTL_WSDISPLAYIO_DELSCREEN = WSDISPLAYIO_DELSCREEN;
unsigned IOCTL_WSDISPLAYIO_SFONT = WSDISPLAYIO_SFONT;
unsigned IOCTL__O_WSDISPLAYIO_SETKEYBOARD = _O_WSDISPLAYIO_SETKEYBOARD;
unsigned IOCTL_WSDISPLAYIO_GETPARAM = WSDISPLAYIO_GETPARAM;
unsigned IOCTL_WSDISPLAYIO_SETPARAM = WSDISPLAYIO_SETPARAM;
unsigned IOCTL_WSDISPLAYIO_GETACTIVESCREEN = WSDISPLAYIO_GETACTIVESCREEN;
unsigned IOCTL_WSDISPLAYIO_GETWSCHAR = WSDISPLAYIO_GETWSCHAR;
unsigned IOCTL_WSDISPLAYIO_PUTWSCHAR = WSDISPLAYIO_PUTWSCHAR;
unsigned IOCTL_WSDISPLAYIO_DGSCROLL = WSDISPLAYIO_DGSCROLL;
unsigned IOCTL_WSDISPLAYIO_DSSCROLL = WSDISPLAYIO_DSSCROLL;
unsigned IOCTL_WSDISPLAYIO_GMSGATTRS = WSDISPLAYIO_GMSGATTRS;
unsigned IOCTL_WSDISPLAYIO_SMSGATTRS = WSDISPLAYIO_SMSGATTRS;
unsigned IOCTL_WSDISPLAYIO_GBORDER = WSDISPLAYIO_GBORDER;
unsigned IOCTL_WSDISPLAYIO_SBORDER = WSDISPLAYIO_SBORDER;
unsigned IOCTL_WSDISPLAYIO_SSPLASH = WSDISPLAYIO_SSPLASH;
unsigned IOCTL_WSDISPLAYIO_SPROGRESS = WSDISPLAYIO_SPROGRESS;
unsigned IOCTL_WSDISPLAYIO_LINEBYTES = WSDISPLAYIO_LINEBYTES;
unsigned IOCTL_WSDISPLAYIO_SETVERSION = WSDISPLAYIO_SETVERSION;
unsigned IOCTL_WSMUXIO_ADD_DEVICE = WSMUXIO_ADD_DEVICE;
unsigned IOCTL_WSMUXIO_REMOVE_DEVICE = WSMUXIO_REMOVE_DEVICE;
unsigned IOCTL_WSMUXIO_LIST_DEVICES = WSMUXIO_LIST_DEVICES;
unsigned IOCTL_WSMUXIO_INJECTEVENT = WSMUXIO_INJECTEVENT;
unsigned IOCTL_WSDISPLAYIO_GET_BUSID = WSDISPLAYIO_GET_BUSID;
unsigned IOCTL_WSDISPLAYIO_GET_EDID = WSDISPLAYIO_GET_EDID;
unsigned IOCTL_WSDISPLAYIO_SET_POLLING = WSDISPLAYIO_SET_POLLING;
unsigned IOCTL_WSDISPLAYIO_GET_FBINFO = WSDISPLAYIO_GET_FBINFO;
unsigned IOCTL_WSDISPLAYIO_DOBLIT = WSDISPLAYIO_DOBLIT;
unsigned IOCTL_WSDISPLAYIO_WAITBLIT = WSDISPLAYIO_WAITBLIT;
unsigned IOCTL_BIOCLOCATE = BIOCLOCATE;
unsigned IOCTL_BIOCINQ = BIOCINQ;
unsigned IOCTL_BIOCDISK_NOVOL = BIOCDISK_NOVOL;
unsigned IOCTL_BIOCDISK = BIOCDISK;
unsigned IOCTL_BIOCVOL = BIOCVOL;
unsigned IOCTL_BIOCALARM = BIOCALARM;
unsigned IOCTL_BIOCBLINK = BIOCBLINK;
unsigned IOCTL_BIOCSETSTATE = BIOCSETSTATE;
unsigned IOCTL_BIOCVOLOPS = BIOCVOLOPS;
unsigned IOCTL_MD_GETCONF = MD_GETCONF;
unsigned IOCTL_MD_SETCONF = MD_SETCONF;
unsigned IOCTL_CCDIOCSET = CCDIOCSET;
unsigned IOCTL_CCDIOCCLR = CCDIOCCLR;
unsigned IOCTL_CGDIOCSET = CGDIOCSET;
unsigned IOCTL_CGDIOCCLR = CGDIOCCLR;
unsigned IOCTL_CGDIOCGET = CGDIOCGET;
unsigned IOCTL_FSSIOCSET = FSSIOCSET;
unsigned IOCTL_FSSIOCGET = FSSIOCGET;
unsigned IOCTL_FSSIOCCLR = FSSIOCCLR;
unsigned IOCTL_FSSIOFSET = FSSIOFSET;
unsigned IOCTL_FSSIOFGET = FSSIOFGET;
unsigned IOCTL_BTDEV_ATTACH = BTDEV_ATTACH;
unsigned IOCTL_BTDEV_DETACH = BTDEV_DETACH;
unsigned IOCTL_BTSCO_GETINFO = BTSCO_GETINFO;
unsigned IOCTL_KTTCP_IO_SEND = KTTCP_IO_SEND;
unsigned IOCTL_KTTCP_IO_RECV = KTTCP_IO_RECV;
unsigned IOCTL_IOC_LOCKSTAT_GVERSION = IOC_LOCKSTAT_GVERSION;
unsigned IOCTL_IOC_LOCKSTAT_ENABLE = IOC_LOCKSTAT_ENABLE;
unsigned IOCTL_IOC_LOCKSTAT_DISABLE = IOC_LOCKSTAT_DISABLE;
unsigned IOCTL_VNDIOCSET = VNDIOCSET;
unsigned IOCTL_VNDIOCCLR = VNDIOCCLR;
unsigned IOCTL_VNDIOCGET = VNDIOCGET;
unsigned IOCTL_SPKRTONE = SPKRTONE;
unsigned IOCTL_SPKRTUNE = SPKRTUNE;
unsigned IOCTL_SPKRGETVOL = SPKRGETVOL;
unsigned IOCTL_SPKRSETVOL = SPKRSETVOL;
#if 0 /* interfaces are WIP */
unsigned IOCTL_NVMM_IOC_CAPABILITY = NVMM_IOC_CAPABILITY;
unsigned IOCTL_NVMM_IOC_MACHINE_CREATE = NVMM_IOC_MACHINE_CREATE;
unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY = NVMM_IOC_MACHINE_DESTROY;
unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE = NVMM_IOC_MACHINE_CONFIGURE;
unsigned IOCTL_NVMM_IOC_VCPU_CREATE = NVMM_IOC_VCPU_CREATE;
unsigned IOCTL_NVMM_IOC_VCPU_DESTROY = NVMM_IOC_VCPU_DESTROY;
unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE = NVMM_IOC_VCPU_SETSTATE;
unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE = NVMM_IOC_VCPU_GETSTATE;
unsigned IOCTL_NVMM_IOC_VCPU_INJECT = NVMM_IOC_VCPU_INJECT;
unsigned IOCTL_NVMM_IOC_VCPU_RUN = NVMM_IOC_VCPU_RUN;
unsigned IOCTL_NVMM_IOC_GPA_MAP = NVMM_IOC_GPA_MAP;
unsigned IOCTL_NVMM_IOC_GPA_UNMAP = NVMM_IOC_GPA_UNMAP;
unsigned IOCTL_NVMM_IOC_HVA_MAP = NVMM_IOC_HVA_MAP;
unsigned IOCTL_NVMM_IOC_HVA_UNMAP = NVMM_IOC_HVA_UNMAP;
#endif
unsigned IOCTL_AUTOFSREQUEST = AUTOFSREQUEST;
unsigned IOCTL_AUTOFSDONE = AUTOFSDONE;
unsigned IOCTL_BIOCGBLEN = BIOCGBLEN;
unsigned IOCTL_BIOCSBLEN = BIOCSBLEN;
unsigned IOCTL_BIOCSETF = BIOCSETF;
unsigned IOCTL_BIOCFLUSH = BIOCFLUSH;
unsigned IOCTL_BIOCPROMISC = BIOCPROMISC;
unsigned IOCTL_BIOCGDLT = BIOCGDLT;
unsigned IOCTL_BIOCGETIF = BIOCGETIF;
unsigned IOCTL_BIOCSETIF = BIOCSETIF;
unsigned IOCTL_BIOCGSTATS = BIOCGSTATS;
unsigned IOCTL_BIOCGSTATSOLD = BIOCGSTATSOLD;
unsigned IOCTL_BIOCIMMEDIATE = BIOCIMMEDIATE;
unsigned IOCTL_BIOCVERSION = BIOCVERSION;
unsigned IOCTL_BIOCSTCPF = BIOCSTCPF;
unsigned IOCTL_BIOCSUDPF = BIOCSUDPF;
unsigned IOCTL_BIOCGHDRCMPLT = BIOCGHDRCMPLT;
unsigned IOCTL_BIOCSHDRCMPLT = BIOCSHDRCMPLT;
unsigned IOCTL_BIOCSDLT = BIOCSDLT;
unsigned IOCTL_BIOCGDLTLIST = BIOCGDLTLIST;
unsigned IOCTL_BIOCGDIRECTION = BIOCGDIRECTION;
unsigned IOCTL_BIOCSDIRECTION = BIOCSDIRECTION;
unsigned IOCTL_BIOCSRTIMEOUT = BIOCSRTIMEOUT;
unsigned IOCTL_BIOCGRTIMEOUT = BIOCGRTIMEOUT;
unsigned IOCTL_BIOCGFEEDBACK = BIOCGFEEDBACK;
unsigned IOCTL_BIOCSFEEDBACK = BIOCSFEEDBACK;
unsigned IOCTL_GRESADDRS = GRESADDRS;
unsigned IOCTL_GRESADDRD = GRESADDRD;
unsigned IOCTL_GREGADDRS = GREGADDRS;
unsigned IOCTL_GREGADDRD = GREGADDRD;
unsigned IOCTL_GRESPROTO = GRESPROTO;
unsigned IOCTL_GREGPROTO = GREGPROTO;
unsigned IOCTL_GRESSOCK = GRESSOCK;
unsigned IOCTL_GREDSOCK = GREDSOCK;
unsigned IOCTL_PPPIOCGRAWIN = PPPIOCGRAWIN;
unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS;
unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS;
unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP;
unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP;
unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT;
unsigned IOCTL_PPPIOCGRASYNCMAP = PPPIOCGRASYNCMAP;
unsigned IOCTL_PPPIOCSRASYNCMAP = PPPIOCSRASYNCMAP;
unsigned IOCTL_PPPIOCGMRU = PPPIOCGMRU;
unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU;
unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID;
unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP;
unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP;
unsigned IOCTL_PPPIOCXFERUNIT = PPPIOCXFERUNIT;
unsigned IOCTL_PPPIOCSCOMPRESS = PPPIOCSCOMPRESS;
unsigned IOCTL_PPPIOCGNPMODE = PPPIOCGNPMODE;
unsigned IOCTL_PPPIOCSNPMODE = PPPIOCSNPMODE;
unsigned IOCTL_PPPIOCGIDLE = PPPIOCGIDLE;
unsigned IOCTL_PPPIOCGMTU = PPPIOCGMTU;
unsigned IOCTL_PPPIOCSMTU = PPPIOCSMTU;
unsigned IOCTL_SIOCGPPPSTATS = SIOCGPPPSTATS;
unsigned IOCTL_SIOCGPPPCSTATS = SIOCGPPPCSTATS;
unsigned IOCTL_IOC_NPF_VERSION = IOC_NPF_VERSION;
unsigned IOCTL_IOC_NPF_SWITCH = IOC_NPF_SWITCH;
unsigned IOCTL_IOC_NPF_LOAD = IOC_NPF_LOAD;
unsigned IOCTL_IOC_NPF_TABLE = IOC_NPF_TABLE;
unsigned IOCTL_IOC_NPF_STATS = IOC_NPF_STATS;
unsigned IOCTL_IOC_NPF_SAVE = IOC_NPF_SAVE;
unsigned IOCTL_IOC_NPF_RULE = IOC_NPF_RULE;
unsigned IOCTL_IOC_NPF_CONN_LOOKUP = IOC_NPF_CONN_LOOKUP;
unsigned IOCTL_PPPOESETPARMS = PPPOESETPARMS;
unsigned IOCTL_PPPOEGETPARMS = PPPOEGETPARMS;
unsigned IOCTL_PPPOEGETSESSION = PPPOEGETSESSION;
unsigned IOCTL_SPPPGETAUTHCFG = SPPPGETAUTHCFG;
unsigned IOCTL_SPPPSETAUTHCFG = SPPPSETAUTHCFG;
unsigned IOCTL_SPPPGETLCPCFG = SPPPGETLCPCFG;
unsigned IOCTL_SPPPSETLCPCFG = SPPPSETLCPCFG;
unsigned IOCTL_SPPPGETSTATUS = SPPPGETSTATUS;
unsigned IOCTL_SPPPGETSTATUSNCP = SPPPGETSTATUSNCP;
unsigned IOCTL_SPPPGETIDLETO = SPPPGETIDLETO;
unsigned IOCTL_SPPPSETIDLETO = SPPPSETIDLETO;
unsigned IOCTL_SPPPGETAUTHFAILURES = SPPPGETAUTHFAILURES;
unsigned IOCTL_SPPPSETAUTHFAILURE = SPPPSETAUTHFAILURE;
unsigned IOCTL_SPPPSETDNSOPTS = SPPPSETDNSOPTS;
unsigned IOCTL_SPPPGETDNSOPTS = SPPPGETDNSOPTS;
unsigned IOCTL_SPPPGETDNSADDRS = SPPPGETDNSADDRS;
unsigned IOCTL_SPPPSETKEEPALIVE = SPPPSETKEEPALIVE;
unsigned IOCTL_SPPPGETKEEPALIVE = SPPPGETKEEPALIVE;
unsigned IOCTL_SRT_GETNRT = SRT_GETNRT;
unsigned IOCTL_SRT_GETRT = SRT_GETRT;
unsigned IOCTL_SRT_SETRT = SRT_SETRT;
unsigned IOCTL_SRT_DELRT = SRT_DELRT;
unsigned IOCTL_SRT_SFLAGS = SRT_SFLAGS;
unsigned IOCTL_SRT_GFLAGS = SRT_GFLAGS;
unsigned IOCTL_SRT_SGFLAGS = SRT_SGFLAGS;
unsigned IOCTL_SRT_DEBUG = SRT_DEBUG;
unsigned IOCTL_TAPGIFNAME = TAPGIFNAME;
unsigned IOCTL_TUNSDEBUG = TUNSDEBUG;
unsigned IOCTL_TUNGDEBUG = TUNGDEBUG;
unsigned IOCTL_TUNSIFMODE = TUNSIFMODE;
unsigned IOCTL_TUNSLMODE = TUNSLMODE;
unsigned IOCTL_TUNSIFHEAD = TUNSIFHEAD;
unsigned IOCTL_TUNGIFHEAD = TUNGIFHEAD;
unsigned IOCTL_DIOCSTART = DIOCSTART;
unsigned IOCTL_DIOCSTOP = DIOCSTOP;
unsigned IOCTL_DIOCADDRULE = DIOCADDRULE;
unsigned IOCTL_DIOCGETRULES = DIOCGETRULES;
unsigned IOCTL_DIOCGETRULE = DIOCGETRULE;
unsigned IOCTL_DIOCSETLCK = DIOCSETLCK;
unsigned IOCTL_DIOCCLRSTATES = DIOCCLRSTATES;
unsigned IOCTL_DIOCGETSTATE = DIOCGETSTATE;
unsigned IOCTL_DIOCSETSTATUSIF = DIOCSETSTATUSIF;
unsigned IOCTL_DIOCGETSTATUS = DIOCGETSTATUS;
unsigned IOCTL_DIOCCLRSTATUS = DIOCCLRSTATUS;
unsigned IOCTL_DIOCNATLOOK = DIOCNATLOOK;
unsigned IOCTL_DIOCSETDEBUG = DIOCSETDEBUG;
unsigned IOCTL_DIOCGETSTATES = DIOCGETSTATES;
unsigned IOCTL_DIOCCHANGERULE = DIOCCHANGERULE;
unsigned IOCTL_DIOCSETTIMEOUT = DIOCSETTIMEOUT;
unsigned IOCTL_DIOCGETTIMEOUT = DIOCGETTIMEOUT;
unsigned IOCTL_DIOCADDSTATE = DIOCADDSTATE;
unsigned IOCTL_DIOCCLRRULECTRS = DIOCCLRRULECTRS;
unsigned IOCTL_DIOCGETLIMIT = DIOCGETLIMIT;
unsigned IOCTL_DIOCSETLIMIT = DIOCSETLIMIT;
unsigned IOCTL_DIOCKILLSTATES = DIOCKILLSTATES;
unsigned IOCTL_DIOCSTARTALTQ = DIOCSTARTALTQ;
unsigned IOCTL_DIOCSTOPALTQ = DIOCSTOPALTQ;
unsigned IOCTL_DIOCADDALTQ = DIOCADDALTQ;
unsigned IOCTL_DIOCGETALTQS = DIOCGETALTQS;
unsigned IOCTL_DIOCGETALTQ = DIOCGETALTQ;
unsigned IOCTL_DIOCCHANGEALTQ = DIOCCHANGEALTQ;
unsigned IOCTL_DIOCGETQSTATS = DIOCGETQSTATS;
unsigned IOCTL_DIOCBEGINADDRS = DIOCBEGINADDRS;
unsigned IOCTL_DIOCADDADDR = DIOCADDADDR;
unsigned IOCTL_DIOCGETADDRS = DIOCGETADDRS;
unsigned IOCTL_DIOCGETADDR = DIOCGETADDR;
unsigned IOCTL_DIOCCHANGEADDR = DIOCCHANGEADDR;
unsigned IOCTL_DIOCADDSTATES = DIOCADDSTATES;
unsigned IOCTL_DIOCGETRULESETS = DIOCGETRULESETS;
unsigned IOCTL_DIOCGETRULESET = DIOCGETRULESET;
unsigned IOCTL_DIOCRCLRTABLES = DIOCRCLRTABLES;
unsigned IOCTL_DIOCRADDTABLES = DIOCRADDTABLES;
unsigned IOCTL_DIOCRDELTABLES = DIOCRDELTABLES;
unsigned IOCTL_DIOCRGETTABLES = DIOCRGETTABLES;
unsigned IOCTL_DIOCRGETTSTATS = DIOCRGETTSTATS;
unsigned IOCTL_DIOCRCLRTSTATS = DIOCRCLRTSTATS;
unsigned IOCTL_DIOCRCLRADDRS = DIOCRCLRADDRS;
unsigned IOCTL_DIOCRADDADDRS = DIOCRADDADDRS;
unsigned IOCTL_DIOCRDELADDRS = DIOCRDELADDRS;
unsigned IOCTL_DIOCRSETADDRS = DIOCRSETADDRS;
unsigned IOCTL_DIOCRGETADDRS = DIOCRGETADDRS;
unsigned IOCTL_DIOCRGETASTATS = DIOCRGETASTATS;
unsigned IOCTL_DIOCRCLRASTATS = DIOCRCLRASTATS;
unsigned IOCTL_DIOCRTSTADDRS = DIOCRTSTADDRS;
unsigned IOCTL_DIOCRSETTFLAGS = DIOCRSETTFLAGS;
unsigned IOCTL_DIOCRINADEFINE = DIOCRINADEFINE;
unsigned IOCTL_DIOCOSFPFLUSH = DIOCOSFPFLUSH;
unsigned IOCTL_DIOCOSFPADD = DIOCOSFPADD;
unsigned IOCTL_DIOCOSFPGET = DIOCOSFPGET;
unsigned IOCTL_DIOCXBEGIN = DIOCXBEGIN;
unsigned IOCTL_DIOCXCOMMIT = DIOCXCOMMIT;
unsigned IOCTL_DIOCXROLLBACK = DIOCXROLLBACK;
unsigned IOCTL_DIOCGETSRCNODES = DIOCGETSRCNODES;
unsigned IOCTL_DIOCCLRSRCNODES = DIOCCLRSRCNODES;
unsigned IOCTL_DIOCSETHOSTID = DIOCSETHOSTID;
unsigned IOCTL_DIOCIGETIFACES = DIOCIGETIFACES;
unsigned IOCTL_DIOCSETIFFLAG = DIOCSETIFFLAG;
unsigned IOCTL_DIOCCLRIFFLAG = DIOCCLRIFFLAG;
unsigned IOCTL_DIOCKILLSRCNODES = DIOCKILLSRCNODES;
unsigned IOCTL_SLIOCGUNIT = SLIOCGUNIT;
unsigned IOCTL_SIOCGBTINFO = SIOCGBTINFO;
unsigned IOCTL_SIOCGBTINFOA = SIOCGBTINFOA;
unsigned IOCTL_SIOCNBTINFO = SIOCNBTINFO;
unsigned IOCTL_SIOCSBTFLAGS = SIOCSBTFLAGS;
unsigned IOCTL_SIOCSBTPOLICY = SIOCSBTPOLICY;
unsigned IOCTL_SIOCSBTPTYPE = SIOCSBTPTYPE;
unsigned IOCTL_SIOCGBTSTATS = SIOCGBTSTATS;
unsigned IOCTL_SIOCZBTSTATS = SIOCZBTSTATS;
unsigned IOCTL_SIOCBTDUMP = SIOCBTDUMP;
unsigned IOCTL_SIOCSBTSCOMTU = SIOCSBTSCOMTU;
unsigned IOCTL_SIOCGBTFEAT = SIOCGBTFEAT;
unsigned IOCTL_SIOCADNAT = SIOCADNAT;
unsigned IOCTL_SIOCRMNAT = SIOCRMNAT;
unsigned IOCTL_SIOCGNATS = SIOCGNATS;
unsigned IOCTL_SIOCGNATL = SIOCGNATL;
unsigned IOCTL_SIOCPURGENAT = SIOCPURGENAT;
unsigned IOCTL_SIOCCONNECTX = SIOCCONNECTX;
unsigned IOCTL_SIOCCONNECTXDEL = SIOCCONNECTXDEL;
unsigned IOCTL_SIOCSIFINFO_FLAGS = SIOCSIFINFO_FLAGS;
unsigned IOCTL_SIOCAADDRCTL_POLICY = SIOCAADDRCTL_POLICY;
unsigned IOCTL_SIOCDADDRCTL_POLICY = SIOCDADDRCTL_POLICY;
unsigned IOCTL_SMBIOC_OPENSESSION = SMBIOC_OPENSESSION;
unsigned IOCTL_SMBIOC_OPENSHARE = SMBIOC_OPENSHARE;
unsigned IOCTL_SMBIOC_REQUEST = SMBIOC_REQUEST;
unsigned IOCTL_SMBIOC_SETFLAGS = SMBIOC_SETFLAGS;
unsigned IOCTL_SMBIOC_LOOKUP = SMBIOC_LOOKUP;
unsigned IOCTL_SMBIOC_READ = SMBIOC_READ;
unsigned IOCTL_SMBIOC_WRITE = SMBIOC_WRITE;
unsigned IOCTL_AGPIOC_INFO = AGPIOC_INFO;
unsigned IOCTL_AGPIOC_ACQUIRE = AGPIOC_ACQUIRE;
unsigned IOCTL_AGPIOC_RELEASE = AGPIOC_RELEASE;
unsigned IOCTL_AGPIOC_SETUP = AGPIOC_SETUP;
unsigned IOCTL_AGPIOC_ALLOCATE = AGPIOC_ALLOCATE;
unsigned IOCTL_AGPIOC_DEALLOCATE = AGPIOC_DEALLOCATE;
unsigned IOCTL_AGPIOC_BIND = AGPIOC_BIND;
unsigned IOCTL_AGPIOC_UNBIND = AGPIOC_UNBIND;
unsigned IOCTL_AUDIO_GETINFO = AUDIO_GETINFO;
unsigned IOCTL_AUDIO_SETINFO = AUDIO_SETINFO;
unsigned IOCTL_AUDIO_DRAIN = AUDIO_DRAIN;
unsigned IOCTL_AUDIO_FLUSH = AUDIO_FLUSH;
unsigned IOCTL_AUDIO_WSEEK = AUDIO_WSEEK;
unsigned IOCTL_AUDIO_RERROR = AUDIO_RERROR;
unsigned IOCTL_AUDIO_GETDEV = AUDIO_GETDEV;
unsigned IOCTL_AUDIO_GETENC = AUDIO_GETENC;
unsigned IOCTL_AUDIO_GETFD = AUDIO_GETFD;
unsigned IOCTL_AUDIO_SETFD = AUDIO_SETFD;
unsigned IOCTL_AUDIO_PERROR = AUDIO_PERROR;
unsigned IOCTL_AUDIO_GETIOFFS = AUDIO_GETIOFFS;
unsigned IOCTL_AUDIO_GETOOFFS = AUDIO_GETOOFFS;
unsigned IOCTL_AUDIO_GETPROPS = AUDIO_GETPROPS;
unsigned IOCTL_AUDIO_GETBUFINFO = AUDIO_GETBUFINFO;
unsigned IOCTL_AUDIO_SETCHAN = AUDIO_SETCHAN;
unsigned IOCTL_AUDIO_GETCHAN = AUDIO_GETCHAN;
unsigned IOCTL_AUDIO_MIXER_READ = AUDIO_MIXER_READ;
unsigned IOCTL_AUDIO_MIXER_WRITE = AUDIO_MIXER_WRITE;
unsigned IOCTL_AUDIO_MIXER_DEVINFO = AUDIO_MIXER_DEVINFO;
unsigned IOCTL_ATAIOCCOMMAND = ATAIOCCOMMAND;
unsigned IOCTL_ATABUSIOSCAN = ATABUSIOSCAN;
unsigned IOCTL_ATABUSIORESET = ATABUSIORESET;
unsigned IOCTL_ATABUSIODETACH = ATABUSIODETACH;
unsigned IOCTL_CDIOCPLAYTRACKS = CDIOCPLAYTRACKS;
unsigned IOCTL_CDIOCPLAYBLOCKS = CDIOCPLAYBLOCKS;
unsigned IOCTL_CDIOCREADSUBCHANNEL = CDIOCREADSUBCHANNEL;
unsigned IOCTL_CDIOREADTOCHEADER = CDIOREADTOCHEADER;
unsigned IOCTL_CDIOREADTOCENTRIES = CDIOREADTOCENTRIES;
unsigned IOCTL_CDIOREADMSADDR = CDIOREADMSADDR;
unsigned IOCTL_CDIOCSETPATCH = CDIOCSETPATCH;
unsigned IOCTL_CDIOCGETVOL = CDIOCGETVOL;
unsigned IOCTL_CDIOCSETVOL = CDIOCSETVOL;
unsigned IOCTL_CDIOCSETMONO = CDIOCSETMONO;
unsigned IOCTL_CDIOCSETSTEREO = CDIOCSETSTEREO;
unsigned IOCTL_CDIOCSETMUTE = CDIOCSETMUTE;
unsigned IOCTL_CDIOCSETLEFT = CDIOCSETLEFT;
unsigned IOCTL_CDIOCSETRIGHT = CDIOCSETRIGHT;
unsigned IOCTL_CDIOCSETDEBUG = CDIOCSETDEBUG;
unsigned IOCTL_CDIOCCLRDEBUG = CDIOCCLRDEBUG;
unsigned IOCTL_CDIOCPAUSE = CDIOCPAUSE;
unsigned IOCTL_CDIOCRESUME = CDIOCRESUME;
unsigned IOCTL_CDIOCRESET = CDIOCRESET;
unsigned IOCTL_CDIOCSTART = CDIOCSTART;
unsigned IOCTL_CDIOCSTOP = CDIOCSTOP;
unsigned IOCTL_CDIOCEJECT = CDIOCEJECT;
unsigned IOCTL_CDIOCALLOW = CDIOCALLOW;
unsigned IOCTL_CDIOCPREVENT = CDIOCPREVENT;
unsigned IOCTL_CDIOCCLOSE = CDIOCCLOSE;
unsigned IOCTL_CDIOCPLAYMSF = CDIOCPLAYMSF;
unsigned IOCTL_CDIOCLOADUNLOAD = CDIOCLOADUNLOAD;
unsigned IOCTL_CHIOMOVE = CHIOMOVE;
unsigned IOCTL_CHIOEXCHANGE = CHIOEXCHANGE;
unsigned IOCTL_CHIOPOSITION = CHIOPOSITION;
unsigned IOCTL_CHIOGPICKER = CHIOGPICKER;
unsigned IOCTL_CHIOSPICKER = CHIOSPICKER;
unsigned IOCTL_CHIOGPARAMS = CHIOGPARAMS;
unsigned IOCTL_CHIOIELEM = CHIOIELEM;
unsigned IOCTL_OCHIOGSTATUS = OCHIOGSTATUS;
unsigned IOCTL_CHIOGSTATUS = CHIOGSTATUS;
unsigned IOCTL_CHIOSVOLTAG = CHIOSVOLTAG;
unsigned IOCTL_CLOCKCTL_SETTIMEOFDAY = CLOCKCTL_SETTIMEOFDAY;
unsigned IOCTL_CLOCKCTL_ADJTIME = CLOCKCTL_ADJTIME;
unsigned IOCTL_CLOCKCTL_CLOCK_SETTIME = CLOCKCTL_CLOCK_SETTIME;
unsigned IOCTL_CLOCKCTL_NTP_ADJTIME = CLOCKCTL_NTP_ADJTIME;
unsigned IOCTL_IOC_CPU_SETSTATE = IOC_CPU_SETSTATE;
unsigned IOCTL_IOC_CPU_GETSTATE = IOC_CPU_GETSTATE;
unsigned IOCTL_IOC_CPU_GETCOUNT = IOC_CPU_GETCOUNT;
unsigned IOCTL_IOC_CPU_MAPID = IOC_CPU_MAPID;
unsigned IOCTL_IOC_CPU_UCODE_GET_VERSION = IOC_CPU_UCODE_GET_VERSION;
unsigned IOCTL_IOC_CPU_UCODE_APPLY = IOC_CPU_UCODE_APPLY;
unsigned IOCTL_DIOCGDINFO = DIOCGDINFO;
unsigned IOCTL_DIOCSDINFO = DIOCSDINFO;
unsigned IOCTL_DIOCWDINFO = DIOCWDINFO;
unsigned IOCTL_DIOCRFORMAT = DIOCRFORMAT;
unsigned IOCTL_DIOCWFORMAT = DIOCWFORMAT;
unsigned IOCTL_DIOCSSTEP = DIOCSSTEP;
unsigned IOCTL_DIOCSRETRIES = DIOCSRETRIES;
unsigned IOCTL_DIOCKLABEL = DIOCKLABEL;
unsigned IOCTL_DIOCWLABEL = DIOCWLABEL;
unsigned IOCTL_DIOCSBAD = DIOCSBAD;
unsigned IOCTL_DIOCEJECT = DIOCEJECT;
unsigned IOCTL_ODIOCEJECT = ODIOCEJECT;
unsigned IOCTL_DIOCLOCK = DIOCLOCK;
unsigned IOCTL_DIOCGDEFLABEL = DIOCGDEFLABEL;
unsigned IOCTL_DIOCCLRLABEL = DIOCCLRLABEL;
unsigned IOCTL_DIOCGCACHE = DIOCGCACHE;
unsigned IOCTL_DIOCSCACHE = DIOCSCACHE;
unsigned IOCTL_DIOCCACHESYNC = DIOCCACHESYNC;
unsigned IOCTL_DIOCBSLIST = DIOCBSLIST;
unsigned IOCTL_DIOCBSFLUSH = DIOCBSFLUSH;
unsigned IOCTL_DIOCAWEDGE = DIOCAWEDGE;
unsigned IOCTL_DIOCGWEDGEINFO = DIOCGWEDGEINFO;
unsigned IOCTL_DIOCDWEDGE = DIOCDWEDGE;
unsigned IOCTL_DIOCLWEDGES = DIOCLWEDGES;
unsigned IOCTL_DIOCGSTRATEGY = DIOCGSTRATEGY;
unsigned IOCTL_DIOCSSTRATEGY = DIOCSSTRATEGY;
unsigned IOCTL_DIOCGDISKINFO = DIOCGDISKINFO;
unsigned IOCTL_DIOCTUR = DIOCTUR;
unsigned IOCTL_DIOCMWEDGES = DIOCMWEDGES;
unsigned IOCTL_DIOCGSECTORSIZE = DIOCGSECTORSIZE;
unsigned IOCTL_DIOCGMEDIASIZE = DIOCGMEDIASIZE;
unsigned IOCTL_DRVDETACHDEV = DRVDETACHDEV;
unsigned IOCTL_DRVRESCANBUS = DRVRESCANBUS;
unsigned IOCTL_DRVCTLCOMMAND = DRVCTLCOMMAND;
unsigned IOCTL_DRVRESUMEDEV = DRVRESUMEDEV;
unsigned IOCTL_DRVLISTDEV = DRVLISTDEV;
unsigned IOCTL_DRVGETEVENT = DRVGETEVENT;
unsigned IOCTL_DRVSUSPENDDEV = DRVSUSPENDDEV;
unsigned IOCTL_DVD_READ_STRUCT = DVD_READ_STRUCT;
unsigned IOCTL_DVD_WRITE_STRUCT = DVD_WRITE_STRUCT;
unsigned IOCTL_DVD_AUTH = DVD_AUTH;
unsigned IOCTL_ENVSYS_GETDICTIONARY = ENVSYS_GETDICTIONARY;
unsigned IOCTL_ENVSYS_SETDICTIONARY = ENVSYS_SETDICTIONARY;
unsigned IOCTL_ENVSYS_REMOVEPROPS = ENVSYS_REMOVEPROPS;
unsigned IOCTL_ENVSYS_GTREDATA = ENVSYS_GTREDATA;
unsigned IOCTL_ENVSYS_GTREINFO = ENVSYS_GTREINFO;
unsigned IOCTL_KFILTER_BYFILTER = KFILTER_BYFILTER;
unsigned IOCTL_KFILTER_BYNAME = KFILTER_BYNAME;
unsigned IOCTL_FDIOCGETOPTS = FDIOCGETOPTS;
unsigned IOCTL_FDIOCSETOPTS = FDIOCSETOPTS;
unsigned IOCTL_FDIOCSETFORMAT = FDIOCSETFORMAT;
unsigned IOCTL_FDIOCGETFORMAT = FDIOCGETFORMAT;
unsigned IOCTL_FDIOCFORMAT_TRACK = FDIOCFORMAT_TRACK;
unsigned IOCTL_FIOCLEX = FIOCLEX;
unsigned IOCTL_FIONCLEX = FIONCLEX;
unsigned IOCTL_FIOSEEKDATA = FIOSEEKDATA;
unsigned IOCTL_FIOSEEKHOLE = FIOSEEKHOLE;
unsigned IOCTL_FIONREAD = FIONREAD;
unsigned IOCTL_FIONBIO = FIONBIO;
unsigned IOCTL_FIOASYNC = FIOASYNC;
unsigned IOCTL_FIOSETOWN = FIOSETOWN;
unsigned IOCTL_FIOGETOWN = FIOGETOWN;
unsigned IOCTL_OFIOGETBMAP = OFIOGETBMAP;
unsigned IOCTL_FIOGETBMAP = FIOGETBMAP;
unsigned IOCTL_FIONWRITE = FIONWRITE;
unsigned IOCTL_FIONSPACE = FIONSPACE;
unsigned IOCTL_GPIOINFO = GPIOINFO;
unsigned IOCTL_GPIOSET = GPIOSET;
unsigned IOCTL_GPIOUNSET = GPIOUNSET;
unsigned IOCTL_GPIOREAD = GPIOREAD;
unsigned IOCTL_GPIOWRITE = GPIOWRITE;
unsigned IOCTL_GPIOTOGGLE = GPIOTOGGLE;
unsigned IOCTL_GPIOATTACH = GPIOATTACH;
unsigned IOCTL_PTIOCNETBSD = PTIOCNETBSD;
unsigned IOCTL_PTIOCSUNOS = PTIOCSUNOS;
unsigned IOCTL_PTIOCLINUX = PTIOCLINUX;
unsigned IOCTL_PTIOCFREEBSD = PTIOCFREEBSD;
unsigned IOCTL_PTIOCULTRIX = PTIOCULTRIX;
unsigned IOCTL_TIOCHPCL = TIOCHPCL;
unsigned IOCTL_TIOCGETP = TIOCGETP;
unsigned IOCTL_TIOCSETP = TIOCSETP;
unsigned IOCTL_TIOCSETN = TIOCSETN;
unsigned IOCTL_TIOCSETC = TIOCSETC;
unsigned IOCTL_TIOCGETC = TIOCGETC;
unsigned IOCTL_TIOCLBIS = TIOCLBIS;
unsigned IOCTL_TIOCLBIC = TIOCLBIC;
unsigned IOCTL_TIOCLSET = TIOCLSET;
unsigned IOCTL_TIOCLGET = TIOCLGET;
unsigned IOCTL_TIOCSLTC = TIOCSLTC;
unsigned IOCTL_TIOCGLTC = TIOCGLTC;
unsigned IOCTL_OTIOCCONS = OTIOCCONS;
unsigned IOCTL_JOY_SETTIMEOUT = JOY_SETTIMEOUT;
unsigned IOCTL_JOY_GETTIMEOUT = JOY_GETTIMEOUT;
unsigned IOCTL_JOY_SET_X_OFFSET = JOY_SET_X_OFFSET;
unsigned IOCTL_JOY_SET_Y_OFFSET = JOY_SET_Y_OFFSET;
unsigned IOCTL_JOY_GET_X_OFFSET = JOY_GET_X_OFFSET;
unsigned IOCTL_JOY_GET_Y_OFFSET = JOY_GET_Y_OFFSET;
unsigned IOCTL_OKIOCGSYMBOL = OKIOCGSYMBOL;
unsigned IOCTL_OKIOCGVALUE = OKIOCGVALUE;
unsigned IOCTL_KIOCGSIZE = KIOCGSIZE;
unsigned IOCTL_KIOCGVALUE = KIOCGVALUE;
unsigned IOCTL_KIOCGSYMBOL = KIOCGSYMBOL;
unsigned IOCTL_LUAINFO = LUAINFO;
unsigned IOCTL_LUACREATE = LUACREATE;
unsigned IOCTL_LUADESTROY = LUADESTROY;
unsigned IOCTL_LUAREQUIRE = LUAREQUIRE;
unsigned IOCTL_LUALOAD = LUALOAD;
unsigned IOCTL_MIDI_PRETIME = MIDI_PRETIME;
unsigned IOCTL_MIDI_MPUMODE = MIDI_MPUMODE;
unsigned IOCTL_MIDI_MPUCMD = MIDI_MPUCMD;
unsigned IOCTL_SEQUENCER_RESET = SEQUENCER_RESET;
unsigned IOCTL_SEQUENCER_SYNC = SEQUENCER_SYNC;
unsigned IOCTL_SEQUENCER_INFO = SEQUENCER_INFO;
unsigned IOCTL_SEQUENCER_CTRLRATE = SEQUENCER_CTRLRATE;
unsigned IOCTL_SEQUENCER_GETOUTCOUNT = SEQUENCER_GETOUTCOUNT;
unsigned IOCTL_SEQUENCER_GETINCOUNT = SEQUENCER_GETINCOUNT;
unsigned IOCTL_SEQUENCER_RESETSAMPLES = SEQUENCER_RESETSAMPLES;
unsigned IOCTL_SEQUENCER_NRSYNTHS = SEQUENCER_NRSYNTHS;
unsigned IOCTL_SEQUENCER_NRMIDIS = SEQUENCER_NRMIDIS;
unsigned IOCTL_SEQUENCER_THRESHOLD = SEQUENCER_THRESHOLD;
unsigned IOCTL_SEQUENCER_MEMAVL = SEQUENCER_MEMAVL;
unsigned IOCTL_SEQUENCER_PANIC = SEQUENCER_PANIC;
unsigned IOCTL_SEQUENCER_OUTOFBAND = SEQUENCER_OUTOFBAND;
unsigned IOCTL_SEQUENCER_GETTIME = SEQUENCER_GETTIME;
unsigned IOCTL_SEQUENCER_TMR_TIMEBASE = SEQUENCER_TMR_TIMEBASE;
unsigned IOCTL_SEQUENCER_TMR_START = SEQUENCER_TMR_START;
unsigned IOCTL_SEQUENCER_TMR_STOP = SEQUENCER_TMR_STOP;
unsigned IOCTL_SEQUENCER_TMR_CONTINUE = SEQUENCER_TMR_CONTINUE;
unsigned IOCTL_SEQUENCER_TMR_TEMPO = SEQUENCER_TMR_TEMPO;
unsigned IOCTL_SEQUENCER_TMR_SOURCE = SEQUENCER_TMR_SOURCE;
unsigned IOCTL_SEQUENCER_TMR_METRONOME = SEQUENCER_TMR_METRONOME;
unsigned IOCTL_SEQUENCER_TMR_SELECT = SEQUENCER_TMR_SELECT;
unsigned IOCTL_MTIOCTOP = MTIOCTOP;
unsigned IOCTL_MTIOCGET = MTIOCGET;
unsigned IOCTL_MTIOCIEOT = MTIOCIEOT;
unsigned IOCTL_MTIOCEEOT = MTIOCEEOT;
unsigned IOCTL_MTIOCRDSPOS = MTIOCRDSPOS;
unsigned IOCTL_MTIOCRDHPOS = MTIOCRDHPOS;
unsigned IOCTL_MTIOCSLOCATE = MTIOCSLOCATE;
unsigned IOCTL_MTIOCHLOCATE = MTIOCHLOCATE;
unsigned IOCTL_POWER_EVENT_RECVDICT = POWER_EVENT_RECVDICT;
unsigned IOCTL_POWER_IOC_GET_TYPE = POWER_IOC_GET_TYPE;
unsigned IOCTL_RIOCGINFO = RIOCGINFO;
unsigned IOCTL_RIOCSINFO = RIOCSINFO;
unsigned IOCTL_RIOCSSRCH = RIOCSSRCH;
unsigned IOCTL_RNDGETENTCNT = RNDGETENTCNT;
unsigned IOCTL_RNDGETSRCNUM = RNDGETSRCNUM;
unsigned IOCTL_RNDGETSRCNAME = RNDGETSRCNAME;
unsigned IOCTL_RNDCTL = RNDCTL;
unsigned IOCTL_RNDADDDATA = RNDADDDATA;
unsigned IOCTL_RNDGETPOOLSTAT = RNDGETPOOLSTAT;
unsigned IOCTL_RNDGETESTNUM = RNDGETESTNUM;
unsigned IOCTL_RNDGETESTNAME = RNDGETESTNAME;
unsigned IOCTL_SCIOCGET = SCIOCGET;
unsigned IOCTL_SCIOCSET = SCIOCSET;
unsigned IOCTL_SCIOCRESTART = SCIOCRESTART;
unsigned IOCTL_SCIOC_USE_ADF = SCIOC_USE_ADF;
unsigned IOCTL_SCIOCCOMMAND = SCIOCCOMMAND;
unsigned IOCTL_SCIOCDEBUG = SCIOCDEBUG;
unsigned IOCTL_SCIOCIDENTIFY = SCIOCIDENTIFY;
unsigned IOCTL_OSCIOCIDENTIFY = OSCIOCIDENTIFY;
unsigned IOCTL_SCIOCDECONFIG = SCIOCDECONFIG;
unsigned IOCTL_SCIOCRECONFIG = SCIOCRECONFIG;
unsigned IOCTL_SCIOCRESET = SCIOCRESET;
unsigned IOCTL_SCBUSIOSCAN = SCBUSIOSCAN;
unsigned IOCTL_SCBUSIORESET = SCBUSIORESET;
unsigned IOCTL_SCBUSIODETACH = SCBUSIODETACH;
unsigned IOCTL_SCBUSACCEL = SCBUSACCEL;
unsigned IOCTL_SCBUSIOLLSCAN = SCBUSIOLLSCAN;
unsigned IOCTL_SIOCSHIWAT = SIOCSHIWAT;
unsigned IOCTL_SIOCGHIWAT = SIOCGHIWAT;
unsigned IOCTL_SIOCSLOWAT = SIOCSLOWAT;
unsigned IOCTL_SIOCGLOWAT = SIOCGLOWAT;
unsigned IOCTL_SIOCATMARK = SIOCATMARK;
unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
unsigned IOCTL_SIOCPEELOFF = SIOCPEELOFF;
unsigned IOCTL_SIOCADDRT = SIOCADDRT;
unsigned IOCTL_SIOCDELRT = SIOCDELRT;
unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
unsigned IOCTL_SIOCDIFADDR = SIOCDIFADDR;
unsigned IOCTL_SIOCAIFADDR = SIOCAIFADDR;
unsigned IOCTL_SIOCGIFALIAS = SIOCGIFALIAS;
unsigned IOCTL_SIOCGIFAFLAG_IN = SIOCGIFAFLAG_IN;
unsigned IOCTL_SIOCALIFADDR = SIOCALIFADDR;
unsigned IOCTL_SIOCGLIFADDR = SIOCGLIFADDR;
unsigned IOCTL_SIOCDLIFADDR = SIOCDLIFADDR;
unsigned IOCTL_SIOCSIFADDRPREF = SIOCSIFADDRPREF;
unsigned IOCTL_SIOCGIFADDRPREF = SIOCGIFADDRPREF;
unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
unsigned IOCTL_SIOCSIFMEDIA = SIOCSIFMEDIA;
unsigned IOCTL_SIOCGIFMEDIA = SIOCGIFMEDIA;
unsigned IOCTL_SIOCSIFGENERIC = SIOCSIFGENERIC;
unsigned IOCTL_SIOCGIFGENERIC = SIOCGIFGENERIC;
unsigned IOCTL_SIOCSIFPHYADDR = SIOCSIFPHYADDR;
unsigned IOCTL_SIOCGIFPSRCADDR = SIOCGIFPSRCADDR;
unsigned IOCTL_SIOCGIFPDSTADDR = SIOCGIFPDSTADDR;
unsigned IOCTL_SIOCDIFPHYADDR = SIOCDIFPHYADDR;
unsigned IOCTL_SIOCSLIFPHYADDR = SIOCSLIFPHYADDR;
unsigned IOCTL_SIOCGLIFPHYADDR = SIOCGLIFPHYADDR;
unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
unsigned IOCTL_SIOCSDRVSPEC = SIOCSDRVSPEC;
unsigned IOCTL_SIOCGDRVSPEC = SIOCGDRVSPEC;
unsigned IOCTL_SIOCIFCREATE = SIOCIFCREATE;
unsigned IOCTL_SIOCIFDESTROY = SIOCIFDESTROY;
unsigned IOCTL_SIOCIFGCLONERS = SIOCIFGCLONERS;
unsigned IOCTL_SIOCGIFDLT = SIOCGIFDLT;
unsigned IOCTL_SIOCGIFCAP = SIOCGIFCAP;
unsigned IOCTL_SIOCSIFCAP = SIOCSIFCAP;
unsigned IOCTL_SIOCSVH = SIOCSVH;
unsigned IOCTL_SIOCGVH = SIOCGVH;
unsigned IOCTL_SIOCINITIFADDR = SIOCINITIFADDR;
unsigned IOCTL_SIOCGIFDATA = SIOCGIFDATA;
unsigned IOCTL_SIOCZIFDATA = SIOCZIFDATA;
unsigned IOCTL_SIOCGLINKSTR = SIOCGLINKSTR;
unsigned IOCTL_SIOCSLINKSTR = SIOCSLINKSTR;
unsigned IOCTL_SIOCGETHERCAP = SIOCGETHERCAP;
unsigned IOCTL_SIOCGIFINDEX = SIOCGIFINDEX;
unsigned IOCTL_SIOCSETHERCAP = SIOCSETHERCAP;
unsigned IOCTL_SIOCGUMBINFO = SIOCGUMBINFO;
unsigned IOCTL_SIOCSUMBPARAM = SIOCSUMBPARAM;
unsigned IOCTL_SIOCGUMBPARAM = SIOCGUMBPARAM;
unsigned IOCTL_SIOCSETPFSYNC = SIOCSETPFSYNC;
unsigned IOCTL_SIOCGETPFSYNC = SIOCGETPFSYNC;
unsigned IOCTL_PPS_IOC_CREATE = PPS_IOC_CREATE;
unsigned IOCTL_PPS_IOC_DESTROY = PPS_IOC_DESTROY;
unsigned IOCTL_PPS_IOC_SETPARAMS = PPS_IOC_SETPARAMS;
unsigned IOCTL_PPS_IOC_GETPARAMS = PPS_IOC_GETPARAMS;
unsigned IOCTL_PPS_IOC_GETCAP = PPS_IOC_GETCAP;
unsigned IOCTL_PPS_IOC_FETCH = PPS_IOC_FETCH;
unsigned IOCTL_PPS_IOC_KCBIND = PPS_IOC_KCBIND;
unsigned IOCTL_TIOCEXCL = TIOCEXCL;
unsigned IOCTL_TIOCNXCL = TIOCNXCL;
unsigned IOCTL_TIOCFLUSH = TIOCFLUSH;
unsigned IOCTL_TIOCGETA = TIOCGETA;
unsigned IOCTL_TIOCSETA = TIOCSETA;
unsigned IOCTL_TIOCSETAW = TIOCSETAW;
unsigned IOCTL_TIOCSETAF = TIOCSETAF;
unsigned IOCTL_TIOCGETD = TIOCGETD;
unsigned IOCTL_TIOCSETD = TIOCSETD;
unsigned IOCTL_TIOCGLINED = TIOCGLINED;
unsigned IOCTL_TIOCSLINED = TIOCSLINED;
unsigned IOCTL_TIOCSBRK = TIOCSBRK;
unsigned IOCTL_TIOCCBRK = TIOCCBRK;
unsigned IOCTL_TIOCSDTR = TIOCSDTR;
unsigned IOCTL_TIOCCDTR = TIOCCDTR;
unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
unsigned IOCTL_TIOCSTI = TIOCSTI;
unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
unsigned IOCTL_TIOCPKT = TIOCPKT;
unsigned IOCTL_TIOCSTOP = TIOCSTOP;
unsigned IOCTL_TIOCSTART = TIOCSTART;
unsigned IOCTL_TIOCMSET = TIOCMSET;
unsigned IOCTL_TIOCMBIS = TIOCMBIS;
unsigned IOCTL_TIOCMBIC = TIOCMBIC;
unsigned IOCTL_TIOCMGET = TIOCMGET;
unsigned IOCTL_TIOCREMOTE = TIOCREMOTE;
unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
unsigned IOCTL_TIOCUCNTL = TIOCUCNTL;
unsigned IOCTL_TIOCSTAT = TIOCSTAT;
unsigned IOCTL_TIOCGSID = TIOCGSID;
unsigned IOCTL_TIOCCONS = TIOCCONS;
unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
unsigned IOCTL_TIOCEXT = TIOCEXT;
unsigned IOCTL_TIOCSIG = TIOCSIG;
unsigned IOCTL_TIOCDRAIN = TIOCDRAIN;
unsigned IOCTL_TIOCGFLAGS = TIOCGFLAGS;
unsigned IOCTL_TIOCSFLAGS = TIOCSFLAGS;
unsigned IOCTL_TIOCDCDTIMESTAMP = TIOCDCDTIMESTAMP;
unsigned IOCTL_TIOCRCVFRAME = TIOCRCVFRAME;
unsigned IOCTL_TIOCXMTFRAME = TIOCXMTFRAME;
unsigned IOCTL_TIOCPTMGET = TIOCPTMGET;
unsigned IOCTL_TIOCGRANTPT = TIOCGRANTPT;
unsigned IOCTL_TIOCPTSNAME = TIOCPTSNAME;
unsigned IOCTL_TIOCSQSIZE = TIOCSQSIZE;
unsigned IOCTL_TIOCGQSIZE = TIOCGQSIZE;
unsigned IOCTL_VERIEXEC_LOAD = VERIEXEC_LOAD;
unsigned IOCTL_VERIEXEC_TABLESIZE = VERIEXEC_TABLESIZE;
unsigned IOCTL_VERIEXEC_DELETE = VERIEXEC_DELETE;
unsigned IOCTL_VERIEXEC_QUERY = VERIEXEC_QUERY;
unsigned IOCTL_VERIEXEC_DUMP = VERIEXEC_DUMP;
unsigned IOCTL_VERIEXEC_FLUSH = VERIEXEC_FLUSH;
unsigned IOCTL_VIDIOC_QUERYCAP = VIDIOC_QUERYCAP;
unsigned IOCTL_VIDIOC_RESERVED = VIDIOC_RESERVED;
unsigned IOCTL_VIDIOC_ENUM_FMT = VIDIOC_ENUM_FMT;
unsigned IOCTL_VIDIOC_G_FMT = VIDIOC_G_FMT;
unsigned IOCTL_VIDIOC_S_FMT = VIDIOC_S_FMT;
unsigned IOCTL_VIDIOC_REQBUFS = VIDIOC_REQBUFS;
unsigned IOCTL_VIDIOC_QUERYBUF = VIDIOC_QUERYBUF;
unsigned IOCTL_VIDIOC_G_FBUF = VIDIOC_G_FBUF;
unsigned IOCTL_VIDIOC_S_FBUF = VIDIOC_S_FBUF;
unsigned IOCTL_VIDIOC_OVERLAY = VIDIOC_OVERLAY;
unsigned IOCTL_VIDIOC_QBUF = VIDIOC_QBUF;
unsigned IOCTL_VIDIOC_DQBUF = VIDIOC_DQBUF;
unsigned IOCTL_VIDIOC_STREAMON = VIDIOC_STREAMON;
unsigned IOCTL_VIDIOC_STREAMOFF = VIDIOC_STREAMOFF;
unsigned IOCTL_VIDIOC_G_PARM = VIDIOC_G_PARM;
unsigned IOCTL_VIDIOC_S_PARM = VIDIOC_S_PARM;
unsigned IOCTL_VIDIOC_G_STD = VIDIOC_G_STD;
unsigned IOCTL_VIDIOC_S_STD = VIDIOC_S_STD;
unsigned IOCTL_VIDIOC_ENUMSTD = VIDIOC_ENUMSTD;
unsigned IOCTL_VIDIOC_ENUMINPUT = VIDIOC_ENUMINPUT;
unsigned IOCTL_VIDIOC_G_CTRL = VIDIOC_G_CTRL;
unsigned IOCTL_VIDIOC_S_CTRL = VIDIOC_S_CTRL;
unsigned IOCTL_VIDIOC_G_TUNER = VIDIOC_G_TUNER;
unsigned IOCTL_VIDIOC_S_TUNER = VIDIOC_S_TUNER;
unsigned IOCTL_VIDIOC_G_AUDIO = VIDIOC_G_AUDIO;
unsigned IOCTL_VIDIOC_S_AUDIO = VIDIOC_S_AUDIO;
unsigned IOCTL_VIDIOC_QUERYCTRL = VIDIOC_QUERYCTRL;
unsigned IOCTL_VIDIOC_QUERYMENU = VIDIOC_QUERYMENU;
unsigned IOCTL_VIDIOC_G_INPUT = VIDIOC_G_INPUT;
unsigned IOCTL_VIDIOC_S_INPUT = VIDIOC_S_INPUT;
unsigned IOCTL_VIDIOC_G_OUTPUT = VIDIOC_G_OUTPUT;
unsigned IOCTL_VIDIOC_S_OUTPUT = VIDIOC_S_OUTPUT;
unsigned IOCTL_VIDIOC_ENUMOUTPUT = VIDIOC_ENUMOUTPUT;
unsigned IOCTL_VIDIOC_G_AUDOUT = VIDIOC_G_AUDOUT;
unsigned IOCTL_VIDIOC_S_AUDOUT = VIDIOC_S_AUDOUT;
unsigned IOCTL_VIDIOC_G_MODULATOR = VIDIOC_G_MODULATOR;
unsigned IOCTL_VIDIOC_S_MODULATOR = VIDIOC_S_MODULATOR;
unsigned IOCTL_VIDIOC_G_FREQUENCY = VIDIOC_G_FREQUENCY;
unsigned IOCTL_VIDIOC_S_FREQUENCY = VIDIOC_S_FREQUENCY;
unsigned IOCTL_VIDIOC_CROPCAP = VIDIOC_CROPCAP;
unsigned IOCTL_VIDIOC_G_CROP = VIDIOC_G_CROP;
unsigned IOCTL_VIDIOC_S_CROP = VIDIOC_S_CROP;
unsigned IOCTL_VIDIOC_G_JPEGCOMP = VIDIOC_G_JPEGCOMP;
unsigned IOCTL_VIDIOC_S_JPEGCOMP = VIDIOC_S_JPEGCOMP;
unsigned IOCTL_VIDIOC_QUERYSTD = VIDIOC_QUERYSTD;
unsigned IOCTL_VIDIOC_TRY_FMT = VIDIOC_TRY_FMT;
unsigned IOCTL_VIDIOC_ENUMAUDIO = VIDIOC_ENUMAUDIO;
unsigned IOCTL_VIDIOC_ENUMAUDOUT = VIDIOC_ENUMAUDOUT;
unsigned IOCTL_VIDIOC_G_PRIORITY = VIDIOC_G_PRIORITY;
unsigned IOCTL_VIDIOC_S_PRIORITY = VIDIOC_S_PRIORITY;
unsigned IOCTL_VIDIOC_ENUM_FRAMESIZES = VIDIOC_ENUM_FRAMESIZES;
unsigned IOCTL_VIDIOC_ENUM_FRAMEINTERVALS = VIDIOC_ENUM_FRAMEINTERVALS;
unsigned IOCTL_WDOGIOC_GMODE = WDOGIOC_GMODE;
unsigned IOCTL_WDOGIOC_SMODE = WDOGIOC_SMODE;
unsigned IOCTL_WDOGIOC_WHICH = WDOGIOC_WHICH;
unsigned IOCTL_WDOGIOC_TICKLE = WDOGIOC_TICKLE;
unsigned IOCTL_WDOGIOC_GTICKLER = WDOGIOC_GTICKLER;
unsigned IOCTL_WDOGIOC_GWDOGS = WDOGIOC_GWDOGS;
unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE;
unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS;
unsigned IOCTL_SNDCTL_DSP_CHANNELS = SNDCTL_DSP_CHANNELS;
unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS;
unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER;
unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER;
unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE;
unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
unsigned IOCTL_SNDCTL_DSP_GETCAPS = SNDCTL_DSP_GETCAPS;
unsigned IOCTL_SNDCTL_DSP_GETTRIGGER = SNDCTL_DSP_GETTRIGGER;
unsigned IOCTL_SNDCTL_DSP_SETTRIGGER = SNDCTL_DSP_SETTRIGGER;
unsigned IOCTL_SNDCTL_DSP_GETIPTR = SNDCTL_DSP_GETIPTR;
unsigned IOCTL_SNDCTL_DSP_GETOPTR = SNDCTL_DSP_GETOPTR;
unsigned IOCTL_SNDCTL_DSP_MAPINBUF = SNDCTL_DSP_MAPINBUF;
unsigned IOCTL_SNDCTL_DSP_MAPOUTBUF = SNDCTL_DSP_MAPOUTBUF;
unsigned IOCTL_SNDCTL_DSP_SETSYNCRO = SNDCTL_DSP_SETSYNCRO;
unsigned IOCTL_SNDCTL_DSP_SETDUPLEX = SNDCTL_DSP_SETDUPLEX;
unsigned IOCTL_SNDCTL_DSP_PROFILE = SNDCTL_DSP_PROFILE;
unsigned IOCTL_SNDCTL_DSP_GETODELAY = SNDCTL_DSP_GETODELAY;
unsigned IOCTL_SOUND_MIXER_INFO = SOUND_MIXER_INFO;
unsigned IOCTL_SOUND_OLD_MIXER_INFO = SOUND_OLD_MIXER_INFO;
unsigned IOCTL_OSS_GETVERSION = OSS_GETVERSION;
unsigned IOCTL_SNDCTL_SYSINFO = SNDCTL_SYSINFO;
unsigned IOCTL_SNDCTL_AUDIOINFO = SNDCTL_AUDIOINFO;
unsigned IOCTL_SNDCTL_ENGINEINFO = SNDCTL_ENGINEINFO;
unsigned IOCTL_SNDCTL_DSP_GETPLAYVOL = SNDCTL_DSP_GETPLAYVOL;
unsigned IOCTL_SNDCTL_DSP_SETPLAYVOL = SNDCTL_DSP_SETPLAYVOL;
unsigned IOCTL_SNDCTL_DSP_GETRECVOL = SNDCTL_DSP_GETRECVOL;
unsigned IOCTL_SNDCTL_DSP_SETRECVOL = SNDCTL_DSP_SETRECVOL;
unsigned IOCTL_SNDCTL_DSP_SKIP = SNDCTL_DSP_SKIP;
unsigned IOCTL_SNDCTL_DSP_SILENCE = SNDCTL_DSP_SILENCE;
const int si_SEGV_MAPERR = SEGV_MAPERR;
const int si_SEGV_ACCERR = SEGV_ACCERR;
const int modctl_load = MODCTL_LOAD;
const int modctl_unload = MODCTL_UNLOAD;
const int modctl_stat = MODCTL_STAT;
const int modctl_exists = MODCTL_EXISTS;
const unsigned SHA1_CTX_sz = sizeof(SHA1_CTX);
const unsigned SHA1_return_length = SHA1_DIGEST_STRING_LENGTH;
const unsigned MD4_CTX_sz = sizeof(MD4_CTX);
const unsigned MD4_return_length = MD4_DIGEST_STRING_LENGTH;
const unsigned RMD160_CTX_sz = sizeof(RMD160_CTX);
const unsigned RMD160_return_length = RMD160_DIGEST_STRING_LENGTH;
const unsigned MD5_CTX_sz = sizeof(MD5_CTX);
const unsigned MD5_return_length = MD5_DIGEST_STRING_LENGTH;
const unsigned fpos_t_sz = sizeof(fpos_t);
const unsigned MD2_CTX_sz = sizeof(MD2_CTX);
const unsigned MD2_return_length = MD2_DIGEST_STRING_LENGTH;
#define SHA2_CONST(LEN) \
const unsigned SHA##LEN##_CTX_sz = sizeof(SHA##LEN##_CTX); \
const unsigned SHA##LEN##_return_length = SHA##LEN##_DIGEST_STRING_LENGTH; \
const unsigned SHA##LEN##_block_length = SHA##LEN##_BLOCK_LENGTH; \
const unsigned SHA##LEN##_digest_length = SHA##LEN##_DIGEST_LENGTH
SHA2_CONST(224);
SHA2_CONST(256);
SHA2_CONST(384);
SHA2_CONST(512);
#undef SHA2_CONST
const int unvis_valid = UNVIS_VALID;
const int unvis_validpush = UNVIS_VALIDPUSH;
} // namespace __sanitizer
using namespace __sanitizer;
COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned));
CHECK_TYPE_SIZE(pthread_key_t);
// There are more undocumented fields in dl_phdr_info that we are not interested
// in.
COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info));
CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr);
CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name);
CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
CHECK_TYPE_SIZE(glob_t);
CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
CHECK_SIZE_AND_OFFSET(glob_t, gl_offs);
CHECK_SIZE_AND_OFFSET(glob_t, gl_flags);
CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir);
CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
CHECK_TYPE_SIZE(addrinfo);
CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
CHECK_SIZE_AND_OFFSET(addrinfo, ai_family);
CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype);
CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen);
CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname);
CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr);
CHECK_TYPE_SIZE(hostent);
CHECK_SIZE_AND_OFFSET(hostent, h_name);
CHECK_SIZE_AND_OFFSET(hostent, h_aliases);
CHECK_SIZE_AND_OFFSET(hostent, h_addrtype);
CHECK_SIZE_AND_OFFSET(hostent, h_length);
CHECK_SIZE_AND_OFFSET(hostent, h_addr_list);
CHECK_TYPE_SIZE(iovec);
CHECK_SIZE_AND_OFFSET(iovec, iov_base);
CHECK_SIZE_AND_OFFSET(iovec, iov_len);
CHECK_TYPE_SIZE(msghdr);
CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
CHECK_TYPE_SIZE(cmsghdr);
CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent));
CHECK_SIZE_AND_OFFSET(dirent, d_fileno);
CHECK_SIZE_AND_OFFSET(dirent, d_reclen);
CHECK_TYPE_SIZE(ifconf);
CHECK_SIZE_AND_OFFSET(ifconf, ifc_len);
CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu);
CHECK_TYPE_SIZE(pollfd);
CHECK_SIZE_AND_OFFSET(pollfd, fd);
CHECK_SIZE_AND_OFFSET(pollfd, events);
CHECK_SIZE_AND_OFFSET(pollfd, revents);
CHECK_TYPE_SIZE(nfds_t);
CHECK_TYPE_SIZE(sigset_t);
COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction));
// Can't write checks for sa_handler and sa_sigaction due to them being
// preprocessor macros.
CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask);
CHECK_TYPE_SIZE(wordexp_t);
CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc);
CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv);
CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs);
COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE));
CHECK_SIZE_AND_OFFSET(FILE, _p);
CHECK_SIZE_AND_OFFSET(FILE, _r);
CHECK_SIZE_AND_OFFSET(FILE, _w);
CHECK_SIZE_AND_OFFSET(FILE, _flags);
CHECK_SIZE_AND_OFFSET(FILE, _file);
CHECK_SIZE_AND_OFFSET(FILE, _bf);
CHECK_SIZE_AND_OFFSET(FILE, _lbfsize);
CHECK_SIZE_AND_OFFSET(FILE, _cookie);
CHECK_SIZE_AND_OFFSET(FILE, _close);
CHECK_SIZE_AND_OFFSET(FILE, _read);
CHECK_SIZE_AND_OFFSET(FILE, _seek);
CHECK_SIZE_AND_OFFSET(FILE, _write);
CHECK_SIZE_AND_OFFSET(FILE, _ext);
CHECK_SIZE_AND_OFFSET(FILE, _up);
CHECK_SIZE_AND_OFFSET(FILE, _ur);
CHECK_SIZE_AND_OFFSET(FILE, _ubuf);
CHECK_SIZE_AND_OFFSET(FILE, _nbuf);
CHECK_SIZE_AND_OFFSET(FILE, _flush);
CHECK_SIZE_AND_OFFSET(FILE, _lb_unused);
CHECK_SIZE_AND_OFFSET(FILE, _blksize);
CHECK_SIZE_AND_OFFSET(FILE, _offset);
CHECK_TYPE_SIZE(tm);
CHECK_SIZE_AND_OFFSET(tm, tm_sec);
CHECK_SIZE_AND_OFFSET(tm, tm_min);
CHECK_SIZE_AND_OFFSET(tm, tm_hour);
CHECK_SIZE_AND_OFFSET(tm, tm_mday);
CHECK_SIZE_AND_OFFSET(tm, tm_mon);
CHECK_SIZE_AND_OFFSET(tm, tm_year);
CHECK_SIZE_AND_OFFSET(tm, tm_wday);
CHECK_SIZE_AND_OFFSET(tm, tm_yday);
CHECK_SIZE_AND_OFFSET(tm, tm_isdst);
CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff);
CHECK_SIZE_AND_OFFSET(tm, tm_zone);
CHECK_TYPE_SIZE(ether_addr);
CHECK_TYPE_SIZE(ipc_perm);
CHECK_SIZE_AND_OFFSET(ipc_perm, _key);
CHECK_SIZE_AND_OFFSET(ipc_perm, _seq);
CHECK_SIZE_AND_OFFSET(ipc_perm, uid);
CHECK_SIZE_AND_OFFSET(ipc_perm, gid);
CHECK_SIZE_AND_OFFSET(ipc_perm, cuid);
CHECK_SIZE_AND_OFFSET(ipc_perm, cgid);
CHECK_SIZE_AND_OFFSET(ipc_perm, mode);
CHECK_TYPE_SIZE(shmid_ds);
CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm);
CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz);
CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime);
CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime);
CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime);
CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid);
CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid);
CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch);
CHECK_TYPE_SIZE(clock_t);
CHECK_TYPE_SIZE(ifaddrs);
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next);
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name);
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr);
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask);
// Compare against the union, because we can't reach into the union in a
// compliant way.
#ifdef ifa_dstaddr
#undef ifa_dstaddr
#endif
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
CHECK_TYPE_SIZE(timeb);
CHECK_SIZE_AND_OFFSET(timeb, time);
CHECK_SIZE_AND_OFFSET(timeb, millitm);
CHECK_SIZE_AND_OFFSET(timeb, timezone);
CHECK_SIZE_AND_OFFSET(timeb, dstflag);
CHECK_TYPE_SIZE(passwd);
CHECK_SIZE_AND_OFFSET(passwd, pw_name);
CHECK_SIZE_AND_OFFSET(passwd, pw_passwd);
CHECK_SIZE_AND_OFFSET(passwd, pw_uid);
CHECK_SIZE_AND_OFFSET(passwd, pw_gid);
CHECK_SIZE_AND_OFFSET(passwd, pw_dir);
CHECK_SIZE_AND_OFFSET(passwd, pw_shell);
CHECK_SIZE_AND_OFFSET(passwd, pw_gecos);
CHECK_TYPE_SIZE(group);
CHECK_SIZE_AND_OFFSET(group, gr_name);
CHECK_SIZE_AND_OFFSET(group, gr_passwd);
CHECK_SIZE_AND_OFFSET(group, gr_gid);
CHECK_SIZE_AND_OFFSET(group, gr_mem);
CHECK_TYPE_SIZE(modctl_load_t);
CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_filename);
CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_flags);
CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_props);
CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_propslen);
#endif // SANITIZER_NETBSD
Index: stable/11/contrib/libunwind/src/DwarfInstructions.hpp
===================================================================
--- stable/11/contrib/libunwind/src/DwarfInstructions.hpp (revision 350258)
+++ stable/11/contrib/libunwind/src/DwarfInstructions.hpp (revision 350259)
@@ -1,795 +1,820 @@
//===-------------------------- DwarfInstructions.hpp ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//
// Processor specific interpretation of DWARF unwind info.
//
//===----------------------------------------------------------------------===//
#ifndef __DWARF_INSTRUCTIONS_HPP__
#define __DWARF_INSTRUCTIONS_HPP__
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "dwarf2.h"
#include "Registers.hpp"
#include "DwarfParser.hpp"
#include "config.h"
namespace libunwind {
/// DwarfInstructions maps abtract DWARF unwind instructions to a particular
/// architecture
template <typename A, typename R>
class DwarfInstructions {
public:
typedef typename A::pint_t pint_t;
typedef typename A::sint_t sint_t;
static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
R &registers);
private:
enum {
DW_X86_64_RET_ADDR = 16
};
enum {
DW_X86_RET_ADDR = 8
};
typedef typename CFI_Parser<A>::RegisterLocation RegisterLocation;
typedef typename CFI_Parser<A>::PrologInfo PrologInfo;
typedef typename CFI_Parser<A>::FDE_Info FDE_Info;
typedef typename CFI_Parser<A>::CIE_Info CIE_Info;
static pint_t evaluateExpression(pint_t expression, A &addressSpace,
const R &registers,
pint_t initialStackValue);
static pint_t getSavedRegister(A &addressSpace, const R &registers,
pint_t cfa, const RegisterLocation &savedReg);
static double getSavedFloatRegister(A &addressSpace, const R &registers,
pint_t cfa, const RegisterLocation &savedReg);
static v128 getSavedVectorRegister(A &addressSpace, const R &registers,
pint_t cfa, const RegisterLocation &savedReg);
static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
const R &registers) {
if (prolog.cfaRegister != 0)
return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) +
prolog.cfaRegisterOffset);
if (prolog.cfaExpression != 0)
return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
registers, 0);
assert(0 && "getCFA(): unknown location");
__builtin_unreachable();
}
};
template <typename A, typename R>
typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
A &addressSpace, const R &registers, pint_t cfa,
const RegisterLocation &savedReg) {
switch (savedReg.location) {
case CFI_Parser<A>::kRegisterInCFA:
return addressSpace.getRegister(cfa + (pint_t)savedReg.value);
case CFI_Parser<A>::kRegisterAtExpression:
return addressSpace.getRegister(
evaluateExpression((pint_t)savedReg.value, addressSpace,
registers, cfa));
case CFI_Parser<A>::kRegisterIsExpression:
return evaluateExpression((pint_t)savedReg.value, addressSpace,
registers, cfa);
case CFI_Parser<A>::kRegisterInRegister:
return registers.getRegister((int)savedReg.value);
case CFI_Parser<A>::kRegisterUnused:
case CFI_Parser<A>::kRegisterOffsetFromCFA:
// FIX ME
break;
}
_LIBUNWIND_ABORT("unsupported restore location for register");
}
template <typename A, typename R>
double DwarfInstructions<A, R>::getSavedFloatRegister(
A &addressSpace, const R &registers, pint_t cfa,
const RegisterLocation &savedReg) {
switch (savedReg.location) {
case CFI_Parser<A>::kRegisterInCFA:
return addressSpace.getDouble(cfa + (pint_t)savedReg.value);
case CFI_Parser<A>::kRegisterAtExpression:
return addressSpace.getDouble(
evaluateExpression((pint_t)savedReg.value, addressSpace,
registers, cfa));
case CFI_Parser<A>::kRegisterIsExpression:
case CFI_Parser<A>::kRegisterUnused:
case CFI_Parser<A>::kRegisterOffsetFromCFA:
case CFI_Parser<A>::kRegisterInRegister:
// FIX ME
break;
}
_LIBUNWIND_ABORT("unsupported restore location for float register");
}
template <typename A, typename R>
v128 DwarfInstructions<A, R>::getSavedVectorRegister(
A &addressSpace, const R &registers, pint_t cfa,
const RegisterLocation &savedReg) {
switch (savedReg.location) {
case CFI_Parser<A>::kRegisterInCFA:
return addressSpace.getVector(cfa + (pint_t)savedReg.value);
case CFI_Parser<A>::kRegisterAtExpression:
return addressSpace.getVector(
evaluateExpression((pint_t)savedReg.value, addressSpace,
registers, cfa));
case CFI_Parser<A>::kRegisterIsExpression:
case CFI_Parser<A>::kRegisterUnused:
case CFI_Parser<A>::kRegisterOffsetFromCFA:
case CFI_Parser<A>::kRegisterInRegister:
// FIX ME
break;
}
_LIBUNWIND_ABORT("unsupported restore location for vector register");
}
template <typename A, typename R>
int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
pint_t fdeStart, R &registers) {
FDE_Info fdeInfo;
CIE_Info cieInfo;
if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo,
&cieInfo) == NULL) {
PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
R::getArch(), &prolog)) {
// get pointer to cfa (architecture specific)
pint_t cfa = getCFA(addressSpace, prolog, registers);
// restore registers that DWARF says were saved
R newRegisters = registers;
pint_t returnAddress = 0;
const int lastReg = R::lastDwarfRegNum();
assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= lastReg &&
"register range too large");
assert(lastReg >= (int)cieInfo.returnAddressRegister &&
"register range does not contain return address register");
for (int i = 0; i <= lastReg; ++i) {
if (prolog.savedRegisters[i].location !=
CFI_Parser<A>::kRegisterUnused) {
if (registers.validFloatRegister(i))
newRegisters.setFloatRegister(
i, getSavedFloatRegister(addressSpace, registers, cfa,
prolog.savedRegisters[i]));
else if (registers.validVectorRegister(i))
newRegisters.setVectorRegister(
i, getSavedVectorRegister(addressSpace, registers, cfa,
prolog.savedRegisters[i]));
else if (i == (int)cieInfo.returnAddressRegister)
returnAddress = getSavedRegister(addressSpace, registers, cfa,
prolog.savedRegisters[i]);
else if (registers.validRegister(i))
newRegisters.setRegister(
i, getSavedRegister(addressSpace, registers, cfa,
prolog.savedRegisters[i]));
else
return UNW_EBADREG;
}
}
// By definition, the CFA is the stack pointer at the call site, so
// restoring SP means setting it to CFA.
newRegisters.setSP(cfa);
#if defined(_LIBUNWIND_TARGET_AARCH64)
// If the target is aarch64 then the return address may have been signed
// using the v8.3 pointer authentication extensions. The original
// return address needs to be authenticated before the return address is
// restored. autia1716 is used instead of autia as autia1716 assembles
// to a NOP on pre-v8.3a architectures.
if ((R::getArch() == REGISTERS_ARM64) &&
prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value) {
#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
return UNW_ECROSSRASIGNING;
#else
register unsigned long long x17 __asm("x17") = returnAddress;
register unsigned long long x16 __asm("x16") = cfa;
// These are the autia1716/autib1716 instructions. The hint instructions
// are used here as gcc does not assemble autia1716/autib1716 for pre
// armv8.3a targets.
if (cieInfo.addressesSignedWithBKey)
asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
else
asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
returnAddress = x17;
#endif
}
#endif
#if defined(_LIBUNWIND_TARGET_SPARC)
if (R::getArch() == REGISTERS_SPARC) {
// Skip call site instruction and delay slot
returnAddress += 8;
// Skip unimp instruction if function returns a struct
if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0)
returnAddress += 4;
}
#endif
+#if defined(_LIBUNWIND_TARGET_PPC64)
+#define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1)
+#define PPC64_ELFV1_R2_OFFSET 40
+#define PPC64_ELFV2_R2_LOAD_INST_ENCODING 0xe8410018u // ld r2,24(r1)
+#define PPC64_ELFV2_R2_OFFSET 24
+ // If the instruction at return address is a TOC (r2) restore,
+ // then r2 was saved and needs to be restored.
+ // ELFv2 ABI specifies that the TOC Pointer must be saved at SP + 24,
+ // while in ELFv1 ABI it is saved at SP + 40.
+ if (R::getArch() == REGISTERS_PPC64 && returnAddress != 0) {
+ pint_t sp = newRegisters.getRegister(UNW_REG_SP);
+ pint_t r2 = 0;
+ switch (addressSpace.get32(returnAddress)) {
+ case PPC64_ELFV1_R2_LOAD_INST_ENCODING:
+ r2 = addressSpace.get64(sp + PPC64_ELFV1_R2_OFFSET);
+ break;
+ case PPC64_ELFV2_R2_LOAD_INST_ENCODING:
+ r2 = addressSpace.get64(sp + PPC64_ELFV2_R2_OFFSET);
+ break;
+ }
+ if (r2)
+ newRegisters.setRegister(UNW_PPC64_R2, r2);
+ }
+#endif
+
// Return address is address after call site instruction, so setting IP to
// that does simualates a return.
newRegisters.setIP(returnAddress);
// Simulate the step by replacing the register set with the new ones.
registers = newRegisters;
return UNW_STEP_SUCCESS;
}
}
return UNW_EBADFRAME;
}
template <typename A, typename R>
typename A::pint_t
DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
const R &registers,
pint_t initialStackValue) {
const bool log = false;
pint_t p = expression;
pint_t expressionEnd = expression + 20; // temp, until len read
pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd);
expressionEnd = p + length;
if (log)
fprintf(stderr, "evaluateExpression(): length=%" PRIu64 "\n",
(uint64_t)length);
pint_t stack[100];
pint_t *sp = stack;
*(++sp) = initialStackValue;
while (p < expressionEnd) {
if (log) {
for (pint_t *t = sp; t > stack; --t) {
fprintf(stderr, "sp[] = 0x%" PRIx64 "\n", (uint64_t)(*t));
}
}
uint8_t opcode = addressSpace.get8(p++);
sint_t svalue, svalue2;
pint_t value;
uint32_t reg;
switch (opcode) {
case DW_OP_addr:
// push immediate address sized value
value = addressSpace.getP(p);
p += sizeof(pint_t);
*(++sp) = value;
if (log)
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
break;
case DW_OP_deref:
// pop stack, dereference, push result
value = *sp--;
*(++sp) = addressSpace.getP(value);
if (log)
fprintf(stderr, "dereference 0x%" PRIx64 "\n", (uint64_t)value);
break;
case DW_OP_const1u:
// push immediate 1 byte value
value = addressSpace.get8(p);
p += 1;
*(++sp) = value;
if (log)
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
break;
case DW_OP_const1s:
// push immediate 1 byte signed value
svalue = (int8_t) addressSpace.get8(p);
p += 1;
*(++sp) = (pint_t)svalue;
if (log)
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
break;
case DW_OP_const2u:
// push immediate 2 byte value
value = addressSpace.get16(p);
p += 2;
*(++sp) = value;
if (log)
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
break;
case DW_OP_const2s:
// push immediate 2 byte signed value
svalue = (int16_t) addressSpace.get16(p);
p += 2;
*(++sp) = (pint_t)svalue;
if (log)
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
break;
case DW_OP_const4u:
// push immediate 4 byte value
value = addressSpace.get32(p);
p += 4;
*(++sp) = value;
if (log)
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
break;
case DW_OP_const4s:
// push immediate 4 byte signed value
svalue = (int32_t)addressSpace.get32(p);
p += 4;
*(++sp) = (pint_t)svalue;
if (log)
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
break;
case DW_OP_const8u:
// push immediate 8 byte value
value = (pint_t)addressSpace.get64(p);
p += 8;
*(++sp) = value;
if (log)
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
break;
case DW_OP_const8s:
// push immediate 8 byte signed value
value = (pint_t)addressSpace.get64(p);
p += 8;
*(++sp) = value;
if (log)
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
break;
case DW_OP_constu:
// push immediate ULEB128 value
value = (pint_t)addressSpace.getULEB128(p, expressionEnd);
*(++sp) = value;
if (log)
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
break;
case DW_OP_consts:
// push immediate SLEB128 value
svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
*(++sp) = (pint_t)svalue;
if (log)
fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
break;
case DW_OP_dup:
// push top of stack
value = *sp;
*(++sp) = value;
if (log)
fprintf(stderr, "duplicate top of stack\n");
break;
case DW_OP_drop:
// pop
--sp;
if (log)
fprintf(stderr, "pop top of stack\n");
break;
case DW_OP_over:
// dup second
value = sp[-1];
*(++sp) = value;
if (log)
fprintf(stderr, "duplicate second in stack\n");
break;
case DW_OP_pick:
// pick from
reg = addressSpace.get8(p);
p += 1;
value = sp[-reg];
*(++sp) = value;
if (log)
fprintf(stderr, "duplicate %d in stack\n", reg);
break;
case DW_OP_swap:
// swap top two
value = sp[0];
sp[0] = sp[-1];
sp[-1] = value;
if (log)
fprintf(stderr, "swap top of stack\n");
break;
case DW_OP_rot:
// rotate top three
value = sp[0];
sp[0] = sp[-1];
sp[-1] = sp[-2];
sp[-2] = value;
if (log)
fprintf(stderr, "rotate top three of stack\n");
break;
case DW_OP_xderef:
// pop stack, dereference, push result
value = *sp--;
*sp = *((pint_t*)value);
if (log)
fprintf(stderr, "x-dereference 0x%" PRIx64 "\n", (uint64_t)value);
break;
case DW_OP_abs:
svalue = (sint_t)*sp;
if (svalue < 0)
*sp = (pint_t)(-svalue);
if (log)
fprintf(stderr, "abs\n");
break;
case DW_OP_and:
value = *sp--;
*sp &= value;
if (log)
fprintf(stderr, "and\n");
break;
case DW_OP_div:
svalue = (sint_t)(*sp--);
svalue2 = (sint_t)*sp;
*sp = (pint_t)(svalue2 / svalue);
if (log)
fprintf(stderr, "div\n");
break;
case DW_OP_minus:
value = *sp--;
*sp = *sp - value;
if (log)
fprintf(stderr, "minus\n");
break;
case DW_OP_mod:
svalue = (sint_t)(*sp--);
svalue2 = (sint_t)*sp;
*sp = (pint_t)(svalue2 % svalue);
if (log)
fprintf(stderr, "module\n");
break;
case DW_OP_mul:
svalue = (sint_t)(*sp--);
svalue2 = (sint_t)*sp;
*sp = (pint_t)(svalue2 * svalue);
if (log)
fprintf(stderr, "mul\n");
break;
case DW_OP_neg:
*sp = 0 - *sp;
if (log)
fprintf(stderr, "neg\n");
break;
case DW_OP_not:
svalue = (sint_t)(*sp);
*sp = (pint_t)(~svalue);
if (log)
fprintf(stderr, "not\n");
break;
case DW_OP_or:
value = *sp--;
*sp |= value;
if (log)
fprintf(stderr, "or\n");
break;
case DW_OP_plus:
value = *sp--;
*sp += value;
if (log)
fprintf(stderr, "plus\n");
break;
case DW_OP_plus_uconst:
// pop stack, add uelb128 constant, push result
*sp += static_cast<pint_t>(addressSpace.getULEB128(p, expressionEnd));
if (log)
fprintf(stderr, "add constant\n");
break;
case DW_OP_shl:
value = *sp--;
*sp = *sp << value;
if (log)
fprintf(stderr, "shift left\n");
break;
case DW_OP_shr:
value = *sp--;
*sp = *sp >> value;
if (log)
fprintf(stderr, "shift left\n");
break;
case DW_OP_shra:
value = *sp--;
svalue = (sint_t)*sp;
*sp = (pint_t)(svalue >> value);
if (log)
fprintf(stderr, "shift left arithmetric\n");
break;
case DW_OP_xor:
value = *sp--;
*sp ^= value;
if (log)
fprintf(stderr, "xor\n");
break;
case DW_OP_skip:
svalue = (int16_t) addressSpace.get16(p);
p += 2;
p = (pint_t)((sint_t)p + svalue);
if (log)
fprintf(stderr, "skip %" PRIu64 "\n", (uint64_t)svalue);
break;
case DW_OP_bra:
svalue = (int16_t) addressSpace.get16(p);
p += 2;
if (*sp--)
p = (pint_t)((sint_t)p + svalue);
if (log)
fprintf(stderr, "bra %" PRIu64 "\n", (uint64_t)svalue);
break;
case DW_OP_eq:
value = *sp--;
*sp = (*sp == value);
if (log)
fprintf(stderr, "eq\n");
break;
case DW_OP_ge:
value = *sp--;
*sp = (*sp >= value);
if (log)
fprintf(stderr, "ge\n");
break;
case DW_OP_gt:
value = *sp--;
*sp = (*sp > value);
if (log)
fprintf(stderr, "gt\n");
break;
case DW_OP_le:
value = *sp--;
*sp = (*sp <= value);
if (log)
fprintf(stderr, "le\n");
break;
case DW_OP_lt:
value = *sp--;
*sp = (*sp < value);
if (log)
fprintf(stderr, "lt\n");
break;
case DW_OP_ne:
value = *sp--;
*sp = (*sp != value);
if (log)
fprintf(stderr, "ne\n");
break;
case DW_OP_lit0:
case DW_OP_lit1:
case DW_OP_lit2:
case DW_OP_lit3:
case DW_OP_lit4:
case DW_OP_lit5:
case DW_OP_lit6:
case DW_OP_lit7:
case DW_OP_lit8:
case DW_OP_lit9:
case DW_OP_lit10:
case DW_OP_lit11:
case DW_OP_lit12:
case DW_OP_lit13:
case DW_OP_lit14:
case DW_OP_lit15:
case DW_OP_lit16:
case DW_OP_lit17:
case DW_OP_lit18:
case DW_OP_lit19:
case DW_OP_lit20:
case DW_OP_lit21:
case DW_OP_lit22:
case DW_OP_lit23:
case DW_OP_lit24:
case DW_OP_lit25:
case DW_OP_lit26:
case DW_OP_lit27:
case DW_OP_lit28:
case DW_OP_lit29:
case DW_OP_lit30:
case DW_OP_lit31:
value = static_cast<pint_t>(opcode - DW_OP_lit0);
*(++sp) = value;
if (log)
fprintf(stderr, "push literal 0x%" PRIx64 "\n", (uint64_t)value);
break;
case DW_OP_reg0:
case DW_OP_reg1:
case DW_OP_reg2:
case DW_OP_reg3:
case DW_OP_reg4:
case DW_OP_reg5:
case DW_OP_reg6:
case DW_OP_reg7:
case DW_OP_reg8:
case DW_OP_reg9:
case DW_OP_reg10:
case DW_OP_reg11:
case DW_OP_reg12:
case DW_OP_reg13:
case DW_OP_reg14:
case DW_OP_reg15:
case DW_OP_reg16:
case DW_OP_reg17:
case DW_OP_reg18:
case DW_OP_reg19:
case DW_OP_reg20:
case DW_OP_reg21:
case DW_OP_reg22:
case DW_OP_reg23:
case DW_OP_reg24:
case DW_OP_reg25:
case DW_OP_reg26:
case DW_OP_reg27:
case DW_OP_reg28:
case DW_OP_reg29:
case DW_OP_reg30:
case DW_OP_reg31:
reg = static_cast<uint32_t>(opcode - DW_OP_reg0);
*(++sp) = registers.getRegister((int)reg);
if (log)
fprintf(stderr, "push reg %d\n", reg);
break;
case DW_OP_regx:
reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd));
*(++sp) = registers.getRegister((int)reg);
if (log)
fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
break;
case DW_OP_breg0:
case DW_OP_breg1:
case DW_OP_breg2:
case DW_OP_breg3:
case DW_OP_breg4:
case DW_OP_breg5:
case DW_OP_breg6:
case DW_OP_breg7:
case DW_OP_breg8:
case DW_OP_breg9:
case DW_OP_breg10:
case DW_OP_breg11:
case DW_OP_breg12:
case DW_OP_breg13:
case DW_OP_breg14:
case DW_OP_breg15:
case DW_OP_breg16:
case DW_OP_breg17:
case DW_OP_breg18:
case DW_OP_breg19:
case DW_OP_breg20:
case DW_OP_breg21:
case DW_OP_breg22:
case DW_OP_breg23:
case DW_OP_breg24:
case DW_OP_breg25:
case DW_OP_breg26:
case DW_OP_breg27:
case DW_OP_breg28:
case DW_OP_breg29:
case DW_OP_breg30:
case DW_OP_breg31:
reg = static_cast<uint32_t>(opcode - DW_OP_breg0);
svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
svalue += static_cast<sint_t>(registers.getRegister((int)reg));
*(++sp) = (pint_t)(svalue);
if (log)
fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
break;
case DW_OP_bregx:
reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd));
svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
svalue += static_cast<sint_t>(registers.getRegister((int)reg));
*(++sp) = (pint_t)(svalue);
if (log)
fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
break;
case DW_OP_fbreg:
_LIBUNWIND_ABORT("DW_OP_fbreg not implemented");
break;
case DW_OP_piece:
_LIBUNWIND_ABORT("DW_OP_piece not implemented");
break;
case DW_OP_deref_size:
// pop stack, dereference, push result
value = *sp--;
switch (addressSpace.get8(p++)) {
case 1:
value = addressSpace.get8(value);
break;
case 2:
value = addressSpace.get16(value);
break;
case 4:
value = addressSpace.get32(value);
break;
case 8:
value = (pint_t)addressSpace.get64(value);
break;
default:
_LIBUNWIND_ABORT("DW_OP_deref_size with bad size");
}
*(++sp) = value;
if (log)
fprintf(stderr, "sized dereference 0x%" PRIx64 "\n", (uint64_t)value);
break;
case DW_OP_xderef_size:
case DW_OP_nop:
case DW_OP_push_object_addres:
case DW_OP_call2:
case DW_OP_call4:
case DW_OP_call_ref:
default:
_LIBUNWIND_ABORT("DWARF opcode not implemented");
}
}
if (log)
fprintf(stderr, "expression evaluates to 0x%" PRIx64 "\n", (uint64_t)*sp);
return *sp;
}
} // namespace libunwind
#endif // __DWARF_INSTRUCTIONS_HPP__
Index: stable/11/contrib/libunwind/src/UnwindRegistersRestore.S
===================================================================
--- stable/11/contrib/libunwind/src/UnwindRegistersRestore.S (revision 350258)
+++ stable/11/contrib/libunwind/src/UnwindRegistersRestore.S (revision 350259)
@@ -1,1111 +1,1111 @@
//===-------------------- UnwindRegistersRestore.S ------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "assembly.h"
.text
#if !defined(__USING_SJLJ_EXCEPTIONS__)
#if defined(__i386__)
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
#
# void libunwind::Registers_x86::jumpto()
#
#if defined(_WIN32)
# On windows, the 'this' pointer is passed in ecx instead of on the stack
movl %ecx, %eax
#else
# On entry:
# + +
# +-----------------------+
# + thread_state pointer +
# +-----------------------+
# + return address +
# +-----------------------+ <-- SP
# + +
movl 4(%esp), %eax
#endif
# set up eax and ret on new stack location
movl 28(%eax), %edx # edx holds new stack pointer
subl $8,%edx
movl %edx, 28(%eax)
movl 0(%eax), %ebx
movl %ebx, 0(%edx)
movl 40(%eax), %ebx
movl %ebx, 4(%edx)
# we now have ret and eax pushed onto where new stack will be
# restore all registers
movl 4(%eax), %ebx
movl 8(%eax), %ecx
movl 12(%eax), %edx
movl 16(%eax), %edi
movl 20(%eax), %esi
movl 24(%eax), %ebp
movl 28(%eax), %esp
# skip ss
# skip eflags
pop %eax # eax was already pushed on new stack
ret # eip was already pushed on new stack
# skip cs
# skip ds
# skip es
# skip fs
# skip gs
#elif defined(__x86_64__)
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv)
#
# void libunwind::Registers_x86_64::jumpto()
#
#if defined(_WIN64)
# On entry, thread_state pointer is in rcx; move it into rdi
# to share restore code below. Since this routine restores and
# overwrites all registers, we can use the same registers for
# pointers and temporaries as on unix even though win64 normally
# mustn't clobber some of them.
movq %rcx, %rdi
#else
# On entry, thread_state pointer is in rdi
#endif
movq 56(%rdi), %rax # rax holds new stack pointer
subq $16, %rax
movq %rax, 56(%rdi)
movq 32(%rdi), %rbx # store new rdi on new stack
movq %rbx, 0(%rax)
movq 128(%rdi), %rbx # store new rip on new stack
movq %rbx, 8(%rax)
# restore all registers
movq 0(%rdi), %rax
movq 8(%rdi), %rbx
movq 16(%rdi), %rcx
movq 24(%rdi), %rdx
# restore rdi later
movq 40(%rdi), %rsi
movq 48(%rdi), %rbp
# restore rsp later
movq 64(%rdi), %r8
movq 72(%rdi), %r9
movq 80(%rdi), %r10
movq 88(%rdi), %r11
movq 96(%rdi), %r12
movq 104(%rdi), %r13
movq 112(%rdi), %r14
movq 120(%rdi), %r15
# skip rflags
# skip cs
# skip fs
# skip gs
#if defined(_WIN64)
movdqu 176(%rdi),%xmm0
movdqu 192(%rdi),%xmm1
movdqu 208(%rdi),%xmm2
movdqu 224(%rdi),%xmm3
movdqu 240(%rdi),%xmm4
movdqu 256(%rdi),%xmm5
movdqu 272(%rdi),%xmm6
movdqu 288(%rdi),%xmm7
movdqu 304(%rdi),%xmm8
movdqu 320(%rdi),%xmm9
movdqu 336(%rdi),%xmm10
movdqu 352(%rdi),%xmm11
movdqu 368(%rdi),%xmm12
movdqu 384(%rdi),%xmm13
movdqu 400(%rdi),%xmm14
movdqu 416(%rdi),%xmm15
#endif
movq 56(%rdi), %rsp # cut back rsp to new location
pop %rdi # rdi was saved here earlier
ret # rip was saved here
#elif defined(__powerpc64__)
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv)
//
// void libunwind::Registers_ppc64::jumpto()
//
// On entry:
// thread_state pointer is in r3
//
// load register (GPR)
#define PPC64_LR(n) \
ld %r##n, (8 * (n + 2))(%r3)
// restore integral registers
// skip r0 for now
// skip r1 for now
PPC64_LR(2)
// skip r3 for now
// skip r4 for now
// skip r5 for now
PPC64_LR(6)
PPC64_LR(7)
PPC64_LR(8)
PPC64_LR(9)
PPC64_LR(10)
PPC64_LR(11)
PPC64_LR(12)
PPC64_LR(13)
PPC64_LR(14)
PPC64_LR(15)
PPC64_LR(16)
PPC64_LR(17)
PPC64_LR(18)
PPC64_LR(19)
PPC64_LR(20)
PPC64_LR(21)
PPC64_LR(22)
PPC64_LR(23)
PPC64_LR(24)
PPC64_LR(25)
PPC64_LR(26)
PPC64_LR(27)
PPC64_LR(28)
PPC64_LR(29)
PPC64_LR(30)
PPC64_LR(31)
#ifdef PPC64_HAS_VMX
// restore VS registers
// (note that this also restores floating point registers and V registers,
// because part of VS is mapped to these registers)
addi %r4, %r3, PPC64_OFFS_FP
// load VS register
#define PPC64_LVS(n) \
lxvd2x %vs##n, 0, %r4 ;\
addi %r4, %r4, 16
// restore the first 32 VS regs (and also all floating point regs)
PPC64_LVS(0)
PPC64_LVS(1)
PPC64_LVS(2)
PPC64_LVS(3)
PPC64_LVS(4)
PPC64_LVS(5)
PPC64_LVS(6)
PPC64_LVS(7)
PPC64_LVS(8)
PPC64_LVS(9)
PPC64_LVS(10)
PPC64_LVS(11)
PPC64_LVS(12)
PPC64_LVS(13)
PPC64_LVS(14)
PPC64_LVS(15)
PPC64_LVS(16)
PPC64_LVS(17)
PPC64_LVS(18)
PPC64_LVS(19)
PPC64_LVS(20)
PPC64_LVS(21)
PPC64_LVS(22)
PPC64_LVS(23)
PPC64_LVS(24)
PPC64_LVS(25)
PPC64_LVS(26)
PPC64_LVS(27)
PPC64_LVS(28)
PPC64_LVS(29)
PPC64_LVS(30)
PPC64_LVS(31)
// use VRSAVE to conditionally restore the remaining VS regs,
// that are where the V regs are mapped
ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave
cmpwi %r5, 0
beq Lnovec
// conditionally load VS
#define PPC64_CLVS_BOTTOM(n) \
beq Ldone##n ;\
addi %r4, %r3, PPC64_OFFS_FP + n * 16 ;\
lxvd2x %vs##n, 0, %r4 ;\
Ldone##n:
#define PPC64_CLVSl(n) \
andis. %r0, %r5, (1<<(47-n)) ;\
PPC64_CLVS_BOTTOM(n)
#define PPC64_CLVSh(n) \
andi. %r0, %r5, (1<<(63-n)) ;\
PPC64_CLVS_BOTTOM(n)
PPC64_CLVSl(32)
PPC64_CLVSl(33)
PPC64_CLVSl(34)
PPC64_CLVSl(35)
PPC64_CLVSl(36)
PPC64_CLVSl(37)
PPC64_CLVSl(38)
PPC64_CLVSl(39)
PPC64_CLVSl(40)
PPC64_CLVSl(41)
PPC64_CLVSl(42)
PPC64_CLVSl(43)
PPC64_CLVSl(44)
PPC64_CLVSl(45)
PPC64_CLVSl(46)
PPC64_CLVSl(47)
PPC64_CLVSh(48)
PPC64_CLVSh(49)
PPC64_CLVSh(50)
PPC64_CLVSh(51)
PPC64_CLVSh(52)
PPC64_CLVSh(53)
PPC64_CLVSh(54)
PPC64_CLVSh(55)
PPC64_CLVSh(56)
PPC64_CLVSh(57)
PPC64_CLVSh(58)
PPC64_CLVSh(59)
PPC64_CLVSh(60)
PPC64_CLVSh(61)
PPC64_CLVSh(62)
PPC64_CLVSh(63)
#else
// load FP register
#define PPC64_LF(n) \
lfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3)
// restore float registers
PPC64_LF(0)
PPC64_LF(1)
PPC64_LF(2)
PPC64_LF(3)
PPC64_LF(4)
PPC64_LF(5)
PPC64_LF(6)
PPC64_LF(7)
PPC64_LF(8)
PPC64_LF(9)
PPC64_LF(10)
PPC64_LF(11)
PPC64_LF(12)
PPC64_LF(13)
PPC64_LF(14)
PPC64_LF(15)
PPC64_LF(16)
PPC64_LF(17)
PPC64_LF(18)
PPC64_LF(19)
PPC64_LF(20)
PPC64_LF(21)
PPC64_LF(22)
PPC64_LF(23)
PPC64_LF(24)
PPC64_LF(25)
PPC64_LF(26)
PPC64_LF(27)
PPC64_LF(28)
PPC64_LF(29)
PPC64_LF(30)
PPC64_LF(31)
// restore vector registers if any are in use
ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave
cmpwi %r5, 0
beq Lnovec
subi %r4, %r1, 16
// r4 is now a 16-byte aligned pointer into the red zone
// the _vectorScalarRegisters may not be 16-byte aligned
// so copy via red zone temp buffer
#define PPC64_CLV_UNALIGNED_BOTTOM(n) \
beq Ldone##n ;\
ld %r0, (PPC64_OFFS_V + n * 16)(%r3) ;\
std %r0, 0(%r4) ;\
ld %r0, (PPC64_OFFS_V + n * 16 + 8)(%r3) ;\
std %r0, 8(%r4) ;\
lvx %v##n, 0, %r4 ;\
Ldone ## n:
#define PPC64_CLV_UNALIGNEDl(n) \
andis. %r0, %r5, (1<<(15-n)) ;\
PPC64_CLV_UNALIGNED_BOTTOM(n)
#define PPC64_CLV_UNALIGNEDh(n) \
andi. %r0, %r5, (1<<(31-n)) ;\
PPC64_CLV_UNALIGNED_BOTTOM(n)
PPC64_CLV_UNALIGNEDl(0)
PPC64_CLV_UNALIGNEDl(1)
PPC64_CLV_UNALIGNEDl(2)
PPC64_CLV_UNALIGNEDl(3)
PPC64_CLV_UNALIGNEDl(4)
PPC64_CLV_UNALIGNEDl(5)
PPC64_CLV_UNALIGNEDl(6)
PPC64_CLV_UNALIGNEDl(7)
PPC64_CLV_UNALIGNEDl(8)
PPC64_CLV_UNALIGNEDl(9)
PPC64_CLV_UNALIGNEDl(10)
PPC64_CLV_UNALIGNEDl(11)
PPC64_CLV_UNALIGNEDl(12)
PPC64_CLV_UNALIGNEDl(13)
PPC64_CLV_UNALIGNEDl(14)
PPC64_CLV_UNALIGNEDl(15)
PPC64_CLV_UNALIGNEDh(16)
PPC64_CLV_UNALIGNEDh(17)
PPC64_CLV_UNALIGNEDh(18)
PPC64_CLV_UNALIGNEDh(19)
PPC64_CLV_UNALIGNEDh(20)
PPC64_CLV_UNALIGNEDh(21)
PPC64_CLV_UNALIGNEDh(22)
PPC64_CLV_UNALIGNEDh(23)
PPC64_CLV_UNALIGNEDh(24)
PPC64_CLV_UNALIGNEDh(25)
PPC64_CLV_UNALIGNEDh(26)
PPC64_CLV_UNALIGNEDh(27)
PPC64_CLV_UNALIGNEDh(28)
PPC64_CLV_UNALIGNEDh(29)
PPC64_CLV_UNALIGNEDh(30)
PPC64_CLV_UNALIGNEDh(31)
#endif
Lnovec:
ld %r0, PPC64_OFFS_CR(%r3)
mtcr %r0
ld %r0, PPC64_OFFS_SRR0(%r3)
mtctr %r0
PPC64_LR(0)
PPC64_LR(5)
PPC64_LR(4)
PPC64_LR(1)
PPC64_LR(3)
bctr
#elif defined(__ppc__)
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
-;
-; void libunwind::Registers_ppc::jumpto()
-;
-; On entry:
-; thread_state pointer is in r3
-;
+//
+// void libunwind::Registers_ppc::jumpto()
+//
+// On entry:
+// thread_state pointer is in r3
+//
- ; restore integral registerrs
- ; skip r0 for now
- ; skip r1 for now
- lwz r2, 16(r3)
- ; skip r3 for now
- ; skip r4 for now
- ; skip r5 for now
- lwz r6, 32(r3)
- lwz r7, 36(r3)
- lwz r8, 40(r3)
- lwz r9, 44(r3)
- lwz r10, 48(r3)
- lwz r11, 52(r3)
- lwz r12, 56(r3)
- lwz r13, 60(r3)
- lwz r14, 64(r3)
- lwz r15, 68(r3)
- lwz r16, 72(r3)
- lwz r17, 76(r3)
- lwz r18, 80(r3)
- lwz r19, 84(r3)
- lwz r20, 88(r3)
- lwz r21, 92(r3)
- lwz r22, 96(r3)
- lwz r23,100(r3)
- lwz r24,104(r3)
- lwz r25,108(r3)
- lwz r26,112(r3)
- lwz r27,116(r3)
- lwz r28,120(r3)
- lwz r29,124(r3)
- lwz r30,128(r3)
- lwz r31,132(r3)
+ // restore integral registerrs
+ // skip r0 for now
+ // skip r1 for now
+ lwz %r2, 16(%r3)
+ // skip r3 for now
+ // skip r4 for now
+ // skip r5 for now
+ lwz %r6, 32(%r3)
+ lwz %r7, 36(%r3)
+ lwz %r8, 40(%r3)
+ lwz %r9, 44(%r3)
+ lwz %r10, 48(%r3)
+ lwz %r11, 52(%r3)
+ lwz %r12, 56(%r3)
+ lwz %r13, 60(%r3)
+ lwz %r14, 64(%r3)
+ lwz %r15, 68(%r3)
+ lwz %r16, 72(%r3)
+ lwz %r17, 76(%r3)
+ lwz %r18, 80(%r3)
+ lwz %r19, 84(%r3)
+ lwz %r20, 88(%r3)
+ lwz %r21, 92(%r3)
+ lwz %r22, 96(%r3)
+ lwz %r23,100(%r3)
+ lwz %r24,104(%r3)
+ lwz %r25,108(%r3)
+ lwz %r26,112(%r3)
+ lwz %r27,116(%r3)
+ lwz %r28,120(%r3)
+ lwz %r29,124(%r3)
+ lwz %r30,128(%r3)
+ lwz %r31,132(%r3)
- ; restore float registers
- lfd f0, 160(r3)
- lfd f1, 168(r3)
- lfd f2, 176(r3)
- lfd f3, 184(r3)
- lfd f4, 192(r3)
- lfd f5, 200(r3)
- lfd f6, 208(r3)
- lfd f7, 216(r3)
- lfd f8, 224(r3)
- lfd f9, 232(r3)
- lfd f10,240(r3)
- lfd f11,248(r3)
- lfd f12,256(r3)
- lfd f13,264(r3)
- lfd f14,272(r3)
- lfd f15,280(r3)
- lfd f16,288(r3)
- lfd f17,296(r3)
- lfd f18,304(r3)
- lfd f19,312(r3)
- lfd f20,320(r3)
- lfd f21,328(r3)
- lfd f22,336(r3)
- lfd f23,344(r3)
- lfd f24,352(r3)
- lfd f25,360(r3)
- lfd f26,368(r3)
- lfd f27,376(r3)
- lfd f28,384(r3)
- lfd f29,392(r3)
- lfd f30,400(r3)
- lfd f31,408(r3)
+ // restore float registers
+ lfd %f0, 160(%r3)
+ lfd %f1, 168(%r3)
+ lfd %f2, 176(%r3)
+ lfd %f3, 184(%r3)
+ lfd %f4, 192(%r3)
+ lfd %f5, 200(%r3)
+ lfd %f6, 208(%r3)
+ lfd %f7, 216(%r3)
+ lfd %f8, 224(%r3)
+ lfd %f9, 232(%r3)
+ lfd %f10,240(%r3)
+ lfd %f11,248(%r3)
+ lfd %f12,256(%r3)
+ lfd %f13,264(%r3)
+ lfd %f14,272(%r3)
+ lfd %f15,280(%r3)
+ lfd %f16,288(%r3)
+ lfd %f17,296(%r3)
+ lfd %f18,304(%r3)
+ lfd %f19,312(%r3)
+ lfd %f20,320(%r3)
+ lfd %f21,328(%r3)
+ lfd %f22,336(%r3)
+ lfd %f23,344(%r3)
+ lfd %f24,352(%r3)
+ lfd %f25,360(%r3)
+ lfd %f26,368(%r3)
+ lfd %f27,376(%r3)
+ lfd %f28,384(%r3)
+ lfd %f29,392(%r3)
+ lfd %f30,400(%r3)
+ lfd %f31,408(%r3)
- ; restore vector registers if any are in use
- lwz r5,156(r3) ; test VRsave
- cmpwi r5,0
- beq Lnovec
+ // restore vector registers if any are in use
+ lwz %r5, 156(%r3) // test VRsave
+ cmpwi %r5, 0
+ beq Lnovec
- subi r4,r1,16
- rlwinm r4,r4,0,0,27 ; mask low 4-bits
- ; r4 is now a 16-byte aligned pointer into the red zone
- ; the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer
+ subi %r4, %r1, 16
+ rlwinm %r4, %r4, 0, 0, 27 // mask low 4-bits
+ // r4 is now a 16-byte aligned pointer into the red zone
+ // the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer
+
-
#define LOAD_VECTOR_UNALIGNEDl(_index) \
- andis. r0,r5,(1<<(15-_index)) @\
- beq Ldone ## _index @\
- lwz r0, 424+_index*16(r3) @\
- stw r0, 0(r4) @\
- lwz r0, 424+_index*16+4(r3) @\
- stw r0, 4(r4) @\
- lwz r0, 424+_index*16+8(r3) @\
- stw r0, 8(r4) @\
- lwz r0, 424+_index*16+12(r3)@\
- stw r0, 12(r4) @\
- lvx v ## _index,0,r4 @\
-Ldone ## _index:
+ andis. %r0, %r5, (1<<(15-_index)) SEPARATOR \
+ beq Ldone ## _index SEPARATOR \
+ lwz %r0, 424+_index*16(%r3) SEPARATOR \
+ stw %r0, 0(%r4) SEPARATOR \
+ lwz %r0, 424+_index*16+4(%r3) SEPARATOR \
+ stw %r0, 4(%r4) SEPARATOR \
+ lwz %r0, 424+_index*16+8(%r3) SEPARATOR \
+ stw %r0, 8(%r4) SEPARATOR \
+ lwz %r0, 424+_index*16+12(%r3) SEPARATOR \
+ stw %r0, 12(%r4) SEPARATOR \
+ lvx %v ## _index, 0, %r4 SEPARATOR \
+ Ldone ## _index:
#define LOAD_VECTOR_UNALIGNEDh(_index) \
- andi. r0,r5,(1<<(31-_index)) @\
- beq Ldone ## _index @\
- lwz r0, 424+_index*16(r3) @\
- stw r0, 0(r4) @\
- lwz r0, 424+_index*16+4(r3) @\
- stw r0, 4(r4) @\
- lwz r0, 424+_index*16+8(r3) @\
- stw r0, 8(r4) @\
- lwz r0, 424+_index*16+12(r3)@\
- stw r0, 12(r4) @\
- lvx v ## _index,0,r4 @\
- Ldone ## _index:
+ andi. %r0, %r5, (1<<(31-_index)) SEPARATOR \
+ beq Ldone ## _index SEPARATOR \
+ lwz %r0, 424+_index*16(%r3) SEPARATOR \
+ stw %r0, 0(%r4) SEPARATOR \
+ lwz %r0, 424+_index*16+4(%r3) SEPARATOR \
+ stw %r0, 4(%r4) SEPARATOR \
+ lwz %r0, 424+_index*16+8(%r3) SEPARATOR \
+ stw %r0, 8(%r4) SEPARATOR \
+ lwz %r0, 424+_index*16+12(%r3) SEPARATOR \
+ stw %r0, 12(%r4) SEPARATOR \
+ lvx %v ## _index, 0, %r4 SEPARATOR \
+ Ldone ## _index:
LOAD_VECTOR_UNALIGNEDl(0)
LOAD_VECTOR_UNALIGNEDl(1)
LOAD_VECTOR_UNALIGNEDl(2)
LOAD_VECTOR_UNALIGNEDl(3)
LOAD_VECTOR_UNALIGNEDl(4)
LOAD_VECTOR_UNALIGNEDl(5)
LOAD_VECTOR_UNALIGNEDl(6)
LOAD_VECTOR_UNALIGNEDl(7)
LOAD_VECTOR_UNALIGNEDl(8)
LOAD_VECTOR_UNALIGNEDl(9)
LOAD_VECTOR_UNALIGNEDl(10)
LOAD_VECTOR_UNALIGNEDl(11)
LOAD_VECTOR_UNALIGNEDl(12)
LOAD_VECTOR_UNALIGNEDl(13)
LOAD_VECTOR_UNALIGNEDl(14)
LOAD_VECTOR_UNALIGNEDl(15)
LOAD_VECTOR_UNALIGNEDh(16)
LOAD_VECTOR_UNALIGNEDh(17)
LOAD_VECTOR_UNALIGNEDh(18)
LOAD_VECTOR_UNALIGNEDh(19)
LOAD_VECTOR_UNALIGNEDh(20)
LOAD_VECTOR_UNALIGNEDh(21)
LOAD_VECTOR_UNALIGNEDh(22)
LOAD_VECTOR_UNALIGNEDh(23)
LOAD_VECTOR_UNALIGNEDh(24)
LOAD_VECTOR_UNALIGNEDh(25)
LOAD_VECTOR_UNALIGNEDh(26)
LOAD_VECTOR_UNALIGNEDh(27)
LOAD_VECTOR_UNALIGNEDh(28)
LOAD_VECTOR_UNALIGNEDh(29)
LOAD_VECTOR_UNALIGNEDh(30)
LOAD_VECTOR_UNALIGNEDh(31)
Lnovec:
- lwz r0, 136(r3) ; __cr
- mtocrf 255,r0
- lwz r0, 148(r3) ; __ctr
- mtctr r0
- lwz r0, 0(r3) ; __ssr0
- mtctr r0
- lwz r0, 8(r3) ; do r0 now
- lwz r5,28(r3) ; do r5 now
- lwz r4,24(r3) ; do r4 now
- lwz r1,12(r3) ; do sp now
- lwz r3,20(r3) ; do r3 last
+ lwz %r0, 136(%r3) // __cr
+ mtcr %r0
+ lwz %r0, 148(%r3) // __ctr
+ mtctr %r0
+ lwz %r0, 0(%r3) // __ssr0
+ mtctr %r0
+ lwz %r0, 8(%r3) // do r0 now
+ lwz %r5, 28(%r3) // do r5 now
+ lwz %r4, 24(%r3) // do r4 now
+ lwz %r1, 12(%r3) // do sp now
+ lwz %r3, 20(%r3) // do r3 last
bctr
#elif defined(__arm64__) || defined(__aarch64__)
//
// void libunwind::Registers_arm64::jumpto()
//
// On entry:
// thread_state pointer is in x0
//
.p2align 2
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv)
// skip restore of x0,x1 for now
ldp x2, x3, [x0, #0x010]
ldp x4, x5, [x0, #0x020]
ldp x6, x7, [x0, #0x030]
ldp x8, x9, [x0, #0x040]
ldp x10,x11, [x0, #0x050]
ldp x12,x13, [x0, #0x060]
ldp x14,x15, [x0, #0x070]
ldp x16,x17, [x0, #0x080]
ldp x18,x19, [x0, #0x090]
ldp x20,x21, [x0, #0x0A0]
ldp x22,x23, [x0, #0x0B0]
ldp x24,x25, [x0, #0x0C0]
ldp x26,x27, [x0, #0x0D0]
ldp x28,x29, [x0, #0x0E0]
ldr x30, [x0, #0x100] // restore pc into lr
ldr x1, [x0, #0x0F8]
mov sp,x1 // restore sp
ldp d0, d1, [x0, #0x110]
ldp d2, d3, [x0, #0x120]
ldp d4, d5, [x0, #0x130]
ldp d6, d7, [x0, #0x140]
ldp d8, d9, [x0, #0x150]
ldp d10,d11, [x0, #0x160]
ldp d12,d13, [x0, #0x170]
ldp d14,d15, [x0, #0x180]
ldp d16,d17, [x0, #0x190]
ldp d18,d19, [x0, #0x1A0]
ldp d20,d21, [x0, #0x1B0]
ldp d22,d23, [x0, #0x1C0]
ldp d24,d25, [x0, #0x1D0]
ldp d26,d27, [x0, #0x1E0]
ldp d28,d29, [x0, #0x1F0]
ldr d30, [x0, #0x200]
ldr d31, [x0, #0x208]
ldp x0, x1, [x0, #0x000] // restore x0,x1
ret x30 // jump to pc
#elif defined(__arm__) && !defined(__APPLE__)
#if !defined(__ARM_ARCH_ISA_ARM)
.thumb
#endif
@
@ void libunwind::Registers_arm::restoreCoreAndJumpTo()
@
@ On entry:
@ thread_state pointer is in r0
@
.p2align 2
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv)
#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
@ r8-r11: ldm into r1-r4, then mov to r8-r11
adds r0, #0x20
ldm r0!, {r1-r4}
subs r0, #0x30
mov r8, r1
mov r9, r2
mov r10, r3
mov r11, r4
@ r12 does not need loading, it it the intra-procedure-call scratch register
ldr r2, [r0, #0x34]
ldr r3, [r0, #0x3c]
mov sp, r2
mov lr, r3 @ restore pc into lr
ldm r0, {r0-r7}
#else
@ Use lr as base so that r0 can be restored.
mov lr, r0
@ 32bit thumb-2 restrictions for ldm:
@ . the sp (r13) cannot be in the list
@ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction
ldm lr, {r0-r12}
ldr sp, [lr, #52]
ldr lr, [lr, #60] @ restore pc into lr
#endif
JMP(lr)
@
@ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values)
@
@ On entry:
@ values pointer is in r0
@
.p2align 2
#if defined(__ELF__)
.fpu vfpv3-d16
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPy)
@ VFP and iwMMX instructions are only available when compiling with the flags
@ that enable them. We do not want to do that in the library (because we do not
@ want the compiler to generate instructions that access those) but this is
@ only accessed if the personality routine needs these registers. Use of
@ these registers implies they are, actually, available on the target, so
@ it's ok to execute.
@ So, generate the instruction using the corresponding coprocessor mnemonic.
vldmia r0, {d0-d15}
JMP(lr)
@
@ static void libunwind::Registers_arm::restoreVFPWithFLDMX(unw_fpreg_t* values)
@
@ On entry:
@ values pointer is in r0
@
.p2align 2
#if defined(__ELF__)
.fpu vfpv3-d16
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPy)
vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia
JMP(lr)
@
@ static void libunwind::Registers_arm::restoreVFPv3(unw_fpreg_t* values)
@
@ On entry:
@ values pointer is in r0
@
.p2align 2
#if defined(__ELF__)
.fpu vfpv3
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy)
vldmia r0, {d16-d31}
JMP(lr)
#if defined(__ARM_WMMX)
@
@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values)
@
@ On entry:
@ values pointer is in r0
@
.p2align 2
#if defined(__ELF__)
.arch armv5te
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy)
ldcl p1, cr0, [r0], #8 @ wldrd wR0, [r0], #8
ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8
ldcl p1, cr2, [r0], #8 @ wldrd wR2, [r0], #8
ldcl p1, cr3, [r0], #8 @ wldrd wR3, [r0], #8
ldcl p1, cr4, [r0], #8 @ wldrd wR4, [r0], #8
ldcl p1, cr5, [r0], #8 @ wldrd wR5, [r0], #8
ldcl p1, cr6, [r0], #8 @ wldrd wR6, [r0], #8
ldcl p1, cr7, [r0], #8 @ wldrd wR7, [r0], #8
ldcl p1, cr8, [r0], #8 @ wldrd wR8, [r0], #8
ldcl p1, cr9, [r0], #8 @ wldrd wR9, [r0], #8
ldcl p1, cr10, [r0], #8 @ wldrd wR10, [r0], #8
ldcl p1, cr11, [r0], #8 @ wldrd wR11, [r0], #8
ldcl p1, cr12, [r0], #8 @ wldrd wR12, [r0], #8
ldcl p1, cr13, [r0], #8 @ wldrd wR13, [r0], #8
ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8
ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8
JMP(lr)
@
@ static void libunwind::Registers_arm::restoreiWMMXControl(unw_uint32_t* values)
@
@ On entry:
@ values pointer is in r0
@
.p2align 2
#if defined(__ELF__)
.arch armv5te
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj)
ldc2 p1, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4
ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4
ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4
ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4
JMP(lr)
#endif
#elif defined(__or1k__)
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
#
# void libunwind::Registers_or1k::jumpto()
#
# On entry:
# thread_state pointer is in r3
#
# restore integral registers
l.lwz r0, 0(r3)
l.lwz r1, 4(r3)
l.lwz r2, 8(r3)
# skip r3 for now
l.lwz r4, 16(r3)
l.lwz r5, 20(r3)
l.lwz r6, 24(r3)
l.lwz r7, 28(r3)
l.lwz r8, 32(r3)
# skip r9
l.lwz r10, 40(r3)
l.lwz r11, 44(r3)
l.lwz r12, 48(r3)
l.lwz r13, 52(r3)
l.lwz r14, 56(r3)
l.lwz r15, 60(r3)
l.lwz r16, 64(r3)
l.lwz r17, 68(r3)
l.lwz r18, 72(r3)
l.lwz r19, 76(r3)
l.lwz r20, 80(r3)
l.lwz r21, 84(r3)
l.lwz r22, 88(r3)
l.lwz r23, 92(r3)
l.lwz r24, 96(r3)
l.lwz r25,100(r3)
l.lwz r26,104(r3)
l.lwz r27,108(r3)
l.lwz r28,112(r3)
l.lwz r29,116(r3)
l.lwz r30,120(r3)
l.lwz r31,124(r3)
# at last, restore r3
l.lwz r3, 12(r3)
# load new pc into ra
l.lwz r9, 128(r3)
# jump to pc
l.jr r9
l.nop
#elif defined(__riscv)
//
// void libunwind::Registers_riscv::jumpto()
//
// On entry:
// thread_state pointer is in a0
//
.p2align 2
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv)
#ifdef __riscv_float_abi_double
fld f0, (8 * 32 + 8 * 0)(a0)
fld f1, (8 * 32 + 8 * 1)(a0)
fld f2, (8 * 32 + 8 * 2)(a0)
fld f3, (8 * 32 + 8 * 3)(a0)
fld f4, (8 * 32 + 8 * 4)(a0)
fld f5, (8 * 32 + 8 * 5)(a0)
fld f6, (8 * 32 + 8 * 6)(a0)
fld f7, (8 * 32 + 8 * 7)(a0)
fld f8, (8 * 32 + 8 * 8)(a0)
fld f9, (8 * 32 + 8 * 9)(a0)
fld f10, (8 * 32 + 8 * 10)(a0)
fld f11, (8 * 32 + 8 * 11)(a0)
fld f12, (8 * 32 + 8 * 12)(a0)
fld f13, (8 * 32 + 8 * 13)(a0)
fld f14, (8 * 32 + 8 * 14)(a0)
fld f15, (8 * 32 + 8 * 15)(a0)
fld f16, (8 * 32 + 8 * 16)(a0)
fld f17, (8 * 32 + 8 * 17)(a0)
fld f18, (8 * 32 + 8 * 18)(a0)
fld f19, (8 * 32 + 8 * 19)(a0)
fld f20, (8 * 32 + 8 * 20)(a0)
fld f21, (8 * 32 + 8 * 21)(a0)
fld f22, (8 * 32 + 8 * 22)(a0)
fld f23, (8 * 32 + 8 * 23)(a0)
fld f24, (8 * 32 + 8 * 24)(a0)
fld f25, (8 * 32 + 8 * 25)(a0)
fld f26, (8 * 32 + 8 * 26)(a0)
fld f27, (8 * 32 + 8 * 27)(a0)
fld f28, (8 * 32 + 8 * 28)(a0)
fld f29, (8 * 32 + 8 * 29)(a0)
fld f30, (8 * 32 + 8 * 30)(a0)
fld f31, (8 * 32 + 8 * 31)(a0)
#endif
// x0 is zero
ld x1, (8 * 1)(a0)
ld x2, (8 * 2)(a0)
ld x3, (8 * 3)(a0)
ld x4, (8 * 4)(a0)
ld x5, (8 * 5)(a0)
ld x6, (8 * 6)(a0)
ld x7, (8 * 7)(a0)
ld x8, (8 * 8)(a0)
ld x9, (8 * 9)(a0)
// skip a0 for now
ld x11, (8 * 11)(a0)
ld x12, (8 * 12)(a0)
ld x13, (8 * 13)(a0)
ld x14, (8 * 14)(a0)
ld x15, (8 * 15)(a0)
ld x16, (8 * 16)(a0)
ld x17, (8 * 17)(a0)
ld x18, (8 * 18)(a0)
ld x19, (8 * 19)(a0)
ld x20, (8 * 20)(a0)
ld x21, (8 * 21)(a0)
ld x22, (8 * 22)(a0)
ld x23, (8 * 23)(a0)
ld x24, (8 * 24)(a0)
ld x25, (8 * 25)(a0)
ld x26, (8 * 26)(a0)
ld x27, (8 * 27)(a0)
ld x28, (8 * 28)(a0)
ld x29, (8 * 29)(a0)
ld x30, (8 * 30)(a0)
ld x31, (8 * 31)(a0)
ld x10, (8 * 10)(a0) // restore a0
ret // jump to ra
#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
//
// void libunwind::Registers_mips_o32::jumpto()
//
// On entry:
// thread state pointer is in a0 ($4)
//
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv)
.set push
.set noat
.set noreorder
.set nomacro
#ifdef __mips_hard_float
#if __mips_fpr != 64
ldc1 $f0, (4 * 36 + 8 * 0)($4)
ldc1 $f2, (4 * 36 + 8 * 2)($4)
ldc1 $f4, (4 * 36 + 8 * 4)($4)
ldc1 $f6, (4 * 36 + 8 * 6)($4)
ldc1 $f8, (4 * 36 + 8 * 8)($4)
ldc1 $f10, (4 * 36 + 8 * 10)($4)
ldc1 $f12, (4 * 36 + 8 * 12)($4)
ldc1 $f14, (4 * 36 + 8 * 14)($4)
ldc1 $f16, (4 * 36 + 8 * 16)($4)
ldc1 $f18, (4 * 36 + 8 * 18)($4)
ldc1 $f20, (4 * 36 + 8 * 20)($4)
ldc1 $f22, (4 * 36 + 8 * 22)($4)
ldc1 $f24, (4 * 36 + 8 * 24)($4)
ldc1 $f26, (4 * 36 + 8 * 26)($4)
ldc1 $f28, (4 * 36 + 8 * 28)($4)
ldc1 $f30, (4 * 36 + 8 * 30)($4)
#else
ldc1 $f0, (4 * 36 + 8 * 0)($4)
ldc1 $f1, (4 * 36 + 8 * 1)($4)
ldc1 $f2, (4 * 36 + 8 * 2)($4)
ldc1 $f3, (4 * 36 + 8 * 3)($4)
ldc1 $f4, (4 * 36 + 8 * 4)($4)
ldc1 $f5, (4 * 36 + 8 * 5)($4)
ldc1 $f6, (4 * 36 + 8 * 6)($4)
ldc1 $f7, (4 * 36 + 8 * 7)($4)
ldc1 $f8, (4 * 36 + 8 * 8)($4)
ldc1 $f9, (4 * 36 + 8 * 9)($4)
ldc1 $f10, (4 * 36 + 8 * 10)($4)
ldc1 $f11, (4 * 36 + 8 * 11)($4)
ldc1 $f12, (4 * 36 + 8 * 12)($4)
ldc1 $f13, (4 * 36 + 8 * 13)($4)
ldc1 $f14, (4 * 36 + 8 * 14)($4)
ldc1 $f15, (4 * 36 + 8 * 15)($4)
ldc1 $f16, (4 * 36 + 8 * 16)($4)
ldc1 $f17, (4 * 36 + 8 * 17)($4)
ldc1 $f18, (4 * 36 + 8 * 18)($4)
ldc1 $f19, (4 * 36 + 8 * 19)($4)
ldc1 $f20, (4 * 36 + 8 * 20)($4)
ldc1 $f21, (4 * 36 + 8 * 21)($4)
ldc1 $f22, (4 * 36 + 8 * 22)($4)
ldc1 $f23, (4 * 36 + 8 * 23)($4)
ldc1 $f24, (4 * 36 + 8 * 24)($4)
ldc1 $f25, (4 * 36 + 8 * 25)($4)
ldc1 $f26, (4 * 36 + 8 * 26)($4)
ldc1 $f27, (4 * 36 + 8 * 27)($4)
ldc1 $f28, (4 * 36 + 8 * 28)($4)
ldc1 $f29, (4 * 36 + 8 * 29)($4)
ldc1 $f30, (4 * 36 + 8 * 30)($4)
ldc1 $f31, (4 * 36 + 8 * 31)($4)
#endif
#endif
// restore hi and lo
lw $8, (4 * 33)($4)
mthi $8
lw $8, (4 * 34)($4)
mtlo $8
// r0 is zero
lw $1, (4 * 1)($4)
lw $2, (4 * 2)($4)
lw $3, (4 * 3)($4)
// skip a0 for now
lw $5, (4 * 5)($4)
lw $6, (4 * 6)($4)
lw $7, (4 * 7)($4)
lw $8, (4 * 8)($4)
lw $9, (4 * 9)($4)
lw $10, (4 * 10)($4)
lw $11, (4 * 11)($4)
lw $12, (4 * 12)($4)
lw $13, (4 * 13)($4)
lw $14, (4 * 14)($4)
lw $15, (4 * 15)($4)
lw $16, (4 * 16)($4)
lw $17, (4 * 17)($4)
lw $18, (4 * 18)($4)
lw $19, (4 * 19)($4)
lw $20, (4 * 20)($4)
lw $21, (4 * 21)($4)
lw $22, (4 * 22)($4)
lw $23, (4 * 23)($4)
lw $24, (4 * 24)($4)
lw $25, (4 * 25)($4)
lw $26, (4 * 26)($4)
lw $27, (4 * 27)($4)
lw $28, (4 * 28)($4)
lw $29, (4 * 29)($4)
lw $30, (4 * 30)($4)
// load new pc into ra
lw $31, (4 * 32)($4)
// jump to ra, load a0 in the delay slot
jr $31
lw $4, (4 * 4)($4)
.set pop
#elif defined(__mips64)
//
// void libunwind::Registers_mips_newabi::jumpto()
//
// On entry:
// thread state pointer is in a0 ($4)
//
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
.set push
.set noat
.set noreorder
.set nomacro
#ifdef __mips_hard_float
ldc1 $f0, (8 * 35)($4)
ldc1 $f1, (8 * 36)($4)
ldc1 $f2, (8 * 37)($4)
ldc1 $f3, (8 * 38)($4)
ldc1 $f4, (8 * 39)($4)
ldc1 $f5, (8 * 40)($4)
ldc1 $f6, (8 * 41)($4)
ldc1 $f7, (8 * 42)($4)
ldc1 $f8, (8 * 43)($4)
ldc1 $f9, (8 * 44)($4)
ldc1 $f10, (8 * 45)($4)
ldc1 $f11, (8 * 46)($4)
ldc1 $f12, (8 * 47)($4)
ldc1 $f13, (8 * 48)($4)
ldc1 $f14, (8 * 49)($4)
ldc1 $f15, (8 * 50)($4)
ldc1 $f16, (8 * 51)($4)
ldc1 $f17, (8 * 52)($4)
ldc1 $f18, (8 * 53)($4)
ldc1 $f19, (8 * 54)($4)
ldc1 $f20, (8 * 55)($4)
ldc1 $f21, (8 * 56)($4)
ldc1 $f22, (8 * 57)($4)
ldc1 $f23, (8 * 58)($4)
ldc1 $f24, (8 * 59)($4)
ldc1 $f25, (8 * 60)($4)
ldc1 $f26, (8 * 61)($4)
ldc1 $f27, (8 * 62)($4)
ldc1 $f28, (8 * 63)($4)
ldc1 $f29, (8 * 64)($4)
ldc1 $f30, (8 * 65)($4)
ldc1 $f31, (8 * 66)($4)
#endif
// restore hi and lo
ld $8, (8 * 33)($4)
mthi $8
ld $8, (8 * 34)($4)
mtlo $8
// r0 is zero
ld $1, (8 * 1)($4)
ld $2, (8 * 2)($4)
ld $3, (8 * 3)($4)
// skip a0 for now
ld $5, (8 * 5)($4)
ld $6, (8 * 6)($4)
ld $7, (8 * 7)($4)
ld $8, (8 * 8)($4)
ld $9, (8 * 9)($4)
ld $10, (8 * 10)($4)
ld $11, (8 * 11)($4)
ld $12, (8 * 12)($4)
ld $13, (8 * 13)($4)
ld $14, (8 * 14)($4)
ld $15, (8 * 15)($4)
ld $16, (8 * 16)($4)
ld $17, (8 * 17)($4)
ld $18, (8 * 18)($4)
ld $19, (8 * 19)($4)
ld $20, (8 * 20)($4)
ld $21, (8 * 21)($4)
ld $22, (8 * 22)($4)
ld $23, (8 * 23)($4)
ld $24, (8 * 24)($4)
ld $25, (8 * 25)($4)
ld $26, (8 * 26)($4)
ld $27, (8 * 27)($4)
ld $28, (8 * 28)($4)
ld $29, (8 * 29)($4)
ld $30, (8 * 30)($4)
// load new pc into ra
ld $31, (8 * 32)($4)
// jump to ra, load a0 in the delay slot
jr $31
ld $4, (8 * 4)($4)
.set pop
#elif defined(__sparc__)
//
// void libunwind::Registers_sparc_o32::jumpto()
//
// On entry:
// thread_state pointer is in o0
//
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv)
ta 3
ldd [%o0 + 64], %l0
ldd [%o0 + 72], %l2
ldd [%o0 + 80], %l4
ldd [%o0 + 88], %l6
ldd [%o0 + 96], %i0
ldd [%o0 + 104], %i2
ldd [%o0 + 112], %i4
ldd [%o0 + 120], %i6
ld [%o0 + 60], %o7
jmp %o7
nop
#endif
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
NO_EXEC_STACK_DIRECTIVE
Index: stable/11/contrib/libunwind/src/UnwindRegistersSave.S
===================================================================
--- stable/11/contrib/libunwind/src/UnwindRegistersSave.S (revision 350258)
+++ stable/11/contrib/libunwind/src/UnwindRegistersSave.S (revision 350259)
@@ -1,1058 +1,1058 @@
//===------------------------ UnwindRegistersSave.S -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "assembly.h"
.text
#if !defined(__USING_SJLJ_EXCEPTIONS__)
#if defined(__i386__)
#
# extern int unw_getcontext(unw_context_t* thread_state)
#
# On entry:
# + +
# +-----------------------+
# + thread_state pointer +
# +-----------------------+
# + return address +
# +-----------------------+ <-- SP
# + +
#
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
push %eax
movl 8(%esp), %eax
movl %ebx, 4(%eax)
movl %ecx, 8(%eax)
movl %edx, 12(%eax)
movl %edi, 16(%eax)
movl %esi, 20(%eax)
movl %ebp, 24(%eax)
movl %esp, %edx
addl $8, %edx
movl %edx, 28(%eax) # store what sp was at call site as esp
# skip ss
# skip eflags
movl 4(%esp), %edx
movl %edx, 40(%eax) # store return address as eip
# skip cs
# skip ds
# skip es
# skip fs
# skip gs
movl (%esp), %edx
movl %edx, (%eax) # store original eax
popl %eax
xorl %eax, %eax # return UNW_ESUCCESS
ret
#elif defined(__x86_64__)
#
# extern int unw_getcontext(unw_context_t* thread_state)
#
# On entry:
# thread_state pointer is in rdi
#
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
#if defined(_WIN64)
#define PTR %rcx
#define TMP %rdx
#else
#define PTR %rdi
#define TMP %rsi
#endif
movq %rax, (PTR)
movq %rbx, 8(PTR)
movq %rcx, 16(PTR)
movq %rdx, 24(PTR)
movq %rdi, 32(PTR)
movq %rsi, 40(PTR)
movq %rbp, 48(PTR)
movq %rsp, 56(PTR)
addq $8, 56(PTR)
movq %r8, 64(PTR)
movq %r9, 72(PTR)
movq %r10, 80(PTR)
movq %r11, 88(PTR)
movq %r12, 96(PTR)
movq %r13,104(PTR)
movq %r14,112(PTR)
movq %r15,120(PTR)
movq (%rsp),TMP
movq TMP,128(PTR) # store return address as rip
# skip rflags
# skip cs
# skip fs
# skip gs
#if defined(_WIN64)
movdqu %xmm0,176(PTR)
movdqu %xmm1,192(PTR)
movdqu %xmm2,208(PTR)
movdqu %xmm3,224(PTR)
movdqu %xmm4,240(PTR)
movdqu %xmm5,256(PTR)
movdqu %xmm6,272(PTR)
movdqu %xmm7,288(PTR)
movdqu %xmm8,304(PTR)
movdqu %xmm9,320(PTR)
movdqu %xmm10,336(PTR)
movdqu %xmm11,352(PTR)
movdqu %xmm12,368(PTR)
movdqu %xmm13,384(PTR)
movdqu %xmm14,400(PTR)
movdqu %xmm15,416(PTR)
#endif
xorl %eax, %eax # return UNW_ESUCCESS
ret
#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
#
# extern int unw_getcontext(unw_context_t* thread_state)
#
# On entry:
# thread_state pointer is in a0 ($4)
#
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
.set push
.set noat
.set noreorder
.set nomacro
sw $1, (4 * 1)($4)
sw $2, (4 * 2)($4)
sw $3, (4 * 3)($4)
sw $4, (4 * 4)($4)
sw $5, (4 * 5)($4)
sw $6, (4 * 6)($4)
sw $7, (4 * 7)($4)
sw $8, (4 * 8)($4)
sw $9, (4 * 9)($4)
sw $10, (4 * 10)($4)
sw $11, (4 * 11)($4)
sw $12, (4 * 12)($4)
sw $13, (4 * 13)($4)
sw $14, (4 * 14)($4)
sw $15, (4 * 15)($4)
sw $16, (4 * 16)($4)
sw $17, (4 * 17)($4)
sw $18, (4 * 18)($4)
sw $19, (4 * 19)($4)
sw $20, (4 * 20)($4)
sw $21, (4 * 21)($4)
sw $22, (4 * 22)($4)
sw $23, (4 * 23)($4)
sw $24, (4 * 24)($4)
sw $25, (4 * 25)($4)
sw $26, (4 * 26)($4)
sw $27, (4 * 27)($4)
sw $28, (4 * 28)($4)
sw $29, (4 * 29)($4)
sw $30, (4 * 30)($4)
sw $31, (4 * 31)($4)
# Store return address to pc
sw $31, (4 * 32)($4)
# hi and lo
mfhi $8
sw $8, (4 * 33)($4)
mflo $8
sw $8, (4 * 34)($4)
#ifdef __mips_hard_float
#if __mips_fpr != 64
sdc1 $f0, (4 * 36 + 8 * 0)($4)
sdc1 $f2, (4 * 36 + 8 * 2)($4)
sdc1 $f4, (4 * 36 + 8 * 4)($4)
sdc1 $f6, (4 * 36 + 8 * 6)($4)
sdc1 $f8, (4 * 36 + 8 * 8)($4)
sdc1 $f10, (4 * 36 + 8 * 10)($4)
sdc1 $f12, (4 * 36 + 8 * 12)($4)
sdc1 $f14, (4 * 36 + 8 * 14)($4)
sdc1 $f16, (4 * 36 + 8 * 16)($4)
sdc1 $f18, (4 * 36 + 8 * 18)($4)
sdc1 $f20, (4 * 36 + 8 * 20)($4)
sdc1 $f22, (4 * 36 + 8 * 22)($4)
sdc1 $f24, (4 * 36 + 8 * 24)($4)
sdc1 $f26, (4 * 36 + 8 * 26)($4)
sdc1 $f28, (4 * 36 + 8 * 28)($4)
sdc1 $f30, (4 * 36 + 8 * 30)($4)
#else
sdc1 $f0, (4 * 36 + 8 * 0)($4)
sdc1 $f1, (4 * 36 + 8 * 1)($4)
sdc1 $f2, (4 * 36 + 8 * 2)($4)
sdc1 $f3, (4 * 36 + 8 * 3)($4)
sdc1 $f4, (4 * 36 + 8 * 4)($4)
sdc1 $f5, (4 * 36 + 8 * 5)($4)
sdc1 $f6, (4 * 36 + 8 * 6)($4)
sdc1 $f7, (4 * 36 + 8 * 7)($4)
sdc1 $f8, (4 * 36 + 8 * 8)($4)
sdc1 $f9, (4 * 36 + 8 * 9)($4)
sdc1 $f10, (4 * 36 + 8 * 10)($4)
sdc1 $f11, (4 * 36 + 8 * 11)($4)
sdc1 $f12, (4 * 36 + 8 * 12)($4)
sdc1 $f13, (4 * 36 + 8 * 13)($4)
sdc1 $f14, (4 * 36 + 8 * 14)($4)
sdc1 $f15, (4 * 36 + 8 * 15)($4)
sdc1 $f16, (4 * 36 + 8 * 16)($4)
sdc1 $f17, (4 * 36 + 8 * 17)($4)
sdc1 $f18, (4 * 36 + 8 * 18)($4)
sdc1 $f19, (4 * 36 + 8 * 19)($4)
sdc1 $f20, (4 * 36 + 8 * 20)($4)
sdc1 $f21, (4 * 36 + 8 * 21)($4)
sdc1 $f22, (4 * 36 + 8 * 22)($4)
sdc1 $f23, (4 * 36 + 8 * 23)($4)
sdc1 $f24, (4 * 36 + 8 * 24)($4)
sdc1 $f25, (4 * 36 + 8 * 25)($4)
sdc1 $f26, (4 * 36 + 8 * 26)($4)
sdc1 $f27, (4 * 36 + 8 * 27)($4)
sdc1 $f28, (4 * 36 + 8 * 28)($4)
sdc1 $f29, (4 * 36 + 8 * 29)($4)
sdc1 $f30, (4 * 36 + 8 * 30)($4)
sdc1 $f31, (4 * 36 + 8 * 31)($4)
#endif
#endif
jr $31
# return UNW_ESUCCESS
or $2, $0, $0
.set pop
#elif defined(__mips64)
#
# extern int unw_getcontext(unw_context_t* thread_state)
#
# On entry:
# thread_state pointer is in a0 ($4)
#
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
.set push
.set noat
.set noreorder
.set nomacro
sd $1, (8 * 1)($4)
sd $2, (8 * 2)($4)
sd $3, (8 * 3)($4)
sd $4, (8 * 4)($4)
sd $5, (8 * 5)($4)
sd $6, (8 * 6)($4)
sd $7, (8 * 7)($4)
sd $8, (8 * 8)($4)
sd $9, (8 * 9)($4)
sd $10, (8 * 10)($4)
sd $11, (8 * 11)($4)
sd $12, (8 * 12)($4)
sd $13, (8 * 13)($4)
sd $14, (8 * 14)($4)
sd $15, (8 * 15)($4)
sd $16, (8 * 16)($4)
sd $17, (8 * 17)($4)
sd $18, (8 * 18)($4)
sd $19, (8 * 19)($4)
sd $20, (8 * 20)($4)
sd $21, (8 * 21)($4)
sd $22, (8 * 22)($4)
sd $23, (8 * 23)($4)
sd $24, (8 * 24)($4)
sd $25, (8 * 25)($4)
sd $26, (8 * 26)($4)
sd $27, (8 * 27)($4)
sd $28, (8 * 28)($4)
sd $29, (8 * 29)($4)
sd $30, (8 * 30)($4)
sd $31, (8 * 31)($4)
# Store return address to pc
sd $31, (8 * 32)($4)
# hi and lo
mfhi $8
sd $8, (8 * 33)($4)
mflo $8
sd $8, (8 * 34)($4)
#ifdef __mips_hard_float
sdc1 $f0, (8 * 35)($4)
sdc1 $f1, (8 * 36)($4)
sdc1 $f2, (8 * 37)($4)
sdc1 $f3, (8 * 38)($4)
sdc1 $f4, (8 * 39)($4)
sdc1 $f5, (8 * 40)($4)
sdc1 $f6, (8 * 41)($4)
sdc1 $f7, (8 * 42)($4)
sdc1 $f8, (8 * 43)($4)
sdc1 $f9, (8 * 44)($4)
sdc1 $f10, (8 * 45)($4)
sdc1 $f11, (8 * 46)($4)
sdc1 $f12, (8 * 47)($4)
sdc1 $f13, (8 * 48)($4)
sdc1 $f14, (8 * 49)($4)
sdc1 $f15, (8 * 50)($4)
sdc1 $f16, (8 * 51)($4)
sdc1 $f17, (8 * 52)($4)
sdc1 $f18, (8 * 53)($4)
sdc1 $f19, (8 * 54)($4)
sdc1 $f20, (8 * 55)($4)
sdc1 $f21, (8 * 56)($4)
sdc1 $f22, (8 * 57)($4)
sdc1 $f23, (8 * 58)($4)
sdc1 $f24, (8 * 59)($4)
sdc1 $f25, (8 * 60)($4)
sdc1 $f26, (8 * 61)($4)
sdc1 $f27, (8 * 62)($4)
sdc1 $f28, (8 * 63)($4)
sdc1 $f29, (8 * 64)($4)
sdc1 $f30, (8 * 65)($4)
sdc1 $f31, (8 * 66)($4)
#endif
jr $31
# return UNW_ESUCCESS
or $2, $0, $0
.set pop
# elif defined(__mips__)
#
# extern int unw_getcontext(unw_context_t* thread_state)
#
# Just trap for the time being.
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
teq $0, $0
#elif defined(__powerpc64__)
//
// extern int unw_getcontext(unw_context_t* thread_state)
//
// On entry:
// thread_state pointer is in r3
//
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
// store register (GPR)
#define PPC64_STR(n) \
std %r##n, (8 * (n + 2))(%r3)
// save GPRs
PPC64_STR(0)
mflr %r0
std %r0, PPC64_OFFS_SRR0(%r3) // store lr as ssr0
PPC64_STR(1)
PPC64_STR(2)
PPC64_STR(3)
PPC64_STR(4)
PPC64_STR(5)
PPC64_STR(6)
PPC64_STR(7)
PPC64_STR(8)
PPC64_STR(9)
PPC64_STR(10)
PPC64_STR(11)
PPC64_STR(12)
PPC64_STR(13)
PPC64_STR(14)
PPC64_STR(15)
PPC64_STR(16)
PPC64_STR(17)
PPC64_STR(18)
PPC64_STR(19)
PPC64_STR(20)
PPC64_STR(21)
PPC64_STR(22)
PPC64_STR(23)
PPC64_STR(24)
PPC64_STR(25)
PPC64_STR(26)
PPC64_STR(27)
PPC64_STR(28)
PPC64_STR(29)
PPC64_STR(30)
PPC64_STR(31)
mfcr %r0
std %r0, PPC64_OFFS_CR(%r3)
mfxer %r0
std %r0, PPC64_OFFS_XER(%r3)
mflr %r0
std %r0, PPC64_OFFS_LR(%r3)
mfctr %r0
std %r0, PPC64_OFFS_CTR(%r3)
mfvrsave %r0
std %r0, PPC64_OFFS_VRSAVE(%r3)
#ifdef PPC64_HAS_VMX
// save VS registers
// (note that this also saves floating point registers and V registers,
// because part of VS is mapped to these registers)
addi %r4, %r3, PPC64_OFFS_FP
// store VS register
#define PPC64_STVS(n) \
stxvd2x %vs##n, 0, %r4 ;\
addi %r4, %r4, 16
PPC64_STVS(0)
PPC64_STVS(1)
PPC64_STVS(2)
PPC64_STVS(3)
PPC64_STVS(4)
PPC64_STVS(5)
PPC64_STVS(6)
PPC64_STVS(7)
PPC64_STVS(8)
PPC64_STVS(9)
PPC64_STVS(10)
PPC64_STVS(11)
PPC64_STVS(12)
PPC64_STVS(13)
PPC64_STVS(14)
PPC64_STVS(15)
PPC64_STVS(16)
PPC64_STVS(17)
PPC64_STVS(18)
PPC64_STVS(19)
PPC64_STVS(20)
PPC64_STVS(21)
PPC64_STVS(22)
PPC64_STVS(23)
PPC64_STVS(24)
PPC64_STVS(25)
PPC64_STVS(26)
PPC64_STVS(27)
PPC64_STVS(28)
PPC64_STVS(29)
PPC64_STVS(30)
PPC64_STVS(31)
PPC64_STVS(32)
PPC64_STVS(33)
PPC64_STVS(34)
PPC64_STVS(35)
PPC64_STVS(36)
PPC64_STVS(37)
PPC64_STVS(38)
PPC64_STVS(39)
PPC64_STVS(40)
PPC64_STVS(41)
PPC64_STVS(42)
PPC64_STVS(43)
PPC64_STVS(44)
PPC64_STVS(45)
PPC64_STVS(46)
PPC64_STVS(47)
PPC64_STVS(48)
PPC64_STVS(49)
PPC64_STVS(50)
PPC64_STVS(51)
PPC64_STVS(52)
PPC64_STVS(53)
PPC64_STVS(54)
PPC64_STVS(55)
PPC64_STVS(56)
PPC64_STVS(57)
PPC64_STVS(58)
PPC64_STVS(59)
PPC64_STVS(60)
PPC64_STVS(61)
PPC64_STVS(62)
PPC64_STVS(63)
#else
// store FP register
#define PPC64_STF(n) \
stfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3)
// save float registers
PPC64_STF(0)
PPC64_STF(1)
PPC64_STF(2)
PPC64_STF(3)
PPC64_STF(4)
PPC64_STF(5)
PPC64_STF(6)
PPC64_STF(7)
PPC64_STF(8)
PPC64_STF(9)
PPC64_STF(10)
PPC64_STF(11)
PPC64_STF(12)
PPC64_STF(13)
PPC64_STF(14)
PPC64_STF(15)
PPC64_STF(16)
PPC64_STF(17)
PPC64_STF(18)
PPC64_STF(19)
PPC64_STF(20)
PPC64_STF(21)
PPC64_STF(22)
PPC64_STF(23)
PPC64_STF(24)
PPC64_STF(25)
PPC64_STF(26)
PPC64_STF(27)
PPC64_STF(28)
PPC64_STF(29)
PPC64_STF(30)
PPC64_STF(31)
// save vector registers
// Use 16-bytes below the stack pointer as an
// aligned buffer to save each vector register.
// Note that the stack pointer is always 16-byte aligned.
subi %r4, %r1, 16
#define PPC64_STV_UNALIGNED(n) \
stvx %v##n, 0, %r4 ;\
ld %r5, 0(%r4) ;\
std %r5, (PPC64_OFFS_V + n * 16)(%r3) ;\
ld %r5, 8(%r4) ;\
std %r5, (PPC64_OFFS_V + n * 16 + 8)(%r3)
PPC64_STV_UNALIGNED(0)
PPC64_STV_UNALIGNED(1)
PPC64_STV_UNALIGNED(2)
PPC64_STV_UNALIGNED(3)
PPC64_STV_UNALIGNED(4)
PPC64_STV_UNALIGNED(5)
PPC64_STV_UNALIGNED(6)
PPC64_STV_UNALIGNED(7)
PPC64_STV_UNALIGNED(8)
PPC64_STV_UNALIGNED(9)
PPC64_STV_UNALIGNED(10)
PPC64_STV_UNALIGNED(11)
PPC64_STV_UNALIGNED(12)
PPC64_STV_UNALIGNED(13)
PPC64_STV_UNALIGNED(14)
PPC64_STV_UNALIGNED(15)
PPC64_STV_UNALIGNED(16)
PPC64_STV_UNALIGNED(17)
PPC64_STV_UNALIGNED(18)
PPC64_STV_UNALIGNED(19)
PPC64_STV_UNALIGNED(20)
PPC64_STV_UNALIGNED(21)
PPC64_STV_UNALIGNED(22)
PPC64_STV_UNALIGNED(23)
PPC64_STV_UNALIGNED(24)
PPC64_STV_UNALIGNED(25)
PPC64_STV_UNALIGNED(26)
PPC64_STV_UNALIGNED(27)
PPC64_STV_UNALIGNED(28)
PPC64_STV_UNALIGNED(29)
PPC64_STV_UNALIGNED(30)
PPC64_STV_UNALIGNED(31)
#endif
li %r3, 0 // return UNW_ESUCCESS
blr
#elif defined(__ppc__)
-;
-; extern int unw_getcontext(unw_context_t* thread_state)
-;
-; On entry:
-; thread_state pointer is in r3
-;
+//
+// extern int unw_getcontext(unw_context_t* thread_state)
+//
+// On entry:
+// thread_state pointer is in r3
+//
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
- stw r0, 8(r3)
- mflr r0
- stw r0, 0(r3) ; store lr as ssr0
- stw r1, 12(r3)
- stw r2, 16(r3)
- stw r3, 20(r3)
- stw r4, 24(r3)
- stw r5, 28(r3)
- stw r6, 32(r3)
- stw r7, 36(r3)
- stw r8, 40(r3)
- stw r9, 44(r3)
- stw r10, 48(r3)
- stw r11, 52(r3)
- stw r12, 56(r3)
- stw r13, 60(r3)
- stw r14, 64(r3)
- stw r15, 68(r3)
- stw r16, 72(r3)
- stw r17, 76(r3)
- stw r18, 80(r3)
- stw r19, 84(r3)
- stw r20, 88(r3)
- stw r21, 92(r3)
- stw r22, 96(r3)
- stw r23,100(r3)
- stw r24,104(r3)
- stw r25,108(r3)
- stw r26,112(r3)
- stw r27,116(r3)
- stw r28,120(r3)
- stw r29,124(r3)
- stw r30,128(r3)
- stw r31,132(r3)
+ stw %r0, 8(%r3)
+ mflr %r0
+ stw %r0, 0(%r3) // store lr as ssr0
+ stw %r1, 12(%r3)
+ stw %r2, 16(%r3)
+ stw %r3, 20(%r3)
+ stw %r4, 24(%r3)
+ stw %r5, 28(%r3)
+ stw %r6, 32(%r3)
+ stw %r7, 36(%r3)
+ stw %r8, 40(%r3)
+ stw %r9, 44(%r3)
+ stw %r10, 48(%r3)
+ stw %r11, 52(%r3)
+ stw %r12, 56(%r3)
+ stw %r13, 60(%r3)
+ stw %r14, 64(%r3)
+ stw %r15, 68(%r3)
+ stw %r16, 72(%r3)
+ stw %r17, 76(%r3)
+ stw %r18, 80(%r3)
+ stw %r19, 84(%r3)
+ stw %r20, 88(%r3)
+ stw %r21, 92(%r3)
+ stw %r22, 96(%r3)
+ stw %r23,100(%r3)
+ stw %r24,104(%r3)
+ stw %r25,108(%r3)
+ stw %r26,112(%r3)
+ stw %r27,116(%r3)
+ stw %r28,120(%r3)
+ stw %r29,124(%r3)
+ stw %r30,128(%r3)
+ stw %r31,132(%r3)
- ; save VRSave register
- mfspr r0,256
- stw r0,156(r3)
- ; save CR registers
- mfcr r0
- stw r0,136(r3)
- ; save CTR register
- mfctr r0
- stw r0,148(r3)
+ // save VRSave register
+ mfspr %r0, 256
+ stw %r0, 156(%r3)
+ // save CR registers
+ mfcr %r0
+ stw %r0, 136(%r3)
+ // save CTR register
+ mfctr %r0
+ stw %r0, 148(%r3)
- ; save float registers
- stfd f0, 160(r3)
- stfd f1, 168(r3)
- stfd f2, 176(r3)
- stfd f3, 184(r3)
- stfd f4, 192(r3)
- stfd f5, 200(r3)
- stfd f6, 208(r3)
- stfd f7, 216(r3)
- stfd f8, 224(r3)
- stfd f9, 232(r3)
- stfd f10,240(r3)
- stfd f11,248(r3)
- stfd f12,256(r3)
- stfd f13,264(r3)
- stfd f14,272(r3)
- stfd f15,280(r3)
- stfd f16,288(r3)
- stfd f17,296(r3)
- stfd f18,304(r3)
- stfd f19,312(r3)
- stfd f20,320(r3)
- stfd f21,328(r3)
- stfd f22,336(r3)
- stfd f23,344(r3)
- stfd f24,352(r3)
- stfd f25,360(r3)
- stfd f26,368(r3)
- stfd f27,376(r3)
- stfd f28,384(r3)
- stfd f29,392(r3)
- stfd f30,400(r3)
- stfd f31,408(r3)
+ // save float registers
+ stfd %f0, 160(%r3)
+ stfd %f1, 168(%r3)
+ stfd %f2, 176(%r3)
+ stfd %f3, 184(%r3)
+ stfd %f4, 192(%r3)
+ stfd %f5, 200(%r3)
+ stfd %f6, 208(%r3)
+ stfd %f7, 216(%r3)
+ stfd %f8, 224(%r3)
+ stfd %f9, 232(%r3)
+ stfd %f10,240(%r3)
+ stfd %f11,248(%r3)
+ stfd %f12,256(%r3)
+ stfd %f13,264(%r3)
+ stfd %f14,272(%r3)
+ stfd %f15,280(%r3)
+ stfd %f16,288(%r3)
+ stfd %f17,296(%r3)
+ stfd %f18,304(%r3)
+ stfd %f19,312(%r3)
+ stfd %f20,320(%r3)
+ stfd %f21,328(%r3)
+ stfd %f22,336(%r3)
+ stfd %f23,344(%r3)
+ stfd %f24,352(%r3)
+ stfd %f25,360(%r3)
+ stfd %f26,368(%r3)
+ stfd %f27,376(%r3)
+ stfd %f28,384(%r3)
+ stfd %f29,392(%r3)
+ stfd %f30,400(%r3)
+ stfd %f31,408(%r3)
- ; save vector registers
+ // save vector registers
- subi r4,r1,16
- rlwinm r4,r4,0,0,27 ; mask low 4-bits
- ; r4 is now a 16-byte aligned pointer into the red zone
+ subi %r4, %r1, 16
+ rlwinm %r4, %r4, 0, 0, 27 // mask low 4-bits
+ // r4 is now a 16-byte aligned pointer into the red zone
#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \
- stvx _vec,0,r4 @\
- lwz r5, 0(r4) @\
- stw r5, _offset(r3) @\
- lwz r5, 4(r4) @\
- stw r5, _offset+4(r3) @\
- lwz r5, 8(r4) @\
- stw r5, _offset+8(r3) @\
- lwz r5, 12(r4) @\
- stw r5, _offset+12(r3)
+ stvx _vec, 0, %r4 SEPARATOR \
+ lwz %r5, 0(%r4) SEPARATOR \
+ stw %r5, _offset(%r3) SEPARATOR \
+ lwz %r5, 4(%r4) SEPARATOR \
+ stw %r5, _offset+4(%r3) SEPARATOR \
+ lwz %r5, 8(%r4) SEPARATOR \
+ stw %r5, _offset+8(%r3) SEPARATOR \
+ lwz %r5, 12(%r4) SEPARATOR \
+ stw %r5, _offset+12(%r3)
- SAVE_VECTOR_UNALIGNED( v0, 424+0x000)
- SAVE_VECTOR_UNALIGNED( v1, 424+0x010)
- SAVE_VECTOR_UNALIGNED( v2, 424+0x020)
- SAVE_VECTOR_UNALIGNED( v3, 424+0x030)
- SAVE_VECTOR_UNALIGNED( v4, 424+0x040)
- SAVE_VECTOR_UNALIGNED( v5, 424+0x050)
- SAVE_VECTOR_UNALIGNED( v6, 424+0x060)
- SAVE_VECTOR_UNALIGNED( v7, 424+0x070)
- SAVE_VECTOR_UNALIGNED( v8, 424+0x080)
- SAVE_VECTOR_UNALIGNED( v9, 424+0x090)
- SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0)
- SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0)
- SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0)
- SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0)
- SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0)
- SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0)
- SAVE_VECTOR_UNALIGNED(v16, 424+0x100)
- SAVE_VECTOR_UNALIGNED(v17, 424+0x110)
- SAVE_VECTOR_UNALIGNED(v18, 424+0x120)
- SAVE_VECTOR_UNALIGNED(v19, 424+0x130)
- SAVE_VECTOR_UNALIGNED(v20, 424+0x140)
- SAVE_VECTOR_UNALIGNED(v21, 424+0x150)
- SAVE_VECTOR_UNALIGNED(v22, 424+0x160)
- SAVE_VECTOR_UNALIGNED(v23, 424+0x170)
- SAVE_VECTOR_UNALIGNED(v24, 424+0x180)
- SAVE_VECTOR_UNALIGNED(v25, 424+0x190)
- SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0)
- SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0)
- SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0)
- SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0)
- SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0)
- SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0)
+ SAVE_VECTOR_UNALIGNED( %v0, 424+0x000)
+ SAVE_VECTOR_UNALIGNED( %v1, 424+0x010)
+ SAVE_VECTOR_UNALIGNED( %v2, 424+0x020)
+ SAVE_VECTOR_UNALIGNED( %v3, 424+0x030)
+ SAVE_VECTOR_UNALIGNED( %v4, 424+0x040)
+ SAVE_VECTOR_UNALIGNED( %v5, 424+0x050)
+ SAVE_VECTOR_UNALIGNED( %v6, 424+0x060)
+ SAVE_VECTOR_UNALIGNED( %v7, 424+0x070)
+ SAVE_VECTOR_UNALIGNED( %v8, 424+0x080)
+ SAVE_VECTOR_UNALIGNED( %v9, 424+0x090)
+ SAVE_VECTOR_UNALIGNED(%v10, 424+0x0A0)
+ SAVE_VECTOR_UNALIGNED(%v11, 424+0x0B0)
+ SAVE_VECTOR_UNALIGNED(%v12, 424+0x0C0)
+ SAVE_VECTOR_UNALIGNED(%v13, 424+0x0D0)
+ SAVE_VECTOR_UNALIGNED(%v14, 424+0x0E0)
+ SAVE_VECTOR_UNALIGNED(%v15, 424+0x0F0)
+ SAVE_VECTOR_UNALIGNED(%v16, 424+0x100)
+ SAVE_VECTOR_UNALIGNED(%v17, 424+0x110)
+ SAVE_VECTOR_UNALIGNED(%v18, 424+0x120)
+ SAVE_VECTOR_UNALIGNED(%v19, 424+0x130)
+ SAVE_VECTOR_UNALIGNED(%v20, 424+0x140)
+ SAVE_VECTOR_UNALIGNED(%v21, 424+0x150)
+ SAVE_VECTOR_UNALIGNED(%v22, 424+0x160)
+ SAVE_VECTOR_UNALIGNED(%v23, 424+0x170)
+ SAVE_VECTOR_UNALIGNED(%v24, 424+0x180)
+ SAVE_VECTOR_UNALIGNED(%v25, 424+0x190)
+ SAVE_VECTOR_UNALIGNED(%v26, 424+0x1A0)
+ SAVE_VECTOR_UNALIGNED(%v27, 424+0x1B0)
+ SAVE_VECTOR_UNALIGNED(%v28, 424+0x1C0)
+ SAVE_VECTOR_UNALIGNED(%v29, 424+0x1D0)
+ SAVE_VECTOR_UNALIGNED(%v30, 424+0x1E0)
+ SAVE_VECTOR_UNALIGNED(%v31, 424+0x1F0)
- li r3, 0 ; return UNW_ESUCCESS
+ li %r3, 0 // return UNW_ESUCCESS
blr
#elif defined(__arm64__) || defined(__aarch64__)
//
// extern int unw_getcontext(unw_context_t* thread_state)
//
// On entry:
// thread_state pointer is in x0
//
.p2align 2
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
stp x0, x1, [x0, #0x000]
stp x2, x3, [x0, #0x010]
stp x4, x5, [x0, #0x020]
stp x6, x7, [x0, #0x030]
stp x8, x9, [x0, #0x040]
stp x10,x11, [x0, #0x050]
stp x12,x13, [x0, #0x060]
stp x14,x15, [x0, #0x070]
stp x16,x17, [x0, #0x080]
stp x18,x19, [x0, #0x090]
stp x20,x21, [x0, #0x0A0]
stp x22,x23, [x0, #0x0B0]
stp x24,x25, [x0, #0x0C0]
stp x26,x27, [x0, #0x0D0]
stp x28,x29, [x0, #0x0E0]
str x30, [x0, #0x0F0]
mov x1,sp
str x1, [x0, #0x0F8]
str x30, [x0, #0x100] // store return address as pc
// skip cpsr
stp d0, d1, [x0, #0x110]
stp d2, d3, [x0, #0x120]
stp d4, d5, [x0, #0x130]
stp d6, d7, [x0, #0x140]
stp d8, d9, [x0, #0x150]
stp d10,d11, [x0, #0x160]
stp d12,d13, [x0, #0x170]
stp d14,d15, [x0, #0x180]
stp d16,d17, [x0, #0x190]
stp d18,d19, [x0, #0x1A0]
stp d20,d21, [x0, #0x1B0]
stp d22,d23, [x0, #0x1C0]
stp d24,d25, [x0, #0x1D0]
stp d26,d27, [x0, #0x1E0]
stp d28,d29, [x0, #0x1F0]
str d30, [x0, #0x200]
str d31, [x0, #0x208]
mov x0, #0 // return UNW_ESUCCESS
ret
#elif defined(__arm__) && !defined(__APPLE__)
#if !defined(__ARM_ARCH_ISA_ARM)
.thumb
#endif
@
@ extern int unw_getcontext(unw_context_t* thread_state)
@
@ On entry:
@ thread_state pointer is in r0
@
@ Per EHABI #4.7 this only saves the core integer registers.
@ EHABI #7.4.5 notes that in general all VRS registers should be restored
@ however this is very hard to do for VFP registers because it is unknown
@ to the library how many registers are implemented by the architecture.
@ Instead, VFP registers are demand saved by logic external to unw_getcontext.
@
.p2align 2
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
stm r0!, {r0-r7}
mov r1, r8
mov r2, r9
mov r3, r10
stm r0!, {r1-r3}
mov r1, r11
mov r2, sp
mov r3, lr
str r1, [r0, #0] @ r11
@ r12 does not need storing, it it the intra-procedure-call scratch register
str r2, [r0, #8] @ sp
str r3, [r0, #12] @ lr
str r3, [r0, #16] @ store return address as pc
@ T1 does not have a non-cpsr-clobbering register-zeroing instruction.
@ It is safe to use here though because we are about to return, and cpsr is
@ not expected to be preserved.
movs r0, #0 @ return UNW_ESUCCESS
#else
@ 32bit thumb-2 restrictions for stm:
@ . the sp (r13) cannot be in the list
@ . the pc (r15) cannot be in the list in an STM instruction
stm r0, {r0-r12}
str sp, [r0, #52]
str lr, [r0, #56]
str lr, [r0, #60] @ store return address as pc
mov r0, #0 @ return UNW_ESUCCESS
#endif
JMP(lr)
@
@ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values)
@
@ On entry:
@ values pointer is in r0
@
.p2align 2
#if defined(__ELF__)
.fpu vfpv3-d16
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy)
vstmia r0, {d0-d15}
JMP(lr)
@
@ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values)
@
@ On entry:
@ values pointer is in r0
@
.p2align 2
#if defined(__ELF__)
.fpu vfpv3-d16
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy)
vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia
JMP(lr)
@
@ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values)
@
@ On entry:
@ values pointer is in r0
@
.p2align 2
#if defined(__ELF__)
.fpu vfpv3
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy)
@ VFP and iwMMX instructions are only available when compiling with the flags
@ that enable them. We do not want to do that in the library (because we do not
@ want the compiler to generate instructions that access those) but this is
@ only accessed if the personality routine needs these registers. Use of
@ these registers implies they are, actually, available on the target, so
@ it's ok to execute.
@ So, generate the instructions using the corresponding coprocessor mnemonic.
vstmia r0, {d16-d31}
JMP(lr)
#if defined(_LIBUNWIND_ARM_WMMX)
@
@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values)
@
@ On entry:
@ values pointer is in r0
@
.p2align 2
#if defined(__ELF__)
.arch armv5te
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy)
stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8
stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8
stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8
stcl p1, cr3, [r0], #8 @ wstrd wR3, [r0], #8
stcl p1, cr4, [r0], #8 @ wstrd wR4, [r0], #8
stcl p1, cr5, [r0], #8 @ wstrd wR5, [r0], #8
stcl p1, cr6, [r0], #8 @ wstrd wR6, [r0], #8
stcl p1, cr7, [r0], #8 @ wstrd wR7, [r0], #8
stcl p1, cr8, [r0], #8 @ wstrd wR8, [r0], #8
stcl p1, cr9, [r0], #8 @ wstrd wR9, [r0], #8
stcl p1, cr10, [r0], #8 @ wstrd wR10, [r0], #8
stcl p1, cr11, [r0], #8 @ wstrd wR11, [r0], #8
stcl p1, cr12, [r0], #8 @ wstrd wR12, [r0], #8
stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8
stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8
stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8
JMP(lr)
@
@ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values)
@
@ On entry:
@ values pointer is in r0
@
.p2align 2
#if defined(__ELF__)
.arch armv5te
#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj)
stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4
stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4
stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4
stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4
JMP(lr)
#endif
#elif defined(__or1k__)
#
# extern int unw_getcontext(unw_context_t* thread_state)
#
# On entry:
# thread_state pointer is in r3
#
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
l.sw 0(r3), r0
l.sw 4(r3), r1
l.sw 8(r3), r2
l.sw 12(r3), r3
l.sw 16(r3), r4
l.sw 20(r3), r5
l.sw 24(r3), r6
l.sw 28(r3), r7
l.sw 32(r3), r8
l.sw 36(r3), r9
l.sw 40(r3), r10
l.sw 44(r3), r11
l.sw 48(r3), r12
l.sw 52(r3), r13
l.sw 56(r3), r14
l.sw 60(r3), r15
l.sw 64(r3), r16
l.sw 68(r3), r17
l.sw 72(r3), r18
l.sw 76(r3), r19
l.sw 80(r3), r20
l.sw 84(r3), r21
l.sw 88(r3), r22
l.sw 92(r3), r23
l.sw 96(r3), r24
l.sw 100(r3), r25
l.sw 104(r3), r26
l.sw 108(r3), r27
l.sw 112(r3), r28
l.sw 116(r3), r29
l.sw 120(r3), r30
l.sw 124(r3), r31
# store ra to pc
l.sw 128(r3), r9
# zero epcr
l.sw 132(r3), r0
#elif defined(__riscv)
#
# extern int unw_getcontext(unw_context_t* thread_state)
#
# On entry:
# thread_state pointer is in a0
#
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
// x0 is zero
sd x1, (8 * 1)(a0)
sd x2, (8 * 2)(a0)
sd x3, (8 * 3)(a0)
sd x4, (8 * 4)(a0)
sd x5, (8 * 5)(a0)
sd x6, (8 * 6)(a0)
sd x7, (8 * 7)(a0)
sd x8, (8 * 8)(a0)
sd x9, (8 * 9)(a0)
sd x10, (8 * 10)(a0)
sd x11, (8 * 11)(a0)
sd x12, (8 * 12)(a0)
sd x13, (8 * 13)(a0)
sd x14, (8 * 14)(a0)
sd x15, (8 * 15)(a0)
sd x16, (8 * 16)(a0)
sd x17, (8 * 17)(a0)
sd x18, (8 * 18)(a0)
sd x19, (8 * 19)(a0)
sd x20, (8 * 20)(a0)
sd x21, (8 * 21)(a0)
sd x22, (8 * 22)(a0)
sd x23, (8 * 23)(a0)
sd x24, (8 * 24)(a0)
sd x25, (8 * 25)(a0)
sd x26, (8 * 26)(a0)
sd x27, (8 * 27)(a0)
sd x28, (8 * 28)(a0)
sd x29, (8 * 29)(a0)
sd x30, (8 * 30)(a0)
sd x31, (8 * 31)(a0)
#ifdef __riscv_float_abi_double
fsd f0, (8 * 32 + 8 * 0)(a0)
fsd f1, (8 * 32 + 8 * 1)(a0)
fsd f2, (8 * 32 + 8 * 2)(a0)
fsd f3, (8 * 32 + 8 * 3)(a0)
fsd f4, (8 * 32 + 8 * 4)(a0)
fsd f5, (8 * 32 + 8 * 5)(a0)
fsd f6, (8 * 32 + 8 * 6)(a0)
fsd f7, (8 * 32 + 8 * 7)(a0)
fsd f8, (8 * 32 + 8 * 8)(a0)
fsd f9, (8 * 32 + 8 * 9)(a0)
fsd f10, (8 * 32 + 8 * 10)(a0)
fsd f11, (8 * 32 + 8 * 11)(a0)
fsd f12, (8 * 32 + 8 * 12)(a0)
fsd f13, (8 * 32 + 8 * 13)(a0)
fsd f14, (8 * 32 + 8 * 14)(a0)
fsd f15, (8 * 32 + 8 * 15)(a0)
fsd f16, (8 * 32 + 8 * 16)(a0)
fsd f17, (8 * 32 + 8 * 17)(a0)
fsd f18, (8 * 32 + 8 * 18)(a0)
fsd f19, (8 * 32 + 8 * 19)(a0)
fsd f20, (8 * 32 + 8 * 20)(a0)
fsd f21, (8 * 32 + 8 * 21)(a0)
fsd f22, (8 * 32 + 8 * 22)(a0)
fsd f23, (8 * 32 + 8 * 23)(a0)
fsd f24, (8 * 32 + 8 * 24)(a0)
fsd f25, (8 * 32 + 8 * 25)(a0)
fsd f26, (8 * 32 + 8 * 26)(a0)
fsd f27, (8 * 32 + 8 * 27)(a0)
fsd f28, (8 * 32 + 8 * 28)(a0)
fsd f29, (8 * 32 + 8 * 29)(a0)
fsd f30, (8 * 32 + 8 * 30)(a0)
fsd f31, (8 * 32 + 8 * 31)(a0)
#endif
li a0, 0 // return UNW_ESUCCESS
ret // jump to ra
#elif defined(__sparc__)
#
# extern int unw_getcontext(unw_context_t* thread_state)
#
# On entry:
# thread_state pointer is in o0
#
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
ta 3
add %o7, 8, %o7
std %g0, [%o0 + 0]
std %g2, [%o0 + 8]
std %g4, [%o0 + 16]
std %g6, [%o0 + 24]
std %o0, [%o0 + 32]
std %o2, [%o0 + 40]
std %o4, [%o0 + 48]
std %o6, [%o0 + 56]
std %l0, [%o0 + 64]
std %l2, [%o0 + 72]
std %l4, [%o0 + 80]
std %l6, [%o0 + 88]
std %i0, [%o0 + 96]
std %i2, [%o0 + 104]
std %i4, [%o0 + 112]
std %i6, [%o0 + 120]
jmp %o7
clr %o0 // return UNW_ESUCCESS
#endif
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
NO_EXEC_STACK_DIRECTIVE
Index: stable/11/contrib/libunwind/src/assembly.h
===================================================================
--- stable/11/contrib/libunwind/src/assembly.h (revision 350258)
+++ stable/11/contrib/libunwind/src/assembly.h (revision 350259)
@@ -1,124 +1,140 @@
/* ===-- assembly.h - libUnwind assembler support macros -------------------===
*
* The LLVM Compiler Infrastructure
*
* This file is dual licensed under the MIT and the University of Illinois Open
* Source Licenses. See LICENSE.TXT for details.
*
* ===----------------------------------------------------------------------===
*
* This file defines macros for use in libUnwind assembler source.
* This file is not part of the interface of this library.
*
* ===----------------------------------------------------------------------===
*/
#ifndef UNWIND_ASSEMBLY_H
#define UNWIND_ASSEMBLY_H
#if defined(__powerpc64__)
#define SEPARATOR ;
#define PPC64_OFFS_SRR0 0
#define PPC64_OFFS_CR 272
#define PPC64_OFFS_XER 280
#define PPC64_OFFS_LR 288
#define PPC64_OFFS_CTR 296
#define PPC64_OFFS_VRSAVE 304
#define PPC64_OFFS_FP 312
#define PPC64_OFFS_V 824
#ifdef _ARCH_PWR8
#define PPC64_HAS_VMX
#endif
-#elif defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
-#define SEPARATOR @
#elif defined(__arm64__)
#define SEPARATOR %%
#else
#define SEPARATOR ;
#endif
+#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1)
+#define PPC64_OPD1 .section .opd,"aw",@progbits SEPARATOR
+#define PPC64_OPD2 SEPARATOR \
+ .p2align 3 SEPARATOR \
+ .quad .Lfunc_begin0 SEPARATOR \
+ .quad .TOC.@tocbase SEPARATOR \
+ .quad 0 SEPARATOR \
+ .text SEPARATOR \
+.Lfunc_begin0:
+#else
+#define PPC64_OPD1
+#define PPC64_OPD2
+#endif
+
#define GLUE2(a, b) a ## b
#define GLUE(a, b) GLUE2(a, b)
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
#if defined(__APPLE__)
#define SYMBOL_IS_FUNC(name)
#define EXPORT_SYMBOL(name)
#define HIDDEN_SYMBOL(name) .private_extern name
#define NO_EXEC_STACK_DIRECTIVE
#elif defined(__ELF__)
#if defined(__arm__)
#define SYMBOL_IS_FUNC(name) .type name,%function
#else
#define SYMBOL_IS_FUNC(name) .type name,@function
#endif
#define EXPORT_SYMBOL(name)
#define HIDDEN_SYMBOL(name) .hidden name
#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
defined(__linux__)
#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
#else
#define NO_EXEC_STACK_DIRECTIVE
#endif
#elif defined(_WIN32)
#define SYMBOL_IS_FUNC(name) \
.def name SEPARATOR \
.scl 2 SEPARATOR \
.type 32 SEPARATOR \
.endef
#define EXPORT_SYMBOL2(name) \
.section .drectve,"yn" SEPARATOR \
.ascii "-export:", #name, "\0" SEPARATOR \
.text
#if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS)
#define EXPORT_SYMBOL(name)
#else
#define EXPORT_SYMBOL(name) EXPORT_SYMBOL2(name)
#endif
#define HIDDEN_SYMBOL(name)
#define NO_EXEC_STACK_DIRECTIVE
#elif defined(__sparc__)
#else
#error Unsupported target
#endif
#define DEFINE_LIBUNWIND_FUNCTION(name) \
.globl SYMBOL_NAME(name) SEPARATOR \
EXPORT_SYMBOL(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
- SYMBOL_NAME(name):
+ PPC64_OPD1 \
+ SYMBOL_NAME(name): \
+ PPC64_OPD2
#define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name) \
.globl SYMBOL_NAME(name) SEPARATOR \
HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
- SYMBOL_NAME(name):
+ PPC64_OPD1 \
+ SYMBOL_NAME(name): \
+ PPC64_OPD2
#if defined(__arm__)
#if !defined(__ARM_ARCH)
#define __ARM_ARCH 4
#endif
#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
#define ARM_HAS_BX
#endif
#ifdef ARM_HAS_BX
#define JMP(r) bx r
#else
#define JMP(r) mov pc, r
#endif
#endif /* __arm__ */
#endif /* UNWIND_ASSEMBLY_H */
Index: stable/11/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
===================================================================
--- stable/11/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp (revision 350259)
@@ -1,556 +1,556 @@
//===- DWARFDebugFrame.h - Parsing of .debug_frame ------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cinttypes>
#include <cstdint>
#include <string>
#include <vector>
using namespace llvm;
using namespace dwarf;
// See DWARF standard v3, section 7.23
const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f;
Error CFIProgram::parse(DataExtractor Data, uint32_t *Offset,
uint32_t EndOffset) {
while (*Offset < EndOffset) {
uint8_t Opcode = Data.getU8(Offset);
// Some instructions have a primary opcode encoded in the top bits.
uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK;
if (Primary) {
// If it's a primary opcode, the first operand is encoded in the bottom
// bits of the opcode itself.
uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK;
switch (Primary) {
default:
return createStringError(errc::illegal_byte_sequence,
"Invalid primary CFI opcode 0x%" PRIx8,
Primary);
case DW_CFA_advance_loc:
case DW_CFA_restore:
addInstruction(Primary, Op1);
break;
case DW_CFA_offset:
addInstruction(Primary, Op1, Data.getULEB128(Offset));
break;
}
} else {
// Extended opcode - its value is Opcode itself.
switch (Opcode) {
default:
return createStringError(errc::illegal_byte_sequence,
"Invalid extended CFI opcode 0x%" PRIx8,
Opcode);
case DW_CFA_nop:
case DW_CFA_remember_state:
case DW_CFA_restore_state:
case DW_CFA_GNU_window_save:
// No operands
addInstruction(Opcode);
break;
case DW_CFA_set_loc:
// Operands: Address
addInstruction(Opcode, Data.getAddress(Offset));
break;
case DW_CFA_advance_loc1:
// Operands: 1-byte delta
addInstruction(Opcode, Data.getU8(Offset));
break;
case DW_CFA_advance_loc2:
// Operands: 2-byte delta
addInstruction(Opcode, Data.getU16(Offset));
break;
case DW_CFA_advance_loc4:
// Operands: 4-byte delta
addInstruction(Opcode, Data.getU32(Offset));
break;
case DW_CFA_restore_extended:
case DW_CFA_undefined:
case DW_CFA_same_value:
case DW_CFA_def_cfa_register:
case DW_CFA_def_cfa_offset:
case DW_CFA_GNU_args_size:
// Operands: ULEB128
addInstruction(Opcode, Data.getULEB128(Offset));
break;
case DW_CFA_def_cfa_offset_sf:
// Operands: SLEB128
addInstruction(Opcode, Data.getSLEB128(Offset));
break;
case DW_CFA_offset_extended:
case DW_CFA_register:
case DW_CFA_def_cfa:
case DW_CFA_val_offset: {
// Operands: ULEB128, ULEB128
// Note: We can not embed getULEB128 directly into function
// argument list. getULEB128 changes Offset and order of evaluation
// for arguments is unspecified.
auto op1 = Data.getULEB128(Offset);
auto op2 = Data.getULEB128(Offset);
addInstruction(Opcode, op1, op2);
break;
}
case DW_CFA_offset_extended_sf:
case DW_CFA_def_cfa_sf:
case DW_CFA_val_offset_sf: {
// Operands: ULEB128, SLEB128
// Note: see comment for the previous case
auto op1 = Data.getULEB128(Offset);
auto op2 = (uint64_t)Data.getSLEB128(Offset);
addInstruction(Opcode, op1, op2);
break;
}
case DW_CFA_def_cfa_expression: {
uint32_t ExprLength = Data.getULEB128(Offset);
addInstruction(Opcode, 0);
DataExtractor Extractor(
Data.getData().slice(*Offset, *Offset + ExprLength),
Data.isLittleEndian(), Data.getAddressSize());
Instructions.back().Expression = DWARFExpression(
Extractor, Data.getAddressSize(), dwarf::DWARF_VERSION);
*Offset += ExprLength;
break;
}
case DW_CFA_expression:
case DW_CFA_val_expression: {
auto RegNum = Data.getULEB128(Offset);
auto BlockLength = Data.getULEB128(Offset);
addInstruction(Opcode, RegNum, 0);
DataExtractor Extractor(
Data.getData().slice(*Offset, *Offset + BlockLength),
Data.isLittleEndian(), Data.getAddressSize());
Instructions.back().Expression = DWARFExpression(
Extractor, Data.getAddressSize(), dwarf::DWARF_VERSION);
*Offset += BlockLength;
break;
}
}
}
}
return Error::success();
}
namespace {
} // end anonymous namespace
ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
static OperandType OpTypes[DW_CFA_restore+1][2];
static bool Initialized = false;
if (Initialized) {
return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
}
Initialized = true;
#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \
do { \
OpTypes[OP][0] = OPTYPE0; \
OpTypes[OP][1] = OPTYPE1; \
} while (false)
#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None)
#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None)
DECLARE_OP1(DW_CFA_set_loc, OT_Address);
DECLARE_OP1(DW_CFA_advance_loc, OT_FactoredCodeOffset);
DECLARE_OP1(DW_CFA_advance_loc1, OT_FactoredCodeOffset);
DECLARE_OP1(DW_CFA_advance_loc2, OT_FactoredCodeOffset);
DECLARE_OP1(DW_CFA_advance_loc4, OT_FactoredCodeOffset);
DECLARE_OP1(DW_CFA_MIPS_advance_loc8, OT_FactoredCodeOffset);
DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset);
DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset);
DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register);
DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset);
DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset);
DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression);
DECLARE_OP1(DW_CFA_undefined, OT_Register);
DECLARE_OP1(DW_CFA_same_value, OT_Register);
DECLARE_OP2(DW_CFA_offset, OT_Register, OT_UnsignedFactDataOffset);
DECLARE_OP2(DW_CFA_offset_extended, OT_Register, OT_UnsignedFactDataOffset);
DECLARE_OP2(DW_CFA_offset_extended_sf, OT_Register, OT_SignedFactDataOffset);
DECLARE_OP2(DW_CFA_val_offset, OT_Register, OT_UnsignedFactDataOffset);
DECLARE_OP2(DW_CFA_val_offset_sf, OT_Register, OT_SignedFactDataOffset);
DECLARE_OP2(DW_CFA_register, OT_Register, OT_Register);
DECLARE_OP2(DW_CFA_expression, OT_Register, OT_Expression);
DECLARE_OP2(DW_CFA_val_expression, OT_Register, OT_Expression);
DECLARE_OP1(DW_CFA_restore, OT_Register);
DECLARE_OP1(DW_CFA_restore_extended, OT_Register);
DECLARE_OP0(DW_CFA_remember_state);
DECLARE_OP0(DW_CFA_restore_state);
DECLARE_OP0(DW_CFA_GNU_window_save);
DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset);
DECLARE_OP0(DW_CFA_nop);
#undef DECLARE_OP0
#undef DECLARE_OP1
#undef DECLARE_OP2
return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
}
/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
void CFIProgram::printOperand(raw_ostream &OS, const MCRegisterInfo *MRI,
bool IsEH, const Instruction &Instr,
unsigned OperandIdx, uint64_t Operand) const {
assert(OperandIdx < 2);
uint8_t Opcode = Instr.Opcode;
OperandType Type = getOperandTypes()[Opcode][OperandIdx];
switch (Type) {
case OT_Unset: {
OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to";
auto OpcodeName = CallFrameString(Opcode, Arch);
if (!OpcodeName.empty())
OS << " " << OpcodeName;
else
OS << format(" Opcode %x", Opcode);
break;
}
case OT_None:
break;
case OT_Address:
OS << format(" %" PRIx64, Operand);
break;
case OT_Offset:
// The offsets are all encoded in a unsigned form, but in practice
// consumers use them signed. It's most certainly legacy due to
// the lack of signed variants in the first Dwarf standards.
OS << format(" %+" PRId64, int64_t(Operand));
break;
case OT_FactoredCodeOffset: // Always Unsigned
if (CodeAlignmentFactor)
OS << format(" %" PRId64, Operand * CodeAlignmentFactor);
else
OS << format(" %" PRId64 "*code_alignment_factor" , Operand);
break;
case OT_SignedFactDataOffset:
if (DataAlignmentFactor)
OS << format(" %" PRId64, int64_t(Operand) * DataAlignmentFactor);
else
OS << format(" %" PRId64 "*data_alignment_factor" , int64_t(Operand));
break;
case OT_UnsignedFactDataOffset:
if (DataAlignmentFactor)
OS << format(" %" PRId64, Operand * DataAlignmentFactor);
else
OS << format(" %" PRId64 "*data_alignment_factor" , Operand);
break;
case OT_Register:
OS << format(" reg%" PRId64, Operand);
break;
case OT_Expression:
assert(Instr.Expression && "missing DWARFExpression object");
OS << " ";
Instr.Expression->print(OS, MRI, IsEH);
break;
}
}
void CFIProgram::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
unsigned IndentLevel) const {
for (const auto &Instr : Instructions) {
uint8_t Opcode = Instr.Opcode;
if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
OS.indent(2 * IndentLevel);
OS << CallFrameString(Opcode, Arch) << ":";
for (unsigned i = 0; i < Instr.Ops.size(); ++i)
printOperand(OS, MRI, IsEH, Instr, i, Instr.Ops[i]);
OS << '\n';
}
}
void CIE::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH) const {
OS << format("%08x %08x %08x CIE", (uint32_t)Offset, (uint32_t)Length,
DW_CIE_ID)
<< "\n";
OS << format(" Version: %d\n", Version);
OS << " Augmentation: \"" << Augmentation << "\"\n";
if (Version >= 4) {
OS << format(" Address size: %u\n", (uint32_t)AddressSize);
OS << format(" Segment desc size: %u\n",
(uint32_t)SegmentDescriptorSize);
}
OS << format(" Code alignment factor: %u\n", (uint32_t)CodeAlignmentFactor);
OS << format(" Data alignment factor: %d\n", (int32_t)DataAlignmentFactor);
OS << format(" Return address column: %d\n", (int32_t)ReturnAddressRegister);
if (Personality)
- OS << format(" Personality Address: %08x\n", *Personality);
+ OS << format(" Personality Address: %016" PRIx64 "\n", *Personality);
if (!AugmentationData.empty()) {
OS << " Augmentation data: ";
for (uint8_t Byte : AugmentationData)
OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf);
OS << "\n";
}
OS << "\n";
CFIs.dump(OS, MRI, IsEH);
OS << "\n";
}
void FDE::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH) const {
OS << format("%08x %08x %08x FDE ", (uint32_t)Offset, (uint32_t)Length,
(int32_t)LinkedCIEOffset);
OS << format("cie=%08x pc=%08x...%08x\n", (int32_t)LinkedCIEOffset,
(uint32_t)InitialLocation,
(uint32_t)InitialLocation + (uint32_t)AddressRange);
if (LSDAAddress)
- OS << format(" LSDA Address: %08x\n", *LSDAAddress);
+ OS << format(" LSDA Address: %016" PRIx64 "\n", *LSDAAddress);
CFIs.dump(OS, MRI, IsEH);
OS << "\n";
}
DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch,
bool IsEH, uint64_t EHFrameAddress)
: Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}
DWARFDebugFrame::~DWARFDebugFrame() = default;
static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
uint32_t Offset, int Length) {
errs() << "DUMP: ";
for (int i = 0; i < Length; ++i) {
uint8_t c = Data.getU8(&Offset);
errs().write_hex(c); errs() << " ";
}
errs() << "\n";
}
// This is a workaround for old compilers which do not allow
// noreturn attribute usage in lambdas. Once the support for those
// compilers are phased out, we can remove this and return back to
// a ReportError lambda: [StartOffset](const char *ErrorMsg).
static void LLVM_ATTRIBUTE_NORETURN ReportError(uint32_t StartOffset,
const char *ErrorMsg) {
std::string Str;
raw_string_ostream OS(Str);
OS << format(ErrorMsg, StartOffset);
OS.flush();
report_fatal_error(Str);
}
void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
uint32_t Offset = 0;
DenseMap<uint32_t, CIE *> CIEs;
while (Data.isValidOffset(Offset)) {
uint32_t StartOffset = Offset;
bool IsDWARF64 = false;
uint64_t Length = Data.getU32(&Offset);
uint64_t Id;
if (Length == UINT32_MAX) {
// DWARF-64 is distinguished by the first 32 bits of the initial length
// field being 0xffffffff. Then, the next 64 bits are the actual entry
// length.
IsDWARF64 = true;
Length = Data.getU64(&Offset);
}
// At this point, Offset points to the next field after Length.
// Length is the structure size excluding itself. Compute an offset one
// past the end of the structure (needed to know how many instructions to
// read).
// TODO: For honest DWARF64 support, DataExtractor will have to treat
// offset_ptr as uint64_t*
uint32_t StartStructureOffset = Offset;
uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length);
// The Id field's size depends on the DWARF format
Id = Data.getUnsigned(&Offset, (IsDWARF64 && !IsEH) ? 8 : 4);
bool IsCIE =
((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID || (IsEH && !Id));
if (IsCIE) {
uint8_t Version = Data.getU8(&Offset);
const char *Augmentation = Data.getCStr(&Offset);
StringRef AugmentationString(Augmentation ? Augmentation : "");
uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
Data.getU8(&Offset);
Data.setAddressSize(AddressSize);
uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);
uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
uint64_t ReturnAddressRegister =
Version == 1 ? Data.getU8(&Offset) : Data.getULEB128(&Offset);
// Parse the augmentation data for EH CIEs
StringRef AugmentationData("");
uint32_t FDEPointerEncoding = DW_EH_PE_absptr;
uint32_t LSDAPointerEncoding = DW_EH_PE_omit;
Optional<uint64_t> Personality;
Optional<uint32_t> PersonalityEncoding;
if (IsEH) {
Optional<uint64_t> AugmentationLength;
uint32_t StartAugmentationOffset;
uint32_t EndAugmentationOffset;
// Walk the augmentation string to get all the augmentation data.
for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
switch (AugmentationString[i]) {
default:
ReportError(StartOffset,
"Unknown augmentation character in entry at %lx");
case 'L':
LSDAPointerEncoding = Data.getU8(&Offset);
break;
case 'P': {
if (Personality)
ReportError(StartOffset,
"Duplicate personality in entry at %lx");
PersonalityEncoding = Data.getU8(&Offset);
Personality = Data.getEncodedPointer(
&Offset, *PersonalityEncoding,
EHFrameAddress ? EHFrameAddress + Offset : 0);
break;
}
case 'R':
FDEPointerEncoding = Data.getU8(&Offset);
break;
case 'S':
// Current frame is a signal trampoline.
break;
case 'z':
if (i)
ReportError(StartOffset,
"'z' must be the first character at %lx");
// Parse the augmentation length first. We only parse it if
// the string contains a 'z'.
AugmentationLength = Data.getULEB128(&Offset);
StartAugmentationOffset = Offset;
EndAugmentationOffset = Offset +
static_cast<uint32_t>(*AugmentationLength);
break;
case 'B':
// B-Key is used for signing functions associated with this
// augmentation string
break;
}
}
if (AugmentationLength.hasValue()) {
if (Offset != EndAugmentationOffset)
ReportError(StartOffset, "Parsing augmentation data at %lx failed");
AugmentationData = Data.getData().slice(StartAugmentationOffset,
EndAugmentationOffset);
}
}
auto Cie = llvm::make_unique<CIE>(
StartOffset, Length, Version, AugmentationString, AddressSize,
SegmentDescriptorSize, CodeAlignmentFactor, DataAlignmentFactor,
ReturnAddressRegister, AugmentationData, FDEPointerEncoding,
LSDAPointerEncoding, Personality, PersonalityEncoding, Arch);
CIEs[StartOffset] = Cie.get();
Entries.emplace_back(std::move(Cie));
} else {
// FDE
uint64_t CIEPointer = Id;
uint64_t InitialLocation = 0;
uint64_t AddressRange = 0;
Optional<uint64_t> LSDAAddress;
CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
if (IsEH) {
// The address size is encoded in the CIE we reference.
if (!Cie)
ReportError(StartOffset,
"Parsing FDE data at %lx failed due to missing CIE");
if (auto Val = Data.getEncodedPointer(
&Offset, Cie->getFDEPointerEncoding(),
EHFrameAddress ? EHFrameAddress + Offset : 0)) {
InitialLocation = *Val;
}
if (auto Val = Data.getEncodedPointer(
&Offset, Cie->getFDEPointerEncoding(), 0)) {
AddressRange = *Val;
}
StringRef AugmentationString = Cie->getAugmentationString();
if (!AugmentationString.empty()) {
// Parse the augmentation length and data for this FDE.
uint64_t AugmentationLength = Data.getULEB128(&Offset);
uint32_t EndAugmentationOffset =
Offset + static_cast<uint32_t>(AugmentationLength);
// Decode the LSDA if the CIE augmentation string said we should.
if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) {
LSDAAddress = Data.getEncodedPointer(
&Offset, Cie->getLSDAPointerEncoding(),
EHFrameAddress ? Offset + EHFrameAddress : 0);
}
if (Offset != EndAugmentationOffset)
ReportError(StartOffset, "Parsing augmentation data at %lx failed");
}
} else {
InitialLocation = Data.getAddress(&Offset);
AddressRange = Data.getAddress(&Offset);
}
Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer,
InitialLocation, AddressRange,
Cie, LSDAAddress, Arch));
}
if (Error E =
Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset)) {
report_fatal_error(toString(std::move(E)));
}
if (Offset != EndStructureOffset)
ReportError(StartOffset, "Parsing entry instructions at %lx failed");
}
}
FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {
auto It =
std::lower_bound(Entries.begin(), Entries.end(), Offset,
[](const std::unique_ptr<FrameEntry> &E,
uint64_t Offset) { return E->getOffset() < Offset; });
if (It != Entries.end() && (*It)->getOffset() == Offset)
return It->get();
return nullptr;
}
void DWARFDebugFrame::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
Optional<uint64_t> Offset) const {
if (Offset) {
if (auto *Entry = getEntryAtOffset(*Offset))
Entry->dump(OS, MRI, IsEH);
return;
}
OS << "\n";
for (const auto &Entry : Entries)
Entry->dump(OS, MRI, IsEH);
}
Index: stable/11/contrib/llvm/lib/MC/ELFObjectWriter.cpp
===================================================================
--- stable/11/contrib/llvm/lib/MC/ELFObjectWriter.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/MC/ELFObjectWriter.cpp (revision 350259)
@@ -1,1545 +1,1546 @@
//===- lib/MC/ELFObjectWriter.cpp - ELF File Writer -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements ELF object file writer information.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCFragment.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCSymbolELF.h"
#include "llvm/MC/MCValue.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SMLoc.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/SwapByteOrder.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
using namespace llvm;
#undef DEBUG_TYPE
#define DEBUG_TYPE "reloc-info"
namespace {
using SectionIndexMapTy = DenseMap<const MCSectionELF *, uint32_t>;
class ELFObjectWriter;
struct ELFWriter;
bool isDwoSection(const MCSectionELF &Sec) {
return Sec.getSectionName().endswith(".dwo");
}
class SymbolTableWriter {
ELFWriter &EWriter;
bool Is64Bit;
// indexes we are going to write to .symtab_shndx.
std::vector<uint32_t> ShndxIndexes;
// The numbel of symbols written so far.
unsigned NumWritten;
void createSymtabShndx();
template <typename T> void write(T Value);
public:
SymbolTableWriter(ELFWriter &EWriter, bool Is64Bit);
void writeSymbol(uint32_t name, uint8_t info, uint64_t value, uint64_t size,
uint8_t other, uint32_t shndx, bool Reserved);
ArrayRef<uint32_t> getShndxIndexes() const { return ShndxIndexes; }
};
struct ELFWriter {
ELFObjectWriter &OWriter;
support::endian::Writer W;
enum DwoMode {
AllSections,
NonDwoOnly,
DwoOnly,
} Mode;
static uint64_t SymbolValue(const MCSymbol &Sym, const MCAsmLayout &Layout);
static bool isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol,
bool Used, bool Renamed);
/// Helper struct for containing some precomputed information on symbols.
struct ELFSymbolData {
const MCSymbolELF *Symbol;
uint32_t SectionIndex;
StringRef Name;
// Support lexicographic sorting.
bool operator<(const ELFSymbolData &RHS) const {
unsigned LHSType = Symbol->getType();
unsigned RHSType = RHS.Symbol->getType();
if (LHSType == ELF::STT_SECTION && RHSType != ELF::STT_SECTION)
return false;
if (LHSType != ELF::STT_SECTION && RHSType == ELF::STT_SECTION)
return true;
if (LHSType == ELF::STT_SECTION && RHSType == ELF::STT_SECTION)
return SectionIndex < RHS.SectionIndex;
return Name < RHS.Name;
}
};
/// @}
/// @name Symbol Table Data
/// @{
StringTableBuilder StrTabBuilder{StringTableBuilder::ELF};
/// @}
// This holds the symbol table index of the last local symbol.
unsigned LastLocalSymbolIndex;
// This holds the .strtab section index.
unsigned StringTableIndex;
// This holds the .symtab section index.
unsigned SymbolTableIndex;
// Sections in the order they are to be output in the section table.
std::vector<const MCSectionELF *> SectionTable;
unsigned addToSectionTable(const MCSectionELF *Sec);
// TargetObjectWriter wrappers.
bool is64Bit() const;
bool hasRelocationAddend() const;
void align(unsigned Alignment);
bool maybeWriteCompression(uint64_t Size,
SmallVectorImpl<char> &CompressedContents,
bool ZLibStyle, unsigned Alignment);
public:
ELFWriter(ELFObjectWriter &OWriter, raw_pwrite_stream &OS,
bool IsLittleEndian, DwoMode Mode)
: OWriter(OWriter),
W(OS, IsLittleEndian ? support::little : support::big), Mode(Mode) {}
void WriteWord(uint64_t Word) {
if (is64Bit())
W.write<uint64_t>(Word);
else
W.write<uint32_t>(Word);
}
template <typename T> void write(T Val) {
W.write(Val);
}
void writeHeader(const MCAssembler &Asm);
void writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex,
ELFSymbolData &MSD, const MCAsmLayout &Layout);
// Start and end offset of each section
using SectionOffsetsTy =
std::map<const MCSectionELF *, std::pair<uint64_t, uint64_t>>;
// Map from a signature symbol to the group section index
using RevGroupMapTy = DenseMap<const MCSymbol *, unsigned>;
/// Compute the symbol table data
///
/// \param Asm - The assembler.
/// \param SectionIndexMap - Maps a section to its index.
/// \param RevGroupMap - Maps a signature symbol to the group section.
void computeSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout,
const SectionIndexMapTy &SectionIndexMap,
const RevGroupMapTy &RevGroupMap,
SectionOffsetsTy &SectionOffsets);
void writeAddrsigSection();
MCSectionELF *createRelocationSection(MCContext &Ctx,
const MCSectionELF &Sec);
const MCSectionELF *createStringTable(MCContext &Ctx);
void writeSectionHeader(const MCAsmLayout &Layout,
const SectionIndexMapTy &SectionIndexMap,
const SectionOffsetsTy &SectionOffsets);
void writeSectionData(const MCAssembler &Asm, MCSection &Sec,
const MCAsmLayout &Layout);
void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags,
uint64_t Address, uint64_t Offset, uint64_t Size,
uint32_t Link, uint32_t Info, uint64_t Alignment,
uint64_t EntrySize);
void writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec);
uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout);
void writeSection(const SectionIndexMapTy &SectionIndexMap,
uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size,
const MCSectionELF &Section);
};
class ELFObjectWriter : public MCObjectWriter {
/// The target specific ELF writer instance.
std::unique_ptr<MCELFObjectTargetWriter> TargetObjectWriter;
DenseMap<const MCSectionELF *, std::vector<ELFRelocationEntry>> Relocations;
DenseMap<const MCSymbolELF *, const MCSymbolELF *> Renames;
bool EmitAddrsigSection = false;
std::vector<const MCSymbol *> AddrsigSyms;
bool hasRelocationAddend() const;
bool shouldRelocateWithSymbol(const MCAssembler &Asm,
const MCSymbolRefExpr *RefA,
const MCSymbolELF *Sym, uint64_t C,
unsigned Type) const;
public:
ELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW)
: TargetObjectWriter(std::move(MOTW)) {}
void reset() override {
Relocations.clear();
Renames.clear();
MCObjectWriter::reset();
}
bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
const MCSymbol &SymA,
const MCFragment &FB, bool InSet,
bool IsPCRel) const override;
virtual bool checkRelocation(MCContext &Ctx, SMLoc Loc,
const MCSectionELF *From,
const MCSectionELF *To) {
return true;
}
void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
const MCFragment *Fragment, const MCFixup &Fixup,
MCValue Target, uint64_t &FixedValue) override;
void executePostLayoutBinding(MCAssembler &Asm,
const MCAsmLayout &Layout) override;
void emitAddrsigSection() override { EmitAddrsigSection = true; }
void addAddrsigSymbol(const MCSymbol *Sym) override {
AddrsigSyms.push_back(Sym);
}
friend struct ELFWriter;
};
class ELFSingleObjectWriter : public ELFObjectWriter {
raw_pwrite_stream &OS;
bool IsLittleEndian;
public:
ELFSingleObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
raw_pwrite_stream &OS, bool IsLittleEndian)
: ELFObjectWriter(std::move(MOTW)), OS(OS),
IsLittleEndian(IsLittleEndian) {}
uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override {
return ELFWriter(*this, OS, IsLittleEndian, ELFWriter::AllSections)
.writeObject(Asm, Layout);
}
friend struct ELFWriter;
};
class ELFDwoObjectWriter : public ELFObjectWriter {
raw_pwrite_stream &OS, &DwoOS;
bool IsLittleEndian;
public:
ELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS,
bool IsLittleEndian)
: ELFObjectWriter(std::move(MOTW)), OS(OS), DwoOS(DwoOS),
IsLittleEndian(IsLittleEndian) {}
virtual bool checkRelocation(MCContext &Ctx, SMLoc Loc,
const MCSectionELF *From,
const MCSectionELF *To) override {
if (isDwoSection(*From)) {
Ctx.reportError(Loc, "A dwo section may not contain relocations");
return false;
}
if (To && isDwoSection(*To)) {
Ctx.reportError(Loc, "A relocation may not refer to a dwo section");
return false;
}
return true;
}
uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override {
uint64_t Size = ELFWriter(*this, OS, IsLittleEndian, ELFWriter::NonDwoOnly)
.writeObject(Asm, Layout);
Size += ELFWriter(*this, DwoOS, IsLittleEndian, ELFWriter::DwoOnly)
.writeObject(Asm, Layout);
return Size;
}
};
} // end anonymous namespace
void ELFWriter::align(unsigned Alignment) {
uint64_t Padding = OffsetToAlignment(W.OS.tell(), Alignment);
W.OS.write_zeros(Padding);
}
unsigned ELFWriter::addToSectionTable(const MCSectionELF *Sec) {
SectionTable.push_back(Sec);
StrTabBuilder.add(Sec->getSectionName());
return SectionTable.size();
}
void SymbolTableWriter::createSymtabShndx() {
if (!ShndxIndexes.empty())
return;
ShndxIndexes.resize(NumWritten);
}
template <typename T> void SymbolTableWriter::write(T Value) {
EWriter.write(Value);
}
SymbolTableWriter::SymbolTableWriter(ELFWriter &EWriter, bool Is64Bit)
: EWriter(EWriter), Is64Bit(Is64Bit), NumWritten(0) {}
void SymbolTableWriter::writeSymbol(uint32_t name, uint8_t info, uint64_t value,
uint64_t size, uint8_t other,
uint32_t shndx, bool Reserved) {
bool LargeIndex = shndx >= ELF::SHN_LORESERVE && !Reserved;
if (LargeIndex)
createSymtabShndx();
if (!ShndxIndexes.empty()) {
if (LargeIndex)
ShndxIndexes.push_back(shndx);
else
ShndxIndexes.push_back(0);
}
uint16_t Index = LargeIndex ? uint16_t(ELF::SHN_XINDEX) : shndx;
if (Is64Bit) {
write(name); // st_name
write(info); // st_info
write(other); // st_other
write(Index); // st_shndx
write(value); // st_value
write(size); // st_size
} else {
write(name); // st_name
write(uint32_t(value)); // st_value
write(uint32_t(size)); // st_size
write(info); // st_info
write(other); // st_other
write(Index); // st_shndx
}
++NumWritten;
}
bool ELFWriter::is64Bit() const {
return OWriter.TargetObjectWriter->is64Bit();
}
bool ELFWriter::hasRelocationAddend() const {
return OWriter.hasRelocationAddend();
}
// Emit the ELF header.
void ELFWriter::writeHeader(const MCAssembler &Asm) {
// ELF Header
// ----------
//
// Note
// ----
// emitWord method behaves differently for ELF32 and ELF64, writing
// 4 bytes in the former and 8 in the latter.
W.OS << ELF::ElfMagic; // e_ident[EI_MAG0] to e_ident[EI_MAG3]
W.OS << char(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS]
// e_ident[EI_DATA]
W.OS << char(W.Endian == support::little ? ELF::ELFDATA2LSB
: ELF::ELFDATA2MSB);
W.OS << char(ELF::EV_CURRENT); // e_ident[EI_VERSION]
// e_ident[EI_OSABI]
W.OS << char(OWriter.TargetObjectWriter->getOSABI());
W.OS << char(0); // e_ident[EI_ABIVERSION]
W.OS.write_zeros(ELF::EI_NIDENT - ELF::EI_PAD);
W.write<uint16_t>(ELF::ET_REL); // e_type
W.write<uint16_t>(OWriter.TargetObjectWriter->getEMachine()); // e_machine = target
W.write<uint32_t>(ELF::EV_CURRENT); // e_version
WriteWord(0); // e_entry, no entry point in .o file
WriteWord(0); // e_phoff, no program header for .o
WriteWord(0); // e_shoff = sec hdr table off in bytes
// e_flags = whatever the target wants
W.write<uint32_t>(Asm.getELFHeaderEFlags());
// e_ehsize = ELF header size
W.write<uint16_t>(is64Bit() ? sizeof(ELF::Elf64_Ehdr)
: sizeof(ELF::Elf32_Ehdr));
W.write<uint16_t>(0); // e_phentsize = prog header entry size
W.write<uint16_t>(0); // e_phnum = # prog header entries = 0
// e_shentsize = Section header entry size
W.write<uint16_t>(is64Bit() ? sizeof(ELF::Elf64_Shdr)
: sizeof(ELF::Elf32_Shdr));
// e_shnum = # of section header ents
W.write<uint16_t>(0);
// e_shstrndx = Section # of '.shstrtab'
assert(StringTableIndex < ELF::SHN_LORESERVE);
W.write<uint16_t>(StringTableIndex);
}
uint64_t ELFWriter::SymbolValue(const MCSymbol &Sym,
const MCAsmLayout &Layout) {
if (Sym.isCommon() && Sym.isExternal())
return Sym.getCommonAlignment();
uint64_t Res;
if (!Layout.getSymbolOffset(Sym, Res))
return 0;
if (Layout.getAssembler().isThumbFunc(&Sym))
Res |= 1;
return Res;
}
static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) {
uint8_t Type = newType;
// Propagation rules:
// IFUNC > FUNC > OBJECT > NOTYPE
// TLS_OBJECT > OBJECT > NOTYPE
//
// dont let the new type degrade the old type
switch (origType) {
default:
break;
case ELF::STT_GNU_IFUNC:
if (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT ||
Type == ELF::STT_NOTYPE || Type == ELF::STT_TLS)
Type = ELF::STT_GNU_IFUNC;
break;
case ELF::STT_FUNC:
if (Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE ||
Type == ELF::STT_TLS)
Type = ELF::STT_FUNC;
break;
case ELF::STT_OBJECT:
if (Type == ELF::STT_NOTYPE)
Type = ELF::STT_OBJECT;
break;
case ELF::STT_TLS:
if (Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE ||
Type == ELF::STT_GNU_IFUNC || Type == ELF::STT_FUNC)
Type = ELF::STT_TLS;
break;
}
return Type;
}
void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex,
ELFSymbolData &MSD, const MCAsmLayout &Layout) {
const auto &Symbol = cast<MCSymbolELF>(*MSD.Symbol);
const MCSymbolELF *Base =
cast_or_null<MCSymbolELF>(Layout.getBaseSymbol(Symbol));
// This has to be in sync with when computeSymbolTable uses SHN_ABS or
// SHN_COMMON.
bool IsReserved = !Base || Symbol.isCommon();
// Binding and Type share the same byte as upper and lower nibbles
uint8_t Binding = Symbol.getBinding();
uint8_t Type = Symbol.getType();
if (Base) {
Type = mergeTypeForSet(Type, Base->getType());
}
uint8_t Info = (Binding << 4) | Type;
// Other and Visibility share the same byte with Visibility using the lower
// 2 bits
uint8_t Visibility = Symbol.getVisibility();
uint8_t Other = Symbol.getOther() | Visibility;
uint64_t Value = SymbolValue(*MSD.Symbol, Layout);
uint64_t Size = 0;
const MCExpr *ESize = MSD.Symbol->getSize();
if (!ESize && Base)
ESize = Base->getSize();
if (ESize) {
int64_t Res;
if (!ESize->evaluateKnownAbsolute(Res, Layout))
report_fatal_error("Size expression must be absolute.");
Size = Res;
}
// Write out the symbol table entry
Writer.writeSymbol(StringIndex, Info, Value, Size, Other, MSD.SectionIndex,
IsReserved);
}
// True if the assembler knows nothing about the final value of the symbol.
// This doesn't cover the comdat issues, since in those cases the assembler
// can at least know that all symbols in the section will move together.
static bool isWeak(const MCSymbolELF &Sym) {
if (Sym.getType() == ELF::STT_GNU_IFUNC)
return true;
switch (Sym.getBinding()) {
default:
llvm_unreachable("Unknown binding");
case ELF::STB_LOCAL:
return false;
case ELF::STB_GLOBAL:
return false;
case ELF::STB_WEAK:
case ELF::STB_GNU_UNIQUE:
return true;
}
}
bool ELFWriter::isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol,
bool Used, bool Renamed) {
if (Symbol.isVariable()) {
const MCExpr *Expr = Symbol.getVariableValue();
if (const MCSymbolRefExpr *Ref = dyn_cast<MCSymbolRefExpr>(Expr)) {
if (Ref->getKind() == MCSymbolRefExpr::VK_WEAKREF)
return false;
}
}
if (Used)
return true;
if (Renamed)
return false;
if (Symbol.isVariable() && Symbol.isUndefined()) {
// FIXME: this is here just to diagnose the case of a var = commmon_sym.
Layout.getBaseSymbol(Symbol);
return false;
}
if (Symbol.isUndefined() && !Symbol.isBindingSet())
return false;
if (Symbol.isTemporary())
return false;
if (Symbol.getType() == ELF::STT_SECTION)
return false;
return true;
}
void ELFWriter::computeSymbolTable(
MCAssembler &Asm, const MCAsmLayout &Layout,
const SectionIndexMapTy &SectionIndexMap, const RevGroupMapTy &RevGroupMap,
SectionOffsetsTy &SectionOffsets) {
MCContext &Ctx = Asm.getContext();
SymbolTableWriter Writer(*this, is64Bit());
// Symbol table
unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32;
MCSectionELF *SymtabSection =
Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, EntrySize, "");
SymtabSection->setAlignment(is64Bit() ? 8 : 4);
SymbolTableIndex = addToSectionTable(SymtabSection);
align(SymtabSection->getAlignment());
uint64_t SecStart = W.OS.tell();
// The first entry is the undefined symbol entry.
Writer.writeSymbol(0, 0, 0, 0, 0, 0, false);
std::vector<ELFSymbolData> LocalSymbolData;
std::vector<ELFSymbolData> ExternalSymbolData;
// Add the data for the symbols.
bool HasLargeSectionIndex = false;
for (const MCSymbol &S : Asm.symbols()) {
const auto &Symbol = cast<MCSymbolELF>(S);
bool Used = Symbol.isUsedInReloc();
bool WeakrefUsed = Symbol.isWeakrefUsedInReloc();
bool isSignature = Symbol.isSignature();
if (!isInSymtab(Layout, Symbol, Used || WeakrefUsed || isSignature,
OWriter.Renames.count(&Symbol)))
continue;
if (Symbol.isTemporary() && Symbol.isUndefined()) {
Ctx.reportError(SMLoc(), "Undefined temporary symbol");
continue;
}
ELFSymbolData MSD;
MSD.Symbol = cast<MCSymbolELF>(&Symbol);
bool Local = Symbol.getBinding() == ELF::STB_LOCAL;
assert(Local || !Symbol.isTemporary());
if (Symbol.isAbsolute()) {
MSD.SectionIndex = ELF::SHN_ABS;
} else if (Symbol.isCommon()) {
assert(!Local);
MSD.SectionIndex = ELF::SHN_COMMON;
} else if (Symbol.isUndefined()) {
if (isSignature && !Used) {
MSD.SectionIndex = RevGroupMap.lookup(&Symbol);
if (MSD.SectionIndex >= ELF::SHN_LORESERVE)
HasLargeSectionIndex = true;
} else {
MSD.SectionIndex = ELF::SHN_UNDEF;
}
} else {
const MCSectionELF &Section =
static_cast<const MCSectionELF &>(Symbol.getSection());
// We may end up with a situation when section symbol is technically
// defined, but should not be. That happens because we explicitly
// pre-create few .debug_* sections to have accessors.
// And if these sections were not really defined in the code, but were
// referenced, we simply error out.
if (!Section.isRegistered()) {
assert(static_cast<const MCSymbolELF &>(Symbol).getType() ==
ELF::STT_SECTION);
Ctx.reportError(SMLoc(),
"Undefined section reference: " + Symbol.getName());
continue;
}
if (Mode == NonDwoOnly && isDwoSection(Section))
continue;
MSD.SectionIndex = SectionIndexMap.lookup(&Section);
assert(MSD.SectionIndex && "Invalid section index!");
if (MSD.SectionIndex >= ELF::SHN_LORESERVE)
HasLargeSectionIndex = true;
}
StringRef Name = Symbol.getName();
// Sections have their own string table
if (Symbol.getType() != ELF::STT_SECTION) {
MSD.Name = Name;
StrTabBuilder.add(Name);
}
if (Local)
LocalSymbolData.push_back(MSD);
else
ExternalSymbolData.push_back(MSD);
}
// This holds the .symtab_shndx section index.
unsigned SymtabShndxSectionIndex = 0;
if (HasLargeSectionIndex) {
MCSectionELF *SymtabShndxSection =
Ctx.getELFSection(".symtab_shndxr", ELF::SHT_SYMTAB_SHNDX, 0, 4, "");
SymtabShndxSectionIndex = addToSectionTable(SymtabShndxSection);
SymtabShndxSection->setAlignment(4);
}
ArrayRef<std::string> FileNames = Asm.getFileNames();
for (const std::string &Name : FileNames)
StrTabBuilder.add(Name);
StrTabBuilder.finalize();
// File symbols are emitted first and handled separately from normal symbols,
// i.e. a non-STT_FILE symbol with the same name may appear.
for (const std::string &Name : FileNames)
Writer.writeSymbol(StrTabBuilder.getOffset(Name),
ELF::STT_FILE | ELF::STB_LOCAL, 0, 0, ELF::STV_DEFAULT,
ELF::SHN_ABS, true);
// Symbols are required to be in lexicographic order.
array_pod_sort(LocalSymbolData.begin(), LocalSymbolData.end());
array_pod_sort(ExternalSymbolData.begin(), ExternalSymbolData.end());
// Set the symbol indices. Local symbols must come before all other
// symbols with non-local bindings.
unsigned Index = FileNames.size() + 1;
for (ELFSymbolData &MSD : LocalSymbolData) {
unsigned StringIndex = MSD.Symbol->getType() == ELF::STT_SECTION
? 0
: StrTabBuilder.getOffset(MSD.Name);
MSD.Symbol->setIndex(Index++);
writeSymbol(Writer, StringIndex, MSD, Layout);
}
// Write the symbol table entries.
LastLocalSymbolIndex = Index;
for (ELFSymbolData &MSD : ExternalSymbolData) {
unsigned StringIndex = StrTabBuilder.getOffset(MSD.Name);
MSD.Symbol->setIndex(Index++);
writeSymbol(Writer, StringIndex, MSD, Layout);
assert(MSD.Symbol->getBinding() != ELF::STB_LOCAL);
}
uint64_t SecEnd = W.OS.tell();
SectionOffsets[SymtabSection] = std::make_pair(SecStart, SecEnd);
ArrayRef<uint32_t> ShndxIndexes = Writer.getShndxIndexes();
if (ShndxIndexes.empty()) {
assert(SymtabShndxSectionIndex == 0);
return;
}
assert(SymtabShndxSectionIndex != 0);
SecStart = W.OS.tell();
const MCSectionELF *SymtabShndxSection =
SectionTable[SymtabShndxSectionIndex - 1];
for (uint32_t Index : ShndxIndexes)
write(Index);
SecEnd = W.OS.tell();
SectionOffsets[SymtabShndxSection] = std::make_pair(SecStart, SecEnd);
}
void ELFWriter::writeAddrsigSection() {
for (const MCSymbol *Sym : OWriter.AddrsigSyms)
encodeULEB128(Sym->getIndex(), W.OS);
}
MCSectionELF *ELFWriter::createRelocationSection(MCContext &Ctx,
const MCSectionELF &Sec) {
if (OWriter.Relocations[&Sec].empty())
return nullptr;
const StringRef SectionName = Sec.getSectionName();
std::string RelaSectionName = hasRelocationAddend() ? ".rela" : ".rel";
RelaSectionName += SectionName;
unsigned EntrySize;
if (hasRelocationAddend())
EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela);
else
EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel);
unsigned Flags = 0;
if (Sec.getFlags() & ELF::SHF_GROUP)
Flags = ELF::SHF_GROUP;
MCSectionELF *RelaSection = Ctx.createELFRelSection(
RelaSectionName, hasRelocationAddend() ? ELF::SHT_RELA : ELF::SHT_REL,
Flags, EntrySize, Sec.getGroup(), &Sec);
RelaSection->setAlignment(is64Bit() ? 8 : 4);
return RelaSection;
}
// Include the debug info compression header.
bool ELFWriter::maybeWriteCompression(
uint64_t Size, SmallVectorImpl<char> &CompressedContents, bool ZLibStyle,
unsigned Alignment) {
if (ZLibStyle) {
uint64_t HdrSize =
is64Bit() ? sizeof(ELF::Elf32_Chdr) : sizeof(ELF::Elf64_Chdr);
if (Size <= HdrSize + CompressedContents.size())
return false;
// Platform specific header is followed by compressed data.
if (is64Bit()) {
// Write Elf64_Chdr header.
write(static_cast<ELF::Elf64_Word>(ELF::ELFCOMPRESS_ZLIB));
write(static_cast<ELF::Elf64_Word>(0)); // ch_reserved field.
write(static_cast<ELF::Elf64_Xword>(Size));
write(static_cast<ELF::Elf64_Xword>(Alignment));
} else {
// Write Elf32_Chdr header otherwise.
write(static_cast<ELF::Elf32_Word>(ELF::ELFCOMPRESS_ZLIB));
write(static_cast<ELF::Elf32_Word>(Size));
write(static_cast<ELF::Elf32_Word>(Alignment));
}
return true;
}
// "ZLIB" followed by 8 bytes representing the uncompressed size of the section,
// useful for consumers to preallocate a buffer to decompress into.
const StringRef Magic = "ZLIB";
if (Size <= Magic.size() + sizeof(Size) + CompressedContents.size())
return false;
W.OS << Magic;
support::endian::write(W.OS, Size, support::big);
return true;
}
void ELFWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec,
const MCAsmLayout &Layout) {
MCSectionELF &Section = static_cast<MCSectionELF &>(Sec);
StringRef SectionName = Section.getSectionName();
auto &MC = Asm.getContext();
const auto &MAI = MC.getAsmInfo();
// Compressing debug_frame requires handling alignment fragments which is
// more work (possibly generalizing MCAssembler.cpp:writeFragment to allow
// for writing to arbitrary buffers) for little benefit.
bool CompressionEnabled =
MAI->compressDebugSections() != DebugCompressionType::None;
if (!CompressionEnabled || !SectionName.startswith(".debug_") ||
SectionName == ".debug_frame") {
Asm.writeSectionData(W.OS, &Section, Layout);
return;
}
assert((MAI->compressDebugSections() == DebugCompressionType::Z ||
MAI->compressDebugSections() == DebugCompressionType::GNU) &&
"expected zlib or zlib-gnu style compression");
SmallVector<char, 128> UncompressedData;
raw_svector_ostream VecOS(UncompressedData);
Asm.writeSectionData(VecOS, &Section, Layout);
SmallVector<char, 128> CompressedContents;
if (Error E = zlib::compress(
StringRef(UncompressedData.data(), UncompressedData.size()),
CompressedContents)) {
consumeError(std::move(E));
W.OS << UncompressedData;
return;
}
bool ZlibStyle = MAI->compressDebugSections() == DebugCompressionType::Z;
if (!maybeWriteCompression(UncompressedData.size(), CompressedContents,
ZlibStyle, Sec.getAlignment())) {
W.OS << UncompressedData;
return;
}
if (ZlibStyle)
// Set the compressed flag. That is zlib style.
Section.setFlags(Section.getFlags() | ELF::SHF_COMPRESSED);
else
// Add "z" prefix to section name. This is zlib-gnu style.
MC.renameELFSection(&Section, (".z" + SectionName.drop_front(1)).str());
W.OS << CompressedContents;
}
void ELFWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags,
uint64_t Address, uint64_t Offset,
uint64_t Size, uint32_t Link, uint32_t Info,
uint64_t Alignment, uint64_t EntrySize) {
W.write<uint32_t>(Name); // sh_name: index into string table
W.write<uint32_t>(Type); // sh_type
WriteWord(Flags); // sh_flags
WriteWord(Address); // sh_addr
WriteWord(Offset); // sh_offset
WriteWord(Size); // sh_size
W.write<uint32_t>(Link); // sh_link
W.write<uint32_t>(Info); // sh_info
WriteWord(Alignment); // sh_addralign
WriteWord(EntrySize); // sh_entsize
}
void ELFWriter::writeRelocations(const MCAssembler &Asm,
const MCSectionELF &Sec) {
std::vector<ELFRelocationEntry> &Relocs = OWriter.Relocations[&Sec];
// We record relocations by pushing to the end of a vector. Reverse the vector
// to get the relocations in the order they were created.
// In most cases that is not important, but it can be for special sections
// (.eh_frame) or specific relocations (TLS optimizations on SystemZ).
std::reverse(Relocs.begin(), Relocs.end());
// Sort the relocation entries. MIPS needs this.
OWriter.TargetObjectWriter->sortRelocs(Asm, Relocs);
for (unsigned i = 0, e = Relocs.size(); i != e; ++i) {
const ELFRelocationEntry &Entry = Relocs[e - i - 1];
unsigned Index = Entry.Symbol ? Entry.Symbol->getIndex() : 0;
if (is64Bit()) {
write(Entry.Offset);
if (OWriter.TargetObjectWriter->getEMachine() == ELF::EM_MIPS) {
write(uint32_t(Index));
write(OWriter.TargetObjectWriter->getRSsym(Entry.Type));
write(OWriter.TargetObjectWriter->getRType3(Entry.Type));
write(OWriter.TargetObjectWriter->getRType2(Entry.Type));
write(OWriter.TargetObjectWriter->getRType(Entry.Type));
} else {
struct ELF::Elf64_Rela ERE64;
ERE64.setSymbolAndType(Index, Entry.Type);
write(ERE64.r_info);
}
if (hasRelocationAddend())
write(Entry.Addend);
} else {
write(uint32_t(Entry.Offset));
struct ELF::Elf32_Rela ERE32;
ERE32.setSymbolAndType(Index, Entry.Type);
write(ERE32.r_info);
if (hasRelocationAddend())
write(uint32_t(Entry.Addend));
if (OWriter.TargetObjectWriter->getEMachine() == ELF::EM_MIPS) {
if (uint32_t RType =
OWriter.TargetObjectWriter->getRType2(Entry.Type)) {
write(uint32_t(Entry.Offset));
ERE32.setSymbolAndType(0, RType);
write(ERE32.r_info);
write(uint32_t(0));
}
if (uint32_t RType =
OWriter.TargetObjectWriter->getRType3(Entry.Type)) {
write(uint32_t(Entry.Offset));
ERE32.setSymbolAndType(0, RType);
write(ERE32.r_info);
write(uint32_t(0));
}
}
}
}
}
const MCSectionELF *ELFWriter::createStringTable(MCContext &Ctx) {
const MCSectionELF *StrtabSection = SectionTable[StringTableIndex - 1];
StrTabBuilder.write(W.OS);
return StrtabSection;
}
void ELFWriter::writeSection(const SectionIndexMapTy &SectionIndexMap,
uint32_t GroupSymbolIndex, uint64_t Offset,
uint64_t Size, const MCSectionELF &Section) {
uint64_t sh_link = 0;
uint64_t sh_info = 0;
switch(Section.getType()) {
default:
// Nothing to do.
break;
case ELF::SHT_DYNAMIC:
llvm_unreachable("SHT_DYNAMIC in a relocatable object");
case ELF::SHT_REL:
case ELF::SHT_RELA: {
sh_link = SymbolTableIndex;
assert(sh_link && ".symtab not found");
const MCSection *InfoSection = Section.getAssociatedSection();
sh_info = SectionIndexMap.lookup(cast<MCSectionELF>(InfoSection));
break;
}
case ELF::SHT_SYMTAB:
sh_link = StringTableIndex;
sh_info = LastLocalSymbolIndex;
break;
case ELF::SHT_SYMTAB_SHNDX:
case ELF::SHT_LLVM_CALL_GRAPH_PROFILE:
case ELF::SHT_LLVM_ADDRSIG:
sh_link = SymbolTableIndex;
break;
case ELF::SHT_GROUP:
sh_link = SymbolTableIndex;
sh_info = GroupSymbolIndex;
break;
}
if (Section.getFlags() & ELF::SHF_LINK_ORDER) {
const MCSymbol *Sym = Section.getAssociatedSymbol();
const MCSectionELF *Sec = cast<MCSectionELF>(&Sym->getSection());
sh_link = SectionIndexMap.lookup(Sec);
}
WriteSecHdrEntry(StrTabBuilder.getOffset(Section.getSectionName()),
Section.getType(), Section.getFlags(), 0, Offset, Size,
sh_link, sh_info, Section.getAlignment(),
Section.getEntrySize());
}
void ELFWriter::writeSectionHeader(
const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap,
const SectionOffsetsTy &SectionOffsets) {
const unsigned NumSections = SectionTable.size();
// Null section first.
uint64_t FirstSectionSize =
(NumSections + 1) >= ELF::SHN_LORESERVE ? NumSections + 1 : 0;
WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, 0, 0, 0, 0);
for (const MCSectionELF *Section : SectionTable) {
uint32_t GroupSymbolIndex;
unsigned Type = Section->getType();
if (Type != ELF::SHT_GROUP)
GroupSymbolIndex = 0;
else
GroupSymbolIndex = Section->getGroup()->getIndex();
const std::pair<uint64_t, uint64_t> &Offsets =
SectionOffsets.find(Section)->second;
uint64_t Size;
if (Type == ELF::SHT_NOBITS)
Size = Layout.getSectionAddressSize(Section);
else
Size = Offsets.second - Offsets.first;
writeSection(SectionIndexMap, GroupSymbolIndex, Offsets.first, Size,
*Section);
}
}
uint64_t ELFWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) {
uint64_t StartOffset = W.OS.tell();
MCContext &Ctx = Asm.getContext();
MCSectionELF *StrtabSection =
Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0);
StringTableIndex = addToSectionTable(StrtabSection);
RevGroupMapTy RevGroupMap;
SectionIndexMapTy SectionIndexMap;
std::map<const MCSymbol *, std::vector<const MCSectionELF *>> GroupMembers;
// Write out the ELF header ...
writeHeader(Asm);
// ... then the sections ...
SectionOffsetsTy SectionOffsets;
std::vector<MCSectionELF *> Groups;
std::vector<MCSectionELF *> Relocations;
for (MCSection &Sec : Asm) {
MCSectionELF &Section = static_cast<MCSectionELF &>(Sec);
if (Mode == NonDwoOnly && isDwoSection(Section))
continue;
if (Mode == DwoOnly && !isDwoSection(Section))
continue;
align(Section.getAlignment());
// Remember the offset into the file for this section.
uint64_t SecStart = W.OS.tell();
const MCSymbolELF *SignatureSymbol = Section.getGroup();
writeSectionData(Asm, Section, Layout);
uint64_t SecEnd = W.OS.tell();
SectionOffsets[&Section] = std::make_pair(SecStart, SecEnd);
MCSectionELF *RelSection = createRelocationSection(Ctx, Section);
if (SignatureSymbol) {
Asm.registerSymbol(*SignatureSymbol);
unsigned &GroupIdx = RevGroupMap[SignatureSymbol];
if (!GroupIdx) {
MCSectionELF *Group = Ctx.createELFGroupSection(SignatureSymbol);
GroupIdx = addToSectionTable(Group);
Group->setAlignment(4);
Groups.push_back(Group);
}
std::vector<const MCSectionELF *> &Members =
GroupMembers[SignatureSymbol];
Members.push_back(&Section);
if (RelSection)
Members.push_back(RelSection);
}
SectionIndexMap[&Section] = addToSectionTable(&Section);
if (RelSection) {
SectionIndexMap[RelSection] = addToSectionTable(RelSection);
Relocations.push_back(RelSection);
}
OWriter.TargetObjectWriter->addTargetSectionFlags(Ctx, Section);
}
MCSectionELF *CGProfileSection = nullptr;
if (!Asm.CGProfile.empty()) {
CGProfileSection = Ctx.getELFSection(".llvm.call-graph-profile",
ELF::SHT_LLVM_CALL_GRAPH_PROFILE,
ELF::SHF_EXCLUDE, 16, "");
SectionIndexMap[CGProfileSection] = addToSectionTable(CGProfileSection);
}
for (MCSectionELF *Group : Groups) {
align(Group->getAlignment());
// Remember the offset into the file for this section.
uint64_t SecStart = W.OS.tell();
const MCSymbol *SignatureSymbol = Group->getGroup();
assert(SignatureSymbol);
write(uint32_t(ELF::GRP_COMDAT));
for (const MCSectionELF *Member : GroupMembers[SignatureSymbol]) {
uint32_t SecIndex = SectionIndexMap.lookup(Member);
write(SecIndex);
}
uint64_t SecEnd = W.OS.tell();
SectionOffsets[Group] = std::make_pair(SecStart, SecEnd);
}
if (Mode == DwoOnly) {
// dwo files don't have symbol tables or relocations, but they do have
// string tables.
StrTabBuilder.finalize();
} else {
MCSectionELF *AddrsigSection;
if (OWriter.EmitAddrsigSection) {
AddrsigSection = Ctx.getELFSection(".llvm_addrsig", ELF::SHT_LLVM_ADDRSIG,
ELF::SHF_EXCLUDE);
addToSectionTable(AddrsigSection);
}
// Compute symbol table information.
computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap,
SectionOffsets);
for (MCSectionELF *RelSection : Relocations) {
align(RelSection->getAlignment());
// Remember the offset into the file for this section.
uint64_t SecStart = W.OS.tell();
writeRelocations(Asm,
cast<MCSectionELF>(*RelSection->getAssociatedSection()));
uint64_t SecEnd = W.OS.tell();
SectionOffsets[RelSection] = std::make_pair(SecStart, SecEnd);
}
if (OWriter.EmitAddrsigSection) {
uint64_t SecStart = W.OS.tell();
writeAddrsigSection();
uint64_t SecEnd = W.OS.tell();
SectionOffsets[AddrsigSection] = std::make_pair(SecStart, SecEnd);
}
}
if (CGProfileSection) {
uint64_t SecStart = W.OS.tell();
for (const MCAssembler::CGProfileEntry &CGPE : Asm.CGProfile) {
W.write<uint32_t>(CGPE.From->getSymbol().getIndex());
W.write<uint32_t>(CGPE.To->getSymbol().getIndex());
W.write<uint64_t>(CGPE.Count);
}
uint64_t SecEnd = W.OS.tell();
SectionOffsets[CGProfileSection] = std::make_pair(SecStart, SecEnd);
}
{
uint64_t SecStart = W.OS.tell();
const MCSectionELF *Sec = createStringTable(Ctx);
uint64_t SecEnd = W.OS.tell();
SectionOffsets[Sec] = std::make_pair(SecStart, SecEnd);
}
uint64_t NaturalAlignment = is64Bit() ? 8 : 4;
align(NaturalAlignment);
const uint64_t SectionHeaderOffset = W.OS.tell();
// ... then the section header table ...
writeSectionHeader(Layout, SectionIndexMap, SectionOffsets);
uint16_t NumSections = support::endian::byte_swap<uint16_t>(
(SectionTable.size() + 1 >= ELF::SHN_LORESERVE) ? (uint16_t)ELF::SHN_UNDEF
: SectionTable.size() + 1,
W.Endian);
unsigned NumSectionsOffset;
auto &Stream = static_cast<raw_pwrite_stream &>(W.OS);
if (is64Bit()) {
uint64_t Val =
support::endian::byte_swap<uint64_t>(SectionHeaderOffset, W.Endian);
Stream.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val),
offsetof(ELF::Elf64_Ehdr, e_shoff));
NumSectionsOffset = offsetof(ELF::Elf64_Ehdr, e_shnum);
} else {
uint32_t Val =
support::endian::byte_swap<uint32_t>(SectionHeaderOffset, W.Endian);
Stream.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val),
offsetof(ELF::Elf32_Ehdr, e_shoff));
NumSectionsOffset = offsetof(ELF::Elf32_Ehdr, e_shnum);
}
Stream.pwrite(reinterpret_cast<char *>(&NumSections), sizeof(NumSections),
NumSectionsOffset);
return W.OS.tell() - StartOffset;
}
bool ELFObjectWriter::hasRelocationAddend() const {
return TargetObjectWriter->hasRelocationAddend();
}
void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
const MCAsmLayout &Layout) {
// The presence of symbol versions causes undefined symbols and
// versions declared with @@@ to be renamed.
for (const std::pair<StringRef, const MCSymbol *> &P : Asm.Symvers) {
StringRef AliasName = P.first;
const auto &Symbol = cast<MCSymbolELF>(*P.second);
size_t Pos = AliasName.find('@');
assert(Pos != StringRef::npos);
StringRef Prefix = AliasName.substr(0, Pos);
StringRef Rest = AliasName.substr(Pos);
StringRef Tail = Rest;
if (Rest.startswith("@@@"))
Tail = Rest.substr(Symbol.isUndefined() ? 2 : 1);
auto *Alias =
cast<MCSymbolELF>(Asm.getContext().getOrCreateSymbol(Prefix + Tail));
Asm.registerSymbol(*Alias);
const MCExpr *Value = MCSymbolRefExpr::create(&Symbol, Asm.getContext());
Alias->setVariableValue(Value);
// Aliases defined with .symvar copy the binding from the symbol they alias.
// This is the first place we are able to copy this information.
Alias->setExternal(Symbol.isExternal());
Alias->setBinding(Symbol.getBinding());
+ Alias->setOther(Symbol.getOther());
if (!Symbol.isUndefined() && !Rest.startswith("@@@"))
continue;
// FIXME: Get source locations for these errors or diagnose them earlier.
if (Symbol.isUndefined() && Rest.startswith("@@") &&
!Rest.startswith("@@@")) {
Asm.getContext().reportError(SMLoc(), "versioned symbol " + AliasName +
" must be defined");
continue;
}
if (Renames.count(&Symbol) && Renames[&Symbol] != Alias) {
Asm.getContext().reportError(
SMLoc(), llvm::Twine("multiple symbol versions defined for ") +
Symbol.getName());
continue;
}
Renames.insert(std::make_pair(&Symbol, Alias));
}
for (const MCSymbol *&Sym : AddrsigSyms) {
if (const MCSymbol *R = Renames.lookup(cast<MCSymbolELF>(Sym)))
Sym = R;
if (Sym->isInSection() && Sym->getName().startswith(".L"))
Sym = Sym->getSection().getBeginSymbol();
Sym->setUsedInReloc();
}
}
// It is always valid to create a relocation with a symbol. It is preferable
// to use a relocation with a section if that is possible. Using the section
// allows us to omit some local symbols from the symbol table.
bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm,
const MCSymbolRefExpr *RefA,
const MCSymbolELF *Sym,
uint64_t C,
unsigned Type) const {
// A PCRel relocation to an absolute value has no symbol (or section). We
// represent that with a relocation to a null section.
if (!RefA)
return false;
MCSymbolRefExpr::VariantKind Kind = RefA->getKind();
switch (Kind) {
default:
break;
// The .odp creation emits a relocation against the symbol ".TOC." which
// create a R_PPC64_TOC relocation. However the relocation symbol name
// in final object creation should be NULL, since the symbol does not
// really exist, it is just the reference to TOC base for the current
// object file. Since the symbol is undefined, returning false results
// in a relocation with a null section which is the desired result.
case MCSymbolRefExpr::VK_PPC_TOCBASE:
return false;
// These VariantKind cause the relocation to refer to something other than
// the symbol itself, like a linker generated table. Since the address of
// symbol is not relevant, we cannot replace the symbol with the
// section and patch the difference in the addend.
case MCSymbolRefExpr::VK_GOT:
case MCSymbolRefExpr::VK_PLT:
case MCSymbolRefExpr::VK_GOTPCREL:
case MCSymbolRefExpr::VK_PPC_GOT_LO:
case MCSymbolRefExpr::VK_PPC_GOT_HI:
case MCSymbolRefExpr::VK_PPC_GOT_HA:
return true;
}
// An undefined symbol is not in any section, so the relocation has to point
// to the symbol itself.
assert(Sym && "Expected a symbol");
if (Sym->isUndefined())
return true;
unsigned Binding = Sym->getBinding();
switch(Binding) {
default:
llvm_unreachable("Invalid Binding");
case ELF::STB_LOCAL:
break;
case ELF::STB_WEAK:
// If the symbol is weak, it might be overridden by a symbol in another
// file. The relocation has to point to the symbol so that the linker
// can update it.
return true;
case ELF::STB_GLOBAL:
// Global ELF symbols can be preempted by the dynamic linker. The relocation
// has to point to the symbol for a reason analogous to the STB_WEAK case.
return true;
}
// If a relocation points to a mergeable section, we have to be careful.
// If the offset is zero, a relocation with the section will encode the
// same information. With a non-zero offset, the situation is different.
// For example, a relocation can point 42 bytes past the end of a string.
// If we change such a relocation to use the section, the linker would think
// that it pointed to another string and subtracting 42 at runtime will
// produce the wrong value.
if (Sym->isInSection()) {
auto &Sec = cast<MCSectionELF>(Sym->getSection());
unsigned Flags = Sec.getFlags();
if (Flags & ELF::SHF_MERGE) {
if (C != 0)
return true;
// It looks like gold has a bug (http://sourceware.org/PR16794) and can
// only handle section relocations to mergeable sections if using RELA.
if (!hasRelocationAddend())
return true;
}
// Most TLS relocations use a got, so they need the symbol. Even those that
// are just an offset (@tpoff), require a symbol in gold versions before
// 5efeedf61e4fe720fd3e9a08e6c91c10abb66d42 (2014-09-26) which fixed
// http://sourceware.org/PR16773.
if (Flags & ELF::SHF_TLS)
return true;
}
// If the symbol is a thumb function the final relocation must set the lowest
// bit. With a symbol that is done by just having the symbol have that bit
// set, so we would lose the bit if we relocated with the section.
// FIXME: We could use the section but add the bit to the relocation value.
if (Asm.isThumbFunc(Sym))
return true;
if (TargetObjectWriter->needsRelocateWithSymbol(*Sym, Type))
return true;
return false;
}
void ELFObjectWriter::recordRelocation(MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFragment *Fragment,
const MCFixup &Fixup, MCValue Target,
uint64_t &FixedValue) {
MCAsmBackend &Backend = Asm.getBackend();
bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags &
MCFixupKindInfo::FKF_IsPCRel;
const MCSectionELF &FixupSection = cast<MCSectionELF>(*Fragment->getParent());
uint64_t C = Target.getConstant();
uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
MCContext &Ctx = Asm.getContext();
if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
// Let A, B and C being the components of Target and R be the location of
// the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
// If it is pcrel, we want to compute (A - B + C - R).
// In general, ELF has no relocations for -B. It can only represent (A + C)
// or (A + C - R). If B = R + K and the relocation is not pcrel, we can
// replace B to implement it: (A - R - K + C)
if (IsPCRel) {
Ctx.reportError(
Fixup.getLoc(),
"No relocation available to represent this relative expression");
return;
}
const auto &SymB = cast<MCSymbolELF>(RefB->getSymbol());
if (SymB.isUndefined()) {
Ctx.reportError(Fixup.getLoc(),
Twine("symbol '") + SymB.getName() +
"' can not be undefined in a subtraction expression");
return;
}
assert(!SymB.isAbsolute() && "Should have been folded");
const MCSection &SecB = SymB.getSection();
if (&SecB != &FixupSection) {
Ctx.reportError(Fixup.getLoc(),
"Cannot represent a difference across sections");
return;
}
uint64_t SymBOffset = Layout.getSymbolOffset(SymB);
uint64_t K = SymBOffset - FixupOffset;
IsPCRel = true;
C -= K;
}
// We either rejected the fixup or folded B into C at this point.
const MCSymbolRefExpr *RefA = Target.getSymA();
const auto *SymA = RefA ? cast<MCSymbolELF>(&RefA->getSymbol()) : nullptr;
bool ViaWeakRef = false;
if (SymA && SymA->isVariable()) {
const MCExpr *Expr = SymA->getVariableValue();
if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) {
if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) {
SymA = cast<MCSymbolELF>(&Inner->getSymbol());
ViaWeakRef = true;
}
}
}
unsigned Type = TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel);
uint64_t OriginalC = C;
bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type);
if (!RelocateWithSymbol && SymA && !SymA->isUndefined())
C += Layout.getSymbolOffset(*SymA);
uint64_t Addend = 0;
if (hasRelocationAddend()) {
Addend = C;
C = 0;
}
FixedValue = C;
const MCSectionELF *SecA = (SymA && SymA->isInSection())
? cast<MCSectionELF>(&SymA->getSection())
: nullptr;
if (!checkRelocation(Ctx, Fixup.getLoc(), &FixupSection, SecA))
return;
if (!RelocateWithSymbol) {
const auto *SectionSymbol =
SecA ? cast<MCSymbolELF>(SecA->getBeginSymbol()) : nullptr;
if (SectionSymbol)
SectionSymbol->setUsedInReloc();
ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA,
OriginalC);
Relocations[&FixupSection].push_back(Rec);
return;
}
const auto *RenamedSymA = SymA;
if (SymA) {
if (const MCSymbolELF *R = Renames.lookup(SymA))
RenamedSymA = R;
if (ViaWeakRef)
RenamedSymA->setIsWeakrefUsedInReloc();
else
RenamedSymA->setUsedInReloc();
}
ELFRelocationEntry Rec(FixupOffset, RenamedSymA, Type, Addend, SymA,
OriginalC);
Relocations[&FixupSection].push_back(Rec);
}
bool ELFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(
const MCAssembler &Asm, const MCSymbol &SA, const MCFragment &FB,
bool InSet, bool IsPCRel) const {
const auto &SymA = cast<MCSymbolELF>(SA);
if (IsPCRel) {
assert(!InSet);
if (isWeak(SymA))
return false;
}
return MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(Asm, SymA, FB,
InSet, IsPCRel);
}
std::unique_ptr<MCObjectWriter>
llvm::createELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
raw_pwrite_stream &OS, bool IsLittleEndian) {
return llvm::make_unique<ELFSingleObjectWriter>(std::move(MOTW), OS,
IsLittleEndian);
}
std::unique_ptr<MCObjectWriter>
llvm::createELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS,
bool IsLittleEndian) {
return llvm::make_unique<ELFDwoObjectWriter>(std::move(MOTW), OS, DwoOS,
IsLittleEndian);
}
Index: stable/11/contrib/llvm/lib/MC/MCWin64EH.cpp
===================================================================
--- stable/11/contrib/llvm/lib/MC/MCWin64EH.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/MC/MCWin64EH.cpp (revision 350259)
@@ -1,644 +1,644 @@
//===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/MC/MCWin64EH.h"
#include "llvm/ADT/Twine.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectStreamer.h"
#include "llvm/MC/MCSectionCOFF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/Win64EH.h"
using namespace llvm;
// NOTE: All relocations generated here are 4-byte image-relative.
static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) {
uint8_t Count = 0;
for (const auto &I : Insns) {
switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
default:
llvm_unreachable("Unsupported unwind code");
case Win64EH::UOP_PushNonVol:
case Win64EH::UOP_AllocSmall:
case Win64EH::UOP_SetFPReg:
case Win64EH::UOP_PushMachFrame:
Count += 1;
break;
case Win64EH::UOP_SaveNonVol:
case Win64EH::UOP_SaveXMM128:
Count += 2;
break;
case Win64EH::UOP_SaveNonVolBig:
case Win64EH::UOP_SaveXMM128Big:
Count += 3;
break;
case Win64EH::UOP_AllocLarge:
Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2;
break;
}
}
return Count;
}
static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
const MCSymbol *RHS) {
MCContext &Context = Streamer.getContext();
const MCExpr *Diff =
MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
MCSymbolRefExpr::create(RHS, Context), Context);
Streamer.EmitValue(Diff, 1);
}
static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
WinEH::Instruction &inst) {
uint8_t b2;
uint16_t w;
b2 = (inst.Operation & 0x0F);
switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
default:
llvm_unreachable("Unsupported unwind code");
case Win64EH::UOP_PushNonVol:
EmitAbsDifference(streamer, inst.Label, begin);
b2 |= (inst.Register & 0x0F) << 4;
streamer.EmitIntValue(b2, 1);
break;
case Win64EH::UOP_AllocLarge:
EmitAbsDifference(streamer, inst.Label, begin);
if (inst.Offset > 512 * 1024 - 8) {
b2 |= 0x10;
streamer.EmitIntValue(b2, 1);
w = inst.Offset & 0xFFF8;
streamer.EmitIntValue(w, 2);
w = inst.Offset >> 16;
} else {
streamer.EmitIntValue(b2, 1);
w = inst.Offset >> 3;
}
streamer.EmitIntValue(w, 2);
break;
case Win64EH::UOP_AllocSmall:
b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4;
EmitAbsDifference(streamer, inst.Label, begin);
streamer.EmitIntValue(b2, 1);
break;
case Win64EH::UOP_SetFPReg:
EmitAbsDifference(streamer, inst.Label, begin);
streamer.EmitIntValue(b2, 1);
break;
case Win64EH::UOP_SaveNonVol:
case Win64EH::UOP_SaveXMM128:
b2 |= (inst.Register & 0x0F) << 4;
EmitAbsDifference(streamer, inst.Label, begin);
streamer.EmitIntValue(b2, 1);
w = inst.Offset >> 3;
if (inst.Operation == Win64EH::UOP_SaveXMM128)
w >>= 1;
streamer.EmitIntValue(w, 2);
break;
case Win64EH::UOP_SaveNonVolBig:
case Win64EH::UOP_SaveXMM128Big:
b2 |= (inst.Register & 0x0F) << 4;
EmitAbsDifference(streamer, inst.Label, begin);
streamer.EmitIntValue(b2, 1);
if (inst.Operation == Win64EH::UOP_SaveXMM128Big)
w = inst.Offset & 0xFFF0;
else
w = inst.Offset & 0xFFF8;
streamer.EmitIntValue(w, 2);
w = inst.Offset >> 16;
streamer.EmitIntValue(w, 2);
break;
case Win64EH::UOP_PushMachFrame:
if (inst.Offset == 1)
b2 |= 0x10;
EmitAbsDifference(streamer, inst.Label, begin);
streamer.EmitIntValue(b2, 1);
break;
}
}
static void EmitSymbolRefWithOfs(MCStreamer &streamer,
const MCSymbol *Base,
const MCSymbol *Other) {
MCContext &Context = streamer.getContext();
const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::create(Base, Context);
const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::create(Other, Context);
const MCExpr *Ofs = MCBinaryExpr::createSub(OtherRef, BaseRef, Context);
const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
MCSymbolRefExpr::VK_COFF_IMGREL32,
Context);
streamer.EmitValue(MCBinaryExpr::createAdd(BaseRefRel, Ofs, Context), 4);
}
static void EmitRuntimeFunction(MCStreamer &streamer,
const WinEH::FrameInfo *info) {
MCContext &context = streamer.getContext();
streamer.EmitValueToAlignment(4);
EmitSymbolRefWithOfs(streamer, info->Function, info->Begin);
EmitSymbolRefWithOfs(streamer, info->Function, info->End);
streamer.EmitValue(MCSymbolRefExpr::create(info->Symbol,
MCSymbolRefExpr::VK_COFF_IMGREL32,
context), 4);
}
static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
// If this UNWIND_INFO already has a symbol, it's already been emitted.
if (info->Symbol)
return;
MCContext &context = streamer.getContext();
MCSymbol *Label = context.createTempSymbol();
streamer.EmitValueToAlignment(4);
streamer.EmitLabel(Label);
info->Symbol = Label;
// Upper 3 bits are the version number (currently 1).
uint8_t flags = 0x01;
if (info->ChainedParent)
flags |= Win64EH::UNW_ChainInfo << 3;
else {
if (info->HandlesUnwind)
flags |= Win64EH::UNW_TerminateHandler << 3;
if (info->HandlesExceptions)
flags |= Win64EH::UNW_ExceptionHandler << 3;
}
streamer.EmitIntValue(flags, 1);
if (info->PrologEnd)
EmitAbsDifference(streamer, info->PrologEnd, info->Begin);
else
streamer.EmitIntValue(0, 1);
uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
streamer.EmitIntValue(numCodes, 1);
uint8_t frame = 0;
if (info->LastFrameInst >= 0) {
WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst];
assert(frameInst.Operation == Win64EH::UOP_SetFPReg);
frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0);
}
streamer.EmitIntValue(frame, 1);
// Emit unwind instructions (in reverse order).
uint8_t numInst = info->Instructions.size();
for (uint8_t c = 0; c < numInst; ++c) {
WinEH::Instruction inst = info->Instructions.back();
info->Instructions.pop_back();
EmitUnwindCode(streamer, info->Begin, inst);
}
// For alignment purposes, the instruction array will always have an even
// number of entries, with the final entry potentially unused (in which case
// the array will be one longer than indicated by the count of unwind codes
// field).
if (numCodes & 1) {
streamer.EmitIntValue(0, 2);
}
if (flags & (Win64EH::UNW_ChainInfo << 3))
EmitRuntimeFunction(streamer, info->ChainedParent);
else if (flags &
((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3))
streamer.EmitValue(MCSymbolRefExpr::create(info->ExceptionHandler,
MCSymbolRefExpr::VK_COFF_IMGREL32,
context), 4);
else if (numCodes == 0) {
// The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
// a chained unwind info, if there is no handler, and if there are fewer
// than 2 slots used in the unwind code array, we have to pad to 8 bytes.
streamer.EmitIntValue(0, 4);
}
}
void llvm::Win64EH::UnwindEmitter::Emit(MCStreamer &Streamer) const {
// Emit the unwind info structs first.
for (const auto &CFI : Streamer.getWinFrameInfos()) {
MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
Streamer.SwitchSection(XData);
::EmitUnwindInfo(Streamer, CFI.get());
}
// Now emit RUNTIME_FUNCTION entries.
for (const auto &CFI : Streamer.getWinFrameInfos()) {
MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
Streamer.SwitchSection(PData);
EmitRuntimeFunction(Streamer, CFI.get());
}
}
void llvm::Win64EH::UnwindEmitter::EmitUnwindInfo(
MCStreamer &Streamer, WinEH::FrameInfo *info) const {
// Switch sections (the static function above is meant to be called from
// here and from Emit().
MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
Streamer.SwitchSection(XData);
::EmitUnwindInfo(Streamer, info);
}
static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
const MCSymbol *RHS) {
MCContext &Context = Streamer.getContext();
const MCExpr *Diff =
MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
MCSymbolRefExpr::create(RHS, Context), Context);
MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer);
int64_t value;
Diff->evaluateAsAbsolute(value, OS->getAssembler());
return value;
}
static uint32_t
ARM64CountOfUnwindCodes(const std::vector<WinEH::Instruction> &Insns) {
uint32_t Count = 0;
for (const auto &I : Insns) {
switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
default:
llvm_unreachable("Unsupported ARM64 unwind code");
case Win64EH::UOP_AllocSmall:
Count += 1;
break;
case Win64EH::UOP_AllocMedium:
Count += 2;
break;
case Win64EH::UOP_AllocLarge:
Count += 4;
break;
case Win64EH::UOP_SaveFPLRX:
Count += 1;
break;
case Win64EH::UOP_SaveFPLR:
Count += 1;
break;
case Win64EH::UOP_SaveReg:
Count += 2;
break;
case Win64EH::UOP_SaveRegP:
Count += 2;
break;
case Win64EH::UOP_SaveRegPX:
Count += 2;
break;
case Win64EH::UOP_SaveRegX:
Count += 2;
break;
case Win64EH::UOP_SaveFReg:
Count += 2;
break;
case Win64EH::UOP_SaveFRegP:
Count += 2;
break;
case Win64EH::UOP_SaveFRegX:
Count += 2;
break;
case Win64EH::UOP_SaveFRegPX:
Count += 2;
break;
case Win64EH::UOP_SetFP:
Count += 1;
break;
case Win64EH::UOP_AddFP:
Count += 2;
break;
case Win64EH::UOP_Nop:
Count += 1;
break;
case Win64EH::UOP_End:
Count += 1;
break;
}
}
return Count;
}
// Unwind opcode encodings and restrictions are documented at
// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
static void ARM64EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
WinEH::Instruction &inst) {
uint8_t b, reg;
switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
default:
llvm_unreachable("Unsupported ARM64 unwind code");
case Win64EH::UOP_AllocSmall:
b = (inst.Offset >> 4) & 0x1F;
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_AllocMedium: {
uint16_t hw = (inst.Offset >> 4) & 0x7FF;
b = 0xC0;
b |= (hw >> 8);
streamer.EmitIntValue(b, 1);
b = hw & 0xFF;
streamer.EmitIntValue(b, 1);
break;
}
case Win64EH::UOP_AllocLarge: {
uint32_t w;
b = 0xE0;
streamer.EmitIntValue(b, 1);
w = inst.Offset >> 4;
b = (w & 0x00FF0000) >> 16;
streamer.EmitIntValue(b, 1);
b = (w & 0x0000FF00) >> 8;
streamer.EmitIntValue(b, 1);
b = w & 0x000000FF;
streamer.EmitIntValue(b, 1);
break;
}
case Win64EH::UOP_SetFP:
b = 0xE1;
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_AddFP:
b = 0xE2;
streamer.EmitIntValue(b, 1);
b = (inst.Offset >> 3);
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_Nop:
b = 0xE3;
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_SaveFPLRX:
b = 0x80;
b |= ((inst.Offset - 1) >> 3) & 0x3F;
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_SaveFPLR:
b = 0x40;
b |= (inst.Offset >> 3) & 0x3F;
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_SaveReg:
assert(inst.Register >= 19 && "Saved reg must be >= 19");
reg = inst.Register - 19;
b = 0xD0 | ((reg & 0xC) >> 2);
streamer.EmitIntValue(b, 1);
b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_SaveRegX:
assert(inst.Register >= 19 && "Saved reg must be >= 19");
reg = inst.Register - 19;
b = 0xD4 | ((reg & 0x8) >> 3);
streamer.EmitIntValue(b, 1);
b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_SaveRegP:
assert(inst.Register >= 19 && "Saved registers must be >= 19");
reg = inst.Register - 19;
b = 0xC8 | ((reg & 0xC) >> 2);
streamer.EmitIntValue(b, 1);
b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_SaveRegPX:
assert(inst.Register >= 19 && "Saved registers must be >= 19");
reg = inst.Register - 19;
b = 0xCC | ((reg & 0xC) >> 2);
streamer.EmitIntValue(b, 1);
b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_SaveFReg:
assert(inst.Register >= 8 && "Saved dreg must be >= 8");
reg = inst.Register - 8;
b = 0xDC | ((reg & 0x4) >> 2);
streamer.EmitIntValue(b, 1);
b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_SaveFRegX:
assert(inst.Register >= 8 && "Saved dreg must be >= 8");
reg = inst.Register - 8;
b = 0xDE;
streamer.EmitIntValue(b, 1);
b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_SaveFRegP:
assert(inst.Register >= 8 && "Saved dregs must be >= 8");
reg = inst.Register - 8;
b = 0xD8 | ((reg & 0x4) >> 2);
streamer.EmitIntValue(b, 1);
b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_SaveFRegPX:
assert(inst.Register >= 8 && "Saved dregs must be >= 8");
reg = inst.Register - 8;
b = 0xDA | ((reg & 0x4) >> 2);
streamer.EmitIntValue(b, 1);
b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
streamer.EmitIntValue(b, 1);
break;
case Win64EH::UOP_End:
b = 0xE4;
streamer.EmitIntValue(b, 1);
break;
}
}
// Returns the epilog symbol of an epilog with the exact same unwind code
// sequence, if it exists. Otherwise, returns nulltpr.
// EpilogInstrs - Unwind codes for the current epilog.
// Epilogs - Epilogs that potentialy match the current epilog.
static MCSymbol*
FindMatchingEpilog(const std::vector<WinEH::Instruction>& EpilogInstrs,
const std::vector<MCSymbol *>& Epilogs,
const WinEH::FrameInfo *info) {
for (auto *EpilogStart : Epilogs) {
auto InstrsIter = info->EpilogMap.find(EpilogStart);
assert(InstrsIter != info->EpilogMap.end() &&
"Epilog not found in EpilogMap");
const auto &Instrs = InstrsIter->second;
if (Instrs.size() != EpilogInstrs.size())
continue;
bool Match = true;
for (unsigned i = 0; i < Instrs.size(); ++i)
if (Instrs[i].Operation != EpilogInstrs[i].Operation ||
Instrs[i].Offset != EpilogInstrs[i].Offset ||
Instrs[i].Register != EpilogInstrs[i].Register) {
Match = false;
break;
}
if (Match)
return EpilogStart;
}
return nullptr;
}
// Populate the .xdata section. The format of .xdata on ARM64 is documented at
// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
// If this UNWIND_INFO already has a symbol, it's already been emitted.
if (info->Symbol)
return;
MCContext &context = streamer.getContext();
MCSymbol *Label = context.createTempSymbol();
streamer.EmitValueToAlignment(4);
streamer.EmitLabel(Label);
info->Symbol = Label;
uint32_t FuncLength = 0x0;
if (info->FuncletOrFuncEnd)
FuncLength = (uint32_t)GetAbsDifference(streamer, info->FuncletOrFuncEnd,
info->Begin);
FuncLength /= 4;
uint32_t PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions);
uint32_t TotalCodeBytes = PrologCodeBytes;
// Process epilogs.
MapVector<MCSymbol *, uint32_t> EpilogInfo;
// Epilogs processed so far.
std::vector<MCSymbol *> AddedEpilogs;
for (auto &I : info->EpilogMap) {
MCSymbol *EpilogStart = I.first;
auto &EpilogInstrs = I.second;
uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs);
MCSymbol* MatchingEpilog =
FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
if (MatchingEpilog) {
assert(EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() &&
"Duplicate epilog not found");
- EpilogInfo[EpilogStart] = EpilogInfo[MatchingEpilog];
+ EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
// Clear the unwind codes in the EpilogMap, so that they don't get output
// in the logic below.
EpilogInstrs.clear();
} else {
EpilogInfo[EpilogStart] = TotalCodeBytes;
TotalCodeBytes += CodeBytes;
AddedEpilogs.push_back(EpilogStart);
}
}
// Code Words, Epilog count, E, X, Vers, Function Length
uint32_t row1 = 0x0;
uint32_t CodeWords = TotalCodeBytes / 4;
uint32_t CodeWordsMod = TotalCodeBytes % 4;
if (CodeWordsMod)
CodeWords++;
uint32_t EpilogCount = info->EpilogMap.size();
bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124;
if (!ExtensionWord) {
row1 |= (EpilogCount & 0x1F) << 22;
row1 |= (CodeWords & 0x1F) << 27;
}
// E is always 0 right now, TODO: packed epilog setup
if (info->HandlesExceptions) // X
row1 |= 1 << 20;
row1 |= FuncLength & 0x3FFFF;
streamer.EmitIntValue(row1, 4);
// Extended Code Words, Extended Epilog Count
if (ExtensionWord) {
// FIXME: We should be able to split unwind info into multiple sections.
// FIXME: We should share epilog codes across epilogs, where possible,
// which would make this issue show up less frequently.
if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
report_fatal_error("SEH unwind data splitting not yet implemented");
uint32_t row2 = 0x0;
row2 |= (CodeWords & 0xFF) << 16;
row2 |= (EpilogCount & 0xFFFF);
streamer.EmitIntValue(row2, 4);
}
// Epilog Start Index, Epilog Start Offset
for (auto &I : EpilogInfo) {
MCSymbol *EpilogStart = I.first;
uint32_t EpilogIndex = I.second;
uint32_t EpilogOffset =
(uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin);
if (EpilogOffset)
EpilogOffset /= 4;
uint32_t row3 = EpilogOffset;
row3 |= (EpilogIndex & 0x3FF) << 22;
streamer.EmitIntValue(row3, 4);
}
// Emit prolog unwind instructions (in reverse order).
uint8_t numInst = info->Instructions.size();
for (uint8_t c = 0; c < numInst; ++c) {
WinEH::Instruction inst = info->Instructions.back();
info->Instructions.pop_back();
ARM64EmitUnwindCode(streamer, info->Begin, inst);
}
// Emit epilog unwind instructions
for (auto &I : info->EpilogMap) {
auto &EpilogInstrs = I.second;
for (uint32_t i = 0; i < EpilogInstrs.size(); i++) {
WinEH::Instruction inst = EpilogInstrs[i];
ARM64EmitUnwindCode(streamer, info->Begin, inst);
}
}
int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
assert(BytesMod >= 0);
for (int i = 0; i < BytesMod; i++)
streamer.EmitIntValue(0xE3, 1);
if (info->HandlesExceptions)
streamer.EmitValue(
MCSymbolRefExpr::create(info->ExceptionHandler,
MCSymbolRefExpr::VK_COFF_IMGREL32, context),
4);
}
static void ARM64EmitRuntimeFunction(MCStreamer &streamer,
const WinEH::FrameInfo *info) {
MCContext &context = streamer.getContext();
streamer.EmitValueToAlignment(4);
EmitSymbolRefWithOfs(streamer, info->Function, info->Begin);
streamer.EmitValue(MCSymbolRefExpr::create(info->Symbol,
MCSymbolRefExpr::VK_COFF_IMGREL32,
context),
4);
}
void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const {
// Emit the unwind info structs first.
for (const auto &CFI : Streamer.getWinFrameInfos()) {
MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
Streamer.SwitchSection(XData);
ARM64EmitUnwindInfo(Streamer, CFI.get());
}
// Now emit RUNTIME_FUNCTION entries.
for (const auto &CFI : Streamer.getWinFrameInfos()) {
MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
Streamer.SwitchSection(PData);
ARM64EmitRuntimeFunction(Streamer, CFI.get());
}
}
void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo(
MCStreamer &Streamer, WinEH::FrameInfo *info) const {
// Switch sections (the static function above is meant to be called from
// here and from Emit().
MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
Streamer.SwitchSection(XData);
ARM64EmitUnwindInfo(Streamer, info);
}
Index: stable/11/contrib/llvm/lib/MC/WasmObjectWriter.cpp
===================================================================
--- stable/11/contrib/llvm/lib/MC/WasmObjectWriter.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/MC/WasmObjectWriter.cpp (revision 350259)
@@ -1,1590 +1,1596 @@
//===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements Wasm object file writer information.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/BinaryFormat/Wasm.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSectionWasm.h"
#include "llvm/MC/MCSymbolWasm.h"
#include "llvm/MC/MCValue.h"
#include "llvm/MC/MCWasmObjectWriter.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/StringSaver.h"
#include <vector>
using namespace llvm;
#define DEBUG_TYPE "mc"
namespace {
// Went we ceate the indirect function table we start at 1, so that there is
// and emtpy slot at 0 and therefore calling a null function pointer will trap.
static const uint32_t kInitialTableOffset = 1;
// For patching purposes, we need to remember where each section starts, both
// for patching up the section size field, and for patching up references to
// locations within the section.
struct SectionBookkeeping {
// Where the size of the section is written.
uint64_t SizeOffset;
// Where the section header ends (without custom section name).
uint64_t PayloadOffset;
// Where the contents of the section starts.
uint64_t ContentsOffset;
uint32_t Index;
};
// The signature of a wasm function or event, in a struct capable of being used
// as a DenseMap key.
// TODO: Consider using wasm::WasmSignature directly instead.
struct WasmSignature {
// Support empty and tombstone instances, needed by DenseMap.
enum { Plain, Empty, Tombstone } State;
// The return types of the function.
SmallVector<wasm::ValType, 1> Returns;
// The parameter types of the function.
SmallVector<wasm::ValType, 4> Params;
WasmSignature() : State(Plain) {}
bool operator==(const WasmSignature &Other) const {
return State == Other.State && Returns == Other.Returns &&
Params == Other.Params;
}
};
// Traits for using WasmSignature in a DenseMap.
struct WasmSignatureDenseMapInfo {
static WasmSignature getEmptyKey() {
WasmSignature Sig;
Sig.State = WasmSignature::Empty;
return Sig;
}
static WasmSignature getTombstoneKey() {
WasmSignature Sig;
Sig.State = WasmSignature::Tombstone;
return Sig;
}
static unsigned getHashValue(const WasmSignature &Sig) {
uintptr_t Value = Sig.State;
for (wasm::ValType Ret : Sig.Returns)
Value += DenseMapInfo<uint32_t>::getHashValue(uint32_t(Ret));
for (wasm::ValType Param : Sig.Params)
Value += DenseMapInfo<uint32_t>::getHashValue(uint32_t(Param));
return Value;
}
static bool isEqual(const WasmSignature &LHS, const WasmSignature &RHS) {
return LHS == RHS;
}
};
// A wasm data segment. A wasm binary contains only a single data section
// but that can contain many segments, each with their own virtual location
// in memory. Each MCSection data created by llvm is modeled as its own
// wasm data segment.
struct WasmDataSegment {
MCSectionWasm *Section;
StringRef Name;
uint32_t Offset;
uint32_t Alignment;
uint32_t Flags;
SmallVector<char, 4> Data;
};
// A wasm function to be written into the function section.
struct WasmFunction {
uint32_t SigIndex;
const MCSymbolWasm *Sym;
};
// A wasm global to be written into the global section.
struct WasmGlobal {
wasm::WasmGlobalType Type;
uint64_t InitialValue;
};
// Information about a single item which is part of a COMDAT. For each data
// segment or function which is in the COMDAT, there is a corresponding
// WasmComdatEntry.
struct WasmComdatEntry {
unsigned Kind;
uint32_t Index;
};
// Information about a single relocation.
struct WasmRelocationEntry {
uint64_t Offset; // Where is the relocation.
const MCSymbolWasm *Symbol; // The symbol to relocate with.
int64_t Addend; // A value to add to the symbol.
unsigned Type; // The type of the relocation.
const MCSectionWasm *FixupSection; // The section the relocation is targeting.
WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol,
int64_t Addend, unsigned Type,
const MCSectionWasm *FixupSection)
: Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type),
FixupSection(FixupSection) {}
bool hasAddend() const {
switch (Type) {
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
return true;
default:
return false;
}
}
void print(raw_ostream &Out) const {
Out << wasm::relocTypetoString(Type) << " Off=" << Offset
<< ", Sym=" << *Symbol << ", Addend=" << Addend
<< ", FixupSection=" << FixupSection->getSectionName();
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
#endif
};
static const uint32_t INVALID_INDEX = -1;
struct WasmCustomSection {
StringRef Name;
MCSectionWasm *Section;
uint32_t OutputContentsOffset;
uint32_t OutputIndex;
WasmCustomSection(StringRef Name, MCSectionWasm *Section)
: Name(Name), Section(Section), OutputContentsOffset(0),
OutputIndex(INVALID_INDEX) {}
};
#if !defined(NDEBUG)
raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) {
Rel.print(OS);
return OS;
}
#endif
class WasmObjectWriter : public MCObjectWriter {
support::endian::Writer W;
/// The target specific Wasm writer instance.
std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter;
// Relocations for fixing up references in the code section.
std::vector<WasmRelocationEntry> CodeRelocations;
uint32_t CodeSectionIndex;
// Relocations for fixing up references in the data section.
std::vector<WasmRelocationEntry> DataRelocations;
uint32_t DataSectionIndex;
// Index values to use for fixing up call_indirect type indices.
// Maps function symbols to the index of the type of the function
DenseMap<const MCSymbolWasm *, uint32_t> TypeIndices;
// Maps function symbols to the table element index space. Used
// for TABLE_INDEX relocation types (i.e. address taken functions).
DenseMap<const MCSymbolWasm *, uint32_t> TableIndices;
// Maps function/global symbols to the function/global/event/section index
// space.
DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices;
// Maps data symbols to the Wasm segment and offset/size with the segment.
DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations;
// Stores output data (index, relocations, content offset) for custom
// section.
std::vector<WasmCustomSection> CustomSections;
// Relocations for fixing up references in the custom sections.
DenseMap<const MCSectionWasm *, std::vector<WasmRelocationEntry>>
CustomSectionsRelocations;
// Map from section to defining function symbol.
DenseMap<const MCSection *, const MCSymbol *> SectionFunctions;
DenseMap<WasmSignature, uint32_t, WasmSignatureDenseMapInfo> SignatureIndices;
SmallVector<WasmSignature, 4> Signatures;
SmallVector<WasmGlobal, 4> Globals;
SmallVector<WasmDataSegment, 4> DataSegments;
unsigned NumFunctionImports = 0;
unsigned NumGlobalImports = 0;
unsigned NumEventImports = 0;
uint32_t SectionCount = 0;
// TargetObjectWriter wrappers.
bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup) const {
return TargetObjectWriter->getRelocType(Target, Fixup);
}
void startSection(SectionBookkeeping &Section, unsigned SectionId);
void startCustomSection(SectionBookkeeping &Section, StringRef Name);
void endSection(SectionBookkeeping &Section);
public:
WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
raw_pwrite_stream &OS)
: W(OS, support::little), TargetObjectWriter(std::move(MOTW)) {}
~WasmObjectWriter() override;
private:
void reset() override {
CodeRelocations.clear();
DataRelocations.clear();
TypeIndices.clear();
WasmIndices.clear();
TableIndices.clear();
DataLocations.clear();
CustomSectionsRelocations.clear();
SignatureIndices.clear();
Signatures.clear();
Globals.clear();
DataSegments.clear();
SectionFunctions.clear();
NumFunctionImports = 0;
NumGlobalImports = 0;
MCObjectWriter::reset();
}
void writeHeader(const MCAssembler &Asm);
void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
const MCFragment *Fragment, const MCFixup &Fixup,
MCValue Target, uint64_t &FixedValue) override;
void executePostLayoutBinding(MCAssembler &Asm,
const MCAsmLayout &Layout) override;
uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
void writeString(const StringRef Str) {
encodeULEB128(Str.size(), W.OS);
W.OS << Str;
}
void writeValueType(wasm::ValType Ty) { W.OS << static_cast<char>(Ty); }
void writeTypeSection(ArrayRef<WasmSignature> Signatures);
void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize,
uint32_t NumElements);
void writeFunctionSection(ArrayRef<WasmFunction> Functions);
void writeGlobalSection();
void writeExportSection(ArrayRef<wasm::WasmExport> Exports);
void writeElemSection(ArrayRef<uint32_t> TableElems);
void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
ArrayRef<WasmFunction> Functions);
void writeDataSection();
void writeEventSection(ArrayRef<wasm::WasmEventType> Events);
void writeRelocSection(uint32_t SectionIndex, StringRef Name,
std::vector<WasmRelocationEntry> &Relocations);
void writeLinkingMetaDataSection(
ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats);
void writeCustomSections(const MCAssembler &Asm, const MCAsmLayout &Layout);
void writeCustomRelocSections();
void
updateCustomSectionRelocations(const SmallVector<WasmFunction, 4> &Functions,
const MCAsmLayout &Layout);
uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry);
void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
uint64_t ContentsOffset);
uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry);
uint32_t getFunctionType(const MCSymbolWasm &Symbol);
uint32_t getEventType(const MCSymbolWasm &Symbol);
void registerFunctionType(const MCSymbolWasm &Symbol);
void registerEventType(const MCSymbolWasm &Symbol);
};
} // end anonymous namespace
WasmObjectWriter::~WasmObjectWriter() {}
// Write out a section header and a patchable section size field.
void WasmObjectWriter::startSection(SectionBookkeeping &Section,
unsigned SectionId) {
LLVM_DEBUG(dbgs() << "startSection " << SectionId << "\n");
W.OS << char(SectionId);
Section.SizeOffset = W.OS.tell();
// The section size. We don't know the size yet, so reserve enough space
// for any 32-bit value; we'll patch it later.
encodeULEB128(UINT32_MAX, W.OS);
// The position where the section starts, for measuring its size.
Section.ContentsOffset = W.OS.tell();
Section.PayloadOffset = W.OS.tell();
Section.Index = SectionCount++;
}
void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section,
StringRef Name) {
LLVM_DEBUG(dbgs() << "startCustomSection " << Name << "\n");
startSection(Section, wasm::WASM_SEC_CUSTOM);
// The position where the section header ends, for measuring its size.
Section.PayloadOffset = W.OS.tell();
// Custom sections in wasm also have a string identifier.
writeString(Name);
// The position where the custom section starts.
Section.ContentsOffset = W.OS.tell();
}
// Now that the section is complete and we know how big it is, patch up the
// section size field at the start of the section.
void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
- uint64_t Size = W.OS.tell() - Section.PayloadOffset;
+ uint64_t Size = W.OS.tell();
+ // /dev/null doesn't support seek/tell and can report offset of 0.
+ // Simply skip this patching in that case.
+ if (!Size)
+ return;
+
+ Size -= Section.PayloadOffset;
if (uint32_t(Size) != Size)
report_fatal_error("section size does not fit in a uint32_t");
LLVM_DEBUG(dbgs() << "endSection size=" << Size << "\n");
// Write the final section size to the payload_len field, which follows
// the section id byte.
uint8_t Buffer[16];
unsigned SizeLen = encodeULEB128(Size, Buffer, 5);
assert(SizeLen == 5);
static_cast<raw_pwrite_stream &>(W.OS).pwrite((char *)Buffer, SizeLen,
Section.SizeOffset);
}
// Emit the Wasm header.
void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
W.OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic));
W.write<uint32_t>(wasm::WasmVersion);
}
void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
const MCAsmLayout &Layout) {
// Build a map of sections to the function that defines them, for use
// in recordRelocation.
for (const MCSymbol &S : Asm.symbols()) {
const auto &WS = static_cast<const MCSymbolWasm &>(S);
if (WS.isDefined() && WS.isFunction() && !WS.isVariable()) {
const auto &Sec = static_cast<const MCSectionWasm &>(S.getSection());
auto Pair = SectionFunctions.insert(std::make_pair(&Sec, &S));
if (!Pair.second)
report_fatal_error("section already has a defining function: " +
Sec.getSectionName());
}
}
}
void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFragment *Fragment,
const MCFixup &Fixup, MCValue Target,
uint64_t &FixedValue) {
MCAsmBackend &Backend = Asm.getBackend();
bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags &
MCFixupKindInfo::FKF_IsPCRel;
const auto &FixupSection = cast<MCSectionWasm>(*Fragment->getParent());
uint64_t C = Target.getConstant();
uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
MCContext &Ctx = Asm.getContext();
// The .init_array isn't translated as data, so don't do relocations in it.
if (FixupSection.getSectionName().startswith(".init_array"))
return;
if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
assert(RefB->getKind() == MCSymbolRefExpr::VK_None &&
"Should not have constructed this");
// Let A, B and C being the components of Target and R be the location of
// the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
// If it is pcrel, we want to compute (A - B + C - R).
// In general, Wasm has no relocations for -B. It can only represent (A + C)
// or (A + C - R). If B = R + K and the relocation is not pcrel, we can
// replace B to implement it: (A - R - K + C)
if (IsPCRel) {
Ctx.reportError(
Fixup.getLoc(),
"No relocation available to represent this relative expression");
return;
}
const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol());
if (SymB.isUndefined()) {
Ctx.reportError(Fixup.getLoc(),
Twine("symbol '") + SymB.getName() +
"' can not be undefined in a subtraction expression");
return;
}
assert(!SymB.isAbsolute() && "Should have been folded");
const MCSection &SecB = SymB.getSection();
if (&SecB != &FixupSection) {
Ctx.reportError(Fixup.getLoc(),
"Cannot represent a difference across sections");
return;
}
uint64_t SymBOffset = Layout.getSymbolOffset(SymB);
uint64_t K = SymBOffset - FixupOffset;
IsPCRel = true;
C -= K;
}
// We either rejected the fixup or folded B into C at this point.
const MCSymbolRefExpr *RefA = Target.getSymA();
const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr;
if (SymA && SymA->isVariable()) {
const MCExpr *Expr = SymA->getVariableValue();
const auto *Inner = cast<MCSymbolRefExpr>(Expr);
if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF)
llvm_unreachable("weakref used in reloc not yet implemented");
}
// Put any constant offset in an addend. Offsets can be negative, and
// LLVM expects wrapping, in contrast to wasm's immediates which can't
// be negative and don't wrap.
FixedValue = 0;
unsigned Type = getRelocType(Target, Fixup);
assert(!IsPCRel);
assert(SymA);
// Absolute offset within a section or a function.
// Currently only supported for for metadata sections.
// See: test/MC/WebAssembly/blockaddress.ll
if (Type == wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32 ||
Type == wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32) {
if (!FixupSection.getKind().isMetadata())
report_fatal_error("relocations for function or section offsets are "
"only supported in metadata sections");
const MCSymbol *SectionSymbol = nullptr;
const MCSection &SecA = SymA->getSection();
if (SecA.getKind().isText())
SectionSymbol = SectionFunctions.find(&SecA)->second;
else
SectionSymbol = SecA.getBeginSymbol();
if (!SectionSymbol)
report_fatal_error("section symbol is required for relocation");
C += Layout.getSymbolOffset(*SymA);
SymA = cast<MCSymbolWasm>(SectionSymbol);
}
// Relocation other than R_WEBASSEMBLY_TYPE_INDEX_LEB are required to be
// against a named symbol.
if (Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) {
if (SymA->getName().empty())
report_fatal_error("relocations against un-named temporaries are not yet "
"supported by wasm");
SymA->setUsedInReloc();
}
WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec << "\n");
if (FixupSection.isWasmData()) {
DataRelocations.push_back(Rec);
} else if (FixupSection.getKind().isText()) {
CodeRelocations.push_back(Rec);
} else if (FixupSection.getKind().isMetadata()) {
CustomSectionsRelocations[&FixupSection].push_back(Rec);
} else {
llvm_unreachable("unexpected section type");
}
}
// Write X as an (unsigned) LEB value at offset Offset in Stream, padded
// to allow patching.
static void WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X,
uint64_t Offset) {
uint8_t Buffer[5];
unsigned SizeLen = encodeULEB128(X, Buffer, 5);
assert(SizeLen == 5);
Stream.pwrite((char *)Buffer, SizeLen, Offset);
}
// Write X as an signed LEB value at offset Offset in Stream, padded
// to allow patching.
static void WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X,
uint64_t Offset) {
uint8_t Buffer[5];
unsigned SizeLen = encodeSLEB128(X, Buffer, 5);
assert(SizeLen == 5);
Stream.pwrite((char *)Buffer, SizeLen, Offset);
}
// Write X as a plain integer value at offset Offset in Stream.
static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
uint8_t Buffer[4];
support::endian::write32le(Buffer, X);
Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
}
static const MCSymbolWasm *ResolveSymbol(const MCSymbolWasm &Symbol) {
if (Symbol.isVariable()) {
const MCExpr *Expr = Symbol.getVariableValue();
auto *Inner = cast<MCSymbolRefExpr>(Expr);
return cast<MCSymbolWasm>(&Inner->getSymbol());
}
return &Symbol;
}
// Compute a value to write into the code at the location covered
// by RelEntry. This value isn't used by the static linker; it just serves
// to make the object format more readable and more likely to be directly
// useable.
uint32_t
WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
switch (RelEntry.Type) {
case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: {
// Provisional value is table address of the resolved symbol itself
const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol);
assert(Sym->isFunction());
return TableIndices[Sym];
}
case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
// Provisional value is same as the index
return getRelocationIndexValue(RelEntry);
case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB:
// Provisional value is function/global/event Wasm index
if (!WasmIndices.count(RelEntry.Symbol))
report_fatal_error("symbol not found in wasm index space: " +
RelEntry.Symbol->getName());
return WasmIndices[RelEntry.Symbol];
case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: {
const auto &Section =
static_cast<const MCSectionWasm &>(RelEntry.Symbol->getSection());
return Section.getSectionOffset() + RelEntry.Addend;
}
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: {
// Provisional value is address of the global
const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol);
// For undefined symbols, use zero
if (!Sym->isDefined())
return 0;
const wasm::WasmDataReference &Ref = DataLocations[Sym];
const WasmDataSegment &Segment = DataSegments[Ref.Segment];
// Ignore overflow. LLVM allows address arithmetic to silently wrap.
return Segment.Offset + Ref.Offset + RelEntry.Addend;
}
default:
llvm_unreachable("invalid relocation type");
}
}
static void addData(SmallVectorImpl<char> &DataBytes,
MCSectionWasm &DataSection) {
LLVM_DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n");
DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
for (const MCFragment &Frag : DataSection) {
if (Frag.hasInstructions())
report_fatal_error("only data supported in data sections");
if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) {
if (Align->getValueSize() != 1)
report_fatal_error("only byte values supported for alignment");
// If nops are requested, use zeros, as this is the data section.
uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue();
uint64_t Size =
std::min<uint64_t>(alignTo(DataBytes.size(), Align->getAlignment()),
DataBytes.size() + Align->getMaxBytesToEmit());
DataBytes.resize(Size, Value);
} else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) {
int64_t NumValues;
if (!Fill->getNumValues().evaluateAsAbsolute(NumValues))
llvm_unreachable("The fill should be an assembler constant");
DataBytes.insert(DataBytes.end(), Fill->getValueSize() * NumValues,
Fill->getValue());
} else if (auto *LEB = dyn_cast<MCLEBFragment>(&Frag)) {
const SmallVectorImpl<char> &Contents = LEB->getContents();
DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
} else {
const auto &DataFrag = cast<MCDataFragment>(Frag);
const SmallVectorImpl<char> &Contents = DataFrag.getContents();
DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
}
}
LLVM_DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n");
}
uint32_t
WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) {
if (RelEntry.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) {
if (!TypeIndices.count(RelEntry.Symbol))
report_fatal_error("symbol not found in type index space: " +
RelEntry.Symbol->getName());
return TypeIndices[RelEntry.Symbol];
}
return RelEntry.Symbol->getIndex();
}
// Apply the portions of the relocation records that we can handle ourselves
// directly.
void WasmObjectWriter::applyRelocations(
ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset) {
auto &Stream = static_cast<raw_pwrite_stream &>(W.OS);
for (const WasmRelocationEntry &RelEntry : Relocations) {
uint64_t Offset = ContentsOffset +
RelEntry.FixupSection->getSectionOffset() +
RelEntry.Offset;
LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n");
uint32_t Value = getProvisionalValue(RelEntry);
switch (RelEntry.Type) {
case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB:
WritePatchableLEB(Stream, Value, Offset);
break;
case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
WriteI32(Stream, Value, Offset);
break;
case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
WritePatchableSLEB(Stream, Value, Offset);
break;
default:
llvm_unreachable("invalid relocation type");
}
}
}
void WasmObjectWriter::writeTypeSection(ArrayRef<WasmSignature> Signatures) {
if (Signatures.empty())
return;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_TYPE);
encodeULEB128(Signatures.size(), W.OS);
for (const WasmSignature &Sig : Signatures) {
W.OS << char(wasm::WASM_TYPE_FUNC);
encodeULEB128(Sig.Params.size(), W.OS);
for (wasm::ValType Ty : Sig.Params)
writeValueType(Ty);
encodeULEB128(Sig.Returns.size(), W.OS);
for (wasm::ValType Ty : Sig.Returns)
writeValueType(Ty);
}
endSection(Section);
}
void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
uint32_t DataSize,
uint32_t NumElements) {
if (Imports.empty())
return;
uint32_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_IMPORT);
encodeULEB128(Imports.size(), W.OS);
for (const wasm::WasmImport &Import : Imports) {
writeString(Import.Module);
writeString(Import.Field);
W.OS << char(Import.Kind);
switch (Import.Kind) {
case wasm::WASM_EXTERNAL_FUNCTION:
encodeULEB128(Import.SigIndex, W.OS);
break;
case wasm::WASM_EXTERNAL_GLOBAL:
W.OS << char(Import.Global.Type);
W.OS << char(Import.Global.Mutable ? 1 : 0);
break;
case wasm::WASM_EXTERNAL_MEMORY:
encodeULEB128(0, W.OS); // flags
encodeULEB128(NumPages, W.OS); // initial
break;
case wasm::WASM_EXTERNAL_TABLE:
W.OS << char(Import.Table.ElemType);
encodeULEB128(0, W.OS); // flags
encodeULEB128(NumElements, W.OS); // initial
break;
case wasm::WASM_EXTERNAL_EVENT:
encodeULEB128(Import.Event.Attribute, W.OS);
encodeULEB128(Import.Event.SigIndex, W.OS);
break;
default:
llvm_unreachable("unsupported import kind");
}
}
endSection(Section);
}
void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) {
if (Functions.empty())
return;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_FUNCTION);
encodeULEB128(Functions.size(), W.OS);
for (const WasmFunction &Func : Functions)
encodeULEB128(Func.SigIndex, W.OS);
endSection(Section);
}
void WasmObjectWriter::writeGlobalSection() {
if (Globals.empty())
return;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_GLOBAL);
encodeULEB128(Globals.size(), W.OS);
for (const WasmGlobal &Global : Globals) {
writeValueType(static_cast<wasm::ValType>(Global.Type.Type));
W.OS << char(Global.Type.Mutable);
W.OS << char(wasm::WASM_OPCODE_I32_CONST);
encodeSLEB128(Global.InitialValue, W.OS);
W.OS << char(wasm::WASM_OPCODE_END);
}
endSection(Section);
}
void WasmObjectWriter::writeEventSection(ArrayRef<wasm::WasmEventType> Events) {
if (Events.empty())
return;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_EVENT);
encodeULEB128(Events.size(), W.OS);
for (const wasm::WasmEventType &Event : Events) {
encodeULEB128(Event.Attribute, W.OS);
encodeULEB128(Event.SigIndex, W.OS);
}
endSection(Section);
}
void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
if (Exports.empty())
return;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_EXPORT);
encodeULEB128(Exports.size(), W.OS);
for (const wasm::WasmExport &Export : Exports) {
writeString(Export.Name);
W.OS << char(Export.Kind);
encodeULEB128(Export.Index, W.OS);
}
endSection(Section);
}
void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) {
if (TableElems.empty())
return;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_ELEM);
encodeULEB128(1, W.OS); // number of "segments"
encodeULEB128(0, W.OS); // the table index
// init expr for starting offset
W.OS << char(wasm::WASM_OPCODE_I32_CONST);
encodeSLEB128(kInitialTableOffset, W.OS);
W.OS << char(wasm::WASM_OPCODE_END);
encodeULEB128(TableElems.size(), W.OS);
for (uint32_t Elem : TableElems)
encodeULEB128(Elem, W.OS);
endSection(Section);
}
void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
const MCAsmLayout &Layout,
ArrayRef<WasmFunction> Functions) {
if (Functions.empty())
return;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_CODE);
CodeSectionIndex = Section.Index;
encodeULEB128(Functions.size(), W.OS);
for (const WasmFunction &Func : Functions) {
auto &FuncSection = static_cast<MCSectionWasm &>(Func.Sym->getSection());
int64_t Size = 0;
if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
report_fatal_error(".size expression must be evaluatable");
encodeULEB128(Size, W.OS);
FuncSection.setSectionOffset(W.OS.tell() - Section.ContentsOffset);
Asm.writeSectionData(W.OS, &FuncSection, Layout);
}
// Apply fixups.
applyRelocations(CodeRelocations, Section.ContentsOffset);
endSection(Section);
}
void WasmObjectWriter::writeDataSection() {
if (DataSegments.empty())
return;
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_DATA);
DataSectionIndex = Section.Index;
encodeULEB128(DataSegments.size(), W.OS); // count
for (const WasmDataSegment &Segment : DataSegments) {
encodeULEB128(0, W.OS); // memory index
W.OS << char(wasm::WASM_OPCODE_I32_CONST);
encodeSLEB128(Segment.Offset, W.OS); // offset
W.OS << char(wasm::WASM_OPCODE_END);
encodeULEB128(Segment.Data.size(), W.OS); // size
Segment.Section->setSectionOffset(W.OS.tell() - Section.ContentsOffset);
W.OS << Segment.Data; // data
}
// Apply fixups.
applyRelocations(DataRelocations, Section.ContentsOffset);
endSection(Section);
}
void WasmObjectWriter::writeRelocSection(
uint32_t SectionIndex, StringRef Name,
std::vector<WasmRelocationEntry> &Relocs) {
// See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
// for descriptions of the reloc sections.
if (Relocs.empty())
return;
// First, ensure the relocations are sorted in offset order. In general they
// should already be sorted since `recordRelocation` is called in offset
// order, but for the code section we combine many MC sections into single
// wasm section, and this order is determined by the order of Asm.Symbols()
// not the sections order.
std::stable_sort(
Relocs.begin(), Relocs.end(),
[](const WasmRelocationEntry &A, const WasmRelocationEntry &B) {
return (A.Offset + A.FixupSection->getSectionOffset()) <
(B.Offset + B.FixupSection->getSectionOffset());
});
SectionBookkeeping Section;
startCustomSection(Section, std::string("reloc.") + Name.str());
encodeULEB128(SectionIndex, W.OS);
encodeULEB128(Relocs.size(), W.OS);
for (const WasmRelocationEntry &RelEntry : Relocs) {
uint64_t Offset =
RelEntry.Offset + RelEntry.FixupSection->getSectionOffset();
uint32_t Index = getRelocationIndexValue(RelEntry);
W.OS << char(RelEntry.Type);
encodeULEB128(Offset, W.OS);
encodeULEB128(Index, W.OS);
if (RelEntry.hasAddend())
encodeSLEB128(RelEntry.Addend, W.OS);
}
endSection(Section);
}
void WasmObjectWriter::writeCustomRelocSections() {
for (const auto &Sec : CustomSections) {
auto &Relocations = CustomSectionsRelocations[Sec.Section];
writeRelocSection(Sec.OutputIndex, Sec.Name, Relocations);
}
}
void WasmObjectWriter::writeLinkingMetaDataSection(
ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats) {
SectionBookkeeping Section;
startCustomSection(Section, "linking");
encodeULEB128(wasm::WasmMetadataVersion, W.OS);
SectionBookkeeping SubSection;
if (SymbolInfos.size() != 0) {
startSection(SubSection, wasm::WASM_SYMBOL_TABLE);
encodeULEB128(SymbolInfos.size(), W.OS);
for (const wasm::WasmSymbolInfo &Sym : SymbolInfos) {
encodeULEB128(Sym.Kind, W.OS);
encodeULEB128(Sym.Flags, W.OS);
switch (Sym.Kind) {
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
case wasm::WASM_SYMBOL_TYPE_EVENT:
encodeULEB128(Sym.ElementIndex, W.OS);
if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0 ||
(Sym.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0)
writeString(Sym.Name);
break;
case wasm::WASM_SYMBOL_TYPE_DATA:
writeString(Sym.Name);
if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) {
encodeULEB128(Sym.DataRef.Segment, W.OS);
encodeULEB128(Sym.DataRef.Offset, W.OS);
encodeULEB128(Sym.DataRef.Size, W.OS);
}
break;
case wasm::WASM_SYMBOL_TYPE_SECTION: {
const uint32_t SectionIndex =
CustomSections[Sym.ElementIndex].OutputIndex;
encodeULEB128(SectionIndex, W.OS);
break;
}
default:
llvm_unreachable("unexpected kind");
}
}
endSection(SubSection);
}
if (DataSegments.size()) {
startSection(SubSection, wasm::WASM_SEGMENT_INFO);
encodeULEB128(DataSegments.size(), W.OS);
for (const WasmDataSegment &Segment : DataSegments) {
writeString(Segment.Name);
encodeULEB128(Segment.Alignment, W.OS);
encodeULEB128(Segment.Flags, W.OS);
}
endSection(SubSection);
}
if (!InitFuncs.empty()) {
startSection(SubSection, wasm::WASM_INIT_FUNCS);
encodeULEB128(InitFuncs.size(), W.OS);
for (auto &StartFunc : InitFuncs) {
encodeULEB128(StartFunc.first, W.OS); // priority
encodeULEB128(StartFunc.second, W.OS); // function index
}
endSection(SubSection);
}
if (Comdats.size()) {
startSection(SubSection, wasm::WASM_COMDAT_INFO);
encodeULEB128(Comdats.size(), W.OS);
for (const auto &C : Comdats) {
writeString(C.first);
encodeULEB128(0, W.OS); // flags for future use
encodeULEB128(C.second.size(), W.OS);
for (const WasmComdatEntry &Entry : C.second) {
encodeULEB128(Entry.Kind, W.OS);
encodeULEB128(Entry.Index, W.OS);
}
}
endSection(SubSection);
}
endSection(Section);
}
void WasmObjectWriter::writeCustomSections(const MCAssembler &Asm,
const MCAsmLayout &Layout) {
for (auto &CustomSection : CustomSections) {
SectionBookkeeping Section;
auto *Sec = CustomSection.Section;
startCustomSection(Section, CustomSection.Name);
Sec->setSectionOffset(W.OS.tell() - Section.ContentsOffset);
Asm.writeSectionData(W.OS, Sec, Layout);
CustomSection.OutputContentsOffset = Section.ContentsOffset;
CustomSection.OutputIndex = Section.Index;
endSection(Section);
// Apply fixups.
auto &Relocations = CustomSectionsRelocations[CustomSection.Section];
applyRelocations(Relocations, CustomSection.OutputContentsOffset);
}
}
uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) {
assert(Symbol.isFunction());
assert(TypeIndices.count(&Symbol));
return TypeIndices[&Symbol];
}
uint32_t WasmObjectWriter::getEventType(const MCSymbolWasm &Symbol) {
assert(Symbol.isEvent());
assert(TypeIndices.count(&Symbol));
return TypeIndices[&Symbol];
}
void WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) {
assert(Symbol.isFunction());
WasmSignature S;
const MCSymbolWasm *ResolvedSym = ResolveSymbol(Symbol);
if (auto *Sig = ResolvedSym->getSignature()) {
S.Returns = Sig->Returns;
S.Params = Sig->Params;
}
auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size()));
if (Pair.second)
Signatures.push_back(S);
TypeIndices[&Symbol] = Pair.first->second;
LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol
<< " new:" << Pair.second << "\n");
LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
}
void WasmObjectWriter::registerEventType(const MCSymbolWasm &Symbol) {
assert(Symbol.isEvent());
// TODO Currently we don't generate imported exceptions, but if we do, we
// should have a way of infering types of imported exceptions.
WasmSignature S;
if (auto *Sig = Symbol.getSignature()) {
S.Returns = Sig->Returns;
S.Params = Sig->Params;
}
auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size()));
if (Pair.second)
Signatures.push_back(S);
TypeIndices[&Symbol] = Pair.first->second;
LLVM_DEBUG(dbgs() << "registerEventType: " << Symbol << " new:" << Pair.second
<< "\n");
LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
}
static bool isInSymtab(const MCSymbolWasm &Sym) {
if (Sym.isUsedInReloc())
return true;
if (Sym.isComdat() && !Sym.isDefined())
return false;
if (Sym.isTemporary() && Sym.getName().empty())
return false;
if (Sym.isTemporary() && Sym.isData() && !Sym.getSize())
return false;
if (Sym.isSection())
return false;
return true;
}
uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
const MCAsmLayout &Layout) {
uint64_t StartOffset = W.OS.tell();
LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
MCContext &Ctx = Asm.getContext();
// Collect information from the available symbols.
SmallVector<WasmFunction, 4> Functions;
SmallVector<uint32_t, 4> TableElems;
SmallVector<wasm::WasmImport, 4> Imports;
SmallVector<wasm::WasmExport, 4> Exports;
SmallVector<wasm::WasmEventType, 1> Events;
SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos;
SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
uint32_t DataSize = 0;
// For now, always emit the memory import, since loads and stores are not
// valid without it. In the future, we could perhaps be more clever and omit
// it if there are no loads or stores.
MCSymbolWasm *MemorySym =
cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__linear_memory"));
wasm::WasmImport MemImport;
MemImport.Module = MemorySym->getImportModule();
MemImport.Field = MemorySym->getImportName();
MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY;
Imports.push_back(MemImport);
// For now, always emit the table section, since indirect calls are not
// valid without it. In the future, we could perhaps be more clever and omit
// it if there are no indirect calls.
MCSymbolWasm *TableSym =
cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__indirect_function_table"));
wasm::WasmImport TableImport;
TableImport.Module = TableSym->getImportModule();
TableImport.Field = TableSym->getImportName();
TableImport.Kind = wasm::WASM_EXTERNAL_TABLE;
TableImport.Table.ElemType = wasm::WASM_TYPE_FUNCREF;
Imports.push_back(TableImport);
// Populate SignatureIndices, and Imports and WasmIndices for undefined
// symbols. This must be done before populating WasmIndices for defined
// symbols.
for (const MCSymbol &S : Asm.symbols()) {
const auto &WS = static_cast<const MCSymbolWasm &>(S);
// Register types for all functions, including those with private linkage
// (because wasm always needs a type signature).
if (WS.isFunction())
registerFunctionType(WS);
if (WS.isEvent())
registerEventType(WS);
if (WS.isTemporary())
continue;
// If the symbol is not defined in this translation unit, import it.
if (!WS.isDefined() && !WS.isComdat()) {
if (WS.isFunction()) {
wasm::WasmImport Import;
Import.Module = WS.getImportModule();
Import.Field = WS.getImportName();
Import.Kind = wasm::WASM_EXTERNAL_FUNCTION;
Import.SigIndex = getFunctionType(WS);
Imports.push_back(Import);
WasmIndices[&WS] = NumFunctionImports++;
} else if (WS.isGlobal()) {
if (WS.isWeak())
report_fatal_error("undefined global symbol cannot be weak");
wasm::WasmImport Import;
Import.Module = WS.getImportModule();
Import.Field = WS.getImportName();
Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
Import.Global = WS.getGlobalType();
Imports.push_back(Import);
WasmIndices[&WS] = NumGlobalImports++;
} else if (WS.isEvent()) {
if (WS.isWeak())
report_fatal_error("undefined event symbol cannot be weak");
wasm::WasmImport Import;
Import.Module = WS.getImportModule();
Import.Field = WS.getImportName();
Import.Kind = wasm::WASM_EXTERNAL_EVENT;
Import.Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION;
Import.Event.SigIndex = getEventType(WS);
Imports.push_back(Import);
WasmIndices[&WS] = NumEventImports++;
}
}
}
// Populate DataSegments and CustomSections, which must be done before
// populating DataLocations.
for (MCSection &Sec : Asm) {
auto &Section = static_cast<MCSectionWasm &>(Sec);
StringRef SectionName = Section.getSectionName();
// .init_array sections are handled specially elsewhere.
if (SectionName.startswith(".init_array"))
continue;
// Code is handled separately
if (Section.getKind().isText())
continue;
if (Section.isWasmData()) {
uint32_t SegmentIndex = DataSegments.size();
DataSize = alignTo(DataSize, Section.getAlignment());
DataSegments.emplace_back();
WasmDataSegment &Segment = DataSegments.back();
Segment.Name = SectionName;
Segment.Offset = DataSize;
Segment.Section = &Section;
addData(Segment.Data, Section);
Segment.Alignment = Log2_32(Section.getAlignment());
Segment.Flags = 0;
DataSize += Segment.Data.size();
Section.setSegmentIndex(SegmentIndex);
if (const MCSymbolWasm *C = Section.getGroup()) {
Comdats[C->getName()].emplace_back(
WasmComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex});
}
} else {
// Create custom sections
assert(Sec.getKind().isMetadata());
StringRef Name = SectionName;
// For user-defined custom sections, strip the prefix
if (Name.startswith(".custom_section."))
Name = Name.substr(strlen(".custom_section."));
MCSymbol *Begin = Sec.getBeginSymbol();
if (Begin) {
WasmIndices[cast<MCSymbolWasm>(Begin)] = CustomSections.size();
if (SectionName != Begin->getName())
report_fatal_error("section name and begin symbol should match: " +
Twine(SectionName));
}
CustomSections.emplace_back(Name, &Section);
}
}
// Populate WasmIndices and DataLocations for defined symbols.
for (const MCSymbol &S : Asm.symbols()) {
// Ignore unnamed temporary symbols, which aren't ever exported, imported,
// or used in relocations.
if (S.isTemporary() && S.getName().empty())
continue;
const auto &WS = static_cast<const MCSymbolWasm &>(S);
LLVM_DEBUG(
dbgs() << "MCSymbol: " << toString(WS.getType()) << " '" << S << "'"
<< " isDefined=" << S.isDefined() << " isExternal="
<< S.isExternal() << " isTemporary=" << S.isTemporary()
<< " isWeak=" << WS.isWeak() << " isHidden=" << WS.isHidden()
<< " isVariable=" << WS.isVariable() << "\n");
if (WS.isVariable())
continue;
if (WS.isComdat() && !WS.isDefined())
continue;
if (WS.isFunction()) {
unsigned Index;
if (WS.isDefined()) {
if (WS.getOffset() != 0)
report_fatal_error(
"function sections must contain one function each");
if (WS.getSize() == 0)
report_fatal_error(
"function symbols must have a size set with .size");
// A definition. Write out the function body.
Index = NumFunctionImports + Functions.size();
WasmFunction Func;
Func.SigIndex = getFunctionType(WS);
Func.Sym = &WS;
WasmIndices[&WS] = Index;
Functions.push_back(Func);
auto &Section = static_cast<MCSectionWasm &>(WS.getSection());
if (const MCSymbolWasm *C = Section.getGroup()) {
Comdats[C->getName()].emplace_back(
WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index});
}
} else {
// An import; the index was assigned above.
Index = WasmIndices.find(&WS)->second;
}
LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n");
} else if (WS.isData()) {
if (WS.isTemporary() && !WS.getSize())
continue;
if (!WS.isDefined()) {
LLVM_DEBUG(dbgs() << " -> segment index: -1"
<< "\n");
continue;
}
if (!WS.getSize())
report_fatal_error("data symbols must have a size set with .size: " +
WS.getName());
int64_t Size = 0;
if (!WS.getSize()->evaluateAsAbsolute(Size, Layout))
report_fatal_error(".size expression must be evaluatable");
auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
assert(DataSection.isWasmData());
// For each data symbol, export it in the symtab as a reference to the
// corresponding Wasm data segment.
wasm::WasmDataReference Ref = wasm::WasmDataReference{
DataSection.getSegmentIndex(),
static_cast<uint32_t>(Layout.getSymbolOffset(WS)),
static_cast<uint32_t>(Size)};
DataLocations[&WS] = Ref;
LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n");
} else if (WS.isGlobal()) {
// A "true" Wasm global (currently just __stack_pointer)
if (WS.isDefined())
report_fatal_error("don't yet support defined globals");
// An import; the index was assigned above
LLVM_DEBUG(dbgs() << " -> global index: "
<< WasmIndices.find(&WS)->second << "\n");
} else if (WS.isEvent()) {
// C++ exception symbol (__cpp_exception)
unsigned Index;
if (WS.isDefined()) {
Index = NumEventImports + Events.size();
wasm::WasmEventType Event;
Event.SigIndex = getEventType(WS);
Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION;
WasmIndices[&WS] = Index;
Events.push_back(Event);
} else {
// An import; the index was assigned above.
Index = WasmIndices.find(&WS)->second;
}
LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices.find(&WS)->second
<< "\n");
} else {
assert(WS.isSection());
}
}
// Populate WasmIndices and DataLocations for aliased symbols. We need to
// process these in a separate pass because we need to have processed the
// target of the alias before the alias itself and the symbols are not
// necessarily ordered in this way.
for (const MCSymbol &S : Asm.symbols()) {
if (!S.isVariable())
continue;
assert(S.isDefined());
// Find the target symbol of this weak alias and export that index
const auto &WS = static_cast<const MCSymbolWasm &>(S);
const MCSymbolWasm *ResolvedSym = ResolveSymbol(WS);
LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym
<< "'\n");
if (WS.isFunction()) {
assert(WasmIndices.count(ResolvedSym) > 0);
uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second;
WasmIndices[&WS] = WasmIndex;
LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n");
} else if (WS.isData()) {
assert(DataLocations.count(ResolvedSym) > 0);
const wasm::WasmDataReference &Ref =
DataLocations.find(ResolvedSym)->second;
DataLocations[&WS] = Ref;
LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n");
} else {
report_fatal_error("don't yet support global/event aliases");
}
}
// Finally, populate the symbol table itself, in its "natural" order.
for (const MCSymbol &S : Asm.symbols()) {
const auto &WS = static_cast<const MCSymbolWasm &>(S);
if (!isInSymtab(WS)) {
WS.setIndex(INVALID_INDEX);
continue;
}
LLVM_DEBUG(dbgs() << "adding to symtab: " << WS << "\n");
uint32_t Flags = 0;
if (WS.isWeak())
Flags |= wasm::WASM_SYMBOL_BINDING_WEAK;
if (WS.isHidden())
Flags |= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN;
if (!WS.isExternal() && WS.isDefined())
Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
if (WS.isUndefined())
Flags |= wasm::WASM_SYMBOL_UNDEFINED;
if (WS.getName() != WS.getImportName())
Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME;
wasm::WasmSymbolInfo Info;
Info.Name = WS.getName();
Info.Kind = WS.getType();
Info.Flags = Flags;
if (!WS.isData()) {
assert(WasmIndices.count(&WS) > 0);
Info.ElementIndex = WasmIndices.find(&WS)->second;
} else if (WS.isDefined()) {
assert(DataLocations.count(&WS) > 0);
Info.DataRef = DataLocations.find(&WS)->second;
}
WS.setIndex(SymbolInfos.size());
SymbolInfos.emplace_back(Info);
}
{
auto HandleReloc = [&](const WasmRelocationEntry &Rel) {
// Functions referenced by a relocation need to put in the table. This is
// purely to make the object file's provisional values readable, and is
// ignored by the linker, which re-calculates the relocations itself.
if (Rel.Type != wasm::R_WEBASSEMBLY_TABLE_INDEX_I32 &&
Rel.Type != wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB)
return;
assert(Rel.Symbol->isFunction());
const MCSymbolWasm &WS = *ResolveSymbol(*Rel.Symbol);
uint32_t FunctionIndex = WasmIndices.find(&WS)->second;
uint32_t TableIndex = TableElems.size() + kInitialTableOffset;
if (TableIndices.try_emplace(&WS, TableIndex).second) {
LLVM_DEBUG(dbgs() << " -> adding " << WS.getName()
<< " to table: " << TableIndex << "\n");
TableElems.push_back(FunctionIndex);
registerFunctionType(WS);
}
};
for (const WasmRelocationEntry &RelEntry : CodeRelocations)
HandleReloc(RelEntry);
for (const WasmRelocationEntry &RelEntry : DataRelocations)
HandleReloc(RelEntry);
}
// Translate .init_array section contents into start functions.
for (const MCSection &S : Asm) {
const auto &WS = static_cast<const MCSectionWasm &>(S);
if (WS.getSectionName().startswith(".fini_array"))
report_fatal_error(".fini_array sections are unsupported");
if (!WS.getSectionName().startswith(".init_array"))
continue;
if (WS.getFragmentList().empty())
continue;
// init_array is expected to contain a single non-empty data fragment
if (WS.getFragmentList().size() != 3)
report_fatal_error("only one .init_array section fragment supported");
auto IT = WS.begin();
const MCFragment &EmptyFrag = *IT;
if (EmptyFrag.getKind() != MCFragment::FT_Data)
report_fatal_error(".init_array section should be aligned");
IT = std::next(IT);
const MCFragment &AlignFrag = *IT;
if (AlignFrag.getKind() != MCFragment::FT_Align)
report_fatal_error(".init_array section should be aligned");
if (cast<MCAlignFragment>(AlignFrag).getAlignment() != (is64Bit() ? 8 : 4))
report_fatal_error(".init_array section should be aligned for pointers");
const MCFragment &Frag = *std::next(IT);
if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
report_fatal_error("only data supported in .init_array section");
uint16_t Priority = UINT16_MAX;
unsigned PrefixLength = strlen(".init_array");
if (WS.getSectionName().size() > PrefixLength) {
if (WS.getSectionName()[PrefixLength] != '.')
report_fatal_error(
".init_array section priority should start with '.'");
if (WS.getSectionName()
.substr(PrefixLength + 1)
.getAsInteger(10, Priority))
report_fatal_error("invalid .init_array section priority");
}
const auto &DataFrag = cast<MCDataFragment>(Frag);
const SmallVectorImpl<char> &Contents = DataFrag.getContents();
for (const uint8_t *
p = (const uint8_t *)Contents.data(),
*end = (const uint8_t *)Contents.data() + Contents.size();
p != end; ++p) {
if (*p != 0)
report_fatal_error("non-symbolic data in .init_array section");
}
for (const MCFixup &Fixup : DataFrag.getFixups()) {
assert(Fixup.getKind() ==
MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
const MCExpr *Expr = Fixup.getValue();
auto *Sym = dyn_cast<MCSymbolRefExpr>(Expr);
if (!Sym)
report_fatal_error("fixups in .init_array should be symbol references");
if (Sym->getKind() != MCSymbolRefExpr::VK_WebAssembly_FUNCTION)
report_fatal_error("symbols in .init_array should be for functions");
if (Sym->getSymbol().getIndex() == INVALID_INDEX)
report_fatal_error("symbols in .init_array should exist in symbtab");
InitFuncs.push_back(
std::make_pair(Priority, Sym->getSymbol().getIndex()));
}
}
// Write out the Wasm header.
writeHeader(Asm);
writeTypeSection(Signatures);
writeImportSection(Imports, DataSize, TableElems.size());
writeFunctionSection(Functions);
// Skip the "table" section; we import the table instead.
// Skip the "memory" section; we import the memory instead.
writeGlobalSection();
writeEventSection(Events);
writeExportSection(Exports);
writeElemSection(TableElems);
writeCodeSection(Asm, Layout, Functions);
writeDataSection();
writeCustomSections(Asm, Layout);
writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats);
writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations);
writeRelocSection(DataSectionIndex, "DATA", DataRelocations);
writeCustomRelocSections();
// TODO: Translate the .comment section to the output.
return W.OS.tell() - StartOffset;
}
std::unique_ptr<MCObjectWriter>
llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
raw_pwrite_stream &OS) {
return llvm::make_unique<WasmObjectWriter>(std::move(MOTW), OS);
}
Index: stable/11/contrib/llvm/lib/Object/COFFImportFile.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Object/COFFImportFile.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Object/COFFImportFile.cpp (revision 350259)
@@ -1,623 +1,623 @@
//===- COFFImportFile.cpp - COFF short import file implementation ---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the writeImportLibrary function.
//
//===----------------------------------------------------------------------===//
#include "llvm/Object/COFFImportFile.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Path.h"
#include <cstdint>
#include <string>
#include <vector>
using namespace llvm::COFF;
using namespace llvm::object;
using namespace llvm;
namespace llvm {
namespace object {
static bool is32bit(MachineTypes Machine) {
switch (Machine) {
default:
llvm_unreachable("unsupported machine");
case IMAGE_FILE_MACHINE_ARM64:
case IMAGE_FILE_MACHINE_AMD64:
return false;
case IMAGE_FILE_MACHINE_ARMNT:
case IMAGE_FILE_MACHINE_I386:
return true;
}
}
static uint16_t getImgRelRelocation(MachineTypes Machine) {
switch (Machine) {
default:
llvm_unreachable("unsupported machine");
case IMAGE_FILE_MACHINE_AMD64:
return IMAGE_REL_AMD64_ADDR32NB;
case IMAGE_FILE_MACHINE_ARMNT:
return IMAGE_REL_ARM_ADDR32NB;
case IMAGE_FILE_MACHINE_ARM64:
return IMAGE_REL_ARM64_ADDR32NB;
case IMAGE_FILE_MACHINE_I386:
return IMAGE_REL_I386_DIR32NB;
}
}
template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
size_t S = B.size();
B.resize(S + sizeof(T));
memcpy(&B[S], &Data, sizeof(T));
}
static void writeStringTable(std::vector<uint8_t> &B,
ArrayRef<const std::string> Strings) {
// The COFF string table consists of a 4-byte value which is the size of the
// table, including the length field itself. This value is followed by the
// string content itself, which is an array of null-terminated C-style
// strings. The termination is important as they are referenced to by offset
// by the symbol entity in the file format.
size_t Pos = B.size();
size_t Offset = B.size();
// Skip over the length field, we will fill it in later as we will have
// computed the length while emitting the string content itself.
Pos += sizeof(uint32_t);
for (const auto &S : Strings) {
B.resize(Pos + S.length() + 1);
strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
Pos += S.length() + 1;
}
// Backfill the length of the table now that it has been computed.
support::ulittle32_t Length(B.size() - Offset);
support::endian::write32le(&B[Offset], Length);
}
static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
MachineTypes Machine, bool MinGW) {
// A decorated stdcall function in MSVC is exported with the
// type IMPORT_NAME, and the exported function name includes the
// the leading underscore. In MinGW on the other hand, a decorated
// stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX).
// See the comment in isDecorated in COFFModuleDefinition.cpp for more
// details.
if (ExtName.startswith("_") && ExtName.contains('@') && !MinGW)
return IMPORT_NAME;
if (Sym != ExtName)
return IMPORT_NAME_UNDECORATE;
if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
return IMPORT_NAME_NOPREFIX;
return IMPORT_NAME;
}
static Expected<std::string> replace(StringRef S, StringRef From,
StringRef To) {
size_t Pos = S.find(From);
// From and To may be mangled, but substrings in S may not.
if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
From = From.substr(1);
To = To.substr(1);
Pos = S.find(From);
}
if (Pos == StringRef::npos) {
return make_error<StringError>(
StringRef(Twine(S + ": replacing '" + From +
"' with '" + To + "' failed").str()), object_error::parse_failed);
}
return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
}
static const std::string NullImportDescriptorSymbolName =
"__NULL_IMPORT_DESCRIPTOR";
namespace {
// This class constructs various small object files necessary to support linking
// symbols imported from a DLL. The contents are pretty strictly defined and
// nearly entirely static. The details of the structures files are defined in
// WINNT.h and the PE/COFF specification.
class ObjectFactory {
using u16 = support::ulittle16_t;
using u32 = support::ulittle32_t;
MachineTypes Machine;
BumpPtrAllocator Alloc;
StringRef ImportName;
StringRef Library;
std::string ImportDescriptorSymbolName;
std::string NullThunkSymbolName;
public:
ObjectFactory(StringRef S, MachineTypes M)
: Machine(M), ImportName(S), Library(S.drop_back(4)),
ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
// Creates an Import Descriptor. This is a small object file which contains a
// reference to the terminators and contains the library name (entry) for the
// import name table. It will force the linker to construct the necessary
// structure to import symbols from the DLL.
NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
// Creates a NULL import descriptor. This is a small object file whcih
// contains a NULL import descriptor. It is used to terminate the imports
// from a specific DLL.
NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
// Create a NULL Thunk Entry. This is a small object file which contains a
// NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
// is used to terminate the IAT and ILT.
NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
// Create a short import file which is described in PE/COFF spec 7. Import
// Library Format.
NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
ImportType Type, ImportNameType NameType);
// Create a weak external file which is described in PE/COFF Aux Format 3.
NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp);
};
} // namespace
NewArchiveMember
ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
const uint32_t NumberOfSections = 2;
const uint32_t NumberOfSymbols = 7;
const uint32_t NumberOfRelocations = 3;
// COFF Header
coff_file_header Header{
u16(Machine),
u16(NumberOfSections),
u32(0),
u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
// .idata$2
sizeof(coff_import_directory_table_entry) +
NumberOfRelocations * sizeof(coff_relocation) +
// .idata$4
(ImportName.size() + 1)),
u32(NumberOfSymbols),
u16(0),
u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
};
append(Buffer, Header);
// Section Header Table
const coff_section SectionTable[NumberOfSections] = {
{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
u32(0),
u32(0),
u32(sizeof(coff_import_directory_table_entry)),
u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
sizeof(coff_import_directory_table_entry)),
u32(0),
u16(NumberOfRelocations),
u16(0),
u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
u32(0),
u32(0),
u32(ImportName.size() + 1),
u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
sizeof(coff_import_directory_table_entry) +
NumberOfRelocations * sizeof(coff_relocation)),
u32(0),
u32(0),
u16(0),
u16(0),
u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
};
append(Buffer, SectionTable);
// .idata$2
const coff_import_directory_table_entry ImportDescriptor{
u32(0), u32(0), u32(0), u32(0), u32(0),
};
append(Buffer, ImportDescriptor);
const coff_relocation RelocationTable[NumberOfRelocations] = {
{u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
u16(getImgRelRelocation(Machine))},
{u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
u32(3), u16(getImgRelRelocation(Machine))},
{u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
u32(4), u16(getImgRelRelocation(Machine))},
};
append(Buffer, RelocationTable);
// .idata$6
auto S = Buffer.size();
Buffer.resize(S + ImportName.size() + 1);
memcpy(&Buffer[S], ImportName.data(), ImportName.size());
Buffer[S + ImportName.size()] = '\0';
// Symbol Table
coff_symbol16 SymbolTable[NumberOfSymbols] = {
{{{0, 0, 0, 0, 0, 0, 0, 0}},
u32(0),
u16(1),
u16(0),
IMAGE_SYM_CLASS_EXTERNAL,
0},
{{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
u32(0),
u16(1),
u16(0),
IMAGE_SYM_CLASS_SECTION,
0},
{{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
u32(0),
u16(2),
u16(0),
IMAGE_SYM_CLASS_STATIC,
0},
{{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
u32(0),
u16(0),
u16(0),
IMAGE_SYM_CLASS_SECTION,
0},
{{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
u32(0),
u16(0),
u16(0),
IMAGE_SYM_CLASS_SECTION,
0},
{{{0, 0, 0, 0, 0, 0, 0, 0}},
u32(0),
u16(0),
u16(0),
IMAGE_SYM_CLASS_EXTERNAL,
0},
{{{0, 0, 0, 0, 0, 0, 0, 0}},
u32(0),
u16(0),
u16(0),
IMAGE_SYM_CLASS_EXTERNAL,
0},
};
// TODO: Name.Offset.Offset here and in the all similar places below
// suggests a names refactoring. Maybe StringTableOffset.Value?
SymbolTable[0].Name.Offset.Offset =
sizeof(uint32_t);
SymbolTable[5].Name.Offset.Offset =
sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
SymbolTable[6].Name.Offset.Offset =
sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
NullImportDescriptorSymbolName.length() + 1;
append(Buffer, SymbolTable);
// String Table
writeStringTable(Buffer,
{ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
NullThunkSymbolName});
StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
return {MemoryBufferRef(F, ImportName)};
}
NewArchiveMember
ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
const uint32_t NumberOfSections = 1;
const uint32_t NumberOfSymbols = 1;
// COFF Header
coff_file_header Header{
u16(Machine),
u16(NumberOfSections),
u32(0),
u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
// .idata$3
sizeof(coff_import_directory_table_entry)),
u32(NumberOfSymbols),
u16(0),
u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
};
append(Buffer, Header);
// Section Header Table
const coff_section SectionTable[NumberOfSections] = {
{{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
u32(0),
u32(0),
u32(sizeof(coff_import_directory_table_entry)),
u32(sizeof(coff_file_header) +
(NumberOfSections * sizeof(coff_section))),
u32(0),
u32(0),
u16(0),
u16(0),
u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
};
append(Buffer, SectionTable);
// .idata$3
const coff_import_directory_table_entry ImportDescriptor{
u32(0), u32(0), u32(0), u32(0), u32(0),
};
append(Buffer, ImportDescriptor);
// Symbol Table
coff_symbol16 SymbolTable[NumberOfSymbols] = {
{{{0, 0, 0, 0, 0, 0, 0, 0}},
u32(0),
u16(1),
u16(0),
IMAGE_SYM_CLASS_EXTERNAL,
0},
};
SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
append(Buffer, SymbolTable);
// String Table
writeStringTable(Buffer, {NullImportDescriptorSymbolName});
StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
return {MemoryBufferRef(F, ImportName)};
}
NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
const uint32_t NumberOfSections = 2;
const uint32_t NumberOfSymbols = 1;
uint32_t VASize = is32bit(Machine) ? 4 : 8;
// COFF Header
coff_file_header Header{
u16(Machine),
u16(NumberOfSections),
u32(0),
u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
// .idata$5
VASize +
// .idata$4
VASize),
u32(NumberOfSymbols),
u16(0),
u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
};
append(Buffer, Header);
// Section Header Table
const coff_section SectionTable[NumberOfSections] = {
{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
u32(0),
u32(0),
u32(VASize),
u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
u32(0),
u32(0),
u16(0),
u16(0),
u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
: IMAGE_SCN_ALIGN_8BYTES) |
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_WRITE)},
{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
u32(0),
u32(0),
u32(VASize),
u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
VASize),
u32(0),
u32(0),
u16(0),
u16(0),
u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
: IMAGE_SCN_ALIGN_8BYTES) |
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_WRITE)},
};
append(Buffer, SectionTable);
// .idata$5, ILT
append(Buffer, u32(0));
if (!is32bit(Machine))
append(Buffer, u32(0));
// .idata$4, IAT
append(Buffer, u32(0));
if (!is32bit(Machine))
append(Buffer, u32(0));
// Symbol Table
coff_symbol16 SymbolTable[NumberOfSymbols] = {
{{{0, 0, 0, 0, 0, 0, 0, 0}},
u32(0),
u16(1),
u16(0),
IMAGE_SYM_CLASS_EXTERNAL,
0},
};
SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
append(Buffer, SymbolTable);
// String Table
writeStringTable(Buffer, {NullThunkSymbolName});
StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
return {MemoryBufferRef{F, ImportName}};
}
NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
uint16_t Ordinal,
ImportType ImportType,
ImportNameType NameType) {
size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
size_t Size = sizeof(coff_import_header) + ImpSize;
char *Buf = Alloc.Allocate<char>(Size);
memset(Buf, 0, Size);
char *P = Buf;
// Write short import library.
auto *Imp = reinterpret_cast<coff_import_header *>(P);
P += sizeof(*Imp);
Imp->Sig2 = 0xFFFF;
Imp->Machine = Machine;
Imp->SizeOfData = ImpSize;
if (Ordinal > 0)
Imp->OrdinalHint = Ordinal;
Imp->TypeInfo = (NameType << 2) | ImportType;
// Write symbol name and DLL name.
memcpy(P, Sym.data(), Sym.size());
P += Sym.size() + 1;
memcpy(P, ImportName.data(), ImportName.size());
return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
}
NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
StringRef Weak, bool Imp) {
std::vector<uint8_t> Buffer;
const uint32_t NumberOfSections = 1;
const uint32_t NumberOfSymbols = 5;
// COFF Header
coff_file_header Header{
- u16(0),
+ u16(Machine),
u16(NumberOfSections),
u32(0),
u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
u32(NumberOfSymbols),
u16(0),
u16(0),
};
append(Buffer, Header);
// Section Header Table
const coff_section SectionTable[NumberOfSections] = {
{{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
u32(0),
u32(0),
u32(0),
u32(0),
u32(0),
u32(0),
u16(0),
u16(0),
u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
append(Buffer, SectionTable);
// Symbol Table
coff_symbol16 SymbolTable[NumberOfSymbols] = {
{{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
u32(0),
u16(0xFFFF),
u16(0),
IMAGE_SYM_CLASS_STATIC,
0},
{{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
u32(0),
u16(0xFFFF),
u16(0),
IMAGE_SYM_CLASS_STATIC,
0},
{{{0, 0, 0, 0, 0, 0, 0, 0}},
u32(0),
u16(0),
u16(0),
IMAGE_SYM_CLASS_EXTERNAL,
0},
{{{0, 0, 0, 0, 0, 0, 0, 0}},
u32(0),
u16(0),
u16(0),
IMAGE_SYM_CLASS_WEAK_EXTERNAL,
1},
{{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}},
u32(0),
u16(0),
u16(0),
IMAGE_SYM_CLASS_NULL,
0},
};
SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
//__imp_ String Table
StringRef Prefix = Imp ? "__imp_" : "";
SymbolTable[3].Name.Offset.Offset =
sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
append(Buffer, SymbolTable);
writeStringTable(Buffer, {(Prefix + Sym).str(),
(Prefix + Weak).str()});
// Copied here so we can still use writeStringTable
char *Buf = Alloc.Allocate<char>(Buffer.size());
memcpy(Buf, Buffer.data(), Buffer.size());
return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
}
Error writeImportLibrary(StringRef ImportName, StringRef Path,
ArrayRef<COFFShortExport> Exports,
MachineTypes Machine, bool MinGW) {
std::vector<NewArchiveMember> Members;
ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine);
std::vector<uint8_t> ImportDescriptor;
Members.push_back(OF.createImportDescriptor(ImportDescriptor));
std::vector<uint8_t> NullImportDescriptor;
Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
std::vector<uint8_t> NullThunk;
Members.push_back(OF.createNullThunk(NullThunk));
for (COFFShortExport E : Exports) {
if (E.Private)
continue;
ImportType ImportType = IMPORT_CODE;
if (E.Data)
ImportType = IMPORT_DATA;
if (E.Constant)
ImportType = IMPORT_CONST;
StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
ImportNameType NameType = getNameType(SymbolName, E.Name, Machine, MinGW);
Expected<std::string> Name = E.ExtName.empty()
? SymbolName
: replace(SymbolName, E.Name, E.ExtName);
if (!Name)
return Name.takeError();
if (!E.AliasTarget.empty() && *Name != E.AliasTarget) {
Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, false));
Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, true));
continue;
}
Members.push_back(
OF.createShortImport(*Name, E.Ordinal, ImportType, NameType));
}
return writeArchive(Path, Members, /*WriteSymtab*/ true,
object::Archive::K_GNU,
/*Deterministic*/ true, /*Thin*/ false);
}
} // namespace object
} // namespace llvm
Index: stable/11/contrib/llvm/lib/Target/AArch64/AArch64SchedExynosM4.td
===================================================================
--- stable/11/contrib/llvm/lib/Target/AArch64/AArch64SchedExynosM4.td (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/AArch64/AArch64SchedExynosM4.td (revision 350259)
@@ -1,1004 +1,1004 @@
//=- AArch64SchedExynosM4.td - Samsung Exynos M4 Sched Defs --*- tablegen -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the machine model for the Samsung Exynos M4 to support
// instruction scheduling and other instruction cost heuristics.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// The Exynos-M4 is an advanced superscalar microprocessor with a 6-wide
// in-order stage for decode and dispatch and a wider issue stage.
// The execution units and loads and stores are out-of-order.
def ExynosM4Model : SchedMachineModel {
let IssueWidth = 6; // Up to 6 uops per cycle.
let MicroOpBufferSize = 228; // ROB size.
let LoopMicroOpBufferSize = 48; // Based on the instruction queue size.
let LoadLatency = 4; // Optimistic load cases.
let MispredictPenalty = 16; // Minimum branch misprediction penalty.
let CompleteModel = 1; // Use the default model otherwise.
list<Predicate> UnsupportedFeatures = [HasSVE];
}
//===----------------------------------------------------------------------===//
// Define each kind of processor resource and number available on the Exynos-M4.
let SchedModel = ExynosM4Model in {
def M4UnitA : ProcResource<2>; // Simple integer
def M4UnitC : ProcResource<2>; // Simple and complex integer
let Super = M4UnitC, BufferSize = 1 in
def M4UnitD : ProcResource<1>; // Integer division (inside C0, serialized)
let Super = M4UnitC in
def M4UnitE : ProcResource<1>; // CRC (inside C0)
def M4UnitB : ProcResource<2>; // Branch
def M4UnitL0 : ProcResource<1>; // Load
def M4UnitS0 : ProcResource<1>; // Store
def M4PipeLS : ProcResource<1>; // Load/Store
let Super = M4PipeLS in {
def M4UnitL1 : ProcResource<1>;
def M4UnitS1 : ProcResource<1>;
}
def M4PipeF0 : ProcResource<1>; // FP #0
let Super = M4PipeF0 in {
def M4UnitFMAC0 : ProcResource<1>; // FP multiplication
def M4UnitFADD0 : ProcResource<1>; // Simple FP
def M4UnitFCVT0 : ProcResource<1>; // FP conversion
def M4UnitNALU0 : ProcResource<1>; // Simple vector
def M4UnitNHAD : ProcResource<1>; // Horizontal vector
def M4UnitNMSC : ProcResource<1>; // FP and vector miscellanea
def M4UnitNMUL0 : ProcResource<1>; // Vector multiplication
def M4UnitNSHT0 : ProcResource<1>; // Vector shifting
def M4UnitNSHF0 : ProcResource<1>; // Vector shuffling
def M4UnitNCRY0 : ProcResource<1>; // Cryptographic
}
def M4PipeF1 : ProcResource<1>; // FP #1
let Super = M4PipeF1 in {
def M4UnitFMAC1 : ProcResource<1>; // FP multiplication
def M4UnitFADD1 : ProcResource<1>; // Simple FP
def M4UnitFDIV0 : ProcResource<2>; // FP division (serialized)
def M4UnitFSQR0 : ProcResource<2>; // FP square root (serialized)
def M4UnitFST0 : ProcResource<1>; // FP store
def M4UnitNALU1 : ProcResource<1>; // Simple vector
def M4UnitNSHT1 : ProcResource<1>; // Vector shifting
def M4UnitNSHF1 : ProcResource<1>; // Vector shuffling
}
def M4PipeF2 : ProcResource<1>; // FP #2
let Super = M4PipeF2 in {
def M4UnitFMAC2 : ProcResource<1>; // FP multiplication
def M4UnitFADD2 : ProcResource<1>; // Simple FP
def M4UnitFCVT1 : ProcResource<1>; // FP conversion
def M4UnitFDIV1 : ProcResource<2>; // FP division (serialized)
def M4UnitFSQR1 : ProcResource<2>; // FP square root (serialized)
def M4UnitFST1 : ProcResource<1>; // FP store
def M4UnitNALU2 : ProcResource<1>; // Simple vector
def M4UnitNMUL1 : ProcResource<1>; // Vector multiplication
def M4UnitNSHT2 : ProcResource<1>; // Vector shifting
def M4UnitNCRY1 : ProcResource<1>; // Cryptographic
}
def M4UnitALU : ProcResGroup<[M4UnitA,
M4UnitC]>;
def M4UnitL : ProcResGroup<[M4UnitL0,
M4UnitL1]>;
def M4UnitS : ProcResGroup<[M4UnitS0,
M4UnitS1]>;
def M4UnitFMAC : ProcResGroup<[M4UnitFMAC0,
M4UnitFMAC1,
M4UnitFMAC2]>;
def M4UnitFMACH : ProcResGroup<[M4UnitFMAC0,
M4UnitFMAC1]>;
def M4UnitFADD : ProcResGroup<[M4UnitFADD0,
M4UnitFADD1,
M4UnitFADD2]>;
def M4UnitFADDH : ProcResGroup<[M4UnitFADD0,
M4UnitFADD1]>;
def M4UnitFCVT : ProcResGroup<[M4UnitFCVT0,
M4UnitFCVT1]>;
def M4UnitFCVTH : ProcResGroup<[M4UnitFCVT0]>;
def M4UnitFDIV : ProcResGroup<[M4UnitFDIV0,
M4UnitFDIV1]>;
def M4UnitFDIVH : ProcResGroup<[M4UnitFDIV0]>;
def M4UnitFSQR : ProcResGroup<[M4UnitFSQR0,
M4UnitFSQR1]>;
def M4UnitFSQRH : ProcResGroup<[M4UnitFSQR0]>;
def M4UnitFST : ProcResGroup<[M4UnitFST0,
M4UnitFST1]>;
def M4UnitNALU : ProcResGroup<[M4UnitNALU0,
M4UnitNALU1,
M4UnitNALU2]>;
def M4UnitNALUH : ProcResGroup<[M4UnitNALU0,
M4UnitNALU1]>;
def M4UnitNMUL : ProcResGroup<[M4UnitNMUL0,
M4UnitNMUL1]>;
def M4UnitNSHT : ProcResGroup<[M4UnitNSHT0,
M4UnitNSHT1,
M4UnitNSHT2]>;
def M4UnitNSHF : ProcResGroup<[M4UnitNSHF0,
M4UnitNSHF1]>;
def M4UnitNSHFH : ProcResGroup<[M4UnitNSHF0]>;
def M4UnitNCRY : ProcResGroup<[M4UnitNCRY0,
M4UnitNCRY1]>;
//===----------------------------------------------------------------------===//
// Resources details.
def M4WriteZ0 : SchedWriteRes<[]> { let Latency = 0; }
def M4WriteZ1 : SchedWriteRes<[]> { let Latency = 1;
let NumMicroOps = 0; }
def M4WriteZ4 : SchedWriteRes<[]> { let Latency = 4;
let NumMicroOps = 0; }
def M4WriteA1 : SchedWriteRes<[M4UnitALU]> { let Latency = 1; }
def M4WriteA2 : SchedWriteRes<[M4UnitALU]> { let Latency = 2; }
def M4WriteAA : SchedWriteRes<[M4UnitALU]> { let Latency = 2;
let ResourceCycles = [2]; }
def M4WriteAB : SchedWriteRes<[M4UnitALU,
M4UnitC]> { let Latency = 2;
let NumMicroOps = 2; }
def M4WriteAC : SchedWriteRes<[M4UnitALU,
M4UnitALU,
M4UnitC]> { let Latency = 3;
let NumMicroOps = 3; }
def M4WriteAD : SchedWriteRes<[M4UnitALU,
M4UnitC]> { let Latency = 2;
let NumMicroOps = 2; }
def M4WriteAF : SchedWriteRes<[M4UnitALU]> { let Latency = 2;
let NumMicroOps = 2; }
def M4WriteAU : SchedWriteVariant<[SchedVar<IsCopyIdiomPred, [M4WriteZ0]>,
SchedVar<ExynosArithPred, [M4WriteA1]>,
SchedVar<ExynosLogicExPred, [M4WriteA1]>,
SchedVar<NoSchedPred, [M4WriteAA]>]>;
def M4WriteAV : SchedWriteVariant<[SchedVar<ExynosResetPred, [M4WriteZ0]>,
SchedVar<NoSchedPred, [M4WriteAA]>]>;
def M4WriteAX : SchedWriteVariant<[SchedVar<ExynosArithPred, [M4WriteA1]>,
SchedVar<ExynosLogicExPred, [M4WriteA1]>,
SchedVar<NoSchedPred, [M4WriteAA]>]>;
def M4WriteAY : SchedWriteVariant<[SchedVar<ExynosRotateRightImmPred, [M4WriteA1]>,
SchedVar<NoSchedPred, [M4WriteAF]>]>;
def M4WriteB1 : SchedWriteRes<[M4UnitB]> { let Latency = 1; }
def M4WriteBX : SchedWriteVariant<[SchedVar<ExynosBranchLinkLRPred, [M4WriteAC]>,
SchedVar<NoSchedPred, [M4WriteAB]>]>;
def M4WriteC1 : SchedWriteRes<[M4UnitC]> { let Latency = 1; }
def M4WriteC3 : SchedWriteRes<[M4UnitC]> { let Latency = 3; }
def M4WriteCA : SchedWriteRes<[M4UnitC]> { let Latency = 4;
let ResourceCycles = [2]; }
def M4WriteD12 : SchedWriteRes<[M4UnitD]> { let Latency = 12; }
def M4WriteD21 : SchedWriteRes<[M4UnitD]> { let Latency = 21; }
def M4WriteE2 : SchedWriteRes<[M4UnitE]> { let Latency = 2; }
def M4WriteL4 : SchedWriteRes<[M4UnitL]> { let Latency = 4; }
def M4WriteL5 : SchedWriteRes<[M4UnitL]> { let Latency = 5; }
def M4WriteLA : SchedWriteRes<[M4UnitL,
M4UnitL]> { let Latency = 5;
let NumMicroOps = 1; }
def M4WriteLB : SchedWriteRes<[M4UnitA,
M4UnitL]> { let Latency = 5;
let NumMicroOps = 2; }
def M4WriteLC : SchedWriteRes<[M4UnitA,
M4UnitL,
M4UnitL]> { let Latency = 5;
let NumMicroOps = 2; }
def M4WriteLD : SchedWriteRes<[M4UnitA,
M4UnitL]> { let Latency = 4;
let NumMicroOps = 2; }
def M4WriteLE : SchedWriteRes<[M4UnitA,
M4UnitL]> { let Latency = 6;
let NumMicroOps = 2; }
def M4WriteLH : SchedWriteRes<[]> { let Latency = 5;
let NumMicroOps = 0; }
def M4WriteLX : SchedWriteVariant<[SchedVar<ScaledIdxPred, [M4WriteL5]>,
SchedVar<NoSchedPred, [M4WriteL4]>]>;
def M4WriteS1 : SchedWriteRes<[M4UnitS]> { let Latency = 1; }
def M4WriteSA : SchedWriteRes<[M4UnitS0]> { let Latency = 3; }
def M4WriteSB : SchedWriteRes<[M4UnitA,
M4UnitS]> { let Latency = 2;
let NumMicroOps = 1; }
def M4WriteSX : SchedWriteVariant<[SchedVar<ExynosScaledIdxPred, [M4WriteSB]>,
SchedVar<NoSchedPred, [M4WriteS1]>]>;
def M4ReadAdrBase : SchedReadVariant<[SchedVar<
MCSchedPredicate<
CheckAny<
[ScaledIdxFn,
ExynosScaledIdxFn]>>, [ReadDefault]>,
SchedVar<NoSchedPred, [ReadDefault]>]>;
def M4WriteNEONA : SchedWriteRes<[M4UnitNSHF,
M4UnitFADD]> { let Latency = 3;
let NumMicroOps = 2; }
def M4WriteNEONB : SchedWriteRes<[M4UnitNALU,
M4UnitS0]> { let Latency = 5;
let NumMicroOps = 2; }
def M4WriteNEOND : SchedWriteRes<[M4UnitNSHF,
M4UnitFST]> { let Latency = 6;
let NumMicroOps = 2; }
def M4WriteNEONH : SchedWriteRes<[M4UnitNALU,
M4UnitS0]> { let Latency = 5;
let NumMicroOps = 2; }
def M4WriteNEONI : SchedWriteRes<[M4UnitNSHF,
M4UnitS0]> { let Latency = 2;
let NumMicroOps = 2; }
def M4WriteNEONJ : SchedWriteRes<[M4UnitNMSC,
M4UnitS0]> { let Latency = 4; }
def M4WriteNEONK : SchedWriteRes<[M4UnitNSHF,
M4UnitNMSC,
M4UnitS0]> { let Latency = 5;
let NumMicroOps = 2; }
def M4WriteNEONL : SchedWriteRes<[M4UnitNMUL]> { let Latency = 3; }
-def M4WriteNEONM : SchedWriteRes<[M4UnitNMUL]> { let Latency = 3; }
def M4WriteNEONN : SchedWriteRes<[M4UnitNMSC,
M4UnitNMSC]> { let Latency = 5;
let NumMicroOps = 2; }
def M4WriteNEONO : SchedWriteRes<[M4UnitNMSC,
M4UnitNMSC,
M4UnitNMSC]> { let Latency = 8;
let NumMicroOps = 3; }
def M4WriteNEONP : SchedWriteRes<[M4UnitNSHF,
M4UnitNMSC]> { let Latency = 4;
let NumMicroOps = 2; }
def M4WriteNEONQ : SchedWriteRes<[M4UnitNMSC,
M4UnitC]> { let Latency = 3;
let NumMicroOps = 1; }
def M4WriteNEONR : SchedWriteRes<[M4UnitFCVT0,
M4UnitS0]> { let Latency = 4;
let NumMicroOps = 1; }
def M4WriteNEONV : SchedWriteRes<[M4UnitFDIV,
M4UnitFDIV]> { let Latency = 7;
let ResourceCycles = [6, 6]; }
def M4WriteNEONVH : SchedWriteRes<[M4UnitFDIVH,
M4UnitFDIVH]> { let Latency = 7;
let ResourceCycles = [6, 6]; }
def M4WriteNEONW : SchedWriteRes<[M4UnitFDIV,
M4UnitFDIV]> { let Latency = 12;
let ResourceCycles = [9, 9]; }
def M4WriteNEONX : SchedWriteRes<[M4UnitFSQR,
M4UnitFSQR]> { let Latency = 8;
let ResourceCycles = [7, 7]; }
def M4WriteNEONXH : SchedWriteRes<[M4UnitFSQRH,
M4UnitFSQRH]> { let Latency = 7;
let ResourceCycles = [6, 6]; }
def M4WriteNEONY : SchedWriteRes<[M4UnitFSQR,
M4UnitFSQR]> { let Latency = 12;
let ResourceCycles = [9, 9]; }
def M4WriteNEONZ : SchedWriteVariant<[SchedVar<ExynosQFormPred, [M4WriteNEONO]>,
SchedVar<NoSchedPred, [M4WriteNEONN]>]>;
def M4WriteFADD2 : SchedWriteRes<[M4UnitFADD]> { let Latency = 2; }
def M4WriteFADD2H : SchedWriteRes<[M4UnitFADDH]> { let Latency = 2; }
def M4WriteFCVT2 : SchedWriteRes<[M4UnitFCVT]> { let Latency = 2; }
def M4WriteFCVT2A : SchedWriteRes<[M4UnitFCVT0]> { let Latency = 2; }
def M4WriteFCVT2H : SchedWriteRes<[M4UnitFCVTH]> { let Latency = 2; }
def M4WriteFCVT3 : SchedWriteRes<[M4UnitFCVT]> { let Latency = 3; }
def M4WriteFCVT3A : SchedWriteRes<[M4UnitFCVT0]> { let Latency = 3; }
def M4WriteFCVT3H : SchedWriteRes<[M4UnitFCVTH]> { let Latency = 3; }
def M4WriteFCVT4 : SchedWriteRes<[M4UnitFCVT]> { let Latency = 4; }
def M4WriteFCVT4A : SchedWriteRes<[M4UnitFCVT0]> { let Latency = 4; }
def M4WriteFCVT6A : SchedWriteRes<[M4UnitFCVT0]> { let Latency = 6; }
def M4WriteFDIV7 : SchedWriteRes<[M4UnitFDIV]> { let Latency = 7;
let ResourceCycles = [6]; }
def M4WriteFDIV7H : SchedWriteRes<[M4UnitFDIVH]> { let Latency = 7;
let ResourceCycles = [6]; }
def M4WriteFDIV12 : SchedWriteRes<[M4UnitFDIV]> { let Latency = 12;
let ResourceCycles = [9]; }
def M4WriteFMAC2H : SchedWriteRes<[M4UnitFMACH]> { let Latency = 2; }
def M4WriteFMAC3H : SchedWriteRes<[M4UnitFMACH]> { let Latency = 3; }
def M4WriteFMAC3 : SchedWriteRes<[M4UnitFMAC]> { let Latency = 3; }
def M4WriteFMAC4 : SchedWriteRes<[M4UnitFMAC]> { let Latency = 4; }
def M4WriteFMAC4H : SchedWriteRes<[M4UnitFMACH]> { let Latency = 4; }
def M4WriteFMAC5 : SchedWriteRes<[M4UnitFMAC]> { let Latency = 5; }
def M4WriteFSQR7H : SchedWriteRes<[M4UnitFSQRH]> { let Latency = 7;
let ResourceCycles = [6]; }
def M4WriteFSQR8 : SchedWriteRes<[M4UnitFSQR]> { let Latency = 8;
let ResourceCycles = [7]; }
def M4WriteFSQR12 : SchedWriteRes<[M4UnitFSQR]> { let Latency = 12;
let ResourceCycles = [9]; }
def M4WriteNALU1 : SchedWriteRes<[M4UnitNALU]> { let Latency = 1; }
def M4WriteNALU1H : SchedWriteRes<[M4UnitNALUH]> { let Latency = 1; }
def M4WriteNCRY1 : SchedWriteRes<[M4UnitNCRY]> { let Latency = 1; }
def M4WriteNCRY1A : SchedWriteRes<[M4UnitNCRY0]> { let Latency = 1; }
def M4WriteNCRY3A : SchedWriteRes<[M4UnitNCRY0]> { let Latency = 3; }
def M4WriteNCRY5A : SchedWriteRes<[M4UnitNCRY]> { let Latency = 5; }
def M4WriteNHAD1 : SchedWriteRes<[M4UnitNHAD]> { let Latency = 1; }
def M4WriteNHAD3 : SchedWriteRes<[M4UnitNHAD]> { let Latency = 3; }
def M4WriteNMSC1 : SchedWriteRes<[M4UnitNMSC]> { let Latency = 1; }
def M4WriteNMSC2 : SchedWriteRes<[M4UnitNMSC]> { let Latency = 2; }
def M4WriteNMSC3 : SchedWriteRes<[M4UnitNMSC]> { let Latency = 3; }
def M4WriteNMUL3 : SchedWriteRes<[M4UnitNMUL]> { let Latency = 3; }
def M4WriteNSHF1 : SchedWriteRes<[M4UnitNSHF]> { let Latency = 1; }
def M4WriteNSHF1H : SchedWriteRes<[M4UnitNSHFH]> { let Latency = 1; }
def M4WriteNSHF3 : SchedWriteRes<[M4UnitNSHF]> { let Latency = 3; }
def M4WriteNSHFA : SchedWriteRes<[M4UnitNSHF]> { let Latency = 1;
let ResourceCycles = [2]; }
def M4WriteNSHFB : SchedWriteRes<[M4UnitNSHF]> { let Latency = 2;
let NumMicroOps = 2;
let ResourceCycles = [2]; }
def M4WriteNSHFC : SchedWriteRes<[M4UnitNSHF]> { let Latency = 3;
let NumMicroOps = 3;
let ResourceCycles = [4]; }
def M4WriteNSHFD : SchedWriteRes<[M4UnitNSHF]> { let Latency = 4;
let NumMicroOps = 4;
let ResourceCycles = [4]; }
def M4WriteNSHT1 : SchedWriteRes<[M4UnitNSHT]> { let Latency = 1; }
def M4WriteNSHT2 : SchedWriteRes<[M4UnitNSHT]> { let Latency = 2; }
def M4WriteNSHT3 : SchedWriteRes<[M4UnitNSHT]> { let Latency = 3; }
def M4WriteNSHT4A : SchedWriteRes<[M4UnitNSHT1]> { let Latency = 4; }
def M4WriteVLDA : SchedWriteRes<[M4UnitL,
M4UnitL]> { let Latency = 5;
let NumMicroOps = 2; }
def M4WriteVLDB : SchedWriteRes<[M4UnitL,
M4UnitL,
M4UnitL]> { let Latency = 6;
let NumMicroOps = 3; }
def M4WriteVLDC : SchedWriteRes<[M4UnitL,
M4UnitL,
M4UnitL,
M4UnitL]> { let Latency = 6;
let NumMicroOps = 4; }
def M4WriteVLDD : SchedWriteRes<[M4UnitL,
M4UnitNSHF]> { let Latency = 6;
let NumMicroOps = 2;
let ResourceCycles = [2, 1]; }
def M4WriteVLDF : SchedWriteRes<[M4UnitL,
M4UnitL]> { let Latency = 10;
let NumMicroOps = 2;
let ResourceCycles = [3, 3]; }
def M4WriteVLDG : SchedWriteRes<[M4UnitL,
M4UnitNSHF,
M4UnitNSHF]> { let Latency = 6;
let NumMicroOps = 3;
let ResourceCycles = [2, 1, 1]; }
def M4WriteVLDI : SchedWriteRes<[M4UnitL,
M4UnitL,
M4UnitL]> { let Latency = 12;
let NumMicroOps = 3;
let ResourceCycles = [3, 3, 3]; }
def M4WriteVLDJ : SchedWriteRes<[M4UnitL,
M4UnitNSHF,
M4UnitNSHF,
M4UnitNSHF]> { let Latency = 7;
let NumMicroOps = 4;
let ResourceCycles = [3, 1, 1, 1]; }
def M4WriteVLDK : SchedWriteRes<[M4UnitL,
M4UnitNSHF,
M4UnitNSHF,
M4UnitNSHF,
M4UnitNSHF]> { let Latency = 7;
let NumMicroOps = 5;
let ResourceCycles = [3, 1, 1, 1, 1]; }
def M4WriteVLDL : SchedWriteRes<[M4UnitL,
M4UnitNSHF,
M4UnitNSHF,
M4UnitL,
M4UnitNSHF]> { let Latency = 7;
let NumMicroOps = 5;
let ResourceCycles = [3, 1, 1, 6, 1]; }
def M4WriteVLDM : SchedWriteRes<[M4UnitL,
M4UnitNSHF,
M4UnitNSHF,
M4UnitL,
M4UnitNSHF,
M4UnitNSHF]> { let Latency = 7;
let NumMicroOps = 6;
let ResourceCycles = [3, 1, 1, 3, 1, 1]; }
def M4WriteVLDN : SchedWriteRes<[M4UnitL,
M4UnitL,
M4UnitL,
M4UnitL]> { let Latency = 14;
let NumMicroOps = 4;
let ResourceCycles = [3, 3, 3, 3]; }
def M4WriteVST1 : SchedWriteRes<[M4UnitS,
M4UnitFST]> { let Latency = 1;
let NumMicroOps = 1; }
def M4WriteVSTA : WriteSequence<[WriteVST], 2>;
def M4WriteVSTB : WriteSequence<[WriteVST], 3>;
def M4WriteVSTC : WriteSequence<[WriteVST], 4>;
def M4WriteVSTD : SchedWriteRes<[M4UnitS,
M4UnitFST]> { let Latency = 2; }
def M4WriteVSTE : SchedWriteRes<[M4UnitS,
M4UnitFST,
M4UnitS,
M4UnitFST]> { let Latency = 2;
let NumMicroOps = 2; }
def M4WriteVSTF : SchedWriteRes<[M4UnitNSHF,
M4UnitS,
M4UnitFST,
M4UnitS,
M4UnitFST]> { let Latency = 4;
let NumMicroOps = 4;
let ResourceCycles = [1, 2, 1, 2, 1]; }
def M4WriteVSTG : SchedWriteRes<[M4UnitNSHF,
M4UnitNSHF,
M4UnitNSHF,
M4UnitS,
M4UnitFST,
M4UnitS,
M4UnitFST,
M4UnitS,
M4UnitFST]> { let Latency = 5;
let NumMicroOps = 6;
let ResourceCycles = [1, 1, 1, 2, 1, 2, 1, 2, 1]; }
def M4WriteVSTI : SchedWriteRes<[M4UnitNSHF,
M4UnitNSHF,
M4UnitNSHF,
M4UnitNSHF,
M4UnitS,
M4UnitFST,
M4UnitS,
M4UnitFST,
M4UnitS,
M4UnitFST,
M4UnitS,
M4UnitFST]> { let Latency = 8;
let NumMicroOps = 5;
let ResourceCycles = [1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1]; }
def M4WriteVSTJ : SchedWriteRes<[M4UnitA,
M4UnitS,
M4UnitFST]> { let Latency = 1;
let NumMicroOps = 2; }
def M4WriteVSTK : SchedWriteRes<[M4UnitA,
M4UnitS,
M4UnitFST]> { let Latency = 3;
let NumMicroOps = 2; }
def M4WriteVSTL : SchedWriteRes<[M4UnitNSHF,
M4UnitNSHF,
M4UnitS,
M4UnitFST,
M4UnitS,
M4UnitFST]> { let Latency = 4;
let NumMicroOps = 4;
let ResourceCycles = [1, 1, 2, 1, 2, 1]; }
// Special cases.
def M4WriteCOPY : SchedWriteVariant<[SchedVar<ExynosFPPred, [M4WriteNALU1]>,
SchedVar<NoSchedPred, [M4WriteZ0]>]>;
def M4WriteMOVI : SchedWriteVariant<[SchedVar<IsZeroFPIdiomPred, [M4WriteZ0]>,
SchedVar<NoSchedPred, [M4WriteNALU1]>]>;
-def M4WriteMULL : SchedWriteVariant<[SchedVar<ExynosLongVectorUpperPred, [M4WriteNEONM]>,
- SchedVar<NoSchedPred, [M4WriteNMUL3]>]>;
// Fast forwarding.
def M4ReadAESM1 : SchedReadAdvance<+1, [M4WriteNCRY1]>;
def M4ReadFMACM1 : SchedReadAdvance<+1, [M4WriteFMAC4,
M4WriteFMAC4H,
M4WriteFMAC5]>;
def M4ReadNMULM1 : SchedReadAdvance<+1, [M4WriteNMUL3]>;
-def M4ReadMULLP2 : SchedReadAdvance<-2, [M4WriteNEONM]>;
+def M4ReadNMULP2 : SchedReadAdvance<-2, [M4WriteNMUL3]>;
+
//===----------------------------------------------------------------------===//
// Coarse scheduling model.
// Branch instructions.
def : SchedAlias<WriteBr, M4WriteZ0>;
def : SchedAlias<WriteBrReg, M4WriteC1>;
// Arithmetic and logical integer instructions.
def : SchedAlias<WriteI, M4WriteA1>;
def : SchedAlias<WriteIEReg, M4WriteAA>; // FIXME: M4WriteAX crashes TableGen.
def : SchedAlias<WriteISReg, M4WriteAA>; // FIXME: M4WriteAX crashes TableGen.
def : SchedAlias<WriteIS, M4WriteA1>;
// Move instructions.
def : SchedAlias<WriteImm, M4WriteA1>;
// Divide and multiply instructions.
def : SchedAlias<WriteID32, M4WriteD12>;
def : SchedAlias<WriteID64, M4WriteD21>;
def : SchedAlias<WriteIM32, M4WriteC3>;
def : SchedAlias<WriteIM64, M4WriteCA>;
// Miscellaneous instructions.
def : SchedAlias<WriteExtr, M4WriteAY>;
// Addressing modes.
def : SchedAlias<WriteAdr, M4WriteZ1>;
def : SchedAlias<ReadAdrBase, M4ReadAdrBase>;
// Load instructions.
def : SchedAlias<WriteLD, M4WriteL4>;
def : SchedAlias<WriteLDHi, M4WriteZ4>;
def : SchedAlias<WriteLDIdx, M4WriteLX>;
// Store instructions.
def : SchedAlias<WriteST, M4WriteS1>;
def : SchedAlias<WriteSTP, M4WriteS1>;
def : SchedAlias<WriteSTX, M4WriteS1>;
def : SchedAlias<WriteSTIdx, M4WriteSX>;
// FP data instructions.
def : SchedAlias<WriteF, M4WriteFADD2>;
def : SchedAlias<WriteFCmp, M4WriteNMSC2>;
def : SchedAlias<WriteFDiv, M4WriteFDIV12>;
def : SchedAlias<WriteFMul, M4WriteFMAC3>;
// FP miscellaneous instructions.
def : SchedAlias<WriteFCvt, M4WriteFCVT2>;
def : SchedAlias<WriteFImm, M4WriteNALU1>;
def : SchedAlias<WriteFCopy, M4WriteCOPY>;
// FP load instructions.
def : SchedAlias<WriteVLD, M4WriteL5>;
// FP store instructions.
def : SchedAlias<WriteVST, M4WriteVST1>;
// ASIMD FP instructions.
def : SchedAlias<WriteV, M4WriteNALU1>;
// Other miscellaneous instructions.
def : WriteRes<WriteAtomic, []> { let Unsupported = 1; }
def : WriteRes<WriteBarrier, []> { let Latency = 1; }
def : WriteRes<WriteHint, []> { let Latency = 1; }
def : WriteRes<WriteSys, []> { let Latency = 1; }
//===----------------------------------------------------------------------===//
// Generic fast forwarding.
// TODO: Add FP register forwarding rules.
def : ReadAdvance<ReadI, 0>;
def : ReadAdvance<ReadISReg, 0>;
def : ReadAdvance<ReadIEReg, 0>;
def : ReadAdvance<ReadIM, 0>;
// TODO: The forwarding for 32 bits actually saves 2 cycles.
def : ReadAdvance<ReadIMA, 3, [WriteIM32, WriteIM64]>;
def : ReadAdvance<ReadID, 0>;
def : ReadAdvance<ReadExtrHi, 0>;
def : ReadAdvance<ReadAdrBase, 0>;
def : ReadAdvance<ReadVLD, 0>;
//===----------------------------------------------------------------------===//
// Finer scheduling model.
// Branch instructions
def : InstRW<[M4WriteB1], (instrs Bcc)>;
def : InstRW<[M4WriteAF], (instrs BL)>;
def : InstRW<[M4WriteBX], (instrs BLR)>;
def : InstRW<[M4WriteC1], (instregex "^CBN?Z[WX]")>;
def : InstRW<[M4WriteAD], (instregex "^TBN?Z[WX]")>;
// Arithmetic and logical integer instructions.
def : InstRW<[M4WriteAX], (instregex "^(ADD|AND|BIC|EON|EOR|ORN|SUB)[WX]rs$")>;
def : InstRW<[M4WriteAU], (instrs ORRWrs, ORRXrs)>;
def : InstRW<[M4WriteAX], (instregex "^(ADD|AND|BIC|SUB)S[WX]rs$")>;
def : InstRW<[M4WriteAX], (instregex "^(ADD|SUB)S?[WX]rx(64)?$")>;
def : InstRW<[M4WriteAV], (instrs ADDWri, ADDXri, ORRWri, ORRXri)>;
// Move instructions.
def : InstRW<[M4WriteCOPY], (instrs COPY)>;
def : InstRW<[M4WriteZ0], (instrs ADR, ADRP)>;
def : InstRW<[M4WriteZ0], (instregex "^MOV[NZ][WX]i")>;
// Divide and multiply instructions.
// Miscellaneous instructions.
// Load instructions.
def : InstRW<[M4WriteLD,
WriteLDHi,
WriteAdr], (instregex "^LDP(SW|W|X)(post|pre)")>;
def : InstRW<[M4WriteL5,
ReadAdrBase], (instregex "^LDR(BB|SBW|SBX|HH|SHW|SHX|SW|W|X)roW")>;
def : InstRW<[WriteLDIdx,
ReadAdrBase], (instregex "^LDR(BB|SBW|SBX|HH|SHW|SHX|SW|W|X)roX")>;
def : InstRW<[M4WriteL5,
ReadAdrBase], (instrs PRFMroW)>;
def : InstRW<[WriteLDIdx,
ReadAdrBase], (instrs PRFMroX)>;
// Store instructions.
def : InstRW<[M4WriteSB,
ReadAdrBase], (instregex "^STR(BB|HH|W|X)roW")>;
def : InstRW<[WriteST,
ReadAdrBase], (instregex "^STR(BB|HH|W|X)roX")>;
// FP data instructions.
def : InstRW<[M4WriteNSHF1H], (instrs FABSHr)>;
def : InstRW<[M4WriteNSHF1], (instregex "^FABS[SD]r")>;
def : InstRW<[M4WriteFADD2H], (instregex "^F(ADD|SUB)Hrr")>;
def : InstRW<[M4WriteFADD2], (instregex "^F(ADD|SUB)[SD]rr")>;
def : InstRW<[M4WriteFADD2H], (instregex "^FADDPv.i16")>;
def : InstRW<[M4WriteFADD2], (instregex "^FADDPv.i(32|64)")>;
def : InstRW<[M4WriteNEONQ], (instregex "^FCCMPE?[HSD]rr")>;
def : InstRW<[M4WriteNMSC2], (instregex "^FCMPE?[HSD]r[ir]")>;
def : InstRW<[M4WriteNMSC1], (instregex "^F(AC|CM)(EQ|GE|GT|LE|LT)(16|32|64|v1)")>;
def : InstRW<[M4WriteFDIV7H], (instrs FDIVHrr)>;
def : InstRW<[M4WriteFDIV7], (instrs FDIVSrr)>;
def : InstRW<[M4WriteFDIV12], (instrs FDIVDrr)>;
def : InstRW<[M4WriteNMSC1], (instregex "^F(MAX|MIN)(NM)?[HSD]rr")>;
def : InstRW<[M4WriteFMAC3H], (instregex "^FN?MULHrr")>;
def : InstRW<[M4WriteFMAC3], (instregex "^FN?MUL[SD]rr")>;
def : InstRW<[M4WriteFMAC3H], (instrs FMULX16)>;
def : InstRW<[M4WriteFMAC3], (instregex "^FMULX(32|64)")>;
def : InstRW<[M4WriteFMAC4H,
M4ReadFMACM1], (instregex "^FN?M(ADD|SUB)Hrrr")>;
def : InstRW<[M4WriteFMAC4,
M4ReadFMACM1], (instregex "^FN?M(ADD|SUB)[SD]rrr")>;
def : InstRW<[M4WriteNALU1H], (instrs FNEGHr)>;
def : InstRW<[M4WriteNALU1], (instregex "^FNEG[SD]r")>;
def : InstRW<[M4WriteFCVT3A], (instregex "^FRINT.+r")>;
def : InstRW<[M4WriteNEONH], (instregex "^FCSEL[HSD]rrr")>;
def : InstRW<[M4WriteFSQR7H], (instrs FSQRTHr)>;
def : InstRW<[M4WriteFSQR8], (instrs FSQRTSr)>;
def : InstRW<[M4WriteFSQR12], (instrs FSQRTDr)>;
// FP miscellaneous instructions.
def : InstRW<[M4WriteFCVT2H], (instregex "^FCVTH[SD]r")>;
def : InstRW<[M4WriteFCVT2H], (instregex "^FCVT[SD]Hr")>;
def : InstRW<[M4WriteFCVT2], (instregex "^FCVT[SD][SD]r")>;
def : InstRW<[M4WriteFCVT6A], (instregex "^[SU]CVTF[SU][XW][HSD]ri")>;
def : InstRW<[M4WriteNEONR], (instregex "^FCVT[AMNPZ][SU][SU][XW][HSD]r")>;
def : InstRW<[M4WriteNALU1], (instregex "^FMOV[HSD][ir]")>;
def : InstRW<[M4WriteSA], (instregex "^FMOV[WX][HSD]r")>;
def : InstRW<[M4WriteNEONJ], (instregex "^FMOV[HSD][WX]r")>;
def : InstRW<[M4WriteNEONI], (instregex "^FMOVXDHighr")>;
def : InstRW<[M4WriteNEONK], (instregex "^FMOVDXHighr")>;
def : InstRW<[M4WriteFCVT3H], (instregex "^F(RECP|RSQRT)Ev1f16")>;
def : InstRW<[M4WriteFCVT3], (instregex "^F(RECP|RSQRT)Ev1i(32|64)")>;
def : InstRW<[M4WriteNMSC1], (instregex "^FRECPXv1")>;
-def : InstRW<[M4WriteFMAC4H,
- M4ReadFMACM1], (instregex "^F(RECP|RSQRT)S16")>;
-def : InstRW<[M4WriteFMAC4,
- M4ReadFMACM1], (instregex "^F(RECP|RSQRT)S(32|64)")>;
+def : InstRW<[M4WriteFMAC4H], (instregex "^F(RECP|RSQRT)S16")>;
+def : InstRW<[M4WriteFMAC4], (instregex "^F(RECP|RSQRT)S(32|64)")>;
// FP load instructions.
def : InstRW<[WriteVLD], (instregex "^LDR[SDQ]l")>;
def : InstRW<[WriteVLD], (instregex "^LDUR[BHSDQ]i")>;
def : InstRW<[WriteVLD,
WriteAdr], (instregex "^LDR[BHSDQ](post|pre)")>;
def : InstRW<[WriteVLD], (instregex "^LDR[BHSDQ]ui")>;
def : InstRW<[M4WriteLE,
ReadAdrBase], (instregex "^LDR[BHSDQ]roW")>;
def : InstRW<[WriteVLD,
ReadAdrBase], (instregex "^LDR[BHSD]roX")>;
def : InstRW<[M4WriteLE,
ReadAdrBase], (instrs LDRQroX)>;
def : InstRW<[WriteVLD,
M4WriteLH], (instregex "^LDN?P[SD]i")>;
def : InstRW<[M4WriteLA,
M4WriteLH], (instregex "^LDN?PQi")>;
def : InstRW<[M4WriteL5,
M4WriteLH,
WriteAdr], (instregex "^LDP[SD]post")>;
def : InstRW<[M4WriteLB,
M4WriteLH,
WriteAdr], (instrs LDPQpost)>;
def : InstRW<[M4WriteLB,
M4WriteLH,
WriteAdr], (instregex "^LDP[SD]pre")>;
def : InstRW<[M4WriteLC,
M4WriteLH,
WriteAdr], (instrs LDPQpre)>;
// FP store instructions.
def : InstRW<[WriteVST], (instregex "^STUR[BHSDQ]i")>;
def : InstRW<[WriteVST,
WriteAdr], (instregex "^STR[BHSDQ](post|pre)")>;
def : InstRW<[WriteVST], (instregex "^STR[BHSDQ]ui")>;
def : InstRW<[M4WriteVSTJ,
ReadAdrBase], (instregex "^STR[BHSD]roW")>;
def : InstRW<[M4WriteVSTK,
ReadAdrBase], (instrs STRQroW)>;
def : InstRW<[WriteVST,
ReadAdrBase], (instregex "^STR[BHSD]roX")>;
def : InstRW<[M4WriteVSTK,
ReadAdrBase], (instrs STRQroX)>;
def : InstRW<[WriteVST], (instregex "^STN?P[SD]i")>;
def : InstRW<[M4WriteVSTA], (instregex "^STN?PQi")>;
def : InstRW<[WriteVST,
WriteAdr], (instregex "^STP[SD](post|pre)")>;
def : InstRW<[M4WriteVSTJ,
WriteAdr], (instregex "^STPQ(post|pre)")>;
// ASIMD instructions.
def : InstRW<[M4WriteNHAD1], (instregex "^[SU]ABDL?v")>;
def : InstRW<[M4WriteNHAD3], (instregex "^[SU]ABAL?v")>;
def : InstRW<[M4WriteNMSC1], (instregex "^ABSv")>;
def : InstRW<[M4WriteNALU1], (instregex "^(ADD|NEG|SUB)v")>;
def : InstRW<[M4WriteNHAD3], (instregex "^[SU]?ADDL?Pv")>;
def : InstRW<[M4WriteNHAD3], (instregex "^[SU]H(ADD|SUB)v")>;
def : InstRW<[M4WriteNHAD3], (instregex "^[SU](ADD|SUB)[LW]v")>;
def : InstRW<[M4WriteNHAD3], (instregex "^R?(ADD|SUB)HN2?v")>;
def : InstRW<[M4WriteNHAD3], (instregex "^[SU]Q(ADD|SUB)v")>;
def : InstRW<[M4WriteNHAD3], (instregex "^(SU|US)QADDv")>;
def : InstRW<[M4WriteNHAD3], (instregex "^[SU]RHADDv")>;
def : InstRW<[M4WriteNMSC1], (instregex "^SQ(ABS|NEG)v")>;
def : InstRW<[M4WriteNHAD3], (instregex "^[SU]?ADDL?Vv")>;
def : InstRW<[M4WriteNMSC1], (instregex "^CM(EQ|GE|GT|HI|HS|LE|LT)v")>;
def : InstRW<[M4WriteNALU1], (instregex "^CMTSTv")>;
def : InstRW<[M4WriteNALU1], (instregex "^(AND|BIC|EOR|NOT|ORN|ORR)v")>;
def : InstRW<[M4WriteNMSC1], (instregex "^[SU](MIN|MAX)v")>;
def : InstRW<[M4WriteNMSC2], (instregex "^[SU](MIN|MAX)Pv")>;
def : InstRW<[M4WriteNHAD3], (instregex "^[SU](MIN|MAX)Vv")>;
-def : InstRW<[M4WriteNMUL3], (instregex "^(SQR?D)?MULH?v")>;
def : InstRW<[M4WriteNMUL3,
M4ReadNMULM1], (instregex "^ML[AS]v")>;
-def : InstRW<[M4WriteNMUL3], (instregex "^SQRDML[AS]H")>;
-def : InstRW<[M4WriteMULL,
- M4ReadMULLP2], (instregex "^(S|U|SQD)ML[AS]Lv")>;
-def : InstRW<[M4WriteMULL,
- M4ReadMULLP2], (instregex "^(S|U|SQD)MULLv")>;
+def : InstRW<[M4WriteNMUL3,
+ M4ReadNMULM1], (instregex "^(SQR?D)?MULH?v")>;
+def : InstRW<[M4WriteNMUL3,
+ M4ReadNMULM1], (instregex "^SQRDML[AS]H")>;
+def : InstRW<[M4WriteNMUL3,
+ M4ReadNMULM1], (instregex "^(S|U|SQD)ML[AS]L(v1(i32|i64)|v2i32|v4i16|v8i8)")>;
+def : InstRW<[M4WriteNMUL3,
+ M4ReadNMULP2], (instregex "^(S|U|SQD)ML[AS]L(v4i32|v8i16|v16i8)")>;
+def : InstRW<[M4WriteNMUL3,
+ M4ReadNMULM1], (instregex "^(S|U|SQD)MULL(v1(i32|i64)|v2i32|v4i16|v8i8)")>;
+def : InstRW<[M4WriteNMUL3,
+ M4ReadNMULP2], (instregex "^(S|U|SQD)MULL(v4i32|v8i16|v16i8)")>;
def : InstRW<[M4WriteNMUL3], (instregex "^[SU]DOT(lane)?v")>;
def : InstRW<[M4WriteNHAD3], (instregex "^[SU]ADALPv")>;
def : InstRW<[M4WriteNSHT4A], (instregex "^[SU]R?SRA[dv]")>;
def : InstRW<[M4WriteNSHT1], (instregex "^SHL[dv]")>;
def : InstRW<[M4WriteNSHT1], (instregex "^S[LR]I[dv]")>;
def : InstRW<[M4WriteNSHT1], (instregex "^[SU]SH[LR][dv]")>;
def : InstRW<[M4WriteNSHT2], (instregex "^[SU]?SHLLv")>;
def : InstRW<[M4WriteNSHT4A], (instregex "^[SU]?Q?R?SHRU?N[bhsv]")>;
def : InstRW<[M4WriteNSHT4A], (instregex "^[SU]RSH[LR][dv]")>;
def : InstRW<[M4WriteNSHT4A], (instregex "^[SU]QR?SHLU?[bhsdv]")>;
// ASIMD FP instructions.
def : InstRW<[M4WriteNSHF1H], (instregex "^FABSv.f16")>;
def : InstRW<[M4WriteNSHF1], (instregex "^FABSv.f(32|64)")>;
def : InstRW<[M4WriteFADD2H], (instregex "^F(ABD|ADD|SUB)v.f16")>;
def : InstRW<[M4WriteFADD2], (instregex "^F(ABD|ADD|SUB)v.f(32|64)")>;
def : InstRW<[M4WriteFADD2H], (instregex "^FADDPv.f16")>;
def : InstRW<[M4WriteFADD2], (instregex "^FADDPv.f(32|64)")>;
def : InstRW<[M4WriteNMSC1], (instregex "^F(AC|CM)(EQ|GE|GT|LE|LT)v[^1]")>;
def : InstRW<[M4WriteFCVT2], (instregex "^FCVT(L|N|XN)v")>;
def : InstRW<[M4WriteFCVT2A], (instregex "^FCVT[AMNPZ][SU]v")>;
def : InstRW<[M4WriteFCVT2H], (instregex "^[SU]CVTFv.[fi]16")>;
def : InstRW<[M4WriteFCVT2], (instregex "^[SU]CVTFv.[fi](32|64)")>;
def : InstRW<[M4WriteFDIV7H], (instrs FDIVv4f16)>;
def : InstRW<[M4WriteNEONVH], (instrs FDIVv8f16)>;
def : InstRW<[M4WriteFDIV7], (instrs FDIVv2f32)>;
def : InstRW<[M4WriteNEONV], (instrs FDIVv4f32)>;
def : InstRW<[M4WriteNEONW], (instrs FDIVv2f64)>;
def : InstRW<[M4WriteNMSC1], (instregex "^F(MAX|MIN)(NM)?v")>;
def : InstRW<[M4WriteNMSC2], (instregex "^F(MAX|MIN)(NM)?Pv")>;
def : InstRW<[M4WriteNEONZ], (instregex "^F(MAX|MIN)(NM)?Vv")>;
def : InstRW<[M4WriteFMAC2H], (instregex "^FMULX?v.[fi]16")>;
def : InstRW<[M4WriteFMAC3], (instregex "^FMULX?v.[fi](32|64)")>;
def : InstRW<[M4WriteFMAC4H,
M4ReadFMACM1], (instregex "^FML[AS]v.[fi]16")>;
def : InstRW<[M4WriteFMAC4,
M4ReadFMACM1], (instregex "^FML[AS]v.[fi](32|64)")>;
def : InstRW<[M4WriteNALU1H], (instregex "^FNEGv.f16")>;
def : InstRW<[M4WriteNALU1], (instregex "^FNEGv.f(32|64)")>;
def : InstRW<[M4WriteFCVT3A], (instregex "^FRINT[AIMNPXZ]v")>;
def : InstRW<[M4WriteFSQR7H], (instrs FSQRTv4f16)>;
def : InstRW<[M4WriteNEONXH], (instrs FSQRTv8f16)>;
def : InstRW<[M4WriteFSQR8], (instrs FSQRTv2f32)>;
def : InstRW<[M4WriteNEONX], (instrs FSQRTv4f32)>;
def : InstRW<[M4WriteNEONY], (instrs FSQRTv2f64)>;
// ASIMD miscellaneous instructions.
def : InstRW<[M4WriteNALU1], (instregex "^RBITv")>;
def : InstRW<[M4WriteNALU1], (instregex "^(BIF|BIT|BSL)v")>;
def : InstRW<[M4WriteNALU1], (instregex "^CL[STZ]v")>;
def : InstRW<[M4WriteNEONB], (instregex "^DUPv.+gpr")>;
def : InstRW<[M4WriteNSHF1], (instregex "^CPY")>;
def : InstRW<[M4WriteNSHF1], (instregex "^DUPv.+lane")>;
def : InstRW<[M4WriteNSHF1], (instregex "^EXTv")>;
def : InstRW<[M4WriteNSHT4A], (instregex "^XTNv")>;
def : InstRW<[M4WriteNSHT4A], (instregex "^[SU]?QXTU?Nv")>;
def : InstRW<[M4WriteNEONB], (instregex "^INSv.+gpr")>;
def : InstRW<[M4WriteNSHF1], (instregex "^INSv.+lane")>;
def : InstRW<[M4WriteMOVI], (instregex "^(MOV|MVN)I")>;
def : InstRW<[M4WriteNALU1H], (instregex "^FMOVv.f16")>;
def : InstRW<[M4WriteNALU1], (instregex "^FMOVv.f(32|64)")>;
def : InstRW<[M4WriteFCVT3H], (instregex "^F(RECP|RSQRT)Ev[248]f16")>;
def : InstRW<[M4WriteFCVT3], (instregex "^F(RECP|RSQRT)Ev[248]f(32|64)")>;
def : InstRW<[M4WriteFCVT3], (instregex "^U(RECP|RSQRT)Ev[24]i32")>;
-def : InstRW<[M4WriteFMAC4H,
- M4ReadFMACM1], (instregex "^F(RECP|RSQRT)Sv.f16")>;
-def : InstRW<[M4WriteFMAC4,
- M4ReadFMACM1], (instregex "^F(RECP|RSQRT)Sv.f(32|64)")>;
+def : InstRW<[M4WriteFMAC4H], (instregex "^F(RECP|RSQRT)Sv.f16")>;
+def : InstRW<[M4WriteFMAC4], (instregex "^F(RECP|RSQRT)Sv.f(32|64)")>;
def : InstRW<[M4WriteNSHF1], (instregex "^REV(16|32|64)v")>;
def : InstRW<[M4WriteNSHFA], (instregex "^TB[LX]v(8|16)i8One")>;
def : InstRW<[M4WriteNSHFB], (instregex "^TB[LX]v(8|16)i8Two")>;
def : InstRW<[M4WriteNSHFC], (instregex "^TB[LX]v(8|16)i8Three")>;
def : InstRW<[M4WriteNSHFD], (instregex "^TB[LX]v(8|16)i8Four")>;
def : InstRW<[M4WriteNEONP], (instregex "^[SU]MOVv")>;
def : InstRW<[M4WriteNSHF1], (instregex "^(TRN|UZP|ZIP)[12]v")>;
// ASIMD load instructions.
def : InstRW<[WriteVLD], (instregex "LD1Onev(8b|4h|2s|1d)$")>;
def : InstRW<[WriteVLD,
M4WriteA1], (instregex "LD1Onev(8b|4h|2s|1d)_POST$")>;
def : InstRW<[WriteVLD], (instregex "LD1Onev(16b|8h|4s|2d)$")>;
def : InstRW<[WriteVLD,
M4WriteA1], (instregex "LD1Onev(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVLDA], (instregex "LD1Twov(8b|4h|2s|1d)$")>;
def : InstRW<[M4WriteVLDA,
M4WriteA1], (instregex "LD1Twov(8b|4h|2s|1d)_POST$")>;
def : InstRW<[M4WriteVLDA], (instregex "LD1Twov(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVLDA,
M4WriteA1], (instregex "LD1Twov(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVLDB], (instregex "LD1Threev(8b|4h|2s|1d)$")>;
def : InstRW<[M4WriteVLDB,
M4WriteA1], (instregex "LD1Threev(8b|4h|2s|1d)_POST$")>;
def : InstRW<[M4WriteVLDB], (instregex "LD1Threev(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVLDB,
M4WriteA1], (instregex "LD1Threev(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVLDC], (instregex "LD1Fourv(8b|4h|2s|1d)$")>;
def : InstRW<[M4WriteVLDC,
M4WriteA1], (instregex "LD1Fourv(8b|4h|2s|1d)_POST$")>;
def : InstRW<[M4WriteVLDC], (instregex "LD1Fourv(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVLDC,
M4WriteA1], (instregex "LD1Fourv(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVLDD], (instregex "LD1i(8|16|32|64)$")>;
def : InstRW<[M4WriteVLDD,
M4WriteA1], (instregex "LD1i(8|16|32|64)_POST$")>;
def : InstRW<[WriteVLD], (instregex "LD1Rv(8b|4h|2s|1d)$")>;
def : InstRW<[WriteVLD,
M4WriteA1], (instregex "LD1Rv(8b|4h|2s|1d)_POST$")>;
def : InstRW<[WriteVLD], (instregex "LD1Rv(16b|8h|4s|2d)$")>;
def : InstRW<[WriteVLD,
M4WriteA1], (instregex "LD1Rv(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVLDF], (instregex "LD2Twov(8b|4h|2s)$")>;
def : InstRW<[M4WriteVLDF,
M4WriteA1], (instregex "LD2Twov(8b|4h|2s)_POST$")>;
def : InstRW<[M4WriteVLDF], (instregex "LD2Twov(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVLDF,
M4WriteA1], (instregex "LD2Twov(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVLDG], (instregex "LD2i(8|16|32|64)$")>;
def : InstRW<[M4WriteVLDG,
M4WriteA1], (instregex "LD2i(8|16|32|64)_POST$")>;
def : InstRW<[M4WriteVLDA], (instregex "LD2Rv(8b|4h|2s|1d)$")>;
def : InstRW<[M4WriteVLDA,
M4WriteA1], (instregex "LD2Rv(8b|4h|2s|1d)_POST$")>;
def : InstRW<[M4WriteVLDA], (instregex "LD2Rv(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVLDA,
M4WriteA1], (instregex "LD2Rv(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVLDI], (instregex "LD3Threev(8b|4h|2s)$")>;
def : InstRW<[M4WriteVLDI,
M4WriteA1], (instregex "LD3Threev(8b|4h|2s)_POST$")>;
def : InstRW<[M4WriteVLDI], (instregex "LD3Threev(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVLDI,
M4WriteA1], (instregex "LD3Threev(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVLDJ], (instregex "LD3i(8|16|32)$")>;
def : InstRW<[M4WriteVLDJ,
M4WriteA1], (instregex "LD3i(8|16|32)_POST$")>;
def : InstRW<[M4WriteVLDL], (instregex "LD3i64$")>;
def : InstRW<[M4WriteVLDL,
M4WriteA1], (instregex "LD3i64_POST$")>;
def : InstRW<[M4WriteVLDB], (instregex "LD3Rv(8b|4h|2s|1d)$")>;
def : InstRW<[M4WriteVLDB,
M4WriteA1], (instregex "LD3Rv(8b|4h|2s|1d)_POST$")>;
def : InstRW<[M4WriteVLDB], (instregex "LD3Rv(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVLDB,
M4WriteA1], (instregex "LD3Rv(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVLDN], (instregex "LD4Fourv(8b|4h|2s)$")>;
def : InstRW<[M4WriteVLDN,
M4WriteA1], (instregex "LD4Fourv(8b|4h|2s)_POST$")>;
def : InstRW<[M4WriteVLDN], (instregex "LD4Fourv(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVLDN,
M4WriteA1], (instregex "LD4Fourv(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVLDK], (instregex "LD4i(8|16|32)$")>;
def : InstRW<[M4WriteVLDK,
M4WriteA1], (instregex "LD4i(8|16|32)_POST$")>;
def : InstRW<[M4WriteVLDM], (instregex "LD4i64$")>;
def : InstRW<[M4WriteVLDM,
M4WriteA1], (instregex "LD4i64_POST$")>;
def : InstRW<[M4WriteVLDC], (instregex "LD4Rv(8b|4h|2s|1d)$")>;
def : InstRW<[M4WriteVLDC,
M4WriteA1], (instregex "LD4Rv(8b|4h|2s|1d)_POST$")>;
def : InstRW<[M4WriteVLDC], (instregex "LD4Rv(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVLDC,
M4WriteA1], (instregex "LD4Rv(16b|8h|4s|2d)_POST$")>;
// ASIMD store instructions.
def : InstRW<[WriteVST], (instregex "ST1Onev(8b|4h|2s|1d)$")>;
def : InstRW<[WriteVST,
M4WriteA1], (instregex "ST1Onev(8b|4h|2s|1d)_POST$")>;
def : InstRW<[WriteVST], (instregex "ST1Onev(16b|8h|4s|2d)$")>;
def : InstRW<[WriteVST,
M4WriteA1], (instregex "ST1Onev(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVSTA], (instregex "ST1Twov(8b|4h|2s|1d)$")>;
def : InstRW<[M4WriteVSTA,
M4WriteA1], (instregex "ST1Twov(8b|4h|2s|1d)_POST$")>;
def : InstRW<[M4WriteVSTA], (instregex "ST1Twov(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVSTA,
M4WriteA1], (instregex "ST1Twov(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVSTB], (instregex "ST1Threev(8b|4h|2s|1d)$")>;
def : InstRW<[M4WriteVSTB,
M4WriteA1], (instregex "ST1Threev(8b|4h|2s|1d)_POST$")>;
def : InstRW<[M4WriteVSTB], (instregex "ST1Threev(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVSTB,
M4WriteA1], (instregex "ST1Threev(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVSTC], (instregex "ST1Fourv(8b|4h|2s|1d)$")>;
def : InstRW<[M4WriteVSTC,
M4WriteA1], (instregex "ST1Fourv(8b|4h|2s|1d)_POST$")>;
def : InstRW<[M4WriteVSTC], (instregex "ST1Fourv(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVSTC,
M4WriteA1], (instregex "ST1Fourv(16b|8h|4s|2d)_POST$")>;
def : InstRW<[WriteVST], (instregex "ST1i(8|16|32|64)$")>;
def : InstRW<[WriteVST,
M4WriteA1], (instregex "ST1i(8|16|32|64)_POST$")>;
def : InstRW<[M4WriteVSTD], (instregex "ST2Twov(8b|4h|2s)$")>;
def : InstRW<[M4WriteVSTD,
M4WriteA1], (instregex "ST2Twov(8b|4h|2s)_POST$")>;
def : InstRW<[M4WriteVSTE], (instregex "ST2Twov(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVSTE,
M4WriteA1], (instregex "ST2Twov(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVSTD], (instregex "ST2i(8|16|32|64)$")>;
def : InstRW<[M4WriteVSTD,
M4WriteA1], (instregex "ST2i(8|16|32|64)_POST$")>;
def : InstRW<[M4WriteVSTF], (instregex "ST3Threev(8b|4h|2s)$")>;
def : InstRW<[M4WriteVSTF,
M4WriteA1], (instregex "ST3Threev(8b|4h|2s)_POST$")>;
def : InstRW<[M4WriteVSTG], (instregex "ST3Threev(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVSTG,
M4WriteA1], (instregex "ST3Threev(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVSTE], (instregex "ST3i(8|16|32|64)$")>;
def : InstRW<[M4WriteVSTE,
M4WriteA1], (instregex "ST3i(8|16|32|64)_POST$")>;
def : InstRW<[M4WriteVSTL], (instregex "ST4Fourv(8b|4h|2s)$")>;
def : InstRW<[M4WriteVSTL,
M4WriteA1], (instregex "ST4Fourv(8b|4h|2s)_POST$")>;
def : InstRW<[M4WriteVSTI], (instregex "ST4Fourv(16b|8h|4s|2d)$")>;
def : InstRW<[M4WriteVSTI,
M4WriteA1], (instregex "ST4Fourv(16b|8h|4s|2d)_POST$")>;
def : InstRW<[M4WriteVSTE], (instregex "ST4i(8|16|32|64)$")>;
def : InstRW<[M4WriteVSTE,
M4WriteA1], (instregex "ST4i(8|16|32|64)_POST$")>;
// Cryptography instructions.
def : InstRW<[M4WriteNCRY1], (instregex "^AES[DE]")>;
def : InstRW<[M4WriteNCRY1,
M4ReadAESM1], (instregex "^AESI?MC")>;
def : InstRW<[M4WriteNCRY1A], (instregex "^PMULv")>;
def : InstRW<[M4WriteNCRY1A], (instregex "^PMULLv(1|8)i")>;
def : InstRW<[M4WriteNCRY3A], (instregex "^PMULLv(2|16)i")>;
def : InstRW<[M4WriteNCRY1A], (instregex "^SHA1([CHMP]|SU[01])")>;
def : InstRW<[M4WriteNCRY1A], (instrs SHA256SU0rr)>;
def : InstRW<[M4WriteNCRY5A], (instrs SHA256SU1rrr)>;
def : InstRW<[M4WriteNCRY5A], (instrs SHA256H2rrr)>;
// CRC instructions.
def : InstRW<[M4WriteE2], (instregex "^CRC32C?[BHWX]rr$")>;
} // SchedModel = ExynosM4Model
Index: stable/11/contrib/llvm/lib/Target/AArch64/AArch64SchedPredExynos.td
===================================================================
--- stable/11/contrib/llvm/lib/Target/AArch64/AArch64SchedPredExynos.td (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/AArch64/AArch64SchedPredExynos.td (revision 350259)
@@ -1,157 +1,146 @@
//===- AArch64SchedPredExynos.td - AArch64 Sched Preds -----*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines scheduling predicate definitions that are used by the
// AArch64 Exynos processors.
//
//===----------------------------------------------------------------------===//
// Auxiliary predicates.
// Check the shift in arithmetic and logic instructions.
def ExynosCheckShift : CheckAny<[CheckShiftBy0,
CheckAll<
[CheckShiftLSL,
CheckAny<
[CheckShiftBy1,
CheckShiftBy2,
CheckShiftBy3]>]>]>;
// Exynos predicates.
// Identify BLR specifying the LR register as the indirect target register.
def ExynosBranchLinkLRPred : MCSchedPredicate<
CheckAll<[CheckOpcode<[BLR]>,
CheckRegOperand<0, LR>]>>;
// Identify arithmetic instructions without or with limited extension or shift.
def ExynosArithFn : TIIPredicate<
"isExynosArithFast",
MCOpcodeSwitchStatement<
[MCOpcodeSwitchCase<
IsArithExtOp.ValidOpcodes,
MCReturnStatement<
CheckAny<[CheckExtBy0,
CheckAll<
[CheckAny<
[CheckExtUXTW,
CheckExtUXTX]>,
CheckAny<
[CheckExtBy1,
CheckExtBy2,
CheckExtBy3]>]>]>>>,
MCOpcodeSwitchCase<
IsArithShiftOp.ValidOpcodes,
MCReturnStatement<ExynosCheckShift>>,
MCOpcodeSwitchCase<
IsArithUnshiftOp.ValidOpcodes,
MCReturnStatement<TruePred>>],
MCReturnStatement<FalsePred>>>;
def ExynosArithPred : MCSchedPredicate<ExynosArithFn>;
// Identify logic instructions with limited shift.
def ExynosLogicFn : TIIPredicate<
"isExynosLogicFast",
MCOpcodeSwitchStatement<
[MCOpcodeSwitchCase<
IsLogicShiftOp.ValidOpcodes,
MCReturnStatement<ExynosCheckShift>>,
MCOpcodeSwitchCase<
IsLogicUnshiftOp.ValidOpcodes,
MCReturnStatement<TruePred>>],
MCReturnStatement<FalsePred>>>;
def ExynosLogicPred : MCSchedPredicate<ExynosLogicFn>;
// Identify more logic instructions with limited shift.
def ExynosLogicExFn : TIIPredicate<
"isExynosLogicExFast",
MCOpcodeSwitchStatement<
[MCOpcodeSwitchCase<
IsLogicShiftOp.ValidOpcodes,
MCReturnStatement<
CheckAny<
[ExynosCheckShift,
CheckAll<
[CheckShiftLSL,
CheckShiftBy8]>]>>>,
MCOpcodeSwitchCase<
IsLogicUnshiftOp.ValidOpcodes,
MCReturnStatement<TruePred>>],
MCReturnStatement<FalsePred>>>;
def ExynosLogicExPred : MCSchedPredicate<ExynosLogicExFn>;
// Identify a load or store using the register offset addressing mode
// with a scaled non-extended register.
def ExynosScaledIdxFn : TIIPredicate<"isExynosScaledAddr",
MCOpcodeSwitchStatement<
[MCOpcodeSwitchCase<
IsLoadStoreRegOffsetOp.ValidOpcodes,
MCReturnStatement<
CheckAny<
[CheckMemExtSXTW,
CheckMemExtUXTW,
CheckMemScaled]>>>],
MCReturnStatement<FalsePred>>>;
def ExynosScaledIdxPred : MCSchedPredicate<ExynosScaledIdxFn>;
// Identify FP instructions.
def ExynosFPPred : MCSchedPredicate<CheckAny<[CheckDForm, CheckQForm]>>;
-// Identify whether an instruction whose result is a long vector
-// operates on the upper half of the input registers.
-def ExynosLongVectorUpperFn : TIIPredicate<
- "isExynosLongVectorUpper",
- MCOpcodeSwitchStatement<
- [MCOpcodeSwitchCase<
- IsLongVectorUpperOp.ValidOpcodes,
- MCReturnStatement<TruePred>>],
- MCReturnStatement<FalsePred>>>;
-def ExynosLongVectorUpperPred : MCSchedPredicate<ExynosLongVectorUpperFn>;
-
// Identify 128-bit NEON instructions.
def ExynosQFormPred : MCSchedPredicate<CheckQForm>;
// Identify instructions that reset a register efficiently.
def ExynosResetFn : TIIPredicate<
"isExynosResetFast",
MCOpcodeSwitchStatement<
[MCOpcodeSwitchCase<
[ADR, ADRP,
MOVNWi, MOVNXi,
MOVZWi, MOVZXi],
MCReturnStatement<TruePred>>,
MCOpcodeSwitchCase<
[ORRWri, ORRXri],
MCReturnStatement<
CheckAll<
[CheckIsRegOperand<1>,
CheckAny<
[CheckRegOperand<1, WZR>,
CheckRegOperand<1, XZR>]>]>>>],
MCReturnStatement<
CheckAny<
[IsCopyIdiomFn,
IsZeroFPIdiomFn]>>>>;
def ExynosResetPred : MCSchedPredicate<ExynosResetFn>;
// Identify EXTR as the alias for ROR (immediate).
def ExynosRotateRightImmPred : MCSchedPredicate<
CheckAll<[CheckOpcode<[EXTRWrri, EXTRXrri]>,
CheckSameRegOperand<1, 2>]>>;
// Identify cheap arithmetic and logic immediate instructions.
def ExynosCheapFn : TIIPredicate<
"isExynosCheapAsMove",
MCOpcodeSwitchStatement<
[MCOpcodeSwitchCase<
IsArithLogicImmOp.ValidOpcodes,
MCReturnStatement<TruePred>>],
MCReturnStatement<
CheckAny<
[ExynosArithFn, ExynosResetFn, ExynosLogicFn]>>>>;
Index: stable/11/contrib/llvm/lib/Target/AArch64/AArch64SchedPredicates.td
===================================================================
--- stable/11/contrib/llvm/lib/Target/AArch64/AArch64SchedPredicates.td (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/AArch64/AArch64SchedPredicates.td (revision 350259)
@@ -1,423 +1,370 @@
//===- AArch64SchedPredicates.td - AArch64 Sched Preds -----*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines scheduling predicate definitions that are used by the
// AArch64 subtargets.
//
//===----------------------------------------------------------------------===//
// Function mappers.
// Check the extension type in arithmetic instructions.
let FunctionMapper = "AArch64_AM::getArithExtendType" in {
def CheckExtUXTB : CheckImmOperand_s<3, "AArch64_AM::UXTB">;
def CheckExtUXTH : CheckImmOperand_s<3, "AArch64_AM::UXTH">;
def CheckExtUXTW : CheckImmOperand_s<3, "AArch64_AM::UXTW">;
def CheckExtUXTX : CheckImmOperand_s<3, "AArch64_AM::UXTX">;
def CheckExtSXTB : CheckImmOperand_s<3, "AArch64_AM::SXTB">;
def CheckExtSXTH : CheckImmOperand_s<3, "AArch64_AM::SXTH">;
def CheckExtSXTW : CheckImmOperand_s<3, "AArch64_AM::SXTW">;
def CheckExtSXTX : CheckImmOperand_s<3, "AArch64_AM::SXTX">;
}
// Check for shifting in extended arithmetic instructions.
foreach I = {0-3} in {
let FunctionMapper = "AArch64_AM::getArithShiftValue" in
def CheckExtBy#I : CheckImmOperand<3, I>;
}
// Check the extension type in the register offset addressing mode.
let FunctionMapper = "AArch64_AM::getMemExtendType" in {
def CheckMemExtUXTW : CheckImmOperand_s<3, "AArch64_AM::UXTW">;
def CheckMemExtLSL : CheckImmOperand_s<3, "AArch64_AM::UXTX">;
def CheckMemExtSXTW : CheckImmOperand_s<3, "AArch64_AM::SXTW">;
def CheckMemExtSXTX : CheckImmOperand_s<3, "AArch64_AM::SXTX">;
}
// Check for scaling in the register offset addressing mode.
let FunctionMapper = "AArch64_AM::getMemDoShift" in
def CheckMemScaled : CheckImmOperandSimple<3>;
// Check the shifting type in arithmetic and logic instructions.
let FunctionMapper = "AArch64_AM::getShiftType" in {
def CheckShiftLSL : CheckImmOperand_s<3, "AArch64_AM::LSL">;
def CheckShiftLSR : CheckImmOperand_s<3, "AArch64_AM::LSR">;
def CheckShiftASR : CheckImmOperand_s<3, "AArch64_AM::ASR">;
def CheckShiftROR : CheckImmOperand_s<3, "AArch64_AM::ROR">;
def CheckShiftMSL : CheckImmOperand_s<3, "AArch64_AM::MSL">;
}
// Check for shifting in arithmetic and logic instructions.
foreach I = {0-3, 8} in {
let FunctionMapper = "AArch64_AM::getShiftValue" in
def CheckShiftBy#I : CheckImmOperand<3, I>;
}
// Generic predicates.
// Identify whether an instruction is the 64-bit NEON form based on its result.
def CheckDForm : CheckAll<[CheckIsRegOperand<0>,
CheckAny<[CheckRegOperand<0, D0>,
CheckRegOperand<0, D1>,
CheckRegOperand<0, D2>,
CheckRegOperand<0, D3>,
CheckRegOperand<0, D4>,
CheckRegOperand<0, D5>,
CheckRegOperand<0, D6>,
CheckRegOperand<0, D7>,
CheckRegOperand<0, D8>,
CheckRegOperand<0, D9>,
CheckRegOperand<0, D10>,
CheckRegOperand<0, D11>,
CheckRegOperand<0, D12>,
CheckRegOperand<0, D13>,
CheckRegOperand<0, D14>,
CheckRegOperand<0, D15>,
CheckRegOperand<0, D16>,
CheckRegOperand<0, D17>,
CheckRegOperand<0, D18>,
CheckRegOperand<0, D19>,
CheckRegOperand<0, D20>,
CheckRegOperand<0, D21>,
CheckRegOperand<0, D22>,
CheckRegOperand<0, D23>,
CheckRegOperand<0, D24>,
CheckRegOperand<0, D25>,
CheckRegOperand<0, D26>,
CheckRegOperand<0, D27>,
CheckRegOperand<0, D28>,
CheckRegOperand<0, D29>,
CheckRegOperand<0, D30>,
CheckRegOperand<0, D31>]>]>;
// Identify whether an instruction is the 128-bit NEON form based on its result.
def CheckQForm : CheckAll<[CheckIsRegOperand<0>,
CheckAny<[CheckRegOperand<0, Q0>,
CheckRegOperand<0, Q1>,
CheckRegOperand<0, Q2>,
CheckRegOperand<0, Q3>,
CheckRegOperand<0, Q4>,
CheckRegOperand<0, Q5>,
CheckRegOperand<0, Q6>,
CheckRegOperand<0, Q7>,
CheckRegOperand<0, Q8>,
CheckRegOperand<0, Q9>,
CheckRegOperand<0, Q10>,
CheckRegOperand<0, Q11>,
CheckRegOperand<0, Q12>,
CheckRegOperand<0, Q13>,
CheckRegOperand<0, Q14>,
CheckRegOperand<0, Q15>,
CheckRegOperand<0, Q16>,
CheckRegOperand<0, Q17>,
CheckRegOperand<0, Q18>,
CheckRegOperand<0, Q19>,
CheckRegOperand<0, Q20>,
CheckRegOperand<0, Q21>,
CheckRegOperand<0, Q22>,
CheckRegOperand<0, Q23>,
CheckRegOperand<0, Q24>,
CheckRegOperand<0, Q25>,
CheckRegOperand<0, Q26>,
CheckRegOperand<0, Q27>,
CheckRegOperand<0, Q28>,
CheckRegOperand<0, Q29>,
CheckRegOperand<0, Q30>,
CheckRegOperand<0, Q31>]>]>;
// Identify arithmetic instructions with extend.
def IsArithExtOp : CheckOpcode<[ADDWrx, ADDXrx, ADDSWrx, ADDSXrx,
SUBWrx, SUBXrx, SUBSWrx, SUBSXrx,
ADDXrx64, ADDSXrx64,
SUBXrx64, SUBSXrx64]>;
// Identify arithmetic immediate instructions.
def IsArithImmOp : CheckOpcode<[ADDWri, ADDXri, ADDSWri, ADDSXri,
SUBWri, SUBXri, SUBSWri, SUBSXri]>;
// Identify arithmetic instructions with shift.
def IsArithShiftOp : CheckOpcode<[ADDWrs, ADDXrs, ADDSWrs, ADDSXrs,
SUBWrs, SUBXrs, SUBSWrs, SUBSXrs]>;
// Identify arithmetic instructions without shift.
def IsArithUnshiftOp : CheckOpcode<[ADDWrr, ADDXrr, ADDSWrr, ADDSXrr,
SUBWrr, SUBXrr, SUBSWrr, SUBSXrr]>;
// Identify logic immediate instructions.
def IsLogicImmOp : CheckOpcode<[ANDWri, ANDXri,
EORWri, EORXri,
ORRWri, ORRXri]>;
// Identify logic instructions with shift.
def IsLogicShiftOp : CheckOpcode<[ANDWrs, ANDXrs, ANDSWrs, ANDSXrs,
BICWrs, BICXrs, BICSWrs, BICSXrs,
EONWrs, EONXrs,
EORWrs, EORXrs,
ORNWrs, ORNXrs,
ORRWrs, ORRXrs]>;
// Identify logic instructions without shift.
def IsLogicUnshiftOp : CheckOpcode<[ANDWrr, ANDXrr, ANDSWrr, ANDSXrr,
BICWrr, BICXrr, BICSWrr, BICSXrr,
EONWrr, EONXrr,
EORWrr, EORXrr,
ORNWrr, ORNXrr,
ORRWrr, ORRXrr]>;
// Identify arithmetic and logic immediate instructions.
def IsArithLogicImmOp : CheckOpcode<!listconcat(IsArithImmOp.ValidOpcodes,
IsLogicImmOp.ValidOpcodes)>;
// Identify arithmetic and logic instructions with shift.
def IsArithLogicShiftOp : CheckOpcode<!listconcat(IsArithShiftOp.ValidOpcodes,
IsLogicShiftOp.ValidOpcodes)>;
// Identify arithmetic and logic instructions without shift.
def IsArithLogicUnshiftOp : CheckOpcode<!listconcat(IsArithUnshiftOp.ValidOpcodes,
IsLogicUnshiftOp.ValidOpcodes)>;
// Identify whether an instruction is an ASIMD
// load using the post index addressing mode.
def IsLoadASIMDPostOp : CheckOpcode<[LD1Onev8b_POST, LD1Onev4h_POST, LD1Onev2s_POST, LD1Onev1d_POST,
LD1Onev16b_POST, LD1Onev8h_POST, LD1Onev4s_POST, LD1Onev2d_POST,
LD1Twov8b_POST, LD1Twov4h_POST, LD1Twov2s_POST, LD1Twov1d_POST,
LD1Twov16b_POST, LD1Twov8h_POST, LD1Twov4s_POST, LD1Twov2d_POST,
LD1Threev8b_POST, LD1Threev4h_POST, LD1Threev2s_POST, LD1Threev1d_POST,
LD1Threev16b_POST, LD1Threev8h_POST, LD1Threev4s_POST, LD1Threev2d_POST,
LD1Fourv8b_POST, LD1Fourv4h_POST, LD1Fourv2s_POST, LD1Fourv1d_POST,
LD1Fourv16b_POST, LD1Fourv8h_POST, LD1Fourv4s_POST, LD1Fourv2d_POST,
LD1i8_POST, LD1i16_POST, LD1i32_POST, LD1i64_POST,
LD1Rv8b_POST, LD1Rv4h_POST, LD1Rv2s_POST, LD1Rv1d_POST,
LD1Rv16b_POST, LD1Rv8h_POST, LD1Rv4s_POST, LD1Rv2d_POST,
LD2Twov8b_POST, LD2Twov4h_POST, LD2Twov2s_POST,
LD2Twov16b_POST, LD2Twov8h_POST, LD2Twov4s_POST, LD2Twov2d_POST,
LD2i8_POST, LD2i16_POST, LD2i32_POST, LD2i64_POST,
LD2Rv8b_POST, LD2Rv4h_POST, LD2Rv2s_POST, LD2Rv1d_POST,
LD2Rv16b_POST, LD2Rv8h_POST, LD2Rv4s_POST, LD2Rv2d_POST,
LD3Threev8b_POST, LD3Threev4h_POST, LD3Threev2s_POST,
LD3Threev16b_POST, LD3Threev8h_POST, LD3Threev4s_POST, LD3Threev2d_POST,
LD3i8_POST, LD3i16_POST, LD3i32_POST, LD3i64_POST,
LD3Rv8b_POST, LD3Rv4h_POST, LD3Rv2s_POST, LD3Rv1d_POST,
LD3Rv16b_POST, LD3Rv8h_POST, LD3Rv4s_POST, LD3Rv2d_POST,
LD4Fourv8b_POST, LD4Fourv4h_POST, LD4Fourv2s_POST,
LD4Fourv16b_POST, LD4Fourv8h_POST, LD4Fourv4s_POST, LD4Fourv2d_POST,
LD4i8_POST, LD4i16_POST, LD4i32_POST, LD4i64_POST,
LD4Rv8b_POST, LD4Rv4h_POST, LD4Rv2s_POST, LD4Rv1d_POST,
LD4Rv16b_POST, LD4Rv8h_POST, LD4Rv4s_POST, LD4Rv2d_POST]>;
// Identify whether an instruction is an ASIMD
// store using the post index addressing mode.
def IsStoreASIMDPostOp : CheckOpcode<[ST1Onev8b_POST, ST1Onev4h_POST, ST1Onev2s_POST, ST1Onev1d_POST,
ST1Onev16b_POST, ST1Onev8h_POST, ST1Onev4s_POST, ST1Onev2d_POST,
ST1Twov8b_POST, ST1Twov4h_POST, ST1Twov2s_POST, ST1Twov1d_POST,
ST1Twov16b_POST, ST1Twov8h_POST, ST1Twov4s_POST, ST1Twov2d_POST,
ST1Threev8b_POST, ST1Threev4h_POST, ST1Threev2s_POST, ST1Threev1d_POST,
ST1Threev16b_POST, ST1Threev8h_POST, ST1Threev4s_POST, ST1Threev2d_POST,
ST1Fourv8b_POST, ST1Fourv4h_POST, ST1Fourv2s_POST, ST1Fourv1d_POST,
ST1Fourv16b_POST, ST1Fourv8h_POST, ST1Fourv4s_POST, ST1Fourv2d_POST,
ST1i8_POST, ST1i16_POST, ST1i32_POST, ST1i64_POST,
ST2Twov8b_POST, ST2Twov4h_POST, ST2Twov2s_POST,
ST2Twov16b_POST, ST2Twov8h_POST, ST2Twov4s_POST, ST2Twov2d_POST,
ST2i8_POST, ST2i16_POST, ST2i32_POST, ST2i64_POST,
ST3Threev8b_POST, ST3Threev4h_POST, ST3Threev2s_POST,
ST3Threev16b_POST, ST3Threev8h_POST, ST3Threev4s_POST, ST3Threev2d_POST,
ST3i8_POST, ST3i16_POST, ST3i32_POST, ST3i64_POST,
ST4Fourv8b_POST, ST4Fourv4h_POST, ST4Fourv2s_POST,
ST4Fourv16b_POST, ST4Fourv8h_POST, ST4Fourv4s_POST, ST4Fourv2d_POST,
ST4i8_POST, ST4i16_POST, ST4i32_POST, ST4i64_POST]>;
// Identify whether an instruction is an ASIMD load
// or store using the post index addressing mode.
def IsLoadStoreASIMDPostOp : CheckOpcode<!listconcat(IsLoadASIMDPostOp.ValidOpcodes,
IsStoreASIMDPostOp.ValidOpcodes)>;
// Identify whether an instruction is a load
// using the register offset addressing mode.
def IsLoadRegOffsetOp : CheckOpcode<[PRFMroW, PRFMroX,
LDRBBroW, LDRBBroX,
LDRSBWroW, LDRSBWroX, LDRSBXroW, LDRSBXroX,
LDRHHroW, LDRHHroX,
LDRSHWroW, LDRSHWroX, LDRSHXroW, LDRSHXroX,
LDRWroW, LDRWroX,
LDRSWroW, LDRSWroX,
LDRXroW, LDRXroX,
LDRBroW, LDRBroX,
LDRHroW, LDRHroX,
LDRSroW, LDRSroX,
LDRDroW, LDRDroX]>;
// Identify whether an instruction is a load
// using the register offset addressing mode.
def IsStoreRegOffsetOp : CheckOpcode<[STRBBroW, STRBBroX,
STRHHroW, STRHHroX,
STRWroW, STRWroX,
STRXroW, STRXroX,
STRBroW, STRBroX,
STRHroW, STRHroX,
STRSroW, STRSroX,
STRDroW, STRDroX]>;
// Identify whether an instruction is a load or
// store using the register offset addressing mode.
def IsLoadStoreRegOffsetOp : CheckOpcode<!listconcat(IsLoadRegOffsetOp.ValidOpcodes,
IsStoreRegOffsetOp.ValidOpcodes)>;
-// Identify whether an instruction whose result is a long vector
-// operates on the upper half of the input registers.
-def IsLongVectorUpperOp : CheckOpcode<[FCVTLv8i16, FCVTLv4i32,
- FCVTNv8i16, FCVTNv4i32,
- FCVTXNv4f32,
- PMULLv16i8, PMULLv2i64,
- RADDHNv8i16_v16i8, RADDHNv4i32_v8i16, RADDHNv2i64_v4i32,
- RSHRNv16i8_shift, RSHRNv8i16_shift, RSHRNv4i32_shift,
- RSUBHNv8i16_v16i8, RSUBHNv4i32_v8i16, RSUBHNv2i64_v4i32,
- SABALv16i8_v8i16, SABALv8i16_v4i32, SABALv4i32_v2i64,
- SABDLv16i8_v8i16, SABDLv8i16_v4i32, SABDLv4i32_v2i64,
- SADDLv16i8_v8i16, SADDLv8i16_v4i32, SADDLv4i32_v2i64,
- SADDWv16i8_v8i16, SADDWv8i16_v4i32, SADDWv4i32_v2i64,
- SHLLv16i8, SHLLv8i16, SHLLv4i32,
- SHRNv16i8_shift, SHRNv8i16_shift, SHRNv4i32_shift,
- SMLALv16i8_v8i16, SMLALv8i16_v4i32, SMLALv4i32_v2i64,
- SMLALv8i16_indexed, SMLALv4i32_indexed,
- SMLSLv16i8_v8i16, SMLSLv8i16_v4i32, SMLSLv4i32_v2i64,
- SMLSLv8i16_indexed, SMLSLv4i32_indexed,
- SMULLv16i8_v8i16, SMULLv8i16_v4i32, SMULLv4i32_v2i64,
- SMULLv8i16_indexed, SMULLv4i32_indexed,
- SQDMLALv8i16_v4i32, SQDMLALv4i32_v2i64,
- SQDMLALv8i16_indexed, SQDMLALv4i32_indexed,
- SQDMLSLv8i16_v4i32, SQDMLSLv4i32_v2i64,
- SQDMLSLv8i16_indexed, SQDMLSLv4i32_indexed,
- SQDMULLv8i16_v4i32, SQDMULLv4i32_v2i64,
- SQDMULLv8i16_indexed, SQDMULLv4i32_indexed,
- SQRSHRNv16i8_shift, SQRSHRNv8i16_shift, SQRSHRNv4i32_shift,
- SQRSHRUNv16i8_shift, SQRSHRUNv8i16_shift, SQRSHRUNv4i32_shift,
- SQSHRNv16i8_shift, SQSHRNv8i16_shift, SQSHRNv4i32_shift,
- SQSHRUNv16i8_shift, SQSHRUNv8i16_shift, SQSHRUNv4i32_shift,
- SQXTNv16i8, SQXTNv8i16, SQXTNv4i32,
- SQXTUNv16i8, SQXTUNv8i16, SQXTUNv4i32,
- SSHLLv16i8_shift, SSHLLv8i16_shift, SSHLLv4i32_shift,
- SSUBLv16i8_v8i16, SSUBLv8i16_v4i32, SSUBLv4i32_v2i64,
- SSUBWv16i8_v8i16, SSUBWv8i16_v4i32, SSUBWv4i32_v2i64,
- UABALv16i8_v8i16, UABALv8i16_v4i32, UABALv4i32_v2i64,
- UABDLv16i8_v8i16, UABDLv8i16_v4i32, UABDLv4i32_v2i64,
- UADDLv16i8_v8i16, UADDLv8i16_v4i32, UADDLv4i32_v2i64,
- UADDWv16i8_v8i16, UADDWv8i16_v4i32, UADDWv4i32_v2i64,
- UMLALv16i8_v8i16, UMLALv8i16_v4i32, UMLALv4i32_v2i64,
- UMLALv8i16_indexed, UMLALv4i32_indexed,
- UMLSLv16i8_v8i16, UMLSLv8i16_v4i32, UMLSLv4i32_v2i64,
- UMLSLv8i16_indexed, UMLSLv4i32_indexed,
- UMULLv16i8_v8i16, UMULLv8i16_v4i32, UMULLv4i32_v2i64,
- UMULLv8i16_indexed, UMULLv4i32_indexed,
- UQSHRNv16i8_shift, UQSHRNv8i16_shift, UQSHRNv4i32_shift,
- UQXTNv16i8, UQXTNv8i16, UQXTNv4i32,
- USHLLv16i8_shift, USHLLv8i16_shift, USHLLv4i32_shift,
- USUBLv16i8_v8i16, USUBLv8i16_v4i32, USUBLv4i32_v2i64,
- USUBWv16i8_v8i16, USUBWv8i16_v4i32, USUBWv4i32_v2i64,
- XTNv16i8, XTNv8i16, XTNv4i32]>;
-
// Target predicates.
// Identify an instruction that effectively transfers a register to another.
def IsCopyIdiomFn : TIIPredicate<"isCopyIdiom",
MCOpcodeSwitchStatement<
[// MOV {Rd, SP}, {SP, Rn} =>
// ADD {Rd, SP}, {SP, Rn}, #0
MCOpcodeSwitchCase<
[ADDWri, ADDXri],
MCReturnStatement<
CheckAll<
[CheckIsRegOperand<0>,
CheckIsRegOperand<1>,
CheckAny<
[CheckRegOperand<0, WSP>,
CheckRegOperand<0, SP>,
CheckRegOperand<1, WSP>,
CheckRegOperand<1, SP>]>,
CheckZeroOperand<2>]>>>,
// MOV Rd, Rm =>
// ORR Rd, ZR, Rm, LSL #0
MCOpcodeSwitchCase<
[ORRWrs, ORRXrs],
MCReturnStatement<
CheckAll<
[CheckIsRegOperand<1>,
CheckIsRegOperand<2>,
CheckAny<
[CheckRegOperand<1, WZR>,
CheckRegOperand<1, XZR>]>,
CheckShiftBy0]>>>],
MCReturnStatement<FalsePred>>>;
def IsCopyIdiomPred : MCSchedPredicate<IsCopyIdiomFn>;
// Identify arithmetic instructions with an extended register.
def RegExtendedFn : TIIPredicate<"hasExtendedReg",
MCOpcodeSwitchStatement<
[MCOpcodeSwitchCase<
IsArithExtOp.ValidOpcodes,
MCReturnStatement<
CheckNot<CheckZeroOperand<3>>>>],
MCReturnStatement<FalsePred>>>;
def RegExtendedPred : MCSchedPredicate<RegExtendedFn>;
// Identify arithmetic and logic instructions with a shifted register.
def RegShiftedFn : TIIPredicate<"hasShiftedReg",
MCOpcodeSwitchStatement<
[MCOpcodeSwitchCase<
IsArithLogicShiftOp.ValidOpcodes,
MCReturnStatement<
CheckNot<CheckZeroOperand<3>>>>],
MCReturnStatement<FalsePred>>>;
def RegShiftedPred : MCSchedPredicate<RegShiftedFn>;
// Identify a load or store using the register offset addressing mode
// with an extended or scaled register.
def ScaledIdxFn : TIIPredicate<"isScaledAddr",
MCOpcodeSwitchStatement<
[MCOpcodeSwitchCase<
IsLoadStoreRegOffsetOp.ValidOpcodes,
MCReturnStatement<
CheckAny<[CheckNot<CheckMemExtLSL>,
CheckMemScaled]>>>],
MCReturnStatement<FalsePred>>>;
def ScaledIdxPred : MCSchedPredicate<ScaledIdxFn>;
// Identify an instruction that effectively resets a FP register to zero.
def IsZeroFPIdiomFn : TIIPredicate<"isZeroFPIdiom",
MCOpcodeSwitchStatement<
[// MOVI Vd, #0
MCOpcodeSwitchCase<
[MOVIv8b_ns, MOVIv16b_ns,
MOVID, MOVIv2d_ns],
MCReturnStatement<CheckZeroOperand<1>>>,
// MOVI Vd, #0, LSL #0
MCOpcodeSwitchCase<
[MOVIv4i16, MOVIv8i16,
MOVIv2i32, MOVIv4i32],
MCReturnStatement<
CheckAll<
[CheckZeroOperand<1>,
CheckZeroOperand<2>]>>>],
MCReturnStatement<FalsePred>>>;
def IsZeroFPIdiomPred : MCSchedPredicate<IsZeroFPIdiomFn>;
// Identify an instruction that effectively resets a GP register to zero.
def IsZeroIdiomFn : TIIPredicate<"isZeroIdiom",
MCOpcodeSwitchStatement<
[// ORR Rd, ZR, #0
MCOpcodeSwitchCase<
[ORRWri, ORRXri],
MCReturnStatement<
CheckAll<
[CheckIsRegOperand<1>,
CheckAny<
[CheckRegOperand<1, WZR>,
CheckRegOperand<1, XZR>]>,
CheckZeroOperand<2>]>>>],
MCReturnStatement<FalsePred>>>;
def IsZeroIdiomPred : MCSchedPredicate<IsZeroIdiomFn>;
Index: stable/11/contrib/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp (revision 350259)
@@ -1,1160 +1,1169 @@
//===-- SIFoldOperands.cpp - Fold operands --- ----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
/// \file
//===----------------------------------------------------------------------===//
//
#include "AMDGPU.h"
#include "AMDGPUSubtarget.h"
#include "SIInstrInfo.h"
#include "SIMachineFunctionInfo.h"
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#define DEBUG_TYPE "si-fold-operands"
using namespace llvm;
namespace {
struct FoldCandidate {
MachineInstr *UseMI;
union {
MachineOperand *OpToFold;
uint64_t ImmToFold;
int FrameIndexToFold;
};
int ShrinkOpcode;
unsigned char UseOpNo;
MachineOperand::MachineOperandType Kind;
bool Commuted;
FoldCandidate(MachineInstr *MI, unsigned OpNo, MachineOperand *FoldOp,
bool Commuted_ = false,
int ShrinkOp = -1) :
UseMI(MI), OpToFold(nullptr), ShrinkOpcode(ShrinkOp), UseOpNo(OpNo),
Kind(FoldOp->getType()),
Commuted(Commuted_) {
if (FoldOp->isImm()) {
ImmToFold = FoldOp->getImm();
} else if (FoldOp->isFI()) {
FrameIndexToFold = FoldOp->getIndex();
} else {
assert(FoldOp->isReg());
OpToFold = FoldOp;
}
}
bool isFI() const {
return Kind == MachineOperand::MO_FrameIndex;
}
bool isImm() const {
return Kind == MachineOperand::MO_Immediate;
}
bool isReg() const {
return Kind == MachineOperand::MO_Register;
}
bool isCommuted() const {
return Commuted;
}
bool needsShrink() const {
return ShrinkOpcode != -1;
}
int getShrinkOpcode() const {
return ShrinkOpcode;
}
};
class SIFoldOperands : public MachineFunctionPass {
public:
static char ID;
MachineRegisterInfo *MRI;
const SIInstrInfo *TII;
const SIRegisterInfo *TRI;
const GCNSubtarget *ST;
void foldOperand(MachineOperand &OpToFold,
MachineInstr *UseMI,
unsigned UseOpIdx,
SmallVectorImpl<FoldCandidate> &FoldList,
SmallVectorImpl<MachineInstr *> &CopiesToReplace) const;
void foldInstOperand(MachineInstr &MI, MachineOperand &OpToFold) const;
const MachineOperand *isClamp(const MachineInstr &MI) const;
bool tryFoldClamp(MachineInstr &MI);
std::pair<const MachineOperand *, int> isOMod(const MachineInstr &MI) const;
bool tryFoldOMod(MachineInstr &MI);
public:
SIFoldOperands() : MachineFunctionPass(ID) {
initializeSIFoldOperandsPass(*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
StringRef getPassName() const override { return "SI Fold Operands"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
MachineFunctionPass::getAnalysisUsage(AU);
}
};
} // End anonymous namespace.
INITIALIZE_PASS(SIFoldOperands, DEBUG_TYPE,
"SI Fold Operands", false, false)
char SIFoldOperands::ID = 0;
char &llvm::SIFoldOperandsID = SIFoldOperands::ID;
// Wrapper around isInlineConstant that understands special cases when
// instruction types are replaced during operand folding.
static bool isInlineConstantIfFolded(const SIInstrInfo *TII,
const MachineInstr &UseMI,
unsigned OpNo,
const MachineOperand &OpToFold) {
if (TII->isInlineConstant(UseMI, OpNo, OpToFold))
return true;
unsigned Opc = UseMI.getOpcode();
switch (Opc) {
case AMDGPU::V_MAC_F32_e64:
case AMDGPU::V_MAC_F16_e64:
case AMDGPU::V_FMAC_F32_e64: {
// Special case for mac. Since this is replaced with mad when folded into
// src2, we need to check the legality for the final instruction.
int Src2Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
if (static_cast<int>(OpNo) == Src2Idx) {
bool IsFMA = Opc == AMDGPU::V_FMAC_F32_e64;
bool IsF32 = Opc == AMDGPU::V_MAC_F32_e64;
unsigned Opc = IsFMA ?
AMDGPU::V_FMA_F32 : (IsF32 ? AMDGPU::V_MAD_F32 : AMDGPU::V_MAD_F16);
const MCInstrDesc &MadDesc = TII->get(Opc);
return TII->isInlineConstant(OpToFold, MadDesc.OpInfo[OpNo].OperandType);
}
return false;
}
default:
return false;
}
}
FunctionPass *llvm::createSIFoldOperandsPass() {
return new SIFoldOperands();
}
static bool updateOperand(FoldCandidate &Fold,
const SIInstrInfo &TII,
const TargetRegisterInfo &TRI) {
MachineInstr *MI = Fold.UseMI;
MachineOperand &Old = MI->getOperand(Fold.UseOpNo);
assert(Old.isReg());
if (Fold.isImm()) {
if (MI->getDesc().TSFlags & SIInstrFlags::IsPacked) {
// Set op_sel/op_sel_hi on this operand or bail out if op_sel is
// already set.
unsigned Opcode = MI->getOpcode();
int OpNo = MI->getOperandNo(&Old);
int ModIdx = -1;
if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0))
ModIdx = AMDGPU::OpName::src0_modifiers;
else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src1))
ModIdx = AMDGPU::OpName::src1_modifiers;
else if (OpNo == AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src2))
ModIdx = AMDGPU::OpName::src2_modifiers;
assert(ModIdx != -1);
ModIdx = AMDGPU::getNamedOperandIdx(Opcode, ModIdx);
MachineOperand &Mod = MI->getOperand(ModIdx);
unsigned Val = Mod.getImm();
if ((Val & SISrcMods::OP_SEL_0) || !(Val & SISrcMods::OP_SEL_1))
return false;
// If upper part is all zero we do not need op_sel_hi.
if (!isUInt<16>(Fold.ImmToFold)) {
if (!(Fold.ImmToFold & 0xffff)) {
Mod.setImm(Mod.getImm() | SISrcMods::OP_SEL_0);
Mod.setImm(Mod.getImm() & ~SISrcMods::OP_SEL_1);
Old.ChangeToImmediate((Fold.ImmToFold >> 16) & 0xffff);
return true;
}
Mod.setImm(Mod.getImm() & ~SISrcMods::OP_SEL_1);
}
}
+ }
- if (Fold.needsShrink()) {
- MachineBasicBlock *MBB = MI->getParent();
- auto Liveness = MBB->computeRegisterLiveness(&TRI, AMDGPU::VCC, MI);
- if (Liveness != MachineBasicBlock::LQR_Dead)
- return false;
+ if ((Fold.isImm() || Fold.isFI()) && Fold.needsShrink()) {
+ MachineBasicBlock *MBB = MI->getParent();
+ auto Liveness = MBB->computeRegisterLiveness(&TRI, AMDGPU::VCC, MI);
+ if (Liveness != MachineBasicBlock::LQR_Dead)
+ return false;
- MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();
- int Op32 = Fold.getShrinkOpcode();
- MachineOperand &Dst0 = MI->getOperand(0);
- MachineOperand &Dst1 = MI->getOperand(1);
- assert(Dst0.isDef() && Dst1.isDef());
+ MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();
+ int Op32 = Fold.getShrinkOpcode();
+ MachineOperand &Dst0 = MI->getOperand(0);
+ MachineOperand &Dst1 = MI->getOperand(1);
+ assert(Dst0.isDef() && Dst1.isDef());
- bool HaveNonDbgCarryUse = !MRI.use_nodbg_empty(Dst1.getReg());
+ bool HaveNonDbgCarryUse = !MRI.use_nodbg_empty(Dst1.getReg());
- const TargetRegisterClass *Dst0RC = MRI.getRegClass(Dst0.getReg());
- unsigned NewReg0 = MRI.createVirtualRegister(Dst0RC);
- const TargetRegisterClass *Dst1RC = MRI.getRegClass(Dst1.getReg());
- unsigned NewReg1 = MRI.createVirtualRegister(Dst1RC);
+ const TargetRegisterClass *Dst0RC = MRI.getRegClass(Dst0.getReg());
+ unsigned NewReg0 = MRI.createVirtualRegister(Dst0RC);
- MachineInstr *Inst32 = TII.buildShrunkInst(*MI, Op32);
+ MachineInstr *Inst32 = TII.buildShrunkInst(*MI, Op32);
- if (HaveNonDbgCarryUse) {
- BuildMI(*MBB, MI, MI->getDebugLoc(), TII.get(AMDGPU::COPY), Dst1.getReg())
- .addReg(AMDGPU::VCC, RegState::Kill);
- }
-
- // Keep the old instruction around to avoid breaking iterators, but
- // replace the outputs with dummy registers.
- Dst0.setReg(NewReg0);
- Dst1.setReg(NewReg1);
-
- if (Fold.isCommuted())
- TII.commuteInstruction(*Inst32, false);
- return true;
+ if (HaveNonDbgCarryUse) {
+ BuildMI(*MBB, MI, MI->getDebugLoc(), TII.get(AMDGPU::COPY), Dst1.getReg())
+ .addReg(AMDGPU::VCC, RegState::Kill);
}
- Old.ChangeToImmediate(Fold.ImmToFold);
+ // Keep the old instruction around to avoid breaking iterators, but
+ // replace it with a dummy instruction to remove uses.
+ //
+ // FIXME: We should not invert how this pass looks at operands to avoid
+ // this. Should track set of foldable movs instead of looking for uses
+ // when looking at a use.
+ Dst0.setReg(NewReg0);
+ for (unsigned I = MI->getNumOperands() - 1; I > 0; --I)
+ MI->RemoveOperand(I);
+ MI->setDesc(TII.get(AMDGPU::IMPLICIT_DEF));
+
+ if (Fold.isCommuted())
+ TII.commuteInstruction(*Inst32, false);
return true;
}
assert(!Fold.needsShrink() && "not handled");
+ if (Fold.isImm()) {
+ Old.ChangeToImmediate(Fold.ImmToFold);
+ return true;
+ }
+
if (Fold.isFI()) {
Old.ChangeToFrameIndex(Fold.FrameIndexToFold);
return true;
}
MachineOperand *New = Fold.OpToFold;
if (TargetRegisterInfo::isVirtualRegister(Old.getReg()) &&
TargetRegisterInfo::isVirtualRegister(New->getReg())) {
Old.substVirtReg(New->getReg(), New->getSubReg(), TRI);
Old.setIsUndef(New->isUndef());
return true;
}
// FIXME: Handle physical registers.
return false;
}
static bool isUseMIInFoldList(ArrayRef<FoldCandidate> FoldList,
const MachineInstr *MI) {
for (auto Candidate : FoldList) {
if (Candidate.UseMI == MI)
return true;
}
return false;
}
static bool tryAddToFoldList(SmallVectorImpl<FoldCandidate> &FoldList,
MachineInstr *MI, unsigned OpNo,
MachineOperand *OpToFold,
const SIInstrInfo *TII) {
if (!TII->isOperandLegal(*MI, OpNo, OpToFold)) {
// Special case for v_mac_{f16, f32}_e64 if we are trying to fold into src2
unsigned Opc = MI->getOpcode();
if ((Opc == AMDGPU::V_MAC_F32_e64 || Opc == AMDGPU::V_MAC_F16_e64 ||
Opc == AMDGPU::V_FMAC_F32_e64) &&
(int)OpNo == AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2)) {
bool IsFMA = Opc == AMDGPU::V_FMAC_F32_e64;
bool IsF32 = Opc == AMDGPU::V_MAC_F32_e64;
unsigned NewOpc = IsFMA ?
AMDGPU::V_FMA_F32 : (IsF32 ? AMDGPU::V_MAD_F32 : AMDGPU::V_MAD_F16);
// Check if changing this to a v_mad_{f16, f32} instruction will allow us
// to fold the operand.
MI->setDesc(TII->get(NewOpc));
bool FoldAsMAD = tryAddToFoldList(FoldList, MI, OpNo, OpToFold, TII);
if (FoldAsMAD) {
MI->untieRegOperand(OpNo);
return true;
}
MI->setDesc(TII->get(Opc));
}
// Special case for s_setreg_b32
if (Opc == AMDGPU::S_SETREG_B32 && OpToFold->isImm()) {
MI->setDesc(TII->get(AMDGPU::S_SETREG_IMM32_B32));
FoldList.push_back(FoldCandidate(MI, OpNo, OpToFold));
return true;
}
// If we are already folding into another operand of MI, then
// we can't commute the instruction, otherwise we risk making the
// other fold illegal.
if (isUseMIInFoldList(FoldList, MI))
return false;
unsigned CommuteOpNo = OpNo;
// Operand is not legal, so try to commute the instruction to
// see if this makes it possible to fold.
unsigned CommuteIdx0 = TargetInstrInfo::CommuteAnyOperandIndex;
unsigned CommuteIdx1 = TargetInstrInfo::CommuteAnyOperandIndex;
bool CanCommute = TII->findCommutedOpIndices(*MI, CommuteIdx0, CommuteIdx1);
if (CanCommute) {
if (CommuteIdx0 == OpNo)
CommuteOpNo = CommuteIdx1;
else if (CommuteIdx1 == OpNo)
CommuteOpNo = CommuteIdx0;
}
// One of operands might be an Imm operand, and OpNo may refer to it after
// the call of commuteInstruction() below. Such situations are avoided
// here explicitly as OpNo must be a register operand to be a candidate
// for memory folding.
if (CanCommute && (!MI->getOperand(CommuteIdx0).isReg() ||
!MI->getOperand(CommuteIdx1).isReg()))
return false;
if (!CanCommute ||
!TII->commuteInstruction(*MI, false, CommuteIdx0, CommuteIdx1))
return false;
if (!TII->isOperandLegal(*MI, CommuteOpNo, OpToFold)) {
if ((Opc == AMDGPU::V_ADD_I32_e64 ||
Opc == AMDGPU::V_SUB_I32_e64 ||
Opc == AMDGPU::V_SUBREV_I32_e64) && // FIXME
- OpToFold->isImm()) {
+ (OpToFold->isImm() || OpToFold->isFI())) {
MachineRegisterInfo &MRI = MI->getParent()->getParent()->getRegInfo();
// Verify the other operand is a VGPR, otherwise we would violate the
// constant bus restriction.
unsigned OtherIdx = CommuteOpNo == CommuteIdx0 ? CommuteIdx1 : CommuteIdx0;
MachineOperand &OtherOp = MI->getOperand(OtherIdx);
if (!OtherOp.isReg() ||
!TII->getRegisterInfo().isVGPR(MRI, OtherOp.getReg()))
return false;
assert(MI->getOperand(1).isDef());
- int Op32 = AMDGPU::getVOPe32(Opc);
+ // Make sure to get the 32-bit version of the commuted opcode.
+ unsigned MaybeCommutedOpc = MI->getOpcode();
+ int Op32 = AMDGPU::getVOPe32(MaybeCommutedOpc);
+
FoldList.push_back(FoldCandidate(MI, CommuteOpNo, OpToFold, true,
Op32));
return true;
}
TII->commuteInstruction(*MI, false, CommuteIdx0, CommuteIdx1);
return false;
}
FoldList.push_back(FoldCandidate(MI, CommuteOpNo, OpToFold, true));
return true;
}
FoldList.push_back(FoldCandidate(MI, OpNo, OpToFold));
return true;
}
// If the use operand doesn't care about the value, this may be an operand only
// used for register indexing, in which case it is unsafe to fold.
static bool isUseSafeToFold(const SIInstrInfo *TII,
const MachineInstr &MI,
const MachineOperand &UseMO) {
return !UseMO.isUndef() && !TII->isSDWA(MI);
//return !MI.hasRegisterImplicitUseOperand(UseMO.getReg());
}
void SIFoldOperands::foldOperand(
MachineOperand &OpToFold,
MachineInstr *UseMI,
unsigned UseOpIdx,
SmallVectorImpl<FoldCandidate> &FoldList,
SmallVectorImpl<MachineInstr *> &CopiesToReplace) const {
const MachineOperand &UseOp = UseMI->getOperand(UseOpIdx);
if (!isUseSafeToFold(TII, *UseMI, UseOp))
return;
// FIXME: Fold operands with subregs.
if (UseOp.isReg() && OpToFold.isReg()) {
if (UseOp.isImplicit() || UseOp.getSubReg() != AMDGPU::NoSubRegister)
return;
// Don't fold subregister extracts into tied operands, only if it is a full
// copy since a subregister use tied to a full register def doesn't really
// make sense. e.g. don't fold:
//
// %1 = COPY %0:sub1
// %2<tied3> = V_MAC_{F16, F32} %3, %4, %1<tied0>
//
// into
// %2<tied3> = V_MAC_{F16, F32} %3, %4, %0:sub1<tied0>
if (UseOp.isTied() && OpToFold.getSubReg() != AMDGPU::NoSubRegister)
return;
}
// Special case for REG_SEQUENCE: We can't fold literals into
// REG_SEQUENCE instructions, so we have to fold them into the
// uses of REG_SEQUENCE.
if (UseMI->isRegSequence()) {
unsigned RegSeqDstReg = UseMI->getOperand(0).getReg();
unsigned RegSeqDstSubReg = UseMI->getOperand(UseOpIdx + 1).getImm();
for (MachineRegisterInfo::use_iterator
RSUse = MRI->use_begin(RegSeqDstReg), RSE = MRI->use_end();
RSUse != RSE; ++RSUse) {
MachineInstr *RSUseMI = RSUse->getParent();
if (RSUse->getSubReg() != RegSeqDstSubReg)
continue;
foldOperand(OpToFold, RSUseMI, RSUse.getOperandNo(), FoldList,
CopiesToReplace);
}
return;
}
bool FoldingImm = OpToFold.isImm();
if (FoldingImm && UseMI->isCopy()) {
unsigned DestReg = UseMI->getOperand(0).getReg();
const TargetRegisterClass *DestRC
= TargetRegisterInfo::isVirtualRegister(DestReg) ?
MRI->getRegClass(DestReg) :
TRI->getPhysRegClass(DestReg);
unsigned SrcReg = UseMI->getOperand(1).getReg();
if (TargetRegisterInfo::isVirtualRegister(DestReg) &&
TargetRegisterInfo::isVirtualRegister(SrcReg)) {
const TargetRegisterClass * SrcRC = MRI->getRegClass(SrcReg);
if (TRI->isSGPRClass(SrcRC) && TRI->hasVGPRs(DestRC)) {
MachineRegisterInfo::use_iterator NextUse;
SmallVector<FoldCandidate, 4> CopyUses;
for (MachineRegisterInfo::use_iterator
Use = MRI->use_begin(DestReg), E = MRI->use_end();
Use != E; Use = NextUse) {
NextUse = std::next(Use);
FoldCandidate FC = FoldCandidate(Use->getParent(),
Use.getOperandNo(), &UseMI->getOperand(1));
CopyUses.push_back(FC);
}
for (auto & F : CopyUses) {
foldOperand(*F.OpToFold, F.UseMI, F.UseOpNo,
FoldList, CopiesToReplace);
}
}
}
// In order to fold immediates into copies, we need to change the
// copy to a MOV.
unsigned MovOp = TII->getMovOpcode(DestRC);
if (MovOp == AMDGPU::COPY)
return;
UseMI->setDesc(TII->get(MovOp));
CopiesToReplace.push_back(UseMI);
} else {
if (UseMI->isCopy() && OpToFold.isReg() &&
TargetRegisterInfo::isVirtualRegister(UseMI->getOperand(0).getReg()) &&
TargetRegisterInfo::isVirtualRegister(UseMI->getOperand(1).getReg()) &&
TRI->isVGPR(*MRI, UseMI->getOperand(0).getReg()) &&
TRI->isVGPR(*MRI, UseMI->getOperand(1).getReg()) &&
!UseMI->getOperand(1).getSubReg()) {
UseMI->getOperand(1).setReg(OpToFold.getReg());
UseMI->getOperand(1).setSubReg(OpToFold.getSubReg());
UseMI->getOperand(1).setIsKill(false);
CopiesToReplace.push_back(UseMI);
OpToFold.setIsKill(false);
return;
}
const MCInstrDesc &UseDesc = UseMI->getDesc();
// Don't fold into target independent nodes. Target independent opcodes
// don't have defined register classes.
if (UseDesc.isVariadic() ||
UseOp.isImplicit() ||
UseDesc.OpInfo[UseOpIdx].RegClass == -1)
return;
}
if (!FoldingImm) {
tryAddToFoldList(FoldList, UseMI, UseOpIdx, &OpToFold, TII);
// FIXME: We could try to change the instruction from 64-bit to 32-bit
// to enable more folding opportunites. The shrink operands pass
// already does this.
return;
}
const MCInstrDesc &FoldDesc = OpToFold.getParent()->getDesc();
const TargetRegisterClass *FoldRC =
TRI->getRegClass(FoldDesc.OpInfo[0].RegClass);
// Split 64-bit constants into 32-bits for folding.
if (UseOp.getSubReg() && AMDGPU::getRegBitWidth(FoldRC->getID()) == 64) {
unsigned UseReg = UseOp.getReg();
const TargetRegisterClass *UseRC
= TargetRegisterInfo::isVirtualRegister(UseReg) ?
MRI->getRegClass(UseReg) :
TRI->getPhysRegClass(UseReg);
if (AMDGPU::getRegBitWidth(UseRC->getID()) != 64)
return;
APInt Imm(64, OpToFold.getImm());
if (UseOp.getSubReg() == AMDGPU::sub0) {
Imm = Imm.getLoBits(32);
} else {
assert(UseOp.getSubReg() == AMDGPU::sub1);
Imm = Imm.getHiBits(32);
}
MachineOperand ImmOp = MachineOperand::CreateImm(Imm.getSExtValue());
tryAddToFoldList(FoldList, UseMI, UseOpIdx, &ImmOp, TII);
return;
}
tryAddToFoldList(FoldList, UseMI, UseOpIdx, &OpToFold, TII);
}
static bool evalBinaryInstruction(unsigned Opcode, int32_t &Result,
uint32_t LHS, uint32_t RHS) {
switch (Opcode) {
case AMDGPU::V_AND_B32_e64:
case AMDGPU::V_AND_B32_e32:
case AMDGPU::S_AND_B32:
Result = LHS & RHS;
return true;
case AMDGPU::V_OR_B32_e64:
case AMDGPU::V_OR_B32_e32:
case AMDGPU::S_OR_B32:
Result = LHS | RHS;
return true;
case AMDGPU::V_XOR_B32_e64:
case AMDGPU::V_XOR_B32_e32:
case AMDGPU::S_XOR_B32:
Result = LHS ^ RHS;
return true;
case AMDGPU::V_LSHL_B32_e64:
case AMDGPU::V_LSHL_B32_e32:
case AMDGPU::S_LSHL_B32:
// The instruction ignores the high bits for out of bounds shifts.
Result = LHS << (RHS & 31);
return true;
case AMDGPU::V_LSHLREV_B32_e64:
case AMDGPU::V_LSHLREV_B32_e32:
Result = RHS << (LHS & 31);
return true;
case AMDGPU::V_LSHR_B32_e64:
case AMDGPU::V_LSHR_B32_e32:
case AMDGPU::S_LSHR_B32:
Result = LHS >> (RHS & 31);
return true;
case AMDGPU::V_LSHRREV_B32_e64:
case AMDGPU::V_LSHRREV_B32_e32:
Result = RHS >> (LHS & 31);
return true;
case AMDGPU::V_ASHR_I32_e64:
case AMDGPU::V_ASHR_I32_e32:
case AMDGPU::S_ASHR_I32:
Result = static_cast<int32_t>(LHS) >> (RHS & 31);
return true;
case AMDGPU::V_ASHRREV_I32_e64:
case AMDGPU::V_ASHRREV_I32_e32:
Result = static_cast<int32_t>(RHS) >> (LHS & 31);
return true;
default:
return false;
}
}
static unsigned getMovOpc(bool IsScalar) {
return IsScalar ? AMDGPU::S_MOV_B32 : AMDGPU::V_MOV_B32_e32;
}
/// Remove any leftover implicit operands from mutating the instruction. e.g.
/// if we replace an s_and_b32 with a copy, we don't need the implicit scc def
/// anymore.
static void stripExtraCopyOperands(MachineInstr &MI) {
const MCInstrDesc &Desc = MI.getDesc();
unsigned NumOps = Desc.getNumOperands() +
Desc.getNumImplicitUses() +
Desc.getNumImplicitDefs();
for (unsigned I = MI.getNumOperands() - 1; I >= NumOps; --I)
MI.RemoveOperand(I);
}
static void mutateCopyOp(MachineInstr &MI, const MCInstrDesc &NewDesc) {
MI.setDesc(NewDesc);
stripExtraCopyOperands(MI);
}
static MachineOperand *getImmOrMaterializedImm(MachineRegisterInfo &MRI,
MachineOperand &Op) {
if (Op.isReg()) {
// If this has a subregister, it obviously is a register source.
if (Op.getSubReg() != AMDGPU::NoSubRegister ||
!TargetRegisterInfo::isVirtualRegister(Op.getReg()))
return &Op;
MachineInstr *Def = MRI.getVRegDef(Op.getReg());
if (Def && Def->isMoveImmediate()) {
MachineOperand &ImmSrc = Def->getOperand(1);
if (ImmSrc.isImm())
return &ImmSrc;
}
}
return &Op;
}
// Try to simplify operations with a constant that may appear after instruction
// selection.
// TODO: See if a frame index with a fixed offset can fold.
static bool tryConstantFoldOp(MachineRegisterInfo &MRI,
const SIInstrInfo *TII,
MachineInstr *MI,
MachineOperand *ImmOp) {
unsigned Opc = MI->getOpcode();
if (Opc == AMDGPU::V_NOT_B32_e64 || Opc == AMDGPU::V_NOT_B32_e32 ||
Opc == AMDGPU::S_NOT_B32) {
MI->getOperand(1).ChangeToImmediate(~ImmOp->getImm());
mutateCopyOp(*MI, TII->get(getMovOpc(Opc == AMDGPU::S_NOT_B32)));
return true;
}
int Src1Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1);
if (Src1Idx == -1)
return false;
int Src0Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0);
MachineOperand *Src0 = getImmOrMaterializedImm(MRI, MI->getOperand(Src0Idx));
MachineOperand *Src1 = getImmOrMaterializedImm(MRI, MI->getOperand(Src1Idx));
if (!Src0->isImm() && !Src1->isImm())
return false;
if (MI->getOpcode() == AMDGPU::V_LSHL_OR_B32) {
if (Src0->isImm() && Src0->getImm() == 0) {
// v_lshl_or_b32 0, X, Y -> copy Y
// v_lshl_or_b32 0, X, K -> v_mov_b32 K
bool UseCopy = TII->getNamedOperand(*MI, AMDGPU::OpName::src2)->isReg();
MI->RemoveOperand(Src1Idx);
MI->RemoveOperand(Src0Idx);
MI->setDesc(TII->get(UseCopy ? AMDGPU::COPY : AMDGPU::V_MOV_B32_e32));
return true;
}
}
// and k0, k1 -> v_mov_b32 (k0 & k1)
// or k0, k1 -> v_mov_b32 (k0 | k1)
// xor k0, k1 -> v_mov_b32 (k0 ^ k1)
if (Src0->isImm() && Src1->isImm()) {
int32_t NewImm;
if (!evalBinaryInstruction(Opc, NewImm, Src0->getImm(), Src1->getImm()))
return false;
const SIRegisterInfo &TRI = TII->getRegisterInfo();
bool IsSGPR = TRI.isSGPRReg(MRI, MI->getOperand(0).getReg());
// Be careful to change the right operand, src0 may belong to a different
// instruction.
MI->getOperand(Src0Idx).ChangeToImmediate(NewImm);
MI->RemoveOperand(Src1Idx);
mutateCopyOp(*MI, TII->get(getMovOpc(IsSGPR)));
return true;
}
if (!MI->isCommutable())
return false;
if (Src0->isImm() && !Src1->isImm()) {
std::swap(Src0, Src1);
std::swap(Src0Idx, Src1Idx);
}
int32_t Src1Val = static_cast<int32_t>(Src1->getImm());
if (Opc == AMDGPU::V_OR_B32_e64 ||
Opc == AMDGPU::V_OR_B32_e32 ||
Opc == AMDGPU::S_OR_B32) {
if (Src1Val == 0) {
// y = or x, 0 => y = copy x
MI->RemoveOperand(Src1Idx);
mutateCopyOp(*MI, TII->get(AMDGPU::COPY));
} else if (Src1Val == -1) {
// y = or x, -1 => y = v_mov_b32 -1
MI->RemoveOperand(Src1Idx);
mutateCopyOp(*MI, TII->get(getMovOpc(Opc == AMDGPU::S_OR_B32)));
} else
return false;
return true;
}
if (MI->getOpcode() == AMDGPU::V_AND_B32_e64 ||
MI->getOpcode() == AMDGPU::V_AND_B32_e32 ||
MI->getOpcode() == AMDGPU::S_AND_B32) {
if (Src1Val == 0) {
// y = and x, 0 => y = v_mov_b32 0
MI->RemoveOperand(Src0Idx);
mutateCopyOp(*MI, TII->get(getMovOpc(Opc == AMDGPU::S_AND_B32)));
} else if (Src1Val == -1) {
// y = and x, -1 => y = copy x
MI->RemoveOperand(Src1Idx);
mutateCopyOp(*MI, TII->get(AMDGPU::COPY));
stripExtraCopyOperands(*MI);
} else
return false;
return true;
}
if (MI->getOpcode() == AMDGPU::V_XOR_B32_e64 ||
MI->getOpcode() == AMDGPU::V_XOR_B32_e32 ||
MI->getOpcode() == AMDGPU::S_XOR_B32) {
if (Src1Val == 0) {
// y = xor x, 0 => y = copy x
MI->RemoveOperand(Src1Idx);
mutateCopyOp(*MI, TII->get(AMDGPU::COPY));
return true;
}
}
return false;
}
// Try to fold an instruction into a simpler one
static bool tryFoldInst(const SIInstrInfo *TII,
MachineInstr *MI) {
unsigned Opc = MI->getOpcode();
if (Opc == AMDGPU::V_CNDMASK_B32_e32 ||
Opc == AMDGPU::V_CNDMASK_B32_e64 ||
Opc == AMDGPU::V_CNDMASK_B64_PSEUDO) {
const MachineOperand *Src0 = TII->getNamedOperand(*MI, AMDGPU::OpName::src0);
const MachineOperand *Src1 = TII->getNamedOperand(*MI, AMDGPU::OpName::src1);
if (Src1->isIdenticalTo(*Src0)) {
LLVM_DEBUG(dbgs() << "Folded " << *MI << " into ");
int Src2Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
if (Src2Idx != -1)
MI->RemoveOperand(Src2Idx);
MI->RemoveOperand(AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1));
mutateCopyOp(*MI, TII->get(Src0->isReg() ? (unsigned)AMDGPU::COPY
: getMovOpc(false)));
LLVM_DEBUG(dbgs() << *MI << '\n');
return true;
}
}
return false;
}
void SIFoldOperands::foldInstOperand(MachineInstr &MI,
MachineOperand &OpToFold) const {
// We need mutate the operands of new mov instructions to add implicit
// uses of EXEC, but adding them invalidates the use_iterator, so defer
// this.
SmallVector<MachineInstr *, 4> CopiesToReplace;
SmallVector<FoldCandidate, 4> FoldList;
MachineOperand &Dst = MI.getOperand(0);
bool FoldingImm = OpToFold.isImm() || OpToFold.isFI();
if (FoldingImm) {
unsigned NumLiteralUses = 0;
MachineOperand *NonInlineUse = nullptr;
int NonInlineUseOpNo = -1;
MachineRegisterInfo::use_iterator NextUse;
for (MachineRegisterInfo::use_iterator
Use = MRI->use_begin(Dst.getReg()), E = MRI->use_end();
Use != E; Use = NextUse) {
NextUse = std::next(Use);
MachineInstr *UseMI = Use->getParent();
unsigned OpNo = Use.getOperandNo();
// Folding the immediate may reveal operations that can be constant
// folded or replaced with a copy. This can happen for example after
// frame indices are lowered to constants or from splitting 64-bit
// constants.
//
// We may also encounter cases where one or both operands are
// immediates materialized into a register, which would ordinarily not
// be folded due to multiple uses or operand constraints.
if (OpToFold.isImm() && tryConstantFoldOp(*MRI, TII, UseMI, &OpToFold)) {
LLVM_DEBUG(dbgs() << "Constant folded " << *UseMI << '\n');
// Some constant folding cases change the same immediate's use to a new
// instruction, e.g. and x, 0 -> 0. Make sure we re-visit the user
// again. The same constant folded instruction could also have a second
// use operand.
NextUse = MRI->use_begin(Dst.getReg());
FoldList.clear();
continue;
}
// Try to fold any inline immediate uses, and then only fold other
// constants if they have one use.
//
// The legality of the inline immediate must be checked based on the use
// operand, not the defining instruction, because 32-bit instructions
// with 32-bit inline immediate sources may be used to materialize
// constants used in 16-bit operands.
//
// e.g. it is unsafe to fold:
// s_mov_b32 s0, 1.0 // materializes 0x3f800000
// v_add_f16 v0, v1, s0 // 1.0 f16 inline immediate sees 0x00003c00
// Folding immediates with more than one use will increase program size.
// FIXME: This will also reduce register usage, which may be better
// in some cases. A better heuristic is needed.
if (isInlineConstantIfFolded(TII, *UseMI, OpNo, OpToFold)) {
foldOperand(OpToFold, UseMI, OpNo, FoldList, CopiesToReplace);
} else {
if (++NumLiteralUses == 1) {
NonInlineUse = &*Use;
NonInlineUseOpNo = OpNo;
}
}
}
if (NumLiteralUses == 1) {
MachineInstr *UseMI = NonInlineUse->getParent();
foldOperand(OpToFold, UseMI, NonInlineUseOpNo, FoldList, CopiesToReplace);
}
} else {
// Folding register.
SmallVector <MachineRegisterInfo::use_iterator, 4> UsesToProcess;
for (MachineRegisterInfo::use_iterator
Use = MRI->use_begin(Dst.getReg()), E = MRI->use_end();
Use != E; ++Use) {
UsesToProcess.push_back(Use);
}
for (auto U : UsesToProcess) {
MachineInstr *UseMI = U->getParent();
foldOperand(OpToFold, UseMI, U.getOperandNo(),
FoldList, CopiesToReplace);
}
}
MachineFunction *MF = MI.getParent()->getParent();
// Make sure we add EXEC uses to any new v_mov instructions created.
for (MachineInstr *Copy : CopiesToReplace)
Copy->addImplicitDefUseOperands(*MF);
for (FoldCandidate &Fold : FoldList) {
if (updateOperand(Fold, *TII, *TRI)) {
// Clear kill flags.
if (Fold.isReg()) {
assert(Fold.OpToFold && Fold.OpToFold->isReg());
// FIXME: Probably shouldn't bother trying to fold if not an
// SGPR. PeepholeOptimizer can eliminate redundant VGPR->VGPR
// copies.
MRI->clearKillFlags(Fold.OpToFold->getReg());
}
LLVM_DEBUG(dbgs() << "Folded source from " << MI << " into OpNo "
<< static_cast<int>(Fold.UseOpNo) << " of "
<< *Fold.UseMI << '\n');
tryFoldInst(TII, Fold.UseMI);
} else if (Fold.isCommuted()) {
// Restoring instruction's original operand order if fold has failed.
TII->commuteInstruction(*Fold.UseMI, false);
}
}
}
// Clamp patterns are canonically selected to v_max_* instructions, so only
// handle them.
const MachineOperand *SIFoldOperands::isClamp(const MachineInstr &MI) const {
unsigned Op = MI.getOpcode();
switch (Op) {
case AMDGPU::V_MAX_F32_e64:
case AMDGPU::V_MAX_F16_e64:
case AMDGPU::V_MAX_F64:
case AMDGPU::V_PK_MAX_F16: {
if (!TII->getNamedOperand(MI, AMDGPU::OpName::clamp)->getImm())
return nullptr;
// Make sure sources are identical.
const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
if (!Src0->isReg() || !Src1->isReg() ||
Src0->getReg() != Src1->getReg() ||
Src0->getSubReg() != Src1->getSubReg() ||
Src0->getSubReg() != AMDGPU::NoSubRegister)
return nullptr;
// Can't fold up if we have modifiers.
if (TII->hasModifiersSet(MI, AMDGPU::OpName::omod))
return nullptr;
unsigned Src0Mods
= TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers)->getImm();
unsigned Src1Mods
= TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers)->getImm();
// Having a 0 op_sel_hi would require swizzling the output in the source
// instruction, which we can't do.
unsigned UnsetMods = (Op == AMDGPU::V_PK_MAX_F16) ? SISrcMods::OP_SEL_1 : 0;
if (Src0Mods != UnsetMods && Src1Mods != UnsetMods)
return nullptr;
return Src0;
}
default:
return nullptr;
}
}
// We obviously have multiple uses in a clamp since the register is used twice
// in the same instruction.
static bool hasOneNonDBGUseInst(const MachineRegisterInfo &MRI, unsigned Reg) {
int Count = 0;
for (auto I = MRI.use_instr_nodbg_begin(Reg), E = MRI.use_instr_nodbg_end();
I != E; ++I) {
if (++Count > 1)
return false;
}
return true;
}
// FIXME: Clamp for v_mad_mixhi_f16 handled during isel.
bool SIFoldOperands::tryFoldClamp(MachineInstr &MI) {
const MachineOperand *ClampSrc = isClamp(MI);
if (!ClampSrc || !hasOneNonDBGUseInst(*MRI, ClampSrc->getReg()))
return false;
MachineInstr *Def = MRI->getVRegDef(ClampSrc->getReg());
// The type of clamp must be compatible.
if (TII->getClampMask(*Def) != TII->getClampMask(MI))
return false;
MachineOperand *DefClamp = TII->getNamedOperand(*Def, AMDGPU::OpName::clamp);
if (!DefClamp)
return false;
LLVM_DEBUG(dbgs() << "Folding clamp " << *DefClamp << " into " << *Def
<< '\n');
// Clamp is applied after omod, so it is OK if omod is set.
DefClamp->setImm(1);
MRI->replaceRegWith(MI.getOperand(0).getReg(), Def->getOperand(0).getReg());
MI.eraseFromParent();
return true;
}
static int getOModValue(unsigned Opc, int64_t Val) {
switch (Opc) {
case AMDGPU::V_MUL_F32_e64: {
switch (static_cast<uint32_t>(Val)) {
case 0x3f000000: // 0.5
return SIOutMods::DIV2;
case 0x40000000: // 2.0
return SIOutMods::MUL2;
case 0x40800000: // 4.0
return SIOutMods::MUL4;
default:
return SIOutMods::NONE;
}
}
case AMDGPU::V_MUL_F16_e64: {
switch (static_cast<uint16_t>(Val)) {
case 0x3800: // 0.5
return SIOutMods::DIV2;
case 0x4000: // 2.0
return SIOutMods::MUL2;
case 0x4400: // 4.0
return SIOutMods::MUL4;
default:
return SIOutMods::NONE;
}
}
default:
llvm_unreachable("invalid mul opcode");
}
}
// FIXME: Does this really not support denormals with f16?
// FIXME: Does this need to check IEEE mode bit? SNaNs are generally not
// handled, so will anything other than that break?
std::pair<const MachineOperand *, int>
SIFoldOperands::isOMod(const MachineInstr &MI) const {
unsigned Op = MI.getOpcode();
switch (Op) {
case AMDGPU::V_MUL_F32_e64:
case AMDGPU::V_MUL_F16_e64: {
// If output denormals are enabled, omod is ignored.
if ((Op == AMDGPU::V_MUL_F32_e64 && ST->hasFP32Denormals()) ||
(Op == AMDGPU::V_MUL_F16_e64 && ST->hasFP16Denormals()))
return std::make_pair(nullptr, SIOutMods::NONE);
const MachineOperand *RegOp = nullptr;
const MachineOperand *ImmOp = nullptr;
const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
if (Src0->isImm()) {
ImmOp = Src0;
RegOp = Src1;
} else if (Src1->isImm()) {
ImmOp = Src1;
RegOp = Src0;
} else
return std::make_pair(nullptr, SIOutMods::NONE);
int OMod = getOModValue(Op, ImmOp->getImm());
if (OMod == SIOutMods::NONE ||
TII->hasModifiersSet(MI, AMDGPU::OpName::src0_modifiers) ||
TII->hasModifiersSet(MI, AMDGPU::OpName::src1_modifiers) ||
TII->hasModifiersSet(MI, AMDGPU::OpName::omod) ||
TII->hasModifiersSet(MI, AMDGPU::OpName::clamp))
return std::make_pair(nullptr, SIOutMods::NONE);
return std::make_pair(RegOp, OMod);
}
case AMDGPU::V_ADD_F32_e64:
case AMDGPU::V_ADD_F16_e64: {
// If output denormals are enabled, omod is ignored.
if ((Op == AMDGPU::V_ADD_F32_e64 && ST->hasFP32Denormals()) ||
(Op == AMDGPU::V_ADD_F16_e64 && ST->hasFP16Denormals()))
return std::make_pair(nullptr, SIOutMods::NONE);
// Look through the DAGCombiner canonicalization fmul x, 2 -> fadd x, x
const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
if (Src0->isReg() && Src1->isReg() && Src0->getReg() == Src1->getReg() &&
Src0->getSubReg() == Src1->getSubReg() &&
!TII->hasModifiersSet(MI, AMDGPU::OpName::src0_modifiers) &&
!TII->hasModifiersSet(MI, AMDGPU::OpName::src1_modifiers) &&
!TII->hasModifiersSet(MI, AMDGPU::OpName::clamp) &&
!TII->hasModifiersSet(MI, AMDGPU::OpName::omod))
return std::make_pair(Src0, SIOutMods::MUL2);
return std::make_pair(nullptr, SIOutMods::NONE);
}
default:
return std::make_pair(nullptr, SIOutMods::NONE);
}
}
// FIXME: Does this need to check IEEE bit on function?
bool SIFoldOperands::tryFoldOMod(MachineInstr &MI) {
const MachineOperand *RegOp;
int OMod;
std::tie(RegOp, OMod) = isOMod(MI);
if (OMod == SIOutMods::NONE || !RegOp->isReg() ||
RegOp->getSubReg() != AMDGPU::NoSubRegister ||
!hasOneNonDBGUseInst(*MRI, RegOp->getReg()))
return false;
MachineInstr *Def = MRI->getVRegDef(RegOp->getReg());
MachineOperand *DefOMod = TII->getNamedOperand(*Def, AMDGPU::OpName::omod);
if (!DefOMod || DefOMod->getImm() != SIOutMods::NONE)
return false;
// Clamp is applied after omod. If the source already has clamp set, don't
// fold it.
if (TII->hasModifiersSet(*Def, AMDGPU::OpName::clamp))
return false;
LLVM_DEBUG(dbgs() << "Folding omod " << MI << " into " << *Def << '\n');
DefOMod->setImm(OMod);
MRI->replaceRegWith(MI.getOperand(0).getReg(), Def->getOperand(0).getReg());
MI.eraseFromParent();
return true;
}
bool SIFoldOperands::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(MF.getFunction()))
return false;
MRI = &MF.getRegInfo();
ST = &MF.getSubtarget<GCNSubtarget>();
TII = ST->getInstrInfo();
TRI = &TII->getRegisterInfo();
const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
// omod is ignored by hardware if IEEE bit is enabled. omod also does not
// correctly handle signed zeros.
//
bool IsIEEEMode = ST->enableIEEEBit(MF);
bool HasNSZ = MFI->hasNoSignedZerosFPMath();
for (MachineBasicBlock *MBB : depth_first(&MF)) {
MachineBasicBlock::iterator I, Next;
for (I = MBB->begin(); I != MBB->end(); I = Next) {
Next = std::next(I);
MachineInstr &MI = *I;
tryFoldInst(TII, &MI);
if (!TII->isFoldableCopy(MI)) {
// TODO: Omod might be OK if there is NSZ only on the source
// instruction, and not the omod multiply.
if (IsIEEEMode || (!HasNSZ && !MI.getFlag(MachineInstr::FmNsz)) ||
!tryFoldOMod(MI))
tryFoldClamp(MI);
continue;
}
MachineOperand &OpToFold = MI.getOperand(1);
bool FoldingImm = OpToFold.isImm() || OpToFold.isFI();
// FIXME: We could also be folding things like TargetIndexes.
if (!FoldingImm && !OpToFold.isReg())
continue;
if (OpToFold.isReg() &&
!TargetRegisterInfo::isVirtualRegister(OpToFold.getReg()))
continue;
// Prevent folding operands backwards in the function. For example,
// the COPY opcode must not be replaced by 1 in this example:
//
// %3 = COPY %vgpr0; VGPR_32:%3
// ...
// %vgpr0 = V_MOV_B32_e32 1, implicit %exec
MachineOperand &Dst = MI.getOperand(0);
if (Dst.isReg() &&
!TargetRegisterInfo::isVirtualRegister(Dst.getReg()))
continue;
foldInstOperand(MI, OpToFold);
}
}
return false;
}
Index: stable/11/contrib/llvm/lib/Target/AMDGPU/VOP2Instructions.td
===================================================================
--- stable/11/contrib/llvm/lib/Target/AMDGPU/VOP2Instructions.td (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/AMDGPU/VOP2Instructions.td (revision 350259)
@@ -1,1065 +1,1059 @@
//===-- VOP2Instructions.td - Vector Instruction Defintions ---------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// VOP2 Classes
//===----------------------------------------------------------------------===//
class VOP2e <bits<6> op, VOPProfile P> : Enc32 {
bits<8> vdst;
bits<9> src0;
bits<8> src1;
let Inst{8-0} = !if(P.HasSrc0, src0, 0);
let Inst{16-9} = !if(P.HasSrc1, src1, 0);
let Inst{24-17} = !if(P.EmitDst, vdst, 0);
let Inst{30-25} = op;
let Inst{31} = 0x0; //encoding
}
class VOP2_MADKe <bits<6> op, VOPProfile P> : Enc64 {
bits<8> vdst;
bits<9> src0;
bits<8> src1;
bits<32> imm;
let Inst{8-0} = !if(P.HasSrc0, src0, 0);
let Inst{16-9} = !if(P.HasSrc1, src1, 0);
let Inst{24-17} = !if(P.EmitDst, vdst, 0);
let Inst{30-25} = op;
let Inst{31} = 0x0; // encoding
let Inst{63-32} = imm;
}
class VOP2_SDWAe <bits<6> op, VOPProfile P> : VOP_SDWAe <P> {
bits<8> vdst;
bits<8> src1;
let Inst{8-0} = 0xf9; // sdwa
let Inst{16-9} = !if(P.HasSrc1, src1{7-0}, 0);
let Inst{24-17} = !if(P.EmitDst, vdst{7-0}, 0);
let Inst{30-25} = op;
let Inst{31} = 0x0; // encoding
}
class VOP2_SDWA9Ae <bits<6> op, VOPProfile P> : VOP_SDWA9Ae <P> {
bits<8> vdst;
bits<9> src1;
let Inst{8-0} = 0xf9; // sdwa
let Inst{16-9} = !if(P.HasSrc1, src1{7-0}, 0);
let Inst{24-17} = !if(P.EmitDst, vdst{7-0}, 0);
let Inst{30-25} = op;
let Inst{31} = 0x0; // encoding
let Inst{63} = !if(P.HasSrc1, src1{8}, 0); // src1_sgpr
}
class VOP2_Pseudo <string opName, VOPProfile P, list<dag> pattern=[], string suffix = "_e32"> :
VOP_Pseudo <opName, suffix, P, P.Outs32, P.Ins32, "", pattern> {
let AsmOperands = P.Asm32;
let Size = 4;
let mayLoad = 0;
let mayStore = 0;
let hasSideEffects = 0;
let SubtargetPredicate = isGCN;
let VOP2 = 1;
let VALU = 1;
let Uses = [EXEC];
let AsmVariantName = AMDGPUAsmVariants.Default;
}
class VOP2_Real <VOP2_Pseudo ps, int EncodingFamily> :
InstSI <ps.OutOperandList, ps.InOperandList, ps.Mnemonic # ps.AsmOperands, []>,
SIMCInstr <ps.PseudoInstr, EncodingFamily> {
let isPseudo = 0;
let isCodeGenOnly = 0;
let Constraints = ps.Constraints;
let DisableEncoding = ps.DisableEncoding;
// copy relevant pseudo op flags
let SubtargetPredicate = ps.SubtargetPredicate;
let AsmMatchConverter = ps.AsmMatchConverter;
let AsmVariantName = ps.AsmVariantName;
let Constraints = ps.Constraints;
let DisableEncoding = ps.DisableEncoding;
let TSFlags = ps.TSFlags;
let UseNamedOperandTable = ps.UseNamedOperandTable;
let Uses = ps.Uses;
let Defs = ps.Defs;
}
class VOP2_SDWA_Pseudo <string OpName, VOPProfile P, list<dag> pattern=[]> :
VOP_SDWA_Pseudo <OpName, P, pattern> {
let AsmMatchConverter = "cvtSdwaVOP2";
}
class VOP2_DPP_Pseudo <string OpName, VOPProfile P, list<dag> pattern=[]> :
VOP_DPP_Pseudo <OpName, P, pattern> {
}
class getVOP2Pat64 <SDPatternOperator node, VOPProfile P> : LetDummies {
list<dag> ret = !if(P.HasModifiers,
[(set P.DstVT:$vdst,
(node (P.Src0VT
!if(P.HasOMod,
(VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers, i1:$clamp, i32:$omod),
(VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers, i1:$clamp))),
(P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers))))],
[(set P.DstVT:$vdst, (node P.Src0VT:$src0, P.Src1VT:$src1))]);
}
multiclass VOP2Inst_e32<string opName,
VOPProfile P,
SDPatternOperator node = null_frag,
string revOp = opName,
bit GFX9Renamed = 0> {
let renamedInGFX9 = GFX9Renamed in {
def _e32 : VOP2_Pseudo <opName, P, VOPPatOrNull<node,P>.ret>,
Commutable_REV<revOp#"_e32", !eq(revOp, opName)>;
} // End renamedInGFX9 = GFX9Renamed
}
multiclass VOP2Inst_e64<string opName,
VOPProfile P,
SDPatternOperator node = null_frag,
string revOp = opName,
bit GFX9Renamed = 0> {
let renamedInGFX9 = GFX9Renamed in {
def _e64 : VOP3_Pseudo <opName, P, getVOP2Pat64<node, P>.ret>,
Commutable_REV<revOp#"_e64", !eq(revOp, opName)>;
} // End renamedInGFX9 = GFX9Renamed
}
multiclass VOP2Inst_sdwa<string opName,
VOPProfile P,
SDPatternOperator node = null_frag,
string revOp = opName,
bit GFX9Renamed = 0> {
let renamedInGFX9 = GFX9Renamed in {
def _sdwa : VOP2_SDWA_Pseudo <opName, P>;
} // End renamedInGFX9 = GFX9Renamed
}
multiclass VOP2Inst<string opName,
VOPProfile P,
SDPatternOperator node = null_frag,
string revOp = opName,
bit GFX9Renamed = 0> :
VOP2Inst_e32<opName, P, node, revOp, GFX9Renamed>,
VOP2Inst_e64<opName, P, node, revOp, GFX9Renamed>,
VOP2Inst_sdwa<opName, P, node, revOp, GFX9Renamed> {
let renamedInGFX9 = GFX9Renamed in {
foreach _ = BoolToList<P.HasExtDPP>.ret in
def _dpp : VOP2_DPP_Pseudo <opName, P>;
}
}
multiclass VOP2bInst <string opName,
VOPProfile P,
SDPatternOperator node = null_frag,
string revOp = opName,
bit GFX9Renamed = 0,
bit useSGPRInput = !eq(P.NumSrcArgs, 3)> {
let renamedInGFX9 = GFX9Renamed in {
let SchedRW = [Write32Bit, WriteSALU] in {
let Uses = !if(useSGPRInput, [VCC, EXEC], [EXEC]), Defs = [VCC] in {
def _e32 : VOP2_Pseudo <opName, P, VOPPatOrNull<node,P>.ret>,
Commutable_REV<revOp#"_e32", !eq(revOp, opName)>;
def _sdwa : VOP2_SDWA_Pseudo <opName, P> {
let AsmMatchConverter = "cvtSdwaVOP2b";
}
foreach _ = BoolToList<P.HasExtDPP>.ret in
def _dpp : VOP2_DPP_Pseudo <opName, P>;
}
def _e64 : VOP3_Pseudo <opName, P, getVOP2Pat64<node, P>.ret>,
Commutable_REV<revOp#"_e64", !eq(revOp, opName)>;
}
}
}
multiclass VOP2eInst <string opName,
VOPProfile P,
SDPatternOperator node = null_frag,
string revOp = opName,
bit useSGPRInput = !eq(P.NumSrcArgs, 3)> {
let SchedRW = [Write32Bit] in {
let Uses = !if(useSGPRInput, [VCC, EXEC], [EXEC]) in {
def _e32 : VOP2_Pseudo <opName, P>,
Commutable_REV<revOp#"_e32", !eq(revOp, opName)>;
def _sdwa : VOP2_SDWA_Pseudo <opName, P> {
let AsmMatchConverter = "cvtSdwaVOP2b";
}
foreach _ = BoolToList<P.HasExtDPP>.ret in
def _dpp : VOP2_DPP_Pseudo <opName, P>;
}
def _e64 : VOP3_Pseudo <opName, P, getVOP2Pat64<node, P>.ret>,
Commutable_REV<revOp#"_e64", !eq(revOp, opName)>;
}
}
class VOP_MADAK <ValueType vt> : VOPProfile <[vt, vt, vt, vt]> {
field Operand ImmOpType = !if(!eq(vt.Size, 32), f32kimm, f16kimm);
field dag Ins32 = (ins VCSrc_f32:$src0, VGPR_32:$src1, ImmOpType:$imm);
field bit HasExt = 0;
// Hack to stop printing _e64
let DstRC = RegisterOperand<VGPR_32>;
field string Asm32 = " $vdst, $src0, $src1, $imm";
}
def VOP_MADAK_F16 : VOP_MADAK <f16>;
def VOP_MADAK_F32 : VOP_MADAK <f32>;
class VOP_MADMK <ValueType vt> : VOPProfile <[vt, vt, vt, vt]> {
field Operand ImmOpType = !if(!eq(vt.Size, 32), f32kimm, f16kimm);
field dag Ins32 = (ins VCSrc_f32:$src0, ImmOpType:$imm, VGPR_32:$src1);
field bit HasExt = 0;
// Hack to stop printing _e64
let DstRC = RegisterOperand<VGPR_32>;
field string Asm32 = " $vdst, $src0, $imm, $src1";
}
def VOP_MADMK_F16 : VOP_MADMK <f16>;
def VOP_MADMK_F32 : VOP_MADMK <f32>;
// FIXME: Remove src2_modifiers. It isn't used, so is wasting memory
// and processing time but it makes it easier to convert to mad.
class VOP_MAC <ValueType vt> : VOPProfile <[vt, vt, vt, vt]> {
let Ins32 = (ins Src0RC32:$src0, Src1RC32:$src1, VGPR_32:$src2);
let Ins64 = getIns64<Src0RC64, Src1RC64, RegisterOperand<VGPR_32>, 3,
0, HasModifiers, HasOMod, Src0Mod, Src1Mod, Src2Mod>.ret;
let InsDPP = (ins Src0ModDPP:$src0_modifiers, Src0DPP:$src0,
Src1ModDPP:$src1_modifiers, Src1DPP:$src1,
VGPR_32:$src2, // stub argument
dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
bank_mask:$bank_mask, bound_ctrl:$bound_ctrl);
let InsSDWA = (ins Src0ModSDWA:$src0_modifiers, Src0SDWA:$src0,
Src1ModSDWA:$src1_modifiers, Src1SDWA:$src1,
VGPR_32:$src2, // stub argument
clampmod:$clamp, omod:$omod,
dst_sel:$dst_sel, dst_unused:$dst_unused,
src0_sel:$src0_sel, src1_sel:$src1_sel);
let Asm32 = getAsm32<1, 2, vt>.ret;
let Asm64 = getAsm64<1, 2, 0, HasModifiers, HasOMod, vt>.ret;
let AsmDPP = getAsmDPP<1, 2, HasModifiers, vt>.ret;
let AsmSDWA = getAsmSDWA<1, 2, vt>.ret;
let AsmSDWA9 = getAsmSDWA9<1, 1, 2, vt>.ret;
let HasSrc2 = 0;
let HasSrc2Mods = 0;
let HasExt = 1;
let HasExtDPP = 1;
let HasExtSDWA = 1;
let HasExtSDWA9 = 0;
}
def VOP_MAC_F16 : VOP_MAC <f16>;
def VOP_MAC_F32 : VOP_MAC <f32>;
// Write out to vcc or arbitrary SGPR.
def VOP2b_I32_I1_I32_I32 : VOPProfile<[i32, i32, i32, untyped]> {
let Asm32 = "$vdst, vcc, $src0, $src1";
let Asm64 = "$vdst, $sdst, $src0, $src1";
let AsmSDWA = "$vdst, vcc, $src0_modifiers, $src1_modifiers$clamp $dst_sel $dst_unused $src0_sel $src1_sel";
let AsmSDWA9 = "$vdst, vcc, $src0_modifiers, $src1_modifiers$clamp $dst_sel $dst_unused $src0_sel $src1_sel";
let AsmDPP = "$vdst, vcc, $src0, $src1 $dpp_ctrl$row_mask$bank_mask$bound_ctrl";
let Outs32 = (outs DstRC:$vdst);
let Outs64 = (outs DstRC:$vdst, SReg_64:$sdst);
}
// Write out to vcc or arbitrary SGPR and read in from vcc or
// arbitrary SGPR.
def VOP2b_I32_I1_I32_I32_I1 : VOPProfile<[i32, i32, i32, i1]> {
// We use VCSrc_b32 to exclude literal constants, even though the
// encoding normally allows them since the implicit VCC use means
// using one would always violate the constant bus
// restriction. SGPRs are still allowed because it should
// technically be possible to use VCC again as src0.
let Src0RC32 = VCSrc_b32;
let Asm32 = "$vdst, vcc, $src0, $src1, vcc";
let Asm64 = "$vdst, $sdst, $src0, $src1, $src2";
let AsmSDWA = "$vdst, vcc, $src0_modifiers, $src1_modifiers, vcc $clamp $dst_sel $dst_unused $src0_sel $src1_sel";
let AsmSDWA9 = "$vdst, vcc, $src0_modifiers, $src1_modifiers, vcc $clamp $dst_sel $dst_unused $src0_sel $src1_sel";
let AsmDPP = "$vdst, vcc, $src0, $src1, vcc $dpp_ctrl$row_mask$bank_mask$bound_ctrl";
let Outs32 = (outs DstRC:$vdst);
let Outs64 = (outs DstRC:$vdst, SReg_64:$sdst);
// Suppress src2 implied by type since the 32-bit encoding uses an
// implicit VCC use.
let Ins32 = (ins Src0RC32:$src0, Src1RC32:$src1);
let InsSDWA = (ins Src0ModSDWA:$src0_modifiers, Src0SDWA:$src0,
Src1ModSDWA:$src1_modifiers, Src1SDWA:$src1,
clampmod:$clamp,
dst_sel:$dst_sel, dst_unused:$dst_unused,
src0_sel:$src0_sel, src1_sel:$src1_sel);
let InsDPP = (ins DstRCDPP:$old,
Src0DPP:$src0,
Src1DPP:$src1,
dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
bank_mask:$bank_mask, bound_ctrl:$bound_ctrl);
let HasExt = 1;
let HasExtDPP = 1;
let HasExtSDWA = 1;
let HasExtSDWA9 = 1;
}
// Read in from vcc or arbitrary SGPR
def VOP2e_I32_I32_I32_I1 : VOPProfile<[i32, i32, i32, i1]> {
let Src0RC32 = VCSrc_b32; // See comment in def VOP2b_I32_I1_I32_I32_I1 above.
let Asm32 = "$vdst, $src0, $src1, vcc";
let Asm64 = "$vdst, $src0, $src1, $src2";
let AsmSDWA = "$vdst, $src0_modifiers, $src1_modifiers, vcc $clamp $dst_sel $dst_unused $src0_sel $src1_sel";
let AsmSDWA9 = "$vdst, $src0_modifiers, $src1_modifiers, vcc $clamp $dst_sel $dst_unused $src0_sel $src1_sel";
let AsmDPP = "$vdst, $src0, $src1, vcc $dpp_ctrl$row_mask$bank_mask$bound_ctrl";
let Outs32 = (outs DstRC:$vdst);
let Outs64 = (outs DstRC:$vdst);
// Suppress src2 implied by type since the 32-bit encoding uses an
// implicit VCC use.
let Ins32 = (ins Src0RC32:$src0, Src1RC32:$src1);
let InsSDWA = (ins Src0ModSDWA:$src0_modifiers, Src0SDWA:$src0,
Src1ModSDWA:$src1_modifiers, Src1SDWA:$src1,
clampmod:$clamp,
dst_sel:$dst_sel, dst_unused:$dst_unused,
src0_sel:$src0_sel, src1_sel:$src1_sel);
let InsDPP = (ins DstRCDPP:$old,
Src0DPP:$src0,
Src1DPP:$src1,
dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
bank_mask:$bank_mask, bound_ctrl:$bound_ctrl);
let HasExt = 1;
let HasExtDPP = 1;
let HasExtSDWA = 1;
let HasExtSDWA9 = 1;
}
def VOP_READLANE : VOPProfile<[i32, i32, i32]> {
let Outs32 = (outs SReg_32:$vdst);
let Outs64 = Outs32;
let Ins32 = (ins VGPR_32:$src0, SCSrc_b32:$src1);
let Ins64 = Ins32;
let Asm32 = " $vdst, $src0, $src1";
let Asm64 = Asm32;
let HasExt = 0;
let HasExtDPP = 0;
let HasExtSDWA = 0;
let HasExtSDWA9 = 0;
}
def VOP_WRITELANE : VOPProfile<[i32, i32, i32, i32]> {
let Outs32 = (outs VGPR_32:$vdst);
let Outs64 = Outs32;
let Ins32 = (ins SCSrc_b32:$src0, SCSrc_b32:$src1, VGPR_32:$vdst_in);
let Ins64 = Ins32;
let Asm32 = " $vdst, $src0, $src1";
let Asm64 = Asm32;
let HasSrc2 = 0;
let HasSrc2Mods = 0;
let HasExt = 0;
let HasExtDPP = 0;
let HasExtSDWA = 0;
let HasExtSDWA9 = 0;
}
//===----------------------------------------------------------------------===//
// VOP2 Instructions
//===----------------------------------------------------------------------===//
let SubtargetPredicate = isGCN, Predicates = [isGCN] in {
defm V_CNDMASK_B32 : VOP2eInst <"v_cndmask_b32", VOP2e_I32_I32_I32_I1>;
def V_MADMK_F32 : VOP2_Pseudo <"v_madmk_f32", VOP_MADMK_F32, []>;
let isCommutable = 1 in {
defm V_ADD_F32 : VOP2Inst <"v_add_f32", VOP_F32_F32_F32, fadd>;
defm V_SUB_F32 : VOP2Inst <"v_sub_f32", VOP_F32_F32_F32, fsub>;
defm V_SUBREV_F32 : VOP2Inst <"v_subrev_f32", VOP_F32_F32_F32, null_frag, "v_sub_f32">;
defm V_MUL_LEGACY_F32 : VOP2Inst <"v_mul_legacy_f32", VOP_F32_F32_F32, AMDGPUfmul_legacy>;
defm V_MUL_F32 : VOP2Inst <"v_mul_f32", VOP_F32_F32_F32, fmul>;
defm V_MUL_I32_I24 : VOP2Inst <"v_mul_i32_i24", VOP_PAT_GEN<VOP_I32_I32_I32, 2>, AMDGPUmul_i24>;
defm V_MUL_HI_I32_I24 : VOP2Inst <"v_mul_hi_i32_i24", VOP_PAT_GEN<VOP_I32_I32_I32, 2>, AMDGPUmulhi_i24>;
defm V_MUL_U32_U24 : VOP2Inst <"v_mul_u32_u24", VOP_PAT_GEN<VOP_I32_I32_I32, 2>, AMDGPUmul_u24>;
defm V_MUL_HI_U32_U24 : VOP2Inst <"v_mul_hi_u32_u24", VOP_PAT_GEN<VOP_I32_I32_I32, 2>, AMDGPUmulhi_u24>;
defm V_MIN_F32 : VOP2Inst <"v_min_f32", VOP_F32_F32_F32, fminnum_like>;
defm V_MAX_F32 : VOP2Inst <"v_max_f32", VOP_F32_F32_F32, fmaxnum_like>;
defm V_MIN_I32 : VOP2Inst <"v_min_i32", VOP_PAT_GEN<VOP_I32_I32_I32>, smin>;
defm V_MAX_I32 : VOP2Inst <"v_max_i32", VOP_PAT_GEN<VOP_I32_I32_I32>, smax>;
defm V_MIN_U32 : VOP2Inst <"v_min_u32", VOP_PAT_GEN<VOP_I32_I32_I32>, umin>;
defm V_MAX_U32 : VOP2Inst <"v_max_u32", VOP_PAT_GEN<VOP_I32_I32_I32>, umax>;
defm V_LSHRREV_B32 : VOP2Inst <"v_lshrrev_b32", VOP_I32_I32_I32, null_frag, "v_lshr_b32">;
defm V_ASHRREV_I32 : VOP2Inst <"v_ashrrev_i32", VOP_I32_I32_I32, null_frag, "v_ashr_i32">;
defm V_LSHLREV_B32 : VOP2Inst <"v_lshlrev_b32", VOP_I32_I32_I32, null_frag, "v_lshl_b32">;
defm V_AND_B32 : VOP2Inst <"v_and_b32", VOP_PAT_GEN<VOP_I32_I32_I32>, and>;
defm V_OR_B32 : VOP2Inst <"v_or_b32", VOP_PAT_GEN<VOP_I32_I32_I32>, or>;
defm V_XOR_B32 : VOP2Inst <"v_xor_b32", VOP_PAT_GEN<VOP_I32_I32_I32>, xor>;
let Constraints = "$vdst = $src2", DisableEncoding="$src2",
isConvertibleToThreeAddress = 1 in {
defm V_MAC_F32 : VOP2Inst <"v_mac_f32", VOP_MAC_F32>;
}
def V_MADAK_F32 : VOP2_Pseudo <"v_madak_f32", VOP_MADAK_F32, []>;
// No patterns so that the scalar instructions are always selected.
// The scalar versions will be replaced with vector when needed later.
// V_ADD_I32, V_SUB_I32, and V_SUBREV_I32 where renamed to *_U32 in VI,
// but the VI instructions behave the same as the SI versions.
defm V_ADD_I32 : VOP2bInst <"v_add_i32", VOP2b_I32_I1_I32_I32, null_frag, "v_add_i32", 1>;
defm V_SUB_I32 : VOP2bInst <"v_sub_i32", VOP2b_I32_I1_I32_I32, null_frag, "v_sub_i32", 1>;
defm V_SUBREV_I32 : VOP2bInst <"v_subrev_i32", VOP2b_I32_I1_I32_I32, null_frag, "v_sub_i32", 1>;
defm V_ADDC_U32 : VOP2bInst <"v_addc_u32", VOP2b_I32_I1_I32_I32_I1, null_frag, "v_addc_u32", 1>;
defm V_SUBB_U32 : VOP2bInst <"v_subb_u32", VOP2b_I32_I1_I32_I32_I1, null_frag, "v_subb_u32", 1>;
defm V_SUBBREV_U32 : VOP2bInst <"v_subbrev_u32", VOP2b_I32_I1_I32_I32_I1, null_frag, "v_subb_u32", 1>;
let SubtargetPredicate = HasAddNoCarryInsts in {
defm V_ADD_U32 : VOP2Inst <"v_add_u32", VOP_I32_I32_I32, null_frag, "v_add_u32", 1>;
defm V_SUB_U32 : VOP2Inst <"v_sub_u32", VOP_I32_I32_I32, null_frag, "v_sub_u32", 1>;
defm V_SUBREV_U32 : VOP2Inst <"v_subrev_u32", VOP_I32_I32_I32, null_frag, "v_sub_u32", 1>;
}
} // End isCommutable = 1
// These are special and do not read the exec mask.
let isConvergent = 1, Uses = []<Register> in {
def V_READLANE_B32 : VOP2_Pseudo<"v_readlane_b32", VOP_READLANE,
[(set i32:$vdst, (int_amdgcn_readlane i32:$src0, i32:$src1))]>;
let Constraints = "$vdst = $vdst_in", DisableEncoding="$vdst_in" in {
def V_WRITELANE_B32 : VOP2_Pseudo<"v_writelane_b32", VOP_WRITELANE,
[(set i32:$vdst, (int_amdgcn_writelane i32:$src0, i32:$src1, i32:$vdst_in))]>;
} // End $vdst = $vdst_in, DisableEncoding $vdst_in
} // End isConvergent = 1
defm V_BFM_B32 : VOP2Inst <"v_bfm_b32", VOP_NO_EXT<VOP_I32_I32_I32>>;
defm V_BCNT_U32_B32 : VOP2Inst <"v_bcnt_u32_b32", VOP_NO_EXT<VOP_I32_I32_I32>>;
defm V_MBCNT_LO_U32_B32 : VOP2Inst <"v_mbcnt_lo_u32_b32", VOP_NO_EXT<VOP_I32_I32_I32>, int_amdgcn_mbcnt_lo>;
defm V_MBCNT_HI_U32_B32 : VOP2Inst <"v_mbcnt_hi_u32_b32", VOP_NO_EXT<VOP_I32_I32_I32>, int_amdgcn_mbcnt_hi>;
defm V_LDEXP_F32 : VOP2Inst <"v_ldexp_f32", VOP_NO_EXT<VOP_F32_F32_I32>, AMDGPUldexp>;
defm V_CVT_PKACCUM_U8_F32 : VOP2Inst <"v_cvt_pkaccum_u8_f32", VOP_NO_EXT<VOP_I32_F32_I32>>; // TODO: set "Uses = dst"
defm V_CVT_PKNORM_I16_F32 : VOP2Inst <"v_cvt_pknorm_i16_f32", VOP_NO_EXT<VOP_V2I16_F32_F32>, AMDGPUpknorm_i16_f32>;
defm V_CVT_PKNORM_U16_F32 : VOP2Inst <"v_cvt_pknorm_u16_f32", VOP_NO_EXT<VOP_V2I16_F32_F32>, AMDGPUpknorm_u16_f32>;
defm V_CVT_PKRTZ_F16_F32 : VOP2Inst <"v_cvt_pkrtz_f16_f32", VOP_NO_EXT<VOP_V2F16_F32_F32>, AMDGPUpkrtz_f16_f32>;
defm V_CVT_PK_U16_U32 : VOP2Inst <"v_cvt_pk_u16_u32", VOP_NO_EXT<VOP_V2I16_I32_I32>, AMDGPUpk_u16_u32>;
defm V_CVT_PK_I16_I32 : VOP2Inst <"v_cvt_pk_i16_i32", VOP_NO_EXT<VOP_V2I16_I32_I32>, AMDGPUpk_i16_i32>;
} // End SubtargetPredicate = isGCN, Predicates = [isGCN]
def : GCNPat<
(AMDGPUadde i32:$src0, i32:$src1, i1:$src2),
(V_ADDC_U32_e64 $src0, $src1, $src2)
>;
def : GCNPat<
(AMDGPUsube i32:$src0, i32:$src1, i1:$src2),
(V_SUBB_U32_e64 $src0, $src1, $src2)
>;
// These instructions only exist on SI and CI
let SubtargetPredicate = isSICI, Predicates = [isSICI] in {
defm V_MIN_LEGACY_F32 : VOP2Inst <"v_min_legacy_f32", VOP_F32_F32_F32, AMDGPUfmin_legacy>;
defm V_MAX_LEGACY_F32 : VOP2Inst <"v_max_legacy_f32", VOP_F32_F32_F32, AMDGPUfmax_legacy>;
let isCommutable = 1 in {
defm V_MAC_LEGACY_F32 : VOP2Inst <"v_mac_legacy_f32", VOP_F32_F32_F32>;
defm V_LSHR_B32 : VOP2Inst <"v_lshr_b32", VOP_PAT_GEN<VOP_I32_I32_I32>, srl>;
defm V_ASHR_I32 : VOP2Inst <"v_ashr_i32", VOP_PAT_GEN<VOP_I32_I32_I32>, sra>;
defm V_LSHL_B32 : VOP2Inst <"v_lshl_b32", VOP_PAT_GEN<VOP_I32_I32_I32>, shl>;
} // End isCommutable = 1
} // End let SubtargetPredicate = SICI, Predicates = [isSICI]
class DivergentBinOp<SDPatternOperator Op, VOP_Pseudo Inst> :
GCNPat<
(getDivergentFrag<Op>.ret Inst.Pfl.Src0VT:$src0, Inst.Pfl.Src1VT:$src1),
!if(!cast<Commutable_REV>(Inst).IsOrig,
(Inst $src0, $src1),
(Inst $src1, $src0)
)
>;
let AddedComplexity = 1 in {
def : DivergentBinOp<srl, V_LSHRREV_B32_e64>;
def : DivergentBinOp<sra, V_ASHRREV_I32_e64>;
def : DivergentBinOp<shl, V_LSHLREV_B32_e64>;
}
let SubtargetPredicate = HasAddNoCarryInsts in {
- def : DivergentBinOp<add, V_ADD_U32_e32>;
- def : DivergentBinOp<sub, V_SUB_U32_e32>;
- def : DivergentBinOp<sub, V_SUBREV_U32_e32>;
+ def : DivergentBinOp<add, V_ADD_U32_e64>;
+ def : DivergentBinOp<sub, V_SUB_U32_e64>;
}
-
-def : DivergentBinOp<add, V_ADD_I32_e32>;
-
def : DivergentBinOp<add, V_ADD_I32_e64>;
-def : DivergentBinOp<sub, V_SUB_I32_e32>;
-
-def : DivergentBinOp<sub, V_SUBREV_I32_e32>;
+def : DivergentBinOp<sub, V_SUB_I32_e64>;
def : DivergentBinOp<srl, V_LSHRREV_B32_e32>;
def : DivergentBinOp<sra, V_ASHRREV_I32_e32>;
def : DivergentBinOp<shl, V_LSHLREV_B32_e32>;
def : DivergentBinOp<adde, V_ADDC_U32_e32>;
def : DivergentBinOp<sube, V_SUBB_U32_e32>;
class divergent_i64_BinOp <SDPatternOperator Op, Instruction Inst> :
GCNPat<
(getDivergentFrag<Op>.ret i64:$src0, i64:$src1),
(REG_SEQUENCE VReg_64,
(Inst
(i32 (EXTRACT_SUBREG $src0, sub0)),
(i32 (EXTRACT_SUBREG $src1, sub0))
), sub0,
(Inst
(i32 (EXTRACT_SUBREG $src0, sub1)),
(i32 (EXTRACT_SUBREG $src1, sub1))
), sub1
)
>;
def : divergent_i64_BinOp <and, V_AND_B32_e32>;
def : divergent_i64_BinOp <or, V_OR_B32_e32>;
def : divergent_i64_BinOp <xor, V_XOR_B32_e32>;
let SubtargetPredicate = Has16BitInsts in {
let FPDPRounding = 1 in {
def V_MADMK_F16 : VOP2_Pseudo <"v_madmk_f16", VOP_MADMK_F16, [], "">;
defm V_LDEXP_F16 : VOP2Inst <"v_ldexp_f16", VOP_F16_F16_I32, AMDGPUldexp>;
} // End FPDPRounding = 1
defm V_LSHLREV_B16 : VOP2Inst <"v_lshlrev_b16", VOP_I16_I16_I16>;
defm V_LSHRREV_B16 : VOP2Inst <"v_lshrrev_b16", VOP_I16_I16_I16>;
defm V_ASHRREV_I16 : VOP2Inst <"v_ashrrev_i16", VOP_I16_I16_I16>;
let isCommutable = 1 in {
let FPDPRounding = 1 in {
defm V_ADD_F16 : VOP2Inst <"v_add_f16", VOP_F16_F16_F16, fadd>;
defm V_SUB_F16 : VOP2Inst <"v_sub_f16", VOP_F16_F16_F16, fsub>;
defm V_SUBREV_F16 : VOP2Inst <"v_subrev_f16", VOP_F16_F16_F16, null_frag, "v_sub_f16">;
defm V_MUL_F16 : VOP2Inst <"v_mul_f16", VOP_F16_F16_F16, fmul>;
def V_MADAK_F16 : VOP2_Pseudo <"v_madak_f16", VOP_MADAK_F16, [], "">;
} // End FPDPRounding = 1
defm V_ADD_U16 : VOP2Inst <"v_add_u16", VOP_I16_I16_I16>;
defm V_SUB_U16 : VOP2Inst <"v_sub_u16" , VOP_I16_I16_I16>;
defm V_SUBREV_U16 : VOP2Inst <"v_subrev_u16", VOP_I16_I16_I16, null_frag, "v_sub_u16">;
defm V_MUL_LO_U16 : VOP2Inst <"v_mul_lo_u16", VOP_I16_I16_I16>;
defm V_MAX_F16 : VOP2Inst <"v_max_f16", VOP_F16_F16_F16, fmaxnum_like>;
defm V_MIN_F16 : VOP2Inst <"v_min_f16", VOP_F16_F16_F16, fminnum_like>;
defm V_MAX_U16 : VOP2Inst <"v_max_u16", VOP_I16_I16_I16>;
defm V_MAX_I16 : VOP2Inst <"v_max_i16", VOP_I16_I16_I16>;
defm V_MIN_U16 : VOP2Inst <"v_min_u16", VOP_I16_I16_I16>;
defm V_MIN_I16 : VOP2Inst <"v_min_i16", VOP_I16_I16_I16>;
let Constraints = "$vdst = $src2", DisableEncoding="$src2",
isConvertibleToThreeAddress = 1 in {
defm V_MAC_F16 : VOP2Inst <"v_mac_f16", VOP_MAC_F16>;
}
} // End isCommutable = 1
} // End SubtargetPredicate = Has16BitInsts
let SubtargetPredicate = HasDLInsts in {
defm V_XNOR_B32 : VOP2Inst <"v_xnor_b32", VOP_I32_I32_I32>;
let Constraints = "$vdst = $src2",
DisableEncoding="$src2",
isConvertibleToThreeAddress = 1,
isCommutable = 1 in {
defm V_FMAC_F32 : VOP2Inst <"v_fmac_f32", VOP_MAC_F32>;
}
} // End SubtargetPredicate = HasDLInsts
// Note: 16-bit instructions produce a 0 result in the high 16-bits.
multiclass Arithmetic_i16_Pats <SDPatternOperator op, Instruction inst> {
def : GCNPat<
(op i16:$src0, i16:$src1),
(inst $src0, $src1)
>;
def : GCNPat<
(i32 (zext (op i16:$src0, i16:$src1))),
(inst $src0, $src1)
>;
def : GCNPat<
(i64 (zext (op i16:$src0, i16:$src1))),
(REG_SEQUENCE VReg_64,
(inst $src0, $src1), sub0,
(V_MOV_B32_e32 (i32 0)), sub1)
>;
}
multiclass Bits_OpsRev_i16_Pats <SDPatternOperator op, Instruction inst> {
def : GCNPat<
(op i16:$src0, i16:$src1),
(inst $src1, $src0)
>;
def : GCNPat<
(i32 (zext (op i16:$src0, i16:$src1))),
(inst $src1, $src0)
>;
def : GCNPat<
(i64 (zext (op i16:$src0, i16:$src1))),
(REG_SEQUENCE VReg_64,
(inst $src1, $src0), sub0,
(V_MOV_B32_e32 (i32 0)), sub1)
>;
}
class ZExt_i16_i1_Pat <SDNode ext> : GCNPat <
(i16 (ext i1:$src)),
(V_CNDMASK_B32_e64 (i32 0), (i32 1), $src)
>;
let Predicates = [Has16BitInsts] in {
defm : Arithmetic_i16_Pats<add, V_ADD_U16_e64>;
defm : Arithmetic_i16_Pats<mul, V_MUL_LO_U16_e64>;
defm : Arithmetic_i16_Pats<sub, V_SUB_U16_e64>;
defm : Arithmetic_i16_Pats<smin, V_MIN_I16_e64>;
defm : Arithmetic_i16_Pats<smax, V_MAX_I16_e64>;
defm : Arithmetic_i16_Pats<umin, V_MIN_U16_e64>;
defm : Arithmetic_i16_Pats<umax, V_MAX_U16_e64>;
def : GCNPat <
(and i16:$src0, i16:$src1),
(V_AND_B32_e64 $src0, $src1)
>;
def : GCNPat <
(or i16:$src0, i16:$src1),
(V_OR_B32_e64 $src0, $src1)
>;
def : GCNPat <
(xor i16:$src0, i16:$src1),
(V_XOR_B32_e64 $src0, $src1)
>;
defm : Bits_OpsRev_i16_Pats<shl, V_LSHLREV_B16_e64>;
defm : Bits_OpsRev_i16_Pats<srl, V_LSHRREV_B16_e64>;
defm : Bits_OpsRev_i16_Pats<sra, V_ASHRREV_I16_e64>;
def : ZExt_i16_i1_Pat<zext>;
def : ZExt_i16_i1_Pat<anyext>;
def : GCNPat <
(i16 (sext i1:$src)),
(V_CNDMASK_B32_e64 (i32 0), (i32 -1), $src)
>;
// Undo sub x, c -> add x, -c canonicalization since c is more likely
// an inline immediate than -c.
// TODO: Also do for 64-bit.
def : GCNPat<
(add i16:$src0, (i16 NegSubInlineConst16:$src1)),
(V_SUB_U16_e64 $src0, NegSubInlineConst16:$src1)
>;
} // End Predicates = [Has16BitInsts]
//===----------------------------------------------------------------------===//
// SI
//===----------------------------------------------------------------------===//
let AssemblerPredicates = [isSICI], DecoderNamespace = "SICI" in {
multiclass VOP2_Real_si <bits<6> op> {
def _si :
VOP2_Real<!cast<VOP2_Pseudo>(NAME), SIEncodingFamily.SI>,
VOP2e<op{5-0}, !cast<VOP2_Pseudo>(NAME).Pfl>;
}
multiclass VOP2_Real_MADK_si <bits<6> op> {
def _si : VOP2_Real<!cast<VOP2_Pseudo>(NAME), SIEncodingFamily.SI>,
VOP2_MADKe<op{5-0}, !cast<VOP2_Pseudo>(NAME).Pfl>;
}
multiclass VOP2_Real_e32_si <bits<6> op> {
def _e32_si :
VOP2_Real<!cast<VOP2_Pseudo>(NAME#"_e32"), SIEncodingFamily.SI>,
VOP2e<op{5-0}, !cast<VOP2_Pseudo>(NAME#"_e32").Pfl>;
}
multiclass VOP2_Real_e32e64_si <bits<6> op> : VOP2_Real_e32_si<op> {
def _e64_si :
VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.SI>,
VOP3e_si <{1, 0, 0, op{5-0}}, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
}
multiclass VOP2be_Real_e32e64_si <bits<6> op> : VOP2_Real_e32_si<op> {
def _e64_si :
VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.SI>,
VOP3be_si <{1, 0, 0, op{5-0}}, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
}
} // End AssemblerPredicates = [isSICI], DecoderNamespace = "SICI"
defm V_CNDMASK_B32 : VOP2_Real_e32e64_si <0x0>;
defm V_ADD_F32 : VOP2_Real_e32e64_si <0x3>;
defm V_SUB_F32 : VOP2_Real_e32e64_si <0x4>;
defm V_SUBREV_F32 : VOP2_Real_e32e64_si <0x5>;
defm V_MUL_LEGACY_F32 : VOP2_Real_e32e64_si <0x7>;
defm V_MUL_F32 : VOP2_Real_e32e64_si <0x8>;
defm V_MUL_I32_I24 : VOP2_Real_e32e64_si <0x9>;
defm V_MUL_HI_I32_I24 : VOP2_Real_e32e64_si <0xa>;
defm V_MUL_U32_U24 : VOP2_Real_e32e64_si <0xb>;
defm V_MUL_HI_U32_U24 : VOP2_Real_e32e64_si <0xc>;
defm V_MIN_F32 : VOP2_Real_e32e64_si <0xf>;
defm V_MAX_F32 : VOP2_Real_e32e64_si <0x10>;
defm V_MIN_I32 : VOP2_Real_e32e64_si <0x11>;
defm V_MAX_I32 : VOP2_Real_e32e64_si <0x12>;
defm V_MIN_U32 : VOP2_Real_e32e64_si <0x13>;
defm V_MAX_U32 : VOP2_Real_e32e64_si <0x14>;
defm V_LSHRREV_B32 : VOP2_Real_e32e64_si <0x16>;
defm V_ASHRREV_I32 : VOP2_Real_e32e64_si <0x18>;
defm V_LSHLREV_B32 : VOP2_Real_e32e64_si <0x1a>;
defm V_AND_B32 : VOP2_Real_e32e64_si <0x1b>;
defm V_OR_B32 : VOP2_Real_e32e64_si <0x1c>;
defm V_XOR_B32 : VOP2_Real_e32e64_si <0x1d>;
defm V_MAC_F32 : VOP2_Real_e32e64_si <0x1f>;
defm V_MADMK_F32 : VOP2_Real_MADK_si <0x20>;
defm V_MADAK_F32 : VOP2_Real_MADK_si <0x21>;
defm V_ADD_I32 : VOP2be_Real_e32e64_si <0x25>;
defm V_SUB_I32 : VOP2be_Real_e32e64_si <0x26>;
defm V_SUBREV_I32 : VOP2be_Real_e32e64_si <0x27>;
defm V_ADDC_U32 : VOP2be_Real_e32e64_si <0x28>;
defm V_SUBB_U32 : VOP2be_Real_e32e64_si <0x29>;
defm V_SUBBREV_U32 : VOP2be_Real_e32e64_si <0x2a>;
defm V_READLANE_B32 : VOP2_Real_si <0x01>;
let InOperandList = (ins SSrc_b32:$src0, SCSrc_b32:$src1, VSrc_b32:$vdst_in) in {
defm V_WRITELANE_B32 : VOP2_Real_si <0x02>;
}
defm V_MAC_LEGACY_F32 : VOP2_Real_e32e64_si <0x6>;
defm V_MIN_LEGACY_F32 : VOP2_Real_e32e64_si <0xd>;
defm V_MAX_LEGACY_F32 : VOP2_Real_e32e64_si <0xe>;
defm V_LSHR_B32 : VOP2_Real_e32e64_si <0x15>;
defm V_ASHR_I32 : VOP2_Real_e32e64_si <0x17>;
defm V_LSHL_B32 : VOP2_Real_e32e64_si <0x19>;
defm V_BFM_B32 : VOP2_Real_e32e64_si <0x1e>;
defm V_BCNT_U32_B32 : VOP2_Real_e32e64_si <0x22>;
defm V_MBCNT_LO_U32_B32 : VOP2_Real_e32e64_si <0x23>;
defm V_MBCNT_HI_U32_B32 : VOP2_Real_e32e64_si <0x24>;
defm V_LDEXP_F32 : VOP2_Real_e32e64_si <0x2b>;
defm V_CVT_PKACCUM_U8_F32 : VOP2_Real_e32e64_si <0x2c>;
defm V_CVT_PKNORM_I16_F32 : VOP2_Real_e32e64_si <0x2d>;
defm V_CVT_PKNORM_U16_F32 : VOP2_Real_e32e64_si <0x2e>;
defm V_CVT_PKRTZ_F16_F32 : VOP2_Real_e32e64_si <0x2f>;
defm V_CVT_PK_U16_U32 : VOP2_Real_e32e64_si <0x30>;
defm V_CVT_PK_I16_I32 : VOP2_Real_e32e64_si <0x31>;
//===----------------------------------------------------------------------===//
// VI
//===----------------------------------------------------------------------===//
class VOP2_DPPe <bits<6> op, VOP2_DPP_Pseudo ps, VOPProfile P = ps.Pfl> :
VOP_DPPe <P> {
bits<8> vdst;
bits<8> src1;
let Inst{8-0} = 0xfa; //dpp
let Inst{16-9} = !if(P.HasSrc1, src1{7-0}, 0);
let Inst{24-17} = !if(P.EmitDst, vdst{7-0}, 0);
let Inst{30-25} = op;
let Inst{31} = 0x0; //encoding
}
let AssemblerPredicates = [isVI], DecoderNamespace = "VI" in {
multiclass VOP2_Real_MADK_vi <bits<6> op> {
def _vi : VOP2_Real<!cast<VOP2_Pseudo>(NAME), SIEncodingFamily.VI>,
VOP2_MADKe<op{5-0}, !cast<VOP2_Pseudo>(NAME).Pfl>;
}
multiclass VOP2_Real_e32_vi <bits<6> op> {
def _e32_vi :
VOP2_Real<!cast<VOP2_Pseudo>(NAME#"_e32"), SIEncodingFamily.VI>,
VOP2e<op{5-0}, !cast<VOP2_Pseudo>(NAME#"_e32").Pfl>;
}
multiclass VOP2_Real_e64_vi <bits<10> op> {
def _e64_vi :
VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.VI>,
VOP3e_vi <op, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
}
multiclass VOP2_Real_e64only_vi <bits<10> op> {
def _e64_vi :
VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.VI>,
VOP3e_vi <op, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl> {
// Hack to stop printing _e64
VOP3_Pseudo ps = !cast<VOP3_Pseudo>(NAME#"_e64");
let OutOperandList = (outs VGPR_32:$vdst);
let AsmString = ps.Mnemonic # " " # ps.AsmOperands;
}
}
multiclass Base_VOP2_Real_e32e64_vi <bits<6> op> :
VOP2_Real_e32_vi<op>,
VOP2_Real_e64_vi<{0, 1, 0, 0, op{5-0}}>;
} // End AssemblerPredicates = [isVI], DecoderNamespace = "VI"
multiclass VOP2_SDWA_Real <bits<6> op> {
def _sdwa_vi :
VOP_SDWA_Real <!cast<VOP2_SDWA_Pseudo>(NAME#"_sdwa")>,
VOP2_SDWAe <op{5-0}, !cast<VOP2_SDWA_Pseudo>(NAME#"_sdwa").Pfl>;
}
multiclass VOP2_SDWA9_Real <bits<6> op> {
def _sdwa_gfx9 :
VOP_SDWA9_Real <!cast<VOP2_SDWA_Pseudo>(NAME#"_sdwa")>,
VOP2_SDWA9Ae <op{5-0}, !cast<VOP2_SDWA_Pseudo>(NAME#"_sdwa").Pfl>;
}
let AssemblerPredicates = [isVIOnly] in {
multiclass VOP2be_Real_e32e64_vi_only <bits<6> op, string OpName, string AsmName> {
def _e32_vi :
VOP2_Real<!cast<VOP2_Pseudo>(OpName#"_e32"), SIEncodingFamily.VI>,
VOP2e<op{5-0}, !cast<VOP2_Pseudo>(OpName#"_e32").Pfl> {
VOP2_Pseudo ps = !cast<VOP2_Pseudo>(OpName#"_e32");
let AsmString = AsmName # ps.AsmOperands;
let DecoderNamespace = "VI";
}
def _e64_vi :
VOP3_Real<!cast<VOP3_Pseudo>(OpName#"_e64"), SIEncodingFamily.VI>,
VOP3be_vi <{0, 1, 0, 0, op{5-0}}, !cast<VOP3_Pseudo>(OpName#"_e64").Pfl> {
VOP3_Pseudo ps = !cast<VOP3_Pseudo>(OpName#"_e64");
let AsmString = AsmName # ps.AsmOperands;
let DecoderNamespace = "VI";
}
def _sdwa_vi :
VOP_SDWA_Real <!cast<VOP2_SDWA_Pseudo>(OpName#"_sdwa")>,
VOP2_SDWAe <op{5-0}, !cast<VOP2_SDWA_Pseudo>(OpName#"_sdwa").Pfl> {
VOP2_SDWA_Pseudo ps = !cast<VOP2_SDWA_Pseudo>(OpName#"_sdwa");
let AsmString = AsmName # ps.AsmOperands;
}
foreach _ = BoolToList<!cast<VOP2_Pseudo>(OpName#"_e32").Pfl.HasExtDPP>.ret in
def _dpp_vi :
VOP_DPP_Real<!cast<VOP2_DPP_Pseudo>(OpName#"_dpp"), SIEncodingFamily.VI>,
VOP2_DPPe<op, !cast<VOP2_DPP_Pseudo>(OpName#"_dpp")> {
VOP2_DPP_Pseudo ps = !cast<VOP2_DPP_Pseudo>(OpName#"_dpp");
let AsmString = AsmName # ps.AsmOperands;
}
}
}
let AssemblerPredicates = [isGFX9] in {
multiclass VOP2be_Real_e32e64_gfx9 <bits<6> op, string OpName, string AsmName> {
def _e32_gfx9 :
VOP2_Real<!cast<VOP2_Pseudo>(OpName#"_e32"), SIEncodingFamily.GFX9>,
VOP2e<op{5-0}, !cast<VOP2_Pseudo>(OpName#"_e32").Pfl> {
VOP2_Pseudo ps = !cast<VOP2_Pseudo>(OpName#"_e32");
let AsmString = AsmName # ps.AsmOperands;
let DecoderNamespace = "GFX9";
}
def _e64_gfx9 :
VOP3_Real<!cast<VOP3_Pseudo>(OpName#"_e64"), SIEncodingFamily.GFX9>,
VOP3be_vi <{0, 1, 0, 0, op{5-0}}, !cast<VOP3_Pseudo>(OpName#"_e64").Pfl> {
VOP3_Pseudo ps = !cast<VOP3_Pseudo>(OpName#"_e64");
let AsmString = AsmName # ps.AsmOperands;
let DecoderNamespace = "GFX9";
}
def _sdwa_gfx9 :
VOP_SDWA9_Real <!cast<VOP2_SDWA_Pseudo>(OpName#"_sdwa")>,
VOP2_SDWA9Ae <op{5-0}, !cast<VOP2_SDWA_Pseudo>(OpName#"_sdwa").Pfl> {
VOP2_SDWA_Pseudo ps = !cast<VOP2_SDWA_Pseudo>(OpName#"_sdwa");
let AsmString = AsmName # ps.AsmOperands;
}
foreach _ = BoolToList<!cast<VOP2_Pseudo>(OpName#"_e32").Pfl.HasExtDPP>.ret in
def _dpp_gfx9 :
VOP_DPP_Real<!cast<VOP2_DPP_Pseudo>(OpName#"_dpp"), SIEncodingFamily.GFX9>,
VOP2_DPPe<op, !cast<VOP2_DPP_Pseudo>(OpName#"_dpp")> {
VOP2_DPP_Pseudo ps = !cast<VOP2_DPP_Pseudo>(OpName#"_dpp");
let AsmString = AsmName # ps.AsmOperands;
let DecoderNamespace = "SDWA9";
}
}
multiclass VOP2_Real_e32e64_gfx9 <bits<6> op> {
def _e32_gfx9 :
VOP2_Real<!cast<VOP2_Pseudo>(NAME#"_e32"), SIEncodingFamily.GFX9>,
VOP2e<op{5-0}, !cast<VOP2_Pseudo>(NAME#"_e32").Pfl>{
let DecoderNamespace = "GFX9";
}
def _e64_gfx9 :
VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.GFX9>,
VOP3e_vi <{0, 1, 0, 0, op{5-0}}, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl> {
let DecoderNamespace = "GFX9";
}
def _sdwa_gfx9 :
VOP_SDWA9_Real <!cast<VOP2_SDWA_Pseudo>(NAME#"_sdwa")>,
VOP2_SDWA9Ae <op{5-0}, !cast<VOP2_SDWA_Pseudo>(NAME#"_sdwa").Pfl> {
}
foreach _ = BoolToList<!cast<VOP2_Pseudo>(NAME#"_e32").Pfl.HasExtDPP>.ret in
def _dpp_gfx9 :
VOP_DPP_Real<!cast<VOP2_DPP_Pseudo>(NAME#"_dpp"), SIEncodingFamily.GFX9>,
VOP2_DPPe<op, !cast<VOP2_DPP_Pseudo>(NAME#"_dpp")> {
let DecoderNamespace = "SDWA9";
}
}
} // AssemblerPredicates = [isGFX9]
multiclass VOP2_Real_e32e64_vi <bits<6> op> :
Base_VOP2_Real_e32e64_vi<op>, VOP2_SDWA_Real<op>, VOP2_SDWA9_Real<op> {
foreach _ = BoolToList<!cast<VOP2_Pseudo>(NAME#"_e32").Pfl.HasExtDPP>.ret in
def _dpp_vi :
VOP_DPP_Real<!cast<VOP2_DPP_Pseudo>(NAME#"_dpp"), SIEncodingFamily.VI>,
VOP2_DPPe<op, !cast<VOP2_DPP_Pseudo>(NAME#"_dpp")>;
}
defm V_CNDMASK_B32 : VOP2_Real_e32e64_vi <0x0>;
defm V_ADD_F32 : VOP2_Real_e32e64_vi <0x1>;
defm V_SUB_F32 : VOP2_Real_e32e64_vi <0x2>;
defm V_SUBREV_F32 : VOP2_Real_e32e64_vi <0x3>;
defm V_MUL_LEGACY_F32 : VOP2_Real_e32e64_vi <0x4>;
defm V_MUL_F32 : VOP2_Real_e32e64_vi <0x5>;
defm V_MUL_I32_I24 : VOP2_Real_e32e64_vi <0x6>;
defm V_MUL_HI_I32_I24 : VOP2_Real_e32e64_vi <0x7>;
defm V_MUL_U32_U24 : VOP2_Real_e32e64_vi <0x8>;
defm V_MUL_HI_U32_U24 : VOP2_Real_e32e64_vi <0x9>;
defm V_MIN_F32 : VOP2_Real_e32e64_vi <0xa>;
defm V_MAX_F32 : VOP2_Real_e32e64_vi <0xb>;
defm V_MIN_I32 : VOP2_Real_e32e64_vi <0xc>;
defm V_MAX_I32 : VOP2_Real_e32e64_vi <0xd>;
defm V_MIN_U32 : VOP2_Real_e32e64_vi <0xe>;
defm V_MAX_U32 : VOP2_Real_e32e64_vi <0xf>;
defm V_LSHRREV_B32 : VOP2_Real_e32e64_vi <0x10>;
defm V_ASHRREV_I32 : VOP2_Real_e32e64_vi <0x11>;
defm V_LSHLREV_B32 : VOP2_Real_e32e64_vi <0x12>;
defm V_AND_B32 : VOP2_Real_e32e64_vi <0x13>;
defm V_OR_B32 : VOP2_Real_e32e64_vi <0x14>;
defm V_XOR_B32 : VOP2_Real_e32e64_vi <0x15>;
defm V_MAC_F32 : VOP2_Real_e32e64_vi <0x16>;
defm V_MADMK_F32 : VOP2_Real_MADK_vi <0x17>;
defm V_MADAK_F32 : VOP2_Real_MADK_vi <0x18>;
defm V_ADD_U32 : VOP2be_Real_e32e64_vi_only <0x19, "V_ADD_I32", "v_add_u32">;
defm V_SUB_U32 : VOP2be_Real_e32e64_vi_only <0x1a, "V_SUB_I32", "v_sub_u32">;
defm V_SUBREV_U32 : VOP2be_Real_e32e64_vi_only <0x1b, "V_SUBREV_I32", "v_subrev_u32">;
defm V_ADDC_U32 : VOP2be_Real_e32e64_vi_only <0x1c, "V_ADDC_U32", "v_addc_u32">;
defm V_SUBB_U32 : VOP2be_Real_e32e64_vi_only <0x1d, "V_SUBB_U32", "v_subb_u32">;
defm V_SUBBREV_U32 : VOP2be_Real_e32e64_vi_only <0x1e, "V_SUBBREV_U32", "v_subbrev_u32">;
defm V_ADD_CO_U32 : VOP2be_Real_e32e64_gfx9 <0x19, "V_ADD_I32", "v_add_co_u32">;
defm V_SUB_CO_U32 : VOP2be_Real_e32e64_gfx9 <0x1a, "V_SUB_I32", "v_sub_co_u32">;
defm V_SUBREV_CO_U32 : VOP2be_Real_e32e64_gfx9 <0x1b, "V_SUBREV_I32", "v_subrev_co_u32">;
defm V_ADDC_CO_U32 : VOP2be_Real_e32e64_gfx9 <0x1c, "V_ADDC_U32", "v_addc_co_u32">;
defm V_SUBB_CO_U32 : VOP2be_Real_e32e64_gfx9 <0x1d, "V_SUBB_U32", "v_subb_co_u32">;
defm V_SUBBREV_CO_U32 : VOP2be_Real_e32e64_gfx9 <0x1e, "V_SUBBREV_U32", "v_subbrev_co_u32">;
defm V_ADD_U32 : VOP2_Real_e32e64_gfx9 <0x34>;
defm V_SUB_U32 : VOP2_Real_e32e64_gfx9 <0x35>;
defm V_SUBREV_U32 : VOP2_Real_e32e64_gfx9 <0x36>;
defm V_BFM_B32 : VOP2_Real_e64only_vi <0x293>;
defm V_BCNT_U32_B32 : VOP2_Real_e64only_vi <0x28b>;
defm V_MBCNT_LO_U32_B32 : VOP2_Real_e64only_vi <0x28c>;
defm V_MBCNT_HI_U32_B32 : VOP2_Real_e64only_vi <0x28d>;
defm V_LDEXP_F32 : VOP2_Real_e64only_vi <0x288>;
defm V_CVT_PKACCUM_U8_F32 : VOP2_Real_e64only_vi <0x1f0>;
defm V_CVT_PKNORM_I16_F32 : VOP2_Real_e64only_vi <0x294>;
defm V_CVT_PKNORM_U16_F32 : VOP2_Real_e64only_vi <0x295>;
defm V_CVT_PKRTZ_F16_F32 : VOP2_Real_e64only_vi <0x296>;
defm V_CVT_PK_U16_U32 : VOP2_Real_e64only_vi <0x297>;
defm V_CVT_PK_I16_I32 : VOP2_Real_e64only_vi <0x298>;
defm V_ADD_F16 : VOP2_Real_e32e64_vi <0x1f>;
defm V_SUB_F16 : VOP2_Real_e32e64_vi <0x20>;
defm V_SUBREV_F16 : VOP2_Real_e32e64_vi <0x21>;
defm V_MUL_F16 : VOP2_Real_e32e64_vi <0x22>;
defm V_MAC_F16 : VOP2_Real_e32e64_vi <0x23>;
defm V_MADMK_F16 : VOP2_Real_MADK_vi <0x24>;
defm V_MADAK_F16 : VOP2_Real_MADK_vi <0x25>;
defm V_ADD_U16 : VOP2_Real_e32e64_vi <0x26>;
defm V_SUB_U16 : VOP2_Real_e32e64_vi <0x27>;
defm V_SUBREV_U16 : VOP2_Real_e32e64_vi <0x28>;
defm V_MUL_LO_U16 : VOP2_Real_e32e64_vi <0x29>;
defm V_LSHLREV_B16 : VOP2_Real_e32e64_vi <0x2a>;
defm V_LSHRREV_B16 : VOP2_Real_e32e64_vi <0x2b>;
defm V_ASHRREV_I16 : VOP2_Real_e32e64_vi <0x2c>;
defm V_MAX_F16 : VOP2_Real_e32e64_vi <0x2d>;
defm V_MIN_F16 : VOP2_Real_e32e64_vi <0x2e>;
defm V_MAX_U16 : VOP2_Real_e32e64_vi <0x2f>;
defm V_MAX_I16 : VOP2_Real_e32e64_vi <0x30>;
defm V_MIN_U16 : VOP2_Real_e32e64_vi <0x31>;
defm V_MIN_I16 : VOP2_Real_e32e64_vi <0x32>;
defm V_LDEXP_F16 : VOP2_Real_e32e64_vi <0x33>;
let SubtargetPredicate = isVI in {
// Aliases to simplify matching of floating-point instructions that
// are VOP2 on SI and VOP3 on VI.
class SI2_VI3Alias <string name, VOP3_Real inst> : InstAlias <
name#" $dst, $src0, $src1",
!if(inst.Pfl.HasOMod,
(inst VGPR_32:$dst, 0, VCSrc_f32:$src0, 0, VCSrc_f32:$src1, 0, 0),
(inst VGPR_32:$dst, 0, VCSrc_f32:$src0, 0, VCSrc_f32:$src1, 0))
>, PredicateControl {
let UseInstAsmMatchConverter = 0;
let AsmVariantName = AMDGPUAsmVariants.VOP3;
}
def : SI2_VI3Alias <"v_ldexp_f32", V_LDEXP_F32_e64_vi>;
def : SI2_VI3Alias <"v_cvt_pkaccum_u8_f32", V_CVT_PKACCUM_U8_F32_e64_vi>;
def : SI2_VI3Alias <"v_cvt_pknorm_i16_f32", V_CVT_PKNORM_I16_F32_e64_vi>;
def : SI2_VI3Alias <"v_cvt_pknorm_u16_f32", V_CVT_PKNORM_U16_F32_e64_vi>;
def : SI2_VI3Alias <"v_cvt_pkrtz_f16_f32", V_CVT_PKRTZ_F16_F32_e64_vi>;
} // End SubtargetPredicate = isVI
let SubtargetPredicate = HasDLInsts in {
defm V_FMAC_F32 : VOP2_Real_e32e64_vi <0x3b>;
defm V_XNOR_B32 : VOP2_Real_e32e64_vi <0x3d>;
} // End SubtargetPredicate = HasDLInsts
Index: stable/11/contrib/llvm/lib/Target/AVR/AVRISelLowering.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/AVR/AVRISelLowering.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/AVR/AVRISelLowering.cpp (revision 350259)
@@ -1,2038 +1,2044 @@
//===-- AVRISelLowering.cpp - AVR DAG Lowering Implementation -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interfaces that AVR uses to lower LLVM code into a
// selection DAG.
//
//===----------------------------------------------------------------------===//
#include "AVRISelLowering.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/ErrorHandling.h"
#include "AVR.h"
#include "AVRMachineFunctionInfo.h"
+#include "AVRSubtarget.h"
#include "AVRTargetMachine.h"
#include "MCTargetDesc/AVRMCTargetDesc.h"
namespace llvm {
-AVRTargetLowering::AVRTargetLowering(AVRTargetMachine &tm)
- : TargetLowering(tm) {
+AVRTargetLowering::AVRTargetLowering(const AVRTargetMachine &TM,
+ const AVRSubtarget &STI)
+ : TargetLowering(TM), Subtarget(STI) {
// Set up the register classes.
addRegisterClass(MVT::i8, &AVR::GPR8RegClass);
addRegisterClass(MVT::i16, &AVR::DREGSRegClass);
// Compute derived properties from the register classes.
- computeRegisterProperties(tm.getSubtargetImpl()->getRegisterInfo());
+ computeRegisterProperties(Subtarget.getRegisterInfo());
setBooleanContents(ZeroOrOneBooleanContent);
setBooleanVectorContents(ZeroOrOneBooleanContent);
setSchedulingPreference(Sched::RegPressure);
setStackPointerRegisterToSaveRestore(AVR::SP);
setSupportsUnalignedAtomics(true);
setOperationAction(ISD::GlobalAddress, MVT::i16, Custom);
setOperationAction(ISD::BlockAddress, MVT::i16, Custom);
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i8, Expand);
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i16, Expand);
for (MVT VT : MVT::integer_valuetypes()) {
for (auto N : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) {
setLoadExtAction(N, VT, MVT::i1, Promote);
setLoadExtAction(N, VT, MVT::i8, Expand);
}
}
setTruncStoreAction(MVT::i16, MVT::i8, Expand);
for (MVT VT : MVT::integer_valuetypes()) {
setOperationAction(ISD::ADDC, VT, Legal);
setOperationAction(ISD::SUBC, VT, Legal);
setOperationAction(ISD::ADDE, VT, Legal);
setOperationAction(ISD::SUBE, VT, Legal);
}
// sub (x, imm) gets canonicalized to add (x, -imm), so for illegal types
// revert into a sub since we don't have an add with immediate instruction.
setOperationAction(ISD::ADD, MVT::i32, Custom);
setOperationAction(ISD::ADD, MVT::i64, Custom);
// our shift instructions are only able to shift 1 bit at a time, so handle
// this in a custom way.
setOperationAction(ISD::SRA, MVT::i8, Custom);
setOperationAction(ISD::SHL, MVT::i8, Custom);
setOperationAction(ISD::SRL, MVT::i8, Custom);
setOperationAction(ISD::SRA, MVT::i16, Custom);
setOperationAction(ISD::SHL, MVT::i16, Custom);
setOperationAction(ISD::SRL, MVT::i16, Custom);
setOperationAction(ISD::SHL_PARTS, MVT::i16, Expand);
setOperationAction(ISD::SRA_PARTS, MVT::i16, Expand);
setOperationAction(ISD::SRL_PARTS, MVT::i16, Expand);
setOperationAction(ISD::ROTL, MVT::i8, Custom);
setOperationAction(ISD::ROTL, MVT::i16, Custom);
setOperationAction(ISD::ROTR, MVT::i8, Custom);
setOperationAction(ISD::ROTR, MVT::i16, Custom);
setOperationAction(ISD::BR_CC, MVT::i8, Custom);
setOperationAction(ISD::BR_CC, MVT::i16, Custom);
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
setOperationAction(ISD::BR_CC, MVT::i64, Custom);
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
setOperationAction(ISD::SELECT_CC, MVT::i8, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i16, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i32, Expand);
setOperationAction(ISD::SELECT_CC, MVT::i64, Expand);
setOperationAction(ISD::SETCC, MVT::i8, Custom);
setOperationAction(ISD::SETCC, MVT::i16, Custom);
setOperationAction(ISD::SETCC, MVT::i32, Custom);
setOperationAction(ISD::SETCC, MVT::i64, Custom);
setOperationAction(ISD::SELECT, MVT::i8, Expand);
setOperationAction(ISD::SELECT, MVT::i16, Expand);
setOperationAction(ISD::BSWAP, MVT::i16, Expand);
// Add support for postincrement and predecrement load/stores.
setIndexedLoadAction(ISD::POST_INC, MVT::i8, Legal);
setIndexedLoadAction(ISD::POST_INC, MVT::i16, Legal);
setIndexedLoadAction(ISD::PRE_DEC, MVT::i8, Legal);
setIndexedLoadAction(ISD::PRE_DEC, MVT::i16, Legal);
setIndexedStoreAction(ISD::POST_INC, MVT::i8, Legal);
setIndexedStoreAction(ISD::POST_INC, MVT::i16, Legal);
setIndexedStoreAction(ISD::PRE_DEC, MVT::i8, Legal);
setIndexedStoreAction(ISD::PRE_DEC, MVT::i16, Legal);
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction(ISD::VAEND, MVT::Other, Expand);
setOperationAction(ISD::VAARG, MVT::Other, Expand);
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
// Atomic operations which must be lowered to rtlib calls
for (MVT VT : MVT::integer_valuetypes()) {
setOperationAction(ISD::ATOMIC_SWAP, VT, Expand);
setOperationAction(ISD::ATOMIC_CMP_SWAP, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_NAND, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_MAX, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_MIN, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_UMAX, VT, Expand);
setOperationAction(ISD::ATOMIC_LOAD_UMIN, VT, Expand);
}
// Division/remainder
setOperationAction(ISD::UDIV, MVT::i8, Expand);
setOperationAction(ISD::UDIV, MVT::i16, Expand);
setOperationAction(ISD::UREM, MVT::i8, Expand);
setOperationAction(ISD::UREM, MVT::i16, Expand);
setOperationAction(ISD::SDIV, MVT::i8, Expand);
setOperationAction(ISD::SDIV, MVT::i16, Expand);
setOperationAction(ISD::SREM, MVT::i8, Expand);
setOperationAction(ISD::SREM, MVT::i16, Expand);
// Make division and modulus custom
for (MVT VT : MVT::integer_valuetypes()) {
setOperationAction(ISD::UDIVREM, VT, Custom);
setOperationAction(ISD::SDIVREM, VT, Custom);
}
// Do not use MUL. The AVR instructions are closer to SMUL_LOHI &co.
setOperationAction(ISD::MUL, MVT::i8, Expand);
setOperationAction(ISD::MUL, MVT::i16, Expand);
// Expand 16 bit multiplications.
setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand);
setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand);
+ // Expand multiplications to libcalls when there is
+ // no hardware MUL.
+ if (!Subtarget.supportsMultiplication()) {
+ setOperationAction(ISD::SMUL_LOHI, MVT::i8, Expand);
+ setOperationAction(ISD::UMUL_LOHI, MVT::i8, Expand);
+ }
+
for (MVT VT : MVT::integer_valuetypes()) {
setOperationAction(ISD::MULHS, VT, Expand);
setOperationAction(ISD::MULHU, VT, Expand);
}
for (MVT VT : MVT::integer_valuetypes()) {
setOperationAction(ISD::CTPOP, VT, Expand);
setOperationAction(ISD::CTLZ, VT, Expand);
setOperationAction(ISD::CTTZ, VT, Expand);
}
for (MVT VT : MVT::integer_valuetypes()) {
setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand);
// TODO: The generated code is pretty poor. Investigate using the
// same "shift and subtract with carry" trick that we do for
// extending 8-bit to 16-bit. This may require infrastructure
// improvements in how we treat 16-bit "registers" to be feasible.
}
// Division rtlib functions (not supported)
setLibcallName(RTLIB::SDIV_I8, nullptr);
setLibcallName(RTLIB::SDIV_I16, nullptr);
setLibcallName(RTLIB::SDIV_I32, nullptr);
setLibcallName(RTLIB::SDIV_I64, nullptr);
setLibcallName(RTLIB::SDIV_I128, nullptr);
setLibcallName(RTLIB::UDIV_I8, nullptr);
setLibcallName(RTLIB::UDIV_I16, nullptr);
setLibcallName(RTLIB::UDIV_I32, nullptr);
setLibcallName(RTLIB::UDIV_I64, nullptr);
setLibcallName(RTLIB::UDIV_I128, nullptr);
// Modulus rtlib functions (not supported)
setLibcallName(RTLIB::SREM_I8, nullptr);
setLibcallName(RTLIB::SREM_I16, nullptr);
setLibcallName(RTLIB::SREM_I32, nullptr);
setLibcallName(RTLIB::SREM_I64, nullptr);
setLibcallName(RTLIB::SREM_I128, nullptr);
setLibcallName(RTLIB::UREM_I8, nullptr);
setLibcallName(RTLIB::UREM_I16, nullptr);
setLibcallName(RTLIB::UREM_I32, nullptr);
setLibcallName(RTLIB::UREM_I64, nullptr);
setLibcallName(RTLIB::UREM_I128, nullptr);
// Division and modulus rtlib functions
setLibcallName(RTLIB::SDIVREM_I8, "__divmodqi4");
setLibcallName(RTLIB::SDIVREM_I16, "__divmodhi4");
setLibcallName(RTLIB::SDIVREM_I32, "__divmodsi4");
setLibcallName(RTLIB::SDIVREM_I64, "__divmoddi4");
setLibcallName(RTLIB::SDIVREM_I128, "__divmodti4");
setLibcallName(RTLIB::UDIVREM_I8, "__udivmodqi4");
setLibcallName(RTLIB::UDIVREM_I16, "__udivmodhi4");
setLibcallName(RTLIB::UDIVREM_I32, "__udivmodsi4");
setLibcallName(RTLIB::UDIVREM_I64, "__udivmoddi4");
setLibcallName(RTLIB::UDIVREM_I128, "__udivmodti4");
// Several of the runtime library functions use a special calling conv
setLibcallCallingConv(RTLIB::SDIVREM_I8, CallingConv::AVR_BUILTIN);
setLibcallCallingConv(RTLIB::SDIVREM_I16, CallingConv::AVR_BUILTIN);
setLibcallCallingConv(RTLIB::UDIVREM_I8, CallingConv::AVR_BUILTIN);
setLibcallCallingConv(RTLIB::UDIVREM_I16, CallingConv::AVR_BUILTIN);
// Trigonometric rtlib functions
setLibcallName(RTLIB::SIN_F32, "sin");
setLibcallName(RTLIB::COS_F32, "cos");
setMinFunctionAlignment(1);
setMinimumJumpTableEntries(INT_MAX);
}
const char *AVRTargetLowering::getTargetNodeName(unsigned Opcode) const {
#define NODE(name) \
case AVRISD::name: \
return #name
switch (Opcode) {
default:
return nullptr;
NODE(RET_FLAG);
NODE(RETI_FLAG);
NODE(CALL);
NODE(WRAPPER);
NODE(LSL);
NODE(LSR);
NODE(ROL);
NODE(ROR);
NODE(ASR);
NODE(LSLLOOP);
NODE(LSRLOOP);
NODE(ASRLOOP);
NODE(BRCOND);
NODE(CMP);
NODE(CMPC);
NODE(TST);
NODE(SELECT_CC);
#undef NODE
}
}
EVT AVRTargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &,
EVT VT) const {
assert(!VT.isVector() && "No AVR SetCC type for vectors!");
return MVT::i8;
}
SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
//:TODO: this function has to be completely rewritten to produce optimal
// code, for now it's producing very long but correct code.
unsigned Opc8;
const SDNode *N = Op.getNode();
EVT VT = Op.getValueType();
SDLoc dl(N);
// Expand non-constant shifts to loops.
if (!isa<ConstantSDNode>(N->getOperand(1))) {
switch (Op.getOpcode()) {
default:
llvm_unreachable("Invalid shift opcode!");
case ISD::SHL:
return DAG.getNode(AVRISD::LSLLOOP, dl, VT, N->getOperand(0),
N->getOperand(1));
case ISD::SRL:
return DAG.getNode(AVRISD::LSRLOOP, dl, VT, N->getOperand(0),
N->getOperand(1));
case ISD::ROTL:
return DAG.getNode(AVRISD::ROLLOOP, dl, VT, N->getOperand(0),
N->getOperand(1));
case ISD::ROTR:
return DAG.getNode(AVRISD::RORLOOP, dl, VT, N->getOperand(0),
N->getOperand(1));
case ISD::SRA:
return DAG.getNode(AVRISD::ASRLOOP, dl, VT, N->getOperand(0),
N->getOperand(1));
}
}
uint64_t ShiftAmount = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
SDValue Victim = N->getOperand(0);
switch (Op.getOpcode()) {
case ISD::SRA:
Opc8 = AVRISD::ASR;
break;
case ISD::ROTL:
Opc8 = AVRISD::ROL;
break;
case ISD::ROTR:
Opc8 = AVRISD::ROR;
break;
case ISD::SRL:
Opc8 = AVRISD::LSR;
break;
case ISD::SHL:
Opc8 = AVRISD::LSL;
break;
default:
llvm_unreachable("Invalid shift opcode");
}
while (ShiftAmount--) {
Victim = DAG.getNode(Opc8, dl, VT, Victim);
}
return Victim;
}
SDValue AVRTargetLowering::LowerDivRem(SDValue Op, SelectionDAG &DAG) const {
unsigned Opcode = Op->getOpcode();
assert((Opcode == ISD::SDIVREM || Opcode == ISD::UDIVREM) &&
"Invalid opcode for Div/Rem lowering");
bool IsSigned = (Opcode == ISD::SDIVREM);
EVT VT = Op->getValueType(0);
Type *Ty = VT.getTypeForEVT(*DAG.getContext());
RTLIB::Libcall LC;
switch (VT.getSimpleVT().SimpleTy) {
default:
llvm_unreachable("Unexpected request for libcall!");
case MVT::i8:
LC = IsSigned ? RTLIB::SDIVREM_I8 : RTLIB::UDIVREM_I8;
break;
case MVT::i16:
LC = IsSigned ? RTLIB::SDIVREM_I16 : RTLIB::UDIVREM_I16;
break;
case MVT::i32:
LC = IsSigned ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;
break;
case MVT::i64:
LC = IsSigned ? RTLIB::SDIVREM_I64 : RTLIB::UDIVREM_I64;
break;
case MVT::i128:
LC = IsSigned ? RTLIB::SDIVREM_I128 : RTLIB::UDIVREM_I128;
break;
}
SDValue InChain = DAG.getEntryNode();
TargetLowering::ArgListTy Args;
TargetLowering::ArgListEntry Entry;
for (SDValue const &Value : Op->op_values()) {
Entry.Node = Value;
Entry.Ty = Value.getValueType().getTypeForEVT(*DAG.getContext());
Entry.IsSExt = IsSigned;
Entry.IsZExt = !IsSigned;
Args.push_back(Entry);
}
SDValue Callee = DAG.getExternalSymbol(getLibcallName(LC),
getPointerTy(DAG.getDataLayout()));
Type *RetTy = (Type *)StructType::get(Ty, Ty);
SDLoc dl(Op);
TargetLowering::CallLoweringInfo CLI(DAG);
CLI.setDebugLoc(dl)
.setChain(InChain)
.setLibCallee(getLibcallCallingConv(LC), RetTy, Callee, std::move(Args))
.setInRegister()
.setSExtResult(IsSigned)
.setZExtResult(!IsSigned);
std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI);
return CallInfo.first;
}
SDValue AVRTargetLowering::LowerGlobalAddress(SDValue Op,
SelectionDAG &DAG) const {
auto DL = DAG.getDataLayout();
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset();
// Create the TargetGlobalAddress node, folding in the constant offset.
SDValue Result =
DAG.getTargetGlobalAddress(GV, SDLoc(Op), getPointerTy(DL), Offset);
return DAG.getNode(AVRISD::WRAPPER, SDLoc(Op), getPointerTy(DL), Result);
}
SDValue AVRTargetLowering::LowerBlockAddress(SDValue Op,
SelectionDAG &DAG) const {
auto DL = DAG.getDataLayout();
const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
SDValue Result = DAG.getTargetBlockAddress(BA, getPointerTy(DL));
return DAG.getNode(AVRISD::WRAPPER, SDLoc(Op), getPointerTy(DL), Result);
}
/// IntCCToAVRCC - Convert a DAG integer condition code to an AVR CC.
static AVRCC::CondCodes intCCToAVRCC(ISD::CondCode CC) {
switch (CC) {
default:
llvm_unreachable("Unknown condition code!");
case ISD::SETEQ:
return AVRCC::COND_EQ;
case ISD::SETNE:
return AVRCC::COND_NE;
case ISD::SETGE:
return AVRCC::COND_GE;
case ISD::SETLT:
return AVRCC::COND_LT;
case ISD::SETUGE:
return AVRCC::COND_SH;
case ISD::SETULT:
return AVRCC::COND_LO;
}
}
/// Returns appropriate AVR CMP/CMPC nodes and corresponding condition code for
/// the given operands.
SDValue AVRTargetLowering::getAVRCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
SDValue &AVRcc, SelectionDAG &DAG,
SDLoc DL) const {
SDValue Cmp;
EVT VT = LHS.getValueType();
bool UseTest = false;
switch (CC) {
default:
break;
case ISD::SETLE: {
// Swap operands and reverse the branching condition.
std::swap(LHS, RHS);
CC = ISD::SETGE;
break;
}
case ISD::SETGT: {
if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
switch (C->getSExtValue()) {
case -1: {
// When doing lhs > -1 use a tst instruction on the top part of lhs
// and use brpl instead of using a chain of cp/cpc.
UseTest = true;
AVRcc = DAG.getConstant(AVRCC::COND_PL, DL, MVT::i8);
break;
}
case 0: {
// Turn lhs > 0 into 0 < lhs since 0 can be materialized with
// __zero_reg__ in lhs.
RHS = LHS;
LHS = DAG.getConstant(0, DL, VT);
CC = ISD::SETLT;
break;
}
default: {
// Turn lhs < rhs with lhs constant into rhs >= lhs+1, this allows
// us to fold the constant into the cmp instruction.
RHS = DAG.getConstant(C->getSExtValue() + 1, DL, VT);
CC = ISD::SETGE;
break;
}
}
break;
}
// Swap operands and reverse the branching condition.
std::swap(LHS, RHS);
CC = ISD::SETLT;
break;
}
case ISD::SETLT: {
if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
switch (C->getSExtValue()) {
case 1: {
// Turn lhs < 1 into 0 >= lhs since 0 can be materialized with
// __zero_reg__ in lhs.
RHS = LHS;
LHS = DAG.getConstant(0, DL, VT);
CC = ISD::SETGE;
break;
}
case 0: {
// When doing lhs < 0 use a tst instruction on the top part of lhs
// and use brmi instead of using a chain of cp/cpc.
UseTest = true;
AVRcc = DAG.getConstant(AVRCC::COND_MI, DL, MVT::i8);
break;
}
}
}
break;
}
case ISD::SETULE: {
// Swap operands and reverse the branching condition.
std::swap(LHS, RHS);
CC = ISD::SETUGE;
break;
}
case ISD::SETUGT: {
// Turn lhs < rhs with lhs constant into rhs >= lhs+1, this allows us to
// fold the constant into the cmp instruction.
if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
RHS = DAG.getConstant(C->getSExtValue() + 1, DL, VT);
CC = ISD::SETUGE;
break;
}
// Swap operands and reverse the branching condition.
std::swap(LHS, RHS);
CC = ISD::SETULT;
break;
}
}
// Expand 32 and 64 bit comparisons with custom CMP and CMPC nodes instead of
// using the default and/or/xor expansion code which is much longer.
if (VT == MVT::i32) {
SDValue LHSlo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS,
DAG.getIntPtrConstant(0, DL));
SDValue LHShi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS,
DAG.getIntPtrConstant(1, DL));
SDValue RHSlo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS,
DAG.getIntPtrConstant(0, DL));
SDValue RHShi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS,
DAG.getIntPtrConstant(1, DL));
if (UseTest) {
// When using tst we only care about the highest part.
SDValue Top = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHShi,
DAG.getIntPtrConstant(1, DL));
Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue, Top);
} else {
Cmp = DAG.getNode(AVRISD::CMP, DL, MVT::Glue, LHSlo, RHSlo);
Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHShi, RHShi, Cmp);
}
} else if (VT == MVT::i64) {
SDValue LHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, LHS,
DAG.getIntPtrConstant(0, DL));
SDValue LHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, LHS,
DAG.getIntPtrConstant(1, DL));
SDValue LHS0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_0,
DAG.getIntPtrConstant(0, DL));
SDValue LHS1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_0,
DAG.getIntPtrConstant(1, DL));
SDValue LHS2 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_1,
DAG.getIntPtrConstant(0, DL));
SDValue LHS3 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_1,
DAG.getIntPtrConstant(1, DL));
SDValue RHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, RHS,
DAG.getIntPtrConstant(0, DL));
SDValue RHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, RHS,
DAG.getIntPtrConstant(1, DL));
SDValue RHS0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_0,
DAG.getIntPtrConstant(0, DL));
SDValue RHS1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_0,
DAG.getIntPtrConstant(1, DL));
SDValue RHS2 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_1,
DAG.getIntPtrConstant(0, DL));
SDValue RHS3 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_1,
DAG.getIntPtrConstant(1, DL));
if (UseTest) {
// When using tst we only care about the highest part.
SDValue Top = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHS3,
DAG.getIntPtrConstant(1, DL));
Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue, Top);
} else {
Cmp = DAG.getNode(AVRISD::CMP, DL, MVT::Glue, LHS0, RHS0);
Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHS1, RHS1, Cmp);
Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHS2, RHS2, Cmp);
Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHS3, RHS3, Cmp);
}
} else if (VT == MVT::i8 || VT == MVT::i16) {
if (UseTest) {
// When using tst we only care about the highest part.
Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue,
(VT == MVT::i8)
? LHS
: DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8,
LHS, DAG.getIntPtrConstant(1, DL)));
} else {
Cmp = DAG.getNode(AVRISD::CMP, DL, MVT::Glue, LHS, RHS);
}
} else {
llvm_unreachable("Invalid comparison size");
}
// When using a test instruction AVRcc is already set.
if (!UseTest) {
AVRcc = DAG.getConstant(intCCToAVRCC(CC), DL, MVT::i8);
}
return Cmp;
}
SDValue AVRTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
SDValue LHS = Op.getOperand(2);
SDValue RHS = Op.getOperand(3);
SDValue Dest = Op.getOperand(4);
SDLoc dl(Op);
SDValue TargetCC;
SDValue Cmp = getAVRCmp(LHS, RHS, CC, TargetCC, DAG, dl);
return DAG.getNode(AVRISD::BRCOND, dl, MVT::Other, Chain, Dest, TargetCC,
Cmp);
}
SDValue AVRTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
SDValue TrueV = Op.getOperand(2);
SDValue FalseV = Op.getOperand(3);
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
SDLoc dl(Op);
SDValue TargetCC;
SDValue Cmp = getAVRCmp(LHS, RHS, CC, TargetCC, DAG, dl);
SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
SDValue Ops[] = {TrueV, FalseV, TargetCC, Cmp};
return DAG.getNode(AVRISD::SELECT_CC, dl, VTs, Ops);
}
SDValue AVRTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
SDLoc DL(Op);
SDValue TargetCC;
SDValue Cmp = getAVRCmp(LHS, RHS, CC, TargetCC, DAG, DL);
SDValue TrueV = DAG.getConstant(1, DL, Op.getValueType());
SDValue FalseV = DAG.getConstant(0, DL, Op.getValueType());
SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
SDValue Ops[] = {TrueV, FalseV, TargetCC, Cmp};
return DAG.getNode(AVRISD::SELECT_CC, DL, VTs, Ops);
}
SDValue AVRTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const {
const MachineFunction &MF = DAG.getMachineFunction();
const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
auto DL = DAG.getDataLayout();
SDLoc dl(Op);
// Vastart just stores the address of the VarArgsFrameIndex slot into the
// memory location argument.
SDValue FI = DAG.getFrameIndex(AFI->getVarArgsFrameIndex(), getPointerTy(DL));
return DAG.getStore(Op.getOperand(0), dl, FI, Op.getOperand(1),
MachinePointerInfo(SV), 0);
}
SDValue AVRTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
default:
llvm_unreachable("Don't know how to custom lower this!");
case ISD::SHL:
case ISD::SRA:
case ISD::SRL:
case ISD::ROTL:
case ISD::ROTR:
return LowerShifts(Op, DAG);
case ISD::GlobalAddress:
return LowerGlobalAddress(Op, DAG);
case ISD::BlockAddress:
return LowerBlockAddress(Op, DAG);
case ISD::BR_CC:
return LowerBR_CC(Op, DAG);
case ISD::SELECT_CC:
return LowerSELECT_CC(Op, DAG);
case ISD::SETCC:
return LowerSETCC(Op, DAG);
case ISD::VASTART:
return LowerVASTART(Op, DAG);
case ISD::SDIVREM:
case ISD::UDIVREM:
return LowerDivRem(Op, DAG);
}
return SDValue();
}
/// Replace a node with an illegal result type
/// with a new node built out of custom code.
void AVRTargetLowering::ReplaceNodeResults(SDNode *N,
SmallVectorImpl<SDValue> &Results,
SelectionDAG &DAG) const {
SDLoc DL(N);
switch (N->getOpcode()) {
case ISD::ADD: {
// Convert add (x, imm) into sub (x, -imm).
if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
SDValue Sub = DAG.getNode(
ISD::SUB, DL, N->getValueType(0), N->getOperand(0),
DAG.getConstant(-C->getAPIntValue(), DL, C->getValueType(0)));
Results.push_back(Sub);
}
break;
}
default: {
SDValue Res = LowerOperation(SDValue(N, 0), DAG);
for (unsigned I = 0, E = Res->getNumValues(); I != E; ++I)
Results.push_back(Res.getValue(I));
break;
}
}
}
/// Return true if the addressing mode represented
/// by AM is legal for this target, for a load/store of the specified type.
bool AVRTargetLowering::isLegalAddressingMode(const DataLayout &DL,
const AddrMode &AM, Type *Ty,
unsigned AS, Instruction *I) const {
int64_t Offs = AM.BaseOffs;
// Allow absolute addresses.
if (AM.BaseGV && !AM.HasBaseReg && AM.Scale == 0 && Offs == 0) {
return true;
}
// Flash memory instructions only allow zero offsets.
if (isa<PointerType>(Ty) && AS == AVR::ProgramMemory) {
return false;
}
// Allow reg+<6bit> offset.
if (Offs < 0)
Offs = -Offs;
if (AM.BaseGV == 0 && AM.HasBaseReg && AM.Scale == 0 && isUInt<6>(Offs)) {
return true;
}
return false;
}
/// Returns true by value, base pointer and
/// offset pointer and addressing mode by reference if the node's address
/// can be legally represented as pre-indexed load / store address.
bool AVRTargetLowering::getPreIndexedAddressParts(SDNode *N, SDValue &Base,
SDValue &Offset,
ISD::MemIndexedMode &AM,
SelectionDAG &DAG) const {
EVT VT;
const SDNode *Op;
SDLoc DL(N);
if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
VT = LD->getMemoryVT();
Op = LD->getBasePtr().getNode();
if (LD->getExtensionType() != ISD::NON_EXTLOAD)
return false;
if (AVR::isProgramMemoryAccess(LD)) {
return false;
}
} else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
VT = ST->getMemoryVT();
Op = ST->getBasePtr().getNode();
if (AVR::isProgramMemoryAccess(ST)) {
return false;
}
} else {
return false;
}
if (VT != MVT::i8 && VT != MVT::i16) {
return false;
}
if (Op->getOpcode() != ISD::ADD && Op->getOpcode() != ISD::SUB) {
return false;
}
if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1))) {
int RHSC = RHS->getSExtValue();
if (Op->getOpcode() == ISD::SUB)
RHSC = -RHSC;
if ((VT == MVT::i16 && RHSC != -2) || (VT == MVT::i8 && RHSC != -1)) {
return false;
}
Base = Op->getOperand(0);
Offset = DAG.getConstant(RHSC, DL, MVT::i8);
AM = ISD::PRE_DEC;
return true;
}
return false;
}
/// Returns true by value, base pointer and
/// offset pointer and addressing mode by reference if this node can be
/// combined with a load / store to form a post-indexed load / store.
bool AVRTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op,
SDValue &Base,
SDValue &Offset,
ISD::MemIndexedMode &AM,
SelectionDAG &DAG) const {
EVT VT;
SDLoc DL(N);
if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
VT = LD->getMemoryVT();
if (LD->getExtensionType() != ISD::NON_EXTLOAD)
return false;
} else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
VT = ST->getMemoryVT();
if (AVR::isProgramMemoryAccess(ST)) {
return false;
}
} else {
return false;
}
if (VT != MVT::i8 && VT != MVT::i16) {
return false;
}
if (Op->getOpcode() != ISD::ADD && Op->getOpcode() != ISD::SUB) {
return false;
}
if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1))) {
int RHSC = RHS->getSExtValue();
if (Op->getOpcode() == ISD::SUB)
RHSC = -RHSC;
if ((VT == MVT::i16 && RHSC != 2) || (VT == MVT::i8 && RHSC != 1)) {
return false;
}
Base = Op->getOperand(0);
Offset = DAG.getConstant(RHSC, DL, MVT::i8);
AM = ISD::POST_INC;
return true;
}
return false;
}
bool AVRTargetLowering::isOffsetFoldingLegal(
const GlobalAddressSDNode *GA) const {
return true;
}
//===----------------------------------------------------------------------===//
// Formal Arguments Calling Convention Implementation
//===----------------------------------------------------------------------===//
#include "AVRGenCallingConv.inc"
/// For each argument in a function store the number of pieces it is composed
/// of.
static void parseFunctionArgs(const SmallVectorImpl<ISD::InputArg> &Ins,
SmallVectorImpl<unsigned> &Out) {
for (const ISD::InputArg &Arg : Ins) {
if(Arg.PartOffset > 0) continue;
unsigned Bytes = ((Arg.ArgVT.getSizeInBits()) + 7) / 8;
Out.push_back((Bytes + 1) / 2);
}
}
/// For external symbols there is no function prototype information so we
/// have to rely directly on argument sizes.
static void parseExternFuncCallArgs(const SmallVectorImpl<ISD::OutputArg> &In,
SmallVectorImpl<unsigned> &Out) {
for (unsigned i = 0, e = In.size(); i != e;) {
unsigned Size = 0;
unsigned Offset = 0;
while ((i != e) && (In[i].PartOffset == Offset)) {
Offset += In[i].VT.getStoreSize();
++i;
++Size;
}
Out.push_back(Size);
}
}
static StringRef getFunctionName(TargetLowering::CallLoweringInfo &CLI) {
SDValue Callee = CLI.Callee;
if (const ExternalSymbolSDNode *G = dyn_cast<ExternalSymbolSDNode>(Callee)) {
return G->getSymbol();
}
if (const GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
return G->getGlobal()->getName();
}
llvm_unreachable("don't know how to get the name for this callee");
}
/// Analyze incoming and outgoing function arguments. We need custom C++ code
/// to handle special constraints in the ABI like reversing the order of the
/// pieces of splitted arguments. In addition, all pieces of a certain argument
/// have to be passed either using registers or the stack but never mixing both.
static void analyzeStandardArguments(TargetLowering::CallLoweringInfo *CLI,
const Function *F, const DataLayout *TD,
const SmallVectorImpl<ISD::OutputArg> *Outs,
const SmallVectorImpl<ISD::InputArg> *Ins,
CallingConv::ID CallConv,
SmallVectorImpl<CCValAssign> &ArgLocs,
CCState &CCInfo, bool IsCall, bool IsVarArg) {
static const MCPhysReg RegList8[] = {AVR::R24, AVR::R22, AVR::R20,
AVR::R18, AVR::R16, AVR::R14,
AVR::R12, AVR::R10, AVR::R8};
static const MCPhysReg RegList16[] = {AVR::R25R24, AVR::R23R22, AVR::R21R20,
AVR::R19R18, AVR::R17R16, AVR::R15R14,
AVR::R13R12, AVR::R11R10, AVR::R9R8};
if (IsVarArg) {
// Variadic functions do not need all the analisys below.
if (IsCall) {
CCInfo.AnalyzeCallOperands(*Outs, ArgCC_AVR_Vararg);
} else {
CCInfo.AnalyzeFormalArguments(*Ins, ArgCC_AVR_Vararg);
}
return;
}
// Fill in the Args array which will contain original argument sizes.
SmallVector<unsigned, 8> Args;
if (IsCall) {
parseExternFuncCallArgs(*Outs, Args);
} else {
assert(F != nullptr && "function should not be null");
parseFunctionArgs(*Ins, Args);
}
unsigned RegsLeft = array_lengthof(RegList8), ValNo = 0;
// Variadic functions always use the stack.
bool UsesStack = false;
for (unsigned i = 0, pos = 0, e = Args.size(); i != e; ++i) {
unsigned Size = Args[i];
// If we have a zero-sized argument, don't attempt to lower it.
// AVR-GCC does not support zero-sized arguments and so we need not
// worry about ABI compatibility.
if (Size == 0) continue;
MVT LocVT = (IsCall) ? (*Outs)[pos].VT : (*Ins)[pos].VT;
// If we have plenty of regs to pass the whole argument do it.
if (!UsesStack && (Size <= RegsLeft)) {
const MCPhysReg *RegList = (LocVT == MVT::i16) ? RegList16 : RegList8;
for (unsigned j = 0; j != Size; ++j) {
unsigned Reg = CCInfo.AllocateReg(
ArrayRef<MCPhysReg>(RegList, array_lengthof(RegList8)));
CCInfo.addLoc(
CCValAssign::getReg(ValNo++, LocVT, Reg, LocVT, CCValAssign::Full));
--RegsLeft;
}
// Reverse the order of the pieces to agree with the "big endian" format
// required in the calling convention ABI.
std::reverse(ArgLocs.begin() + pos, ArgLocs.begin() + pos + Size);
} else {
// Pass the rest of arguments using the stack.
UsesStack = true;
for (unsigned j = 0; j != Size; ++j) {
unsigned Offset = CCInfo.AllocateStack(
TD->getTypeAllocSize(EVT(LocVT).getTypeForEVT(CCInfo.getContext())),
TD->getABITypeAlignment(
EVT(LocVT).getTypeForEVT(CCInfo.getContext())));
CCInfo.addLoc(CCValAssign::getMem(ValNo++, LocVT, Offset, LocVT,
CCValAssign::Full));
}
}
pos += Size;
}
}
static void analyzeBuiltinArguments(TargetLowering::CallLoweringInfo &CLI,
const Function *F, const DataLayout *TD,
const SmallVectorImpl<ISD::OutputArg> *Outs,
const SmallVectorImpl<ISD::InputArg> *Ins,
CallingConv::ID CallConv,
SmallVectorImpl<CCValAssign> &ArgLocs,
CCState &CCInfo, bool IsCall, bool IsVarArg) {
StringRef FuncName = getFunctionName(CLI);
if (FuncName.startswith("__udivmod") || FuncName.startswith("__divmod")) {
CCInfo.AnalyzeCallOperands(*Outs, ArgCC_AVR_BUILTIN_DIV);
} else {
analyzeStandardArguments(&CLI, F, TD, Outs, Ins,
CallConv, ArgLocs, CCInfo,
IsCall, IsVarArg);
}
}
static void analyzeArguments(TargetLowering::CallLoweringInfo *CLI,
const Function *F, const DataLayout *TD,
const SmallVectorImpl<ISD::OutputArg> *Outs,
const SmallVectorImpl<ISD::InputArg> *Ins,
CallingConv::ID CallConv,
SmallVectorImpl<CCValAssign> &ArgLocs,
CCState &CCInfo, bool IsCall, bool IsVarArg) {
switch (CallConv) {
case CallingConv::AVR_BUILTIN: {
analyzeBuiltinArguments(*CLI, F, TD, Outs, Ins,
CallConv, ArgLocs, CCInfo,
IsCall, IsVarArg);
return;
}
default: {
analyzeStandardArguments(CLI, F, TD, Outs, Ins,
CallConv, ArgLocs, CCInfo,
IsCall, IsVarArg);
return;
}
}
}
SDValue AVRTargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const {
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo &MFI = MF.getFrameInfo();
auto DL = DAG.getDataLayout();
// Assign locations to all of the incoming arguments.
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
*DAG.getContext());
analyzeArguments(nullptr, &MF.getFunction(), &DL, 0, &Ins, CallConv, ArgLocs, CCInfo,
false, isVarArg);
SDValue ArgValue;
for (CCValAssign &VA : ArgLocs) {
// Arguments stored on registers.
if (VA.isRegLoc()) {
EVT RegVT = VA.getLocVT();
const TargetRegisterClass *RC;
if (RegVT == MVT::i8) {
RC = &AVR::GPR8RegClass;
} else if (RegVT == MVT::i16) {
RC = &AVR::DREGSRegClass;
} else {
llvm_unreachable("Unknown argument type!");
}
unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC);
ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT);
// :NOTE: Clang should not promote any i8 into i16 but for safety the
// following code will handle zexts or sexts generated by other
// front ends. Otherwise:
// If this is an 8 bit value, it is really passed promoted
// to 16 bits. Insert an assert[sz]ext to capture this, then
// truncate to the right size.
switch (VA.getLocInfo()) {
default:
llvm_unreachable("Unknown loc info!");
case CCValAssign::Full:
break;
case CCValAssign::BCvt:
ArgValue = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), ArgValue);
break;
case CCValAssign::SExt:
ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue,
DAG.getValueType(VA.getValVT()));
ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
break;
case CCValAssign::ZExt:
ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue,
DAG.getValueType(VA.getValVT()));
ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
break;
}
InVals.push_back(ArgValue);
} else {
// Sanity check.
assert(VA.isMemLoc());
EVT LocVT = VA.getLocVT();
// Create the frame index object for this incoming parameter.
int FI = MFI.CreateFixedObject(LocVT.getSizeInBits() / 8,
VA.getLocMemOffset(), true);
// Create the SelectionDAG nodes corresponding to a load
// from this parameter.
SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DL));
InVals.push_back(DAG.getLoad(LocVT, dl, Chain, FIN,
MachinePointerInfo::getFixedStack(MF, FI),
0));
}
}
// If the function takes variable number of arguments, make a frame index for
// the start of the first vararg value... for expansion of llvm.va_start.
if (isVarArg) {
unsigned StackSize = CCInfo.getNextStackOffset();
AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
AFI->setVarArgsFrameIndex(MFI.CreateFixedObject(2, StackSize, true));
}
return Chain;
}
//===----------------------------------------------------------------------===//
// Call Calling Convention Implementation
//===----------------------------------------------------------------------===//
SDValue AVRTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const {
SelectionDAG &DAG = CLI.DAG;
SDLoc &DL = CLI.DL;
SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
SDValue Chain = CLI.Chain;
SDValue Callee = CLI.Callee;
bool &isTailCall = CLI.IsTailCall;
CallingConv::ID CallConv = CLI.CallConv;
bool isVarArg = CLI.IsVarArg;
MachineFunction &MF = DAG.getMachineFunction();
// AVR does not yet support tail call optimization.
isTailCall = false;
// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
*DAG.getContext());
// If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
// direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
// node so that legalize doesn't hack it.
const Function *F = nullptr;
if (const GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
const GlobalValue *GV = G->getGlobal();
F = cast<Function>(GV);
Callee =
DAG.getTargetGlobalAddress(GV, DL, getPointerTy(DAG.getDataLayout()));
} else if (const ExternalSymbolSDNode *ES =
dyn_cast<ExternalSymbolSDNode>(Callee)) {
Callee = DAG.getTargetExternalSymbol(ES->getSymbol(),
getPointerTy(DAG.getDataLayout()));
}
analyzeArguments(&CLI, F, &DAG.getDataLayout(), &Outs, 0, CallConv, ArgLocs, CCInfo,
true, isVarArg);
// Get a count of how many bytes are to be pushed on the stack.
unsigned NumBytes = CCInfo.getNextStackOffset();
Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, DL);
SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
// First, walk the register assignments, inserting copies.
unsigned AI, AE;
bool HasStackArgs = false;
for (AI = 0, AE = ArgLocs.size(); AI != AE; ++AI) {
CCValAssign &VA = ArgLocs[AI];
EVT RegVT = VA.getLocVT();
SDValue Arg = OutVals[AI];
// Promote the value if needed. With Clang this should not happen.
switch (VA.getLocInfo()) {
default:
llvm_unreachable("Unknown loc info!");
case CCValAssign::Full:
break;
case CCValAssign::SExt:
Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, RegVT, Arg);
break;
case CCValAssign::ZExt:
Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, RegVT, Arg);
break;
case CCValAssign::AExt:
Arg = DAG.getNode(ISD::ANY_EXTEND, DL, RegVT, Arg);
break;
case CCValAssign::BCvt:
Arg = DAG.getNode(ISD::BITCAST, DL, RegVT, Arg);
break;
}
// Stop when we encounter a stack argument, we need to process them
// in reverse order in the loop below.
if (VA.isMemLoc()) {
HasStackArgs = true;
break;
}
// Arguments that can be passed on registers must be kept in the RegsToPass
// vector.
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
}
// Second, stack arguments have to walked in reverse order by inserting
// chained stores, this ensures their order is not changed by the scheduler
// and that the push instruction sequence generated is correct, otherwise they
// can be freely intermixed.
if (HasStackArgs) {
for (AE = AI, AI = ArgLocs.size(); AI != AE; --AI) {
unsigned Loc = AI - 1;
CCValAssign &VA = ArgLocs[Loc];
SDValue Arg = OutVals[Loc];
assert(VA.isMemLoc());
// SP points to one stack slot further so add one to adjust it.
SDValue PtrOff = DAG.getNode(
ISD::ADD, DL, getPointerTy(DAG.getDataLayout()),
DAG.getRegister(AVR::SP, getPointerTy(DAG.getDataLayout())),
DAG.getIntPtrConstant(VA.getLocMemOffset() + 1, DL));
Chain =
DAG.getStore(Chain, DL, Arg, PtrOff,
MachinePointerInfo::getStack(MF, VA.getLocMemOffset()),
0);
}
}
// Build a sequence of copy-to-reg nodes chained together with token chain and
// flag operands which copy the outgoing args into registers. The InFlag in
// necessary since all emited instructions must be stuck together.
SDValue InFlag;
for (auto Reg : RegsToPass) {
Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, InFlag);
InFlag = Chain.getValue(1);
}
// Returns a chain & a flag for retval copy to use.
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
SmallVector<SDValue, 8> Ops;
Ops.push_back(Chain);
Ops.push_back(Callee);
// Add argument registers to the end of the list so that they are known live
// into the call.
for (auto Reg : RegsToPass) {
Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
}
// Add a register mask operand representing the call-preserved registers.
const AVRTargetMachine &TM = (const AVRTargetMachine &)getTargetMachine();
- const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo();
+ const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
const uint32_t *Mask =
TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv);
assert(Mask && "Missing call preserved mask for calling convention");
Ops.push_back(DAG.getRegisterMask(Mask));
if (InFlag.getNode()) {
Ops.push_back(InFlag);
}
Chain = DAG.getNode(AVRISD::CALL, DL, NodeTys, Ops);
InFlag = Chain.getValue(1);
// Create the CALLSEQ_END node.
Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, DL, true),
DAG.getIntPtrConstant(0, DL, true), InFlag, DL);
if (!Ins.empty()) {
InFlag = Chain.getValue(1);
}
// Handle result values, copying them out of physregs into vregs that we
// return.
return LowerCallResult(Chain, InFlag, CallConv, isVarArg, Ins, DL, DAG,
InVals);
}
/// Lower the result values of a call into the
/// appropriate copies out of appropriate physical registers.
///
SDValue AVRTargetLowering::LowerCallResult(
SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const {
// Assign locations to each value returned by this call.
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,
*DAG.getContext());
// Handle runtime calling convs.
auto CCFunction = CCAssignFnForReturn(CallConv);
CCInfo.AnalyzeCallResult(Ins, CCFunction);
if (CallConv != CallingConv::AVR_BUILTIN && RVLocs.size() > 1) {
// Reverse splitted return values to get the "big endian" format required
// to agree with the calling convention ABI.
std::reverse(RVLocs.begin(), RVLocs.end());
}
// Copy all of the result registers out of their specified physreg.
for (CCValAssign const &RVLoc : RVLocs) {
Chain = DAG.getCopyFromReg(Chain, dl, RVLoc.getLocReg(), RVLoc.getValVT(),
InFlag)
.getValue(1);
InFlag = Chain.getValue(2);
InVals.push_back(Chain.getValue(0));
}
return Chain;
}
//===----------------------------------------------------------------------===//
// Return Value Calling Convention Implementation
//===----------------------------------------------------------------------===//
CCAssignFn *AVRTargetLowering::CCAssignFnForReturn(CallingConv::ID CC) const {
switch (CC) {
case CallingConv::AVR_BUILTIN:
return RetCC_AVR_BUILTIN;
default:
return RetCC_AVR;
}
}
bool
AVRTargetLowering::CanLowerReturn(CallingConv::ID CallConv,
MachineFunction &MF, bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
LLVMContext &Context) const
{
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallConv, isVarArg, MF, RVLocs, Context);
auto CCFunction = CCAssignFnForReturn(CallConv);
return CCInfo.CheckReturn(Outs, CCFunction);
}
SDValue
AVRTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
const SDLoc &dl, SelectionDAG &DAG) const {
// CCValAssign - represent the assignment of the return value to locations.
SmallVector<CCValAssign, 16> RVLocs;
// CCState - Info about the registers and stack slot.
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,
*DAG.getContext());
// Analyze return values.
auto CCFunction = CCAssignFnForReturn(CallConv);
CCInfo.AnalyzeReturn(Outs, CCFunction);
// If this is the first return lowered for this function, add the regs to
// the liveout set for the function.
MachineFunction &MF = DAG.getMachineFunction();
unsigned e = RVLocs.size();
// Reverse splitted return values to get the "big endian" format required
// to agree with the calling convention ABI.
if (e > 1) {
std::reverse(RVLocs.begin(), RVLocs.end());
}
SDValue Flag;
SmallVector<SDValue, 4> RetOps(1, Chain);
// Copy the result values into the output registers.
for (unsigned i = 0; i != e; ++i) {
CCValAssign &VA = RVLocs[i];
assert(VA.isRegLoc() && "Can only return in registers!");
Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Flag);
// Guarantee that all emitted copies are stuck together with flags.
Flag = Chain.getValue(1);
RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
}
// Don't emit the ret/reti instruction when the naked attribute is present in
// the function being compiled.
if (MF.getFunction().getAttributes().hasAttribute(
AttributeList::FunctionIndex, Attribute::Naked)) {
return Chain;
}
unsigned RetOpc =
(CallConv == CallingConv::AVR_INTR || CallConv == CallingConv::AVR_SIGNAL)
? AVRISD::RETI_FLAG
: AVRISD::RET_FLAG;
RetOps[0] = Chain; // Update chain.
if (Flag.getNode()) {
RetOps.push_back(Flag);
}
return DAG.getNode(RetOpc, dl, MVT::Other, RetOps);
}
//===----------------------------------------------------------------------===//
// Custom Inserters
//===----------------------------------------------------------------------===//
MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr &MI,
MachineBasicBlock *BB) const {
unsigned Opc;
const TargetRegisterClass *RC;
bool HasRepeatedOperand = false;
MachineFunction *F = BB->getParent();
MachineRegisterInfo &RI = F->getRegInfo();
const AVRTargetMachine &TM = (const AVRTargetMachine &)getTargetMachine();
- const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
+ const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
DebugLoc dl = MI.getDebugLoc();
switch (MI.getOpcode()) {
default:
llvm_unreachable("Invalid shift opcode!");
case AVR::Lsl8:
Opc = AVR::ADDRdRr; // LSL is an alias of ADD Rd, Rd
RC = &AVR::GPR8RegClass;
HasRepeatedOperand = true;
break;
case AVR::Lsl16:
Opc = AVR::LSLWRd;
RC = &AVR::DREGSRegClass;
break;
case AVR::Asr8:
Opc = AVR::ASRRd;
RC = &AVR::GPR8RegClass;
break;
case AVR::Asr16:
Opc = AVR::ASRWRd;
RC = &AVR::DREGSRegClass;
break;
case AVR::Lsr8:
Opc = AVR::LSRRd;
RC = &AVR::GPR8RegClass;
break;
case AVR::Lsr16:
Opc = AVR::LSRWRd;
RC = &AVR::DREGSRegClass;
break;
case AVR::Rol8:
Opc = AVR::ADCRdRr; // ROL is an alias of ADC Rd, Rd
RC = &AVR::GPR8RegClass;
HasRepeatedOperand = true;
break;
case AVR::Rol16:
Opc = AVR::ROLWRd;
RC = &AVR::DREGSRegClass;
break;
case AVR::Ror8:
Opc = AVR::RORRd;
RC = &AVR::GPR8RegClass;
break;
case AVR::Ror16:
Opc = AVR::RORWRd;
RC = &AVR::DREGSRegClass;
break;
}
const BasicBlock *LLVM_BB = BB->getBasicBlock();
MachineFunction::iterator I;
for (I = BB->getIterator(); I != F->end() && &(*I) != BB; ++I);
if (I != F->end()) ++I;
// Create loop block.
MachineBasicBlock *LoopBB = F->CreateMachineBasicBlock(LLVM_BB);
MachineBasicBlock *RemBB = F->CreateMachineBasicBlock(LLVM_BB);
F->insert(I, LoopBB);
F->insert(I, RemBB);
// Update machine-CFG edges by transferring all successors of the current
// block to the block containing instructions after shift.
RemBB->splice(RemBB->begin(), BB, std::next(MachineBasicBlock::iterator(MI)),
BB->end());
RemBB->transferSuccessorsAndUpdatePHIs(BB);
// Add adges BB => LoopBB => RemBB, BB => RemBB, LoopBB => LoopBB.
BB->addSuccessor(LoopBB);
BB->addSuccessor(RemBB);
LoopBB->addSuccessor(RemBB);
LoopBB->addSuccessor(LoopBB);
unsigned ShiftAmtReg = RI.createVirtualRegister(&AVR::LD8RegClass);
unsigned ShiftAmtReg2 = RI.createVirtualRegister(&AVR::LD8RegClass);
unsigned ShiftReg = RI.createVirtualRegister(RC);
unsigned ShiftReg2 = RI.createVirtualRegister(RC);
unsigned ShiftAmtSrcReg = MI.getOperand(2).getReg();
unsigned SrcReg = MI.getOperand(1).getReg();
unsigned DstReg = MI.getOperand(0).getReg();
// BB:
// cpi N, 0
// breq RemBB
BuildMI(BB, dl, TII.get(AVR::CPIRdK)).addReg(ShiftAmtSrcReg).addImm(0);
BuildMI(BB, dl, TII.get(AVR::BREQk)).addMBB(RemBB);
// LoopBB:
// ShiftReg = phi [%SrcReg, BB], [%ShiftReg2, LoopBB]
// ShiftAmt = phi [%N, BB], [%ShiftAmt2, LoopBB]
// ShiftReg2 = shift ShiftReg
// ShiftAmt2 = ShiftAmt - 1;
BuildMI(LoopBB, dl, TII.get(AVR::PHI), ShiftReg)
.addReg(SrcReg)
.addMBB(BB)
.addReg(ShiftReg2)
.addMBB(LoopBB);
BuildMI(LoopBB, dl, TII.get(AVR::PHI), ShiftAmtReg)
.addReg(ShiftAmtSrcReg)
.addMBB(BB)
.addReg(ShiftAmtReg2)
.addMBB(LoopBB);
auto ShiftMI = BuildMI(LoopBB, dl, TII.get(Opc), ShiftReg2).addReg(ShiftReg);
if (HasRepeatedOperand)
ShiftMI.addReg(ShiftReg);
BuildMI(LoopBB, dl, TII.get(AVR::SUBIRdK), ShiftAmtReg2)
.addReg(ShiftAmtReg)
.addImm(1);
BuildMI(LoopBB, dl, TII.get(AVR::BRNEk)).addMBB(LoopBB);
// RemBB:
// DestReg = phi [%SrcReg, BB], [%ShiftReg, LoopBB]
BuildMI(*RemBB, RemBB->begin(), dl, TII.get(AVR::PHI), DstReg)
.addReg(SrcReg)
.addMBB(BB)
.addReg(ShiftReg2)
.addMBB(LoopBB);
MI.eraseFromParent(); // The pseudo instruction is gone now.
return RemBB;
}
static bool isCopyMulResult(MachineBasicBlock::iterator const &I) {
if (I->getOpcode() == AVR::COPY) {
unsigned SrcReg = I->getOperand(1).getReg();
return (SrcReg == AVR::R0 || SrcReg == AVR::R1);
}
return false;
}
// The mul instructions wreak havock on our zero_reg R1. We need to clear it
// after the result has been evacuated. This is probably not the best way to do
// it, but it works for now.
MachineBasicBlock *AVRTargetLowering::insertMul(MachineInstr &MI,
MachineBasicBlock *BB) const {
const AVRTargetMachine &TM = (const AVRTargetMachine &)getTargetMachine();
- const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
+ const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
MachineBasicBlock::iterator I(MI);
++I; // in any case insert *after* the mul instruction
if (isCopyMulResult(I))
++I;
if (isCopyMulResult(I))
++I;
BuildMI(*BB, I, MI.getDebugLoc(), TII.get(AVR::EORRdRr), AVR::R1)
.addReg(AVR::R1)
.addReg(AVR::R1);
return BB;
}
MachineBasicBlock *
AVRTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *MBB) const {
int Opc = MI.getOpcode();
// Pseudo shift instructions with a non constant shift amount are expanded
// into a loop.
switch (Opc) {
case AVR::Lsl8:
case AVR::Lsl16:
case AVR::Lsr8:
case AVR::Lsr16:
case AVR::Rol8:
case AVR::Rol16:
case AVR::Ror8:
case AVR::Ror16:
case AVR::Asr8:
case AVR::Asr16:
return insertShift(MI, MBB);
case AVR::MULRdRr:
case AVR::MULSRdRr:
return insertMul(MI, MBB);
}
assert((Opc == AVR::Select16 || Opc == AVR::Select8) &&
"Unexpected instr type to insert");
const AVRInstrInfo &TII = (const AVRInstrInfo &)*MI.getParent()
->getParent()
->getSubtarget()
.getInstrInfo();
DebugLoc dl = MI.getDebugLoc();
// To "insert" a SELECT instruction, we insert the diamond
// control-flow pattern. The incoming instruction knows the
// destination vreg to set, the condition code register to branch
// on, the true/false values to select between, and a branch opcode
// to use.
MachineFunction *MF = MBB->getParent();
const BasicBlock *LLVM_BB = MBB->getBasicBlock();
MachineBasicBlock *trueMBB = MF->CreateMachineBasicBlock(LLVM_BB);
MachineBasicBlock *falseMBB = MF->CreateMachineBasicBlock(LLVM_BB);
MachineFunction::iterator I;
for (I = MF->begin(); I != MF->end() && &(*I) != MBB; ++I);
if (I != MF->end()) ++I;
MF->insert(I, trueMBB);
MF->insert(I, falseMBB);
// Transfer remaining instructions and all successors of the current
// block to the block which will contain the Phi node for the
// select.
trueMBB->splice(trueMBB->begin(), MBB,
std::next(MachineBasicBlock::iterator(MI)), MBB->end());
trueMBB->transferSuccessorsAndUpdatePHIs(MBB);
AVRCC::CondCodes CC = (AVRCC::CondCodes)MI.getOperand(3).getImm();
BuildMI(MBB, dl, TII.getBrCond(CC)).addMBB(trueMBB);
BuildMI(MBB, dl, TII.get(AVR::RJMPk)).addMBB(falseMBB);
MBB->addSuccessor(falseMBB);
MBB->addSuccessor(trueMBB);
// Unconditionally flow back to the true block
BuildMI(falseMBB, dl, TII.get(AVR::RJMPk)).addMBB(trueMBB);
falseMBB->addSuccessor(trueMBB);
// Set up the Phi node to determine where we came from
BuildMI(*trueMBB, trueMBB->begin(), dl, TII.get(AVR::PHI), MI.getOperand(0).getReg())
.addReg(MI.getOperand(1).getReg())
.addMBB(MBB)
.addReg(MI.getOperand(2).getReg())
.addMBB(falseMBB) ;
MI.eraseFromParent(); // The pseudo instruction is gone now.
return trueMBB;
}
//===----------------------------------------------------------------------===//
// Inline Asm Support
//===----------------------------------------------------------------------===//
AVRTargetLowering::ConstraintType
AVRTargetLowering::getConstraintType(StringRef Constraint) const {
if (Constraint.size() == 1) {
// See http://www.nongnu.org/avr-libc/user-manual/inline_asm.html
switch (Constraint[0]) {
case 'a': // Simple upper registers
case 'b': // Base pointer registers pairs
case 'd': // Upper register
case 'l': // Lower registers
case 'e': // Pointer register pairs
case 'q': // Stack pointer register
case 'r': // Any register
case 'w': // Special upper register pairs
return C_RegisterClass;
case 't': // Temporary register
case 'x': case 'X': // Pointer register pair X
case 'y': case 'Y': // Pointer register pair Y
case 'z': case 'Z': // Pointer register pair Z
return C_Register;
case 'Q': // A memory address based on Y or Z pointer with displacement.
return C_Memory;
case 'G': // Floating point constant
case 'I': // 6-bit positive integer constant
case 'J': // 6-bit negative integer constant
case 'K': // Integer constant (Range: 2)
case 'L': // Integer constant (Range: 0)
case 'M': // 8-bit integer constant
case 'N': // Integer constant (Range: -1)
case 'O': // Integer constant (Range: 8, 16, 24)
case 'P': // Integer constant (Range: 1)
case 'R': // Integer constant (Range: -6 to 5)x
return C_Other;
default:
break;
}
}
return TargetLowering::getConstraintType(Constraint);
}
unsigned
AVRTargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const {
// Not sure if this is actually the right thing to do, but we got to do
// *something* [agnat]
switch (ConstraintCode[0]) {
case 'Q':
return InlineAsm::Constraint_Q;
}
return TargetLowering::getInlineAsmMemConstraint(ConstraintCode);
}
AVRTargetLowering::ConstraintWeight
AVRTargetLowering::getSingleConstraintMatchWeight(
AsmOperandInfo &info, const char *constraint) const {
ConstraintWeight weight = CW_Invalid;
Value *CallOperandVal = info.CallOperandVal;
// If we don't have a value, we can't do a match,
// but allow it at the lowest weight.
// (this behaviour has been copied from the ARM backend)
if (!CallOperandVal) {
return CW_Default;
}
// Look at the constraint type.
switch (*constraint) {
default:
weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint);
break;
case 'd':
case 'r':
case 'l':
weight = CW_Register;
break;
case 'a':
case 'b':
case 'e':
case 'q':
case 't':
case 'w':
case 'x': case 'X':
case 'y': case 'Y':
case 'z': case 'Z':
weight = CW_SpecificReg;
break;
case 'G':
if (const ConstantFP *C = dyn_cast<ConstantFP>(CallOperandVal)) {
if (C->isZero()) {
weight = CW_Constant;
}
}
break;
case 'I':
if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
if (isUInt<6>(C->getZExtValue())) {
weight = CW_Constant;
}
}
break;
case 'J':
if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
if ((C->getSExtValue() >= -63) && (C->getSExtValue() <= 0)) {
weight = CW_Constant;
}
}
break;
case 'K':
if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
if (C->getZExtValue() == 2) {
weight = CW_Constant;
}
}
break;
case 'L':
if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
if (C->getZExtValue() == 0) {
weight = CW_Constant;
}
}
break;
case 'M':
if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
if (isUInt<8>(C->getZExtValue())) {
weight = CW_Constant;
}
}
break;
case 'N':
if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
if (C->getSExtValue() == -1) {
weight = CW_Constant;
}
}
break;
case 'O':
if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
if ((C->getZExtValue() == 8) || (C->getZExtValue() == 16) ||
(C->getZExtValue() == 24)) {
weight = CW_Constant;
}
}
break;
case 'P':
if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
if (C->getZExtValue() == 1) {
weight = CW_Constant;
}
}
break;
case 'R':
if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
if ((C->getSExtValue() >= -6) && (C->getSExtValue() <= 5)) {
weight = CW_Constant;
}
}
break;
case 'Q':
weight = CW_Memory;
break;
}
return weight;
}
std::pair<unsigned, const TargetRegisterClass *>
AVRTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
StringRef Constraint,
MVT VT) const {
- auto STI = static_cast<const AVRTargetMachine &>(this->getTargetMachine())
- .getSubtargetImpl();
-
// We only support i8 and i16.
//
//:FIXME: remove this assert for now since it gets sometimes executed
// assert((VT == MVT::i16 || VT == MVT::i8) && "Wrong operand type.");
if (Constraint.size() == 1) {
switch (Constraint[0]) {
case 'a': // Simple upper registers r16..r23.
return std::make_pair(0U, &AVR::LD8loRegClass);
case 'b': // Base pointer registers: y, z.
return std::make_pair(0U, &AVR::PTRDISPREGSRegClass);
case 'd': // Upper registers r16..r31.
return std::make_pair(0U, &AVR::LD8RegClass);
case 'l': // Lower registers r0..r15.
return std::make_pair(0U, &AVR::GPR8loRegClass);
case 'e': // Pointer register pairs: x, y, z.
return std::make_pair(0U, &AVR::PTRREGSRegClass);
case 'q': // Stack pointer register: SPH:SPL.
return std::make_pair(0U, &AVR::GPRSPRegClass);
case 'r': // Any register: r0..r31.
if (VT == MVT::i8)
return std::make_pair(0U, &AVR::GPR8RegClass);
assert(VT == MVT::i16 && "inline asm constraint too large");
return std::make_pair(0U, &AVR::DREGSRegClass);
case 't': // Temporary register: r0.
return std::make_pair(unsigned(AVR::R0), &AVR::GPR8RegClass);
case 'w': // Special upper register pairs: r24, r26, r28, r30.
return std::make_pair(0U, &AVR::IWREGSRegClass);
case 'x': // Pointer register pair X: r27:r26.
case 'X':
return std::make_pair(unsigned(AVR::R27R26), &AVR::PTRREGSRegClass);
case 'y': // Pointer register pair Y: r29:r28.
case 'Y':
return std::make_pair(unsigned(AVR::R29R28), &AVR::PTRREGSRegClass);
case 'z': // Pointer register pair Z: r31:r30.
case 'Z':
return std::make_pair(unsigned(AVR::R31R30), &AVR::PTRREGSRegClass);
default:
break;
}
}
- return TargetLowering::getRegForInlineAsmConstraint(STI->getRegisterInfo(),
- Constraint, VT);
+ return TargetLowering::getRegForInlineAsmConstraint(
+ Subtarget.getRegisterInfo(), Constraint, VT);
}
void AVRTargetLowering::LowerAsmOperandForConstraint(SDValue Op,
std::string &Constraint,
std::vector<SDValue> &Ops,
SelectionDAG &DAG) const {
SDValue Result(0, 0);
SDLoc DL(Op);
EVT Ty = Op.getValueType();
// Currently only support length 1 constraints.
if (Constraint.length() != 1) {
return;
}
char ConstraintLetter = Constraint[0];
switch (ConstraintLetter) {
default:
break;
// Deal with integers first:
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'R': {
const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op);
if (!C) {
return;
}
int64_t CVal64 = C->getSExtValue();
uint64_t CUVal64 = C->getZExtValue();
switch (ConstraintLetter) {
case 'I': // 0..63
if (!isUInt<6>(CUVal64))
return;
Result = DAG.getTargetConstant(CUVal64, DL, Ty);
break;
case 'J': // -63..0
if (CVal64 < -63 || CVal64 > 0)
return;
Result = DAG.getTargetConstant(CVal64, DL, Ty);
break;
case 'K': // 2
if (CUVal64 != 2)
return;
Result = DAG.getTargetConstant(CUVal64, DL, Ty);
break;
case 'L': // 0
if (CUVal64 != 0)
return;
Result = DAG.getTargetConstant(CUVal64, DL, Ty);
break;
case 'M': // 0..255
if (!isUInt<8>(CUVal64))
return;
// i8 type may be printed as a negative number,
// e.g. 254 would be printed as -2,
// so we force it to i16 at least.
if (Ty.getSimpleVT() == MVT::i8) {
Ty = MVT::i16;
}
Result = DAG.getTargetConstant(CUVal64, DL, Ty);
break;
case 'N': // -1
if (CVal64 != -1)
return;
Result = DAG.getTargetConstant(CVal64, DL, Ty);
break;
case 'O': // 8, 16, 24
if (CUVal64 != 8 && CUVal64 != 16 && CUVal64 != 24)
return;
Result = DAG.getTargetConstant(CUVal64, DL, Ty);
break;
case 'P': // 1
if (CUVal64 != 1)
return;
Result = DAG.getTargetConstant(CUVal64, DL, Ty);
break;
case 'R': // -6..5
if (CVal64 < -6 || CVal64 > 5)
return;
Result = DAG.getTargetConstant(CVal64, DL, Ty);
break;
}
break;
}
case 'G':
const ConstantFPSDNode *FC = dyn_cast<ConstantFPSDNode>(Op);
if (!FC || !FC->isZero())
return;
// Soften float to i8 0
Result = DAG.getTargetConstant(0, DL, MVT::i8);
break;
}
if (Result.getNode()) {
Ops.push_back(Result);
return;
}
return TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
}
unsigned AVRTargetLowering::getRegisterByName(const char *RegName,
EVT VT,
SelectionDAG &DAG) const {
unsigned Reg;
if (VT == MVT::i8) {
Reg = StringSwitch<unsigned>(RegName)
.Case("r0", AVR::R0).Case("r1", AVR::R1).Case("r2", AVR::R2)
.Case("r3", AVR::R3).Case("r4", AVR::R4).Case("r5", AVR::R5)
.Case("r6", AVR::R6).Case("r7", AVR::R7).Case("r8", AVR::R8)
.Case("r9", AVR::R9).Case("r10", AVR::R10).Case("r11", AVR::R11)
.Case("r12", AVR::R12).Case("r13", AVR::R13).Case("r14", AVR::R14)
.Case("r15", AVR::R15).Case("r16", AVR::R16).Case("r17", AVR::R17)
.Case("r18", AVR::R18).Case("r19", AVR::R19).Case("r20", AVR::R20)
.Case("r21", AVR::R21).Case("r22", AVR::R22).Case("r23", AVR::R23)
.Case("r24", AVR::R24).Case("r25", AVR::R25).Case("r26", AVR::R26)
.Case("r27", AVR::R27).Case("r28", AVR::R28).Case("r29", AVR::R29)
.Case("r30", AVR::R30).Case("r31", AVR::R31)
.Case("X", AVR::R27R26).Case("Y", AVR::R29R28).Case("Z", AVR::R31R30)
.Default(0);
} else {
Reg = StringSwitch<unsigned>(RegName)
.Case("r0", AVR::R1R0).Case("r2", AVR::R3R2)
.Case("r4", AVR::R5R4).Case("r6", AVR::R7R6)
.Case("r8", AVR::R9R8).Case("r10", AVR::R11R10)
.Case("r12", AVR::R13R12).Case("r14", AVR::R15R14)
.Case("r16", AVR::R17R16).Case("r18", AVR::R19R18)
.Case("r20", AVR::R21R20).Case("r22", AVR::R23R22)
.Case("r24", AVR::R25R24).Case("r26", AVR::R27R26)
.Case("r28", AVR::R29R28).Case("r30", AVR::R31R30)
.Case("X", AVR::R27R26).Case("Y", AVR::R29R28).Case("Z", AVR::R31R30)
.Default(0);
}
if (Reg)
return Reg;
report_fatal_error("Invalid register name global variable");
}
} // end of namespace llvm
Index: stable/11/contrib/llvm/lib/Target/AVR/AVRISelLowering.h
===================================================================
--- stable/11/contrib/llvm/lib/Target/AVR/AVRISelLowering.h (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/AVR/AVRISelLowering.h (revision 350259)
@@ -1,174 +1,180 @@
//===-- AVRISelLowering.h - AVR DAG Lowering Interface ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interfaces that AVR uses to lower LLVM code into a
// selection DAG.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_AVR_ISEL_LOWERING_H
#define LLVM_AVR_ISEL_LOWERING_H
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/TargetLowering.h"
namespace llvm {
namespace AVRISD {
/// AVR Specific DAG Nodes
enum NodeType {
/// Start the numbering where the builtin ops leave off.
FIRST_NUMBER = ISD::BUILTIN_OP_END,
/// Return from subroutine.
RET_FLAG,
/// Return from ISR.
RETI_FLAG,
/// Represents an abstract call instruction,
/// which includes a bunch of information.
CALL,
/// A wrapper node for TargetConstantPool,
/// TargetExternalSymbol, and TargetGlobalAddress.
WRAPPER,
LSL, ///< Logical shift left.
LSR, ///< Logical shift right.
ASR, ///< Arithmetic shift right.
ROR, ///< Bit rotate right.
ROL, ///< Bit rotate left.
LSLLOOP, ///< A loop of single logical shift left instructions.
LSRLOOP, ///< A loop of single logical shift right instructions.
ROLLOOP, ///< A loop of single left bit rotate instructions.
RORLOOP, ///< A loop of single right bit rotate instructions.
ASRLOOP, ///< A loop of single arithmetic shift right instructions.
/// AVR conditional branches. Operand 0 is the chain operand, operand 1
/// is the block to branch if condition is true, operand 2 is the
/// condition code, and operand 3 is the flag operand produced by a CMP
/// or TEST instruction.
BRCOND,
/// Compare instruction.
CMP,
/// Compare with carry instruction.
CMPC,
/// Test for zero or minus instruction.
TST,
/// Operand 0 and operand 1 are selection variable, operand 2
/// is condition code and operand 3 is flag operand.
SELECT_CC
};
} // end of namespace AVRISD
+class AVRSubtarget;
class AVRTargetMachine;
/// Performs target lowering for the AVR.
class AVRTargetLowering : public TargetLowering {
public:
- explicit AVRTargetLowering(AVRTargetMachine &TM);
+ explicit AVRTargetLowering(const AVRTargetMachine &TM,
+ const AVRSubtarget &STI);
public:
MVT getScalarShiftAmountTy(const DataLayout &, EVT LHSTy) const override {
return MVT::i8;
}
MVT::SimpleValueType getCmpLibcallReturnType() const override {
return MVT::i8;
}
const char *getTargetNodeName(unsigned Opcode) const override;
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue> &Results,
SelectionDAG &DAG) const override;
bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty,
unsigned AS,
Instruction *I = nullptr) const override;
bool getPreIndexedAddressParts(SDNode *N, SDValue &Base, SDValue &Offset,
ISD::MemIndexedMode &AM,
SelectionDAG &DAG) const override;
bool getPostIndexedAddressParts(SDNode *N, SDNode *Op, SDValue &Base,
SDValue &Offset, ISD::MemIndexedMode &AM,
SelectionDAG &DAG) const override;
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override;
EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context,
EVT VT) const override;
MachineBasicBlock *
EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *MBB) const override;
ConstraintType getConstraintType(StringRef Constraint) const override;
ConstraintWeight
getSingleConstraintMatchWeight(AsmOperandInfo &info,
const char *constraint) const override;
std::pair<unsigned, const TargetRegisterClass *>
getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
StringRef Constraint, MVT VT) const override;
unsigned getInlineAsmMemConstraint(StringRef ConstraintCode) const override;
void LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint,
std::vector<SDValue> &Ops,
SelectionDAG &DAG) const override;
unsigned getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const override;
private:
SDValue getAVRCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue &AVRcc,
SelectionDAG &DAG, SDLoc dl) const;
SDValue LowerShifts(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerDivRem(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
CCAssignFn *CCAssignFnForReturn(CallingConv::ID CC) const;
bool CanLowerReturn(CallingConv::ID CallConv,
MachineFunction &MF, bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
LLVMContext &Context) const override;
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals, const SDLoc &dl,
SelectionDAG &DAG) const override;
SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv,
bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins,
const SDLoc &dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const override;
SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const override;
SDValue LowerCallResult(SDValue Chain, SDValue InFlag,
CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins,
const SDLoc &dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const;
+
+protected:
+
+ const AVRSubtarget &Subtarget;
private:
MachineBasicBlock *insertShift(MachineInstr &MI, MachineBasicBlock *BB) const;
MachineBasicBlock *insertMul(MachineInstr &MI, MachineBasicBlock *BB) const;
};
} // end namespace llvm
#endif // LLVM_AVR_ISEL_LOWERING_H
Index: stable/11/contrib/llvm/lib/Target/AVR/AVRSubtarget.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/AVR/AVRSubtarget.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/AVR/AVRSubtarget.cpp (revision 350259)
@@ -1,47 +1,55 @@
//===-- AVRSubtarget.cpp - AVR Subtarget Information ----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the AVR specific subclass of TargetSubtargetInfo.
//
//===----------------------------------------------------------------------===//
#include "AVRSubtarget.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/TargetRegistry.h"
#include "AVR.h"
#include "AVRTargetMachine.h"
#include "MCTargetDesc/AVRMCTargetDesc.h"
#define DEBUG_TYPE "avr-subtarget"
#define GET_SUBTARGETINFO_TARGET_DESC
#define GET_SUBTARGETINFO_CTOR
#include "AVRGenSubtargetInfo.inc"
namespace llvm {
AVRSubtarget::AVRSubtarget(const Triple &TT, const std::string &CPU,
- const std::string &FS, AVRTargetMachine &TM)
+ const std::string &FS, const AVRTargetMachine &TM)
: AVRGenSubtargetInfo(TT, CPU, FS), InstrInfo(), FrameLowering(),
- TLInfo(TM), TSInfo(),
+ TLInfo(TM, initializeSubtargetDependencies(CPU, FS, TM)), TSInfo(),
// Subtarget features
m_hasSRAM(false), m_hasJMPCALL(false), m_hasIJMPCALL(false),
m_hasEIJMPCALL(false), m_hasADDSUBIW(false), m_hasSmallStack(false),
m_hasMOVW(false), m_hasLPM(false), m_hasLPMX(false), m_hasELPM(false),
m_hasELPMX(false), m_hasSPM(false), m_hasSPMX(false), m_hasDES(false),
m_supportsRMW(false), m_supportsMultiplication(false), m_hasBREAK(false),
m_hasTinyEncoding(false), ELFArch(false), m_FeatureSetDummy(false) {
// Parse features string.
ParseSubtargetFeatures(CPU, FS);
+}
+
+AVRSubtarget &
+AVRSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS,
+ const TargetMachine &TM) {
+ // Parse features string.
+ ParseSubtargetFeatures(CPU, FS);
+ return *this;
}
} // end of namespace llvm
Index: stable/11/contrib/llvm/lib/Target/AVR/AVRSubtarget.h
===================================================================
--- stable/11/contrib/llvm/lib/Target/AVR/AVRSubtarget.h (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/AVR/AVRSubtarget.h (revision 350259)
@@ -1,118 +1,121 @@
//===-- AVRSubtarget.h - Define Subtarget for the AVR -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the AVR specific subclass of TargetSubtargetInfo.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_AVR_SUBTARGET_H
#define LLVM_AVR_SUBTARGET_H
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/Target/TargetMachine.h"
#include "AVRFrameLowering.h"
#include "AVRISelLowering.h"
#include "AVRInstrInfo.h"
#include "AVRSelectionDAGInfo.h"
#define GET_SUBTARGETINFO_HEADER
#include "AVRGenSubtargetInfo.inc"
namespace llvm {
/// A specific AVR target MCU.
class AVRSubtarget : public AVRGenSubtargetInfo {
public:
//! Creates an AVR subtarget.
//! \param TT The target triple.
//! \param CPU The CPU to target.
//! \param FS The feature string.
//! \param TM The target machine.
AVRSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS,
- AVRTargetMachine &TM);
+ const AVRTargetMachine &TM);
const AVRInstrInfo *getInstrInfo() const override { return &InstrInfo; }
const TargetFrameLowering *getFrameLowering() const override { return &FrameLowering; }
const AVRTargetLowering *getTargetLowering() const override { return &TLInfo; }
const AVRSelectionDAGInfo *getSelectionDAGInfo() const override { return &TSInfo; }
const AVRRegisterInfo *getRegisterInfo() const override { return &InstrInfo.getRegisterInfo(); }
/// Parses a subtarget feature string, setting appropriate options.
/// \note Definition of function is auto generated by `tblgen`.
void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
+
+ AVRSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS,
+ const TargetMachine &TM);
// Subtarget feature getters.
// See AVR.td for details.
bool hasSRAM() const { return m_hasSRAM; }
bool hasJMPCALL() const { return m_hasJMPCALL; }
bool hasIJMPCALL() const { return m_hasIJMPCALL; }
bool hasEIJMPCALL() const { return m_hasEIJMPCALL; }
bool hasADDSUBIW() const { return m_hasADDSUBIW; }
bool hasSmallStack() const { return m_hasSmallStack; }
bool hasMOVW() const { return m_hasMOVW; }
bool hasLPM() const { return m_hasLPM; }
bool hasLPMX() const { return m_hasLPMX; }
bool hasELPM() const { return m_hasELPM; }
bool hasELPMX() const { return m_hasELPMX; }
bool hasSPM() const { return m_hasSPM; }
bool hasSPMX() const { return m_hasSPMX; }
bool hasDES() const { return m_hasDES; }
bool supportsRMW() const { return m_supportsRMW; }
bool supportsMultiplication() const { return m_supportsMultiplication; }
bool hasBREAK() const { return m_hasBREAK; }
bool hasTinyEncoding() const { return m_hasTinyEncoding; }
/// Gets the ELF architecture for the e_flags field
/// of an ELF object file.
unsigned getELFArch() const {
assert(ELFArch != 0 &&
"every device must have an associate ELF architecture");
return ELFArch;
}
private:
AVRInstrInfo InstrInfo;
AVRFrameLowering FrameLowering;
AVRTargetLowering TLInfo;
AVRSelectionDAGInfo TSInfo;
// Subtarget feature settings
// See AVR.td for details.
bool m_hasSRAM;
bool m_hasJMPCALL;
bool m_hasIJMPCALL;
bool m_hasEIJMPCALL;
bool m_hasADDSUBIW;
bool m_hasSmallStack;
bool m_hasMOVW;
bool m_hasLPM;
bool m_hasLPMX;
bool m_hasELPM;
bool m_hasELPMX;
bool m_hasSPM;
bool m_hasSPMX;
bool m_hasDES;
bool m_supportsRMW;
bool m_supportsMultiplication;
bool m_hasBREAK;
bool m_hasTinyEncoding;
/// The ELF e_flags architecture.
unsigned ELFArch;
// Dummy member, used by FeatureSet's. We cannot have a SubtargetFeature with
// no variable, so we instead bind pseudo features to this variable.
bool m_FeatureSetDummy;
};
} // end namespace llvm
#endif // LLVM_AVR_SUBTARGET_H
Index: stable/11/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp (revision 350259)
@@ -1,1284 +1,1287 @@
//===-- MipsTargetStreamer.cpp - Mips Target Streamer Methods -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides Mips specific target streamer methods.
//
//===----------------------------------------------------------------------===//
#include "MipsTargetStreamer.h"
#include "InstPrinter/MipsInstPrinter.h"
#include "MCTargetDesc/MipsABIInfo.h"
#include "MipsELFStreamer.h"
#include "MipsMCExpr.h"
#include "MipsMCTargetDesc.h"
#include "MipsTargetObjectFile.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbolELF.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
using namespace llvm;
namespace {
static cl::opt<bool> RoundSectionSizes(
"mips-round-section-sizes", cl::init(false),
cl::desc("Round section sizes up to the section alignment"), cl::Hidden);
} // end anonymous namespace
MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S)
: MCTargetStreamer(S), ModuleDirectiveAllowed(true) {
GPRInfoSet = FPRInfoSet = FrameInfoSet = false;
}
void MipsTargetStreamer::emitDirectiveSetMicroMips() {}
void MipsTargetStreamer::emitDirectiveSetNoMicroMips() {}
void MipsTargetStreamer::setUsesMicroMips() {}
void MipsTargetStreamer::emitDirectiveSetMips16() {}
void MipsTargetStreamer::emitDirectiveSetNoMips16() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetReorder() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetNoReorder() {}
void MipsTargetStreamer::emitDirectiveSetMacro() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetNoMacro() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMsa() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetNoMsa() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMt() {}
void MipsTargetStreamer::emitDirectiveSetNoMt() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetCRC() {}
void MipsTargetStreamer::emitDirectiveSetNoCRC() {}
void MipsTargetStreamer::emitDirectiveSetVirt() {}
void MipsTargetStreamer::emitDirectiveSetNoVirt() {}
void MipsTargetStreamer::emitDirectiveSetGINV() {}
void MipsTargetStreamer::emitDirectiveSetNoGINV() {}
void MipsTargetStreamer::emitDirectiveSetAt() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetAtWithArg(unsigned RegNo) {
forbidModuleDirective();
}
void MipsTargetStreamer::emitDirectiveSetNoAt() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveEnd(StringRef Name) {}
void MipsTargetStreamer::emitDirectiveEnt(const MCSymbol &Symbol) {}
void MipsTargetStreamer::emitDirectiveAbiCalls() {}
void MipsTargetStreamer::emitDirectiveNaN2008() {}
void MipsTargetStreamer::emitDirectiveNaNLegacy() {}
void MipsTargetStreamer::emitDirectiveOptionPic0() {}
void MipsTargetStreamer::emitDirectiveOptionPic2() {}
void MipsTargetStreamer::emitDirectiveInsn() { forbidModuleDirective(); }
void MipsTargetStreamer::emitFrame(unsigned StackReg, unsigned StackSize,
unsigned ReturnReg) {}
void MipsTargetStreamer::emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff) {}
void MipsTargetStreamer::emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) {
}
void MipsTargetStreamer::emitDirectiveSetArch(StringRef Arch) {
forbidModuleDirective();
}
void MipsTargetStreamer::emitDirectiveSetMips0() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips1() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips2() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips3() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips4() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips5() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips32() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips32R2() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips32R3() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips32R5() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips32R6() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips64() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips64R2() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips64R3() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips64R5() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetMips64R6() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetPop() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetPush() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetSoftFloat() {
forbidModuleDirective();
}
void MipsTargetStreamer::emitDirectiveSetHardFloat() {
forbidModuleDirective();
}
void MipsTargetStreamer::emitDirectiveSetDsp() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetDspr2() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetNoDsp() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveCpLoad(unsigned RegNo) {}
bool MipsTargetStreamer::emitDirectiveCpRestore(
int Offset, function_ref<unsigned()> GetATReg, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
forbidModuleDirective();
return true;
}
void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset,
const MCSymbol &Sym, bool IsReg) {
}
void MipsTargetStreamer::emitDirectiveCpreturn(unsigned SaveLocation,
bool SaveLocationIsRegister) {}
void MipsTargetStreamer::emitDirectiveModuleFP() {}
void MipsTargetStreamer::emitDirectiveModuleOddSPReg() {
if (!ABIFlagsSection.OddSPReg && !ABIFlagsSection.Is32BitABI)
report_fatal_error("+nooddspreg is only valid for O32");
}
void MipsTargetStreamer::emitDirectiveModuleSoftFloat() {}
void MipsTargetStreamer::emitDirectiveModuleHardFloat() {}
void MipsTargetStreamer::emitDirectiveModuleMT() {}
void MipsTargetStreamer::emitDirectiveModuleCRC() {}
void MipsTargetStreamer::emitDirectiveModuleNoCRC() {}
void MipsTargetStreamer::emitDirectiveModuleVirt() {}
void MipsTargetStreamer::emitDirectiveModuleNoVirt() {}
void MipsTargetStreamer::emitDirectiveModuleGINV() {}
void MipsTargetStreamer::emitDirectiveModuleNoGINV() {}
void MipsTargetStreamer::emitDirectiveSetFp(
MipsABIFlagsSection::FpABIKind Value) {
forbidModuleDirective();
}
void MipsTargetStreamer::emitDirectiveSetOddSPReg() { forbidModuleDirective(); }
void MipsTargetStreamer::emitDirectiveSetNoOddSPReg() {
forbidModuleDirective();
}
void MipsTargetStreamer::emitR(unsigned Opcode, unsigned Reg0, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
MCInst TmpInst;
TmpInst.setOpcode(Opcode);
TmpInst.addOperand(MCOperand::createReg(Reg0));
TmpInst.setLoc(IDLoc);
getStreamer().EmitInstruction(TmpInst, *STI);
}
void MipsTargetStreamer::emitRX(unsigned Opcode, unsigned Reg0, MCOperand Op1,
SMLoc IDLoc, const MCSubtargetInfo *STI) {
MCInst TmpInst;
TmpInst.setOpcode(Opcode);
TmpInst.addOperand(MCOperand::createReg(Reg0));
TmpInst.addOperand(Op1);
TmpInst.setLoc(IDLoc);
getStreamer().EmitInstruction(TmpInst, *STI);
}
void MipsTargetStreamer::emitRI(unsigned Opcode, unsigned Reg0, int32_t Imm,
SMLoc IDLoc, const MCSubtargetInfo *STI) {
emitRX(Opcode, Reg0, MCOperand::createImm(Imm), IDLoc, STI);
}
void MipsTargetStreamer::emitRR(unsigned Opcode, unsigned Reg0, unsigned Reg1,
SMLoc IDLoc, const MCSubtargetInfo *STI) {
emitRX(Opcode, Reg0, MCOperand::createReg(Reg1), IDLoc, STI);
}
void MipsTargetStreamer::emitII(unsigned Opcode, int16_t Imm1, int16_t Imm2,
SMLoc IDLoc, const MCSubtargetInfo *STI) {
MCInst TmpInst;
TmpInst.setOpcode(Opcode);
TmpInst.addOperand(MCOperand::createImm(Imm1));
TmpInst.addOperand(MCOperand::createImm(Imm2));
TmpInst.setLoc(IDLoc);
getStreamer().EmitInstruction(TmpInst, *STI);
}
void MipsTargetStreamer::emitRRX(unsigned Opcode, unsigned Reg0, unsigned Reg1,
MCOperand Op2, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
MCInst TmpInst;
TmpInst.setOpcode(Opcode);
TmpInst.addOperand(MCOperand::createReg(Reg0));
TmpInst.addOperand(MCOperand::createReg(Reg1));
TmpInst.addOperand(Op2);
TmpInst.setLoc(IDLoc);
getStreamer().EmitInstruction(TmpInst, *STI);
}
void MipsTargetStreamer::emitRRR(unsigned Opcode, unsigned Reg0, unsigned Reg1,
unsigned Reg2, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
emitRRX(Opcode, Reg0, Reg1, MCOperand::createReg(Reg2), IDLoc, STI);
}
void MipsTargetStreamer::emitRRI(unsigned Opcode, unsigned Reg0, unsigned Reg1,
int16_t Imm, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
emitRRX(Opcode, Reg0, Reg1, MCOperand::createImm(Imm), IDLoc, STI);
}
void MipsTargetStreamer::emitRRIII(unsigned Opcode, unsigned Reg0,
unsigned Reg1, int16_t Imm0, int16_t Imm1,
int16_t Imm2, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
MCInst TmpInst;
TmpInst.setOpcode(Opcode);
TmpInst.addOperand(MCOperand::createReg(Reg0));
TmpInst.addOperand(MCOperand::createReg(Reg1));
TmpInst.addOperand(MCOperand::createImm(Imm0));
TmpInst.addOperand(MCOperand::createImm(Imm1));
TmpInst.addOperand(MCOperand::createImm(Imm2));
TmpInst.setLoc(IDLoc);
getStreamer().EmitInstruction(TmpInst, *STI);
}
void MipsTargetStreamer::emitAddu(unsigned DstReg, unsigned SrcReg,
unsigned TrgReg, bool Is64Bit,
const MCSubtargetInfo *STI) {
emitRRR(Is64Bit ? Mips::DADDu : Mips::ADDu, DstReg, SrcReg, TrgReg, SMLoc(),
STI);
}
void MipsTargetStreamer::emitDSLL(unsigned DstReg, unsigned SrcReg,
int16_t ShiftAmount, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
if (ShiftAmount >= 32) {
emitRRI(Mips::DSLL32, DstReg, SrcReg, ShiftAmount - 32, IDLoc, STI);
return;
}
emitRRI(Mips::DSLL, DstReg, SrcReg, ShiftAmount, IDLoc, STI);
}
void MipsTargetStreamer::emitEmptyDelaySlot(bool hasShortDelaySlot, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
if (hasShortDelaySlot)
emitRR(Mips::MOVE16_MM, Mips::ZERO, Mips::ZERO, IDLoc, STI);
else
emitRRI(Mips::SLL, Mips::ZERO, Mips::ZERO, 0, IDLoc, STI);
}
void MipsTargetStreamer::emitNop(SMLoc IDLoc, const MCSubtargetInfo *STI) {
const FeatureBitset &Features = STI->getFeatureBits();
if (Features[Mips::FeatureMicroMips])
emitRR(Mips::MOVE16_MM, Mips::ZERO, Mips::ZERO, IDLoc, STI);
else
emitRRI(Mips::SLL, Mips::ZERO, Mips::ZERO, 0, IDLoc, STI);
}
/// Emit the $gp restore operation for .cprestore.
void MipsTargetStreamer::emitGPRestore(int Offset, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
emitLoadWithImmOffset(Mips::LW, Mips::GP, Mips::SP, Offset, Mips::GP, IDLoc,
STI);
}
/// Emit a store instruction with an immediate offset.
void MipsTargetStreamer::emitStoreWithImmOffset(
unsigned Opcode, unsigned SrcReg, unsigned BaseReg, int64_t Offset,
function_ref<unsigned()> GetATReg, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
if (isInt<16>(Offset)) {
emitRRI(Opcode, SrcReg, BaseReg, Offset, IDLoc, STI);
return;
}
// sw $8, offset($8) => lui $at, %hi(offset)
// add $at, $at, $8
// sw $8, %lo(offset)($at)
unsigned ATReg = GetATReg();
if (!ATReg)
return;
unsigned LoOffset = Offset & 0x0000ffff;
unsigned HiOffset = (Offset & 0xffff0000) >> 16;
// If msb of LoOffset is 1(negative number) we must increment HiOffset
// to account for the sign-extension of the low part.
if (LoOffset & 0x8000)
HiOffset++;
// Generate the base address in ATReg.
emitRI(Mips::LUi, ATReg, HiOffset, IDLoc, STI);
if (BaseReg != Mips::ZERO)
emitRRR(Mips::ADDu, ATReg, ATReg, BaseReg, IDLoc, STI);
// Emit the store with the adjusted base and offset.
emitRRI(Opcode, SrcReg, ATReg, LoOffset, IDLoc, STI);
}
/// Emit a store instruction with an symbol offset. Symbols are assumed to be
/// out of range for a simm16 will be expanded to appropriate instructions.
void MipsTargetStreamer::emitStoreWithSymOffset(
unsigned Opcode, unsigned SrcReg, unsigned BaseReg, MCOperand &HiOperand,
MCOperand &LoOperand, unsigned ATReg, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
// sw $8, sym => lui $at, %hi(sym)
// sw $8, %lo(sym)($at)
// Generate the base address in ATReg.
emitRX(Mips::LUi, ATReg, HiOperand, IDLoc, STI);
if (BaseReg != Mips::ZERO)
emitRRR(Mips::ADDu, ATReg, ATReg, BaseReg, IDLoc, STI);
// Emit the store with the adjusted base and offset.
emitRRX(Opcode, SrcReg, ATReg, LoOperand, IDLoc, STI);
}
/// Emit a load instruction with an immediate offset. DstReg and TmpReg are
/// permitted to be the same register iff DstReg is distinct from BaseReg and
/// DstReg is a GPR. It is the callers responsibility to identify such cases
/// and pass the appropriate register in TmpReg.
void MipsTargetStreamer::emitLoadWithImmOffset(unsigned Opcode, unsigned DstReg,
unsigned BaseReg, int64_t Offset,
unsigned TmpReg, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
if (isInt<16>(Offset)) {
emitRRI(Opcode, DstReg, BaseReg, Offset, IDLoc, STI);
return;
}
// 1) lw $8, offset($9) => lui $8, %hi(offset)
// add $8, $8, $9
// lw $8, %lo(offset)($9)
// 2) lw $8, offset($8) => lui $at, %hi(offset)
// add $at, $at, $8
// lw $8, %lo(offset)($at)
unsigned LoOffset = Offset & 0x0000ffff;
unsigned HiOffset = (Offset & 0xffff0000) >> 16;
// If msb of LoOffset is 1(negative number) we must increment HiOffset
// to account for the sign-extension of the low part.
if (LoOffset & 0x8000)
HiOffset++;
// Generate the base address in TmpReg.
emitRI(Mips::LUi, TmpReg, HiOffset, IDLoc, STI);
if (BaseReg != Mips::ZERO)
emitRRR(Mips::ADDu, TmpReg, TmpReg, BaseReg, IDLoc, STI);
// Emit the load with the adjusted base and offset.
emitRRI(Opcode, DstReg, TmpReg, LoOffset, IDLoc, STI);
}
/// Emit a load instruction with an symbol offset. Symbols are assumed to be
/// out of range for a simm16 will be expanded to appropriate instructions.
/// DstReg and TmpReg are permitted to be the same register iff DstReg is a
/// GPR. It is the callers responsibility to identify such cases and pass the
/// appropriate register in TmpReg.
void MipsTargetStreamer::emitLoadWithSymOffset(unsigned Opcode, unsigned DstReg,
unsigned BaseReg,
MCOperand &HiOperand,
MCOperand &LoOperand,
unsigned TmpReg, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
// 1) lw $8, sym => lui $8, %hi(sym)
// lw $8, %lo(sym)($8)
// 2) ldc1 $f0, sym => lui $at, %hi(sym)
// ldc1 $f0, %lo(sym)($at)
// Generate the base address in TmpReg.
emitRX(Mips::LUi, TmpReg, HiOperand, IDLoc, STI);
if (BaseReg != Mips::ZERO)
emitRRR(Mips::ADDu, TmpReg, TmpReg, BaseReg, IDLoc, STI);
// Emit the load with the adjusted base and offset.
emitRRX(Opcode, DstReg, TmpReg, LoOperand, IDLoc, STI);
}
MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S,
formatted_raw_ostream &OS)
: MipsTargetStreamer(S), OS(OS) {}
void MipsTargetAsmStreamer::emitDirectiveSetMicroMips() {
OS << "\t.set\tmicromips\n";
forbidModuleDirective();
}
void MipsTargetAsmStreamer::emitDirectiveSetNoMicroMips() {
OS << "\t.set\tnomicromips\n";
forbidModuleDirective();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips16() {
OS << "\t.set\tmips16\n";
forbidModuleDirective();
}
void MipsTargetAsmStreamer::emitDirectiveSetNoMips16() {
OS << "\t.set\tnomips16\n";
MipsTargetStreamer::emitDirectiveSetNoMips16();
}
void MipsTargetAsmStreamer::emitDirectiveSetReorder() {
OS << "\t.set\treorder\n";
MipsTargetStreamer::emitDirectiveSetReorder();
}
void MipsTargetAsmStreamer::emitDirectiveSetNoReorder() {
OS << "\t.set\tnoreorder\n";
forbidModuleDirective();
}
void MipsTargetAsmStreamer::emitDirectiveSetMacro() {
OS << "\t.set\tmacro\n";
MipsTargetStreamer::emitDirectiveSetMacro();
}
void MipsTargetAsmStreamer::emitDirectiveSetNoMacro() {
OS << "\t.set\tnomacro\n";
MipsTargetStreamer::emitDirectiveSetNoMacro();
}
void MipsTargetAsmStreamer::emitDirectiveSetMsa() {
OS << "\t.set\tmsa\n";
MipsTargetStreamer::emitDirectiveSetMsa();
}
void MipsTargetAsmStreamer::emitDirectiveSetNoMsa() {
OS << "\t.set\tnomsa\n";
MipsTargetStreamer::emitDirectiveSetNoMsa();
}
void MipsTargetAsmStreamer::emitDirectiveSetMt() {
OS << "\t.set\tmt\n";
MipsTargetStreamer::emitDirectiveSetMt();
}
void MipsTargetAsmStreamer::emitDirectiveSetNoMt() {
OS << "\t.set\tnomt\n";
MipsTargetStreamer::emitDirectiveSetNoMt();
}
void MipsTargetAsmStreamer::emitDirectiveSetCRC() {
OS << "\t.set\tcrc\n";
MipsTargetStreamer::emitDirectiveSetCRC();
}
void MipsTargetAsmStreamer::emitDirectiveSetNoCRC() {
OS << "\t.set\tnocrc\n";
MipsTargetStreamer::emitDirectiveSetNoCRC();
}
void MipsTargetAsmStreamer::emitDirectiveSetVirt() {
OS << "\t.set\tvirt\n";
MipsTargetStreamer::emitDirectiveSetVirt();
}
void MipsTargetAsmStreamer::emitDirectiveSetNoVirt() {
OS << "\t.set\tnovirt\n";
MipsTargetStreamer::emitDirectiveSetNoVirt();
}
void MipsTargetAsmStreamer::emitDirectiveSetGINV() {
OS << "\t.set\tginv\n";
MipsTargetStreamer::emitDirectiveSetGINV();
}
void MipsTargetAsmStreamer::emitDirectiveSetNoGINV() {
OS << "\t.set\tnoginv\n";
MipsTargetStreamer::emitDirectiveSetNoGINV();
}
void MipsTargetAsmStreamer::emitDirectiveSetAt() {
OS << "\t.set\tat\n";
MipsTargetStreamer::emitDirectiveSetAt();
}
void MipsTargetAsmStreamer::emitDirectiveSetAtWithArg(unsigned RegNo) {
OS << "\t.set\tat=$" << Twine(RegNo) << "\n";
MipsTargetStreamer::emitDirectiveSetAtWithArg(RegNo);
}
void MipsTargetAsmStreamer::emitDirectiveSetNoAt() {
OS << "\t.set\tnoat\n";
MipsTargetStreamer::emitDirectiveSetNoAt();
}
void MipsTargetAsmStreamer::emitDirectiveEnd(StringRef Name) {
OS << "\t.end\t" << Name << '\n';
}
void MipsTargetAsmStreamer::emitDirectiveEnt(const MCSymbol &Symbol) {
OS << "\t.ent\t" << Symbol.getName() << '\n';
}
void MipsTargetAsmStreamer::emitDirectiveAbiCalls() { OS << "\t.abicalls\n"; }
void MipsTargetAsmStreamer::emitDirectiveNaN2008() { OS << "\t.nan\t2008\n"; }
void MipsTargetAsmStreamer::emitDirectiveNaNLegacy() {
OS << "\t.nan\tlegacy\n";
}
void MipsTargetAsmStreamer::emitDirectiveOptionPic0() {
OS << "\t.option\tpic0\n";
}
void MipsTargetAsmStreamer::emitDirectiveOptionPic2() {
OS << "\t.option\tpic2\n";
}
void MipsTargetAsmStreamer::emitDirectiveInsn() {
MipsTargetStreamer::emitDirectiveInsn();
OS << "\t.insn\n";
}
void MipsTargetAsmStreamer::emitFrame(unsigned StackReg, unsigned StackSize,
unsigned ReturnReg) {
OS << "\t.frame\t$"
<< StringRef(MipsInstPrinter::getRegisterName(StackReg)).lower() << ","
<< StackSize << ",$"
<< StringRef(MipsInstPrinter::getRegisterName(ReturnReg)).lower() << '\n';
}
void MipsTargetAsmStreamer::emitDirectiveSetArch(StringRef Arch) {
OS << "\t.set arch=" << Arch << "\n";
MipsTargetStreamer::emitDirectiveSetArch(Arch);
}
void MipsTargetAsmStreamer::emitDirectiveSetMips0() {
OS << "\t.set\tmips0\n";
MipsTargetStreamer::emitDirectiveSetMips0();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips1() {
OS << "\t.set\tmips1\n";
MipsTargetStreamer::emitDirectiveSetMips1();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips2() {
OS << "\t.set\tmips2\n";
MipsTargetStreamer::emitDirectiveSetMips2();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips3() {
OS << "\t.set\tmips3\n";
MipsTargetStreamer::emitDirectiveSetMips3();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips4() {
OS << "\t.set\tmips4\n";
MipsTargetStreamer::emitDirectiveSetMips4();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips5() {
OS << "\t.set\tmips5\n";
MipsTargetStreamer::emitDirectiveSetMips5();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips32() {
OS << "\t.set\tmips32\n";
MipsTargetStreamer::emitDirectiveSetMips32();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips32R2() {
OS << "\t.set\tmips32r2\n";
MipsTargetStreamer::emitDirectiveSetMips32R2();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips32R3() {
OS << "\t.set\tmips32r3\n";
MipsTargetStreamer::emitDirectiveSetMips32R3();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips32R5() {
OS << "\t.set\tmips32r5\n";
MipsTargetStreamer::emitDirectiveSetMips32R5();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips32R6() {
OS << "\t.set\tmips32r6\n";
MipsTargetStreamer::emitDirectiveSetMips32R6();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips64() {
OS << "\t.set\tmips64\n";
MipsTargetStreamer::emitDirectiveSetMips64();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips64R2() {
OS << "\t.set\tmips64r2\n";
MipsTargetStreamer::emitDirectiveSetMips64R2();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips64R3() {
OS << "\t.set\tmips64r3\n";
MipsTargetStreamer::emitDirectiveSetMips64R3();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips64R5() {
OS << "\t.set\tmips64r5\n";
MipsTargetStreamer::emitDirectiveSetMips64R5();
}
void MipsTargetAsmStreamer::emitDirectiveSetMips64R6() {
OS << "\t.set\tmips64r6\n";
MipsTargetStreamer::emitDirectiveSetMips64R6();
}
void MipsTargetAsmStreamer::emitDirectiveSetDsp() {
OS << "\t.set\tdsp\n";
MipsTargetStreamer::emitDirectiveSetDsp();
}
void MipsTargetAsmStreamer::emitDirectiveSetDspr2() {
OS << "\t.set\tdspr2\n";
MipsTargetStreamer::emitDirectiveSetDspr2();
}
void MipsTargetAsmStreamer::emitDirectiveSetNoDsp() {
OS << "\t.set\tnodsp\n";
MipsTargetStreamer::emitDirectiveSetNoDsp();
}
void MipsTargetAsmStreamer::emitDirectiveSetPop() {
OS << "\t.set\tpop\n";
MipsTargetStreamer::emitDirectiveSetPop();
}
void MipsTargetAsmStreamer::emitDirectiveSetPush() {
OS << "\t.set\tpush\n";
MipsTargetStreamer::emitDirectiveSetPush();
}
void MipsTargetAsmStreamer::emitDirectiveSetSoftFloat() {
OS << "\t.set\tsoftfloat\n";
MipsTargetStreamer::emitDirectiveSetSoftFloat();
}
void MipsTargetAsmStreamer::emitDirectiveSetHardFloat() {
OS << "\t.set\thardfloat\n";
MipsTargetStreamer::emitDirectiveSetHardFloat();
}
// Print a 32 bit hex number with all numbers.
static void printHex32(unsigned Value, raw_ostream &OS) {
OS << "0x";
for (int i = 7; i >= 0; i--)
OS.write_hex((Value & (0xF << (i * 4))) >> (i * 4));
}
void MipsTargetAsmStreamer::emitMask(unsigned CPUBitmask,
int CPUTopSavedRegOff) {
OS << "\t.mask \t";
printHex32(CPUBitmask, OS);
OS << ',' << CPUTopSavedRegOff << '\n';
}
void MipsTargetAsmStreamer::emitFMask(unsigned FPUBitmask,
int FPUTopSavedRegOff) {
OS << "\t.fmask\t";
printHex32(FPUBitmask, OS);
OS << "," << FPUTopSavedRegOff << '\n';
}
void MipsTargetAsmStreamer::emitDirectiveCpLoad(unsigned RegNo) {
OS << "\t.cpload\t$"
<< StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << "\n";
forbidModuleDirective();
}
bool MipsTargetAsmStreamer::emitDirectiveCpRestore(
int Offset, function_ref<unsigned()> GetATReg, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
MipsTargetStreamer::emitDirectiveCpRestore(Offset, GetATReg, IDLoc, STI);
OS << "\t.cprestore\t" << Offset << "\n";
return true;
}
void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo,
int RegOrOffset,
const MCSymbol &Sym,
bool IsReg) {
OS << "\t.cpsetup\t$"
<< StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << ", ";
if (IsReg)
OS << "$"
<< StringRef(MipsInstPrinter::getRegisterName(RegOrOffset)).lower();
else
OS << RegOrOffset;
OS << ", ";
OS << Sym.getName();
forbidModuleDirective();
}
void MipsTargetAsmStreamer::emitDirectiveCpreturn(unsigned SaveLocation,
bool SaveLocationIsRegister) {
OS << "\t.cpreturn";
forbidModuleDirective();
}
void MipsTargetAsmStreamer::emitDirectiveModuleFP() {
- OS << "\t.module\tfp=";
- OS << ABIFlagsSection.getFpABIString(ABIFlagsSection.getFpABI()) << "\n";
+ MipsABIFlagsSection::FpABIKind FpABI = ABIFlagsSection.getFpABI();
+ if (FpABI == MipsABIFlagsSection::FpABIKind::SOFT)
+ OS << "\t.module\tsoftfloat\n";
+ else
+ OS << "\t.module\tfp=" << ABIFlagsSection.getFpABIString(FpABI) << "\n";
}
void MipsTargetAsmStreamer::emitDirectiveSetFp(
MipsABIFlagsSection::FpABIKind Value) {
MipsTargetStreamer::emitDirectiveSetFp(Value);
OS << "\t.set\tfp=";
OS << ABIFlagsSection.getFpABIString(Value) << "\n";
}
void MipsTargetAsmStreamer::emitDirectiveModuleOddSPReg() {
MipsTargetStreamer::emitDirectiveModuleOddSPReg();
OS << "\t.module\t" << (ABIFlagsSection.OddSPReg ? "" : "no") << "oddspreg\n";
}
void MipsTargetAsmStreamer::emitDirectiveSetOddSPReg() {
MipsTargetStreamer::emitDirectiveSetOddSPReg();
OS << "\t.set\toddspreg\n";
}
void MipsTargetAsmStreamer::emitDirectiveSetNoOddSPReg() {
MipsTargetStreamer::emitDirectiveSetNoOddSPReg();
OS << "\t.set\tnooddspreg\n";
}
void MipsTargetAsmStreamer::emitDirectiveModuleSoftFloat() {
OS << "\t.module\tsoftfloat\n";
}
void MipsTargetAsmStreamer::emitDirectiveModuleHardFloat() {
OS << "\t.module\thardfloat\n";
}
void MipsTargetAsmStreamer::emitDirectiveModuleMT() {
OS << "\t.module\tmt\n";
}
void MipsTargetAsmStreamer::emitDirectiveModuleCRC() {
OS << "\t.module\tcrc\n";
}
void MipsTargetAsmStreamer::emitDirectiveModuleNoCRC() {
OS << "\t.module\tnocrc\n";
}
void MipsTargetAsmStreamer::emitDirectiveModuleVirt() {
OS << "\t.module\tvirt\n";
}
void MipsTargetAsmStreamer::emitDirectiveModuleNoVirt() {
OS << "\t.module\tnovirt\n";
}
void MipsTargetAsmStreamer::emitDirectiveModuleGINV() {
OS << "\t.module\tginv\n";
}
void MipsTargetAsmStreamer::emitDirectiveModuleNoGINV() {
OS << "\t.module\tnoginv\n";
}
// This part is for ELF object output.
MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S,
const MCSubtargetInfo &STI)
: MipsTargetStreamer(S), MicroMipsEnabled(false), STI(STI) {
MCAssembler &MCA = getStreamer().getAssembler();
// It's possible that MCObjectFileInfo isn't fully initialized at this point
// due to an initialization order problem where LLVMTargetMachine creates the
// target streamer before TargetLoweringObjectFile calls
// InitializeMCObjectFileInfo. There doesn't seem to be a single place that
// covers all cases so this statement covers most cases and direct object
// emission must call setPic() once MCObjectFileInfo has been initialized. The
// cases we don't handle here are covered by MipsAsmPrinter.
Pic = MCA.getContext().getObjectFileInfo()->isPositionIndependent();
const FeatureBitset &Features = STI.getFeatureBits();
// Set the header flags that we can in the constructor.
// FIXME: This is a fairly terrible hack. We set the rest
// of these in the destructor. The problem here is two-fold:
//
// a: Some of the eflags can be set/reset by directives.
// b: There aren't any usage paths that initialize the ABI
// pointer until after we initialize either an assembler
// or the target machine.
// We can fix this by making the target streamer construct
// the ABI, but this is fraught with wide ranging dependency
// issues as well.
unsigned EFlags = MCA.getELFHeaderEFlags();
// FIXME: Fix a dependency issue by instantiating the ABI object to some
// default based off the triple. The triple doesn't describe the target
// fully, but any external user of the API that uses the MCTargetStreamer
// would otherwise crash on assertion failure.
ABI = MipsABIInfo(
STI.getTargetTriple().getArch() == Triple::ArchType::mipsel ||
STI.getTargetTriple().getArch() == Triple::ArchType::mips
? MipsABIInfo::O32()
: MipsABIInfo::N64());
// Architecture
if (Features[Mips::FeatureMips64r6])
EFlags |= ELF::EF_MIPS_ARCH_64R6;
else if (Features[Mips::FeatureMips64r2] ||
Features[Mips::FeatureMips64r3] ||
Features[Mips::FeatureMips64r5])
EFlags |= ELF::EF_MIPS_ARCH_64R2;
else if (Features[Mips::FeatureMips64])
EFlags |= ELF::EF_MIPS_ARCH_64;
else if (Features[Mips::FeatureMips5])
EFlags |= ELF::EF_MIPS_ARCH_5;
else if (Features[Mips::FeatureMips4])
EFlags |= ELF::EF_MIPS_ARCH_4;
else if (Features[Mips::FeatureMips3])
EFlags |= ELF::EF_MIPS_ARCH_3;
else if (Features[Mips::FeatureMips32r6])
EFlags |= ELF::EF_MIPS_ARCH_32R6;
else if (Features[Mips::FeatureMips32r2] ||
Features[Mips::FeatureMips32r3] ||
Features[Mips::FeatureMips32r5])
EFlags |= ELF::EF_MIPS_ARCH_32R2;
else if (Features[Mips::FeatureMips32])
EFlags |= ELF::EF_MIPS_ARCH_32;
else if (Features[Mips::FeatureMips2])
EFlags |= ELF::EF_MIPS_ARCH_2;
else
EFlags |= ELF::EF_MIPS_ARCH_1;
// Machine
if (Features[Mips::FeatureCnMips])
EFlags |= ELF::EF_MIPS_MACH_OCTEON;
// Other options.
if (Features[Mips::FeatureNaN2008])
EFlags |= ELF::EF_MIPS_NAN2008;
MCA.setELFHeaderEFlags(EFlags);
}
void MipsTargetELFStreamer::emitLabel(MCSymbol *S) {
auto *Symbol = cast<MCSymbolELF>(S);
getStreamer().getAssembler().registerSymbol(*Symbol);
uint8_t Type = Symbol->getType();
if (Type != ELF::STT_FUNC)
return;
if (isMicroMipsEnabled())
Symbol->setOther(ELF::STO_MIPS_MICROMIPS);
}
void MipsTargetELFStreamer::finish() {
MCAssembler &MCA = getStreamer().getAssembler();
const MCObjectFileInfo &OFI = *MCA.getContext().getObjectFileInfo();
// .bss, .text and .data are always at least 16-byte aligned.
MCSection &TextSection = *OFI.getTextSection();
MCA.registerSection(TextSection);
MCSection &DataSection = *OFI.getDataSection();
MCA.registerSection(DataSection);
MCSection &BSSSection = *OFI.getBSSSection();
MCA.registerSection(BSSSection);
TextSection.setAlignment(std::max(16u, TextSection.getAlignment()));
DataSection.setAlignment(std::max(16u, DataSection.getAlignment()));
BSSSection.setAlignment(std::max(16u, BSSSection.getAlignment()));
if (RoundSectionSizes) {
// Make sections sizes a multiple of the alignment. This is useful for
// verifying the output of IAS against the output of other assemblers but
// it's not necessary to produce a correct object and increases section
// size.
MCStreamer &OS = getStreamer();
for (MCSection &S : MCA) {
MCSectionELF &Section = static_cast<MCSectionELF &>(S);
unsigned Alignment = Section.getAlignment();
if (Alignment) {
OS.SwitchSection(&Section);
if (Section.UseCodeAlign())
OS.EmitCodeAlignment(Alignment, Alignment);
else
OS.EmitValueToAlignment(Alignment, 0, 1, Alignment);
}
}
}
const FeatureBitset &Features = STI.getFeatureBits();
// Update e_header flags. See the FIXME and comment above in
// the constructor for a full rundown on this.
unsigned EFlags = MCA.getELFHeaderEFlags();
// ABI
// N64 does not require any ABI bits.
if (getABI().IsO32())
EFlags |= ELF::EF_MIPS_ABI_O32;
else if (getABI().IsN32())
EFlags |= ELF::EF_MIPS_ABI2;
if (Features[Mips::FeatureGP64Bit]) {
if (getABI().IsO32())
EFlags |= ELF::EF_MIPS_32BITMODE; /* Compatibility Mode */
} else if (Features[Mips::FeatureMips64r2] || Features[Mips::FeatureMips64])
EFlags |= ELF::EF_MIPS_32BITMODE;
// -mplt is not implemented but we should act as if it was
// given.
if (!Features[Mips::FeatureNoABICalls])
EFlags |= ELF::EF_MIPS_CPIC;
if (Pic)
EFlags |= ELF::EF_MIPS_PIC | ELF::EF_MIPS_CPIC;
MCA.setELFHeaderEFlags(EFlags);
// Emit all the option records.
// At the moment we are only emitting .Mips.options (ODK_REGINFO) and
// .reginfo.
MipsELFStreamer &MEF = static_cast<MipsELFStreamer &>(Streamer);
MEF.EmitMipsOptionRecords();
emitMipsAbiFlags();
}
void MipsTargetELFStreamer::emitAssignment(MCSymbol *S, const MCExpr *Value) {
auto *Symbol = cast<MCSymbolELF>(S);
// If on rhs is micromips symbol then mark Symbol as microMips.
if (Value->getKind() != MCExpr::SymbolRef)
return;
const auto &RhsSym = cast<MCSymbolELF>(
static_cast<const MCSymbolRefExpr *>(Value)->getSymbol());
if (!(RhsSym.getOther() & ELF::STO_MIPS_MICROMIPS))
return;
Symbol->setOther(ELF::STO_MIPS_MICROMIPS);
}
MCELFStreamer &MipsTargetELFStreamer::getStreamer() {
return static_cast<MCELFStreamer &>(Streamer);
}
void MipsTargetELFStreamer::emitDirectiveSetMicroMips() {
MicroMipsEnabled = true;
forbidModuleDirective();
}
void MipsTargetELFStreamer::emitDirectiveSetNoMicroMips() {
MicroMipsEnabled = false;
forbidModuleDirective();
}
void MipsTargetELFStreamer::setUsesMicroMips() {
MCAssembler &MCA = getStreamer().getAssembler();
unsigned Flags = MCA.getELFHeaderEFlags();
Flags |= ELF::EF_MIPS_MICROMIPS;
MCA.setELFHeaderEFlags(Flags);
}
void MipsTargetELFStreamer::emitDirectiveSetMips16() {
MCAssembler &MCA = getStreamer().getAssembler();
unsigned Flags = MCA.getELFHeaderEFlags();
Flags |= ELF::EF_MIPS_ARCH_ASE_M16;
MCA.setELFHeaderEFlags(Flags);
forbidModuleDirective();
}
void MipsTargetELFStreamer::emitDirectiveSetNoReorder() {
MCAssembler &MCA = getStreamer().getAssembler();
unsigned Flags = MCA.getELFHeaderEFlags();
Flags |= ELF::EF_MIPS_NOREORDER;
MCA.setELFHeaderEFlags(Flags);
forbidModuleDirective();
}
void MipsTargetELFStreamer::emitDirectiveEnd(StringRef Name) {
MCAssembler &MCA = getStreamer().getAssembler();
MCContext &Context = MCA.getContext();
MCStreamer &OS = getStreamer();
MCSectionELF *Sec = Context.getELFSection(".pdr", ELF::SHT_PROGBITS, 0);
MCSymbol *Sym = Context.getOrCreateSymbol(Name);
const MCSymbolRefExpr *ExprRef =
MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Context);
MCA.registerSection(*Sec);
Sec->setAlignment(4);
OS.PushSection();
OS.SwitchSection(Sec);
OS.EmitValueImpl(ExprRef, 4);
OS.EmitIntValue(GPRInfoSet ? GPRBitMask : 0, 4); // reg_mask
OS.EmitIntValue(GPRInfoSet ? GPROffset : 0, 4); // reg_offset
OS.EmitIntValue(FPRInfoSet ? FPRBitMask : 0, 4); // fpreg_mask
OS.EmitIntValue(FPRInfoSet ? FPROffset : 0, 4); // fpreg_offset
OS.EmitIntValue(FrameInfoSet ? FrameOffset : 0, 4); // frame_offset
OS.EmitIntValue(FrameInfoSet ? FrameReg : 0, 4); // frame_reg
OS.EmitIntValue(FrameInfoSet ? ReturnReg : 0, 4); // return_reg
// The .end directive marks the end of a procedure. Invalidate
// the information gathered up until this point.
GPRInfoSet = FPRInfoSet = FrameInfoSet = false;
OS.PopSection();
// .end also implicitly sets the size.
MCSymbol *CurPCSym = Context.createTempSymbol();
OS.EmitLabel(CurPCSym);
const MCExpr *Size = MCBinaryExpr::createSub(
MCSymbolRefExpr::create(CurPCSym, MCSymbolRefExpr::VK_None, Context),
ExprRef, Context);
// The ELFObjectWriter can determine the absolute size as it has access to
// the layout information of the assembly file, so a size expression rather
// than an absolute value is ok here.
static_cast<MCSymbolELF *>(Sym)->setSize(Size);
}
void MipsTargetELFStreamer::emitDirectiveEnt(const MCSymbol &Symbol) {
GPRInfoSet = FPRInfoSet = FrameInfoSet = false;
// .ent also acts like an implicit '.type symbol, STT_FUNC'
static_cast<const MCSymbolELF &>(Symbol).setType(ELF::STT_FUNC);
}
void MipsTargetELFStreamer::emitDirectiveAbiCalls() {
MCAssembler &MCA = getStreamer().getAssembler();
unsigned Flags = MCA.getELFHeaderEFlags();
Flags |= ELF::EF_MIPS_CPIC | ELF::EF_MIPS_PIC;
MCA.setELFHeaderEFlags(Flags);
}
void MipsTargetELFStreamer::emitDirectiveNaN2008() {
MCAssembler &MCA = getStreamer().getAssembler();
unsigned Flags = MCA.getELFHeaderEFlags();
Flags |= ELF::EF_MIPS_NAN2008;
MCA.setELFHeaderEFlags(Flags);
}
void MipsTargetELFStreamer::emitDirectiveNaNLegacy() {
MCAssembler &MCA = getStreamer().getAssembler();
unsigned Flags = MCA.getELFHeaderEFlags();
Flags &= ~ELF::EF_MIPS_NAN2008;
MCA.setELFHeaderEFlags(Flags);
}
void MipsTargetELFStreamer::emitDirectiveOptionPic0() {
MCAssembler &MCA = getStreamer().getAssembler();
unsigned Flags = MCA.getELFHeaderEFlags();
// This option overrides other PIC options like -KPIC.
Pic = false;
Flags &= ~ELF::EF_MIPS_PIC;
MCA.setELFHeaderEFlags(Flags);
}
void MipsTargetELFStreamer::emitDirectiveOptionPic2() {
MCAssembler &MCA = getStreamer().getAssembler();
unsigned Flags = MCA.getELFHeaderEFlags();
Pic = true;
// NOTE: We are following the GAS behaviour here which means the directive
// 'pic2' also sets the CPIC bit in the ELF header. This is different from
// what is stated in the SYSV ABI which consider the bits EF_MIPS_PIC and
// EF_MIPS_CPIC to be mutually exclusive.
Flags |= ELF::EF_MIPS_PIC | ELF::EF_MIPS_CPIC;
MCA.setELFHeaderEFlags(Flags);
}
void MipsTargetELFStreamer::emitDirectiveInsn() {
MipsTargetStreamer::emitDirectiveInsn();
MipsELFStreamer &MEF = static_cast<MipsELFStreamer &>(Streamer);
MEF.createPendingLabelRelocs();
}
void MipsTargetELFStreamer::emitFrame(unsigned StackReg, unsigned StackSize,
unsigned ReturnReg_) {
MCContext &Context = getStreamer().getAssembler().getContext();
const MCRegisterInfo *RegInfo = Context.getRegisterInfo();
FrameInfoSet = true;
FrameReg = RegInfo->getEncodingValue(StackReg);
FrameOffset = StackSize;
ReturnReg = RegInfo->getEncodingValue(ReturnReg_);
}
void MipsTargetELFStreamer::emitMask(unsigned CPUBitmask,
int CPUTopSavedRegOff) {
GPRInfoSet = true;
GPRBitMask = CPUBitmask;
GPROffset = CPUTopSavedRegOff;
}
void MipsTargetELFStreamer::emitFMask(unsigned FPUBitmask,
int FPUTopSavedRegOff) {
FPRInfoSet = true;
FPRBitMask = FPUBitmask;
FPROffset = FPUTopSavedRegOff;
}
void MipsTargetELFStreamer::emitDirectiveCpLoad(unsigned RegNo) {
// .cpload $reg
// This directive expands to:
// lui $gp, %hi(_gp_disp)
// addui $gp, $gp, %lo(_gp_disp)
// addu $gp, $gp, $reg
// when support for position independent code is enabled.
if (!Pic || (getABI().IsN32() || getABI().IsN64()))
return;
// There's a GNU extension controlled by -mno-shared that allows
// locally-binding symbols to be accessed using absolute addresses.
// This is currently not supported. When supported -mno-shared makes
// .cpload expand to:
// lui $gp, %hi(__gnu_local_gp)
// addiu $gp, $gp, %lo(__gnu_local_gp)
StringRef SymName("_gp_disp");
MCAssembler &MCA = getStreamer().getAssembler();
MCSymbol *GP_Disp = MCA.getContext().getOrCreateSymbol(SymName);
MCA.registerSymbol(*GP_Disp);
MCInst TmpInst;
TmpInst.setOpcode(Mips::LUi);
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
const MCExpr *HiSym = MipsMCExpr::create(
MipsMCExpr::MEK_HI,
MCSymbolRefExpr::create("_gp_disp", MCSymbolRefExpr::VK_None,
MCA.getContext()),
MCA.getContext());
TmpInst.addOperand(MCOperand::createExpr(HiSym));
getStreamer().EmitInstruction(TmpInst, STI);
TmpInst.clear();
TmpInst.setOpcode(Mips::ADDiu);
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
const MCExpr *LoSym = MipsMCExpr::create(
MipsMCExpr::MEK_LO,
MCSymbolRefExpr::create("_gp_disp", MCSymbolRefExpr::VK_None,
MCA.getContext()),
MCA.getContext());
TmpInst.addOperand(MCOperand::createExpr(LoSym));
getStreamer().EmitInstruction(TmpInst, STI);
TmpInst.clear();
TmpInst.setOpcode(Mips::ADDu);
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
TmpInst.addOperand(MCOperand::createReg(Mips::GP));
TmpInst.addOperand(MCOperand::createReg(RegNo));
getStreamer().EmitInstruction(TmpInst, STI);
forbidModuleDirective();
}
bool MipsTargetELFStreamer::emitDirectiveCpRestore(
int Offset, function_ref<unsigned()> GetATReg, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
MipsTargetStreamer::emitDirectiveCpRestore(Offset, GetATReg, IDLoc, STI);
// .cprestore offset
// When PIC mode is enabled and the O32 ABI is used, this directive expands
// to:
// sw $gp, offset($sp)
// and adds a corresponding LW after every JAL.
// Note that .cprestore is ignored if used with the N32 and N64 ABIs or if it
// is used in non-PIC mode.
if (!Pic || (getABI().IsN32() || getABI().IsN64()))
return true;
// Store the $gp on the stack.
emitStoreWithImmOffset(Mips::SW, Mips::GP, Mips::SP, Offset, GetATReg, IDLoc,
STI);
return true;
}
void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
int RegOrOffset,
const MCSymbol &Sym,
bool IsReg) {
// Only N32 and N64 emit anything for .cpsetup iff PIC is set.
if (!Pic || !(getABI().IsN32() || getABI().IsN64()))
return;
forbidModuleDirective();
MCAssembler &MCA = getStreamer().getAssembler();
MCInst Inst;
// Either store the old $gp in a register or on the stack
if (IsReg) {
// move $save, $gpreg
emitRRR(Mips::OR64, RegOrOffset, Mips::GP, Mips::ZERO, SMLoc(), &STI);
} else {
// sd $gpreg, offset($sp)
emitRRI(Mips::SD, Mips::GP, Mips::SP, RegOrOffset, SMLoc(), &STI);
}
if (getABI().IsN32()) {
MCSymbol *GPSym = MCA.getContext().getOrCreateSymbol("__gnu_local_gp");
const MipsMCExpr *HiExpr = MipsMCExpr::create(
MipsMCExpr::MEK_HI, MCSymbolRefExpr::create(GPSym, MCA.getContext()),
MCA.getContext());
const MipsMCExpr *LoExpr = MipsMCExpr::create(
MipsMCExpr::MEK_LO, MCSymbolRefExpr::create(GPSym, MCA.getContext()),
MCA.getContext());
// lui $gp, %hi(__gnu_local_gp)
emitRX(Mips::LUi, Mips::GP, MCOperand::createExpr(HiExpr), SMLoc(), &STI);
// addiu $gp, $gp, %lo(__gnu_local_gp)
emitRRX(Mips::ADDiu, Mips::GP, Mips::GP, MCOperand::createExpr(LoExpr),
SMLoc(), &STI);
return;
}
const MipsMCExpr *HiExpr = MipsMCExpr::createGpOff(
MipsMCExpr::MEK_HI, MCSymbolRefExpr::create(&Sym, MCA.getContext()),
MCA.getContext());
const MipsMCExpr *LoExpr = MipsMCExpr::createGpOff(
MipsMCExpr::MEK_LO, MCSymbolRefExpr::create(&Sym, MCA.getContext()),
MCA.getContext());
// lui $gp, %hi(%neg(%gp_rel(funcSym)))
emitRX(Mips::LUi, Mips::GP, MCOperand::createExpr(HiExpr), SMLoc(), &STI);
// addiu $gp, $gp, %lo(%neg(%gp_rel(funcSym)))
emitRRX(Mips::ADDiu, Mips::GP, Mips::GP, MCOperand::createExpr(LoExpr),
SMLoc(), &STI);
// daddu $gp, $gp, $funcreg
emitRRR(Mips::DADDu, Mips::GP, Mips::GP, RegNo, SMLoc(), &STI);
}
void MipsTargetELFStreamer::emitDirectiveCpreturn(unsigned SaveLocation,
bool SaveLocationIsRegister) {
// Only N32 and N64 emit anything for .cpreturn iff PIC is set.
if (!Pic || !(getABI().IsN32() || getABI().IsN64()))
return;
MCInst Inst;
// Either restore the old $gp from a register or on the stack
if (SaveLocationIsRegister) {
Inst.setOpcode(Mips::OR);
Inst.addOperand(MCOperand::createReg(Mips::GP));
Inst.addOperand(MCOperand::createReg(SaveLocation));
Inst.addOperand(MCOperand::createReg(Mips::ZERO));
} else {
Inst.setOpcode(Mips::LD);
Inst.addOperand(MCOperand::createReg(Mips::GP));
Inst.addOperand(MCOperand::createReg(Mips::SP));
Inst.addOperand(MCOperand::createImm(SaveLocation));
}
getStreamer().EmitInstruction(Inst, STI);
forbidModuleDirective();
}
void MipsTargetELFStreamer::emitMipsAbiFlags() {
MCAssembler &MCA = getStreamer().getAssembler();
MCContext &Context = MCA.getContext();
MCStreamer &OS = getStreamer();
MCSectionELF *Sec = Context.getELFSection(
".MIPS.abiflags", ELF::SHT_MIPS_ABIFLAGS, ELF::SHF_ALLOC, 24, "");
MCA.registerSection(*Sec);
Sec->setAlignment(8);
OS.SwitchSection(Sec);
OS << ABIFlagsSection;
}
Index: stable/11/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td
===================================================================
--- stable/11/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td (revision 350259)
@@ -1,1818 +1,1820 @@
//=- MicroMips32r6InstrInfo.td - MicroMips r6 Instruction Information -*- tablegen -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes microMIPSr6 instructions.
//
//===----------------------------------------------------------------------===//
def brtarget21_mm : Operand<OtherVT> {
let EncoderMethod = "getBranchTarget21OpValueMM";
let OperandType = "OPERAND_PCREL";
let DecoderMethod = "DecodeBranchTarget21MM";
let ParserMatchClass = MipsJumpTargetAsmOperand;
}
def brtarget26_mm : Operand<OtherVT> {
let EncoderMethod = "getBranchTarget26OpValueMM";
let OperandType = "OPERAND_PCREL";
let DecoderMethod = "DecodeBranchTarget26MM";
let ParserMatchClass = MipsJumpTargetAsmOperand;
}
def brtargetr6 : Operand<OtherVT> {
let EncoderMethod = "getBranchTargetOpValueMMR6";
let OperandType = "OPERAND_PCREL";
let DecoderMethod = "DecodeBranchTargetMM";
let ParserMatchClass = MipsJumpTargetAsmOperand;
}
def brtarget_lsl2_mm : Operand<OtherVT> {
let EncoderMethod = "getBranchTargetOpValueLsl2MMR6";
let OperandType = "OPERAND_PCREL";
// Instructions that use this operand have their decoder method
// set with DecodeDisambiguates
let DecoderMethod = "";
let ParserMatchClass = MipsJumpTargetAsmOperand;
}
//===----------------------------------------------------------------------===//
//
// Instruction Encodings
//
//===----------------------------------------------------------------------===//
class ADD_MMR6_ENC : ARITH_FM_MMR6<"add", 0x110>;
class ADDIU_MMR6_ENC : ADDI_FM_MMR6<"addiu", 0xc>;
class ADDU_MMR6_ENC : ARITH_FM_MMR6<"addu", 0x150>;
class ADDIUPC_MMR6_ENC : PCREL19_FM_MMR6<0b00>;
class ALUIPC_MMR6_ENC : PCREL16_FM_MMR6<0b11111>;
class AND_MMR6_ENC : ARITH_FM_MMR6<"and", 0x250>;
class ANDI_MMR6_ENC : ADDI_FM_MMR6<"andi", 0x34>;
class AUIPC_MMR6_ENC : PCREL16_FM_MMR6<0b11110>;
class ALIGN_MMR6_ENC : POOL32A_ALIGN_FM_MMR6<0b011111>;
class AUI_MMR6_ENC : AUI_FM_MMR6;
class BALC_MMR6_ENC : BRANCH_OFF26_FM<0b101101>;
class BC_MMR6_ENC : BRANCH_OFF26_FM<0b100101>;
class BC16_MMR6_ENC : BC16_FM_MM16R6;
class BEQZC16_MMR6_ENC : BEQZC_BNEZC_FM_MM16R6<0x23>;
class BNEZC16_MMR6_ENC : BEQZC_BNEZC_FM_MM16R6<0x2b>;
class BITSWAP_MMR6_ENC : POOL32A_BITSWAP_FM_MMR6<0b101100>;
class BRK_MMR6_ENC : BREAK_MMR6_ENC<"break">;
class BEQZC_MMR6_ENC : CMP_BRANCH_OFF21_FM_MMR6<"beqzc", 0b100000>;
class BNEZC_MMR6_ENC : CMP_BRANCH_OFF21_FM_MMR6<"bnezc", 0b101000>;
class BGEC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"bgec", 0b111101>,
DecodeDisambiguates<"POP75GroupBranchMMR6">;
class BGEUC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"bgeuc", 0b110000>,
DecodeDisambiguates<"BlezGroupBranchMMR6">;
class BLTC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"bltc", 0b110101>,
DecodeDisambiguates<"POP65GroupBranchMMR6">;
class BLTUC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"bltuc", 0b111000>,
DecodeDisambiguates<"BgtzGroupBranchMMR6">;
class BEQC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"beqc", 0b011101>;
class BNEC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"bnec", 0b011111>;
class BLTZC_MMR6_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM_MMR6<"bltzc", 0b110101>,
DecodeDisambiguates<"POP65GroupBranchMMR6">;
class BLEZC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"blezc", 0b111101>,
DecodeDisambiguates<"POP75GroupBranchMMR6">;
class BGEZC_MMR6_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM_MMR6<"bgezc", 0b111101>,
DecodeDisambiguates<"POP75GroupBranchMMR6">;
class BGTZC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"bgtzc", 0b110101>,
DecodeDisambiguates<"POP65GroupBranchMMR6">;
class BEQZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"beqzalc", 0b011101>,
DecodeDisambiguates<"POP35GroupBranchMMR6">;
class BNEZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"bnezalc", 0b011111>,
DecodeDisambiguates<"POP37GroupBranchMMR6">;
class BGTZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"bgtzalc", 0b111000>,
MMDecodeDisambiguatedBy<"BgtzGroupBranchMMR6">;
class BLTZALC_MMR6_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM_MMR6<"bltzalc", 0b111000>,
MMDecodeDisambiguatedBy<"BgtzGroupBranchMMR6">;
class BGEZALC_MMR6_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM_MMR6<"bgezalc", 0b110000>,
MMDecodeDisambiguatedBy<"BlezGroupBranchMMR6">;
class BLEZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"blezalc", 0b110000>,
MMDecodeDisambiguatedBy<"BlezGroupBranchMMR6">;
class CACHE_MMR6_ENC : CACHE_PREF_FM_MMR6<0b001000, 0b0110>;
class CLO_MMR6_ENC : POOL32A_2R_FM_MMR6<0b0100101100>;
class CLZ_MMR6_ENC : SPECIAL_2R_FM_MMR6<0b010000>;
class DIV_MMR6_ENC : ARITH_FM_MMR6<"div", 0x118>;
class DIVU_MMR6_ENC : ARITH_FM_MMR6<"divu", 0x198>;
class EHB_MMR6_ENC : BARRIER_MMR6_ENC<"ehb", 0x3>;
class EI_MMR6_ENC : POOL32A_EIDI_MMR6_ENC<"ei", 0x15d>;
class DI_MMR6_ENC : POOL32A_EIDI_MMR6_ENC<"di", 0b0100011101>;
class ERET_MMR6_ENC : POOL32A_ERET_FM_MMR6<"eret", 0x3cd>;
class DERET_MMR6_ENC : POOL32A_ERET_FM_MMR6<"eret", 0b1110001101>;
class ERETNC_MMR6_ENC : ERETNC_FM_MMR6<"eretnc">;
class GINVI_MMR6_ENC : POOL32A_GINV_FM_MMR6<"ginvi", 0b00>;
class GINVT_MMR6_ENC : POOL32A_GINV_FM_MMR6<"ginvt", 0b10>;
class JALRC16_MMR6_ENC : POOL16C_JALRC_FM_MM16R6<0xb>;
class JIALC_MMR6_ENC : JMP_IDX_COMPACT_FM<0b100000>;
class JIC_MMR6_ENC : JMP_IDX_COMPACT_FM<0b101000>;
class JRC16_MMR6_ENC: POOL16C_JALRC_FM_MM16R6<0x3>;
class JRCADDIUSP_MMR6_ENC : POOL16C_JRCADDIUSP_FM_MM16R6<0x13>;
class LSA_MMR6_ENC : POOL32A_LSA_FM<0b001111>;
class LWPC_MMR6_ENC : PCREL19_FM_MMR6<0b01>;
class LWM16_MMR6_ENC : POOL16C_LWM_SWM_FM_MM16R6<0x2>;
class MFC0_MMR6_ENC : POOL32A_MFTC0_FM_MMR6<"mfc0", 0b00011, 0b111100>;
class MFC1_MMR6_ENC : POOL32F_MFTC1_FM_MMR6<"mfc1", 0b10000000>;
class MFC2_MMR6_ENC : POOL32A_MFTC2_FM_MMR6<"mfc2", 0b0100110100>;
class MFHC0_MMR6_ENC : POOL32A_MFTC0_FM_MMR6<"mfhc0", 0b00011, 0b110100>;
class MFHC2_MMR6_ENC : POOL32A_MFTC2_FM_MMR6<"mfhc2", 0b1000110100>;
class MOD_MMR6_ENC : ARITH_FM_MMR6<"mod", 0x158>;
class MODU_MMR6_ENC : ARITH_FM_MMR6<"modu", 0x1d8>;
class MUL_MMR6_ENC : ARITH_FM_MMR6<"mul", 0x18>;
class MUH_MMR6_ENC : ARITH_FM_MMR6<"muh", 0x58>;
class MULU_MMR6_ENC : ARITH_FM_MMR6<"mulu", 0x98>;
class MUHU_MMR6_ENC : ARITH_FM_MMR6<"muhu", 0xd8>;
class MTC0_MMR6_ENC : POOL32A_MFTC0_FM_MMR6<"mtc0", 0b01011, 0b111100>;
class MTC1_MMR6_ENC : POOL32F_MFTC1_FM_MMR6<"mtc1", 0b10100000>;
class MTC2_MMR6_ENC : POOL32A_MFTC2_FM_MMR6<"mtc2", 0b0101110100>;
class MTHC0_MMR6_ENC : POOL32A_MFTC0_FM_MMR6<"mthc0", 0b01011, 0b110100>;
class MTHC2_MMR6_ENC : POOL32A_MFTC2_FM_MMR6<"mthc2", 0b1001110100>;
class NOR_MMR6_ENC : ARITH_FM_MMR6<"nor", 0x2d0>;
class OR_MMR6_ENC : ARITH_FM_MMR6<"or", 0x290>;
class ORI_MMR6_ENC : ADDI_FM_MMR6<"ori", 0x14>;
class PREF_MMR6_ENC : CACHE_PREF_FM_MMR6<0b011000, 0b0010>;
class SB16_MMR6_ENC : LOAD_STORE_FM_MM16<0x22>;
class SELEQZ_MMR6_ENC : POOL32A_FM_MMR6<0b0101000000>;
class SELNEZ_MMR6_ENC : POOL32A_FM_MMR6<0b0110000000>;
class SH16_MMR6_ENC : LOAD_STORE_FM_MM16<0x2a>;
class SLL_MMR6_ENC : SHIFT_MMR6_ENC<"sll", 0x00, 0b0>;
class SUB_MMR6_ENC : ARITH_FM_MMR6<"sub", 0x190>;
class SUBU_MMR6_ENC : ARITH_FM_MMR6<"subu", 0x1d0>;
class SW_MMR6_ENC : SW32_FM_MMR6<"sw", 0x3e>;
class SW16_MMR6_ENC : LOAD_STORE_FM_MM16<0x3a>;
class SWM16_MMR6_ENC : POOL16C_LWM_SWM_FM_MM16R6<0xa>;
class SWSP_MMR6_ENC : LOAD_STORE_SP_FM_MM16<0x32>;
class WRPGPR_MMR6_ENC : POOL32A_WRPGPR_WSBH_FM_MMR6<"wrpgpr", 0x3c5>;
class WSBH_MMR6_ENC : POOL32A_WRPGPR_WSBH_FM_MMR6<"wsbh", 0x1ec>;
class LB_MMR6_ENC : LB32_FM_MMR6;
class LBU_MMR6_ENC : LBU32_FM_MMR6;
class PAUSE_MMR6_ENC : POOL32A_PAUSE_FM_MMR6<"pause", 0b00101>;
class RDHWR_MMR6_ENC : POOL32A_RDHWR_FM_MMR6;
class WAIT_MMR6_ENC : WAIT_FM_MM, MMR6Arch<"wait">;
class SSNOP_MMR6_ENC : BARRIER_FM_MM<0x1>, MMR6Arch<"ssnop">;
class SYNC_MMR6_ENC : POOL32A_SYNC_FM_MMR6;
class SYNCI_MMR6_ENC : POOL32I_SYNCI_FM_MMR6, MMR6Arch<"synci">;
class RDPGPR_MMR6_ENC : POOL32A_RDPGPR_FM_MMR6<0b1110000101>;
class SDBBP_MMR6_ENC : SDBBP_FM_MM, MMR6Arch<"sdbbp">;
class SIGRIE_MMR6_ENC : SIGRIE_FM_MM, MMR6Arch<"sigrie">;
class XOR_MMR6_ENC : ARITH_FM_MMR6<"xor", 0x310>;
class XORI_MMR6_ENC : ADDI_FM_MMR6<"xori", 0x1c>;
class ABS_S_MMR6_ENC : POOL32F_ABS_FM_MMR6<"abs.s", 0, 0b0001101>;
class ABS_D_MMR6_ENC : POOL32F_ABS_FM_MMR6<"abs.d", 1, 0b0001101>;
class FLOOR_L_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"floor.l.s", 0, 0b00001100>;
class FLOOR_L_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"floor.l.d", 1, 0b00001100>;
class FLOOR_W_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"floor.w.s", 0, 0b00101100>;
class FLOOR_W_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"floor.w.d", 1, 0b00101100>;
class CEIL_L_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"ceil.l.s", 0, 0b01001100>;
class CEIL_L_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"ceil.l.d", 1, 0b01001100>;
class CEIL_W_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"ceil.w.s", 0, 0b01101100>;
class CEIL_W_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"ceil.w.d", 1, 0b01101100>;
class TRUNC_L_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"trunc.l.s", 0, 0b10001100>;
class TRUNC_L_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"trunc.l.d", 1, 0b10001100>;
class TRUNC_W_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"trunc.w.s", 0, 0b10101100>;
class TRUNC_W_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"trunc.w.d", 1, 0b10101100>;
class SB_MMR6_ENC : SB32_SH32_STORE_FM_MMR6<0b000110>;
class SH_MMR6_ENC : SB32_SH32_STORE_FM_MMR6<0b001110>;
class LW_MMR6_ENC : LOAD_WORD_FM_MMR6;
class LUI_MMR6_ENC : LOAD_UPPER_IMM_FM_MMR6;
class JALRC_HB_MMR6_ENC : POOL32A_JALRC_FM_MMR6<"jalrc.hb", 0b0001111100>;
class RINT_S_MMR6_ENC : POOL32F_RINT_FM_MMR6<"rint.s", 0>;
class RINT_D_MMR6_ENC : POOL32F_RINT_FM_MMR6<"rint.d", 1>;
class ROUND_L_S_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"round.l.s", 0,
0b11001100>;
class ROUND_L_D_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"round.l.d", 1,
0b11001100>;
class ROUND_W_S_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"round.w.s", 0,
0b11101100>;
class ROUND_W_D_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"round.w.d", 1,
0b11101100>;
class SEL_S_MMR6_ENC : POOL32F_SEL_FM_MMR6<"sel.s", 0, 0b010111000>;
class SEL_D_MMR6_ENC : POOL32F_SEL_FM_MMR6<"sel.d", 1, 0b010111000>;
class SELEQZ_S_MMR6_ENC : POOL32F_SEL_FM_MMR6<"seleqz.s", 0, 0b000111000>;
class SELEQZ_D_MMR6_ENC : POOL32F_SEL_FM_MMR6<"seleqz.d", 1, 0b000111000>;
class SELNEZ_S_MMR6_ENC : POOL32F_SEL_FM_MMR6<"selnez.s", 0, 0b001111000>;
class SELNEZ_D_MMR6_ENC : POOL32F_SEL_FM_MMR6<"selnez.d", 1, 0b001111000>;
class CLASS_S_MMR6_ENC : POOL32F_CLASS_FM_MMR6<"class.s", 0, 0b001100000>;
class CLASS_D_MMR6_ENC : POOL32F_CLASS_FM_MMR6<"class.d", 1, 0b001100000>;
class EXT_MMR6_ENC : POOL32A_EXT_INS_FM_MMR6<"ext", 0b101100>;
class INS_MMR6_ENC : POOL32A_EXT_INS_FM_MMR6<"ins", 0b001100>;
class JALRC_MMR6_ENC : POOL32A_JALRC_FM_MMR6<"jalrc", 0b0000111100>;
class BOVC_MMR6_ENC : POP35_BOVC_FM_MMR6<"bovc">;
class BNVC_MMR6_ENC : POP37_BNVC_FM_MMR6<"bnvc">;
class ADDU16_MMR6_ENC : POOL16A_ADDU16_FM_MMR6;
class AND16_MMR6_ENC : POOL16C_AND16_FM_MMR6;
class ANDI16_MMR6_ENC : ANDI_FM_MM16<0b001011>;
class NOT16_MMR6_ENC : POOL16C_NOT16_FM_MMR6;
class OR16_MMR6_ENC : POOL16C_OR16_XOR16_FM_MMR6<0b1001>;
class SLL16_MMR6_ENC : SHIFT_FM_MM16<0>;
class SRL16_MMR6_ENC : SHIFT_FM_MM16<1>;
class BREAK16_MMR6_ENC : POOL16C_BREAKPOINT_FM_MMR6<0b011011>;
class LI16_MMR6_ENC : LI_FM_MM16;
class MOVE16_MMR6_ENC : MOVE_FM_MM16<0b000011>;
class MOVEP_MMR6_ENC : POOL16C_MOVEP16_FM_MMR6;
class SDBBP16_MMR6_ENC : POOL16C_BREAKPOINT_FM_MMR6<0b111011>;
class SUBU16_MMR6_ENC : POOL16A_SUBU16_FM_MMR6;
class XOR16_MMR6_ENC : POOL16C_OR16_XOR16_FM_MMR6<0b1000>;
class TLBINV_MMR6_ENC : POOL32A_TLBINV_FM_MMR6<"tlbinv", 0x10d>;
class TLBINVF_MMR6_ENC : POOL32A_TLBINV_FM_MMR6<"tlbinvf", 0x14d>;
class DVP_MMR6_ENC : POOL32A_DVPEVP_FM_MMR6<"dvp", 0b0001100101>;
class EVP_MMR6_ENC : POOL32A_DVPEVP_FM_MMR6<"evp", 0b0011100101>;
class BC1EQZC_MMR6_ENC : POOL32I_BRANCH_COP_1_2_FM_MMR6<"bc1eqzc", 0b01000>;
class BC1NEZC_MMR6_ENC : POOL32I_BRANCH_COP_1_2_FM_MMR6<"bc1nezc", 0b01001>;
class BC2EQZC_MMR6_ENC : POOL32I_BRANCH_COP_1_2_FM_MMR6<"bc2eqzc", 0b01010>;
class BC2NEZC_MMR6_ENC : POOL32I_BRANCH_COP_1_2_FM_MMR6<"bc2nezc", 0b01011>;
class LDC1_MMR6_ENC : LDWC1_SDWC1_FM_MMR6<"ldc1", 0b101111>;
class SDC1_MMR6_ENC : LDWC1_SDWC1_FM_MMR6<"sdc1", 0b101110>;
class LDC2_MMR6_ENC : POOL32B_LDWC2_SDWC2_FM_MMR6<"ldc2", 0b0010>;
class SDC2_MMR6_ENC : POOL32B_LDWC2_SDWC2_FM_MMR6<"sdc2", 0b1010>;
class LWC2_MMR6_ENC : POOL32B_LDWC2_SDWC2_FM_MMR6<"lwc2", 0b0000>;
class SWC2_MMR6_ENC : POOL32B_LDWC2_SDWC2_FM_MMR6<"swc2", 0b1000>;
class LL_MMR6_ENC : POOL32C_LL_E_SC_E_FM_MMR6<"ll", 0b0011, 0b000>;
class SC_MMR6_ENC : POOL32C_LL_E_SC_E_FM_MMR6<"sc", 0b1011, 0b000>;
/// Floating Point Instructions
class FADD_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"add.s", 0, 0b00110000>;
class FSUB_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"sub.s", 0, 0b01110000>;
class FMUL_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"mul.s", 0, 0b10110000>;
class FDIV_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"div.s", 0, 0b11110000>;
class MADDF_S_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"maddf.s", 0, 0b110111000>;
class MADDF_D_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"maddf.d", 1, 0b110111000>;
class MSUBF_S_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"msubf.s", 0, 0b111111000>;
class MSUBF_D_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"msubf.d", 1, 0b111111000>;
class FMOV_S_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"mov.s", 0, 0b0000001>;
class FNEG_S_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"neg.s", 0, 0b0101101>;
class MAX_S_MMR6_ENC : POOL32F_MINMAX_FM<"max.s", 0, 0b000001011>;
class MAX_D_MMR6_ENC : POOL32F_MINMAX_FM<"max.d", 1, 0b000001011>;
class MAXA_S_MMR6_ENC : POOL32F_MINMAX_FM<"maxa.s", 0, 0b000101011>;
class MAXA_D_MMR6_ENC : POOL32F_MINMAX_FM<"maxa.d", 1, 0b000101011>;
class MIN_S_MMR6_ENC : POOL32F_MINMAX_FM<"min.s", 0, 0b000000011>;
class MIN_D_MMR6_ENC : POOL32F_MINMAX_FM<"min.d", 1, 0b000000011>;
class MINA_S_MMR6_ENC : POOL32F_MINMAX_FM<"mina.s", 0, 0b000100011>;
class MINA_D_MMR6_ENC : POOL32F_MINMAX_FM<"mina.d", 1, 0b000100011>;
class CVT_L_S_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.l.s", 0, 0b00000100>;
class CVT_L_D_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.l.d", 1, 0b00000100>;
class CVT_W_S_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.w.s", 0, 0b00100100>;
class CVT_D_L_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.d.l", 2, 0b1001101>;
class CVT_S_W_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.s.w", 1, 0b1101101>;
class CVT_S_L_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.s.l", 2, 0b1101101>;
//===----------------------------------------------------------------------===//
//
// Instruction Descriptions
//
//===----------------------------------------------------------------------===//
class CMP_CBR_RT_Z_MMR6_DESC_BASE<string instr_asm, DAGOperand opnd,
RegisterOperand GPROpnd>
: BRANCH_DESC_BASE {
dag InOperandList = (ins GPROpnd:$rt, opnd:$offset);
dag OutOperandList = (outs);
string AsmString = !strconcat(instr_asm, "\t$rt, $offset");
list<Register> Defs = [AT];
InstrItinClass Itinerary = II_BCCZC;
}
class BEQZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"beqzalc", brtarget_mm,
GPR32Opnd> {
list<Register> Defs = [RA];
}
class BGEZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bgezalc", brtarget_mm,
GPR32Opnd> {
list<Register> Defs = [RA];
}
class BGTZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bgtzalc", brtarget_mm,
GPR32Opnd> {
list<Register> Defs = [RA];
}
class BLEZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"blezalc", brtarget_mm,
GPR32Opnd> {
list<Register> Defs = [RA];
}
class BLTZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bltzalc", brtarget_mm,
GPR32Opnd> {
list<Register> Defs = [RA];
}
class BNEZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bnezalc", brtarget_mm,
GPR32Opnd> {
list<Register> Defs = [RA];
}
class BLTZC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bltzc", brtarget_lsl2_mm,
GPR32Opnd>;
class BLEZC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"blezc", brtarget_lsl2_mm,
GPR32Opnd>;
class BGEZC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bgezc", brtarget_lsl2_mm,
GPR32Opnd>;
class BGTZC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bgtzc", brtarget_lsl2_mm,
GPR32Opnd>;
class CMP_CBR_2R_MMR6_DESC_BASE<string instr_asm, DAGOperand opnd,
RegisterOperand GPROpnd> : BRANCH_DESC_BASE {
dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, opnd:$offset);
dag OutOperandList = (outs);
string AsmString = !strconcat(instr_asm, "\t$rs, $rt, $offset");
list<Register> Defs = [AT];
InstrItinClass Itinerary = II_BCCC;
}
class BGEC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bgec", brtarget_lsl2_mm,
GPR32Opnd>;
class BGEUC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bgeuc", brtarget_lsl2_mm,
GPR32Opnd>;
class BLTC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bltc", brtarget_lsl2_mm,
GPR32Opnd>;
class BLTUC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bltuc", brtarget_lsl2_mm,
GPR32Opnd>;
class BEQC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"beqc", brtarget_lsl2_mm,
GPR32Opnd>;
class BNEC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bnec", brtarget_lsl2_mm,
GPR32Opnd>;
class ADD_MMR6_DESC : ArithLogicR<"add", GPR32Opnd, 1, II_ADD>;
class ADDIU_MMR6_DESC : ArithLogicI<"addiu", simm16, GPR32Opnd, II_ADDIU, immSExt16, add>;
class ADDU_MMR6_DESC : ArithLogicR<"addu", GPR32Opnd, 1, II_ADDU>;
class MUL_MMR6_DESC : ArithLogicR<"mul", GPR32Opnd, 1, II_MUL, mul>;
class MUH_MMR6_DESC : ArithLogicR<"muh", GPR32Opnd, 1, II_MUH, mulhs>;
class MULU_MMR6_DESC : ArithLogicR<"mulu", GPR32Opnd, 1, II_MULU>;
class MUHU_MMR6_DESC : ArithLogicR<"muhu", GPR32Opnd, 1, II_MUHU, mulhu>;
class BC_MMR6_DESC_BASE<string instr_asm, DAGOperand opnd, InstrItinClass Itin>
: BRANCH_DESC_BASE, MMR6Arch<instr_asm> {
dag InOperandList = (ins opnd:$offset);
dag OutOperandList = (outs);
string AsmString = !strconcat(instr_asm, "\t$offset");
bit isBarrier = 1;
InstrItinClass Itinerary = Itin;
}
class BALC_MMR6_DESC : BC_MMR6_DESC_BASE<"balc", brtarget26_mm, II_BALC> {
bit isCall = 1;
list<Register> Defs = [RA];
}
class BC_MMR6_DESC : BC_MMR6_DESC_BASE<"bc", brtarget26_mm, II_BC> {
list<dag> Pattern = [(br bb:$offset)];
}
class BC16_MMR6_DESC : MicroMipsInst16<(outs), (ins brtarget10_mm:$offset),
!strconcat("bc16", "\t$offset"), [],
II_BC, FrmI>,
MMR6Arch<"bc16"> {
let isBranch = 1;
let isTerminator = 1;
let isBarrier = 1;
let hasDelaySlot = 0;
let AdditionalPredicates = [RelocPIC];
let Defs = [AT];
}
class BEQZC_BNEZC_MM16R6_DESC_BASE<string instr_asm>
: CBranchZeroMM<instr_asm, brtarget7_mm, GPRMM16Opnd>,
MMR6Arch<instr_asm> {
let isBranch = 1;
let isTerminator = 1;
let hasDelaySlot = 0;
let Defs = [AT];
}
class BEQZC16_MMR6_DESC : BEQZC_BNEZC_MM16R6_DESC_BASE<"beqzc16">;
class BNEZC16_MMR6_DESC : BEQZC_BNEZC_MM16R6_DESC_BASE<"bnezc16">;
class SUB_MMR6_DESC : ArithLogicR<"sub", GPR32Opnd, 0, II_SUB>;
class SUBU_MMR6_DESC : ArithLogicR<"subu", GPR32Opnd, 0,II_SUBU>;
class BITSWAP_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd>
: MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rd);
dag InOperandList = (ins GPROpnd:$rt);
string AsmString = !strconcat(instr_asm, "\t$rd, $rt");
list<dag> Pattern = [];
InstrItinClass Itinerary = II_BITSWAP;
}
class BITSWAP_MMR6_DESC : BITSWAP_MMR6_DESC_BASE<"bitswap", GPR32Opnd>;
class BRK_MMR6_DESC : BRK_FT<"break">;
class CACHE_HINT_MMR6_DESC<string instr_asm, Operand MemOpnd,
RegisterOperand GPROpnd, InstrItinClass Itin>
: MMR6Arch<instr_asm> {
dag OutOperandList = (outs);
dag InOperandList = (ins MemOpnd:$addr, uimm5:$hint);
string AsmString = !strconcat(instr_asm, "\t$hint, $addr");
list<dag> Pattern = [];
string DecoderMethod = "DecodeCacheOpMM";
InstrItinClass Itinerary = Itin;
}
class CACHE_MMR6_DESC : CACHE_HINT_MMR6_DESC<"cache", mem_mm_12, GPR32Opnd,
II_CACHE>;
class PREF_MMR6_DESC : CACHE_HINT_MMR6_DESC<"pref", mem_mm_12, GPR32Opnd,
II_PREF>;
class LB_LBU_MMR6_DESC_BASE<string instr_asm, Operand MemOpnd,
RegisterOperand GPROpnd, InstrItinClass Itin>
: MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rt);
dag InOperandList = (ins MemOpnd:$addr);
string AsmString = !strconcat(instr_asm, "\t$rt, $addr");
string DecoderMethod = "DecodeLoadByte15";
bit mayLoad = 1;
InstrItinClass Itinerary = Itin;
}
class LB_MMR6_DESC : LB_LBU_MMR6_DESC_BASE<"lb", mem_mm_16, GPR32Opnd, II_LB>;
class LBU_MMR6_DESC : LB_LBU_MMR6_DESC_BASE<"lbu", mem_mm_16, GPR32Opnd,
II_LBU>;
class CLO_CLZ_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
InstrItinClass Itin> : MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rt);
dag InOperandList = (ins GPROpnd:$rs);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs");
InstrItinClass Itinerary = Itin;
}
class CLO_MMR6_DESC : CLO_CLZ_MMR6_DESC_BASE<"clo", GPR32Opnd, II_CLO>;
class CLZ_MMR6_DESC : CLO_CLZ_MMR6_DESC_BASE<"clz", GPR32Opnd, II_CLZ>;
class EHB_MMR6_DESC : Barrier<"ehb", II_EHB>;
class EI_MMR6_DESC : DEI_FT<"ei", GPR32Opnd, II_EI>;
class DI_MMR6_DESC : DEI_FT<"di", GPR32Opnd, II_DI>;
class ERET_MMR6_DESC : ER_FT<"eret", II_ERET>;
class DERET_MMR6_DESC : ER_FT<"deret", II_DERET>;
class ERETNC_MMR6_DESC : ER_FT<"eretnc", II_ERETNC>;
class JALRC16_MMR6_DESC_BASE<string opstr, RegisterOperand RO>
: MicroMipsInst16<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs"),
[(MipsJmpLink RO:$rs)], II_JALR, FrmR>,
MMR6Arch<opstr> {
let isCall = 1;
let hasDelaySlot = 0;
let Defs = [RA];
let hasPostISelHook = 1;
}
class JALRC16_MMR6_DESC : JALRC16_MMR6_DESC_BASE<"jalr", GPR32Opnd>;
class JMP_MMR6_IDX_COMPACT_DESC_BASE<string opstr, DAGOperand opnd,
RegisterOperand GPROpnd,
InstrItinClass Itin>
: MMR6Arch<opstr> {
dag InOperandList = (ins GPROpnd:$rt, opnd:$offset);
string AsmString = !strconcat(opstr, "\t$rt, $offset");
list<dag> Pattern = [];
bit isTerminator = 1;
bit hasDelaySlot = 0;
InstrItinClass Itinerary = Itin;
}
class JIALC_MMR6_DESC : JMP_MMR6_IDX_COMPACT_DESC_BASE<"jialc", calloffset16,
GPR32Opnd, II_JIALC> {
bit isCall = 1;
list<Register> Defs = [RA];
}
class JIC_MMR6_DESC : JMP_MMR6_IDX_COMPACT_DESC_BASE<"jic", jmpoffset16,
GPR32Opnd, II_JIC> {
bit isBarrier = 1;
list<Register> Defs = [AT];
}
class JRC16_MMR6_DESC_BASE<string opstr, RegisterOperand RO>
: MicroMipsInst16<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs"),
[], II_JR, FrmR>,
MMR6Arch<opstr> {
let hasDelaySlot = 0;
let isBranch = 1;
let isIndirectBranch = 1;
}
class JRC16_MMR6_DESC : JRC16_MMR6_DESC_BASE<"jrc16", GPR32Opnd>;
class JRCADDIUSP_MMR6_DESC
: MicroMipsInst16<(outs), (ins uimm5_lsl2:$imm), "jrcaddiusp\t$imm",
[], II_JRADDIUSP, FrmR>,
MMR6Arch<"jrcaddiusp"> {
let hasDelaySlot = 0;
let isTerminator = 1;
let isBarrier = 1;
let isBranch = 1;
let isIndirectBranch = 1;
}
class ALIGN_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
Operand ImmOpnd, InstrItinClass Itin>
: MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rd);
dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$bp);
string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $bp");
list<dag> Pattern = [];
InstrItinClass Itinerary = Itin;
}
class ALIGN_MMR6_DESC : ALIGN_MMR6_DESC_BASE<"align", GPR32Opnd, uimm2,
II_ALIGN>;
class AUI_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
InstrItinClass Itin> : MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rt);
dag InOperandList = (ins GPROpnd:$rs, uimm16:$imm);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $imm");
list<dag> Pattern = [];
InstrItinClass Itinerary = Itin;
}
class AUI_MMR6_DESC : AUI_MMR6_DESC_BASE<"aui", GPR32Opnd, II_AUI>;
class ALUIPC_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
InstrItinClass Itin> : MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rt);
dag InOperandList = (ins simm16:$imm);
string AsmString = !strconcat(instr_asm, "\t$rt, $imm");
list<dag> Pattern = [];
InstrItinClass Itinerary = Itin;
}
class ALUIPC_MMR6_DESC : ALUIPC_MMR6_DESC_BASE<"aluipc", GPR32Opnd, II_ALUIPC>;
class AUIPC_MMR6_DESC : ALUIPC_MMR6_DESC_BASE<"auipc", GPR32Opnd, II_AUIPC>;
class LSA_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
Operand ImmOpnd, InstrItinClass Itin>
: MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rd);
dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$imm2);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $rd, $imm2");
list<dag> Pattern = [];
InstrItinClass Itinerary = Itin;
}
class LSA_MMR6_DESC : LSA_MMR6_DESC_BASE<"lsa", GPR32Opnd, uimm2_plus1, II_LSA>;
class PCREL_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
Operand ImmOpnd, InstrItinClass Itin>
: MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rt);
dag InOperandList = (ins ImmOpnd:$imm);
string AsmString = !strconcat(instr_asm, "\t$rt, $imm");
list<dag> Pattern = [];
InstrItinClass Itinerary = Itin;
}
class ADDIUPC_MMR6_DESC : PCREL_MMR6_DESC_BASE<"addiupc", GPR32Opnd,
simm19_lsl2, II_ADDIUPC>;
class LWPC_MMR6_DESC: PCREL_MMR6_DESC_BASE<"lwpc", GPR32Opnd, simm19_lsl2,
II_LWPC>;
class SELEQNE_Z_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
InstrItinClass Itin> : MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rd);
dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt);
string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt");
list<dag> Pattern = [];
InstrItinClass Itinerary = Itin;
}
class SELEQZ_MMR6_DESC : SELEQNE_Z_MMR6_DESC_BASE<"seleqz", GPR32Opnd,
II_SELCCZ>;
class SELNEZ_MMR6_DESC : SELEQNE_Z_MMR6_DESC_BASE<"selnez", GPR32Opnd,
II_SELCCZ>;
class PAUSE_MMR6_DESC : Barrier<"pause", II_PAUSE>;
class RDHWR_MMR6_DESC : MMR6Arch<"rdhwr">, MipsR6Inst {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins HWRegsOpnd:$rs, uimm3:$sel);
string AsmString = !strconcat("rdhwr", "\t$rt, $rs, $sel");
list<dag> Pattern = [];
InstrItinClass Itinerary = II_RDHWR;
Format Form = FrmR;
}
class WAIT_MMR6_DESC : WaitMM<"wait">;
// FIXME: ssnop should not be defined for R6. Per MD000582 microMIPS32 6.03:
// Assemblers targeting specifically Release 6 should reject the SSNOP
// instruction with an error.
class SSNOP_MMR6_DESC : Barrier<"ssnop", II_SSNOP>;
class SLL_MMR6_DESC : shift_rotate_imm<"sll", uimm5, GPR32Opnd, II_SLL>;
class DIVMOD_MMR6_DESC_BASE<string opstr, RegisterOperand GPROpnd,
InstrItinClass Itin,
SDPatternOperator OpNode=null_frag>
: MipsR6Inst {
dag OutOperandList = (outs GPROpnd:$rd);
dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt);
string AsmString = !strconcat(opstr, "\t$rd, $rs, $rt");
list<dag> Pattern = [(set GPROpnd:$rd, (OpNode GPROpnd:$rs, GPROpnd:$rt))];
string BaseOpcode = opstr;
Format f = FrmR;
let isCommutable = 0;
let isReMaterializable = 1;
InstrItinClass Itinerary = Itin;
// This instruction doesn't trap division by zero itself. We must insert
// teq instructions as well.
bit usesCustomInserter = 1;
}
class DIV_MMR6_DESC : DIVMOD_MMR6_DESC_BASE<"div", GPR32Opnd, II_DIV, sdiv>;
class DIVU_MMR6_DESC : DIVMOD_MMR6_DESC_BASE<"divu", GPR32Opnd, II_DIVU, udiv>;
class MOD_MMR6_DESC : DIVMOD_MMR6_DESC_BASE<"mod", GPR32Opnd, II_MOD, srem>;
class MODU_MMR6_DESC : DIVMOD_MMR6_DESC_BASE<"modu", GPR32Opnd, II_MODU, urem>;
class AND_MMR6_DESC : ArithLogicR<"and", GPR32Opnd, 1, II_AND, and>;
class ANDI_MMR6_DESC : ArithLogicI<"andi", uimm16, GPR32Opnd, II_ANDI>;
class NOR_MMR6_DESC : LogicNOR<"nor", GPR32Opnd>;
class OR_MMR6_DESC : ArithLogicR<"or", GPR32Opnd, 1, II_OR, or>;
class ORI_MMR6_DESC : ArithLogicI<"ori", uimm16, GPR32Opnd, II_ORI, immZExt16,
or> {
int AddedComplexity = 1;
}
class XOR_MMR6_DESC : ArithLogicR<"xor", GPR32Opnd, 1, II_XOR, xor>;
class XORI_MMR6_DESC : ArithLogicI<"xori", uimm16, GPR32Opnd, II_XORI,
immZExt16, xor>;
class SW_MMR6_DESC : Store<"sw", GPR32Opnd> {
InstrItinClass Itinerary = II_SW;
}
class WRPGPR_WSBH_MMR6_DESC_BASE<string instr_asm, RegisterOperand RO,
InstrItinClass Itin> {
dag InOperandList = (ins RO:$rs);
dag OutOperandList = (outs RO:$rt);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs");
list<dag> Pattern = [];
Format f = FrmR;
string BaseOpcode = instr_asm;
bit hasSideEffects = 0;
InstrItinClass Itinerary = Itin;
}
class WRPGPR_MMR6_DESC : WRPGPR_WSBH_MMR6_DESC_BASE<"wrpgpr", GPR32Opnd,
II_WRPGPR>;
class WSBH_MMR6_DESC : WRPGPR_WSBH_MMR6_DESC_BASE<"wsbh", GPR32Opnd, II_WSBH>;
class MTC0_MMR6_DESC_BASE<string opstr, RegisterOperand DstRC,
RegisterOperand SrcRC, InstrItinClass Itin> {
dag InOperandList = (ins SrcRC:$rt, uimm3:$sel);
dag OutOperandList = (outs DstRC:$rs);
string AsmString = !strconcat(opstr, "\t$rt, $rs, $sel");
list<dag> Pattern = [];
Format f = FrmFR;
string BaseOpcode = opstr;
InstrItinClass Itinerary = Itin;
}
class MTC1_MMR6_DESC_BASE<
string opstr, RegisterOperand DstRC, RegisterOperand SrcRC,
InstrItinClass Itin = NoItinerary, SDPatternOperator OpNode = null_frag>
: MipsR6Inst {
dag InOperandList = (ins SrcRC:$rt);
dag OutOperandList = (outs DstRC:$fs);
string AsmString = !strconcat(opstr, "\t$rt, $fs");
list<dag> Pattern = [(set DstRC:$fs, (OpNode SrcRC:$rt))];
Format f = FrmFR;
InstrItinClass Itinerary = Itin;
string BaseOpcode = opstr;
}
class MTC1_64_MMR6_DESC_BASE<
string opstr, RegisterOperand DstRC, RegisterOperand SrcRC,
InstrItinClass Itin = NoItinerary> : MipsR6Inst {
dag InOperandList = (ins DstRC:$fs_in, SrcRC:$rt);
dag OutOperandList = (outs DstRC:$fs);
string AsmString = !strconcat(opstr, "\t$rt, $fs");
list<dag> Pattern = [];
Format f = FrmFR;
InstrItinClass Itinerary = Itin;
string BaseOpcode = opstr;
// $fs_in is part of a white lie to work around a widespread bug in the FPU
// implementation. See expandBuildPairF64 for details.
let Constraints = "$fs = $fs_in";
}
class MTC2_MMR6_DESC_BASE<string opstr, RegisterOperand DstRC,
RegisterOperand SrcRC, InstrItinClass Itin> {
dag InOperandList = (ins SrcRC:$rt);
dag OutOperandList = (outs DstRC:$impl);
string AsmString = !strconcat(opstr, "\t$rt, $impl");
list<dag> Pattern = [];
Format f = FrmFR;
string BaseOpcode = opstr;
InstrItinClass Itinerary = Itin;
}
class MTC0_MMR6_DESC : MTC0_MMR6_DESC_BASE<"mtc0", COP0Opnd, GPR32Opnd,
II_MTC0>;
class MTC1_MMR6_DESC : MTC1_MMR6_DESC_BASE<"mtc1", FGR32Opnd, GPR32Opnd,
II_MTC1, bitconvert>, HARDFLOAT;
class MTC2_MMR6_DESC : MTC2_MMR6_DESC_BASE<"mtc2", COP2Opnd, GPR32Opnd,
II_MTC2>;
class MTHC0_MMR6_DESC : MTC0_MMR6_DESC_BASE<"mthc0", COP0Opnd, GPR32Opnd,
II_MTHC0>;
class MTHC2_MMR6_DESC : MTC2_MMR6_DESC_BASE<"mthc2", COP2Opnd, GPR32Opnd,
II_MTC2>;
class MFC0_MMR6_DESC_BASE<string opstr, RegisterOperand DstRC,
RegisterOperand SrcRC, InstrItinClass Itin> {
dag InOperandList = (ins SrcRC:$rs, uimm3:$sel);
dag OutOperandList = (outs DstRC:$rt);
string AsmString = !strconcat(opstr, "\t$rt, $rs, $sel");
list<dag> Pattern = [];
Format f = FrmFR;
string BaseOpcode = opstr;
InstrItinClass Itinerary = Itin;
}
class MFC1_MMR6_DESC_BASE<string opstr, RegisterOperand DstRC,
RegisterOperand SrcRC,
InstrItinClass Itin = NoItinerary,
SDPatternOperator OpNode = null_frag> : MipsR6Inst {
dag InOperandList = (ins SrcRC:$fs);
dag OutOperandList = (outs DstRC:$rt);
string AsmString = !strconcat(opstr, "\t$rt, $fs");
list<dag> Pattern = [(set DstRC:$rt, (OpNode SrcRC:$fs))];
Format f = FrmFR;
InstrItinClass Itinerary = Itin;
string BaseOpcode = opstr;
}
class MFC2_MMR6_DESC_BASE<string opstr, RegisterOperand DstRC,
RegisterOperand SrcRC, InstrItinClass Itin> {
dag InOperandList = (ins SrcRC:$impl);
dag OutOperandList = (outs DstRC:$rt);
string AsmString = !strconcat(opstr, "\t$rt, $impl");
list<dag> Pattern = [];
Format f = FrmFR;
string BaseOpcode = opstr;
InstrItinClass Itinerary = Itin;
}
class MFC0_MMR6_DESC : MFC0_MMR6_DESC_BASE<"mfc0", GPR32Opnd, COP0Opnd,
II_MFC0>;
class MFC1_MMR6_DESC : MFC1_MMR6_DESC_BASE<"mfc1", GPR32Opnd, FGR32Opnd,
II_MFC1, bitconvert>, HARDFLOAT;
class MFC2_MMR6_DESC : MFC2_MMR6_DESC_BASE<"mfc2", GPR32Opnd, COP2Opnd,
II_MFC2>;
class MFHC0_MMR6_DESC : MFC0_MMR6_DESC_BASE<"mfhc0", GPR32Opnd, COP0Opnd,
II_MFHC0>;
class MFHC2_MMR6_DESC : MFC2_MMR6_DESC_BASE<"mfhc2", GPR32Opnd, COP2Opnd,
II_MFC2>;
class LDC1_D64_MMR6_DESC : MipsR6Inst, HARDFLOAT, FGR_64 {
dag InOperandList = (ins mem_mm_16:$addr);
dag OutOperandList = (outs FGR64Opnd:$ft);
string AsmString = !strconcat("ldc1", "\t$ft, $addr");
list<dag> Pattern = [(set FGR64Opnd:$ft, (load addrimm16:$addr))];
Format f = FrmFI;
InstrItinClass Itinerary = II_LDC1;
string BaseOpcode = "ldc1";
bit mayLoad = 1;
let DecoderMethod = "DecodeFMemMMR2";
}
class SDC1_D64_MMR6_DESC : MipsR6Inst, HARDFLOAT, FGR_64 {
dag InOperandList = (ins FGR64Opnd:$ft, mem_mm_16:$addr);
dag OutOperandList = (outs);
string AsmString = !strconcat("sdc1", "\t$ft, $addr");
list<dag> Pattern = [(store FGR64Opnd:$ft, addrimm16:$addr)];
Format f = FrmFI;
InstrItinClass Itinerary = II_SDC1;
string BaseOpcode = "sdc1";
bit mayStore = 1;
let DecoderMethod = "DecodeFMemMMR2";
}
class LDC2_LWC2_MMR6_DESC_BASE<string opstr, InstrItinClass itin> {
dag OutOperandList = (outs COP2Opnd:$rt);
dag InOperandList = (ins mem_mm_11:$addr);
string AsmString = !strconcat(opstr, "\t$rt, $addr");
list<dag> Pattern = [(set COP2Opnd:$rt, (load addrimm11:$addr))];
Format f = FrmFI;
InstrItinClass Itinerary = itin;
string BaseOpcode = opstr;
bit mayLoad = 1;
string DecoderMethod = "DecodeFMemCop2MMR6";
}
class LDC2_MMR6_DESC : LDC2_LWC2_MMR6_DESC_BASE<"ldc2", II_LDC2>;
class LWC2_MMR6_DESC : LDC2_LWC2_MMR6_DESC_BASE<"lwc2", II_LWC2>;
class SDC2_SWC2_MMR6_DESC_BASE<string opstr, InstrItinClass itin> {
dag OutOperandList = (outs);
dag InOperandList = (ins COP2Opnd:$rt, mem_mm_11:$addr);
string AsmString = !strconcat(opstr, "\t$rt, $addr");
list<dag> Pattern = [(store COP2Opnd:$rt, addrimm11:$addr)];
Format f = FrmFI;
InstrItinClass Itinerary = itin;
string BaseOpcode = opstr;
bit mayStore = 1;
string DecoderMethod = "DecodeFMemCop2MMR6";
}
class SDC2_MMR6_DESC : SDC2_SWC2_MMR6_DESC_BASE<"sdc2", II_SDC2>;
class SWC2_MMR6_DESC : SDC2_SWC2_MMR6_DESC_BASE<"swc2", II_SWC2>;
class GINV_MMR6_DESC_BASE<string opstr,
RegisterOperand SrcRC, InstrItinClass Itin> {
dag InOperandList = (ins SrcRC:$rs, uimm2:$type);
dag OutOperandList = (outs);
string AsmString = !strconcat(opstr, "\t$rs, $type");
list<dag> Pattern = [];
Format f = FrmFR;
string BaseOpcode = opstr;
InstrItinClass Itinerary = Itin;
}
class GINVI_MMR6_DESC : GINV_MMR6_DESC_BASE<"ginvi", GPR32Opnd,
II_GINVI> {
dag InOperandList = (ins GPR32Opnd:$rs);
string AsmString = "ginvi\t$rs";
}
class GINVT_MMR6_DESC : GINV_MMR6_DESC_BASE<"ginvt", GPR32Opnd,
II_GINVT>;
class SC_MMR6_DESC_BASE<string opstr, InstrItinClass itin> {
dag OutOperandList = (outs GPR32Opnd:$dst);
dag InOperandList = (ins GPR32Opnd:$rt, mem_mm_9:$addr);
string AsmString = !strconcat(opstr, "\t$rt, $addr");
InstrItinClass Itinerary = itin;
string BaseOpcode = opstr;
bit mayStore = 1;
string Constraints = "$rt = $dst";
string DecoderMethod = "DecodeMemMMImm9";
}
class LL_MMR6_DESC_BASE<string opstr, InstrItinClass itin> {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins mem_mm_9:$addr);
string AsmString = !strconcat(opstr, "\t$rt, $addr");
InstrItinClass Itinerary = itin;
string BaseOpcode = opstr;
bit mayLoad = 1;
string DecoderMethod = "DecodeMemMMImm9";
}
class SC_MMR6_DESC : SC_MMR6_DESC_BASE<"sc", II_SC>;
class LL_MMR6_DESC : LL_MMR6_DESC_BASE<"ll", II_LL>;
/// Floating Point Instructions
class FARITH_MMR6_DESC_BASE<string instr_asm, RegisterOperand RC,
InstrItinClass Itin, bit isComm,
SDPatternOperator OpNode = null_frag> : HARDFLOAT {
dag OutOperandList = (outs RC:$fd);
dag InOperandList = (ins RC:$ft, RC:$fs);
string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft");
list<dag> Pattern = [(set RC:$fd, (OpNode RC:$fs, RC:$ft))];
InstrItinClass Itinerary = Itin;
bit isCommutable = isComm;
}
class FADD_S_MMR6_DESC
: FARITH_MMR6_DESC_BASE<"add.s", FGR32Opnd, II_ADD_S, 1, fadd>;
class FSUB_S_MMR6_DESC
: FARITH_MMR6_DESC_BASE<"sub.s", FGR32Opnd, II_SUB_S, 0, fsub>;
class FMUL_S_MMR6_DESC
: FARITH_MMR6_DESC_BASE<"mul.s", FGR32Opnd, II_MUL_S, 1, fmul>;
class FDIV_S_MMR6_DESC
: FARITH_MMR6_DESC_BASE<"div.s", FGR32Opnd, II_DIV_S, 0, fdiv>;
class MADDF_S_MMR6_DESC : COP1_4R_DESC_BASE<"maddf.s", FGR32Opnd,
II_MADDF_S>, HARDFLOAT;
class MADDF_D_MMR6_DESC : COP1_4R_DESC_BASE<"maddf.d", FGR64Opnd,
II_MADDF_D>, HARDFLOAT;
class MSUBF_S_MMR6_DESC : COP1_4R_DESC_BASE<"msubf.s", FGR32Opnd,
II_MSUBF_S>, HARDFLOAT;
class MSUBF_D_MMR6_DESC : COP1_4R_DESC_BASE<"msubf.d", FGR64Opnd,
II_MSUBF_D>, HARDFLOAT;
class FMOV_FNEG_MMR6_DESC_BASE<string instr_asm, RegisterOperand DstRC,
RegisterOperand SrcRC, InstrItinClass Itin,
SDPatternOperator OpNode = null_frag>
: HARDFLOAT, NeverHasSideEffects {
dag OutOperandList = (outs DstRC:$ft);
dag InOperandList = (ins SrcRC:$fs);
string AsmString = !strconcat(instr_asm, "\t$ft, $fs");
list<dag> Pattern = [(set DstRC:$ft, (OpNode SrcRC:$fs))];
InstrItinClass Itinerary = Itin;
Format Form = FrmFR;
}
class FMOV_S_MMR6_DESC
: FMOV_FNEG_MMR6_DESC_BASE<"mov.s", FGR32Opnd, FGR32Opnd, II_MOV_S>;
class FNEG_S_MMR6_DESC
: FMOV_FNEG_MMR6_DESC_BASE<"neg.s", FGR32Opnd, FGR32Opnd, II_NEG, fneg>;
class MAX_S_MMR6_DESC : MAX_MIN_DESC_BASE<"max.s", FGR32Opnd, II_MAX_S>,
HARDFLOAT;
class MAX_D_MMR6_DESC : MAX_MIN_DESC_BASE<"max.d", FGR64Opnd, II_MAX_D>,
HARDFLOAT;
class MIN_S_MMR6_DESC : MAX_MIN_DESC_BASE<"min.s", FGR32Opnd, II_MIN_S>,
HARDFLOAT;
class MIN_D_MMR6_DESC : MAX_MIN_DESC_BASE<"min.d", FGR64Opnd, II_MIN_D>,
HARDFLOAT;
class MAXA_S_MMR6_DESC : MAX_MIN_DESC_BASE<"maxa.s", FGR32Opnd, II_MAXA_S>,
HARDFLOAT;
class MAXA_D_MMR6_DESC : MAX_MIN_DESC_BASE<"maxa.d", FGR64Opnd, II_MAXA_D>,
HARDFLOAT;
class MINA_S_MMR6_DESC : MAX_MIN_DESC_BASE<"mina.s", FGR32Opnd, II_MINA_S>,
HARDFLOAT;
class MINA_D_MMR6_DESC : MAX_MIN_DESC_BASE<"mina.d", FGR64Opnd, II_MINA_D>,
HARDFLOAT;
class CVT_MMR6_DESC_BASE<
string instr_asm, RegisterOperand DstRC, RegisterOperand SrcRC,
InstrItinClass Itin, SDPatternOperator OpNode = null_frag>
: HARDFLOAT, NeverHasSideEffects {
dag OutOperandList = (outs DstRC:$ft);
dag InOperandList = (ins SrcRC:$fs);
string AsmString = !strconcat(instr_asm, "\t$ft, $fs");
list<dag> Pattern = [(set DstRC:$ft, (OpNode SrcRC:$fs))];
InstrItinClass Itinerary = Itin;
Format Form = FrmFR;
}
class CVT_L_S_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.l.s", FGR64Opnd, FGR32Opnd,
II_CVT>;
class CVT_L_D_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.l.d", FGR64Opnd, FGR64Opnd,
II_CVT>;
class CVT_W_S_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.w.s", FGR32Opnd, FGR32Opnd,
II_CVT>;
class CVT_D_L_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.d.l", FGR64Opnd, FGR64Opnd,
II_CVT>, FGR_64;
class CVT_S_W_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.s.w", FGR32Opnd, FGR32Opnd,
II_CVT>;
class CVT_S_L_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.s.l", FGR64Opnd, FGR32Opnd,
II_CVT>, FGR_64;
multiclass CMP_CC_MMR6<bits<6> format, string Typestr,
RegisterOperand FGROpnd, InstrItinClass Itin> {
def CMP_AF_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.af.", Typestr), format, FIELD_CMP_COND_AF>,
CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_UN_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.un.", Typestr), format, FIELD_CMP_COND_UN>,
CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd, Itin, setuo>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_EQ_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.eq.", Typestr), format, FIELD_CMP_COND_EQ>,
CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd, Itin, setoeq>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_UEQ_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.ueq.", Typestr), format, FIELD_CMP_COND_UEQ>,
CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd, Itin, setueq>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_LT_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.lt.", Typestr), format, FIELD_CMP_COND_LT>,
CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd, Itin, setolt>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_ULT_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.ult.", Typestr), format, FIELD_CMP_COND_ULT>,
CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd, Itin, setult>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_LE_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.le.", Typestr), format, FIELD_CMP_COND_LE>,
CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd, Itin, setole>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_ULE_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.ule.", Typestr), format, FIELD_CMP_COND_ULE>,
CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd, Itin, setule>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SAF_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.saf.", Typestr), format, FIELD_CMP_COND_SAF>,
CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SUN_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sun.", Typestr), format, FIELD_CMP_COND_SUN>,
CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SEQ_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.seq.", Typestr), format, FIELD_CMP_COND_SEQ>,
CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SUEQ_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sueq.", Typestr), format, FIELD_CMP_COND_SUEQ>,
CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SLT_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.slt.", Typestr), format, FIELD_CMP_COND_SLT>,
CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SULT_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sult.", Typestr), format, FIELD_CMP_COND_SULT>,
CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SLE_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sle.", Typestr), format, FIELD_CMP_COND_SLE>,
CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SULE_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sule.", Typestr), format, FIELD_CMP_COND_SULE>,
CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
}
class ABSS_FT_MMR6_DESC_BASE<string instr_asm, RegisterOperand DstRC,
RegisterOperand SrcRC, InstrItinClass Itin,
SDPatternOperator OpNode = null_frag>
: HARDFLOAT, NeverHasSideEffects {
dag OutOperandList = (outs DstRC:$ft);
dag InOperandList = (ins SrcRC:$fs);
string AsmString = !strconcat(instr_asm, "\t$ft, $fs");
list<dag> Pattern = [(set DstRC:$ft, (OpNode SrcRC:$fs))];
InstrItinClass Itinerary = Itin;
Format Form = FrmFR;
list<Predicate> EncodingPredicates = [HasStdEnc];
}
class FLOOR_L_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"floor.l.s", FGR64Opnd,
FGR32Opnd, II_FLOOR>;
class FLOOR_L_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"floor.l.d", FGR64Opnd,
FGR64Opnd, II_FLOOR>;
class FLOOR_W_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"floor.w.s", FGR32Opnd,
FGR32Opnd, II_FLOOR>;
class FLOOR_W_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"floor.w.d", FGR32Opnd,
AFGR64Opnd, II_FLOOR>;
class CEIL_L_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"ceil.l.s", FGR64Opnd,
FGR32Opnd, II_CEIL>;
class CEIL_L_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"ceil.l.d", FGR64Opnd,
FGR64Opnd, II_CEIL>;
class CEIL_W_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"ceil.w.s", FGR32Opnd,
FGR32Opnd, II_CEIL>;
class CEIL_W_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"ceil.w.d", FGR32Opnd,
AFGR64Opnd, II_CEIL>;
class TRUNC_L_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"trunc.l.s", FGR64Opnd,
FGR32Opnd, II_TRUNC>;
class TRUNC_L_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"trunc.l.d", FGR64Opnd,
FGR64Opnd, II_TRUNC>;
class TRUNC_W_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"trunc.w.s", FGR32Opnd,
FGR32Opnd, II_TRUNC>;
class TRUNC_W_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"trunc.w.d", FGR32Opnd,
- AFGR64Opnd, II_TRUNC>;
+ FGR64Opnd, II_TRUNC>;
class SQRT_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"sqrt.s", FGR32Opnd, FGR32Opnd,
II_SQRT_S, fsqrt>;
class SQRT_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"sqrt.d", AFGR64Opnd, AFGR64Opnd,
II_SQRT_D, fsqrt>;
class ROUND_L_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.l.s", FGR64Opnd,
FGR32Opnd, II_ROUND>;
class ROUND_L_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.l.d", FGR64Opnd,
FGR64Opnd, II_ROUND>;
class ROUND_W_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.w.s", FGR32Opnd,
FGR32Opnd, II_ROUND>;
class ROUND_W_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.w.d", FGR64Opnd,
FGR64Opnd, II_ROUND>;
class SEL_S_MMR6_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd, II_SEL_S>;
class SEL_D_MMR6_DESC : COP1_SEL_D_DESC_BASE<"sel.d", FGR64Opnd, II_SEL_D>;
class SELEQZ_S_MMR6_DESC : SELEQNEZ_DESC_BASE<"seleqz.s", FGR32Opnd,
II_SELCCZ_S>;
class SELEQZ_D_MMR6_DESC : SELEQNEZ_DESC_BASE<"seleqz.d", FGR64Opnd,
II_SELCCZ_D>;
class SELNEZ_S_MMR6_DESC : SELEQNEZ_DESC_BASE<"selnez.s", FGR32Opnd,
II_SELCCZ_S>;
class SELNEZ_D_MMR6_DESC : SELEQNEZ_DESC_BASE<"selnez.d", FGR64Opnd,
II_SELCCZ_D>;
class RINT_S_MMR6_DESC : CLASS_RINT_DESC_BASE<"rint.s", FGR32Opnd,
II_RINT_S>;
class RINT_D_MMR6_DESC : CLASS_RINT_DESC_BASE<"rint.d", FGR64Opnd,
II_RINT_S>;
class CLASS_S_MMR6_DESC : CLASS_RINT_DESC_BASE<"class.s", FGR32Opnd,
II_CLASS_S>;
class CLASS_D_MMR6_DESC : CLASS_RINT_DESC_BASE<"class.d", FGR64Opnd,
II_CLASS_S>;
class STORE_MMR6_DESC_BASE<string opstr, DAGOperand RO,
InstrItinClass Itin>
: Store<opstr, RO>, MMR6Arch<opstr> {
let DecoderMethod = "DecodeMemMMImm16";
InstrItinClass Itinerary = Itin;
}
class SB_MMR6_DESC : STORE_MMR6_DESC_BASE<"sb", GPR32Opnd, II_SB>;
class SH_MMR6_DESC : STORE_MMR6_DESC_BASE<"sh", GPR32Opnd, II_SH>;
class ADDU16_MMR6_DESC : ArithRMM16<"addu16", GPRMM16Opnd, 1, II_ADDU, add>,
MMR6Arch<"addu16"> {
int AddedComplexity = 1;
}
class AND16_MMR6_DESC : LogicRMM16<"and16", GPRMM16Opnd, II_AND>,
MMR6Arch<"and16">;
class ANDI16_MMR6_DESC : AndImmMM16<"andi16", GPRMM16Opnd, II_AND>,
MMR6Arch<"andi16">;
class NOT16_MMR6_DESC : NotMM16<"not16", GPRMM16Opnd>, MMR6Arch<"not16"> {
int AddedComplexity = 1;
}
class OR16_MMR6_DESC : LogicRMM16<"or16", GPRMM16Opnd, II_OR>, MMR6Arch<"or16">;
class SLL16_MMR6_DESC : ShiftIMM16<"sll16", uimm3_shift, GPRMM16Opnd, II_SLL>,
MMR6Arch<"sll16">;
class SRL16_MMR6_DESC : ShiftIMM16<"srl16", uimm3_shift, GPRMM16Opnd, II_SRL>,
MMR6Arch<"srl16">;
class BREAK16_MMR6_DESC : BrkSdbbp16MM<"break16", II_BREAK>, MMR6Arch<"break16">;
class LI16_MMR6_DESC : LoadImmMM16<"li16", li16_imm, GPRMM16Opnd>,
MMR6Arch<"li16">, IsAsCheapAsAMove;
class MOVE16_MMR6_DESC : MoveMM16<"move16", GPR32Opnd>, MMR6Arch<"move16">;
class MOVEP_MMR6_DESC : MovePMM16<"movep", GPRMM16OpndMovePPairFirst,
GPRMM16OpndMovePPairSecond, GPRMM16OpndMoveP>,
MMR6Arch<"movep">;
class SDBBP16_MMR6_DESC : BrkSdbbp16MM<"sdbbp16", II_SDBBP>, MMR6Arch<"sdbbp16">;
class SUBU16_MMR6_DESC : ArithRMM16<"subu16", GPRMM16Opnd, 0, II_SUBU, sub>,
MMR6Arch<"subu16"> {
int AddedComplexity = 1;
}
class XOR16_MMR6_DESC : LogicRMM16<"xor16", GPRMM16Opnd, II_XOR>,
MMR6Arch<"xor16">;
class LW_MMR6_DESC : MMR6Arch<"lw">, MipsR6Inst {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins mem:$addr);
string AsmString = "lw\t$rt, $addr";
let DecoderMethod = "DecodeMemMMImm16";
let canFoldAsLoad = 1;
let mayLoad = 1;
list<dag> Pattern = [(set GPR32Opnd:$rt, (load addrDefault:$addr))];
InstrItinClass Itinerary = II_LW;
}
class LUI_MMR6_DESC : IsAsCheapAsAMove, MMR6Arch<"lui">, MipsR6Inst{
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins uimm16:$imm16);
string AsmString = "lui\t$rt, $imm16";
list<dag> Pattern = [];
bit hasSideEffects = 0;
bit isReMaterializable = 1;
InstrItinClass Itinerary = II_LUI;
Format Form = FrmI;
}
class SYNC_MMR6_DESC : MMR6Arch<"sync">, MipsR6Inst {
dag OutOperandList = (outs);
dag InOperandList = (ins uimm5:$stype);
string AsmString = !strconcat("sync", "\t$stype");
list<dag> Pattern = [(MipsSync immZExt5:$stype)];
InstrItinClass Itinerary = II_SYNC;
bit HasSideEffects = 1;
}
class SYNCI_MMR6_DESC : SYNCI_FT<"synci", mem_mm_16> {
let DecoderMethod = "DecodeSynciR6";
}
class RDPGPR_MMR6_DESC : MMR6Arch<"rdpgpr">, MipsR6Inst {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins GPR32Opnd:$rd);
string AsmString = !strconcat("rdpgpr", "\t$rt, $rd");
InstrItinClass Itinerary = II_RDPGPR;
}
class SDBBP_MMR6_DESC : MipsR6Inst {
dag OutOperandList = (outs);
dag InOperandList = (ins uimm20:$code_);
string AsmString = !strconcat("sdbbp", "\t$code_");
list<dag> Pattern = [];
InstrItinClass Itinerary = II_SDBBP;
}
class SIGRIE_MMR6_DESC : MipsR6Inst {
dag OutOperandList = (outs);
dag InOperandList = (ins uimm16:$code_);
string AsmString = !strconcat("sigrie", "\t$code_");
list<dag> Pattern = [];
InstrItinClass Itinerary = II_SIGRIE;
}
class LWM16_MMR6_DESC
: MicroMipsInst16<(outs reglist16:$rt), (ins mem_mm_4sp:$addr),
!strconcat("lwm16", "\t$rt, $addr"), [],
II_LWM, FrmI>,
MMR6Arch<"lwm16"> {
let DecoderMethod = "DecodeMemMMReglistImm4Lsl2";
let mayLoad = 1;
ComplexPattern Addr = addr;
}
class SWM16_MMR6_DESC
: MicroMipsInst16<(outs), (ins reglist16:$rt, mem_mm_4sp:$addr),
!strconcat("swm16", "\t$rt, $addr"), [],
II_SWM, FrmI>,
MMR6Arch<"swm16"> {
let DecoderMethod = "DecodeMemMMReglistImm4Lsl2";
let mayStore = 1;
ComplexPattern Addr = addr;
}
class SB16_MMR6_DESC_BASE<string opstr, DAGOperand RTOpnd, DAGOperand RO,
SDPatternOperator OpNode, InstrItinClass Itin,
Operand MemOpnd>
: MicroMipsInst16<(outs), (ins RTOpnd:$rt, MemOpnd:$addr),
!strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI>,
MMR6Arch<opstr> {
let DecoderMethod = "DecodeMemMMImm4";
let mayStore = 1;
}
class SB16_MMR6_DESC : SB16_MMR6_DESC_BASE<"sb16", GPRMM16OpndZero, GPRMM16Opnd,
truncstorei8, II_SB, mem_mm_4>;
class SH16_MMR6_DESC : SB16_MMR6_DESC_BASE<"sh16", GPRMM16OpndZero, GPRMM16Opnd,
truncstorei16, II_SH, mem_mm_4_lsl1>;
class SW16_MMR6_DESC : SB16_MMR6_DESC_BASE<"sw16", GPRMM16OpndZero, GPRMM16Opnd,
store, II_SW, mem_mm_4_lsl2>;
class SWSP_MMR6_DESC
: MicroMipsInst16<(outs), (ins GPR32Opnd:$rt, mem_mm_sp_imm5_lsl2:$offset),
!strconcat("sw", "\t$rt, $offset"), [], II_SW, FrmI>,
MMR6Arch<"sw"> {
let DecoderMethod = "DecodeMemMMSPImm5Lsl2";
let mayStore = 1;
}
class JALRC_HB_MMR6_DESC {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins GPR32Opnd:$rs);
string AsmString = !strconcat("jalrc.hb", "\t$rt, $rs");
list<dag> Pattern = [];
InstrItinClass Itinerary = II_JALR_HB;
Format Form = FrmJ;
bit isIndirectBranch = 1;
bit hasDelaySlot = 0;
}
class TLBINV_MMR6_DESC_BASE<string opstr, InstrItinClass Itin> {
dag OutOperandList = (outs);
dag InOperandList = (ins);
string AsmString = opstr;
list<dag> Pattern = [];
InstrItinClass Itinerary = Itin;
}
class TLBINV_MMR6_DESC : TLBINV_MMR6_DESC_BASE<"tlbinv", II_TLBINV>;
class TLBINVF_MMR6_DESC : TLBINV_MMR6_DESC_BASE<"tlbinvf", II_TLBINVF>;
class DVPEVP_MMR6_DESC_BASE<string opstr, InstrItinClass Itin> {
dag OutOperandList = (outs GPR32Opnd:$rs);
dag InOperandList = (ins);
string AsmString = !strconcat(opstr, "\t$rs");
list<dag> Pattern = [];
InstrItinClass Itinerary = Itin;
bit hasUnModeledSideEffects = 1;
}
class DVP_MMR6_DESC : DVPEVP_MMR6_DESC_BASE<"dvp", II_DVP>;
class EVP_MMR6_DESC : DVPEVP_MMR6_DESC_BASE<"evp", II_EVP>;
class BEQZC_MMR6_DESC
: CMP_CBR_EQNE_Z_DESC_BASE<"beqzc", brtarget21_mm, GPR32Opnd>,
MMR6Arch<"beqzc">;
class BNEZC_MMR6_DESC
: CMP_CBR_EQNE_Z_DESC_BASE<"bnezc", brtarget21_mm, GPR32Opnd>,
MMR6Arch<"bnezc">;
class BRANCH_COP1_MMR6_DESC_BASE<string opstr> :
InstSE<(outs), (ins FGR64Opnd:$rt, brtarget_mm:$offset),
!strconcat(opstr, "\t$rt, $offset"), [], II_BC1CCZ, FrmI>,
HARDFLOAT, BRANCH_DESC_BASE {
list<Register> Defs = [AT];
}
class BC1EQZC_MMR6_DESC : BRANCH_COP1_MMR6_DESC_BASE<"bc1eqzc">;
class BC1NEZC_MMR6_DESC : BRANCH_COP1_MMR6_DESC_BASE<"bc1nezc">;
class BRANCH_COP2_MMR6_DESC_BASE<string opstr, InstrItinClass Itin>
: BRANCH_DESC_BASE {
dag InOperandList = (ins COP2Opnd:$rt, brtarget_mm:$offset);
dag OutOperandList = (outs);
string AsmString = !strconcat(opstr, "\t$rt, $offset");
list<Register> Defs = [AT];
InstrItinClass Itinerary = Itin;
}
class BC2EQZC_MMR6_DESC : BRANCH_COP2_MMR6_DESC_BASE<"bc2eqzc", II_BC2CCZ>;
class BC2NEZC_MMR6_DESC : BRANCH_COP2_MMR6_DESC_BASE<"bc2nezc", II_BC2CCZ>;
class EXT_MMR6_DESC {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins GPR32Opnd:$rs, uimm5:$pos, uimm5_plus1:$size);
string AsmString = !strconcat("ext", "\t$rt, $rs, $pos, $size");
list<dag> Pattern = [(set GPR32Opnd:$rt, (MipsExt GPR32Opnd:$rs, imm:$pos,
imm:$size))];
InstrItinClass Itinerary = II_EXT;
Format Form = FrmR;
string BaseOpcode = "ext";
}
class INS_MMR6_DESC {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins GPR32Opnd:$rs, uimm5:$pos, uimm5_inssize_plus1:$size,
GPR32Opnd:$src);
string AsmString = !strconcat("ins", "\t$rt, $rs, $pos, $size");
list<dag> Pattern = [(set GPR32Opnd:$rt, (MipsIns GPR32Opnd:$rs, imm:$pos,
imm:$size, GPR32Opnd:$src))];
InstrItinClass Itinerary = II_INS;
Format Form = FrmR;
string BaseOpcode = "ins";
string Constraints = "$src = $rt";
}
class JALRC_MMR6_DESC {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins GPR32Opnd:$rs);
string AsmString = !strconcat("jalrc", "\t$rt, $rs");
list<dag> Pattern = [];
InstrItinClass Itinerary = II_JALRC;
bit isCall = 1;
bit hasDelaySlot = 0;
list<Register> Defs = [RA];
}
class BOVC_BNVC_MMR6_DESC_BASE<string instr_asm, Operand opnd,
RegisterOperand GPROpnd>
: BRANCH_DESC_BASE {
dag InOperandList = (ins GPROpnd:$rt, GPROpnd:$rs, opnd:$offset);
dag OutOperandList = (outs);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $offset");
list<Register> Defs = [AT];
InstrItinClass Itinerary = II_BCCC;
}
class BOVC_MMR6_DESC : BOVC_BNVC_MMR6_DESC_BASE<"bovc", brtargetr6, GPR32Opnd>;
class BNVC_MMR6_DESC : BOVC_BNVC_MMR6_DESC_BASE<"bnvc", brtargetr6, GPR32Opnd>;
//===----------------------------------------------------------------------===//
//
// Instruction Definitions
//
//===----------------------------------------------------------------------===//
let DecoderNamespace = "MicroMipsR6" in {
def ADD_MMR6 : StdMMR6Rel, ADD_MMR6_DESC, ADD_MMR6_ENC, ISA_MICROMIPS32R6;
def ADDIU_MMR6 : StdMMR6Rel, ADDIU_MMR6_DESC, ADDIU_MMR6_ENC, ISA_MICROMIPS32R6;
def ADDU_MMR6 : StdMMR6Rel, ADDU_MMR6_DESC, ADDU_MMR6_ENC, ISA_MICROMIPS32R6;
def ADDIUPC_MMR6 : R6MMR6Rel, ADDIUPC_MMR6_ENC, ADDIUPC_MMR6_DESC,
ISA_MICROMIPS32R6;
def ALUIPC_MMR6 : R6MMR6Rel, ALUIPC_MMR6_ENC, ALUIPC_MMR6_DESC,
ISA_MICROMIPS32R6;
def AND_MMR6 : StdMMR6Rel, AND_MMR6_DESC, AND_MMR6_ENC, ISA_MICROMIPS32R6;
def ANDI_MMR6 : StdMMR6Rel, ANDI_MMR6_DESC, ANDI_MMR6_ENC, ISA_MICROMIPS32R6;
def AUIPC_MMR6 : R6MMR6Rel, AUIPC_MMR6_ENC, AUIPC_MMR6_DESC, ISA_MICROMIPS32R6;
def ALIGN_MMR6 : R6MMR6Rel, ALIGN_MMR6_ENC, ALIGN_MMR6_DESC, ISA_MICROMIPS32R6;
def AUI_MMR6 : R6MMR6Rel, AUI_MMR6_ENC, AUI_MMR6_DESC, ISA_MICROMIPS32R6;
def BALC_MMR6 : R6MMR6Rel, BALC_MMR6_ENC, BALC_MMR6_DESC, ISA_MICROMIPS32R6;
def BC_MMR6 : R6MMR6Rel, BC_MMR6_ENC, BC_MMR6_DESC, ISA_MICROMIPS32R6;
def BC16_MMR6 : StdMMR6Rel, BC16_MMR6_DESC, BC16_MMR6_ENC, ISA_MICROMIPS32R6;
def BEQZC_MMR6 : R6MMR6Rel, BEQZC_MMR6_ENC, BEQZC_MMR6_DESC,
ISA_MICROMIPS32R6;
def BEQZC16_MMR6 : StdMMR6Rel, BEQZC16_MMR6_DESC, BEQZC16_MMR6_ENC,
ISA_MICROMIPS32R6;
def BNEZC_MMR6 : R6MMR6Rel, BNEZC_MMR6_ENC, BNEZC_MMR6_DESC,
ISA_MICROMIPS32R6;
def BNEZC16_MMR6 : StdMMR6Rel, BNEZC16_MMR6_DESC, BNEZC16_MMR6_ENC,
ISA_MICROMIPS32R6;
def BITSWAP_MMR6 : R6MMR6Rel, BITSWAP_MMR6_ENC, BITSWAP_MMR6_DESC,
ISA_MICROMIPS32R6;
def BEQZALC_MMR6 : R6MMR6Rel, BEQZALC_MMR6_ENC, BEQZALC_MMR6_DESC,
ISA_MICROMIPS32R6;
def BNEZALC_MMR6 : R6MMR6Rel, BNEZALC_MMR6_ENC, BNEZALC_MMR6_DESC,
ISA_MICROMIPS32R6;
def BREAK_MMR6 : StdMMR6Rel, BRK_MMR6_DESC, BRK_MMR6_ENC, ISA_MICROMIPS32R6;
def CACHE_MMR6 : R6MMR6Rel, CACHE_MMR6_ENC, CACHE_MMR6_DESC, ISA_MICROMIPS32R6;
def CLO_MMR6 : R6MMR6Rel, CLO_MMR6_ENC, CLO_MMR6_DESC, ISA_MICROMIPS32R6;
def CLZ_MMR6 : R6MMR6Rel, CLZ_MMR6_ENC, CLZ_MMR6_DESC, ISA_MICROMIPS32R6;
def DIV_MMR6 : R6MMR6Rel, DIV_MMR6_DESC, DIV_MMR6_ENC, ISA_MICROMIPS32R6;
def DIVU_MMR6 : R6MMR6Rel, DIVU_MMR6_DESC, DIVU_MMR6_ENC, ISA_MICROMIPS32R6;
def EHB_MMR6 : StdMMR6Rel, EHB_MMR6_DESC, EHB_MMR6_ENC, ISA_MICROMIPS32R6;
def EI_MMR6 : StdMMR6Rel, EI_MMR6_DESC, EI_MMR6_ENC, ISA_MICROMIPS32R6;
def DI_MMR6 : StdMMR6Rel, DI_MMR6_DESC, DI_MMR6_ENC, ISA_MICROMIPS32R6;
def ERET_MMR6 : StdMMR6Rel, ERET_MMR6_DESC, ERET_MMR6_ENC, ISA_MICROMIPS32R6;
def DERET_MMR6 : StdMMR6Rel, DERET_MMR6_DESC, DERET_MMR6_ENC, ISA_MICROMIPS32R6;
def ERETNC_MMR6 : R6MMR6Rel, ERETNC_MMR6_DESC, ERETNC_MMR6_ENC,
ISA_MICROMIPS32R6;
def GINVI_MMR6 : R6MMR6Rel, GINVI_MMR6_ENC, GINVI_MMR6_DESC,
ISA_MICROMIPS32R6, ASE_GINV;
def GINVT_MMR6 : R6MMR6Rel, GINVT_MMR6_ENC, GINVT_MMR6_DESC,
ISA_MICROMIPS32R6, ASE_GINV;
let FastISelShouldIgnore = 1 in
def JALRC16_MMR6 : R6MMR6Rel, JALRC16_MMR6_DESC, JALRC16_MMR6_ENC,
ISA_MICROMIPS32R6;
def JIALC_MMR6 : R6MMR6Rel, JIALC_MMR6_ENC, JIALC_MMR6_DESC, ISA_MICROMIPS32R6;
def JIC_MMR6 : R6MMR6Rel, JIC_MMR6_ENC, JIC_MMR6_DESC, ISA_MICROMIPS32R6;
def JRC16_MMR6 : R6MMR6Rel, JRC16_MMR6_DESC, JRC16_MMR6_ENC, ISA_MICROMIPS32R6;
def JRCADDIUSP_MMR6 : R6MMR6Rel, JRCADDIUSP_MMR6_DESC, JRCADDIUSP_MMR6_ENC,
ISA_MICROMIPS32R6;
def LSA_MMR6 : R6MMR6Rel, LSA_MMR6_ENC, LSA_MMR6_DESC, ISA_MICROMIPS32R6;
def LWPC_MMR6 : R6MMR6Rel, LWPC_MMR6_ENC, LWPC_MMR6_DESC, ISA_MICROMIPS32R6;
def LWM16_MMR6 : StdMMR6Rel, LWM16_MMR6_DESC, LWM16_MMR6_ENC, ISA_MICROMIPS32R6;
def MTC0_MMR6 : StdMMR6Rel, MTC0_MMR6_ENC, MTC0_MMR6_DESC, ISA_MICROMIPS32R6;
def MTC1_MMR6 : StdMMR6Rel, MTC1_MMR6_DESC, MTC1_MMR6_ENC, ISA_MICROMIPS32R6;
def MTC2_MMR6 : StdMMR6Rel, MTC2_MMR6_ENC, MTC2_MMR6_DESC, ISA_MICROMIPS32R6;
def MTHC0_MMR6 : R6MMR6Rel, MTHC0_MMR6_ENC, MTHC0_MMR6_DESC, ISA_MICROMIPS32R6;
def MTHC2_MMR6 : StdMMR6Rel, MTHC2_MMR6_ENC, MTHC2_MMR6_DESC, ISA_MICROMIPS32R6;
def MFC0_MMR6 : StdMMR6Rel, MFC0_MMR6_ENC, MFC0_MMR6_DESC, ISA_MICROMIPS32R6;
def MFC1_MMR6 : StdMMR6Rel, MFC1_MMR6_DESC, MFC1_MMR6_ENC, ISA_MICROMIPS32R6;
def MFC2_MMR6 : StdMMR6Rel, MFC2_MMR6_ENC, MFC2_MMR6_DESC, ISA_MICROMIPS32R6;
def MFHC0_MMR6 : R6MMR6Rel, MFHC0_MMR6_ENC, MFHC0_MMR6_DESC, ISA_MICROMIPS32R6;
def MFHC2_MMR6 : StdMMR6Rel, MFHC2_MMR6_ENC, MFHC2_MMR6_DESC, ISA_MICROMIPS32R6;
def MOD_MMR6 : R6MMR6Rel, MOD_MMR6_DESC, MOD_MMR6_ENC, ISA_MICROMIPS32R6;
def MODU_MMR6 : R6MMR6Rel, MODU_MMR6_DESC, MODU_MMR6_ENC, ISA_MICROMIPS32R6;
def MUL_MMR6 : R6MMR6Rel, MUL_MMR6_DESC, MUL_MMR6_ENC, ISA_MICROMIPS32R6;
def MUH_MMR6 : R6MMR6Rel, MUH_MMR6_DESC, MUH_MMR6_ENC, ISA_MICROMIPS32R6;
def MULU_MMR6 : R6MMR6Rel, MULU_MMR6_DESC, MULU_MMR6_ENC, ISA_MICROMIPS32R6;
def MUHU_MMR6 : R6MMR6Rel, MUHU_MMR6_DESC, MUHU_MMR6_ENC, ISA_MICROMIPS32R6;
def NOR_MMR6 : StdMMR6Rel, NOR_MMR6_DESC, NOR_MMR6_ENC, ISA_MICROMIPS32R6;
def OR_MMR6 : StdMMR6Rel, OR_MMR6_DESC, OR_MMR6_ENC, ISA_MICROMIPS32R6;
def ORI_MMR6 : StdMMR6Rel, ORI_MMR6_DESC, ORI_MMR6_ENC, ISA_MICROMIPS32R6;
def PREF_MMR6 : R6MMR6Rel, PREF_MMR6_ENC, PREF_MMR6_DESC, ISA_MICROMIPS32R6;
def SB16_MMR6 : StdMMR6Rel, SB16_MMR6_DESC, SB16_MMR6_ENC, ISA_MICROMIPS32R6;
def SELEQZ_MMR6 : R6MMR6Rel, SELEQZ_MMR6_ENC, SELEQZ_MMR6_DESC,
ISA_MICROMIPS32R6;
def SELNEZ_MMR6 : R6MMR6Rel, SELNEZ_MMR6_ENC, SELNEZ_MMR6_DESC,
ISA_MICROMIPS32R6;
def SH16_MMR6 : StdMMR6Rel, SH16_MMR6_DESC, SH16_MMR6_ENC, ISA_MICROMIPS32R6;
def SLL_MMR6 : StdMMR6Rel, SLL_MMR6_DESC, SLL_MMR6_ENC, ISA_MICROMIPS32R6;
def SUB_MMR6 : StdMMR6Rel, SUB_MMR6_DESC, SUB_MMR6_ENC, ISA_MICROMIPS32R6;
def SUBU_MMR6 : StdMMR6Rel, SUBU_MMR6_DESC, SUBU_MMR6_ENC, ISA_MICROMIPS32R6;
def SW16_MMR6 : StdMMR6Rel, SW16_MMR6_DESC, SW16_MMR6_ENC, ISA_MICROMIPS32R6;
def SWM16_MMR6 : StdMMR6Rel, SWM16_MMR6_DESC, SWM16_MMR6_ENC, ISA_MICROMIPS32R6;
def SWSP_MMR6 : StdMMR6Rel, SWSP_MMR6_DESC, SWSP_MMR6_ENC, ISA_MICROMIPS32R6;
def WRPGPR_MMR6 : StdMMR6Rel, WRPGPR_MMR6_ENC, WRPGPR_MMR6_DESC,
ISA_MICROMIPS32R6;
def WSBH_MMR6 : StdMMR6Rel, WSBH_MMR6_ENC, WSBH_MMR6_DESC, ISA_MICROMIPS32R6;
def LB_MMR6 : R6MMR6Rel, LB_MMR6_ENC, LB_MMR6_DESC, ISA_MICROMIPS32R6;
def LBU_MMR6 : R6MMR6Rel, LBU_MMR6_ENC, LBU_MMR6_DESC, ISA_MICROMIPS32R6;
def PAUSE_MMR6 : StdMMR6Rel, PAUSE_MMR6_DESC, PAUSE_MMR6_ENC, ISA_MICROMIPS32R6;
def RDHWR_MMR6 : R6MMR6Rel, RDHWR_MMR6_DESC, RDHWR_MMR6_ENC, ISA_MICROMIPS32R6;
def WAIT_MMR6 : StdMMR6Rel, WAIT_MMR6_DESC, WAIT_MMR6_ENC, ISA_MICROMIPS32R6;
def SSNOP_MMR6 : StdMMR6Rel, SSNOP_MMR6_DESC, SSNOP_MMR6_ENC, ISA_MICROMIPS32R6;
def SYNC_MMR6 : StdMMR6Rel, SYNC_MMR6_DESC, SYNC_MMR6_ENC, ISA_MICROMIPS32R6;
def SYNCI_MMR6 : StdMMR6Rel, SYNCI_MMR6_DESC, SYNCI_MMR6_ENC, ISA_MICROMIPS32R6;
def RDPGPR_MMR6 : R6MMR6Rel, RDPGPR_MMR6_DESC, RDPGPR_MMR6_ENC,
ISA_MICROMIPS32R6;
def SDBBP_MMR6 : R6MMR6Rel, SDBBP_MMR6_DESC, SDBBP_MMR6_ENC, ISA_MICROMIPS32R6;
def SIGRIE_MMR6 : R6MMR6Rel, SIGRIE_MMR6_DESC, SIGRIE_MMR6_ENC, ISA_MICROMIPS32R6;
def XOR_MMR6 : StdMMR6Rel, XOR_MMR6_DESC, XOR_MMR6_ENC, ISA_MICROMIPS32R6;
def XORI_MMR6 : StdMMR6Rel, XORI_MMR6_DESC, XORI_MMR6_ENC, ISA_MICROMIPS32R6;
let DecoderMethod = "DecodeMemMMImm16" in {
def SW_MMR6 : StdMMR6Rel, SW_MMR6_DESC, SW_MMR6_ENC, ISA_MICROMIPS32R6;
}
/// Floating Point Instructions
def FADD_S_MMR6 : StdMMR6Rel, FADD_S_MMR6_ENC, FADD_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def FSUB_S_MMR6 : StdMMR6Rel, FSUB_S_MMR6_ENC, FSUB_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def FMUL_S_MMR6 : StdMMR6Rel, FMUL_S_MMR6_ENC, FMUL_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def FDIV_S_MMR6 : StdMMR6Rel, FDIV_S_MMR6_ENC, FDIV_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def MADDF_S_MMR6 : R6MMR6Rel, MADDF_S_MMR6_ENC, MADDF_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def MADDF_D_MMR6 : R6MMR6Rel, MADDF_D_MMR6_ENC, MADDF_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def MSUBF_S_MMR6 : R6MMR6Rel, MSUBF_S_MMR6_ENC, MSUBF_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def MSUBF_D_MMR6 : R6MMR6Rel, MSUBF_D_MMR6_ENC, MSUBF_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def FMOV_S_MMR6 : StdMMR6Rel, FMOV_S_MMR6_ENC, FMOV_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def FNEG_S_MMR6 : StdMMR6Rel, FNEG_S_MMR6_ENC, FNEG_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def MAX_S_MMR6 : R6MMR6Rel, MAX_S_MMR6_ENC, MAX_S_MMR6_DESC, ISA_MICROMIPS32R6;
def MAX_D_MMR6 : R6MMR6Rel, MAX_D_MMR6_ENC, MAX_D_MMR6_DESC, ISA_MICROMIPS32R6;
def MIN_S_MMR6 : R6MMR6Rel, MIN_S_MMR6_ENC, MIN_S_MMR6_DESC, ISA_MICROMIPS32R6;
def MIN_D_MMR6 : R6MMR6Rel, MIN_D_MMR6_ENC, MIN_D_MMR6_DESC, ISA_MICROMIPS32R6;
def MAXA_S_MMR6 : R6MMR6Rel, MAXA_S_MMR6_ENC, MAXA_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def MAXA_D_MMR6 : R6MMR6Rel, MAXA_D_MMR6_ENC, MAXA_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def MINA_S_MMR6 : R6MMR6Rel, MINA_S_MMR6_ENC, MINA_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def MINA_D_MMR6 : R6MMR6Rel, MINA_D_MMR6_ENC, MINA_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def CVT_L_S_MMR6 : StdMMR6Rel, CVT_L_S_MMR6_ENC, CVT_L_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def CVT_L_D_MMR6 : StdMMR6Rel, CVT_L_D_MMR6_ENC, CVT_L_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def CVT_W_S_MMR6 : StdMMR6Rel, CVT_W_S_MMR6_ENC, CVT_W_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def CVT_D_L_MMR6 : StdMMR6Rel, CVT_D_L_MMR6_ENC, CVT_D_L_MMR6_DESC,
ISA_MICROMIPS32R6;
def CVT_S_W_MMR6 : StdMMR6Rel, CVT_S_W_MMR6_ENC, CVT_S_W_MMR6_DESC,
ISA_MICROMIPS32R6;
def CVT_S_L_MMR6 : StdMMR6Rel, CVT_S_L_MMR6_ENC, CVT_S_L_MMR6_DESC,
ISA_MICROMIPS32R6;
defm S_MMR6 : CMP_CC_MMR6<0b000101, "s", FGR32Opnd, II_CMP_CC_S>;
defm D_MMR6 : CMP_CC_MMR6<0b010101, "d", FGR64Opnd, II_CMP_CC_D>;
def FLOOR_L_S_MMR6 : StdMMR6Rel, FLOOR_L_S_MMR6_ENC, FLOOR_L_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def FLOOR_L_D_MMR6 : StdMMR6Rel, FLOOR_L_D_MMR6_ENC, FLOOR_L_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def FLOOR_W_S_MMR6 : StdMMR6Rel, FLOOR_W_S_MMR6_ENC, FLOOR_W_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def FLOOR_W_D_MMR6 : StdMMR6Rel, FLOOR_W_D_MMR6_ENC, FLOOR_W_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def CEIL_L_S_MMR6 : StdMMR6Rel, CEIL_L_S_MMR6_ENC, CEIL_L_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def CEIL_L_D_MMR6 : StdMMR6Rel, CEIL_L_D_MMR6_ENC, CEIL_L_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def CEIL_W_S_MMR6 : StdMMR6Rel, CEIL_W_S_MMR6_ENC, CEIL_W_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def CEIL_W_D_MMR6 : StdMMR6Rel, CEIL_W_D_MMR6_ENC, CEIL_W_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def TRUNC_L_S_MMR6 : StdMMR6Rel, TRUNC_L_S_MMR6_ENC, TRUNC_L_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def TRUNC_L_D_MMR6 : StdMMR6Rel, TRUNC_L_D_MMR6_ENC, TRUNC_L_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def TRUNC_W_S_MMR6 : StdMMR6Rel, TRUNC_W_S_MMR6_ENC, TRUNC_W_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def TRUNC_W_D_MMR6 : StdMMR6Rel, TRUNC_W_D_MMR6_ENC, TRUNC_W_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def SB_MMR6 : StdMMR6Rel, SB_MMR6_DESC, SB_MMR6_ENC, ISA_MICROMIPS32R6;
def SH_MMR6 : StdMMR6Rel, SH_MMR6_DESC, SH_MMR6_ENC, ISA_MICROMIPS32R6;
def LW_MMR6 : StdMMR6Rel, LW_MMR6_DESC, LW_MMR6_ENC, ISA_MICROMIPS32R6;
def LUI_MMR6 : R6MMR6Rel, LUI_MMR6_DESC, LUI_MMR6_ENC, ISA_MICROMIPS32R6;
def ADDU16_MMR6 : StdMMR6Rel, ADDU16_MMR6_DESC, ADDU16_MMR6_ENC,
ISA_MICROMIPS32R6;
def AND16_MMR6 : StdMMR6Rel, AND16_MMR6_DESC, AND16_MMR6_ENC,
ISA_MICROMIPS32R6;
def ANDI16_MMR6 : StdMMR6Rel, ANDI16_MMR6_DESC, ANDI16_MMR6_ENC,
ISA_MICROMIPS32R6;
def NOT16_MMR6 : StdMMR6Rel, NOT16_MMR6_DESC, NOT16_MMR6_ENC,
ISA_MICROMIPS32R6;
def OR16_MMR6 : StdMMR6Rel, OR16_MMR6_DESC, OR16_MMR6_ENC,
ISA_MICROMIPS32R6;
def SLL16_MMR6 : StdMMR6Rel, SLL16_MMR6_DESC, SLL16_MMR6_ENC,
ISA_MICROMIPS32R6;
def SRL16_MMR6 : StdMMR6Rel, SRL16_MMR6_DESC, SRL16_MMR6_ENC,
ISA_MICROMIPS32R6;
def BREAK16_MMR6 : StdMMR6Rel, BREAK16_MMR6_DESC, BREAK16_MMR6_ENC,
ISA_MICROMIPS32R6;
def LI16_MMR6 : StdMMR6Rel, LI16_MMR6_DESC, LI16_MMR6_ENC,
ISA_MICROMIPS32R6;
def MOVE16_MMR6 : StdMMR6Rel, MOVE16_MMR6_DESC, MOVE16_MMR6_ENC,
ISA_MICROMIPS32R6;
def MOVEP_MMR6 : StdMMR6Rel, MOVEP_MMR6_DESC, MOVEP_MMR6_ENC,
ISA_MICROMIPS32R6;
def SDBBP16_MMR6 : StdMMR6Rel, SDBBP16_MMR6_DESC, SDBBP16_MMR6_ENC,
ISA_MICROMIPS32R6;
def SUBU16_MMR6 : StdMMR6Rel, SUBU16_MMR6_DESC, SUBU16_MMR6_ENC,
ISA_MICROMIPS32R6;
def XOR16_MMR6 : StdMMR6Rel, XOR16_MMR6_DESC, XOR16_MMR6_ENC,
ISA_MICROMIPS32R6;
def JALRC_HB_MMR6 : R6MMR6Rel, JALRC_HB_MMR6_ENC, JALRC_HB_MMR6_DESC,
ISA_MICROMIPS32R6;
def EXT_MMR6 : StdMMR6Rel, EXT_MMR6_ENC, EXT_MMR6_DESC, ISA_MICROMIPS32R6;
def INS_MMR6 : StdMMR6Rel, INS_MMR6_ENC, INS_MMR6_DESC, ISA_MICROMIPS32R6;
def JALRC_MMR6 : R6MMR6Rel, JALRC_MMR6_ENC, JALRC_MMR6_DESC, ISA_MICROMIPS32R6;
def RINT_S_MMR6 : StdMMR6Rel, RINT_S_MMR6_ENC, RINT_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def RINT_D_MMR6 : StdMMR6Rel, RINT_D_MMR6_ENC, RINT_D_MMR6_DESC, ISA_MICROMIPS32R6;
def ROUND_L_S_MMR6 : StdMMR6Rel, ROUND_L_S_MMR6_ENC, ROUND_L_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def ROUND_L_D_MMR6 : StdMMR6Rel, ROUND_L_D_MMR6_ENC, ROUND_L_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def ROUND_W_S_MMR6 : StdMMR6Rel, ROUND_W_S_MMR6_ENC, ROUND_W_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def ROUND_W_D_MMR6 : StdMMR6Rel, ROUND_W_D_MMR6_ENC, ROUND_W_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def SEL_S_MMR6 : R6MMR6Rel, SEL_S_MMR6_ENC, SEL_S_MMR6_DESC, ISA_MICROMIPS32R6;
def SEL_D_MMR6 : R6MMR6Rel, SEL_D_MMR6_ENC, SEL_D_MMR6_DESC, ISA_MICROMIPS32R6;
def SELEQZ_S_MMR6 : R6MMR6Rel, SELEQZ_S_MMR6_ENC, SELEQZ_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def SELEQZ_D_MMR6 : R6MMR6Rel, SELEQZ_D_MMR6_ENC, SELEQZ_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def SELNEZ_S_MMR6 : R6MMR6Rel, SELNEZ_S_MMR6_ENC, SELNEZ_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def SELNEZ_D_MMR6 : R6MMR6Rel, SELNEZ_D_MMR6_ENC, SELNEZ_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def CLASS_S_MMR6 : StdMMR6Rel, CLASS_S_MMR6_ENC, CLASS_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def CLASS_D_MMR6 : StdMMR6Rel, CLASS_D_MMR6_ENC, CLASS_D_MMR6_DESC,
ISA_MICROMIPS32R6;
def TLBINV_MMR6 : StdMMR6Rel, TLBINV_MMR6_ENC, TLBINV_MMR6_DESC,
ISA_MICROMIPS32R6;
def TLBINVF_MMR6 : StdMMR6Rel, TLBINVF_MMR6_ENC, TLBINVF_MMR6_DESC,
ISA_MICROMIPS32R6;
def DVP_MMR6 : R6MMR6Rel, DVP_MMR6_ENC, DVP_MMR6_DESC, ISA_MICROMIPS32R6;
def EVP_MMR6 : R6MMR6Rel, EVP_MMR6_ENC, EVP_MMR6_DESC, ISA_MICROMIPS32R6;
def BC1EQZC_MMR6 : R6MMR6Rel, BC1EQZC_MMR6_DESC, BC1EQZC_MMR6_ENC,
ISA_MICROMIPS32R6;
def BC1NEZC_MMR6 : R6MMR6Rel, BC1NEZC_MMR6_DESC, BC1NEZC_MMR6_ENC,
ISA_MICROMIPS32R6;
def BC2EQZC_MMR6 : R6MMR6Rel, MipsR6Inst, BC2EQZC_MMR6_ENC, BC2EQZC_MMR6_DESC,
ISA_MICROMIPS32R6;
def BC2NEZC_MMR6 : R6MMR6Rel, MipsR6Inst, BC2NEZC_MMR6_ENC, BC2NEZC_MMR6_DESC,
ISA_MICROMIPS32R6;
let DecoderNamespace = "MicroMipsFP64" in {
def LDC1_D64_MMR6 : StdMMR6Rel, LDC1_D64_MMR6_DESC, LDC1_MMR6_ENC,
ISA_MICROMIPS32R6 {
let BaseOpcode = "LDC164";
}
def SDC1_D64_MMR6 : StdMMR6Rel, SDC1_D64_MMR6_DESC, SDC1_MMR6_ENC,
ISA_MICROMIPS32R6;
}
def LDC2_MMR6 : StdMMR6Rel, LDC2_MMR6_ENC, LDC2_MMR6_DESC, ISA_MICROMIPS32R6;
def SDC2_MMR6 : StdMMR6Rel, SDC2_MMR6_ENC, SDC2_MMR6_DESC, ISA_MICROMIPS32R6;
def LWC2_MMR6 : StdMMR6Rel, LWC2_MMR6_ENC, LWC2_MMR6_DESC, ISA_MICROMIPS32R6;
def SWC2_MMR6 : StdMMR6Rel, SWC2_MMR6_ENC, SWC2_MMR6_DESC, ISA_MICROMIPS32R6;
def LL_MMR6 : R6MMR6Rel, LL_MMR6_ENC, LL_MMR6_DESC, ISA_MICROMIPS32R6;
def SC_MMR6 : R6MMR6Rel, SC_MMR6_ENC, SC_MMR6_DESC, ISA_MICROMIPS32R6;
}
def BOVC_MMR6 : R6MMR6Rel, BOVC_MMR6_ENC, BOVC_MMR6_DESC, ISA_MICROMIPS32R6,
MMDecodeDisambiguatedBy<"POP35GroupBranchMMR6">;
def BNVC_MMR6 : R6MMR6Rel, BNVC_MMR6_ENC, BNVC_MMR6_DESC, ISA_MICROMIPS32R6,
MMDecodeDisambiguatedBy<"POP37GroupBranchMMR6">;
def BGEC_MMR6 : R6MMR6Rel, BGEC_MMR6_ENC, BGEC_MMR6_DESC, ISA_MICROMIPS32R6;
def BGEUC_MMR6 : R6MMR6Rel, BGEUC_MMR6_ENC, BGEUC_MMR6_DESC, ISA_MICROMIPS32R6;
def BLTC_MMR6 : R6MMR6Rel, BLTC_MMR6_ENC, BLTC_MMR6_DESC, ISA_MICROMIPS32R6;
def BLTUC_MMR6 : R6MMR6Rel, BLTUC_MMR6_ENC, BLTUC_MMR6_DESC, ISA_MICROMIPS32R6;
def BEQC_MMR6 : R6MMR6Rel, BEQC_MMR6_ENC, BEQC_MMR6_DESC, ISA_MICROMIPS32R6,
DecodeDisambiguates<"POP35GroupBranchMMR6">;
def BNEC_MMR6 : R6MMR6Rel, BNEC_MMR6_ENC, BNEC_MMR6_DESC, ISA_MICROMIPS32R6,
DecodeDisambiguates<"POP37GroupBranchMMR6">;
def BLTZC_MMR6 : R6MMR6Rel, BLTZC_MMR6_ENC, BLTZC_MMR6_DESC, ISA_MICROMIPS32R6;
def BLEZC_MMR6 : R6MMR6Rel, BLEZC_MMR6_ENC, BLEZC_MMR6_DESC, ISA_MICROMIPS32R6;
def BGEZC_MMR6 : R6MMR6Rel, BGEZC_MMR6_ENC, BGEZC_MMR6_DESC, ISA_MICROMIPS32R6;
def BGTZC_MMR6 : R6MMR6Rel, BGTZC_MMR6_ENC, BGTZC_MMR6_DESC, ISA_MICROMIPS32R6;
def BGEZALC_MMR6 : R6MMR6Rel, BGEZALC_MMR6_ENC, BGEZALC_MMR6_DESC,
ISA_MICROMIPS32R6;
def BGTZALC_MMR6 : R6MMR6Rel, BGTZALC_MMR6_ENC, BGTZALC_MMR6_DESC,
ISA_MICROMIPS32R6;
def BLEZALC_MMR6 : R6MMR6Rel, BLEZALC_MMR6_ENC, BLEZALC_MMR6_DESC,
ISA_MICROMIPS32R6;
def BLTZALC_MMR6 : R6MMR6Rel, BLTZALC_MMR6_ENC, BLTZALC_MMR6_DESC,
ISA_MICROMIPS32R6;
//===----------------------------------------------------------------------===//
//
// MicroMips instruction aliases
//
//===----------------------------------------------------------------------===//
def : MipsInstAlias<"ei", (EI_MMR6 ZERO), 1>, ISA_MICROMIPS32R6;
def : MipsInstAlias<"di", (DI_MMR6 ZERO), 1>, ISA_MICROMIPS32R6;
def : MipsInstAlias<"nop", (SLL_MMR6 ZERO, ZERO, 0), 1>, ISA_MICROMIPS32R6;
def B_MMR6_Pseudo : MipsAsmPseudoInst<(outs), (ins brtarget_mm:$offset),
!strconcat("b", "\t$offset")> {
string DecoderNamespace = "MicroMipsR6";
}
def : MipsInstAlias<"sync", (SYNC_MMR6 0), 1>, ISA_MICROMIPS32R6;
def : MipsInstAlias<"sdbbp", (SDBBP_MMR6 0), 1>, ISA_MICROMIPS32R6;
def : MipsInstAlias<"sigrie", (SIGRIE_MMR6 0), 1>, ISA_MICROMIPS32R6;
def : MipsInstAlias<"rdhwr $rt, $rs",
(RDHWR_MMR6 GPR32Opnd:$rt, HWRegsOpnd:$rs, 0), 1>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"mtc0 $rt, $rs",
(MTC0_MMR6 COP0Opnd:$rs, GPR32Opnd:$rt, 0), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"mthc0 $rt, $rs",
(MTHC0_MMR6 COP0Opnd:$rs, GPR32Opnd:$rt, 0), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"mfc0 $rt, $rs",
(MFC0_MMR6 GPR32Opnd:$rt, COP0Opnd:$rs, 0), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"mfhc0 $rt, $rs",
(MFHC0_MMR6 GPR32Opnd:$rt, COP0Opnd:$rs, 0), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"jalrc.hb $rs", (JALRC_HB_MMR6 RA, GPR32Opnd:$rs), 1>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"jal $offset", (BALC_MMR6 brtarget26_mm:$offset), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"dvp", (DVP_MMR6 ZERO), 0>, ISA_MICROMIPS32R6;
def : MipsInstAlias<"evp", (EVP_MMR6 ZERO), 0>, ISA_MICROMIPS32R6;
def : MipsInstAlias<"jalrc $rs", (JALRC_MMR6 RA, GPR32Opnd:$rs), 1>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"and $rs, $rt, $imm",
(ANDI_MMR6 GPR32Opnd:$rs, GPR32Opnd:$rt, uimm16:$imm), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"and $rs, $imm",
(ANDI_MMR6 GPR32Opnd:$rs, GPR32Opnd:$rs, uimm16:$imm), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"or $rs, $rt, $imm",
(ORI_MMR6 GPR32Opnd:$rs, GPR32Opnd:$rt, uimm16:$imm), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"or $rs, $imm",
(ORI_MMR6 GPR32Opnd:$rs, GPR32Opnd:$rs, uimm16:$imm), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"xor $rs, $rt, $imm",
(XORI_MMR6 GPR32Opnd:$rs, GPR32Opnd:$rt, uimm16:$imm), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"xor $rs, $imm",
(XORI_MMR6 GPR32Opnd:$rs, GPR32Opnd:$rs, uimm16:$imm), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"not $rt, $rs",
(NOR_MMR6 GPR32Opnd:$rt, GPR32Opnd:$rs, ZERO), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"not $rt",
(NOR_MMR6 GPR32Opnd:$rt, GPR32Opnd:$rt, ZERO), 0>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"lapc $rd, $imm",
(ADDIUPC_MMR6 GPR32Opnd:$rd, simm19_lsl2:$imm)>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"neg $rt, $rs",
(SUB_MMR6 GPR32Opnd:$rt, ZERO, GPR32Opnd:$rs), 1>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"neg $rt",
(SUB_MMR6 GPR32Opnd:$rt, ZERO, GPR32Opnd:$rt), 1>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"negu $rt, $rs",
(SUBU_MMR6 GPR32Opnd:$rt, ZERO, GPR32Opnd:$rs), 1>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"negu $rt",
(SUBU_MMR6 GPR32Opnd:$rt, ZERO, GPR32Opnd:$rt), 1>,
ISA_MICROMIPS32R6;
def : MipsInstAlias<"beqz16 $rs, $offset", (BEQZC16_MMR6 GPRMM16Opnd:$rs,
brtarget7_mm:$offset),
0>, ISA_MICROMIPS32R6;
def : MipsInstAlias<"bnez16 $rs, $offset", (BNEZC16_MMR6 GPRMM16Opnd:$rs,
brtarget7_mm:$offset),
0>, ISA_MICROMIPS32R6;
def : MipsInstAlias<"b16 $offset", (BC16_MMR6 brtarget10_mm:$offset), 0>,
ISA_MICROMIPS32R6;
//===----------------------------------------------------------------------===//
//
// MicroMips arbitrary patterns that map to one or more instructions
//
//===----------------------------------------------------------------------===//
def : MipsPat<(store GPRMM16:$src, addrimm4lsl2:$addr),
(SW16_MMR6 GPRMM16:$src, addrimm4lsl2:$addr)>, ISA_MICROMIPS32R6;
def : MipsPat<(subc GPR32:$lhs, GPR32:$rhs),
(SUBU_MMR6 GPR32:$lhs, GPR32:$rhs)>, ISA_MICROMIPS32R6;
def : MipsPat<(select i32:$cond, i32:$t, i32:$f),
(OR_MM (SELNEZ_MMR6 i32:$t, i32:$cond),
(SELEQZ_MMR6 i32:$f, i32:$cond))>,
ISA_MICROMIPS32R6;
def : MipsPat<(select i32:$cond, i32:$t, immz),
(SELNEZ_MMR6 i32:$t, i32:$cond)>,
ISA_MICROMIPS32R6;
def : MipsPat<(select i32:$cond, immz, i32:$f),
(SELEQZ_MMR6 i32:$f, i32:$cond)>,
ISA_MICROMIPS32R6;
defm : SelectInt_Pats<i32, OR_MM, XORI_MMR6, SLTi_MM, SLTiu_MM, SELEQZ_MMR6,
SELNEZ_MMR6, immZExt16, i32>, ISA_MICROMIPS32R6;
defm S_MMR6 : Cmp_Pats<f32, NOR_MMR6, ZERO>, ISA_MICROMIPS32R6;
defm D_MMR6 : Cmp_Pats<f64, NOR_MMR6, ZERO>, ISA_MICROMIPS32R6;
def : MipsPat<(f32 fpimm0), (MTC1_MMR6 ZERO)>, ISA_MICROMIPS32R6;
def : MipsPat<(f32 fpimm0neg), (FNEG_S_MMR6 (MTC1_MMR6 ZERO))>, ISA_MICROMIPS32R6;
def : MipsPat<(MipsTruncIntFP FGR64Opnd:$src),
(TRUNC_W_D_MMR6 FGR64Opnd:$src)>, ISA_MICROMIPS32R6;
+def : MipsPat<(MipsTruncIntFP FGR32Opnd:$src),
+ (TRUNC_W_S_MMR6 FGR32Opnd:$src)>, ISA_MICROMIPS32R6;
def : MipsPat<(and GPRMM16:$src, immZExtAndi16:$imm),
(ANDI16_MMR6 GPRMM16:$src, immZExtAndi16:$imm)>,
ISA_MICROMIPS32R6;
def : MipsPat<(and GPR32:$src, immZExt16:$imm),
(ANDI_MMR6 GPR32:$src, immZExt16:$imm)>, ISA_MICROMIPS32R6;
def : MipsPat<(i32 immZExt16:$imm),
(XORI_MMR6 ZERO, immZExt16:$imm)>, ISA_MICROMIPS32R6;
def : MipsPat<(not GPRMM16:$in),
(NOT16_MMR6 GPRMM16:$in)>, ISA_MICROMIPS32R6;
def : MipsPat<(not GPR32:$in),
(NOR_MMR6 GPR32Opnd:$in, ZERO)>, ISA_MICROMIPS32R6;
// Patterns for load with a reg+imm operand.
let AddedComplexity = 41 in {
def : LoadRegImmPat<LDC1_D64_MMR6, f64, load>, FGR_64, ISA_MICROMIPS32R6;
def : StoreRegImmPat<SDC1_D64_MMR6, f64>, FGR_64, ISA_MICROMIPS32R6;
}
def TAILCALL_MMR6 : TailCall<BC_MMR6, brtarget26_mm>, ISA_MICROMIPS32R6;
def TAILCALLREG_MMR6 : TailCallReg<JRC16_MM, GPR32Opnd>, ISA_MICROMIPS32R6;
def PseudoIndirectBranch_MMR6 : PseudoIndirectBranchBase<JRC16_MMR6,
GPR32Opnd>,
ISA_MICROMIPS32R6;
def : MipsPat<(MipsTailCall (iPTR tglobaladdr:$dst)),
(TAILCALL_MMR6 tglobaladdr:$dst)>, ISA_MICROMIPS32R6;
def : MipsPat<(MipsTailCall (iPTR texternalsym:$dst)),
(TAILCALL_MMR6 texternalsym:$dst)>, ISA_MICROMIPS32R6;
def : MipsPat<(brcond (i32 (setne GPR32:$lhs, 0)), bb:$dst),
(BNEZC_MMR6 GPR32:$lhs, bb:$dst)>, ISA_MICROMIPS32R6;
def : MipsPat<(brcond (i32 (seteq GPR32:$lhs, 0)), bb:$dst),
(BEQZC_MMR6 GPR32:$lhs, bb:$dst)>, ISA_MICROMIPS32R6;
def : MipsPat<(brcond (i32 (setge GPR32:$lhs, GPR32:$rhs)), bb:$dst),
(BEQZC_MMR6 (SLT_MM GPR32:$lhs, GPR32:$rhs), bb:$dst)>,
ISA_MICROMIPS32R6;
def : MipsPat<(brcond (i32 (setuge GPR32:$lhs, GPR32:$rhs)), bb:$dst),
(BEQZC_MMR6 (SLTu_MM GPR32:$lhs, GPR32:$rhs), bb:$dst)>,
ISA_MICROMIPS32R6;
def : MipsPat<(brcond (i32 (setge GPR32:$lhs, immSExt16:$rhs)), bb:$dst),
(BEQZC_MMR6 (SLTi_MM GPR32:$lhs, immSExt16:$rhs), bb:$dst)>,
ISA_MICROMIPS32R6;
def : MipsPat<(brcond (i32 (setuge GPR32:$lhs, immSExt16:$rhs)), bb:$dst),
(BEQZC_MMR6 (SLTiu_MM GPR32:$lhs, immSExt16:$rhs), bb:$dst)>,
ISA_MICROMIPS32R6;
def : MipsPat<(brcond (i32 (setgt GPR32:$lhs, immSExt16Plus1:$rhs)), bb:$dst),
(BEQZC_MMR6 (SLTi_MM GPR32:$lhs, (Plus1 imm:$rhs)), bb:$dst)>,
ISA_MICROMIPS32R6;
def : MipsPat<(brcond (i32 (setugt GPR32:$lhs, immSExt16Plus1:$rhs)), bb:$dst),
(BEQZC_MMR6 (SLTiu_MM GPR32:$lhs, (Plus1 imm:$rhs)), bb:$dst)>,
ISA_MICROMIPS32R6;
def : MipsPat<(brcond (i32 (setle GPR32:$lhs, GPR32:$rhs)), bb:$dst),
(BEQZC_MMR6 (SLT_MM GPR32:$rhs, GPR32:$lhs), bb:$dst)>,
ISA_MICROMIPS32R6;
def : MipsPat<(brcond (i32 (setule GPR32:$lhs, GPR32:$rhs)), bb:$dst),
(BEQZC_MMR6 (SLTu_MM GPR32:$rhs, GPR32:$lhs), bb:$dst)>,
ISA_MICROMIPS32R6;
def : MipsPat<(brcond GPR32:$cond, bb:$dst),
(BNEZC_MMR6 GPR32:$cond, bb:$dst)>, ISA_MICROMIPS32R6;
Index: stable/11/contrib/llvm/lib/Target/Mips/MicroMipsInstrFPU.td
===================================================================
--- stable/11/contrib/llvm/lib/Target/Mips/MicroMipsInstrFPU.td (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/Mips/MicroMipsInstrFPU.td (revision 350259)
@@ -1,444 +1,449 @@
//==- MicroMipsInstrFPU.td - microMIPS FPU Instruction Info -*- tablegen -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the microMIPS FPU instruction set.
//
//===----------------------------------------------------------------------===//
multiclass ADDS_MMM<string opstr, InstrItinClass Itin, bit IsComm,
SDPatternOperator OpNode = null_frag> {
def _D32_MM : MMRel, ADDS_FT<opstr, AFGR64Opnd, Itin, IsComm, OpNode>,
FGR_32 {
string DecoderNamespace = "MicroMips";
}
// FIXME: This needs to be part of the instruction mapping tables.
def _D64_MM : ADDS_FT<opstr, FGR64Opnd, Itin, IsComm, OpNode>, FGR_64 {
string DecoderNamespace = "MicroMipsFP64";
}
}
def FADD_S_MM : MMRel, ADDS_FT<"add.s", FGR32Opnd, II_ADD_S, 1, fadd>,
ADDS_FM_MM<0, 0x30>, ISA_MICROMIPS;
def FDIV_S_MM : MMRel, ADDS_FT<"div.s", FGR32Opnd, II_DIV_S, 0, fdiv>,
ADDS_FM_MM<0, 0xf0>, ISA_MICROMIPS;
def FMUL_S_MM : MMRel, ADDS_FT<"mul.s", FGR32Opnd, II_MUL_S, 1, fmul>,
ADDS_FM_MM<0, 0xb0>, ISA_MICROMIPS;
def FSUB_S_MM : MMRel, ADDS_FT<"sub.s", FGR32Opnd, II_SUB_S, 0, fsub>,
ADDS_FM_MM<0, 0x70>, ISA_MICROMIPS;
defm FADD : ADDS_MMM<"add.d", II_ADD_D, 1, fadd>,
ADDS_FM_MM<1, 0x30>, ISA_MICROMIPS;
defm FDIV : ADDS_MMM<"div.d", II_DIV_D, 0, fdiv>,
ADDS_FM_MM<1, 0xf0>, ISA_MICROMIPS;
defm FMUL : ADDS_MMM<"mul.d", II_MUL_D, 1, fmul>,
ADDS_FM_MM<1, 0xb0>, ISA_MICROMIPS;
defm FSUB : ADDS_MMM<"sub.d", II_SUB_D, 0, fsub>,
ADDS_FM_MM<1, 0x70>, ISA_MICROMIPS;
let DecoderNamespace = "MicroMips" in {
def LWXC1_MM : MMRel, LWXC1_FT<"lwxc1", FGR32Opnd, II_LWXC1, load>,
LWXC1_FM_MM<0x48>, ISA_MICROMIPS32_NOT_MIPS32R6;
def SWXC1_MM : MMRel, SWXC1_FT<"swxc1", FGR32Opnd, II_SWXC1, store>,
SWXC1_FM_MM<0x88>, ISA_MICROMIPS32_NOT_MIPS32R6;
def LUXC1_MM : MMRel, LWXC1_FT<"luxc1", FGR64Opnd, II_LUXC1>,
LWXC1_FM_MM<0x148>, FGR_64, ISA_MICROMIPS32_NOT_MIPS32R6;
def SUXC1_MM : MMRel, SWXC1_FT<"suxc1", FGR64Opnd, II_SUXC1>,
SWXC1_FM_MM<0x188>, FGR_64, ISA_MICROMIPS32_NOT_MIPS32R6;
}
let isCodeGenOnly = 1 in {
def FCMP_S32_MM : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>,
CEQS_FM_MM<0>, ISA_MICROMIPS32_NOT_MIPS32R6 {
// FIXME: This is a required to work around the fact that these instructions
// only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the
// fcc register set is used directly.
bits<3> fcc = 0;
}
def FCMP_D32_MM : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>,
CEQS_FM_MM<1>, ISA_MICROMIPS32_NOT_MIPS32R6 {
// FIXME: This is a required to work around the fact that these instructions
// only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the
// fcc register set is used directly.
bits<3> fcc = 0;
}
}
let DecoderNamespace = "MicroMips" in {
def BC1F_MM : MMRel, BC1F_FT<"bc1f", brtarget_mm, II_BC1F, MIPS_BRANCH_F>,
BC1F_FM_MM<0x1c>, ISA_MICROMIPS32_NOT_MIPS32R6;
def BC1T_MM : MMRel, BC1F_FT<"bc1t", brtarget_mm, II_BC1T, MIPS_BRANCH_T>,
BC1F_FM_MM<0x1d>, ISA_MICROMIPS32_NOT_MIPS32R6;
def CVT_W_S_MM : MMRel, ABSS_FT<"cvt.w.s", FGR32Opnd, FGR32Opnd, II_CVT>,
ROUND_W_FM_MM<0, 0x24>, ISA_MICROMIPS;
}
let DecoderNamespace = "MicroMips" in {
def ROUND_W_S_MM : MMRel, StdMMR6Rel, ABSS_FT<"round.w.s", FGR32Opnd,
FGR32Opnd, II_ROUND>,
ROUND_W_FM_MM<0, 0xec>, ISA_MICROMIPS;
def CEIL_W_MM : MMRel, ABSS_FT<"ceil.w.d", FGR32Opnd, AFGR64Opnd, II_CEIL>,
ROUND_W_FM_MM<1, 0x6c>, ISA_MICROMIPS, FGR_32;
def FLOOR_W_MM : MMRel, ABSS_FT<"floor.w.d", FGR32Opnd, AFGR64Opnd, II_FLOOR>,
ROUND_W_FM_MM<1, 0x2c>, ISA_MICROMIPS, FGR_32;
def ROUND_W_MM : MMRel, StdMMR6Rel, ABSS_FT<"round.w.d", FGR32Opnd,
AFGR64Opnd, II_ROUND>,
ROUND_W_FM_MM<1, 0xec>, ISA_MICROMIPS, FGR_32;
def TRUNC_W_MM : MMRel, ABSS_FT<"trunc.w.d", FGR32Opnd, AFGR64Opnd, II_TRUNC>,
ROUND_W_FM_MM<1, 0xac>, ISA_MICROMIPS, FGR_32;
def CVT_L_S_MM : MMRel, ABSS_FT<"cvt.l.s", FGR64Opnd, FGR32Opnd, II_CVT>,
ROUND_W_FM_MM<0, 0x4>, ISA_MICROMIPS, FGR_64;
def CVT_L_D64_MM : MMRel, ABSS_FT<"cvt.l.d", FGR64Opnd, FGR64Opnd, II_CVT>,
ROUND_W_FM_MM<1, 0x4>, ISA_MICROMIPS, FGR_64;
def CVT_W_D32_MM : MMRel, ABSS_FT<"cvt.w.d", FGR32Opnd, AFGR64Opnd, II_CVT>,
ROUND_W_FM_MM<1, 0x24>, ISA_MICROMIPS, FGR_32;
}
let DecoderNamespace = "MicroMipsFP64" in {
def CVT_W_D64_MM : ABSS_FT<"cvt.w.d", FGR32Opnd, FGR64Opnd, II_CVT>,
ROUND_W_FM_MM<1, 0x24>, ISA_MICROMIPS, FGR_64;
}
multiclass ABSS_MMM<string opstr, InstrItinClass Itin,
SDPatternOperator OpNode = null_frag> {
def _D32_MM : MMRel, ABSS_FT<opstr, AFGR64Opnd, AFGR64Opnd, Itin, OpNode>,
ISA_MICROMIPS, FGR_32 {
string DecoderNamespace = "MicroMips";
}
// FIXME: This needs to be part of the instruction mapping tables.
def _D64_MM : ABSS_FT<opstr, FGR64Opnd, FGR64Opnd, Itin, OpNode>,
ISA_MICROMIPS, FGR_64 {
string DecoderNamespace = "MicroMipsFP64";
}
}
defm FSQRT : ABSS_MMM<"sqrt.d", II_SQRT_D, fsqrt>, ROUND_W_FM_MM<1, 0x28>;
defm FABS : ABSS_MMM<"abs.d", II_SQRT_D, fabs>, ABS_FM_MM<1, 0xd>;
let DecoderNamespace = "MicroMips" in {
def FABS_S_MM : MMRel, ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, II_ABS, fabs>,
ABS_FM_MM<0, 0xd>, ISA_MICROMIPS;
}
def FMOV_S_MM : MMRel, ABSS_FT<"mov.s", FGR32Opnd, FGR32Opnd, II_MOV_S>,
ABS_FM_MM<0, 0x1>, ISA_MICROMIPS {
let isMoveReg = 1;
}
def FNEG_S_MM : MMRel, ABSS_FT<"neg.s", FGR32Opnd, FGR32Opnd, II_NEG, fneg>,
ABS_FM_MM<0, 0x2d>, ISA_MICROMIPS;
let DecoderNamespace = "MicroMips" in {
def CVT_D32_S_MM : MMRel, ABSS_FT<"cvt.d.s", AFGR64Opnd, FGR32Opnd, II_CVT>,
ABS_FM_MM<0, 0x4d>, ISA_MICROMIPS, FGR_32;
def CVT_D32_W_MM : MMRel, ABSS_FT<"cvt.d.w", AFGR64Opnd, FGR32Opnd, II_CVT>,
ABS_FM_MM<1, 0x4d>, ISA_MICROMIPS, FGR_32;
}
let DecoderNamespace = "MicroMipsFP64" in {
def CVT_D64_S_MM : ABSS_FT<"cvt.d.s", FGR64Opnd, FGR32Opnd, II_CVT>,
ABS_FM_MM<0, 0x4d>, ISA_MICROMIPS, FGR_64;
def CVT_D64_W_MM : ABSS_FT<"cvt.d.w", FGR64Opnd, FGR32Opnd, II_CVT>,
ABS_FM_MM<1, 0x4d>, ISA_MICROMIPS, FGR_64;
def CVT_S_D64_MM : ABSS_FT<"cvt.s.d", FGR32Opnd, FGR64Opnd, II_CVT>,
ABS_FM_MM<0, 0x6d>, ISA_MICROMIPS, FGR_64;
}
let DecoderNamespace = "MicroMips" in {
def CVT_S_D32_MM : MMRel, ABSS_FT<"cvt.s.d", FGR32Opnd, AFGR64Opnd, II_CVT>,
ABS_FM_MM<0, 0x6d>, ISA_MICROMIPS, FGR_32;
def CVT_S_W_MM : MMRel, ABSS_FT<"cvt.s.w", FGR32Opnd, FGR32Opnd, II_CVT>,
ABS_FM_MM<1, 0x6d>, ISA_MICROMIPS;
}
defm FNEG : ABSS_MMM<"neg.d", II_NEG, fneg>, ABS_FM_MM<1, 0x2d>;
defm FMOV : ABSS_MMM<"mov.d", II_MOV_D>, ABS_FM_MM<1, 0x1>;
let DecoderNamespace = "MicroMips" in {
def MOVZ_I_S_MM : MMRel, CMov_I_F_FT<"movz.s", GPR32Opnd, FGR32Opnd,
II_MOVZ_S>, CMov_I_F_FM_MM<0x78, 0>,
ISA_MICROMIPS32_NOT_MIPS32R6;
def MOVN_I_S_MM : MMRel, CMov_I_F_FT<"movn.s", GPR32Opnd, FGR32Opnd,
II_MOVN_S>, CMov_I_F_FM_MM<0x38, 0>,
ISA_MICROMIPS32_NOT_MIPS32R6;
def MOVZ_I_D32_MM : MMRel, CMov_I_F_FT<"movz.d", GPR32Opnd, AFGR64Opnd,
II_MOVZ_D>, CMov_I_F_FM_MM<0x78, 1>,
ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32;
def MOVN_I_D32_MM : MMRel, CMov_I_F_FT<"movn.d", GPR32Opnd, AFGR64Opnd,
II_MOVN_D>, CMov_I_F_FM_MM<0x38, 1>,
ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32;
def MOVT_S_MM : MMRel, CMov_F_F_FT<"movt.s", FGR32Opnd, II_MOVT_S,
MipsCMovFP_T>, CMov_F_F_FM_MM<0x60, 0>,
ISA_MICROMIPS32_NOT_MIPS32R6;
def MOVF_S_MM : MMRel, CMov_F_F_FT<"movf.s", FGR32Opnd, II_MOVF_S,
MipsCMovFP_F>, CMov_F_F_FM_MM<0x20, 0>,
ISA_MICROMIPS32_NOT_MIPS32R6;
def MOVT_D32_MM : MMRel, CMov_F_F_FT<"movt.d", AFGR64Opnd, II_MOVT_D,
MipsCMovFP_T>, CMov_F_F_FM_MM<0x60, 1>,
ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32;
def MOVF_D32_MM : MMRel, CMov_F_F_FT<"movf.d", AFGR64Opnd, II_MOVF_D,
MipsCMovFP_F>, CMov_F_F_FM_MM<0x20, 1>,
ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32;
def MFC1_MM : MMRel, MFC1_FT<"mfc1", GPR32Opnd, FGR32Opnd,
II_MFC1, bitconvert>, MFC1_FM_MM<0x80>,
ISA_MICROMIPS;
def MTC1_MM : MMRel, MTC1_FT<"mtc1", FGR32Opnd, GPR32Opnd,
II_MTC1, bitconvert>, MFC1_FM_MM<0xa0>,
ISA_MICROMIPS;
def MADD_S_MM : MMRel, MADDS_FT<"madd.s", FGR32Opnd, II_MADD_S>,
MADDS_FM_MM<0x1>, ISA_MICROMIPS32_NOT_MIPS32R6, MADD4;
def MSUB_S_MM : MMRel, MADDS_FT<"msub.s", FGR32Opnd, II_MSUB_S>,
MADDS_FM_MM<0x21>, ISA_MICROMIPS32_NOT_MIPS32R6, MADD4;
let AdditionalPredicates = [NoNaNsFPMath, HasMadd4] in {
def NMADD_S_MM : MMRel, NMADDS_FT<"nmadd.s", FGR32Opnd, II_NMADD_S>,
MADDS_FM_MM<0x2>, ISA_MICROMIPS32_NOT_MIPS32R6;
def NMSUB_S_MM : MMRel, NMADDS_FT<"nmsub.s", FGR32Opnd, II_NMSUB_S>,
MADDS_FM_MM<0x22>, ISA_MICROMIPS32_NOT_MIPS32R6;
}
def MADD_D32_MM : MMRel, MADDS_FT<"madd.d", AFGR64Opnd, II_MADD_D>,
MADDS_FM_MM<0x9>, ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32,
MADD4;
def MSUB_D32_MM : MMRel, MADDS_FT<"msub.d", AFGR64Opnd, II_MSUB_D>,
MADDS_FM_MM<0x29>, ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32,
MADD4;
let AdditionalPredicates = [NoNaNsFPMath, HasMadd4] in {
def NMADD_D32_MM : MMRel, NMADDS_FT<"nmadd.d", AFGR64Opnd, II_NMADD_D>,
MADDS_FM_MM<0xa>, ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32;
def NMSUB_D32_MM : MMRel, NMADDS_FT<"nmsub.d", AFGR64Opnd, II_NMSUB_D>,
MADDS_FM_MM<0x2a>, ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32;
}
def FLOOR_W_S_MM : MMRel, ABSS_FT<"floor.w.s", FGR32Opnd, FGR32Opnd,
II_FLOOR>, ROUND_W_FM_MM<0, 0x2c>,
ISA_MICROMIPS;
def TRUNC_W_S_MM : MMRel, StdMMR6Rel, ABSS_FT<"trunc.w.s", FGR32Opnd,
FGR32Opnd, II_TRUNC>,
ROUND_W_FM_MM<0, 0xac>, ISA_MICROMIPS;
def CEIL_W_S_MM : MMRel, ABSS_FT<"ceil.w.s", FGR32Opnd, FGR32Opnd, II_CEIL>,
ROUND_W_FM_MM<0, 0x6c>, ISA_MICROMIPS;
def FSQRT_S_MM : MMRel, ABSS_FT<"sqrt.s", FGR32Opnd, FGR32Opnd, II_SQRT_S,
fsqrt>, ROUND_W_FM_MM<0, 0x28>, ISA_MICROMIPS;
def MTHC1_D32_MM : MMRel, MTC1_64_FT<"mthc1", AFGR64Opnd, GPR32Opnd, II_MTHC1>,
MFC1_FM_MM<0xe0>, ISA_MICROMIPS, FGR_32;
def MFHC1_D32_MM : MMRel, MFC1_FT<"mfhc1", GPR32Opnd, AFGR64Opnd, II_MFHC1>,
MFC1_FM_MM<0xc0>, ISA_MICROMIPS, FGR_32;
}
let DecoderNamespace = "MicroMipsFP64" in {
def MTHC1_D64_MM : MTC1_64_FT<"mthc1", FGR64Opnd, GPR32Opnd, II_MTHC1>,
MFC1_FM_MM<0xe0>, ISA_MICROMIPS, FGR_64;
def MFHC1_D64_MM : MFC1_FT<"mfhc1", GPR32Opnd, FGR64Opnd, II_MFHC1>,
MFC1_FM_MM<0xc0>, ISA_MICROMIPS, FGR_64;
def MTC1_D64_MM : MTC1_FT<"mtc1", FGR64Opnd, GPR32Opnd, II_MTC1>,
MFC1_FM_MM<0xa0>, ISA_MICROMIPS, FGR_64;
}
let DecoderNamespace = "MicroMips" in {
def CFC1_MM : MMRel, MFC1_FT<"cfc1", GPR32Opnd, CCROpnd, II_CFC1>,
MFC1_FM_MM<0x40>, ISA_MICROMIPS;
def CTC1_MM : MMRel, MTC1_FT<"ctc1", CCROpnd, GPR32Opnd, II_CTC1>,
MFC1_FM_MM<0x60>, ISA_MICROMIPS;
def RECIP_S_MM : MMRel, ABSS_FT<"recip.s", FGR32Opnd, FGR32Opnd,
II_RECIP_S>,
ROUND_W_FM_MM<0b0, 0b01001000>, ISA_MICROMIPS;
def RECIP_D32_MM : MMRel, ABSS_FT<"recip.d", AFGR64Opnd, AFGR64Opnd,
II_RECIP_D>,
ROUND_W_FM_MM<0b1, 0b01001000>, ISA_MICROMIPS, FGR_32 {
let BaseOpcode = "RECIP_D32";
}
let DecoderNamespace = "MicroMipsFP64" in
def RECIP_D64_MM : MMRel, ABSS_FT<"recip.d", FGR64Opnd, FGR64Opnd,
II_RECIP_D>,
ROUND_W_FM_MM<0b1, 0b01001000>, ISA_MICROMIPS, FGR_64;
def RSQRT_S_MM : MMRel, ABSS_FT<"rsqrt.s", FGR32Opnd, FGR32Opnd,
II_RECIP_S>,
ROUND_W_FM_MM<0b0, 0b00001000>;
def RSQRT_D32_MM : MMRel, ABSS_FT<"rsqrt.d", AFGR64Opnd, AFGR64Opnd,
II_RECIP_D>,
ROUND_W_FM_MM<0b1, 0b00001000>, ISA_MICROMIPS, FGR_32 {
let BaseOpcode = "RSQRT_D32";
}
let DecoderNamespace = "MicroMipsFP64" in
def RSQRT_D64_MM : MMRel, ABSS_FT<"rsqrt.d", FGR64Opnd, FGR64Opnd,
II_RECIP_D>,
ROUND_W_FM_MM<0b1, 0b00001000>, ISA_MICROMIPS, FGR_64;
}
let DecoderNamespace = "MicroMips", DecoderMethod = "DecodeFMemMMR2" in {
def LDC1_MM : MMRel, LW_FT<"ldc1", AFGR64Opnd, mem_mm_16, II_LDC1, load>,
LW_FM_MM<0x2f>, ISA_MICROMIPS, FGR_32 {
let BaseOpcode = "LDC132";
}
def SDC1_MM : MMRel, SW_FT<"sdc1", AFGR64Opnd, mem_mm_16, II_SDC1, store>,
LW_FM_MM<0x2e>, ISA_MICROMIPS, FGR_32;
def LWC1_MM : MMRel, LW_FT<"lwc1", FGR32Opnd, mem_mm_16, II_LWC1, load>,
LW_FM_MM<0x27>, ISA_MICROMIPS;
def SWC1_MM : MMRel, SW_FT<"swc1", FGR32Opnd, mem_mm_16, II_SWC1, store>,
LW_FM_MM<0x26>, ISA_MICROMIPS;
}
multiclass C_COND_MM<string TypeStr, RegisterOperand RC, bits<2> fmt,
InstrItinClass itin> {
def C_F_#NAME#_MM : MMRel, C_COND_FT<"f", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 0> {
let BaseOpcode = "c.f."#NAME;
let isCommutable = 1;
}
def C_UN_#NAME#_MM : MMRel, C_COND_FT<"un", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 1> {
let BaseOpcode = "c.un."#NAME;
let isCommutable = 1;
}
def C_EQ_#NAME#_MM : MMRel, C_COND_FT<"eq", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 2> {
let BaseOpcode = "c.eq."#NAME;
let isCommutable = 1;
}
def C_UEQ_#NAME#_MM : MMRel, C_COND_FT<"ueq", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 3> {
let BaseOpcode = "c.ueq."#NAME;
let isCommutable = 1;
}
def C_OLT_#NAME#_MM : MMRel, C_COND_FT<"olt", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 4> {
let BaseOpcode = "c.olt."#NAME;
}
def C_ULT_#NAME#_MM : MMRel, C_COND_FT<"ult", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 5> {
let BaseOpcode = "c.ult."#NAME;
}
def C_OLE_#NAME#_MM : MMRel, C_COND_FT<"ole", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 6> {
let BaseOpcode = "c.ole."#NAME;
}
def C_ULE_#NAME#_MM : MMRel, C_COND_FT<"ule", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 7> {
let BaseOpcode = "c.ule."#NAME;
}
def C_SF_#NAME#_MM : MMRel, C_COND_FT<"sf", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 8> {
let BaseOpcode = "c.sf."#NAME;
let isCommutable = 1;
}
def C_NGLE_#NAME#_MM : MMRel, C_COND_FT<"ngle", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 9> {
let BaseOpcode = "c.ngle."#NAME;
}
def C_SEQ_#NAME#_MM : MMRel, C_COND_FT<"seq", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 10> {
let BaseOpcode = "c.seq."#NAME;
let isCommutable = 1;
}
def C_NGL_#NAME#_MM : MMRel, C_COND_FT<"ngl", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 11> {
let BaseOpcode = "c.ngl."#NAME;
}
def C_LT_#NAME#_MM : MMRel, C_COND_FT<"lt", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 12> {
let BaseOpcode = "c.lt."#NAME;
}
def C_NGE_#NAME#_MM : MMRel, C_COND_FT<"nge", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 13> {
let BaseOpcode = "c.nge."#NAME;
}
def C_LE_#NAME#_MM : MMRel, C_COND_FT<"le", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 14> {
let BaseOpcode = "c.le."#NAME;
}
def C_NGT_#NAME#_MM : MMRel, C_COND_FT<"ngt", TypeStr, RC, itin>,
C_COND_FM_MM<fmt, 15> {
let BaseOpcode = "c.ngt."#NAME;
}
}
let DecoderNamespace = "MicroMips" in {
defm S : C_COND_MM<"s", FGR32Opnd, 0b00, II_C_CC_S>,
ISA_MICROMIPS32_NOT_MIPS32R6;
defm D32 : C_COND_MM<"d", AFGR64Opnd, 0b01, II_C_CC_D>,
ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32;
}
let DecoderNamespace = "Mips64" in
defm D64 : C_COND_MM<"d", FGR64Opnd, 0b01, II_C_CC_D>,
ISA_MICROMIPS32_NOT_MIPS32R6, FGR_64;
defm S_MM : C_COND_ALIASES<"s", FGR32Opnd>, HARDFLOAT,
ISA_MICROMIPS32_NOT_MIPS32R6;
defm D32_MM : C_COND_ALIASES<"d", AFGR64Opnd>, HARDFLOAT,
ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32;
defm D64_MM : C_COND_ALIASES<"d", FGR64Opnd>, HARDFLOAT,
ISA_MICROMIPS32_NOT_MIPS32R6, FGR_64;
defm : BC1_ALIASES<BC1T_MM, "bc1t", BC1F_MM, "bc1f">,
ISA_MICROMIPS32_NOT_MIPS32R6, HARDFLOAT;
// To generate NMADD and NMSUB instructions when fneg node is present
let AdditionalPredicates = [NoNaNsFPMath, HasMadd4,
InMicroMips, NotMips32r6] in {
defm : NMADD_NMSUB<NMADD_S_MM, NMSUB_S_MM, FGR32Opnd>,
ISA_MICROMIPS32_NOT_MIPS32R6;
defm : NMADD_NMSUB<NMADD_D32_MM, NMSUB_D32_MM, AFGR64Opnd>,
ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32;
}
//===----------------------------------------------------------------------===//
// Floating Point Patterns
//===----------------------------------------------------------------------===//
// Patterns for loads/stores with a reg+imm operand.
let AddedComplexity = 40 in {
def : LoadRegImmPat<LDC1_MM, f64, load>, ISA_MICROMIPS, FGR_32;
def : StoreRegImmPat<SDC1_MM, f64>, ISA_MICROMIPS, FGR_32;
def : LoadRegImmPat<LWC1_MM, f32, load>, ISA_MICROMIPS;
def : StoreRegImmPat<SWC1_MM, f32>, ISA_MICROMIPS;
}
def : MipsPat<(MipsMTC1_D64 GPR32Opnd:$src),
(MTC1_D64_MM GPR32Opnd:$src)>, ISA_MICROMIPS, FGR_64;
def : MipsPat<(f32 fpimm0), (MTC1_MM ZERO)>, ISA_MICROMIPS32_NOT_MIPS32R6;
def : MipsPat<(f32 fpimm0neg), (FNEG_S_MM (MTC1_MM ZERO))>,
ISA_MICROMIPS32_NOT_MIPS32R6;
def : MipsPat<(f32 (fpround FGR64Opnd:$src)),
(CVT_S_D64_MM FGR64Opnd:$src)>, ISA_MICROMIPS, FGR_64;
def : MipsPat<(f64 (fpextend FGR32Opnd:$src)),
(CVT_D64_S_MM FGR32Opnd:$src)>, ISA_MICROMIPS, FGR_64;
def : MipsPat<(f32 (fpround AFGR64Opnd:$src)),
(CVT_S_D32_MM AFGR64Opnd:$src)>, ISA_MICROMIPS, FGR_32;
def : MipsPat<(f64 (fpextend FGR32Opnd:$src)),
(CVT_D32_S_MM FGR32Opnd:$src)>, ISA_MICROMIPS, FGR_32;
def : MipsPat<(MipsTruncIntFP AFGR64Opnd:$src),
(TRUNC_W_MM AFGR64Opnd:$src)>, ISA_MICROMIPS32_NOT_MIPS32R6,
FGR_32;
+def : MipsPat<(MipsTruncIntFP FGR64Opnd:$src),
+ (CVT_W_D64_MM FGR64Opnd:$src)>, ISA_MICROMIPS32_NOT_MIPS32R6,
+ FGR_64;
+def : MipsPat<(MipsTruncIntFP FGR32Opnd:$src),
+ (TRUNC_W_S_MM FGR32Opnd:$src)>, ISA_MICROMIPS32_NOT_MIPS32R6;
// Selects
defm : MovzPats0<GPR32, FGR32, MOVZ_I_S_MM, SLT_MM, SLTu_MM, SLTi_MM, SLTiu_MM>,
ISA_MICROMIPS32_NOT_MIPS32R6;
defm : MovzPats1<GPR32, FGR32, MOVZ_I_S_MM, XOR_MM>,
ISA_MICROMIPS32_NOT_MIPS32R6;
defm : MovnPats<GPR32, FGR32, MOVN_I_S_MM, XOR_MM>,
ISA_MICROMIPS32_NOT_MIPS32R6;
defm : MovzPats0<GPR32, AFGR64, MOVZ_I_D32_MM, SLT_MM, SLTu_MM, SLTi_MM,
SLTiu_MM>,
ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32;
defm : MovzPats1<GPR32, AFGR64, MOVZ_I_D32_MM, XOR_MM>,
ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32;
defm : MovnPats<GPR32, AFGR64, MOVN_I_D32_MM, XOR_MM>,
ISA_MICROMIPS32_NOT_MIPS32R6, FGR_32;
Index: stable/11/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp (revision 350259)
@@ -1,1304 +1,1305 @@
//===- MipsAsmPrinter.cpp - Mips LLVM Assembly Printer --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a printer that converts from our internal representation
// of machine-dependent LLVM code to GAS-format MIPS assembly language.
//
//===----------------------------------------------------------------------===//
#include "MipsAsmPrinter.h"
#include "InstPrinter/MipsInstPrinter.h"
#include "MCTargetDesc/MipsABIInfo.h"
#include "MCTargetDesc/MipsBaseInfo.h"
#include "MCTargetDesc/MipsMCNaCl.h"
#include "MCTargetDesc/MipsMCTargetDesc.h"
#include "Mips.h"
#include "MipsMCInstLower.h"
#include "MipsMachineFunction.h"
#include "MipsSubtarget.h"
#include "MipsTargetMachine.h"
#include "MipsTargetStreamer.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instructions.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCSymbolELF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include <cassert>
#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <vector>
using namespace llvm;
#define DEBUG_TYPE "mips-asm-printer"
extern cl::opt<bool> EmitJalrReloc;
MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() const {
return static_cast<MipsTargetStreamer &>(*OutStreamer->getTargetStreamer());
}
bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
Subtarget = &MF.getSubtarget<MipsSubtarget>();
MipsFI = MF.getInfo<MipsFunctionInfo>();
if (Subtarget->inMips16Mode())
for (std::map<
const char *,
const Mips16HardFloatInfo::FuncSignature *>::const_iterator
it = MipsFI->StubsNeeded.begin();
it != MipsFI->StubsNeeded.end(); ++it) {
const char *Symbol = it->first;
const Mips16HardFloatInfo::FuncSignature *Signature = it->second;
if (StubsNeeded.find(Symbol) == StubsNeeded.end())
StubsNeeded[Symbol] = Signature;
}
MCP = MF.getConstantPool();
// In NaCl, all indirect jump targets must be aligned to bundle size.
if (Subtarget->isTargetNaCl())
NaClAlignIndirectJumpTargets(MF);
AsmPrinter::runOnMachineFunction(MF);
emitXRayTable();
return true;
}
bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) {
MCOp = MCInstLowering.LowerOperand(MO);
return MCOp.isValid();
}
#include "MipsGenMCPseudoLowering.inc"
// Lower PseudoReturn/PseudoIndirectBranch/PseudoIndirectBranch64 to JR, JR_MM,
// JALR, or JALR64 as appropriate for the target.
void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer,
const MachineInstr *MI) {
bool HasLinkReg = false;
bool InMicroMipsMode = Subtarget->inMicroMipsMode();
MCInst TmpInst0;
if (Subtarget->hasMips64r6()) {
// MIPS64r6 should use (JALR64 ZERO_64, $rs)
TmpInst0.setOpcode(Mips::JALR64);
HasLinkReg = true;
} else if (Subtarget->hasMips32r6()) {
// MIPS32r6 should use (JALR ZERO, $rs)
if (InMicroMipsMode)
TmpInst0.setOpcode(Mips::JRC16_MMR6);
else {
TmpInst0.setOpcode(Mips::JALR);
HasLinkReg = true;
}
} else if (Subtarget->inMicroMipsMode())
// microMIPS should use (JR_MM $rs)
TmpInst0.setOpcode(Mips::JR_MM);
else {
// Everything else should use (JR $rs)
TmpInst0.setOpcode(Mips::JR);
}
MCOperand MCOp;
if (HasLinkReg) {
unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO;
TmpInst0.addOperand(MCOperand::createReg(ZeroReg));
}
lowerOperand(MI->getOperand(0), MCOp);
TmpInst0.addOperand(MCOp);
EmitToStreamer(OutStreamer, TmpInst0);
}
// If there is an MO_JALR operand, insert:
//
// .reloc tmplabel, R_{MICRO}MIPS_JALR, symbol
// tmplabel:
//
// This is an optimization hint for the linker which may then replace
// an indirect call with a direct branch.
static void emitDirectiveRelocJalr(const MachineInstr &MI,
MCContext &OutContext,
TargetMachine &TM,
MCStreamer &OutStreamer,
const MipsSubtarget &Subtarget) {
for (unsigned int I = MI.getDesc().getNumOperands(), E = MI.getNumOperands();
I < E; ++I) {
MachineOperand MO = MI.getOperand(I);
if (MO.isMCSymbol() && (MO.getTargetFlags() & MipsII::MO_JALR)) {
MCSymbol *Callee = MO.getMCSymbol();
if (Callee && !Callee->getName().empty()) {
MCSymbol *OffsetLabel = OutContext.createTempSymbol();
const MCExpr *OffsetExpr =
MCSymbolRefExpr::create(OffsetLabel, OutContext);
const MCExpr *CaleeExpr =
MCSymbolRefExpr::create(Callee, OutContext);
OutStreamer.EmitRelocDirective
(*OffsetExpr,
Subtarget.inMicroMipsMode() ? "R_MICROMIPS_JALR" : "R_MIPS_JALR",
CaleeExpr, SMLoc(), *TM.getMCSubtargetInfo());
OutStreamer.EmitLabel(OffsetLabel);
return;
}
}
}
}
void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
MipsTargetStreamer &TS = getTargetStreamer();
unsigned Opc = MI->getOpcode();
TS.forbidModuleDirective();
if (MI->isDebugValue()) {
SmallString<128> Str;
raw_svector_ostream OS(Str);
PrintDebugValueComment(MI, OS);
return;
}
if (MI->isDebugLabel())
return;
// If we just ended a constant pool, mark it as such.
if (InConstantPool && Opc != Mips::CONSTPOOL_ENTRY) {
OutStreamer->EmitDataRegion(MCDR_DataRegionEnd);
InConstantPool = false;
}
if (Opc == Mips::CONSTPOOL_ENTRY) {
// CONSTPOOL_ENTRY - This instruction represents a floating
// constant pool in the function. The first operand is the ID#
// for this instruction, the second is the index into the
// MachineConstantPool that this is, the third is the size in
// bytes of this constant pool entry.
// The required alignment is specified on the basic block holding this MI.
//
unsigned LabelId = (unsigned)MI->getOperand(0).getImm();
unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
// If this is the first entry of the pool, mark it.
if (!InConstantPool) {
OutStreamer->EmitDataRegion(MCDR_DataRegion);
InConstantPool = true;
}
OutStreamer->EmitLabel(GetCPISymbol(LabelId));
const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];
if (MCPE.isMachineConstantPoolEntry())
EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
else
EmitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal);
return;
}
switch (Opc) {
case Mips::PATCHABLE_FUNCTION_ENTER:
LowerPATCHABLE_FUNCTION_ENTER(*MI);
return;
case Mips::PATCHABLE_FUNCTION_EXIT:
LowerPATCHABLE_FUNCTION_EXIT(*MI);
return;
case Mips::PATCHABLE_TAIL_CALL:
LowerPATCHABLE_TAIL_CALL(*MI);
return;
}
if (EmitJalrReloc &&
(MI->isReturn() || MI->isCall() || MI->isIndirectBranch())) {
emitDirectiveRelocJalr(*MI, OutContext, TM, *OutStreamer, *Subtarget);
}
MachineBasicBlock::const_instr_iterator I = MI->getIterator();
MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
do {
// Do any auto-generated pseudo lowerings.
if (emitPseudoExpansionLowering(*OutStreamer, &*I))
continue;
if (I->getOpcode() == Mips::PseudoReturn ||
I->getOpcode() == Mips::PseudoReturn64 ||
I->getOpcode() == Mips::PseudoIndirectBranch ||
I->getOpcode() == Mips::PseudoIndirectBranch64 ||
I->getOpcode() == Mips::TAILCALLREG ||
I->getOpcode() == Mips::TAILCALLREG64) {
emitPseudoIndirectBranch(*OutStreamer, &*I);
continue;
}
// The inMips16Mode() test is not permanent.
// Some instructions are marked as pseudo right now which
// would make the test fail for the wrong reason but
// that will be fixed soon. We need this here because we are
// removing another test for this situation downstream in the
// callchain.
//
if (I->isPseudo() && !Subtarget->inMips16Mode()
&& !isLongBranchPseudo(I->getOpcode()))
llvm_unreachable("Pseudo opcode found in EmitInstruction()");
MCInst TmpInst0;
MCInstLowering.Lower(&*I, TmpInst0);
EmitToStreamer(*OutStreamer, TmpInst0);
} while ((++I != E) && I->isInsideBundle()); // Delay slot check
}
//===----------------------------------------------------------------------===//
//
// Mips Asm Directives
//
// -- Frame directive "frame Stackpointer, Stacksize, RARegister"
// Describe the stack frame.
//
// -- Mask directives "(f)mask bitmask, offset"
// Tells the assembler which registers are saved and where.
// bitmask - contain a little endian bitset indicating which registers are
// saved on function prologue (e.g. with a 0x80000000 mask, the
// assembler knows the register 31 (RA) is saved at prologue.
// offset - the position before stack pointer subtraction indicating where
// the first saved register on prologue is located. (e.g. with a
//
// Consider the following function prologue:
//
// .frame $fp,48,$ra
// .mask 0xc0000000,-8
// addiu $sp, $sp, -48
// sw $ra, 40($sp)
// sw $fp, 36($sp)
//
// With a 0xc0000000 mask, the assembler knows the register 31 (RA) and
// 30 (FP) are saved at prologue. As the save order on prologue is from
// left to right, RA is saved first. A -8 offset means that after the
// stack pointer subtration, the first register in the mask (RA) will be
// saved at address 48-8=40.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Mask directives
//===----------------------------------------------------------------------===//
// Create a bitmask with all callee saved registers for CPU or Floating Point
// registers. For CPU registers consider RA, GP and FP for saving if necessary.
void MipsAsmPrinter::printSavedRegsBitmask() {
// CPU and FPU Saved Registers Bitmasks
unsigned CPUBitmask = 0, FPUBitmask = 0;
int CPUTopSavedRegOff, FPUTopSavedRegOff;
// Set the CPU and FPU Bitmasks
const MachineFrameInfo &MFI = MF->getFrameInfo();
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
// size of stack area to which FP callee-saved regs are saved.
unsigned CPURegSize = TRI->getRegSizeInBits(Mips::GPR32RegClass) / 8;
unsigned FGR32RegSize = TRI->getRegSizeInBits(Mips::FGR32RegClass) / 8;
unsigned AFGR64RegSize = TRI->getRegSizeInBits(Mips::AFGR64RegClass) / 8;
bool HasAFGR64Reg = false;
unsigned CSFPRegsSize = 0;
for (const auto &I : CSI) {
unsigned Reg = I.getReg();
unsigned RegNum = TRI->getEncodingValue(Reg);
// If it's a floating point register, set the FPU Bitmask.
// If it's a general purpose register, set the CPU Bitmask.
if (Mips::FGR32RegClass.contains(Reg)) {
FPUBitmask |= (1 << RegNum);
CSFPRegsSize += FGR32RegSize;
} else if (Mips::AFGR64RegClass.contains(Reg)) {
FPUBitmask |= (3 << RegNum);
CSFPRegsSize += AFGR64RegSize;
HasAFGR64Reg = true;
} else if (Mips::GPR32RegClass.contains(Reg))
CPUBitmask |= (1 << RegNum);
}
// FP Regs are saved right below where the virtual frame pointer points to.
FPUTopSavedRegOff = FPUBitmask ?
(HasAFGR64Reg ? -AFGR64RegSize : -FGR32RegSize) : 0;
// CPU Regs are saved below FP Regs.
CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0;
MipsTargetStreamer &TS = getTargetStreamer();
// Print CPUBitmask
TS.emitMask(CPUBitmask, CPUTopSavedRegOff);
// Print FPUBitmask
TS.emitFMask(FPUBitmask, FPUTopSavedRegOff);
}
//===----------------------------------------------------------------------===//
// Frame and Set directives
//===----------------------------------------------------------------------===//
/// Frame Directive
void MipsAsmPrinter::emitFrameDirective() {
const TargetRegisterInfo &RI = *MF->getSubtarget().getRegisterInfo();
unsigned stackReg = RI.getFrameRegister(*MF);
unsigned returnReg = RI.getRARegister();
unsigned stackSize = MF->getFrameInfo().getStackSize();
getTargetStreamer().emitFrame(stackReg, stackSize, returnReg);
}
/// Emit Set directives.
const char *MipsAsmPrinter::getCurrentABIString() const {
switch (static_cast<MipsTargetMachine &>(TM).getABI().GetEnumValue()) {
case MipsABIInfo::ABI::O32: return "abi32";
case MipsABIInfo::ABI::N32: return "abiN32";
case MipsABIInfo::ABI::N64: return "abi64";
default: llvm_unreachable("Unknown Mips ABI");
}
}
void MipsAsmPrinter::EmitFunctionEntryLabel() {
MipsTargetStreamer &TS = getTargetStreamer();
// NaCl sandboxing requires that indirect call instructions are masked.
// This means that function entry points should be bundle-aligned.
if (Subtarget->isTargetNaCl())
EmitAlignment(std::max(MF->getAlignment(), MIPS_NACL_BUNDLE_ALIGN));
if (Subtarget->inMicroMipsMode()) {
TS.emitDirectiveSetMicroMips();
TS.setUsesMicroMips();
TS.updateABIInfo(*Subtarget);
} else
TS.emitDirectiveSetNoMicroMips();
if (Subtarget->inMips16Mode())
TS.emitDirectiveSetMips16();
else
TS.emitDirectiveSetNoMips16();
TS.emitDirectiveEnt(*CurrentFnSym);
OutStreamer->EmitLabel(CurrentFnSym);
}
/// EmitFunctionBodyStart - Targets can override this to emit stuff before
/// the first basic block in the function.
void MipsAsmPrinter::EmitFunctionBodyStart() {
MipsTargetStreamer &TS = getTargetStreamer();
MCInstLowering.Initialize(&MF->getContext());
bool IsNakedFunction = MF->getFunction().hasFnAttribute(Attribute::Naked);
if (!IsNakedFunction)
emitFrameDirective();
if (!IsNakedFunction)
printSavedRegsBitmask();
if (!Subtarget->inMips16Mode()) {
TS.emitDirectiveSetNoReorder();
TS.emitDirectiveSetNoMacro();
TS.emitDirectiveSetNoAt();
}
}
/// EmitFunctionBodyEnd - Targets can override this to emit stuff after
/// the last basic block in the function.
void MipsAsmPrinter::EmitFunctionBodyEnd() {
MipsTargetStreamer &TS = getTargetStreamer();
// There are instruction for this macros, but they must
// always be at the function end, and we can't emit and
// break with BB logic.
if (!Subtarget->inMips16Mode()) {
TS.emitDirectiveSetAt();
TS.emitDirectiveSetMacro();
TS.emitDirectiveSetReorder();
}
TS.emitDirectiveEnd(CurrentFnSym->getName());
// Make sure to terminate any constant pools that were at the end
// of the function.
if (!InConstantPool)
return;
InConstantPool = false;
OutStreamer->EmitDataRegion(MCDR_DataRegionEnd);
}
void MipsAsmPrinter::EmitBasicBlockEnd(const MachineBasicBlock &MBB) {
AsmPrinter::EmitBasicBlockEnd(MBB);
MipsTargetStreamer &TS = getTargetStreamer();
if (MBB.empty())
TS.emitDirectiveInsn();
}
/// isBlockOnlyReachableByFallthough - Return true if the basic block has
/// exactly one predecessor and the control transfer mechanism between
/// the predecessor and this block is a fall-through.
bool MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock*
MBB) const {
// The predecessor has to be immediately before this block.
const MachineBasicBlock *Pred = *MBB->pred_begin();
// If the predecessor is a switch statement, assume a jump table
// implementation, so it is not a fall through.
if (const BasicBlock *bb = Pred->getBasicBlock())
if (isa<SwitchInst>(bb->getTerminator()))
return false;
// If this is a landing pad, it isn't a fall through. If it has no preds,
// then nothing falls through to it.
if (MBB->isEHPad() || MBB->pred_empty())
return false;
// If there isn't exactly one predecessor, it can't be a fall through.
MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI;
++PI2;
if (PI2 != MBB->pred_end())
return false;
// The predecessor has to be immediately before this block.
if (!Pred->isLayoutSuccessor(MBB))
return false;
// If the block is completely empty, then it definitely does fall through.
if (Pred->empty())
return true;
// Otherwise, check the last instruction.
// Check if the last terminator is an unconditional branch.
MachineBasicBlock::const_iterator I = Pred->end();
while (I != Pred->begin() && !(--I)->isTerminator()) ;
return !I->isBarrier();
}
// Print out an operand for an inline asm expression.
bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &O) {
// Does this asm operand have a single letter operand modifier?
if (ExtraCode && ExtraCode[0]) {
if (ExtraCode[1] != 0) return true; // Unknown modifier.
const MachineOperand &MO = MI->getOperand(OpNum);
switch (ExtraCode[0]) {
default:
// See if this is a generic print operand
return AsmPrinter::PrintAsmOperand(MI,OpNum,AsmVariant,ExtraCode,O);
case 'X': // hex const int
if ((MO.getType()) != MachineOperand::MO_Immediate)
return true;
O << "0x" << Twine::utohexstr(MO.getImm());
return false;
case 'x': // hex const int (low 16 bits)
if ((MO.getType()) != MachineOperand::MO_Immediate)
return true;
O << "0x" << Twine::utohexstr(MO.getImm() & 0xffff);
return false;
case 'd': // decimal const int
if ((MO.getType()) != MachineOperand::MO_Immediate)
return true;
O << MO.getImm();
return false;
case 'm': // decimal const int minus 1
if ((MO.getType()) != MachineOperand::MO_Immediate)
return true;
O << MO.getImm() - 1;
return false;
case 'y': // exact log2
if ((MO.getType()) != MachineOperand::MO_Immediate)
return true;
if (!isPowerOf2_64(MO.getImm()))
return true;
O << Log2_64(MO.getImm());
return false;
case 'z':
// $0 if zero, regular printing otherwise
if (MO.getType() == MachineOperand::MO_Immediate && MO.getImm() == 0) {
O << "$0";
return false;
}
// If not, call printOperand as normal.
break;
case 'D': // Second part of a double word register operand
case 'L': // Low order register of a double word register operand
case 'M': // High order register of a double word register operand
{
if (OpNum == 0)
return true;
const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1);
if (!FlagsOP.isImm())
return true;
unsigned Flags = FlagsOP.getImm();
unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags);
// Number of registers represented by this operand. We are looking
// for 2 for 32 bit mode and 1 for 64 bit mode.
if (NumVals != 2) {
if (Subtarget->isGP64bit() && NumVals == 1 && MO.isReg()) {
unsigned Reg = MO.getReg();
O << '$' << MipsInstPrinter::getRegisterName(Reg);
return false;
}
return true;
}
unsigned RegOp = OpNum;
if (!Subtarget->isGP64bit()){
// Endianness reverses which register holds the high or low value
// between M and L.
switch(ExtraCode[0]) {
case 'M':
RegOp = (Subtarget->isLittle()) ? OpNum + 1 : OpNum;
break;
case 'L':
RegOp = (Subtarget->isLittle()) ? OpNum : OpNum + 1;
break;
case 'D': // Always the second part
RegOp = OpNum + 1;
}
if (RegOp >= MI->getNumOperands())
return true;
const MachineOperand &MO = MI->getOperand(RegOp);
if (!MO.isReg())
return true;
unsigned Reg = MO.getReg();
O << '$' << MipsInstPrinter::getRegisterName(Reg);
return false;
}
break;
}
case 'w':
// Print MSA registers for the 'f' constraint
// In LLVM, the 'w' modifier doesn't need to do anything.
// We can just call printOperand as normal.
break;
}
}
printOperand(MI, OpNum, O);
return false;
}
bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
unsigned OpNum, unsigned AsmVariant,
const char *ExtraCode,
raw_ostream &O) {
assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands");
const MachineOperand &BaseMO = MI->getOperand(OpNum);
const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1);
assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand.");
assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand.");
int Offset = OffsetMO.getImm();
// Currently we are expecting either no ExtraCode or 'D','M','L'.
if (ExtraCode) {
switch (ExtraCode[0]) {
case 'D':
Offset += 4;
break;
case 'M':
if (Subtarget->isLittle())
Offset += 4;
break;
case 'L':
if (!Subtarget->isLittle())
Offset += 4;
break;
default:
return true; // Unknown modifier.
}
}
O << Offset << "($" << MipsInstPrinter::getRegisterName(BaseMO.getReg())
<< ")";
return false;
}
void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
raw_ostream &O) {
const MachineOperand &MO = MI->getOperand(opNum);
bool closeP = false;
if (MO.getTargetFlags())
closeP = true;
switch(MO.getTargetFlags()) {
case MipsII::MO_GPREL: O << "%gp_rel("; break;
case MipsII::MO_GOT_CALL: O << "%call16("; break;
case MipsII::MO_GOT: O << "%got("; break;
case MipsII::MO_ABS_HI: O << "%hi("; break;
case MipsII::MO_ABS_LO: O << "%lo("; break;
case MipsII::MO_HIGHER: O << "%higher("; break;
case MipsII::MO_HIGHEST: O << "%highest(("; break;
case MipsII::MO_TLSGD: O << "%tlsgd("; break;
case MipsII::MO_GOTTPREL: O << "%gottprel("; break;
case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break;
case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break;
case MipsII::MO_GPOFF_HI: O << "%hi(%neg(%gp_rel("; break;
case MipsII::MO_GPOFF_LO: O << "%lo(%neg(%gp_rel("; break;
case MipsII::MO_GOT_DISP: O << "%got_disp("; break;
case MipsII::MO_GOT_PAGE: O << "%got_page("; break;
case MipsII::MO_GOT_OFST: O << "%got_ofst("; break;
}
switch (MO.getType()) {
case MachineOperand::MO_Register:
O << '$'
<< StringRef(MipsInstPrinter::getRegisterName(MO.getReg())).lower();
break;
case MachineOperand::MO_Immediate:
O << MO.getImm();
break;
case MachineOperand::MO_MachineBasicBlock:
MO.getMBB()->getSymbol()->print(O, MAI);
return;
case MachineOperand::MO_GlobalAddress:
getSymbol(MO.getGlobal())->print(O, MAI);
break;
case MachineOperand::MO_BlockAddress: {
MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
O << BA->getName();
break;
}
case MachineOperand::MO_ConstantPoolIndex:
O << getDataLayout().getPrivateGlobalPrefix() << "CPI"
<< getFunctionNumber() << "_" << MO.getIndex();
if (MO.getOffset())
O << "+" << MO.getOffset();
break;
default:
llvm_unreachable("<unknown operand type>");
}
if (closeP) O << ")";
}
void MipsAsmPrinter::
printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) {
// Load/Store memory operands -- imm($reg)
// If PIC target the target is loaded as the
// pattern lw $25,%call16($28)
// opNum can be invalid if instruction has reglist as operand.
// MemOperand is always last operand of instruction (base + offset).
switch (MI->getOpcode()) {
default:
break;
case Mips::SWM32_MM:
case Mips::LWM32_MM:
opNum = MI->getNumOperands() - 2;
break;
}
printOperand(MI, opNum+1, O);
O << "(";
printOperand(MI, opNum, O);
O << ")";
}
void MipsAsmPrinter::
printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) {
// when using stack locations for not load/store instructions
// print the same way as all normal 3 operand instructions.
printOperand(MI, opNum, O);
O << ", ";
printOperand(MI, opNum+1, O);
}
void MipsAsmPrinter::
printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
const char *Modifier) {
const MachineOperand &MO = MI->getOperand(opNum);
O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm());
}
void MipsAsmPrinter::
printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O) {
for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) {
if (i != opNum) O << ", ";
printOperand(MI, i, O);
}
}
void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) {
MipsTargetStreamer &TS = getTargetStreamer();
// MipsTargetStreamer has an initialization order problem when emitting an
// object file directly (see MipsTargetELFStreamer for full details). Work
// around it by re-initializing the PIC state here.
TS.setPic(OutContext.getObjectFileInfo()->isPositionIndependent());
// Compute MIPS architecture attributes based on the default subtarget
// that we'd have constructed. Module level directives aren't LTO
// clean anyhow.
// FIXME: For ifunc related functions we could iterate over and look
// for a feature string that doesn't match the default one.
const Triple &TT = TM.getTargetTriple();
StringRef CPU = MIPS_MC::selectMipsCPU(TT, TM.getTargetCPU());
StringRef FS = TM.getTargetFeatureString();
const MipsTargetMachine &MTM = static_cast<const MipsTargetMachine &>(TM);
const MipsSubtarget STI(TT, CPU, FS, MTM.isLittleEndian(), MTM, 0);
bool IsABICalls = STI.isABICalls();
const MipsABIInfo &ABI = MTM.getABI();
if (IsABICalls) {
TS.emitDirectiveAbiCalls();
// FIXME: This condition should be a lot more complicated that it is here.
// Ideally it should test for properties of the ABI and not the ABI
// itself.
// For the moment, I'm only correcting enough to make MIPS-IV work.
if (!isPositionIndependent() && STI.hasSym32())
TS.emitDirectiveOptionPic0();
}
// Tell the assembler which ABI we are using
std::string SectionName = std::string(".mdebug.") + getCurrentABIString();
OutStreamer->SwitchSection(
OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, 0));
// NaN: At the moment we only support:
// 1. .nan legacy (default)
// 2. .nan 2008
STI.isNaN2008() ? TS.emitDirectiveNaN2008()
: TS.emitDirectiveNaNLegacy();
// TODO: handle O64 ABI
TS.updateABIInfo(STI);
// We should always emit a '.module fp=...' but binutils 2.24 does not accept
// it. We therefore emit it when it contradicts the ABI defaults (-mfpxx or
// -mfp64) and omit it otherwise.
- if (ABI.IsO32() && (STI.isABI_FPXX() || STI.isFP64bit()))
+ if ((ABI.IsO32() && (STI.isABI_FPXX() || STI.isFP64bit())) ||
+ STI.useSoftFloat())
TS.emitDirectiveModuleFP();
// We should always emit a '.module [no]oddspreg' but binutils 2.24 does not
// accept it. We therefore emit it when it contradicts the default or an
// option has changed the default (i.e. FPXX) and omit it otherwise.
if (ABI.IsO32() && (!STI.useOddSPReg() || STI.isABI_FPXX()))
TS.emitDirectiveModuleOddSPReg();
}
void MipsAsmPrinter::emitInlineAsmStart() const {
MipsTargetStreamer &TS = getTargetStreamer();
// GCC's choice of assembler options for inline assembly code ('at', 'macro'
// and 'reorder') is different from LLVM's choice for generated code ('noat',
// 'nomacro' and 'noreorder').
// In order to maintain compatibility with inline assembly code which depends
// on GCC's assembler options being used, we have to switch to those options
// for the duration of the inline assembly block and then switch back.
TS.emitDirectiveSetPush();
TS.emitDirectiveSetAt();
TS.emitDirectiveSetMacro();
TS.emitDirectiveSetReorder();
OutStreamer->AddBlankLine();
}
void MipsAsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
const MCSubtargetInfo *EndInfo) const {
OutStreamer->AddBlankLine();
getTargetStreamer().emitDirectiveSetPop();
}
void MipsAsmPrinter::EmitJal(const MCSubtargetInfo &STI, MCSymbol *Symbol) {
MCInst I;
I.setOpcode(Mips::JAL);
I.addOperand(
MCOperand::createExpr(MCSymbolRefExpr::create(Symbol, OutContext)));
OutStreamer->EmitInstruction(I, STI);
}
void MipsAsmPrinter::EmitInstrReg(const MCSubtargetInfo &STI, unsigned Opcode,
unsigned Reg) {
MCInst I;
I.setOpcode(Opcode);
I.addOperand(MCOperand::createReg(Reg));
OutStreamer->EmitInstruction(I, STI);
}
void MipsAsmPrinter::EmitInstrRegReg(const MCSubtargetInfo &STI,
unsigned Opcode, unsigned Reg1,
unsigned Reg2) {
MCInst I;
//
// Because of the current td files for Mips32, the operands for MTC1
// appear backwards from their normal assembly order. It's not a trivial
// change to fix this in the td file so we adjust for it here.
//
if (Opcode == Mips::MTC1) {
unsigned Temp = Reg1;
Reg1 = Reg2;
Reg2 = Temp;
}
I.setOpcode(Opcode);
I.addOperand(MCOperand::createReg(Reg1));
I.addOperand(MCOperand::createReg(Reg2));
OutStreamer->EmitInstruction(I, STI);
}
void MipsAsmPrinter::EmitInstrRegRegReg(const MCSubtargetInfo &STI,
unsigned Opcode, unsigned Reg1,
unsigned Reg2, unsigned Reg3) {
MCInst I;
I.setOpcode(Opcode);
I.addOperand(MCOperand::createReg(Reg1));
I.addOperand(MCOperand::createReg(Reg2));
I.addOperand(MCOperand::createReg(Reg3));
OutStreamer->EmitInstruction(I, STI);
}
void MipsAsmPrinter::EmitMovFPIntPair(const MCSubtargetInfo &STI,
unsigned MovOpc, unsigned Reg1,
unsigned Reg2, unsigned FPReg1,
unsigned FPReg2, bool LE) {
if (!LE) {
unsigned temp = Reg1;
Reg1 = Reg2;
Reg2 = temp;
}
EmitInstrRegReg(STI, MovOpc, Reg1, FPReg1);
EmitInstrRegReg(STI, MovOpc, Reg2, FPReg2);
}
void MipsAsmPrinter::EmitSwapFPIntParams(const MCSubtargetInfo &STI,
Mips16HardFloatInfo::FPParamVariant PV,
bool LE, bool ToFP) {
using namespace Mips16HardFloatInfo;
unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1;
switch (PV) {
case FSig:
EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12);
break;
case FFSig:
EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE);
break;
case FDSig:
EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12);
EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE);
break;
case DSig:
EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
break;
case DDSig:
EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE);
break;
case DFSig:
EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
EmitInstrRegReg(STI, MovOpc, Mips::A2, Mips::F14);
break;
case NoSig:
return;
}
}
void MipsAsmPrinter::EmitSwapFPIntRetval(
const MCSubtargetInfo &STI, Mips16HardFloatInfo::FPReturnVariant RV,
bool LE) {
using namespace Mips16HardFloatInfo;
unsigned MovOpc = Mips::MFC1;
switch (RV) {
case FRet:
EmitInstrRegReg(STI, MovOpc, Mips::V0, Mips::F0);
break;
case DRet:
EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
break;
case CFRet:
EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
break;
case CDRet:
EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE);
break;
case NoFPRet:
break;
}
}
void MipsAsmPrinter::EmitFPCallStub(
const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) {
using namespace Mips16HardFloatInfo;
MCSymbol *MSymbol = OutContext.getOrCreateSymbol(StringRef(Symbol));
bool LE = getDataLayout().isLittleEndian();
// Construct a local MCSubtargetInfo here.
// This is because the MachineFunction won't exist (but have not yet been
// freed) and since we're at the global level we can use the default
// constructed subtarget.
std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo(
TM.getTargetTriple().str(), TM.getTargetCPU(),
TM.getTargetFeatureString()));
//
// .global xxxx
//
OutStreamer->EmitSymbolAttribute(MSymbol, MCSA_Global);
const char *RetType;
//
// make the comment field identifying the return and parameter
// types of the floating point stub
// # Stub function to call rettype xxxx (params)
//
switch (Signature->RetSig) {
case FRet:
RetType = "float";
break;
case DRet:
RetType = "double";
break;
case CFRet:
RetType = "complex";
break;
case CDRet:
RetType = "double complex";
break;
case NoFPRet:
RetType = "";
break;
}
const char *Parms;
switch (Signature->ParamSig) {
case FSig:
Parms = "float";
break;
case FFSig:
Parms = "float, float";
break;
case FDSig:
Parms = "float, double";
break;
case DSig:
Parms = "double";
break;
case DDSig:
Parms = "double, double";
break;
case DFSig:
Parms = "double, float";
break;
case NoSig:
Parms = "";
break;
}
OutStreamer->AddComment("\t# Stub function to call " + Twine(RetType) + " " +
Twine(Symbol) + " (" + Twine(Parms) + ")");
//
// probably not necessary but we save and restore the current section state
//
OutStreamer->PushSection();
//
// .section mips16.call.fpxxxx,"ax",@progbits
//
MCSectionELF *M = OutContext.getELFSection(
".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS,
ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
OutStreamer->SwitchSection(M, nullptr);
//
// .align 2
//
OutStreamer->EmitValueToAlignment(4);
MipsTargetStreamer &TS = getTargetStreamer();
//
// .set nomips16
// .set nomicromips
//
TS.emitDirectiveSetNoMips16();
TS.emitDirectiveSetNoMicroMips();
//
// .ent __call_stub_fp_xxxx
// .type __call_stub_fp_xxxx,@function
// __call_stub_fp_xxxx:
//
std::string x = "__call_stub_fp_" + std::string(Symbol);
MCSymbolELF *Stub =
cast<MCSymbolELF>(OutContext.getOrCreateSymbol(StringRef(x)));
TS.emitDirectiveEnt(*Stub);
MCSymbol *MType =
OutContext.getOrCreateSymbol("__call_stub_fp_" + Twine(Symbol));
OutStreamer->EmitSymbolAttribute(MType, MCSA_ELF_TypeFunction);
OutStreamer->EmitLabel(Stub);
// Only handle non-pic for now.
assert(!isPositionIndependent() &&
"should not be here if we are compiling pic");
TS.emitDirectiveSetReorder();
//
// We need to add a MipsMCExpr class to MCTargetDesc to fully implement
// stubs without raw text but this current patch is for compiler generated
// functions and they all return some value.
// The calling sequence for non pic is different in that case and we need
// to implement %lo and %hi in order to handle the case of no return value
// See the corresponding method in Mips16HardFloat for details.
//
// mov the return address to S2.
// we have no stack space to store it and we are about to make another call.
// We need to make sure that the enclosing function knows to save S2
// This should have already been handled.
//
// Mov $18, $31
EmitInstrRegRegReg(*STI, Mips::OR, Mips::S2, Mips::RA, Mips::ZERO);
EmitSwapFPIntParams(*STI, Signature->ParamSig, LE, true);
// Jal xxxx
//
EmitJal(*STI, MSymbol);
// fix return values
EmitSwapFPIntRetval(*STI, Signature->RetSig, LE);
//
// do the return
// if (Signature->RetSig == NoFPRet)
// llvm_unreachable("should not be any stubs here with no return value");
// else
EmitInstrReg(*STI, Mips::JR, Mips::S2);
MCSymbol *Tmp = OutContext.createTempSymbol();
OutStreamer->EmitLabel(Tmp);
const MCSymbolRefExpr *E = MCSymbolRefExpr::create(Stub, OutContext);
const MCSymbolRefExpr *T = MCSymbolRefExpr::create(Tmp, OutContext);
const MCExpr *T_min_E = MCBinaryExpr::createSub(T, E, OutContext);
OutStreamer->emitELFSize(Stub, T_min_E);
TS.emitDirectiveEnd(x);
OutStreamer->PopSection();
}
void MipsAsmPrinter::EmitEndOfAsmFile(Module &M) {
// Emit needed stubs
//
for (std::map<
const char *,
const Mips16HardFloatInfo::FuncSignature *>::const_iterator
it = StubsNeeded.begin();
it != StubsNeeded.end(); ++it) {
const char *Symbol = it->first;
const Mips16HardFloatInfo::FuncSignature *Signature = it->second;
EmitFPCallStub(Symbol, Signature);
}
// return to the text section
OutStreamer->SwitchSection(OutContext.getObjectFileInfo()->getTextSection());
}
void MipsAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) {
const uint8_t NoopsInSledCount = Subtarget->isGP64bit() ? 15 : 11;
// For mips32 we want to emit the following pattern:
//
// .Lxray_sled_N:
// ALIGN
// B .tmpN
// 11 NOP instructions (44 bytes)
// ADDIU T9, T9, 52
// .tmpN
//
// We need the 44 bytes (11 instructions) because at runtime, we'd
// be patching over the full 48 bytes (12 instructions) with the following
// pattern:
//
// ADDIU SP, SP, -8
// NOP
// SW RA, 4(SP)
// SW T9, 0(SP)
// LUI T9, %hi(__xray_FunctionEntry/Exit)
// ORI T9, T9, %lo(__xray_FunctionEntry/Exit)
// LUI T0, %hi(function_id)
// JALR T9
// ORI T0, T0, %lo(function_id)
// LW T9, 0(SP)
// LW RA, 4(SP)
// ADDIU SP, SP, 8
//
// We add 52 bytes to t9 because we want to adjust the function pointer to
// the actual start of function i.e. the address just after the noop sled.
// We do this because gp displacement relocation is emitted at the start of
// of the function i.e after the nop sled and to correctly calculate the
// global offset table address, t9 must hold the address of the instruction
// containing the gp displacement relocation.
// FIXME: Is this correct for the static relocation model?
//
// For mips64 we want to emit the following pattern:
//
// .Lxray_sled_N:
// ALIGN
// B .tmpN
// 15 NOP instructions (60 bytes)
// .tmpN
//
// We need the 60 bytes (15 instructions) because at runtime, we'd
// be patching over the full 64 bytes (16 instructions) with the following
// pattern:
//
// DADDIU SP, SP, -16
// NOP
// SD RA, 8(SP)
// SD T9, 0(SP)
// LUI T9, %highest(__xray_FunctionEntry/Exit)
// ORI T9, T9, %higher(__xray_FunctionEntry/Exit)
// DSLL T9, T9, 16
// ORI T9, T9, %hi(__xray_FunctionEntry/Exit)
// DSLL T9, T9, 16
// ORI T9, T9, %lo(__xray_FunctionEntry/Exit)
// LUI T0, %hi(function_id)
// JALR T9
// ADDIU T0, T0, %lo(function_id)
// LD T9, 0(SP)
// LD RA, 8(SP)
// DADDIU SP, SP, 16
//
OutStreamer->EmitCodeAlignment(4);
auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
OutStreamer->EmitLabel(CurSled);
auto Target = OutContext.createTempSymbol();
// Emit "B .tmpN" instruction, which jumps over the nop sled to the actual
// start of function
const MCExpr *TargetExpr = MCSymbolRefExpr::create(
Target, MCSymbolRefExpr::VariantKind::VK_None, OutContext);
EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::BEQ)
.addReg(Mips::ZERO)
.addReg(Mips::ZERO)
.addExpr(TargetExpr));
for (int8_t I = 0; I < NoopsInSledCount; I++)
EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::SLL)
.addReg(Mips::ZERO)
.addReg(Mips::ZERO)
.addImm(0));
OutStreamer->EmitLabel(Target);
if (!Subtarget->isGP64bit()) {
EmitToStreamer(*OutStreamer,
MCInstBuilder(Mips::ADDiu)
.addReg(Mips::T9)
.addReg(Mips::T9)
.addImm(0x34));
}
recordSled(CurSled, MI, Kind);
}
void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI) {
EmitSled(MI, SledKind::FUNCTION_ENTER);
}
void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {
EmitSled(MI, SledKind::FUNCTION_EXIT);
}
void MipsAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {
EmitSled(MI, SledKind::TAIL_CALL);
}
void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
raw_ostream &OS) {
// TODO: implement
}
// Emit .dtprelword or .dtpreldword directive
// and value for debug thread local expression.
void MipsAsmPrinter::EmitDebugValue(const MCExpr *Value, unsigned Size) const {
if (auto *MipsExpr = dyn_cast<MipsMCExpr>(Value)) {
if (MipsExpr && MipsExpr->getKind() == MipsMCExpr::MEK_DTPREL) {
switch (Size) {
case 4:
OutStreamer->EmitDTPRel32Value(MipsExpr->getSubExpr());
break;
case 8:
OutStreamer->EmitDTPRel64Value(MipsExpr->getSubExpr());
break;
default:
llvm_unreachable("Unexpected size of expression value.");
}
return;
}
}
AsmPrinter::EmitDebugValue(Value, Size);
}
// Align all targets of indirect branches on bundle size. Used only if target
// is NaCl.
void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) {
// Align all blocks that are jumped to through jump table.
if (MachineJumpTableInfo *JtInfo = MF.getJumpTableInfo()) {
const std::vector<MachineJumpTableEntry> &JT = JtInfo->getJumpTables();
for (unsigned I = 0; I < JT.size(); ++I) {
const std::vector<MachineBasicBlock*> &MBBs = JT[I].MBBs;
for (unsigned J = 0; J < MBBs.size(); ++J)
MBBs[J]->setAlignment(MIPS_NACL_BUNDLE_ALIGN);
}
}
// If basic block address is taken, block can be target of indirect branch.
for (auto &MBB : MF) {
if (MBB.hasAddressTaken())
MBB.setAlignment(MIPS_NACL_BUNDLE_ALIGN);
}
}
bool MipsAsmPrinter::isLongBranchPseudo(int Opcode) const {
return (Opcode == Mips::LONG_BRANCH_LUi
|| Opcode == Mips::LONG_BRANCH_LUi2Op
|| Opcode == Mips::LONG_BRANCH_LUi2Op_64
|| Opcode == Mips::LONG_BRANCH_ADDiu
|| Opcode == Mips::LONG_BRANCH_ADDiu2Op
|| Opcode == Mips::LONG_BRANCH_DADDiu
|| Opcode == Mips::LONG_BRANCH_DADDiu2Op);
}
// Force static initialization.
extern "C" void LLVMInitializeMipsAsmPrinter() {
RegisterAsmPrinter<MipsAsmPrinter> X(getTheMipsTarget());
RegisterAsmPrinter<MipsAsmPrinter> Y(getTheMipselTarget());
RegisterAsmPrinter<MipsAsmPrinter> A(getTheMips64Target());
RegisterAsmPrinter<MipsAsmPrinter> B(getTheMips64elTarget());
}
Index: stable/11/contrib/llvm/lib/Target/Mips/MipsDSPInstrInfo.td
===================================================================
--- stable/11/contrib/llvm/lib/Target/Mips/MipsDSPInstrInfo.td (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/Mips/MipsDSPInstrInfo.td (revision 350259)
@@ -1,1471 +1,1473 @@
//===- MipsDSPInstrInfo.td - DSP ASE instructions -*- tablegen ------------*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes Mips DSP ASE instructions.
//
//===----------------------------------------------------------------------===//
// ImmLeaf
def immZExt1 : ImmLeaf<i32, [{return isUInt<1>(Imm);}]>;
def immZExt2 : ImmLeaf<i32, [{return isUInt<2>(Imm);}]>;
def immZExt3 : ImmLeaf<i32, [{return isUInt<3>(Imm);}]>;
def immZExt4 : ImmLeaf<i32, [{return isUInt<4>(Imm);}]>;
def immZExt8 : ImmLeaf<i32, [{return isUInt<8>(Imm);}]>;
def immZExt10 : ImmLeaf<i32, [{return isUInt<10>(Imm);}]>;
def immSExt6 : ImmLeaf<i32, [{return isInt<6>(Imm);}]>;
def immSExt10 : ImmLeaf<i32, [{return isInt<10>(Imm);}]>;
// Mips-specific dsp nodes
def SDT_MipsExtr : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>,
SDTCisVT<2, untyped>]>;
def SDT_MipsShilo : SDTypeProfile<1, 2, [SDTCisVT<0, untyped>,
SDTCisSameAs<0, 2>, SDTCisVT<1, i32>]>;
def SDT_MipsDPA : SDTypeProfile<1, 3, [SDTCisVT<0, untyped>, SDTCisSameAs<0, 3>,
SDTCisVT<1, i32>, SDTCisSameAs<1, 2>]>;
def SDT_MipsSHIFT_DSP : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisSameAs<0, 1>,
SDTCisVT<2, i32>]>;
class MipsDSPBase<string Opc, SDTypeProfile Prof> :
SDNode<!strconcat("MipsISD::", Opc), Prof>;
class MipsDSPSideEffectBase<string Opc, SDTypeProfile Prof> :
SDNode<!strconcat("MipsISD::", Opc), Prof, [SDNPHasChain, SDNPSideEffect]>;
def MipsEXTP : MipsDSPSideEffectBase<"EXTP", SDT_MipsExtr>;
def MipsEXTPDP : MipsDSPSideEffectBase<"EXTPDP", SDT_MipsExtr>;
def MipsEXTR_S_H : MipsDSPSideEffectBase<"EXTR_S_H", SDT_MipsExtr>;
def MipsEXTR_W : MipsDSPSideEffectBase<"EXTR_W", SDT_MipsExtr>;
def MipsEXTR_R_W : MipsDSPSideEffectBase<"EXTR_R_W", SDT_MipsExtr>;
def MipsEXTR_RS_W : MipsDSPSideEffectBase<"EXTR_RS_W", SDT_MipsExtr>;
def MipsSHILO : MipsDSPBase<"SHILO", SDT_MipsShilo>;
def MipsMTHLIP : MipsDSPSideEffectBase<"MTHLIP", SDT_MipsShilo>;
def MipsMULSAQ_S_W_PH : MipsDSPSideEffectBase<"MULSAQ_S_W_PH", SDT_MipsDPA>;
def MipsMAQ_S_W_PHL : MipsDSPSideEffectBase<"MAQ_S_W_PHL", SDT_MipsDPA>;
def MipsMAQ_S_W_PHR : MipsDSPSideEffectBase<"MAQ_S_W_PHR", SDT_MipsDPA>;
def MipsMAQ_SA_W_PHL : MipsDSPSideEffectBase<"MAQ_SA_W_PHL", SDT_MipsDPA>;
def MipsMAQ_SA_W_PHR : MipsDSPSideEffectBase<"MAQ_SA_W_PHR", SDT_MipsDPA>;
def MipsDPAU_H_QBL : MipsDSPBase<"DPAU_H_QBL", SDT_MipsDPA>;
def MipsDPAU_H_QBR : MipsDSPBase<"DPAU_H_QBR", SDT_MipsDPA>;
def MipsDPSU_H_QBL : MipsDSPBase<"DPSU_H_QBL", SDT_MipsDPA>;
def MipsDPSU_H_QBR : MipsDSPBase<"DPSU_H_QBR", SDT_MipsDPA>;
def MipsDPAQ_S_W_PH : MipsDSPSideEffectBase<"DPAQ_S_W_PH", SDT_MipsDPA>;
def MipsDPSQ_S_W_PH : MipsDSPSideEffectBase<"DPSQ_S_W_PH", SDT_MipsDPA>;
def MipsDPAQ_SA_L_W : MipsDSPSideEffectBase<"DPAQ_SA_L_W", SDT_MipsDPA>;
def MipsDPSQ_SA_L_W : MipsDSPSideEffectBase<"DPSQ_SA_L_W", SDT_MipsDPA>;
def MipsDPA_W_PH : MipsDSPBase<"DPA_W_PH", SDT_MipsDPA>;
def MipsDPS_W_PH : MipsDSPBase<"DPS_W_PH", SDT_MipsDPA>;
def MipsDPAQX_S_W_PH : MipsDSPSideEffectBase<"DPAQX_S_W_PH", SDT_MipsDPA>;
def MipsDPAQX_SA_W_PH : MipsDSPSideEffectBase<"DPAQX_SA_W_PH", SDT_MipsDPA>;
def MipsDPAX_W_PH : MipsDSPBase<"DPAX_W_PH", SDT_MipsDPA>;
def MipsDPSX_W_PH : MipsDSPBase<"DPSX_W_PH", SDT_MipsDPA>;
def MipsDPSQX_S_W_PH : MipsDSPSideEffectBase<"DPSQX_S_W_PH", SDT_MipsDPA>;
def MipsDPSQX_SA_W_PH : MipsDSPSideEffectBase<"DPSQX_SA_W_PH", SDT_MipsDPA>;
def MipsMULSA_W_PH : MipsDSPBase<"MULSA_W_PH", SDT_MipsDPA>;
def MipsMULT : MipsDSPBase<"MULT", SDT_MipsDPA>;
def MipsMULTU : MipsDSPBase<"MULTU", SDT_MipsDPA>;
def MipsMADD_DSP : MipsDSPBase<"MADD_DSP", SDT_MipsDPA>;
def MipsMADDU_DSP : MipsDSPBase<"MADDU_DSP", SDT_MipsDPA>;
def MipsMSUB_DSP : MipsDSPBase<"MSUB_DSP", SDT_MipsDPA>;
def MipsMSUBU_DSP : MipsDSPBase<"MSUBU_DSP", SDT_MipsDPA>;
def MipsSHLL_DSP : MipsDSPBase<"SHLL_DSP", SDT_MipsSHIFT_DSP>;
def MipsSHRA_DSP : MipsDSPBase<"SHRA_DSP", SDT_MipsSHIFT_DSP>;
def MipsSHRL_DSP : MipsDSPBase<"SHRL_DSP", SDT_MipsSHIFT_DSP>;
def MipsSETCC_DSP : MipsDSPBase<"SETCC_DSP", SDTSetCC>;
def MipsSELECT_CC_DSP : MipsDSPBase<"SELECT_CC_DSP", SDTSelectCC>;
// Flags.
class Uses<list<Register> Regs> {
list<Register> Uses = Regs;
}
class Defs<list<Register> Regs> {
list<Register> Defs = Regs;
}
// Instruction encoding.
class ADDU_QB_ENC : ADDU_QB_FMT<0b00000>;
class ADDU_S_QB_ENC : ADDU_QB_FMT<0b00100>;
class SUBU_QB_ENC : ADDU_QB_FMT<0b00001>;
class SUBU_S_QB_ENC : ADDU_QB_FMT<0b00101>;
class ADDQ_PH_ENC : ADDU_QB_FMT<0b01010>;
class ADDQ_S_PH_ENC : ADDU_QB_FMT<0b01110>;
class SUBQ_PH_ENC : ADDU_QB_FMT<0b01011>;
class SUBQ_S_PH_ENC : ADDU_QB_FMT<0b01111>;
class ADDQ_S_W_ENC : ADDU_QB_FMT<0b10110>;
class SUBQ_S_W_ENC : ADDU_QB_FMT<0b10111>;
class ADDSC_ENC : ADDU_QB_FMT<0b10000>;
class ADDWC_ENC : ADDU_QB_FMT<0b10001>;
class MODSUB_ENC : ADDU_QB_FMT<0b10010>;
class RADDU_W_QB_ENC : RADDU_W_QB_FMT<0b10100>;
class ABSQ_S_PH_ENC : ABSQ_S_PH_R2_FMT<0b01001>;
class ABSQ_S_W_ENC : ABSQ_S_PH_R2_FMT<0b10001>;
class PRECRQ_QB_PH_ENC : CMP_EQ_QB_R3_FMT<0b01100>;
class PRECRQ_PH_W_ENC : CMP_EQ_QB_R3_FMT<0b10100>;
class PRECRQ_RS_PH_W_ENC : CMP_EQ_QB_R3_FMT<0b10101>;
class PRECRQU_S_QB_PH_ENC : CMP_EQ_QB_R3_FMT<0b01111>;
class PRECEQ_W_PHL_ENC : ABSQ_S_PH_R2_FMT<0b01100>;
class PRECEQ_W_PHR_ENC : ABSQ_S_PH_R2_FMT<0b01101>;
class PRECEQU_PH_QBL_ENC : ABSQ_S_PH_R2_FMT<0b00100>;
class PRECEQU_PH_QBR_ENC : ABSQ_S_PH_R2_FMT<0b00101>;
class PRECEQU_PH_QBLA_ENC : ABSQ_S_PH_R2_FMT<0b00110>;
class PRECEQU_PH_QBRA_ENC : ABSQ_S_PH_R2_FMT<0b00111>;
class PRECEU_PH_QBL_ENC : ABSQ_S_PH_R2_FMT<0b11100>;
class PRECEU_PH_QBR_ENC : ABSQ_S_PH_R2_FMT<0b11101>;
class PRECEU_PH_QBLA_ENC : ABSQ_S_PH_R2_FMT<0b11110>;
class PRECEU_PH_QBRA_ENC : ABSQ_S_PH_R2_FMT<0b11111>;
class SHLL_QB_ENC : SHLL_QB_FMT<0b00000>;
class SHLLV_QB_ENC : SHLL_QB_FMT<0b00010>;
class SHRL_QB_ENC : SHLL_QB_FMT<0b00001>;
class SHRLV_QB_ENC : SHLL_QB_FMT<0b00011>;
class SHLL_PH_ENC : SHLL_QB_FMT<0b01000>;
class SHLLV_PH_ENC : SHLL_QB_FMT<0b01010>;
class SHLL_S_PH_ENC : SHLL_QB_FMT<0b01100>;
class SHLLV_S_PH_ENC : SHLL_QB_FMT<0b01110>;
class SHRA_PH_ENC : SHLL_QB_FMT<0b01001>;
class SHRAV_PH_ENC : SHLL_QB_FMT<0b01011>;
class SHRA_R_PH_ENC : SHLL_QB_FMT<0b01101>;
class SHRAV_R_PH_ENC : SHLL_QB_FMT<0b01111>;
class SHLL_S_W_ENC : SHLL_QB_FMT<0b10100>;
class SHLLV_S_W_ENC : SHLL_QB_FMT<0b10110>;
class SHRA_R_W_ENC : SHLL_QB_FMT<0b10101>;
class SHRAV_R_W_ENC : SHLL_QB_FMT<0b10111>;
class MULEU_S_PH_QBL_ENC : ADDU_QB_FMT<0b00110>;
class MULEU_S_PH_QBR_ENC : ADDU_QB_FMT<0b00111>;
class MULEQ_S_W_PHL_ENC : ADDU_QB_FMT<0b11100>;
class MULEQ_S_W_PHR_ENC : ADDU_QB_FMT<0b11101>;
class MULQ_RS_PH_ENC : ADDU_QB_FMT<0b11111>;
class MULSAQ_S_W_PH_ENC : DPA_W_PH_FMT<0b00110>;
class MAQ_S_W_PHL_ENC : DPA_W_PH_FMT<0b10100>;
class MAQ_S_W_PHR_ENC : DPA_W_PH_FMT<0b10110>;
class MAQ_SA_W_PHL_ENC : DPA_W_PH_FMT<0b10000>;
class MAQ_SA_W_PHR_ENC : DPA_W_PH_FMT<0b10010>;
class MFHI_ENC : MFHI_FMT<0b010000>;
class MFLO_ENC : MFHI_FMT<0b010010>;
class MTHI_ENC : MTHI_FMT<0b010001>;
class MTLO_ENC : MTHI_FMT<0b010011>;
class DPAU_H_QBL_ENC : DPA_W_PH_FMT<0b00011>;
class DPAU_H_QBR_ENC : DPA_W_PH_FMT<0b00111>;
class DPSU_H_QBL_ENC : DPA_W_PH_FMT<0b01011>;
class DPSU_H_QBR_ENC : DPA_W_PH_FMT<0b01111>;
class DPAQ_S_W_PH_ENC : DPA_W_PH_FMT<0b00100>;
class DPSQ_S_W_PH_ENC : DPA_W_PH_FMT<0b00101>;
class DPAQ_SA_L_W_ENC : DPA_W_PH_FMT<0b01100>;
class DPSQ_SA_L_W_ENC : DPA_W_PH_FMT<0b01101>;
class MULT_DSP_ENC : MULT_FMT<0b000000, 0b011000>;
class MULTU_DSP_ENC : MULT_FMT<0b000000, 0b011001>;
class MADD_DSP_ENC : MULT_FMT<0b011100, 0b000000>;
class MADDU_DSP_ENC : MULT_FMT<0b011100, 0b000001>;
class MSUB_DSP_ENC : MULT_FMT<0b011100, 0b000100>;
class MSUBU_DSP_ENC : MULT_FMT<0b011100, 0b000101>;
class CMPU_EQ_QB_ENC : CMP_EQ_QB_R2_FMT<0b00000>;
class CMPU_LT_QB_ENC : CMP_EQ_QB_R2_FMT<0b00001>;
class CMPU_LE_QB_ENC : CMP_EQ_QB_R2_FMT<0b00010>;
class CMPGU_EQ_QB_ENC : CMP_EQ_QB_R3_FMT<0b00100>;
class CMPGU_LT_QB_ENC : CMP_EQ_QB_R3_FMT<0b00101>;
class CMPGU_LE_QB_ENC : CMP_EQ_QB_R3_FMT<0b00110>;
class CMP_EQ_PH_ENC : CMP_EQ_QB_R2_FMT<0b01000>;
class CMP_LT_PH_ENC : CMP_EQ_QB_R2_FMT<0b01001>;
class CMP_LE_PH_ENC : CMP_EQ_QB_R2_FMT<0b01010>;
class BITREV_ENC : ABSQ_S_PH_R2_FMT<0b11011>;
class PACKRL_PH_ENC : CMP_EQ_QB_R3_FMT<0b01110>;
class REPL_QB_ENC : REPL_FMT<0b00010>;
class REPL_PH_ENC : REPL_FMT<0b01010>;
class REPLV_QB_ENC : ABSQ_S_PH_R2_FMT<0b00011>;
class REPLV_PH_ENC : ABSQ_S_PH_R2_FMT<0b01011>;
class PICK_QB_ENC : CMP_EQ_QB_R3_FMT<0b00011>;
class PICK_PH_ENC : CMP_EQ_QB_R3_FMT<0b01011>;
class LWX_ENC : LX_FMT<0b00000>;
class LHX_ENC : LX_FMT<0b00100>;
class LBUX_ENC : LX_FMT<0b00110>;
class BPOSGE32_ENC : BPOSGE32_FMT<0b11100>;
class INSV_ENC : INSV_FMT<0b001100>;
class EXTP_ENC : EXTR_W_TY1_FMT<0b00010>;
class EXTPV_ENC : EXTR_W_TY1_FMT<0b00011>;
class EXTPDP_ENC : EXTR_W_TY1_FMT<0b01010>;
class EXTPDPV_ENC : EXTR_W_TY1_FMT<0b01011>;
class EXTR_W_ENC : EXTR_W_TY1_FMT<0b00000>;
class EXTRV_W_ENC : EXTR_W_TY1_FMT<0b00001>;
class EXTR_R_W_ENC : EXTR_W_TY1_FMT<0b00100>;
class EXTRV_R_W_ENC : EXTR_W_TY1_FMT<0b00101>;
class EXTR_RS_W_ENC : EXTR_W_TY1_FMT<0b00110>;
class EXTRV_RS_W_ENC : EXTR_W_TY1_FMT<0b00111>;
class EXTR_S_H_ENC : EXTR_W_TY1_FMT<0b01110>;
class EXTRV_S_H_ENC : EXTR_W_TY1_FMT<0b01111>;
class SHILO_ENC : SHILO_R1_FMT<0b11010>;
class SHILOV_ENC : SHILO_R2_FMT<0b11011>;
class MTHLIP_ENC : SHILO_R2_FMT<0b11111>;
class RDDSP_ENC : RDDSP_FMT<0b10010>;
class WRDSP_ENC : WRDSP_FMT<0b10011>;
class ADDU_PH_ENC : ADDU_QB_FMT<0b01000>;
class ADDU_S_PH_ENC : ADDU_QB_FMT<0b01100>;
class SUBU_PH_ENC : ADDU_QB_FMT<0b01001>;
class SUBU_S_PH_ENC : ADDU_QB_FMT<0b01101>;
class CMPGDU_EQ_QB_ENC : CMP_EQ_QB_R3_FMT<0b11000>;
class CMPGDU_LT_QB_ENC : CMP_EQ_QB_R3_FMT<0b11001>;
class CMPGDU_LE_QB_ENC : CMP_EQ_QB_R3_FMT<0b11010>;
class ABSQ_S_QB_ENC : ABSQ_S_PH_R2_FMT<0b00001>;
class ADDUH_QB_ENC : ADDUH_QB_FMT<0b00000>;
class ADDUH_R_QB_ENC : ADDUH_QB_FMT<0b00010>;
class SUBUH_QB_ENC : ADDUH_QB_FMT<0b00001>;
class SUBUH_R_QB_ENC : ADDUH_QB_FMT<0b00011>;
class ADDQH_PH_ENC : ADDUH_QB_FMT<0b01000>;
class ADDQH_R_PH_ENC : ADDUH_QB_FMT<0b01010>;
class SUBQH_PH_ENC : ADDUH_QB_FMT<0b01001>;
class SUBQH_R_PH_ENC : ADDUH_QB_FMT<0b01011>;
class ADDQH_W_ENC : ADDUH_QB_FMT<0b10000>;
class ADDQH_R_W_ENC : ADDUH_QB_FMT<0b10010>;
class SUBQH_W_ENC : ADDUH_QB_FMT<0b10001>;
class SUBQH_R_W_ENC : ADDUH_QB_FMT<0b10011>;
class MUL_PH_ENC : ADDUH_QB_FMT<0b01100>;
class MUL_S_PH_ENC : ADDUH_QB_FMT<0b01110>;
class MULQ_S_W_ENC : ADDUH_QB_FMT<0b10110>;
class MULQ_RS_W_ENC : ADDUH_QB_FMT<0b10111>;
class MULQ_S_PH_ENC : ADDU_QB_FMT<0b11110>;
class DPA_W_PH_ENC : DPA_W_PH_FMT<0b00000>;
class DPS_W_PH_ENC : DPA_W_PH_FMT<0b00001>;
class DPAQX_S_W_PH_ENC : DPA_W_PH_FMT<0b11000>;
class DPAQX_SA_W_PH_ENC : DPA_W_PH_FMT<0b11010>;
class DPAX_W_PH_ENC : DPA_W_PH_FMT<0b01000>;
class DPSX_W_PH_ENC : DPA_W_PH_FMT<0b01001>;
class DPSQX_S_W_PH_ENC : DPA_W_PH_FMT<0b11001>;
class DPSQX_SA_W_PH_ENC : DPA_W_PH_FMT<0b11011>;
class MULSA_W_PH_ENC : DPA_W_PH_FMT<0b00010>;
class PRECR_QB_PH_ENC : CMP_EQ_QB_R3_FMT<0b01101>;
class PRECR_SRA_PH_W_ENC : PRECR_SRA_PH_W_FMT<0b11110>;
class PRECR_SRA_R_PH_W_ENC : PRECR_SRA_PH_W_FMT<0b11111>;
class SHRA_QB_ENC : SHLL_QB_FMT<0b00100>;
class SHRAV_QB_ENC : SHLL_QB_FMT<0b00110>;
class SHRA_R_QB_ENC : SHLL_QB_FMT<0b00101>;
class SHRAV_R_QB_ENC : SHLL_QB_FMT<0b00111>;
class SHRL_PH_ENC : SHLL_QB_FMT<0b11001>;
class SHRLV_PH_ENC : SHLL_QB_FMT<0b11011>;
class APPEND_ENC : APPEND_FMT<0b00000>;
class BALIGN_ENC : APPEND_FMT<0b10000>;
class PREPEND_ENC : APPEND_FMT<0b00001>;
// Instruction desc.
class ADDU_QB_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin, RegisterOperand ROD,
RegisterOperand ROS, RegisterOperand ROT = ROS> {
dag OutOperandList = (outs ROD:$rd);
dag InOperandList = (ins ROS:$rs, ROT:$rt);
string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt");
list<dag> Pattern = [(set ROD:$rd, (OpNode ROS:$rs, ROT:$rt))];
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
}
class RADDU_W_QB_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin, RegisterOperand ROD,
RegisterOperand ROS = ROD> {
dag OutOperandList = (outs ROD:$rd);
dag InOperandList = (ins ROS:$rs);
string AsmString = !strconcat(instr_asm, "\t$rd, $rs");
list<dag> Pattern = [(set ROD:$rd, (OpNode ROS:$rs))];
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
}
class CMP_EQ_QB_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin, RegisterOperand ROS,
RegisterOperand ROT = ROS> {
dag OutOperandList = (outs);
dag InOperandList = (ins ROS:$rs, ROT:$rt);
string AsmString = !strconcat(instr_asm, "\t$rs, $rt");
list<dag> Pattern = [(OpNode ROS:$rs, ROT:$rt)];
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
}
class CMP_EQ_QB_R3_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin, RegisterOperand ROD,
RegisterOperand ROS, RegisterOperand ROT = ROS> {
dag OutOperandList = (outs ROD:$rd);
dag InOperandList = (ins ROS:$rs, ROT:$rt);
string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt");
list<dag> Pattern = [(set ROD:$rd, (OpNode ROS:$rs, ROT:$rt))];
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
}
class PRECR_SRA_PH_W_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin, RegisterOperand ROT,
RegisterOperand ROS = ROT> {
dag OutOperandList = (outs ROT:$rt);
dag InOperandList = (ins ROS:$rs, uimm5:$sa, ROS:$src);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $sa");
list<dag> Pattern = [(set ROT:$rt, (OpNode ROS:$src, ROS:$rs, immZExt5:$sa))];
InstrItinClass Itinerary = itin;
string Constraints = "$src = $rt";
string BaseOpcode = instr_asm;
}
class ABSQ_S_PH_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin, RegisterOperand ROD,
RegisterOperand ROT = ROD> {
dag OutOperandList = (outs ROD:$rd);
dag InOperandList = (ins ROT:$rt);
string AsmString = !strconcat(instr_asm, "\t$rd, $rt");
list<dag> Pattern = [(set ROD:$rd, (OpNode ROT:$rt))];
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
}
class REPL_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
Operand ImmOp, ImmLeaf immPat, InstrItinClass itin,
RegisterOperand RO> {
dag OutOperandList = (outs RO:$rd);
dag InOperandList = (ins ImmOp:$imm);
string AsmString = !strconcat(instr_asm, "\t$rd, $imm");
list<dag> Pattern = [(set RO:$rd, (OpNode immPat:$imm))];
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
}
class SHLL_QB_R3_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin, RegisterOperand RO> {
dag OutOperandList = (outs RO:$rd);
dag InOperandList = (ins RO:$rt, GPR32Opnd:$rs_sa);
string AsmString = !strconcat(instr_asm, "\t$rd, $rt, $rs_sa");
list<dag> Pattern = [(set RO:$rd, (OpNode RO:$rt, GPR32Opnd:$rs_sa))];
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
}
class SHLL_QB_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
SDPatternOperator ImmPat, InstrItinClass itin,
RegisterOperand RO, Operand ImmOpnd> {
dag OutOperandList = (outs RO:$rd);
dag InOperandList = (ins RO:$rt, ImmOpnd:$rs_sa);
string AsmString = !strconcat(instr_asm, "\t$rd, $rt, $rs_sa");
list<dag> Pattern = [(set RO:$rd, (OpNode RO:$rt, ImmPat:$rs_sa))];
InstrItinClass Itinerary = itin;
bit hasSideEffects = 1;
string BaseOpcode = instr_asm;
}
class LX_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin> {
dag OutOperandList = (outs GPR32Opnd:$rd);
dag InOperandList = (ins PtrRC:$base, PtrRC:$index);
string AsmString = !strconcat(instr_asm, "\t$rd, ${index}(${base})");
list<dag> Pattern = [(set GPR32Opnd:$rd, (OpNode iPTR:$base, iPTR:$index))];
InstrItinClass Itinerary = itin;
bit mayLoad = 1;
string BaseOpcode = instr_asm;
}
class ADDUH_QB_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin, RegisterOperand ROD,
RegisterOperand ROS = ROD, RegisterOperand ROT = ROD> {
dag OutOperandList = (outs ROD:$rd);
dag InOperandList = (ins ROS:$rs, ROT:$rt);
string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt");
list<dag> Pattern = [(set ROD:$rd, (OpNode ROS:$rs, ROT:$rt))];
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
}
class APPEND_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
Operand ImmOp, SDPatternOperator Imm, InstrItinClass itin> {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins GPR32Opnd:$rs, ImmOp:$sa, GPR32Opnd:$src);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $sa");
list<dag> Pattern = [(set GPR32Opnd:$rt,
(OpNode GPR32Opnd:$src, GPR32Opnd:$rs, Imm:$sa))];
InstrItinClass Itinerary = itin;
string Constraints = "$src = $rt";
string BaseOpcode = instr_asm;
}
class EXTR_W_TY1_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin> {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins ACC64DSPOpnd:$ac, GPR32Opnd:$shift_rs);
string AsmString = !strconcat(instr_asm, "\t$rt, $ac, $shift_rs");
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
}
class EXTR_W_TY1_R1_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin> {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins ACC64DSPOpnd:$ac, uimm5:$shift_rs);
string AsmString = !strconcat(instr_asm, "\t$rt, $ac, $shift_rs");
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
}
class SHILO_R1_DESC_BASE<string instr_asm, SDPatternOperator OpNode> {
dag OutOperandList = (outs ACC64DSPOpnd:$ac);
dag InOperandList = (ins simm6:$shift, ACC64DSPOpnd:$acin);
string AsmString = !strconcat(instr_asm, "\t$ac, $shift");
list<dag> Pattern = [(set ACC64DSPOpnd:$ac,
(OpNode immSExt6:$shift, ACC64DSPOpnd:$acin))];
string Constraints = "$acin = $ac";
string BaseOpcode = instr_asm;
}
class SHILO_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode> {
dag OutOperandList = (outs ACC64DSPOpnd:$ac);
dag InOperandList = (ins GPR32Opnd:$rs, ACC64DSPOpnd:$acin);
string AsmString = !strconcat(instr_asm, "\t$ac, $rs");
list<dag> Pattern = [(set ACC64DSPOpnd:$ac,
(OpNode GPR32Opnd:$rs, ACC64DSPOpnd:$acin))];
string Constraints = "$acin = $ac";
string BaseOpcode = instr_asm;
}
class MTHLIP_DESC_BASE<string instr_asm, SDPatternOperator OpNode> {
dag OutOperandList = (outs ACC64DSPOpnd:$ac);
dag InOperandList = (ins GPR32Opnd:$rs, ACC64DSPOpnd:$acin);
string AsmString = !strconcat(instr_asm, "\t$rs, $ac");
list<dag> Pattern = [(set ACC64DSPOpnd:$ac,
(OpNode GPR32Opnd:$rs, ACC64DSPOpnd:$acin))];
string Constraints = "$acin = $ac";
string BaseOpcode = instr_asm;
}
class RDDSP_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin> {
dag OutOperandList = (outs GPR32Opnd:$rd);
dag InOperandList = (ins uimm10:$mask);
string AsmString = !strconcat(instr_asm, "\t$rd, $mask");
list<dag> Pattern = [(set GPR32Opnd:$rd, (OpNode immZExt10:$mask))];
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
bit isMoveReg = 1;
}
class WRDSP_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin> {
dag OutOperandList = (outs);
dag InOperandList = (ins GPR32Opnd:$rs, uimm10:$mask);
string AsmString = !strconcat(instr_asm, "\t$rs, $mask");
list<dag> Pattern = [(OpNode GPR32Opnd:$rs, immZExt10:$mask)];
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
bit isMoveReg = 1;
}
class DPA_W_PH_DESC_BASE<string instr_asm, SDPatternOperator OpNode> {
dag OutOperandList = (outs ACC64DSPOpnd:$ac);
dag InOperandList = (ins GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64DSPOpnd:$acin);
string AsmString = !strconcat(instr_asm, "\t$ac, $rs, $rt");
list<dag> Pattern = [(set ACC64DSPOpnd:$ac,
(OpNode GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64DSPOpnd:$acin))];
string Constraints = "$acin = $ac";
string BaseOpcode = instr_asm;
}
class MULT_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin> {
dag OutOperandList = (outs ACC64DSPOpnd:$ac);
dag InOperandList = (ins GPR32Opnd:$rs, GPR32Opnd:$rt);
string AsmString = !strconcat(instr_asm, "\t$ac, $rs, $rt");
list<dag> Pattern = [(set ACC64DSPOpnd:$ac, (OpNode GPR32Opnd:$rs, GPR32Opnd:$rt))];
InstrItinClass Itinerary = itin;
bit isCommutable = 1;
string BaseOpcode = instr_asm;
}
class MADD_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin> {
dag OutOperandList = (outs ACC64DSPOpnd:$ac);
dag InOperandList = (ins GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64DSPOpnd:$acin);
string AsmString = !strconcat(instr_asm, "\t$ac, $rs, $rt");
list<dag> Pattern = [(set ACC64DSPOpnd:$ac,
(OpNode GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64DSPOpnd:$acin))];
InstrItinClass Itinerary = itin;
string Constraints = "$acin = $ac";
string BaseOpcode = instr_asm;
}
class MFHI_DESC_BASE<string instr_asm, RegisterOperand RO, SDNode OpNode,
InstrItinClass itin> {
dag OutOperandList = (outs GPR32Opnd:$rd);
dag InOperandList = (ins RO:$ac);
string AsmString = !strconcat(instr_asm, "\t$rd, $ac");
list<dag> Pattern = [(set GPR32Opnd:$rd, (OpNode RO:$ac))];
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
bit isMoveReg = 1;
}
class MTHI_DESC_BASE<string instr_asm, RegisterOperand RO, InstrItinClass itin> {
dag OutOperandList = (outs RO:$ac);
dag InOperandList = (ins GPR32Opnd:$rs);
string AsmString = !strconcat(instr_asm, "\t$rs, $ac");
InstrItinClass Itinerary = itin;
string BaseOpcode = instr_asm;
bit isMoveReg = 1;
}
class BPOSGE32_PSEUDO_DESC_BASE<SDPatternOperator OpNode, InstrItinClass itin> :
MipsPseudo<(outs GPR32Opnd:$dst), (ins), [(set GPR32Opnd:$dst, (OpNode))]> {
bit usesCustomInserter = 1;
}
class BPOSGE32_DESC_BASE<string instr_asm, DAGOperand opnd,
InstrItinClass itin> {
dag OutOperandList = (outs);
dag InOperandList = (ins opnd:$offset);
string AsmString = !strconcat(instr_asm, "\t$offset");
InstrItinClass Itinerary = itin;
bit isBranch = 1;
bit isTerminator = 1;
bit hasDelaySlot = 1;
string BaseOpcode = instr_asm;
}
class INSV_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
InstrItinClass itin> {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins GPR32Opnd:$src, GPR32Opnd:$rs);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs");
list<dag> Pattern = [(set GPR32Opnd:$rt, (OpNode GPR32Opnd:$src, GPR32Opnd:$rs))];
InstrItinClass Itinerary = itin;
string Constraints = "$src = $rt";
string BaseOpcode = instr_asm;
}
//===----------------------------------------------------------------------===//
// MIPS DSP Rev 1
//===----------------------------------------------------------------------===//
// Addition/subtraction
class ADDU_QB_DESC : ADDU_QB_DESC_BASE<"addu.qb", null_frag, NoItinerary,
DSPROpnd, DSPROpnd>, IsCommutable,
Defs<[DSPOutFlag20]>;
class ADDU_S_QB_DESC : ADDU_QB_DESC_BASE<"addu_s.qb", int_mips_addu_s_qb,
NoItinerary, DSPROpnd, DSPROpnd>,
IsCommutable, Defs<[DSPOutFlag20]>;
class SUBU_QB_DESC : ADDU_QB_DESC_BASE<"subu.qb", null_frag, NoItinerary,
DSPROpnd, DSPROpnd>,
Defs<[DSPOutFlag20]>;
class SUBU_S_QB_DESC : ADDU_QB_DESC_BASE<"subu_s.qb", int_mips_subu_s_qb,
NoItinerary, DSPROpnd, DSPROpnd>,
Defs<[DSPOutFlag20]>;
class ADDQ_PH_DESC : ADDU_QB_DESC_BASE<"addq.ph", null_frag, NoItinerary,
DSPROpnd, DSPROpnd>, IsCommutable,
Defs<[DSPOutFlag20]>;
class ADDQ_S_PH_DESC : ADDU_QB_DESC_BASE<"addq_s.ph", int_mips_addq_s_ph,
NoItinerary, DSPROpnd, DSPROpnd>,
IsCommutable, Defs<[DSPOutFlag20]>;
class SUBQ_PH_DESC : ADDU_QB_DESC_BASE<"subq.ph", null_frag, NoItinerary,
DSPROpnd, DSPROpnd>,
Defs<[DSPOutFlag20]>;
class SUBQ_S_PH_DESC : ADDU_QB_DESC_BASE<"subq_s.ph", int_mips_subq_s_ph,
NoItinerary, DSPROpnd, DSPROpnd>,
Defs<[DSPOutFlag20]>;
class ADDQ_S_W_DESC : ADDU_QB_DESC_BASE<"addq_s.w", int_mips_addq_s_w,
NoItinerary, GPR32Opnd, GPR32Opnd>,
IsCommutable, Defs<[DSPOutFlag20]>;
class SUBQ_S_W_DESC : ADDU_QB_DESC_BASE<"subq_s.w", int_mips_subq_s_w,
NoItinerary, GPR32Opnd, GPR32Opnd>,
Defs<[DSPOutFlag20]>;
class ADDSC_DESC : ADDU_QB_DESC_BASE<"addsc", null_frag, NoItinerary,
GPR32Opnd, GPR32Opnd>, IsCommutable,
Defs<[DSPCarry]>;
class ADDWC_DESC : ADDU_QB_DESC_BASE<"addwc", null_frag, NoItinerary,
GPR32Opnd, GPR32Opnd>,
IsCommutable, Uses<[DSPCarry]>, Defs<[DSPOutFlag20]>;
class MODSUB_DESC : ADDU_QB_DESC_BASE<"modsub", int_mips_modsub, NoItinerary,
GPR32Opnd, GPR32Opnd>;
class RADDU_W_QB_DESC : RADDU_W_QB_DESC_BASE<"raddu.w.qb", int_mips_raddu_w_qb,
NoItinerary, GPR32Opnd, DSPROpnd>;
// Absolute value
class ABSQ_S_PH_DESC : ABSQ_S_PH_R2_DESC_BASE<"absq_s.ph", int_mips_absq_s_ph,
NoItinerary, DSPROpnd>,
Defs<[DSPOutFlag20]>;
class ABSQ_S_W_DESC : ABSQ_S_PH_R2_DESC_BASE<"absq_s.w", int_mips_absq_s_w,
NoItinerary, GPR32Opnd>,
Defs<[DSPOutFlag20]>;
// Precision reduce/expand
class PRECRQ_QB_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"precrq.qb.ph",
int_mips_precrq_qb_ph,
NoItinerary, DSPROpnd, DSPROpnd>;
class PRECRQ_PH_W_DESC : CMP_EQ_QB_R3_DESC_BASE<"precrq.ph.w",
int_mips_precrq_ph_w,
NoItinerary, DSPROpnd, GPR32Opnd>;
class PRECRQ_RS_PH_W_DESC : CMP_EQ_QB_R3_DESC_BASE<"precrq_rs.ph.w",
int_mips_precrq_rs_ph_w,
NoItinerary, DSPROpnd,
GPR32Opnd>,
Defs<[DSPOutFlag22]>;
class PRECRQU_S_QB_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"precrqu_s.qb.ph",
int_mips_precrqu_s_qb_ph,
NoItinerary, DSPROpnd,
DSPROpnd>,
Defs<[DSPOutFlag22]>;
class PRECEQ_W_PHL_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceq.w.phl",
int_mips_preceq_w_phl,
NoItinerary, GPR32Opnd, DSPROpnd>;
class PRECEQ_W_PHR_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceq.w.phr",
int_mips_preceq_w_phr,
NoItinerary, GPR32Opnd, DSPROpnd>;
class PRECEQU_PH_QBL_DESC : ABSQ_S_PH_R2_DESC_BASE<"precequ.ph.qbl",
int_mips_precequ_ph_qbl,
NoItinerary, DSPROpnd>;
class PRECEQU_PH_QBR_DESC : ABSQ_S_PH_R2_DESC_BASE<"precequ.ph.qbr",
int_mips_precequ_ph_qbr,
NoItinerary, DSPROpnd>;
class PRECEQU_PH_QBLA_DESC : ABSQ_S_PH_R2_DESC_BASE<"precequ.ph.qbla",
int_mips_precequ_ph_qbla,
NoItinerary, DSPROpnd>;
class PRECEQU_PH_QBRA_DESC : ABSQ_S_PH_R2_DESC_BASE<"precequ.ph.qbra",
int_mips_precequ_ph_qbra,
NoItinerary, DSPROpnd>;
class PRECEU_PH_QBL_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceu.ph.qbl",
int_mips_preceu_ph_qbl,
NoItinerary, DSPROpnd>;
class PRECEU_PH_QBR_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceu.ph.qbr",
int_mips_preceu_ph_qbr,
NoItinerary, DSPROpnd>;
class PRECEU_PH_QBLA_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceu.ph.qbla",
int_mips_preceu_ph_qbla,
NoItinerary, DSPROpnd>;
class PRECEU_PH_QBRA_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceu.ph.qbra",
int_mips_preceu_ph_qbra,
NoItinerary, DSPROpnd>;
// Shift
class SHLL_QB_DESC : SHLL_QB_R2_DESC_BASE<"shll.qb", null_frag, immZExt3,
NoItinerary, DSPROpnd, uimm3>,
Defs<[DSPOutFlag22]>;
class SHLLV_QB_DESC : SHLL_QB_R3_DESC_BASE<"shllv.qb", int_mips_shll_qb,
NoItinerary, DSPROpnd>,
Defs<[DSPOutFlag22]>;
class SHRL_QB_DESC : SHLL_QB_R2_DESC_BASE<"shrl.qb", null_frag, immZExt3,
NoItinerary, DSPROpnd, uimm3>;
class SHRLV_QB_DESC : SHLL_QB_R3_DESC_BASE<"shrlv.qb", int_mips_shrl_qb,
NoItinerary, DSPROpnd>;
class SHLL_PH_DESC : SHLL_QB_R2_DESC_BASE<"shll.ph", null_frag, immZExt4,
NoItinerary, DSPROpnd, uimm4>,
Defs<[DSPOutFlag22]>;
class SHLLV_PH_DESC : SHLL_QB_R3_DESC_BASE<"shllv.ph", int_mips_shll_ph,
NoItinerary, DSPROpnd>,
Defs<[DSPOutFlag22]>;
class SHLL_S_PH_DESC : SHLL_QB_R2_DESC_BASE<"shll_s.ph", int_mips_shll_s_ph,
immZExt4, NoItinerary, DSPROpnd,
uimm4>,
Defs<[DSPOutFlag22]>;
class SHLLV_S_PH_DESC : SHLL_QB_R3_DESC_BASE<"shllv_s.ph", int_mips_shll_s_ph,
NoItinerary, DSPROpnd>,
Defs<[DSPOutFlag22]>;
class SHRA_PH_DESC : SHLL_QB_R2_DESC_BASE<"shra.ph", null_frag, immZExt4,
NoItinerary, DSPROpnd, uimm4>;
class SHRAV_PH_DESC : SHLL_QB_R3_DESC_BASE<"shrav.ph", int_mips_shra_ph,
NoItinerary, DSPROpnd>;
class SHRA_R_PH_DESC : SHLL_QB_R2_DESC_BASE<"shra_r.ph", int_mips_shra_r_ph,
immZExt4, NoItinerary, DSPROpnd,
uimm4>;
class SHRAV_R_PH_DESC : SHLL_QB_R3_DESC_BASE<"shrav_r.ph", int_mips_shra_r_ph,
NoItinerary, DSPROpnd>;
class SHLL_S_W_DESC : SHLL_QB_R2_DESC_BASE<"shll_s.w", int_mips_shll_s_w,
immZExt5, NoItinerary, GPR32Opnd,
uimm5>,
Defs<[DSPOutFlag22]>;
class SHLLV_S_W_DESC : SHLL_QB_R3_DESC_BASE<"shllv_s.w", int_mips_shll_s_w,
NoItinerary, GPR32Opnd>,
Defs<[DSPOutFlag22]>;
class SHRA_R_W_DESC : SHLL_QB_R2_DESC_BASE<"shra_r.w", int_mips_shra_r_w,
immZExt5, NoItinerary, GPR32Opnd,
uimm5>;
class SHRAV_R_W_DESC : SHLL_QB_R3_DESC_BASE<"shrav_r.w", int_mips_shra_r_w,
NoItinerary, GPR32Opnd>;
// Multiplication
class MULEU_S_PH_QBL_DESC : ADDU_QB_DESC_BASE<"muleu_s.ph.qbl",
int_mips_muleu_s_ph_qbl,
NoItinerary, DSPROpnd, DSPROpnd>,
Defs<[DSPOutFlag21]>;
class MULEU_S_PH_QBR_DESC : ADDU_QB_DESC_BASE<"muleu_s.ph.qbr",
int_mips_muleu_s_ph_qbr,
NoItinerary, DSPROpnd, DSPROpnd>,
Defs<[DSPOutFlag21]>;
class MULEQ_S_W_PHL_DESC : ADDU_QB_DESC_BASE<"muleq_s.w.phl",
int_mips_muleq_s_w_phl,
NoItinerary, GPR32Opnd, DSPROpnd>,
IsCommutable, Defs<[DSPOutFlag21]>;
class MULEQ_S_W_PHR_DESC : ADDU_QB_DESC_BASE<"muleq_s.w.phr",
int_mips_muleq_s_w_phr,
NoItinerary, GPR32Opnd, DSPROpnd>,
IsCommutable, Defs<[DSPOutFlag21]>;
class MULQ_RS_PH_DESC : ADDU_QB_DESC_BASE<"mulq_rs.ph", int_mips_mulq_rs_ph,
NoItinerary, DSPROpnd, DSPROpnd>,
IsCommutable, Defs<[DSPOutFlag21]>;
class MULSAQ_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"mulsaq_s.w.ph",
MipsMULSAQ_S_W_PH>,
Defs<[DSPOutFlag16_19]>;
class MAQ_S_W_PHL_DESC : DPA_W_PH_DESC_BASE<"maq_s.w.phl", MipsMAQ_S_W_PHL>,
Defs<[DSPOutFlag16_19]>;
class MAQ_S_W_PHR_DESC : DPA_W_PH_DESC_BASE<"maq_s.w.phr", MipsMAQ_S_W_PHR>,
Defs<[DSPOutFlag16_19]>;
class MAQ_SA_W_PHL_DESC : DPA_W_PH_DESC_BASE<"maq_sa.w.phl", MipsMAQ_SA_W_PHL>,
Defs<[DSPOutFlag16_19]>;
class MAQ_SA_W_PHR_DESC : DPA_W_PH_DESC_BASE<"maq_sa.w.phr", MipsMAQ_SA_W_PHR>,
Defs<[DSPOutFlag16_19]>;
// Move from/to hi/lo.
class MFHI_DESC : MFHI_DESC_BASE<"mfhi", ACC64DSPOpnd, MipsMFHI, NoItinerary>;
class MFLO_DESC : MFHI_DESC_BASE<"mflo", ACC64DSPOpnd, MipsMFLO, NoItinerary>;
class MTHI_DESC : MTHI_DESC_BASE<"mthi", HI32DSPOpnd, NoItinerary>;
class MTLO_DESC : MTHI_DESC_BASE<"mtlo", LO32DSPOpnd, NoItinerary>;
// Dot product with accumulate/subtract
class DPAU_H_QBL_DESC : DPA_W_PH_DESC_BASE<"dpau.h.qbl", MipsDPAU_H_QBL>;
class DPAU_H_QBR_DESC : DPA_W_PH_DESC_BASE<"dpau.h.qbr", MipsDPAU_H_QBR>;
class DPSU_H_QBL_DESC : DPA_W_PH_DESC_BASE<"dpsu.h.qbl", MipsDPSU_H_QBL>;
class DPSU_H_QBR_DESC : DPA_W_PH_DESC_BASE<"dpsu.h.qbr", MipsDPSU_H_QBR>;
class DPAQ_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpaq_s.w.ph", MipsDPAQ_S_W_PH>,
Defs<[DSPOutFlag16_19]>;
class DPSQ_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpsq_s.w.ph", MipsDPSQ_S_W_PH>,
Defs<[DSPOutFlag16_19]>;
class DPAQ_SA_L_W_DESC : DPA_W_PH_DESC_BASE<"dpaq_sa.l.w", MipsDPAQ_SA_L_W>,
Defs<[DSPOutFlag16_19]>;
class DPSQ_SA_L_W_DESC : DPA_W_PH_DESC_BASE<"dpsq_sa.l.w", MipsDPSQ_SA_L_W>,
Defs<[DSPOutFlag16_19]>;
class MULT_DSP_DESC : MULT_DESC_BASE<"mult", MipsMult, NoItinerary>;
class MULTU_DSP_DESC : MULT_DESC_BASE<"multu", MipsMultu, NoItinerary>;
class MADD_DSP_DESC : MADD_DESC_BASE<"madd", MipsMAdd, NoItinerary>;
class MADDU_DSP_DESC : MADD_DESC_BASE<"maddu", MipsMAddu, NoItinerary>;
class MSUB_DSP_DESC : MADD_DESC_BASE<"msub", MipsMSub, NoItinerary>;
class MSUBU_DSP_DESC : MADD_DESC_BASE<"msubu", MipsMSubu, NoItinerary>;
// Comparison
class CMPU_EQ_QB_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmpu.eq.qb",
int_mips_cmpu_eq_qb, NoItinerary,
DSPROpnd>,
IsCommutable, Defs<[DSPCCond]>;
class CMPU_LT_QB_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmpu.lt.qb",
int_mips_cmpu_lt_qb, NoItinerary,
DSPROpnd>, Defs<[DSPCCond]>;
class CMPU_LE_QB_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmpu.le.qb",
int_mips_cmpu_le_qb, NoItinerary,
DSPROpnd>, Defs<[DSPCCond]>;
class CMPGU_EQ_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgu.eq.qb",
int_mips_cmpgu_eq_qb,
NoItinerary, GPR32Opnd, DSPROpnd>,
IsCommutable;
class CMPGU_LT_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgu.lt.qb",
int_mips_cmpgu_lt_qb,
NoItinerary, GPR32Opnd, DSPROpnd>;
class CMPGU_LE_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgu.le.qb",
int_mips_cmpgu_le_qb,
NoItinerary, GPR32Opnd, DSPROpnd>;
class CMP_EQ_PH_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmp.eq.ph", int_mips_cmp_eq_ph,
NoItinerary, DSPROpnd>,
IsCommutable, Defs<[DSPCCond]>;
class CMP_LT_PH_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmp.lt.ph", int_mips_cmp_lt_ph,
NoItinerary, DSPROpnd>,
Defs<[DSPCCond]>;
class CMP_LE_PH_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmp.le.ph", int_mips_cmp_le_ph,
NoItinerary, DSPROpnd>,
Defs<[DSPCCond]>;
// Misc
class BITREV_DESC : ABSQ_S_PH_R2_DESC_BASE<"bitrev", int_mips_bitrev,
NoItinerary, GPR32Opnd>;
class PACKRL_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"packrl.ph", int_mips_packrl_ph,
NoItinerary, DSPROpnd, DSPROpnd>;
class REPL_QB_DESC : REPL_DESC_BASE<"repl.qb", int_mips_repl_qb, uimm8,
immZExt8, NoItinerary, DSPROpnd>;
class REPL_PH_DESC : REPL_DESC_BASE<"repl.ph", int_mips_repl_ph, simm10,
immSExt10, NoItinerary, DSPROpnd>;
class REPLV_QB_DESC : ABSQ_S_PH_R2_DESC_BASE<"replv.qb", int_mips_repl_qb,
NoItinerary, DSPROpnd, GPR32Opnd>;
class REPLV_PH_DESC : ABSQ_S_PH_R2_DESC_BASE<"replv.ph", int_mips_repl_ph,
NoItinerary, DSPROpnd, GPR32Opnd>;
class PICK_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"pick.qb", int_mips_pick_qb,
NoItinerary, DSPROpnd, DSPROpnd>,
Uses<[DSPCCond]>;
class PICK_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"pick.ph", int_mips_pick_ph,
NoItinerary, DSPROpnd, DSPROpnd>,
Uses<[DSPCCond]>;
class LWX_DESC : LX_DESC_BASE<"lwx", int_mips_lwx, NoItinerary>;
class LHX_DESC : LX_DESC_BASE<"lhx", int_mips_lhx, NoItinerary>;
class LBUX_DESC : LX_DESC_BASE<"lbux", int_mips_lbux, NoItinerary>;
class BPOSGE32_DESC : BPOSGE32_DESC_BASE<"bposge32", brtarget, NoItinerary>;
// Extr
class EXTP_DESC : EXTR_W_TY1_R1_DESC_BASE<"extp", MipsEXTP, NoItinerary>,
Uses<[DSPPos]>, Defs<[DSPEFI]>;
class EXTPV_DESC : EXTR_W_TY1_R2_DESC_BASE<"extpv", MipsEXTP, NoItinerary>,
Uses<[DSPPos]>, Defs<[DSPEFI]>;
class EXTPDP_DESC : EXTR_W_TY1_R1_DESC_BASE<"extpdp", MipsEXTPDP, NoItinerary>,
Uses<[DSPPos]>, Defs<[DSPPos, DSPEFI]>;
class EXTPDPV_DESC : EXTR_W_TY1_R2_DESC_BASE<"extpdpv", MipsEXTPDP,
NoItinerary>,
Uses<[DSPPos]>, Defs<[DSPPos, DSPEFI]>;
class EXTR_W_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr.w", MipsEXTR_W, NoItinerary>,
Defs<[DSPOutFlag23]>;
class EXTRV_W_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv.w", MipsEXTR_W,
NoItinerary>, Defs<[DSPOutFlag23]>;
class EXTR_R_W_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr_r.w", MipsEXTR_R_W,
NoItinerary>,
Defs<[DSPOutFlag23]>;
class EXTRV_R_W_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv_r.w", MipsEXTR_R_W,
NoItinerary>,
Defs<[DSPOutFlag23]>;
class EXTR_RS_W_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr_rs.w", MipsEXTR_RS_W,
NoItinerary>,
Defs<[DSPOutFlag23]>;
class EXTRV_RS_W_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv_rs.w", MipsEXTR_RS_W,
NoItinerary>,
Defs<[DSPOutFlag23]>;
class EXTR_S_H_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr_s.h", MipsEXTR_S_H,
NoItinerary>,
Defs<[DSPOutFlag23]>;
class EXTRV_S_H_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv_s.h", MipsEXTR_S_H,
NoItinerary>,
Defs<[DSPOutFlag23]>;
class SHILO_DESC : SHILO_R1_DESC_BASE<"shilo", MipsSHILO>;
class SHILOV_DESC : SHILO_R2_DESC_BASE<"shilov", MipsSHILO>;
class MTHLIP_DESC : MTHLIP_DESC_BASE<"mthlip", MipsMTHLIP>, Defs<[DSPPos]>;
class RDDSP_DESC : RDDSP_DESC_BASE<"rddsp", int_mips_rddsp, NoItinerary>;
class WRDSP_DESC : WRDSP_DESC_BASE<"wrdsp", int_mips_wrdsp, NoItinerary>;
class INSV_DESC : INSV_DESC_BASE<"insv", int_mips_insv, NoItinerary>,
Uses<[DSPPos, DSPSCount]>;
//===----------------------------------------------------------------------===//
// MIPS DSP Rev 2
// Addition/subtraction
class ADDU_PH_DESC : ADDU_QB_DESC_BASE<"addu.ph", int_mips_addu_ph, NoItinerary,
DSPROpnd, DSPROpnd>, IsCommutable,
Defs<[DSPOutFlag20]>;
class ADDU_S_PH_DESC : ADDU_QB_DESC_BASE<"addu_s.ph", int_mips_addu_s_ph,
NoItinerary, DSPROpnd, DSPROpnd>,
IsCommutable, Defs<[DSPOutFlag20]>;
class SUBU_PH_DESC : ADDU_QB_DESC_BASE<"subu.ph", int_mips_subu_ph, NoItinerary,
DSPROpnd, DSPROpnd>,
Defs<[DSPOutFlag20]>;
class SUBU_S_PH_DESC : ADDU_QB_DESC_BASE<"subu_s.ph", int_mips_subu_s_ph,
NoItinerary, DSPROpnd, DSPROpnd>,
Defs<[DSPOutFlag20]>;
class ADDUH_QB_DESC : ADDUH_QB_DESC_BASE<"adduh.qb", int_mips_adduh_qb,
NoItinerary, DSPROpnd>, IsCommutable;
class ADDUH_R_QB_DESC : ADDUH_QB_DESC_BASE<"adduh_r.qb", int_mips_adduh_r_qb,
NoItinerary, DSPROpnd>, IsCommutable;
class SUBUH_QB_DESC : ADDUH_QB_DESC_BASE<"subuh.qb", int_mips_subuh_qb,
NoItinerary, DSPROpnd>;
class SUBUH_R_QB_DESC : ADDUH_QB_DESC_BASE<"subuh_r.qb", int_mips_subuh_r_qb,
NoItinerary, DSPROpnd>;
class ADDQH_PH_DESC : ADDUH_QB_DESC_BASE<"addqh.ph", int_mips_addqh_ph,
NoItinerary, DSPROpnd>, IsCommutable;
class ADDQH_R_PH_DESC : ADDUH_QB_DESC_BASE<"addqh_r.ph", int_mips_addqh_r_ph,
NoItinerary, DSPROpnd>, IsCommutable;
class SUBQH_PH_DESC : ADDUH_QB_DESC_BASE<"subqh.ph", int_mips_subqh_ph,
NoItinerary, DSPROpnd>;
class SUBQH_R_PH_DESC : ADDUH_QB_DESC_BASE<"subqh_r.ph", int_mips_subqh_r_ph,
NoItinerary, DSPROpnd>;
class ADDQH_W_DESC : ADDUH_QB_DESC_BASE<"addqh.w", int_mips_addqh_w,
NoItinerary, GPR32Opnd>, IsCommutable;
class ADDQH_R_W_DESC : ADDUH_QB_DESC_BASE<"addqh_r.w", int_mips_addqh_r_w,
NoItinerary, GPR32Opnd>, IsCommutable;
class SUBQH_W_DESC : ADDUH_QB_DESC_BASE<"subqh.w", int_mips_subqh_w,
NoItinerary, GPR32Opnd>;
class SUBQH_R_W_DESC : ADDUH_QB_DESC_BASE<"subqh_r.w", int_mips_subqh_r_w,
NoItinerary, GPR32Opnd>;
// Comparison
class CMPGDU_EQ_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgdu.eq.qb",
int_mips_cmpgdu_eq_qb,
NoItinerary, GPR32Opnd, DSPROpnd>,
IsCommutable, Defs<[DSPCCond]>;
class CMPGDU_LT_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgdu.lt.qb",
int_mips_cmpgdu_lt_qb,
NoItinerary, GPR32Opnd, DSPROpnd>,
Defs<[DSPCCond]>;
class CMPGDU_LE_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgdu.le.qb",
int_mips_cmpgdu_le_qb,
NoItinerary, GPR32Opnd, DSPROpnd>,
Defs<[DSPCCond]>;
// Absolute
class ABSQ_S_QB_DESC : ABSQ_S_PH_R2_DESC_BASE<"absq_s.qb", int_mips_absq_s_qb,
NoItinerary, DSPROpnd>,
Defs<[DSPOutFlag20]>;
// Multiplication
class MUL_PH_DESC : ADDUH_QB_DESC_BASE<"mul.ph", null_frag, NoItinerary,
DSPROpnd>, IsCommutable,
Defs<[DSPOutFlag21]>;
class MUL_S_PH_DESC : ADDUH_QB_DESC_BASE<"mul_s.ph", int_mips_mul_s_ph,
NoItinerary, DSPROpnd>, IsCommutable,
Defs<[DSPOutFlag21]>;
class MULQ_S_W_DESC : ADDUH_QB_DESC_BASE<"mulq_s.w", int_mips_mulq_s_w,
NoItinerary, GPR32Opnd>, IsCommutable,
Defs<[DSPOutFlag21]>;
class MULQ_RS_W_DESC : ADDUH_QB_DESC_BASE<"mulq_rs.w", int_mips_mulq_rs_w,
NoItinerary, GPR32Opnd>, IsCommutable,
Defs<[DSPOutFlag21]>;
class MULQ_S_PH_DESC : ADDU_QB_DESC_BASE<"mulq_s.ph", int_mips_mulq_s_ph,
NoItinerary, DSPROpnd, DSPROpnd>,
IsCommutable, Defs<[DSPOutFlag21]>;
// Dot product with accumulate/subtract
class DPA_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpa.w.ph", MipsDPA_W_PH>;
class DPS_W_PH_DESC : DPA_W_PH_DESC_BASE<"dps.w.ph", MipsDPS_W_PH>;
class DPAQX_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpaqx_s.w.ph", MipsDPAQX_S_W_PH>,
Defs<[DSPOutFlag16_19]>;
class DPAQX_SA_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpaqx_sa.w.ph",
MipsDPAQX_SA_W_PH>,
Defs<[DSPOutFlag16_19]>;
class DPAX_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpax.w.ph", MipsDPAX_W_PH>;
class DPSX_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpsx.w.ph", MipsDPSX_W_PH>;
class DPSQX_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpsqx_s.w.ph", MipsDPSQX_S_W_PH>,
Defs<[DSPOutFlag16_19]>;
class DPSQX_SA_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpsqx_sa.w.ph",
MipsDPSQX_SA_W_PH>,
Defs<[DSPOutFlag16_19]>;
class MULSA_W_PH_DESC : DPA_W_PH_DESC_BASE<"mulsa.w.ph", MipsMULSA_W_PH>;
// Precision reduce/expand
class PRECR_QB_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"precr.qb.ph",
int_mips_precr_qb_ph,
NoItinerary, DSPROpnd, DSPROpnd>;
class PRECR_SRA_PH_W_DESC : PRECR_SRA_PH_W_DESC_BASE<"precr_sra.ph.w",
int_mips_precr_sra_ph_w,
NoItinerary, DSPROpnd,
GPR32Opnd>;
class PRECR_SRA_R_PH_W_DESC : PRECR_SRA_PH_W_DESC_BASE<"precr_sra_r.ph.w",
int_mips_precr_sra_r_ph_w,
NoItinerary, DSPROpnd,
GPR32Opnd>;
// Shift
class SHRA_QB_DESC : SHLL_QB_R2_DESC_BASE<"shra.qb", null_frag, immZExt3,
NoItinerary, DSPROpnd, uimm3>;
class SHRAV_QB_DESC : SHLL_QB_R3_DESC_BASE<"shrav.qb", int_mips_shra_qb,
NoItinerary, DSPROpnd>;
class SHRA_R_QB_DESC : SHLL_QB_R2_DESC_BASE<"shra_r.qb", int_mips_shra_r_qb,
immZExt3, NoItinerary, DSPROpnd,
uimm3>;
class SHRAV_R_QB_DESC : SHLL_QB_R3_DESC_BASE<"shrav_r.qb", int_mips_shra_r_qb,
NoItinerary, DSPROpnd>;
class SHRL_PH_DESC : SHLL_QB_R2_DESC_BASE<"shrl.ph", null_frag, immZExt4,
NoItinerary, DSPROpnd, uimm4>;
class SHRLV_PH_DESC : SHLL_QB_R3_DESC_BASE<"shrlv.ph", int_mips_shrl_ph,
NoItinerary, DSPROpnd>;
// Misc
class APPEND_DESC : APPEND_DESC_BASE<"append", int_mips_append, uimm5, immZExt5,
NoItinerary>;
class BALIGN_DESC : APPEND_DESC_BASE<"balign", int_mips_balign, uimm2, immZExt2,
NoItinerary>;
class PREPEND_DESC : APPEND_DESC_BASE<"prepend", int_mips_prepend, uimm5,
immZExt5, NoItinerary>;
// Pseudos.
def BPOSGE32_PSEUDO : BPOSGE32_PSEUDO_DESC_BASE<int_mips_bposge32,
NoItinerary>, Uses<[DSPPos]>;
// Instruction defs.
// MIPS DSP Rev 1
def ADDU_QB : DspMMRel, ADDU_QB_ENC, ADDU_QB_DESC;
def ADDU_S_QB : DspMMRel, ADDU_S_QB_ENC, ADDU_S_QB_DESC;
def SUBU_QB : DspMMRel, SUBU_QB_ENC, SUBU_QB_DESC;
def SUBU_S_QB : DspMMRel, SUBU_S_QB_ENC, SUBU_S_QB_DESC;
def ADDQ_PH : DspMMRel, ADDQ_PH_ENC, ADDQ_PH_DESC;
def ADDQ_S_PH : DspMMRel, ADDQ_S_PH_ENC, ADDQ_S_PH_DESC;
def SUBQ_PH : DspMMRel, SUBQ_PH_ENC, SUBQ_PH_DESC;
def SUBQ_S_PH : DspMMRel, SUBQ_S_PH_ENC, SUBQ_S_PH_DESC;
def ADDQ_S_W : DspMMRel, ADDQ_S_W_ENC, ADDQ_S_W_DESC;
def SUBQ_S_W : DspMMRel, SUBQ_S_W_ENC, SUBQ_S_W_DESC;
def ADDSC : DspMMRel, ADDSC_ENC, ADDSC_DESC;
def ADDWC : DspMMRel, ADDWC_ENC, ADDWC_DESC;
def MODSUB : DspMMRel, MODSUB_ENC, MODSUB_DESC;
def RADDU_W_QB : DspMMRel, RADDU_W_QB_ENC, RADDU_W_QB_DESC;
def ABSQ_S_PH : DspMMRel, ABSQ_S_PH_ENC, ABSQ_S_PH_DESC;
def ABSQ_S_W : DspMMRel, ABSQ_S_W_ENC, ABSQ_S_W_DESC;
def PRECRQ_QB_PH : DspMMRel, PRECRQ_QB_PH_ENC, PRECRQ_QB_PH_DESC;
def PRECRQ_PH_W : DspMMRel, PRECRQ_PH_W_ENC, PRECRQ_PH_W_DESC;
def PRECRQ_RS_PH_W : DspMMRel, PRECRQ_RS_PH_W_ENC, PRECRQ_RS_PH_W_DESC;
def PRECRQU_S_QB_PH : DspMMRel, PRECRQU_S_QB_PH_ENC, PRECRQU_S_QB_PH_DESC;
def PRECEQ_W_PHL : DspMMRel, PRECEQ_W_PHL_ENC, PRECEQ_W_PHL_DESC;
def PRECEQ_W_PHR : DspMMRel, PRECEQ_W_PHR_ENC, PRECEQ_W_PHR_DESC;
def PRECEQU_PH_QBL : DspMMRel, PRECEQU_PH_QBL_ENC, PRECEQU_PH_QBL_DESC;
def PRECEQU_PH_QBR : DspMMRel, PRECEQU_PH_QBR_ENC, PRECEQU_PH_QBR_DESC;
def PRECEQU_PH_QBLA : DspMMRel, PRECEQU_PH_QBLA_ENC, PRECEQU_PH_QBLA_DESC;
def PRECEQU_PH_QBRA : DspMMRel, PRECEQU_PH_QBRA_ENC, PRECEQU_PH_QBRA_DESC;
def PRECEU_PH_QBL : DspMMRel, PRECEU_PH_QBL_ENC, PRECEU_PH_QBL_DESC;
def PRECEU_PH_QBR : DspMMRel, PRECEU_PH_QBR_ENC, PRECEU_PH_QBR_DESC;
def PRECEU_PH_QBLA : DspMMRel, PRECEU_PH_QBLA_ENC, PRECEU_PH_QBLA_DESC;
def PRECEU_PH_QBRA : DspMMRel, PRECEU_PH_QBRA_ENC, PRECEU_PH_QBRA_DESC;
def SHLL_QB : DspMMRel, SHLL_QB_ENC, SHLL_QB_DESC;
def SHLLV_QB : DspMMRel, SHLLV_QB_ENC, SHLLV_QB_DESC;
def SHRL_QB : DspMMRel, SHRL_QB_ENC, SHRL_QB_DESC;
def SHRLV_QB : DspMMRel, SHRLV_QB_ENC, SHRLV_QB_DESC;
def SHLL_PH : DspMMRel, SHLL_PH_ENC, SHLL_PH_DESC;
def SHLLV_PH : DspMMRel, SHLLV_PH_ENC, SHLLV_PH_DESC;
def SHLL_S_PH : DspMMRel, SHLL_S_PH_ENC, SHLL_S_PH_DESC;
def SHLLV_S_PH : DspMMRel, SHLLV_S_PH_ENC, SHLLV_S_PH_DESC;
def SHRA_PH : DspMMRel, SHRA_PH_ENC, SHRA_PH_DESC;
def SHRAV_PH : DspMMRel, SHRAV_PH_ENC, SHRAV_PH_DESC;
def SHRA_R_PH : DspMMRel, SHRA_R_PH_ENC, SHRA_R_PH_DESC;
def SHRAV_R_PH : DspMMRel, SHRAV_R_PH_ENC, SHRAV_R_PH_DESC;
def SHLL_S_W : DspMMRel, SHLL_S_W_ENC, SHLL_S_W_DESC;
def SHLLV_S_W : DspMMRel, SHLLV_S_W_ENC, SHLLV_S_W_DESC;
def SHRA_R_W : DspMMRel, SHRA_R_W_ENC, SHRA_R_W_DESC;
def SHRAV_R_W : DspMMRel, SHRAV_R_W_ENC, SHRAV_R_W_DESC;
def MULEU_S_PH_QBL : DspMMRel, MULEU_S_PH_QBL_ENC, MULEU_S_PH_QBL_DESC;
def MULEU_S_PH_QBR : DspMMRel, MULEU_S_PH_QBR_ENC, MULEU_S_PH_QBR_DESC;
def MULEQ_S_W_PHL : DspMMRel, MULEQ_S_W_PHL_ENC, MULEQ_S_W_PHL_DESC;
def MULEQ_S_W_PHR : DspMMRel, MULEQ_S_W_PHR_ENC, MULEQ_S_W_PHR_DESC;
def MULQ_RS_PH : DspMMRel, MULQ_RS_PH_ENC, MULQ_RS_PH_DESC;
def MULSAQ_S_W_PH : DspMMRel, MULSAQ_S_W_PH_ENC, MULSAQ_S_W_PH_DESC;
def MAQ_S_W_PHL : DspMMRel, MAQ_S_W_PHL_ENC, MAQ_S_W_PHL_DESC;
def MAQ_S_W_PHR : DspMMRel, MAQ_S_W_PHR_ENC, MAQ_S_W_PHR_DESC;
def MAQ_SA_W_PHL : DspMMRel, MAQ_SA_W_PHL_ENC, MAQ_SA_W_PHL_DESC;
def MAQ_SA_W_PHR : DspMMRel, MAQ_SA_W_PHR_ENC, MAQ_SA_W_PHR_DESC;
def MFHI_DSP : DspMMRel, MFHI_ENC, MFHI_DESC;
def MFLO_DSP : DspMMRel, MFLO_ENC, MFLO_DESC;
def MTHI_DSP : DspMMRel, MTHI_ENC, MTHI_DESC;
def MTLO_DSP : DspMMRel, MTLO_ENC, MTLO_DESC;
def DPAU_H_QBL : DspMMRel, DPAU_H_QBL_ENC, DPAU_H_QBL_DESC;
def DPAU_H_QBR : DspMMRel, DPAU_H_QBR_ENC, DPAU_H_QBR_DESC;
def DPSU_H_QBL : DspMMRel, DPSU_H_QBL_ENC, DPSU_H_QBL_DESC;
def DPSU_H_QBR : DspMMRel, DPSU_H_QBR_ENC, DPSU_H_QBR_DESC;
def DPAQ_S_W_PH : DspMMRel, DPAQ_S_W_PH_ENC, DPAQ_S_W_PH_DESC;
def DPSQ_S_W_PH : DspMMRel, DPSQ_S_W_PH_ENC, DPSQ_S_W_PH_DESC;
def DPAQ_SA_L_W : DspMMRel, DPAQ_SA_L_W_ENC, DPAQ_SA_L_W_DESC;
def DPSQ_SA_L_W : DspMMRel, DPSQ_SA_L_W_ENC, DPSQ_SA_L_W_DESC;
def MULT_DSP : DspMMRel, MULT_DSP_ENC, MULT_DSP_DESC;
def MULTU_DSP : DspMMRel, MULTU_DSP_ENC, MULTU_DSP_DESC;
def MADD_DSP : DspMMRel, MADD_DSP_ENC, MADD_DSP_DESC;
def MADDU_DSP : DspMMRel, MADDU_DSP_ENC, MADDU_DSP_DESC;
def MSUB_DSP : DspMMRel, MSUB_DSP_ENC, MSUB_DSP_DESC;
def MSUBU_DSP : DspMMRel, MSUBU_DSP_ENC, MSUBU_DSP_DESC;
def CMPU_EQ_QB : DspMMRel, CMPU_EQ_QB_ENC, CMPU_EQ_QB_DESC;
def CMPU_LT_QB : DspMMRel, CMPU_LT_QB_ENC, CMPU_LT_QB_DESC;
def CMPU_LE_QB : DspMMRel, CMPU_LE_QB_ENC, CMPU_LE_QB_DESC;
def CMPGU_EQ_QB : DspMMRel, CMPGU_EQ_QB_ENC, CMPGU_EQ_QB_DESC;
def CMPGU_LT_QB : DspMMRel, CMPGU_LT_QB_ENC, CMPGU_LT_QB_DESC;
def CMPGU_LE_QB : DspMMRel, CMPGU_LE_QB_ENC, CMPGU_LE_QB_DESC;
def CMP_EQ_PH : DspMMRel, CMP_EQ_PH_ENC, CMP_EQ_PH_DESC;
def CMP_LT_PH : DspMMRel, CMP_LT_PH_ENC, CMP_LT_PH_DESC;
def CMP_LE_PH : DspMMRel, CMP_LE_PH_ENC, CMP_LE_PH_DESC;
def BITREV : DspMMRel, BITREV_ENC, BITREV_DESC;
def PACKRL_PH : DspMMRel, PACKRL_PH_ENC, PACKRL_PH_DESC;
def REPL_QB : DspMMRel, REPL_QB_ENC, REPL_QB_DESC;
def REPL_PH : DspMMRel, REPL_PH_ENC, REPL_PH_DESC;
def REPLV_QB : DspMMRel, REPLV_QB_ENC, REPLV_QB_DESC;
def REPLV_PH : DspMMRel, REPLV_PH_ENC, REPLV_PH_DESC;
def PICK_QB : DspMMRel, PICK_QB_ENC, PICK_QB_DESC;
def PICK_PH : DspMMRel, PICK_PH_ENC, PICK_PH_DESC;
def LWX : DspMMRel, LWX_ENC, LWX_DESC;
def LHX : DspMMRel, LHX_ENC, LHX_DESC;
def LBUX : DspMMRel, LBUX_ENC, LBUX_DESC;
let AdditionalPredicates = [NotInMicroMips] in {
def BPOSGE32 : DspMMRel, BPOSGE32_ENC, BPOSGE32_DESC;
}
def INSV : DspMMRel, INSV_ENC, INSV_DESC;
def EXTP : DspMMRel, EXTP_ENC, EXTP_DESC;
def EXTPV : DspMMRel, EXTPV_ENC, EXTPV_DESC;
def EXTPDP : DspMMRel, EXTPDP_ENC, EXTPDP_DESC;
def EXTPDPV : DspMMRel, EXTPDPV_ENC, EXTPDPV_DESC;
def EXTR_W : DspMMRel, EXTR_W_ENC, EXTR_W_DESC;
def EXTRV_W : DspMMRel, EXTRV_W_ENC, EXTRV_W_DESC;
def EXTR_R_W : DspMMRel, EXTR_R_W_ENC, EXTR_R_W_DESC;
def EXTRV_R_W : DspMMRel, EXTRV_R_W_ENC, EXTRV_R_W_DESC;
def EXTR_RS_W : DspMMRel, EXTR_RS_W_ENC, EXTR_RS_W_DESC;
def EXTRV_RS_W : DspMMRel, EXTRV_RS_W_ENC, EXTRV_RS_W_DESC;
def EXTR_S_H : DspMMRel, EXTR_S_H_ENC, EXTR_S_H_DESC;
def EXTRV_S_H : DspMMRel, EXTRV_S_H_ENC, EXTRV_S_H_DESC;
def SHILO : DspMMRel, SHILO_ENC, SHILO_DESC;
def SHILOV : DspMMRel, SHILOV_ENC, SHILOV_DESC;
def MTHLIP : DspMMRel, MTHLIP_ENC, MTHLIP_DESC;
def RDDSP : DspMMRel, RDDSP_ENC, RDDSP_DESC;
let AdditionalPredicates = [NotInMicroMips] in {
def WRDSP : WRDSP_ENC, WRDSP_DESC;
}
// MIPS DSP Rev 2
def ADDU_PH : DspMMRel, ADDU_PH_ENC, ADDU_PH_DESC, ISA_DSPR2;
def ADDU_S_PH : DspMMRel, ADDU_S_PH_ENC, ADDU_S_PH_DESC, ISA_DSPR2;
def SUBU_PH : DspMMRel, SUBU_PH_ENC, SUBU_PH_DESC, ISA_DSPR2;
def SUBU_S_PH : DspMMRel, SUBU_S_PH_ENC, SUBU_S_PH_DESC, ISA_DSPR2;
def CMPGDU_EQ_QB : DspMMRel, CMPGDU_EQ_QB_ENC, CMPGDU_EQ_QB_DESC, ISA_DSPR2;
def CMPGDU_LT_QB : DspMMRel, CMPGDU_LT_QB_ENC, CMPGDU_LT_QB_DESC, ISA_DSPR2;
def CMPGDU_LE_QB : DspMMRel, CMPGDU_LE_QB_ENC, CMPGDU_LE_QB_DESC, ISA_DSPR2;
def ABSQ_S_QB : DspMMRel, ABSQ_S_QB_ENC, ABSQ_S_QB_DESC, ISA_DSPR2;
def ADDUH_QB : DspMMRel, ADDUH_QB_ENC, ADDUH_QB_DESC, ISA_DSPR2;
def ADDUH_R_QB : DspMMRel, ADDUH_R_QB_ENC, ADDUH_R_QB_DESC, ISA_DSPR2;
def SUBUH_QB : DspMMRel, SUBUH_QB_ENC, SUBUH_QB_DESC, ISA_DSPR2;
def SUBUH_R_QB : DspMMRel, SUBUH_R_QB_ENC, SUBUH_R_QB_DESC, ISA_DSPR2;
def ADDQH_PH : DspMMRel, ADDQH_PH_ENC, ADDQH_PH_DESC, ISA_DSPR2;
def ADDQH_R_PH : DspMMRel, ADDQH_R_PH_ENC, ADDQH_R_PH_DESC, ISA_DSPR2;
def SUBQH_PH : DspMMRel, SUBQH_PH_ENC, SUBQH_PH_DESC, ISA_DSPR2;
def SUBQH_R_PH : DspMMRel, SUBQH_R_PH_ENC, SUBQH_R_PH_DESC, ISA_DSPR2;
def ADDQH_W : DspMMRel, ADDQH_W_ENC, ADDQH_W_DESC, ISA_DSPR2;
def ADDQH_R_W : DspMMRel, ADDQH_R_W_ENC, ADDQH_R_W_DESC, ISA_DSPR2;
def SUBQH_W : DspMMRel, SUBQH_W_ENC, SUBQH_W_DESC, ISA_DSPR2;
def SUBQH_R_W : DspMMRel, SUBQH_R_W_ENC, SUBQH_R_W_DESC, ISA_DSPR2;
def MUL_PH : DspMMRel, MUL_PH_ENC, MUL_PH_DESC, ISA_DSPR2;
def MUL_S_PH : DspMMRel, MUL_S_PH_ENC, MUL_S_PH_DESC, ISA_DSPR2;
def MULQ_S_W : DspMMRel, MULQ_S_W_ENC, MULQ_S_W_DESC, ISA_DSPR2;
def MULQ_RS_W : DspMMRel, MULQ_RS_W_ENC, MULQ_RS_W_DESC, ISA_DSPR2;
def MULQ_S_PH : DspMMRel, MULQ_S_PH_ENC, MULQ_S_PH_DESC, ISA_DSPR2;
def DPA_W_PH : DspMMRel, DPA_W_PH_ENC, DPA_W_PH_DESC, ISA_DSPR2;
def DPS_W_PH : DspMMRel, DPS_W_PH_ENC, DPS_W_PH_DESC, ISA_DSPR2;
def DPAQX_S_W_PH : DspMMRel, DPAQX_S_W_PH_ENC, DPAQX_S_W_PH_DESC, ISA_DSPR2;
def DPAQX_SA_W_PH : DspMMRel, DPAQX_SA_W_PH_ENC, DPAQX_SA_W_PH_DESC, ISA_DSPR2;
def DPAX_W_PH : DspMMRel, DPAX_W_PH_ENC, DPAX_W_PH_DESC, ISA_DSPR2;
def DPSX_W_PH : DspMMRel, DPSX_W_PH_ENC, DPSX_W_PH_DESC, ISA_DSPR2;
def DPSQX_S_W_PH : DspMMRel, DPSQX_S_W_PH_ENC, DPSQX_S_W_PH_DESC, ISA_DSPR2;
def DPSQX_SA_W_PH : DspMMRel, DPSQX_SA_W_PH_ENC, DPSQX_SA_W_PH_DESC, ISA_DSPR2;
def MULSA_W_PH : DspMMRel, MULSA_W_PH_ENC, MULSA_W_PH_DESC, ISA_DSPR2;
def PRECR_QB_PH : DspMMRel, PRECR_QB_PH_ENC, PRECR_QB_PH_DESC, ISA_DSPR2;
def PRECR_SRA_PH_W : DspMMRel, PRECR_SRA_PH_W_ENC, PRECR_SRA_PH_W_DESC, ISA_DSPR2;
def PRECR_SRA_R_PH_W : DspMMRel, PRECR_SRA_R_PH_W_ENC, PRECR_SRA_R_PH_W_DESC, ISA_DSPR2;
def SHRA_QB : DspMMRel, SHRA_QB_ENC, SHRA_QB_DESC, ISA_DSPR2;
def SHRAV_QB : DspMMRel, SHRAV_QB_ENC, SHRAV_QB_DESC, ISA_DSPR2;
def SHRA_R_QB : DspMMRel, SHRA_R_QB_ENC, SHRA_R_QB_DESC, ISA_DSPR2;
def SHRAV_R_QB : DspMMRel, SHRAV_R_QB_ENC, SHRAV_R_QB_DESC, ISA_DSPR2;
def SHRL_PH : DspMMRel, SHRL_PH_ENC, SHRL_PH_DESC, ISA_DSPR2;
def SHRLV_PH : DspMMRel, SHRLV_PH_ENC, SHRLV_PH_DESC, ISA_DSPR2;
def APPEND : DspMMRel, APPEND_ENC, APPEND_DESC, ISA_DSPR2;
def BALIGN : DspMMRel, BALIGN_ENC, BALIGN_DESC, ISA_DSPR2;
def PREPEND : DspMMRel, PREPEND_ENC, PREPEND_DESC, ISA_DSPR2;
// Pseudos.
let isPseudo = 1, isCodeGenOnly = 1, hasNoSchedulingInfo = 1 in {
// Pseudo instructions for loading and storing accumulator registers.
def LOAD_ACC64DSP : Load<"", ACC64DSPOpnd>;
def STORE_ACC64DSP : Store<"", ACC64DSPOpnd>;
// Pseudos for loading and storing ccond field of DSP control register.
def LOAD_CCOND_DSP : Load<"load_ccond_dsp", DSPCC>;
def STORE_CCOND_DSP : Store<"store_ccond_dsp", DSPCC>;
}
let DecoderNamespace = "MipsDSP", Arch = "dsp",
ASEPredicate = [HasDSP] in {
def LWDSP : Load<"lw", DSPROpnd, null_frag, II_LW>, DspMMRel, LW_FM<0x23>;
def SWDSP : Store<"sw", DSPROpnd, null_frag, II_SW>, DspMMRel, LW_FM<0x2b>;
}
// Pseudo CMP and PICK instructions.
class PseudoCMP<Instruction RealInst> :
PseudoDSP<(outs DSPCC:$cmp), (ins DSPROpnd:$rs, DSPROpnd:$rt), []>,
PseudoInstExpansion<(RealInst DSPROpnd:$rs, DSPROpnd:$rt)>, NeverHasSideEffects;
class PseudoPICK<Instruction RealInst> :
PseudoDSP<(outs DSPROpnd:$rd), (ins DSPCC:$cmp, DSPROpnd:$rs, DSPROpnd:$rt), []>,
PseudoInstExpansion<(RealInst DSPROpnd:$rd, DSPROpnd:$rs, DSPROpnd:$rt)>,
NeverHasSideEffects;
def PseudoCMP_EQ_PH : PseudoCMP<CMP_EQ_PH>;
def PseudoCMP_LT_PH : PseudoCMP<CMP_LT_PH>;
def PseudoCMP_LE_PH : PseudoCMP<CMP_LE_PH>;
def PseudoCMPU_EQ_QB : PseudoCMP<CMPU_EQ_QB>;
def PseudoCMPU_LT_QB : PseudoCMP<CMPU_LT_QB>;
def PseudoCMPU_LE_QB : PseudoCMP<CMPU_LE_QB>;
def PseudoPICK_PH : PseudoPICK<PICK_PH>;
def PseudoPICK_QB : PseudoPICK<PICK_QB>;
-def PseudoMTLOHI_DSP : PseudoMTLOHI<ACC64DSP, GPR32>;
+let AdditionalPredicates = [HasDSP] in {
+ def PseudoMTLOHI_DSP : PseudoMTLOHI<ACC64DSP, GPR32>;
+}
// Patterns.
class DSPPat<dag pattern, dag result, Predicate pred = HasDSP> :
Pat<pattern, result>, Requires<[pred]>;
class BitconvertPat<ValueType DstVT, ValueType SrcVT, RegisterClass DstRC,
RegisterClass SrcRC> :
DSPPat<(DstVT (bitconvert (SrcVT SrcRC:$src))),
(COPY_TO_REGCLASS SrcRC:$src, DstRC)>;
def : BitconvertPat<i32, v2i16, GPR32, DSPR>;
def : BitconvertPat<i32, v4i8, GPR32, DSPR>;
def : BitconvertPat<v2i16, i32, DSPR, GPR32>;
def : BitconvertPat<v4i8, i32, DSPR, GPR32>;
def : BitconvertPat<f32, v2i16, FGR32, DSPR>;
def : BitconvertPat<f32, v4i8, FGR32, DSPR>;
def : BitconvertPat<v2i16, f32, DSPR, FGR32>;
def : BitconvertPat<v4i8, f32, DSPR, FGR32>;
def : DSPPat<(v2i16 (load addr:$a)),
(v2i16 (COPY_TO_REGCLASS (LW addr:$a), DSPR))>;
def : DSPPat<(v4i8 (load addr:$a)),
(v4i8 (COPY_TO_REGCLASS (LW addr:$a), DSPR))>;
def : DSPPat<(store (v2i16 DSPR:$val), addr:$a),
(SW (COPY_TO_REGCLASS DSPR:$val, GPR32), addr:$a)>;
def : DSPPat<(store (v4i8 DSPR:$val), addr:$a),
(SW (COPY_TO_REGCLASS DSPR:$val, GPR32), addr:$a)>;
// Binary operations.
class DSPBinPat<Instruction Inst, ValueType ValTy, SDPatternOperator Node,
Predicate Pred = HasDSP> :
DSPPat<(Node ValTy:$a, ValTy:$b), (Inst ValTy:$a, ValTy:$b), Pred>;
def : DSPBinPat<ADDQ_PH, v2i16, int_mips_addq_ph>;
def : DSPBinPat<ADDQ_PH, v2i16, add>;
def : DSPBinPat<SUBQ_PH, v2i16, int_mips_subq_ph>;
def : DSPBinPat<SUBQ_PH, v2i16, sub>;
def : DSPBinPat<MUL_PH, v2i16, int_mips_mul_ph, HasDSPR2>;
def : DSPBinPat<MUL_PH, v2i16, mul, HasDSPR2>;
def : DSPBinPat<ADDU_QB, v4i8, int_mips_addu_qb>;
def : DSPBinPat<ADDU_QB, v4i8, add>;
def : DSPBinPat<SUBU_QB, v4i8, int_mips_subu_qb>;
def : DSPBinPat<SUBU_QB, v4i8, sub>;
def : DSPBinPat<ADDSC, i32, int_mips_addsc>;
def : DSPBinPat<ADDSC, i32, addc>;
def : DSPBinPat<ADDWC, i32, int_mips_addwc>;
def : DSPBinPat<ADDWC, i32, adde>;
// Shift immediate patterns.
class DSPShiftPat<Instruction Inst, ValueType ValTy, SDPatternOperator Node,
SDPatternOperator Imm, Predicate Pred = HasDSP> :
DSPPat<(Node ValTy:$a, Imm:$shamt), (Inst ValTy:$a, Imm:$shamt), Pred>;
def : DSPShiftPat<SHLL_PH, v2i16, MipsSHLL_DSP, imm>;
def : DSPShiftPat<SHRA_PH, v2i16, MipsSHRA_DSP, imm>;
def : DSPShiftPat<SHRL_PH, v2i16, MipsSHRL_DSP, imm, HasDSPR2>;
def : DSPShiftPat<SHLL_PH, v2i16, int_mips_shll_ph, immZExt4>;
def : DSPShiftPat<SHRA_PH, v2i16, int_mips_shra_ph, immZExt4>;
def : DSPShiftPat<SHRL_PH, v2i16, int_mips_shrl_ph, immZExt4, HasDSPR2>;
def : DSPShiftPat<SHLL_QB, v4i8, MipsSHLL_DSP, imm>;
def : DSPShiftPat<SHRA_QB, v4i8, MipsSHRA_DSP, imm, HasDSPR2>;
def : DSPShiftPat<SHRL_QB, v4i8, MipsSHRL_DSP, imm>;
def : DSPShiftPat<SHLL_QB, v4i8, int_mips_shll_qb, immZExt3>;
def : DSPShiftPat<SHRA_QB, v4i8, int_mips_shra_qb, immZExt3, HasDSPR2>;
def : DSPShiftPat<SHRL_QB, v4i8, int_mips_shrl_qb, immZExt3>;
// SETCC/SELECT_CC patterns.
class DSPSetCCPat<Instruction Cmp, Instruction Pick, ValueType ValTy,
CondCode CC> :
DSPPat<(ValTy (MipsSETCC_DSP ValTy:$a, ValTy:$b, CC)),
(ValTy (Pick (ValTy (Cmp ValTy:$a, ValTy:$b)),
(ValTy (COPY_TO_REGCLASS (ADDiu ZERO, -1), DSPR)),
(ValTy ZERO)))>;
class DSPSetCCPatInv<Instruction Cmp, Instruction Pick, ValueType ValTy,
CondCode CC> :
DSPPat<(ValTy (MipsSETCC_DSP ValTy:$a, ValTy:$b, CC)),
(ValTy (Pick (ValTy (Cmp ValTy:$a, ValTy:$b)),
(ValTy ZERO),
(ValTy (COPY_TO_REGCLASS (ADDiu ZERO, -1), DSPR))))>;
class DSPSelectCCPat<Instruction Cmp, Instruction Pick, ValueType ValTy,
CondCode CC> :
DSPPat<(ValTy (MipsSELECT_CC_DSP ValTy:$a, ValTy:$b, ValTy:$c, ValTy:$d, CC)),
(ValTy (Pick (ValTy (Cmp ValTy:$a, ValTy:$b)), $c, $d))>;
class DSPSelectCCPatInv<Instruction Cmp, Instruction Pick, ValueType ValTy,
CondCode CC> :
DSPPat<(ValTy (MipsSELECT_CC_DSP ValTy:$a, ValTy:$b, ValTy:$c, ValTy:$d, CC)),
(ValTy (Pick (ValTy (Cmp ValTy:$a, ValTy:$b)), $d, $c))>;
def : DSPSetCCPat<PseudoCMP_EQ_PH, PseudoPICK_PH, v2i16, SETEQ>;
def : DSPSetCCPat<PseudoCMP_LT_PH, PseudoPICK_PH, v2i16, SETLT>;
def : DSPSetCCPat<PseudoCMP_LE_PH, PseudoPICK_PH, v2i16, SETLE>;
def : DSPSetCCPatInv<PseudoCMP_EQ_PH, PseudoPICK_PH, v2i16, SETNE>;
def : DSPSetCCPatInv<PseudoCMP_LT_PH, PseudoPICK_PH, v2i16, SETGE>;
def : DSPSetCCPatInv<PseudoCMP_LE_PH, PseudoPICK_PH, v2i16, SETGT>;
def : DSPSetCCPat<PseudoCMPU_EQ_QB, PseudoPICK_QB, v4i8, SETEQ>;
def : DSPSetCCPat<PseudoCMPU_LT_QB, PseudoPICK_QB, v4i8, SETULT>;
def : DSPSetCCPat<PseudoCMPU_LE_QB, PseudoPICK_QB, v4i8, SETULE>;
def : DSPSetCCPatInv<PseudoCMPU_EQ_QB, PseudoPICK_QB, v4i8, SETNE>;
def : DSPSetCCPatInv<PseudoCMPU_LT_QB, PseudoPICK_QB, v4i8, SETUGE>;
def : DSPSetCCPatInv<PseudoCMPU_LE_QB, PseudoPICK_QB, v4i8, SETUGT>;
def : DSPSelectCCPat<PseudoCMP_EQ_PH, PseudoPICK_PH, v2i16, SETEQ>;
def : DSPSelectCCPat<PseudoCMP_LT_PH, PseudoPICK_PH, v2i16, SETLT>;
def : DSPSelectCCPat<PseudoCMP_LE_PH, PseudoPICK_PH, v2i16, SETLE>;
def : DSPSelectCCPatInv<PseudoCMP_EQ_PH, PseudoPICK_PH, v2i16, SETNE>;
def : DSPSelectCCPatInv<PseudoCMP_LT_PH, PseudoPICK_PH, v2i16, SETGE>;
def : DSPSelectCCPatInv<PseudoCMP_LE_PH, PseudoPICK_PH, v2i16, SETGT>;
def : DSPSelectCCPat<PseudoCMPU_EQ_QB, PseudoPICK_QB, v4i8, SETEQ>;
def : DSPSelectCCPat<PseudoCMPU_LT_QB, PseudoPICK_QB, v4i8, SETULT>;
def : DSPSelectCCPat<PseudoCMPU_LE_QB, PseudoPICK_QB, v4i8, SETULE>;
def : DSPSelectCCPatInv<PseudoCMPU_EQ_QB, PseudoPICK_QB, v4i8, SETNE>;
def : DSPSelectCCPatInv<PseudoCMPU_LT_QB, PseudoPICK_QB, v4i8, SETUGE>;
def : DSPSelectCCPatInv<PseudoCMPU_LE_QB, PseudoPICK_QB, v4i8, SETUGT>;
// Extr patterns.
class EXTR_W_TY1_R2_Pat<SDPatternOperator OpNode, Instruction Instr> :
DSPPat<(i32 (OpNode GPR32:$rs, ACC64DSP:$ac)),
(Instr ACC64DSP:$ac, GPR32:$rs)>;
class EXTR_W_TY1_R1_Pat<SDPatternOperator OpNode, Instruction Instr> :
DSPPat<(i32 (OpNode immZExt5:$shift, ACC64DSP:$ac)),
(Instr ACC64DSP:$ac, immZExt5:$shift)>;
def : EXTR_W_TY1_R1_Pat<MipsEXTP, EXTP>;
def : EXTR_W_TY1_R2_Pat<MipsEXTP, EXTPV>;
def : EXTR_W_TY1_R1_Pat<MipsEXTPDP, EXTPDP>;
def : EXTR_W_TY1_R2_Pat<MipsEXTPDP, EXTPDPV>;
def : EXTR_W_TY1_R1_Pat<MipsEXTR_W, EXTR_W>;
def : EXTR_W_TY1_R2_Pat<MipsEXTR_W, EXTRV_W>;
def : EXTR_W_TY1_R1_Pat<MipsEXTR_R_W, EXTR_R_W>;
def : EXTR_W_TY1_R2_Pat<MipsEXTR_R_W, EXTRV_R_W>;
def : EXTR_W_TY1_R1_Pat<MipsEXTR_RS_W, EXTR_RS_W>;
def : EXTR_W_TY1_R2_Pat<MipsEXTR_RS_W, EXTRV_RS_W>;
def : EXTR_W_TY1_R1_Pat<MipsEXTR_S_H, EXTR_S_H>;
def : EXTR_W_TY1_R2_Pat<MipsEXTR_S_H, EXTRV_S_H>;
// Indexed load patterns.
class IndexedLoadPat<SDPatternOperator LoadNode, Instruction Instr> :
DSPPat<(i32 (LoadNode (add i32:$base, i32:$index))),
(Instr i32:$base, i32:$index)>;
let AddedComplexity = 20 in {
def : IndexedLoadPat<zextloadi8, LBUX>;
def : IndexedLoadPat<sextloadi16, LHX>;
def : IndexedLoadPat<load, LWX>;
}
// Instruction alias.
let AdditionalPredicates = [NotInMicroMips] in {
def : DSPInstAlias<"wrdsp $rt", (WRDSP GPR32Opnd:$rt, 0x1F), 1>;
}
Index: stable/11/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp (revision 350259)
@@ -1,933 +1,934 @@
//===- MipsDelaySlotFiller.cpp - Mips Delay Slot Filler -------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Simple pass to fill delay slots with useful instructions.
//
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/MipsMCNaCl.h"
#include "Mips.h"
#include "MipsInstrInfo.h"
#include "MipsRegisterInfo.h"
#include "MipsSubtarget.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Target/TargetMachine.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <memory>
#include <utility>
using namespace llvm;
#define DEBUG_TYPE "mips-delay-slot-filler"
STATISTIC(FilledSlots, "Number of delay slots filled");
STATISTIC(UsefulSlots, "Number of delay slots filled with instructions that"
" are not NOP.");
static cl::opt<bool> DisableDelaySlotFiller(
"disable-mips-delay-filler",
cl::init(false),
cl::desc("Fill all delay slots with NOPs."),
cl::Hidden);
static cl::opt<bool> DisableForwardSearch(
"disable-mips-df-forward-search",
cl::init(true),
cl::desc("Disallow MIPS delay filler to search forward."),
cl::Hidden);
static cl::opt<bool> DisableSuccBBSearch(
"disable-mips-df-succbb-search",
cl::init(true),
cl::desc("Disallow MIPS delay filler to search successor basic blocks."),
cl::Hidden);
static cl::opt<bool> DisableBackwardSearch(
"disable-mips-df-backward-search",
cl::init(false),
cl::desc("Disallow MIPS delay filler to search backward."),
cl::Hidden);
enum CompactBranchPolicy {
CB_Never, ///< The policy 'never' may in some circumstances or for some
///< ISAs not be absolutely adhered to.
CB_Optimal, ///< Optimal is the default and will produce compact branches
///< when delay slots cannot be filled.
CB_Always ///< 'always' may in some circumstances may not be
///< absolutely adhered to there may not be a corresponding
///< compact form of a branch.
};
static cl::opt<CompactBranchPolicy> MipsCompactBranchPolicy(
"mips-compact-branches",cl::Optional,
cl::init(CB_Optimal),
cl::desc("MIPS Specific: Compact branch policy."),
cl::values(
clEnumValN(CB_Never, "never", "Do not use compact branches if possible."),
clEnumValN(CB_Optimal, "optimal", "Use compact branches where appropiate (default)."),
clEnumValN(CB_Always, "always", "Always use compact branches if possible.")
)
);
namespace {
using Iter = MachineBasicBlock::iterator;
using ReverseIter = MachineBasicBlock::reverse_iterator;
using BB2BrMap = SmallDenseMap<MachineBasicBlock *, MachineInstr *, 2>;
class RegDefsUses {
public:
RegDefsUses(const TargetRegisterInfo &TRI);
void init(const MachineInstr &MI);
/// This function sets all caller-saved registers in Defs.
void setCallerSaved(const MachineInstr &MI);
/// This function sets all unallocatable registers in Defs.
void setUnallocatableRegs(const MachineFunction &MF);
/// Set bits in Uses corresponding to MBB's live-out registers except for
/// the registers that are live-in to SuccBB.
void addLiveOut(const MachineBasicBlock &MBB,
const MachineBasicBlock &SuccBB);
bool update(const MachineInstr &MI, unsigned Begin, unsigned End);
private:
bool checkRegDefsUses(BitVector &NewDefs, BitVector &NewUses, unsigned Reg,
bool IsDef) const;
/// Returns true if Reg or its alias is in RegSet.
bool isRegInSet(const BitVector &RegSet, unsigned Reg) const;
const TargetRegisterInfo &TRI;
BitVector Defs, Uses;
};
/// Base class for inspecting loads and stores.
class InspectMemInstr {
public:
InspectMemInstr(bool ForbidMemInstr_) : ForbidMemInstr(ForbidMemInstr_) {}
virtual ~InspectMemInstr() = default;
/// Return true if MI cannot be moved to delay slot.
bool hasHazard(const MachineInstr &MI);
protected:
/// Flags indicating whether loads or stores have been seen.
bool OrigSeenLoad = false;
bool OrigSeenStore = false;
bool SeenLoad = false;
bool SeenStore = false;
/// Memory instructions are not allowed to move to delay slot if this flag
/// is true.
bool ForbidMemInstr;
private:
virtual bool hasHazard_(const MachineInstr &MI) = 0;
};
/// This subclass rejects any memory instructions.
class NoMemInstr : public InspectMemInstr {
public:
NoMemInstr() : InspectMemInstr(true) {}
private:
bool hasHazard_(const MachineInstr &MI) override { return true; }
};
/// This subclass accepts loads from stacks and constant loads.
class LoadFromStackOrConst : public InspectMemInstr {
public:
LoadFromStackOrConst() : InspectMemInstr(false) {}
private:
bool hasHazard_(const MachineInstr &MI) override;
};
/// This subclass uses memory dependence information to determine whether a
/// memory instruction can be moved to a delay slot.
class MemDefsUses : public InspectMemInstr {
public:
MemDefsUses(const DataLayout &DL, const MachineFrameInfo *MFI);
private:
using ValueType = PointerUnion<const Value *, const PseudoSourceValue *>;
bool hasHazard_(const MachineInstr &MI) override;
/// Update Defs and Uses. Return true if there exist dependences that
/// disqualify the delay slot candidate between V and values in Uses and
/// Defs.
bool updateDefsUses(ValueType V, bool MayStore);
/// Get the list of underlying objects of MI's memory operand.
bool getUnderlyingObjects(const MachineInstr &MI,
SmallVectorImpl<ValueType> &Objects) const;
const MachineFrameInfo *MFI;
SmallPtrSet<ValueType, 4> Uses, Defs;
const DataLayout &DL;
/// Flags indicating whether loads or stores with no underlying objects have
/// been seen.
bool SeenNoObjLoad = false;
bool SeenNoObjStore = false;
};
class MipsDelaySlotFiller : public MachineFunctionPass {
public:
MipsDelaySlotFiller() : MachineFunctionPass(ID) {
initializeMipsDelaySlotFillerPass(*PassRegistry::getPassRegistry());
}
StringRef getPassName() const override { return "Mips Delay Slot Filler"; }
bool runOnMachineFunction(MachineFunction &F) override {
TM = &F.getTarget();
bool Changed = false;
for (MachineFunction::iterator FI = F.begin(), FE = F.end();
FI != FE; ++FI)
Changed |= runOnMachineBasicBlock(*FI);
// This pass invalidates liveness information when it reorders
// instructions to fill delay slot. Without this, -verify-machineinstrs
// will fail.
if (Changed)
F.getRegInfo().invalidateLiveness();
return Changed;
}
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::NoVRegs);
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<MachineBranchProbabilityInfo>();
MachineFunctionPass::getAnalysisUsage(AU);
}
static char ID;
private:
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
Iter replaceWithCompactBranch(MachineBasicBlock &MBB, Iter Branch,
const DebugLoc &DL);
/// This function checks if it is valid to move Candidate to the delay slot
/// and returns true if it isn't. It also updates memory and register
/// dependence information.
bool delayHasHazard(const MachineInstr &Candidate, RegDefsUses &RegDU,
InspectMemInstr &IM) const;
/// This function searches range [Begin, End) for an instruction that can be
/// moved to the delay slot. Returns true on success.
template<typename IterTy>
bool searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End,
RegDefsUses &RegDU, InspectMemInstr &IM, Iter Slot,
IterTy &Filler) const;
/// This function searches in the backward direction for an instruction that
/// can be moved to the delay slot. Returns true on success.
bool searchBackward(MachineBasicBlock &MBB, MachineInstr &Slot) const;
/// This function searches MBB in the forward direction for an instruction
/// that can be moved to the delay slot. Returns true on success.
bool searchForward(MachineBasicBlock &MBB, Iter Slot) const;
/// This function searches one of MBB's successor blocks for an instruction
/// that can be moved to the delay slot and inserts clones of the
/// instruction into the successor's predecessor blocks.
bool searchSuccBBs(MachineBasicBlock &MBB, Iter Slot) const;
/// Pick a successor block of MBB. Return NULL if MBB doesn't have a
/// successor block that is not a landing pad.
MachineBasicBlock *selectSuccBB(MachineBasicBlock &B) const;
/// This function analyzes MBB and returns an instruction with an unoccupied
/// slot that branches to Dst.
std::pair<MipsInstrInfo::BranchType, MachineInstr *>
getBranch(MachineBasicBlock &MBB, const MachineBasicBlock &Dst) const;
/// Examine Pred and see if it is possible to insert an instruction into
/// one of its branches delay slot or its end.
bool examinePred(MachineBasicBlock &Pred, const MachineBasicBlock &Succ,
RegDefsUses &RegDU, bool &HasMultipleSuccs,
BB2BrMap &BrMap) const;
bool terminateSearch(const MachineInstr &Candidate) const;
const TargetMachine *TM = nullptr;
};
} // end anonymous namespace
char MipsDelaySlotFiller::ID = 0;
static bool hasUnoccupiedSlot(const MachineInstr *MI) {
return MI->hasDelaySlot() && !MI->isBundledWithSucc();
}
INITIALIZE_PASS(MipsDelaySlotFiller, DEBUG_TYPE,
"Fill delay slot for MIPS", false, false)
/// This function inserts clones of Filler into predecessor blocks.
static void insertDelayFiller(Iter Filler, const BB2BrMap &BrMap) {
MachineFunction *MF = Filler->getParent()->getParent();
for (BB2BrMap::const_iterator I = BrMap.begin(); I != BrMap.end(); ++I) {
if (I->second) {
MIBundleBuilder(I->second).append(MF->CloneMachineInstr(&*Filler));
++UsefulSlots;
} else {
I->first->insert(I->first->end(), MF->CloneMachineInstr(&*Filler));
}
}
}
/// This function adds registers Filler defines to MBB's live-in register list.
static void addLiveInRegs(Iter Filler, MachineBasicBlock &MBB) {
for (unsigned I = 0, E = Filler->getNumOperands(); I != E; ++I) {
const MachineOperand &MO = Filler->getOperand(I);
unsigned R;
if (!MO.isReg() || !MO.isDef() || !(R = MO.getReg()))
continue;
#ifndef NDEBUG
const MachineFunction &MF = *MBB.getParent();
assert(MF.getSubtarget().getRegisterInfo()->getAllocatableSet(MF).test(R) &&
"Shouldn't move an instruction with unallocatable registers across "
"basic block boundaries.");
#endif
if (!MBB.isLiveIn(R))
MBB.addLiveIn(R);
}
}
RegDefsUses::RegDefsUses(const TargetRegisterInfo &TRI)
: TRI(TRI), Defs(TRI.getNumRegs(), false), Uses(TRI.getNumRegs(), false) {}
void RegDefsUses::init(const MachineInstr &MI) {
// Add all register operands which are explicit and non-variadic.
update(MI, 0, MI.getDesc().getNumOperands());
// If MI is a call, add RA to Defs to prevent users of RA from going into
// delay slot.
if (MI.isCall())
Defs.set(Mips::RA);
// Add all implicit register operands of branch instructions except
// register AT.
if (MI.isBranch()) {
update(MI, MI.getDesc().getNumOperands(), MI.getNumOperands());
Defs.reset(Mips::AT);
}
}
void RegDefsUses::setCallerSaved(const MachineInstr &MI) {
assert(MI.isCall());
// Add RA/RA_64 to Defs to prevent users of RA/RA_64 from going into
// the delay slot. The reason is that RA/RA_64 must not be changed
// in the delay slot so that the callee can return to the caller.
if (MI.definesRegister(Mips::RA) || MI.definesRegister(Mips::RA_64)) {
Defs.set(Mips::RA);
Defs.set(Mips::RA_64);
}
// If MI is a call, add all caller-saved registers to Defs.
BitVector CallerSavedRegs(TRI.getNumRegs(), true);
CallerSavedRegs.reset(Mips::ZERO);
CallerSavedRegs.reset(Mips::ZERO_64);
for (const MCPhysReg *R = TRI.getCalleeSavedRegs(MI.getParent()->getParent());
*R; ++R)
for (MCRegAliasIterator AI(*R, &TRI, true); AI.isValid(); ++AI)
CallerSavedRegs.reset(*AI);
Defs |= CallerSavedRegs;
}
void RegDefsUses::setUnallocatableRegs(const MachineFunction &MF) {
BitVector AllocSet = TRI.getAllocatableSet(MF);
for (unsigned R : AllocSet.set_bits())
for (MCRegAliasIterator AI(R, &TRI, false); AI.isValid(); ++AI)
AllocSet.set(*AI);
AllocSet.set(Mips::ZERO);
AllocSet.set(Mips::ZERO_64);
Defs |= AllocSet.flip();
}
void RegDefsUses::addLiveOut(const MachineBasicBlock &MBB,
const MachineBasicBlock &SuccBB) {
for (MachineBasicBlock::const_succ_iterator SI = MBB.succ_begin(),
SE = MBB.succ_end(); SI != SE; ++SI)
if (*SI != &SuccBB)
for (const auto &LI : (*SI)->liveins())
Uses.set(LI.PhysReg);
}
bool RegDefsUses::update(const MachineInstr &MI, unsigned Begin, unsigned End) {
BitVector NewDefs(TRI.getNumRegs()), NewUses(TRI.getNumRegs());
bool HasHazard = false;
for (unsigned I = Begin; I != End; ++I) {
const MachineOperand &MO = MI.getOperand(I);
if (MO.isReg() && MO.getReg())
HasHazard |= checkRegDefsUses(NewDefs, NewUses, MO.getReg(), MO.isDef());
}
Defs |= NewDefs;
Uses |= NewUses;
return HasHazard;
}
bool RegDefsUses::checkRegDefsUses(BitVector &NewDefs, BitVector &NewUses,
unsigned Reg, bool IsDef) const {
if (IsDef) {
NewDefs.set(Reg);
// check whether Reg has already been defined or used.
return (isRegInSet(Defs, Reg) || isRegInSet(Uses, Reg));
}
NewUses.set(Reg);
// check whether Reg has already been defined.
return isRegInSet(Defs, Reg);
}
bool RegDefsUses::isRegInSet(const BitVector &RegSet, unsigned Reg) const {
// Check Reg and all aliased Registers.
for (MCRegAliasIterator AI(Reg, &TRI, true); AI.isValid(); ++AI)
if (RegSet.test(*AI))
return true;
return false;
}
bool InspectMemInstr::hasHazard(const MachineInstr &MI) {
if (!MI.mayStore() && !MI.mayLoad())
return false;
if (ForbidMemInstr)
return true;
OrigSeenLoad = SeenLoad;
OrigSeenStore = SeenStore;
SeenLoad |= MI.mayLoad();
SeenStore |= MI.mayStore();
// If MI is an ordered or volatile memory reference, disallow moving
// subsequent loads and stores to delay slot.
if (MI.hasOrderedMemoryRef() && (OrigSeenLoad || OrigSeenStore)) {
ForbidMemInstr = true;
return true;
}
return hasHazard_(MI);
}
bool LoadFromStackOrConst::hasHazard_(const MachineInstr &MI) {
if (MI.mayStore())
return true;
if (!MI.hasOneMemOperand() || !(*MI.memoperands_begin())->getPseudoValue())
return true;
if (const PseudoSourceValue *PSV =
(*MI.memoperands_begin())->getPseudoValue()) {
if (isa<FixedStackPseudoSourceValue>(PSV))
return false;
return !PSV->isConstant(nullptr) && !PSV->isStack();
}
return true;
}
MemDefsUses::MemDefsUses(const DataLayout &DL, const MachineFrameInfo *MFI_)
: InspectMemInstr(false), MFI(MFI_), DL(DL) {}
bool MemDefsUses::hasHazard_(const MachineInstr &MI) {
bool HasHazard = false;
SmallVector<ValueType, 4> Objs;
// Check underlying object list.
if (getUnderlyingObjects(MI, Objs)) {
for (SmallVectorImpl<ValueType>::const_iterator I = Objs.begin();
I != Objs.end(); ++I)
HasHazard |= updateDefsUses(*I, MI.mayStore());
return HasHazard;
}
// No underlying objects found.
HasHazard = MI.mayStore() && (OrigSeenLoad || OrigSeenStore);
HasHazard |= MI.mayLoad() || OrigSeenStore;
SeenNoObjLoad |= MI.mayLoad();
SeenNoObjStore |= MI.mayStore();
return HasHazard;
}
bool MemDefsUses::updateDefsUses(ValueType V, bool MayStore) {
if (MayStore)
return !Defs.insert(V).second || Uses.count(V) || SeenNoObjStore ||
SeenNoObjLoad;
Uses.insert(V);
return Defs.count(V) || SeenNoObjStore;
}
bool MemDefsUses::
getUnderlyingObjects(const MachineInstr &MI,
SmallVectorImpl<ValueType> &Objects) const {
if (!MI.hasOneMemOperand() ||
(!(*MI.memoperands_begin())->getValue() &&
!(*MI.memoperands_begin())->getPseudoValue()))
return false;
if (const PseudoSourceValue *PSV =
(*MI.memoperands_begin())->getPseudoValue()) {
if (!PSV->isAliased(MFI))
return false;
Objects.push_back(PSV);
return true;
}
const Value *V = (*MI.memoperands_begin())->getValue();
SmallVector<Value *, 4> Objs;
GetUnderlyingObjects(const_cast<Value *>(V), Objs, DL);
for (SmallVectorImpl<Value *>::iterator I = Objs.begin(), E = Objs.end();
I != E; ++I) {
if (!isIdentifiedObject(V))
return false;
Objects.push_back(*I);
}
return true;
}
// Replace Branch with the compact branch instruction.
Iter MipsDelaySlotFiller::replaceWithCompactBranch(MachineBasicBlock &MBB,
Iter Branch,
const DebugLoc &DL) {
const MipsSubtarget &STI = MBB.getParent()->getSubtarget<MipsSubtarget>();
const MipsInstrInfo *TII = STI.getInstrInfo();
unsigned NewOpcode = TII->getEquivalentCompactForm(Branch);
Branch = TII->genInstrWithNewOpc(NewOpcode, Branch);
std::next(Branch)->eraseFromParent();
return Branch;
}
// For given opcode returns opcode of corresponding instruction with short
// delay slot.
// For the pseudo TAILCALL*_MM instructions return the short delay slot
// form. Unfortunately, TAILCALL<->b16 is denied as b16 has a limited range
// that is too short to make use of for tail calls.
static int getEquivalentCallShort(int Opcode) {
switch (Opcode) {
case Mips::BGEZAL:
return Mips::BGEZALS_MM;
case Mips::BLTZAL:
return Mips::BLTZALS_MM;
case Mips::JAL:
case Mips::JAL_MM:
return Mips::JALS_MM;
case Mips::JALR:
return Mips::JALRS_MM;
case Mips::JALR16_MM:
return Mips::JALRS16_MM;
case Mips::TAILCALL_MM:
llvm_unreachable("Attempting to shorten the TAILCALL_MM pseudo!");
case Mips::TAILCALLREG:
return Mips::JR16_MM;
default:
llvm_unreachable("Unexpected call instruction for microMIPS.");
}
}
/// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
/// We assume there is only one delay slot per delayed instruction.
bool MipsDelaySlotFiller::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
bool Changed = false;
const MipsSubtarget &STI = MBB.getParent()->getSubtarget<MipsSubtarget>();
bool InMicroMipsMode = STI.inMicroMipsMode();
const MipsInstrInfo *TII = STI.getInstrInfo();
for (Iter I = MBB.begin(); I != MBB.end(); ++I) {
if (!hasUnoccupiedSlot(&*I))
continue;
// Delay slot filling is disabled at -O0, or in microMIPS32R6.
if (!DisableDelaySlotFiller && (TM->getOptLevel() != CodeGenOpt::None) &&
!(InMicroMipsMode && STI.hasMips32r6())) {
bool Filled = false;
if (MipsCompactBranchPolicy.getValue() != CB_Always ||
!TII->getEquivalentCompactForm(I)) {
if (searchBackward(MBB, *I)) {
Filled = true;
} else if (I->isTerminator()) {
if (searchSuccBBs(MBB, I)) {
Filled = true;
}
} else if (searchForward(MBB, I)) {
Filled = true;
}
}
if (Filled) {
// Get instruction with delay slot.
MachineBasicBlock::instr_iterator DSI = I.getInstrIterator();
if (InMicroMipsMode && TII->getInstSizeInBytes(*std::next(DSI)) == 2 &&
DSI->isCall()) {
// If instruction in delay slot is 16b change opcode to
// corresponding instruction with short delay slot.
// TODO: Implement an instruction mapping table of 16bit opcodes to
// 32bit opcodes so that an instruction can be expanded. This would
// save 16 bits as a TAILCALL_MM pseudo requires a fullsized nop.
// TODO: Permit b16 when branching backwards to the same function
// if it is in range.
DSI->setDesc(TII->get(getEquivalentCallShort(DSI->getOpcode())));
}
++FilledSlots;
Changed = true;
continue;
}
}
// For microMIPS if instruction is BEQ or BNE with one ZERO register, then
// instead of adding NOP replace this instruction with the corresponding
// compact branch instruction, i.e. BEQZC or BNEZC. Additionally
// PseudoReturn and PseudoIndirectBranch are expanded to JR_MM, so they can
// be replaced with JRC16_MM.
// For MIPSR6 attempt to produce the corresponding compact (no delay slot)
// form of the CTI. For indirect jumps this will not require inserting a
// NOP and for branches will hopefully avoid requiring a NOP.
if ((InMicroMipsMode ||
(STI.hasMips32r6() && MipsCompactBranchPolicy != CB_Never)) &&
TII->getEquivalentCompactForm(I)) {
I = replaceWithCompactBranch(MBB, I, I->getDebugLoc());
Changed = true;
continue;
}
// Bundle the NOP to the instruction with the delay slot.
BuildMI(MBB, std::next(I), I->getDebugLoc(), TII->get(Mips::NOP));
MIBundleBuilder(MBB, I, std::next(I, 2));
++FilledSlots;
Changed = true;
}
return Changed;
}
template <typename IterTy>
bool MipsDelaySlotFiller::searchRange(MachineBasicBlock &MBB, IterTy Begin,
IterTy End, RegDefsUses &RegDU,
InspectMemInstr &IM, Iter Slot,
IterTy &Filler) const {
for (IterTy I = Begin; I != End;) {
IterTy CurrI = I;
++I;
// skip debug value
if (CurrI->isDebugInstr())
continue;
if (terminateSearch(*CurrI))
break;
assert((!CurrI->isCall() && !CurrI->isReturn() && !CurrI->isBranch()) &&
"Cannot put calls, returns or branches in delay slot.");
if (CurrI->isKill()) {
CurrI->eraseFromParent();
continue;
}
if (delayHasHazard(*CurrI, RegDU, IM))
continue;
const MipsSubtarget &STI = MBB.getParent()->getSubtarget<MipsSubtarget>();
if (STI.isTargetNaCl()) {
// In NaCl, instructions that must be masked are forbidden in delay slots.
// We only check for loads, stores and SP changes. Calls, returns and
// branches are not checked because non-NaCl targets never put them in
// delay slots.
unsigned AddrIdx;
if ((isBasePlusOffsetMemoryAccess(CurrI->getOpcode(), &AddrIdx) &&
baseRegNeedsLoadStoreMask(CurrI->getOperand(AddrIdx).getReg())) ||
CurrI->modifiesRegister(Mips::SP, STI.getRegisterInfo()))
continue;
}
bool InMicroMipsMode = STI.inMicroMipsMode();
const MipsInstrInfo *TII = STI.getInstrInfo();
unsigned Opcode = (*Slot).getOpcode();
// This is complicated by the tail call optimization. For non-PIC code
// there is only a 32bit sized unconditional branch which can be assumed
// to be able to reach the target. b16 only has a range of +/- 1 KB.
// It's entirely possible that the target function is reachable with b16
// but we don't have enough information to make that decision.
if (InMicroMipsMode && TII->getInstSizeInBytes(*CurrI) == 2 &&
(Opcode == Mips::JR || Opcode == Mips::PseudoIndirectBranch ||
+ Opcode == Mips::PseudoIndirectBranch_MM ||
Opcode == Mips::PseudoReturn || Opcode == Mips::TAILCALL))
continue;
// Instructions LWP/SWP and MOVEP should not be in a delay slot as that
// results in unpredictable behaviour
if (InMicroMipsMode && (Opcode == Mips::LWP_MM || Opcode == Mips::SWP_MM ||
Opcode == Mips::MOVEP_MM))
continue;
Filler = CurrI;
return true;
}
return false;
}
bool MipsDelaySlotFiller::searchBackward(MachineBasicBlock &MBB,
MachineInstr &Slot) const {
if (DisableBackwardSearch)
return false;
auto *Fn = MBB.getParent();
RegDefsUses RegDU(*Fn->getSubtarget().getRegisterInfo());
MemDefsUses MemDU(Fn->getDataLayout(), &Fn->getFrameInfo());
ReverseIter Filler;
RegDU.init(Slot);
MachineBasicBlock::iterator SlotI = Slot;
if (!searchRange(MBB, ++SlotI.getReverse(), MBB.rend(), RegDU, MemDU, Slot,
Filler))
return false;
MBB.splice(std::next(SlotI), &MBB, Filler.getReverse());
MIBundleBuilder(MBB, SlotI, std::next(SlotI, 2));
++UsefulSlots;
return true;
}
bool MipsDelaySlotFiller::searchForward(MachineBasicBlock &MBB,
Iter Slot) const {
// Can handle only calls.
if (DisableForwardSearch || !Slot->isCall())
return false;
RegDefsUses RegDU(*MBB.getParent()->getSubtarget().getRegisterInfo());
NoMemInstr NM;
Iter Filler;
RegDU.setCallerSaved(*Slot);
if (!searchRange(MBB, std::next(Slot), MBB.end(), RegDU, NM, Slot, Filler))
return false;
MBB.splice(std::next(Slot), &MBB, Filler);
MIBundleBuilder(MBB, Slot, std::next(Slot, 2));
++UsefulSlots;
return true;
}
bool MipsDelaySlotFiller::searchSuccBBs(MachineBasicBlock &MBB,
Iter Slot) const {
if (DisableSuccBBSearch)
return false;
MachineBasicBlock *SuccBB = selectSuccBB(MBB);
if (!SuccBB)
return false;
RegDefsUses RegDU(*MBB.getParent()->getSubtarget().getRegisterInfo());
bool HasMultipleSuccs = false;
BB2BrMap BrMap;
std::unique_ptr<InspectMemInstr> IM;
Iter Filler;
auto *Fn = MBB.getParent();
// Iterate over SuccBB's predecessor list.
for (MachineBasicBlock::pred_iterator PI = SuccBB->pred_begin(),
PE = SuccBB->pred_end(); PI != PE; ++PI)
if (!examinePred(**PI, *SuccBB, RegDU, HasMultipleSuccs, BrMap))
return false;
// Do not allow moving instructions which have unallocatable register operands
// across basic block boundaries.
RegDU.setUnallocatableRegs(*Fn);
// Only allow moving loads from stack or constants if any of the SuccBB's
// predecessors have multiple successors.
if (HasMultipleSuccs) {
IM.reset(new LoadFromStackOrConst());
} else {
const MachineFrameInfo &MFI = Fn->getFrameInfo();
IM.reset(new MemDefsUses(Fn->getDataLayout(), &MFI));
}
if (!searchRange(MBB, SuccBB->begin(), SuccBB->end(), RegDU, *IM, Slot,
Filler))
return false;
insertDelayFiller(Filler, BrMap);
addLiveInRegs(Filler, *SuccBB);
Filler->eraseFromParent();
return true;
}
MachineBasicBlock *
MipsDelaySlotFiller::selectSuccBB(MachineBasicBlock &B) const {
if (B.succ_empty())
return nullptr;
// Select the successor with the larget edge weight.
auto &Prob = getAnalysis<MachineBranchProbabilityInfo>();
MachineBasicBlock *S = *std::max_element(
B.succ_begin(), B.succ_end(),
[&](const MachineBasicBlock *Dst0, const MachineBasicBlock *Dst1) {
return Prob.getEdgeProbability(&B, Dst0) <
Prob.getEdgeProbability(&B, Dst1);
});
return S->isEHPad() ? nullptr : S;
}
std::pair<MipsInstrInfo::BranchType, MachineInstr *>
MipsDelaySlotFiller::getBranch(MachineBasicBlock &MBB,
const MachineBasicBlock &Dst) const {
const MipsInstrInfo *TII =
MBB.getParent()->getSubtarget<MipsSubtarget>().getInstrInfo();
MachineBasicBlock *TrueBB = nullptr, *FalseBB = nullptr;
SmallVector<MachineInstr*, 2> BranchInstrs;
SmallVector<MachineOperand, 2> Cond;
MipsInstrInfo::BranchType R =
TII->analyzeBranch(MBB, TrueBB, FalseBB, Cond, false, BranchInstrs);
if ((R == MipsInstrInfo::BT_None) || (R == MipsInstrInfo::BT_NoBranch))
return std::make_pair(R, nullptr);
if (R != MipsInstrInfo::BT_CondUncond) {
if (!hasUnoccupiedSlot(BranchInstrs[0]))
return std::make_pair(MipsInstrInfo::BT_None, nullptr);
assert(((R != MipsInstrInfo::BT_Uncond) || (TrueBB == &Dst)));
return std::make_pair(R, BranchInstrs[0]);
}
assert((TrueBB == &Dst) || (FalseBB == &Dst));
// Examine the conditional branch. See if its slot is occupied.
if (hasUnoccupiedSlot(BranchInstrs[0]))
return std::make_pair(MipsInstrInfo::BT_Cond, BranchInstrs[0]);
// If that fails, try the unconditional branch.
if (hasUnoccupiedSlot(BranchInstrs[1]) && (FalseBB == &Dst))
return std::make_pair(MipsInstrInfo::BT_Uncond, BranchInstrs[1]);
return std::make_pair(MipsInstrInfo::BT_None, nullptr);
}
bool MipsDelaySlotFiller::examinePred(MachineBasicBlock &Pred,
const MachineBasicBlock &Succ,
RegDefsUses &RegDU,
bool &HasMultipleSuccs,
BB2BrMap &BrMap) const {
std::pair<MipsInstrInfo::BranchType, MachineInstr *> P =
getBranch(Pred, Succ);
// Return if either getBranch wasn't able to analyze the branches or there
// were no branches with unoccupied slots.
if (P.first == MipsInstrInfo::BT_None)
return false;
if ((P.first != MipsInstrInfo::BT_Uncond) &&
(P.first != MipsInstrInfo::BT_NoBranch)) {
HasMultipleSuccs = true;
RegDU.addLiveOut(Pred, Succ);
}
BrMap[&Pred] = P.second;
return true;
}
bool MipsDelaySlotFiller::delayHasHazard(const MachineInstr &Candidate,
RegDefsUses &RegDU,
InspectMemInstr &IM) const {
assert(!Candidate.isKill() &&
"KILL instructions should have been eliminated at this point.");
bool HasHazard = Candidate.isImplicitDef();
HasHazard |= IM.hasHazard(Candidate);
HasHazard |= RegDU.update(Candidate, 0, Candidate.getNumOperands());
return HasHazard;
}
bool MipsDelaySlotFiller::terminateSearch(const MachineInstr &Candidate) const {
return (Candidate.isTerminator() || Candidate.isCall() ||
Candidate.isPosition() || Candidate.isInlineAsm() ||
Candidate.hasUnmodeledSideEffects());
}
/// createMipsDelaySlotFillerPass - Returns a pass that fills in delay
/// slots in Mips MachineFunctions
FunctionPass *llvm::createMipsDelaySlotFillerPass() { return new MipsDelaySlotFiller(); }
Index: stable/11/contrib/llvm/lib/Target/Mips/MipsFastISel.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/Mips/MipsFastISel.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/Mips/MipsFastISel.cpp (revision 350259)
@@ -1,2141 +1,2154 @@
//===- MipsFastISel.cpp - Mips FastISel implementation --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines the MIPS-specific support for the FastISel class.
/// Some of the target-specific code is generated by tablegen in the file
/// MipsGenFastISel.inc, which is #included here.
///
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/MipsABIInfo.h"
#include "MCTargetDesc/MipsBaseInfo.h"
#include "MipsCCState.h"
#include "MipsISelLowering.h"
#include "MipsInstrInfo.h"
#include "MipsMachineFunction.h"
#include "MipsSubtarget.h"
#include "MipsTargetMachine.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/FastISel.h"
#include "llvm/CodeGen/FunctionLoweringInfo.h"
#include "llvm/CodeGen/ISDOpcodes.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GetElementPtrTypeIterator.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/Operator.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MachineValueType.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <array>
#include <cassert>
#include <cstdint>
#define DEBUG_TYPE "mips-fastisel"
using namespace llvm;
extern cl::opt<bool> EmitJalrReloc;
namespace {
class MipsFastISel final : public FastISel {
// All possible address modes.
class Address {
public:
using BaseKind = enum { RegBase, FrameIndexBase };
private:
BaseKind Kind = RegBase;
union {
unsigned Reg;
int FI;
} Base;
int64_t Offset = 0;
const GlobalValue *GV = nullptr;
public:
// Innocuous defaults for our address.
Address() { Base.Reg = 0; }
void setKind(BaseKind K) { Kind = K; }
BaseKind getKind() const { return Kind; }
bool isRegBase() const { return Kind == RegBase; }
bool isFIBase() const { return Kind == FrameIndexBase; }
void setReg(unsigned Reg) {
assert(isRegBase() && "Invalid base register access!");
Base.Reg = Reg;
}
unsigned getReg() const {
assert(isRegBase() && "Invalid base register access!");
return Base.Reg;
}
void setFI(unsigned FI) {
assert(isFIBase() && "Invalid base frame index access!");
Base.FI = FI;
}
unsigned getFI() const {
assert(isFIBase() && "Invalid base frame index access!");
return Base.FI;
}
void setOffset(int64_t Offset_) { Offset = Offset_; }
int64_t getOffset() const { return Offset; }
void setGlobalValue(const GlobalValue *G) { GV = G; }
const GlobalValue *getGlobalValue() { return GV; }
};
/// Subtarget - Keep a pointer to the MipsSubtarget around so that we can
/// make the right decision when generating code for different targets.
const TargetMachine &TM;
const MipsSubtarget *Subtarget;
const TargetInstrInfo &TII;
const TargetLowering &TLI;
MipsFunctionInfo *MFI;
// Convenience variables to avoid some queries.
LLVMContext *Context;
bool fastLowerArguments() override;
bool fastLowerCall(CallLoweringInfo &CLI) override;
bool fastLowerIntrinsicCall(const IntrinsicInst *II) override;
bool UnsupportedFPMode; // To allow fast-isel to proceed and just not handle
// floating point but not reject doing fast-isel in other
// situations
private:
// Selection routines.
bool selectLogicalOp(const Instruction *I);
bool selectLoad(const Instruction *I);
bool selectStore(const Instruction *I);
bool selectBranch(const Instruction *I);
bool selectSelect(const Instruction *I);
bool selectCmp(const Instruction *I);
bool selectFPExt(const Instruction *I);
bool selectFPTrunc(const Instruction *I);
bool selectFPToInt(const Instruction *I, bool IsSigned);
bool selectRet(const Instruction *I);
bool selectTrunc(const Instruction *I);
bool selectIntExt(const Instruction *I);
bool selectShift(const Instruction *I);
bool selectDivRem(const Instruction *I, unsigned ISDOpcode);
// Utility helper routines.
bool isTypeLegal(Type *Ty, MVT &VT);
bool isTypeSupported(Type *Ty, MVT &VT);
bool isLoadTypeLegal(Type *Ty, MVT &VT);
bool computeAddress(const Value *Obj, Address &Addr);
bool computeCallAddress(const Value *V, Address &Addr);
void simplifyAddress(Address &Addr);
// Emit helper routines.
bool emitCmp(unsigned DestReg, const CmpInst *CI);
bool emitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
unsigned Alignment = 0);
bool emitStore(MVT VT, unsigned SrcReg, Address Addr,
MachineMemOperand *MMO = nullptr);
bool emitStore(MVT VT, unsigned SrcReg, Address &Addr,
unsigned Alignment = 0);
unsigned emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt);
bool emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg,
bool IsZExt);
bool emitIntZExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg);
bool emitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg);
bool emitIntSExt32r1(MVT SrcVT, unsigned SrcReg, MVT DestVT,
unsigned DestReg);
bool emitIntSExt32r2(MVT SrcVT, unsigned SrcReg, MVT DestVT,
unsigned DestReg);
unsigned getRegEnsuringSimpleIntegerWidening(const Value *, bool IsUnsigned);
unsigned emitLogicalOp(unsigned ISDOpc, MVT RetVT, const Value *LHS,
const Value *RHS);
unsigned materializeFP(const ConstantFP *CFP, MVT VT);
unsigned materializeGV(const GlobalValue *GV, MVT VT);
unsigned materializeInt(const Constant *C, MVT VT);
unsigned materialize32BitInt(int64_t Imm, const TargetRegisterClass *RC);
unsigned materializeExternalCallSym(MCSymbol *Syn);
MachineInstrBuilder emitInst(unsigned Opc) {
return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
}
MachineInstrBuilder emitInst(unsigned Opc, unsigned DstReg) {
return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
DstReg);
}
MachineInstrBuilder emitInstStore(unsigned Opc, unsigned SrcReg,
unsigned MemReg, int64_t MemOffset) {
return emitInst(Opc).addReg(SrcReg).addReg(MemReg).addImm(MemOffset);
}
MachineInstrBuilder emitInstLoad(unsigned Opc, unsigned DstReg,
unsigned MemReg, int64_t MemOffset) {
return emitInst(Opc, DstReg).addReg(MemReg).addImm(MemOffset);
}
unsigned fastEmitInst_rr(unsigned MachineInstOpcode,
const TargetRegisterClass *RC,
unsigned Op0, bool Op0IsKill,
unsigned Op1, bool Op1IsKill);
// for some reason, this default is not generated by tablegen
// so we explicitly generate it here.
unsigned fastEmitInst_riir(uint64_t inst, const TargetRegisterClass *RC,
unsigned Op0, bool Op0IsKill, uint64_t imm1,
uint64_t imm2, unsigned Op3, bool Op3IsKill) {
return 0;
}
// Call handling routines.
private:
CCAssignFn *CCAssignFnForCall(CallingConv::ID CC) const;
bool processCallArgs(CallLoweringInfo &CLI, SmallVectorImpl<MVT> &ArgVTs,
unsigned &NumBytes);
bool finishCall(CallLoweringInfo &CLI, MVT RetVT, unsigned NumBytes);
const MipsABIInfo &getABI() const {
return static_cast<const MipsTargetMachine &>(TM).getABI();
}
public:
// Backend specific FastISel code.
explicit MipsFastISel(FunctionLoweringInfo &funcInfo,
const TargetLibraryInfo *libInfo)
: FastISel(funcInfo, libInfo), TM(funcInfo.MF->getTarget()),
Subtarget(&funcInfo.MF->getSubtarget<MipsSubtarget>()),
TII(*Subtarget->getInstrInfo()), TLI(*Subtarget->getTargetLowering()) {
MFI = funcInfo.MF->getInfo<MipsFunctionInfo>();
Context = &funcInfo.Fn->getContext();
UnsupportedFPMode = Subtarget->isFP64bit() || Subtarget->useSoftFloat();
}
unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
unsigned fastMaterializeConstant(const Constant *C) override;
bool fastSelectInstruction(const Instruction *I) override;
#include "MipsGenFastISel.inc"
};
} // end anonymous namespace
static bool CC_Mips(unsigned ValNo, MVT ValVT, MVT LocVT,
CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
CCState &State) LLVM_ATTRIBUTE_UNUSED;
static bool CC_MipsO32_FP32(unsigned ValNo, MVT ValVT, MVT LocVT,
CCValAssign::LocInfo LocInfo,
ISD::ArgFlagsTy ArgFlags, CCState &State) {
llvm_unreachable("should not be called");
}
static bool CC_MipsO32_FP64(unsigned ValNo, MVT ValVT, MVT LocVT,
CCValAssign::LocInfo LocInfo,
ISD::ArgFlagsTy ArgFlags, CCState &State) {
llvm_unreachable("should not be called");
}
#include "MipsGenCallingConv.inc"
CCAssignFn *MipsFastISel::CCAssignFnForCall(CallingConv::ID CC) const {
return CC_MipsO32;
}
unsigned MipsFastISel::emitLogicalOp(unsigned ISDOpc, MVT RetVT,
const Value *LHS, const Value *RHS) {
// Canonicalize immediates to the RHS first.
if (isa<ConstantInt>(LHS) && !isa<ConstantInt>(RHS))
std::swap(LHS, RHS);
unsigned Opc;
switch (ISDOpc) {
case ISD::AND:
Opc = Mips::AND;
break;
case ISD::OR:
Opc = Mips::OR;
break;
case ISD::XOR:
Opc = Mips::XOR;
break;
default:
llvm_unreachable("unexpected opcode");
}
unsigned LHSReg = getRegForValue(LHS);
if (!LHSReg)
return 0;
unsigned RHSReg;
if (const auto *C = dyn_cast<ConstantInt>(RHS))
RHSReg = materializeInt(C, MVT::i32);
else
RHSReg = getRegForValue(RHS);
if (!RHSReg)
return 0;
unsigned ResultReg = createResultReg(&Mips::GPR32RegClass);
if (!ResultReg)
return 0;
emitInst(Opc, ResultReg).addReg(LHSReg).addReg(RHSReg);
return ResultReg;
}
unsigned MipsFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
assert(TLI.getValueType(DL, AI->getType(), true) == MVT::i32 &&
"Alloca should always return a pointer.");
DenseMap<const AllocaInst *, int>::iterator SI =
FuncInfo.StaticAllocaMap.find(AI);
if (SI != FuncInfo.StaticAllocaMap.end()) {
unsigned ResultReg = createResultReg(&Mips::GPR32RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::LEA_ADDiu),
ResultReg)
.addFrameIndex(SI->second)
.addImm(0);
return ResultReg;
}
return 0;
}
unsigned MipsFastISel::materializeInt(const Constant *C, MVT VT) {
if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1)
return 0;
const TargetRegisterClass *RC = &Mips::GPR32RegClass;
const ConstantInt *CI = cast<ConstantInt>(C);
return materialize32BitInt(CI->getZExtValue(), RC);
}
unsigned MipsFastISel::materialize32BitInt(int64_t Imm,
const TargetRegisterClass *RC) {
unsigned ResultReg = createResultReg(RC);
if (isInt<16>(Imm)) {
unsigned Opc = Mips::ADDiu;
emitInst(Opc, ResultReg).addReg(Mips::ZERO).addImm(Imm);
return ResultReg;
} else if (isUInt<16>(Imm)) {
emitInst(Mips::ORi, ResultReg).addReg(Mips::ZERO).addImm(Imm);
return ResultReg;
}
unsigned Lo = Imm & 0xFFFF;
unsigned Hi = (Imm >> 16) & 0xFFFF;
if (Lo) {
// Both Lo and Hi have nonzero bits.
unsigned TmpReg = createResultReg(RC);
emitInst(Mips::LUi, TmpReg).addImm(Hi);
emitInst(Mips::ORi, ResultReg).addReg(TmpReg).addImm(Lo);
} else {
emitInst(Mips::LUi, ResultReg).addImm(Hi);
}
return ResultReg;
}
unsigned MipsFastISel::materializeFP(const ConstantFP *CFP, MVT VT) {
if (UnsupportedFPMode)
return 0;
int64_t Imm = CFP->getValueAPF().bitcastToAPInt().getZExtValue();
if (VT == MVT::f32) {
const TargetRegisterClass *RC = &Mips::FGR32RegClass;
unsigned DestReg = createResultReg(RC);
unsigned TempReg = materialize32BitInt(Imm, &Mips::GPR32RegClass);
emitInst(Mips::MTC1, DestReg).addReg(TempReg);
return DestReg;
} else if (VT == MVT::f64) {
const TargetRegisterClass *RC = &Mips::AFGR64RegClass;
unsigned DestReg = createResultReg(RC);
unsigned TempReg1 = materialize32BitInt(Imm >> 32, &Mips::GPR32RegClass);
unsigned TempReg2 =
materialize32BitInt(Imm & 0xFFFFFFFF, &Mips::GPR32RegClass);
emitInst(Mips::BuildPairF64, DestReg).addReg(TempReg2).addReg(TempReg1);
return DestReg;
}
return 0;
}
unsigned MipsFastISel::materializeGV(const GlobalValue *GV, MVT VT) {
// For now 32-bit only.
if (VT != MVT::i32)
return 0;
const TargetRegisterClass *RC = &Mips::GPR32RegClass;
unsigned DestReg = createResultReg(RC);
const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
bool IsThreadLocal = GVar && GVar->isThreadLocal();
// TLS not supported at this time.
if (IsThreadLocal)
return 0;
emitInst(Mips::LW, DestReg)
.addReg(MFI->getGlobalBaseReg())
.addGlobalAddress(GV, 0, MipsII::MO_GOT);
if ((GV->hasInternalLinkage() ||
(GV->hasLocalLinkage() && !isa<Function>(GV)))) {
unsigned TempReg = createResultReg(RC);
emitInst(Mips::ADDiu, TempReg)
.addReg(DestReg)
.addGlobalAddress(GV, 0, MipsII::MO_ABS_LO);
DestReg = TempReg;
}
return DestReg;
}
unsigned MipsFastISel::materializeExternalCallSym(MCSymbol *Sym) {
const TargetRegisterClass *RC = &Mips::GPR32RegClass;
unsigned DestReg = createResultReg(RC);
emitInst(Mips::LW, DestReg)
.addReg(MFI->getGlobalBaseReg())
.addSym(Sym, MipsII::MO_GOT);
return DestReg;
}
// Materialize a constant into a register, and return the register
// number (or zero if we failed to handle it).
unsigned MipsFastISel::fastMaterializeConstant(const Constant *C) {
EVT CEVT = TLI.getValueType(DL, C->getType(), true);
// Only handle simple types.
if (!CEVT.isSimple())
return 0;
MVT VT = CEVT.getSimpleVT();
if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C))
return (UnsupportedFPMode) ? 0 : materializeFP(CFP, VT);
else if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
return materializeGV(GV, VT);
else if (isa<ConstantInt>(C))
return materializeInt(C, VT);
return 0;
}
bool MipsFastISel::computeAddress(const Value *Obj, Address &Addr) {
const User *U = nullptr;
unsigned Opcode = Instruction::UserOp1;
if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
// Don't walk into other basic blocks unless the object is an alloca from
// another block, otherwise it may not have a virtual register assigned.
if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
Opcode = I->getOpcode();
U = I;
}
} else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
Opcode = C->getOpcode();
U = C;
}
switch (Opcode) {
default:
break;
case Instruction::BitCast:
// Look through bitcasts.
return computeAddress(U->getOperand(0), Addr);
case Instruction::GetElementPtr: {
Address SavedAddr = Addr;
int64_t TmpOffset = Addr.getOffset();
// Iterate through the GEP folding the constants into offsets where
// we can.
gep_type_iterator GTI = gep_type_begin(U);
for (User::const_op_iterator i = U->op_begin() + 1, e = U->op_end(); i != e;
++i, ++GTI) {
const Value *Op = *i;
if (StructType *STy = GTI.getStructTypeOrNull()) {
const StructLayout *SL = DL.getStructLayout(STy);
unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
TmpOffset += SL->getElementOffset(Idx);
} else {
uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
while (true) {
if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
// Constant-offset addressing.
TmpOffset += CI->getSExtValue() * S;
break;
}
if (canFoldAddIntoGEP(U, Op)) {
// A compatible add with a constant operand. Fold the constant.
ConstantInt *CI =
cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
TmpOffset += CI->getSExtValue() * S;
// Iterate on the other operand.
Op = cast<AddOperator>(Op)->getOperand(0);
continue;
}
// Unsupported
goto unsupported_gep;
}
}
}
// Try to grab the base operand now.
Addr.setOffset(TmpOffset);
if (computeAddress(U->getOperand(0), Addr))
return true;
// We failed, restore everything and try the other options.
Addr = SavedAddr;
unsupported_gep:
break;
}
case Instruction::Alloca: {
const AllocaInst *AI = cast<AllocaInst>(Obj);
DenseMap<const AllocaInst *, int>::iterator SI =
FuncInfo.StaticAllocaMap.find(AI);
if (SI != FuncInfo.StaticAllocaMap.end()) {
Addr.setKind(Address::FrameIndexBase);
Addr.setFI(SI->second);
return true;
}
break;
}
}
Addr.setReg(getRegForValue(Obj));
return Addr.getReg() != 0;
}
bool MipsFastISel::computeCallAddress(const Value *V, Address &Addr) {
const User *U = nullptr;
unsigned Opcode = Instruction::UserOp1;
if (const auto *I = dyn_cast<Instruction>(V)) {
// Check if the value is defined in the same basic block. This information
// is crucial to know whether or not folding an operand is valid.
if (I->getParent() == FuncInfo.MBB->getBasicBlock()) {
Opcode = I->getOpcode();
U = I;
}
} else if (const auto *C = dyn_cast<ConstantExpr>(V)) {
Opcode = C->getOpcode();
U = C;
}
switch (Opcode) {
default:
break;
case Instruction::BitCast:
// Look past bitcasts if its operand is in the same BB.
return computeCallAddress(U->getOperand(0), Addr);
break;
case Instruction::IntToPtr:
// Look past no-op inttoptrs if its operand is in the same BB.
if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
TLI.getPointerTy(DL))
return computeCallAddress(U->getOperand(0), Addr);
break;
case Instruction::PtrToInt:
// Look past no-op ptrtoints if its operand is in the same BB.
if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
return computeCallAddress(U->getOperand(0), Addr);
break;
}
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
Addr.setGlobalValue(GV);
return true;
}
// If all else fails, try to materialize the value in a register.
if (!Addr.getGlobalValue()) {
Addr.setReg(getRegForValue(V));
return Addr.getReg() != 0;
}
return false;
}
bool MipsFastISel::isTypeLegal(Type *Ty, MVT &VT) {
EVT evt = TLI.getValueType(DL, Ty, true);
// Only handle simple types.
if (evt == MVT::Other || !evt.isSimple())
return false;
VT = evt.getSimpleVT();
// Handle all legal types, i.e. a register that will directly hold this
// value.
return TLI.isTypeLegal(VT);
}
bool MipsFastISel::isTypeSupported(Type *Ty, MVT &VT) {
if (Ty->isVectorTy())
return false;
if (isTypeLegal(Ty, VT))
return true;
// If this is a type than can be sign or zero-extended to a basic operation
// go ahead and accept it now.
if (VT == MVT::i1 || VT == MVT::i8 || VT == MVT::i16)
return true;
return false;
}
bool MipsFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) {
if (isTypeLegal(Ty, VT))
return true;
// We will extend this in a later patch:
// If this is a type than can be sign or zero-extended to a basic operation
// go ahead and accept it now.
if (VT == MVT::i8 || VT == MVT::i16)
return true;
return false;
}
// Because of how EmitCmp is called with fast-isel, you can
// end up with redundant "andi" instructions after the sequences emitted below.
// We should try and solve this issue in the future.
//
bool MipsFastISel::emitCmp(unsigned ResultReg, const CmpInst *CI) {
const Value *Left = CI->getOperand(0), *Right = CI->getOperand(1);
bool IsUnsigned = CI->isUnsigned();
unsigned LeftReg = getRegEnsuringSimpleIntegerWidening(Left, IsUnsigned);
if (LeftReg == 0)
return false;
unsigned RightReg = getRegEnsuringSimpleIntegerWidening(Right, IsUnsigned);
if (RightReg == 0)
return false;
CmpInst::Predicate P = CI->getPredicate();
switch (P) {
default:
return false;
case CmpInst::ICMP_EQ: {
unsigned TempReg = createResultReg(&Mips::GPR32RegClass);
emitInst(Mips::XOR, TempReg).addReg(LeftReg).addReg(RightReg);
emitInst(Mips::SLTiu, ResultReg).addReg(TempReg).addImm(1);
break;
}
case CmpInst::ICMP_NE: {
unsigned TempReg = createResultReg(&Mips::GPR32RegClass);
emitInst(Mips::XOR, TempReg).addReg(LeftReg).addReg(RightReg);
emitInst(Mips::SLTu, ResultReg).addReg(Mips::ZERO).addReg(TempReg);
break;
}
case CmpInst::ICMP_UGT:
emitInst(Mips::SLTu, ResultReg).addReg(RightReg).addReg(LeftReg);
break;
case CmpInst::ICMP_ULT:
emitInst(Mips::SLTu, ResultReg).addReg(LeftReg).addReg(RightReg);
break;
case CmpInst::ICMP_UGE: {
unsigned TempReg = createResultReg(&Mips::GPR32RegClass);
emitInst(Mips::SLTu, TempReg).addReg(LeftReg).addReg(RightReg);
emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1);
break;
}
case CmpInst::ICMP_ULE: {
unsigned TempReg = createResultReg(&Mips::GPR32RegClass);
emitInst(Mips::SLTu, TempReg).addReg(RightReg).addReg(LeftReg);
emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1);
break;
}
case CmpInst::ICMP_SGT:
emitInst(Mips::SLT, ResultReg).addReg(RightReg).addReg(LeftReg);
break;
case CmpInst::ICMP_SLT:
emitInst(Mips::SLT, ResultReg).addReg(LeftReg).addReg(RightReg);
break;
case CmpInst::ICMP_SGE: {
unsigned TempReg = createResultReg(&Mips::GPR32RegClass);
emitInst(Mips::SLT, TempReg).addReg(LeftReg).addReg(RightReg);
emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1);
break;
}
case CmpInst::ICMP_SLE: {
unsigned TempReg = createResultReg(&Mips::GPR32RegClass);
emitInst(Mips::SLT, TempReg).addReg(RightReg).addReg(LeftReg);
emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1);
break;
}
case CmpInst::FCMP_OEQ:
case CmpInst::FCMP_UNE:
case CmpInst::FCMP_OLT:
case CmpInst::FCMP_OLE:
case CmpInst::FCMP_OGT:
case CmpInst::FCMP_OGE: {
if (UnsupportedFPMode)
return false;
bool IsFloat = Left->getType()->isFloatTy();
bool IsDouble = Left->getType()->isDoubleTy();
if (!IsFloat && !IsDouble)
return false;
unsigned Opc, CondMovOpc;
switch (P) {
case CmpInst::FCMP_OEQ:
Opc = IsFloat ? Mips::C_EQ_S : Mips::C_EQ_D32;
CondMovOpc = Mips::MOVT_I;
break;
case CmpInst::FCMP_UNE:
Opc = IsFloat ? Mips::C_EQ_S : Mips::C_EQ_D32;
CondMovOpc = Mips::MOVF_I;
break;
case CmpInst::FCMP_OLT:
Opc = IsFloat ? Mips::C_OLT_S : Mips::C_OLT_D32;
CondMovOpc = Mips::MOVT_I;
break;
case CmpInst::FCMP_OLE:
Opc = IsFloat ? Mips::C_OLE_S : Mips::C_OLE_D32;
CondMovOpc = Mips::MOVT_I;
break;
case CmpInst::FCMP_OGT:
Opc = IsFloat ? Mips::C_ULE_S : Mips::C_ULE_D32;
CondMovOpc = Mips::MOVF_I;
break;
case CmpInst::FCMP_OGE:
Opc = IsFloat ? Mips::C_ULT_S : Mips::C_ULT_D32;
CondMovOpc = Mips::MOVF_I;
break;
default:
llvm_unreachable("Only switching of a subset of CCs.");
}
unsigned RegWithZero = createResultReg(&Mips::GPR32RegClass);
unsigned RegWithOne = createResultReg(&Mips::GPR32RegClass);
emitInst(Mips::ADDiu, RegWithZero).addReg(Mips::ZERO).addImm(0);
emitInst(Mips::ADDiu, RegWithOne).addReg(Mips::ZERO).addImm(1);
emitInst(Opc).addReg(Mips::FCC0, RegState::Define).addReg(LeftReg)
.addReg(RightReg);
emitInst(CondMovOpc, ResultReg)
.addReg(RegWithOne)
.addReg(Mips::FCC0)
.addReg(RegWithZero);
break;
}
}
return true;
}
bool MipsFastISel::emitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
unsigned Alignment) {
//
// more cases will be handled here in following patches.
//
unsigned Opc;
switch (VT.SimpleTy) {
case MVT::i32:
ResultReg = createResultReg(&Mips::GPR32RegClass);
Opc = Mips::LW;
break;
case MVT::i16:
ResultReg = createResultReg(&Mips::GPR32RegClass);
Opc = Mips::LHu;
break;
case MVT::i8:
ResultReg = createResultReg(&Mips::GPR32RegClass);
Opc = Mips::LBu;
break;
case MVT::f32:
if (UnsupportedFPMode)
return false;
ResultReg = createResultReg(&Mips::FGR32RegClass);
Opc = Mips::LWC1;
break;
case MVT::f64:
if (UnsupportedFPMode)
return false;
ResultReg = createResultReg(&Mips::AFGR64RegClass);
Opc = Mips::LDC1;
break;
default:
return false;
}
if (Addr.isRegBase()) {
simplifyAddress(Addr);
emitInstLoad(Opc, ResultReg, Addr.getReg(), Addr.getOffset());
return true;
}
if (Addr.isFIBase()) {
unsigned FI = Addr.getFI();
unsigned Align = 4;
int64_t Offset = Addr.getOffset();
MachineFrameInfo &MFI = MF->getFrameInfo();
MachineMemOperand *MMO = MF->getMachineMemOperand(
MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad,
MFI.getObjectSize(FI), Align);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
.addFrameIndex(FI)
.addImm(Offset)
.addMemOperand(MMO);
return true;
}
return false;
}
bool MipsFastISel::emitStore(MVT VT, unsigned SrcReg, Address &Addr,
unsigned Alignment) {
//
// more cases will be handled here in following patches.
//
unsigned Opc;
switch (VT.SimpleTy) {
case MVT::i8:
Opc = Mips::SB;
break;
case MVT::i16:
Opc = Mips::SH;
break;
case MVT::i32:
Opc = Mips::SW;
break;
case MVT::f32:
if (UnsupportedFPMode)
return false;
Opc = Mips::SWC1;
break;
case MVT::f64:
if (UnsupportedFPMode)
return false;
Opc = Mips::SDC1;
break;
default:
return false;
}
if (Addr.isRegBase()) {
simplifyAddress(Addr);
emitInstStore(Opc, SrcReg, Addr.getReg(), Addr.getOffset());
return true;
}
if (Addr.isFIBase()) {
unsigned FI = Addr.getFI();
unsigned Align = 4;
int64_t Offset = Addr.getOffset();
MachineFrameInfo &MFI = MF->getFrameInfo();
MachineMemOperand *MMO = MF->getMachineMemOperand(
MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore,
MFI.getObjectSize(FI), Align);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
.addReg(SrcReg)
.addFrameIndex(FI)
.addImm(Offset)
.addMemOperand(MMO);
return true;
}
return false;
}
bool MipsFastISel::selectLogicalOp(const Instruction *I) {
MVT VT;
if (!isTypeSupported(I->getType(), VT))
return false;
unsigned ResultReg;
switch (I->getOpcode()) {
default:
llvm_unreachable("Unexpected instruction.");
case Instruction::And:
ResultReg = emitLogicalOp(ISD::AND, VT, I->getOperand(0), I->getOperand(1));
break;
case Instruction::Or:
ResultReg = emitLogicalOp(ISD::OR, VT, I->getOperand(0), I->getOperand(1));
break;
case Instruction::Xor:
ResultReg = emitLogicalOp(ISD::XOR, VT, I->getOperand(0), I->getOperand(1));
break;
}
if (!ResultReg)
return false;
updateValueMap(I, ResultReg);
return true;
}
bool MipsFastISel::selectLoad(const Instruction *I) {
// Atomic loads need special handling.
if (cast<LoadInst>(I)->isAtomic())
return false;
// Verify we have a legal type before going any further.
MVT VT;
if (!isLoadTypeLegal(I->getType(), VT))
return false;
// See if we can handle this address.
Address Addr;
if (!computeAddress(I->getOperand(0), Addr))
return false;
unsigned ResultReg;
if (!emitLoad(VT, ResultReg, Addr, cast<LoadInst>(I)->getAlignment()))
return false;
updateValueMap(I, ResultReg);
return true;
}
bool MipsFastISel::selectStore(const Instruction *I) {
Value *Op0 = I->getOperand(0);
unsigned SrcReg = 0;
// Atomic stores need special handling.
if (cast<StoreInst>(I)->isAtomic())
return false;
// Verify we have a legal type before going any further.
MVT VT;
if (!isLoadTypeLegal(I->getOperand(0)->getType(), VT))
return false;
// Get the value to be stored into a register.
SrcReg = getRegForValue(Op0);
if (SrcReg == 0)
return false;
// See if we can handle this address.
Address Addr;
if (!computeAddress(I->getOperand(1), Addr))
return false;
if (!emitStore(VT, SrcReg, Addr, cast<StoreInst>(I)->getAlignment()))
return false;
return true;
}
// This can cause a redundant sltiu to be generated.
// FIXME: try and eliminate this in a future patch.
bool MipsFastISel::selectBranch(const Instruction *I) {
const BranchInst *BI = cast<BranchInst>(I);
MachineBasicBlock *BrBB = FuncInfo.MBB;
//
// TBB is the basic block for the case where the comparison is true.
// FBB is the basic block for the case where the comparison is false.
// if (cond) goto TBB
// goto FBB
// TBB:
//
MachineBasicBlock *TBB = FuncInfo.MBBMap[BI->getSuccessor(0)];
MachineBasicBlock *FBB = FuncInfo.MBBMap[BI->getSuccessor(1)];
- // For now, just try the simplest case where it's fed by a compare.
+
+ // Fold the common case of a conditional branch with a comparison
+ // in the same block.
+ unsigned ZExtCondReg = 0;
if (const CmpInst *CI = dyn_cast<CmpInst>(BI->getCondition())) {
- MVT CIMVT =
- TLI.getValueType(DL, CI->getOperand(0)->getType(), true).getSimpleVT();
- if (CIMVT == MVT::i1)
+ if (CI->hasOneUse() && CI->getParent() == I->getParent()) {
+ ZExtCondReg = createResultReg(&Mips::GPR32RegClass);
+ if (!emitCmp(ZExtCondReg, CI))
+ return false;
+ }
+ }
+
+ // For the general case, we need to mask with 1.
+ if (ZExtCondReg == 0) {
+ unsigned CondReg = getRegForValue(BI->getCondition());
+ if (CondReg == 0)
return false;
- unsigned CondReg = getRegForValue(CI);
- BuildMI(*BrBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::BGTZ))
- .addReg(CondReg)
- .addMBB(TBB);
- finishCondBranch(BI->getParent(), TBB, FBB);
- return true;
+ ZExtCondReg = emitIntExt(MVT::i1, CondReg, MVT::i32, true);
+ if (ZExtCondReg == 0)
+ return false;
}
- return false;
+
+ BuildMI(*BrBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::BGTZ))
+ .addReg(ZExtCondReg)
+ .addMBB(TBB);
+ finishCondBranch(BI->getParent(), TBB, FBB);
+ return true;
}
bool MipsFastISel::selectCmp(const Instruction *I) {
const CmpInst *CI = cast<CmpInst>(I);
unsigned ResultReg = createResultReg(&Mips::GPR32RegClass);
if (!emitCmp(ResultReg, CI))
return false;
updateValueMap(I, ResultReg);
return true;
}
// Attempt to fast-select a floating-point extend instruction.
bool MipsFastISel::selectFPExt(const Instruction *I) {
if (UnsupportedFPMode)
return false;
Value *Src = I->getOperand(0);
EVT SrcVT = TLI.getValueType(DL, Src->getType(), true);
EVT DestVT = TLI.getValueType(DL, I->getType(), true);
if (SrcVT != MVT::f32 || DestVT != MVT::f64)
return false;
unsigned SrcReg =
getRegForValue(Src); // this must be a 32bit floating point register class
// maybe we should handle this differently
if (!SrcReg)
return false;
unsigned DestReg = createResultReg(&Mips::AFGR64RegClass);
emitInst(Mips::CVT_D32_S, DestReg).addReg(SrcReg);
updateValueMap(I, DestReg);
return true;
}
bool MipsFastISel::selectSelect(const Instruction *I) {
assert(isa<SelectInst>(I) && "Expected a select instruction.");
LLVM_DEBUG(dbgs() << "selectSelect\n");
MVT VT;
if (!isTypeSupported(I->getType(), VT) || UnsupportedFPMode) {
LLVM_DEBUG(
dbgs() << ".. .. gave up (!isTypeSupported || UnsupportedFPMode)\n");
return false;
}
unsigned CondMovOpc;
const TargetRegisterClass *RC;
if (VT.isInteger() && !VT.isVector() && VT.getSizeInBits() <= 32) {
CondMovOpc = Mips::MOVN_I_I;
RC = &Mips::GPR32RegClass;
} else if (VT == MVT::f32) {
CondMovOpc = Mips::MOVN_I_S;
RC = &Mips::FGR32RegClass;
} else if (VT == MVT::f64) {
CondMovOpc = Mips::MOVN_I_D32;
RC = &Mips::AFGR64RegClass;
} else
return false;
const SelectInst *SI = cast<SelectInst>(I);
const Value *Cond = SI->getCondition();
unsigned Src1Reg = getRegForValue(SI->getTrueValue());
unsigned Src2Reg = getRegForValue(SI->getFalseValue());
unsigned CondReg = getRegForValue(Cond);
if (!Src1Reg || !Src2Reg || !CondReg)
return false;
unsigned ZExtCondReg = createResultReg(&Mips::GPR32RegClass);
if (!ZExtCondReg)
return false;
if (!emitIntExt(MVT::i1, CondReg, MVT::i32, ZExtCondReg, true))
return false;
unsigned ResultReg = createResultReg(RC);
unsigned TempReg = createResultReg(RC);
if (!ResultReg || !TempReg)
return false;
emitInst(TargetOpcode::COPY, TempReg).addReg(Src2Reg);
emitInst(CondMovOpc, ResultReg)
.addReg(Src1Reg).addReg(ZExtCondReg).addReg(TempReg);
updateValueMap(I, ResultReg);
return true;
}
// Attempt to fast-select a floating-point truncate instruction.
bool MipsFastISel::selectFPTrunc(const Instruction *I) {
if (UnsupportedFPMode)
return false;
Value *Src = I->getOperand(0);
EVT SrcVT = TLI.getValueType(DL, Src->getType(), true);
EVT DestVT = TLI.getValueType(DL, I->getType(), true);
if (SrcVT != MVT::f64 || DestVT != MVT::f32)
return false;
unsigned SrcReg = getRegForValue(Src);
if (!SrcReg)
return false;
unsigned DestReg = createResultReg(&Mips::FGR32RegClass);
if (!DestReg)
return false;
emitInst(Mips::CVT_S_D32, DestReg).addReg(SrcReg);
updateValueMap(I, DestReg);
return true;
}
// Attempt to fast-select a floating-point-to-integer conversion.
bool MipsFastISel::selectFPToInt(const Instruction *I, bool IsSigned) {
if (UnsupportedFPMode)
return false;
MVT DstVT, SrcVT;
if (!IsSigned)
return false; // We don't handle this case yet. There is no native
// instruction for this but it can be synthesized.
Type *DstTy = I->getType();
if (!isTypeLegal(DstTy, DstVT))
return false;
if (DstVT != MVT::i32)
return false;
Value *Src = I->getOperand(0);
Type *SrcTy = Src->getType();
if (!isTypeLegal(SrcTy, SrcVT))
return false;
if (SrcVT != MVT::f32 && SrcVT != MVT::f64)
return false;
unsigned SrcReg = getRegForValue(Src);
if (SrcReg == 0)
return false;
// Determine the opcode for the conversion, which takes place
// entirely within FPRs.
unsigned DestReg = createResultReg(&Mips::GPR32RegClass);
unsigned TempReg = createResultReg(&Mips::FGR32RegClass);
unsigned Opc = (SrcVT == MVT::f32) ? Mips::TRUNC_W_S : Mips::TRUNC_W_D32;
// Generate the convert.
emitInst(Opc, TempReg).addReg(SrcReg);
emitInst(Mips::MFC1, DestReg).addReg(TempReg);
updateValueMap(I, DestReg);
return true;
}
bool MipsFastISel::processCallArgs(CallLoweringInfo &CLI,
SmallVectorImpl<MVT> &OutVTs,
unsigned &NumBytes) {
CallingConv::ID CC = CLI.CallConv;
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CC, false, *FuncInfo.MF, ArgLocs, *Context);
CCInfo.AnalyzeCallOperands(OutVTs, CLI.OutFlags, CCAssignFnForCall(CC));
// Get a count of how many bytes are to be pushed on the stack.
NumBytes = CCInfo.getNextStackOffset();
// This is the minimum argument area used for A0-A3.
if (NumBytes < 16)
NumBytes = 16;
emitInst(Mips::ADJCALLSTACKDOWN).addImm(16).addImm(0);
// Process the args.
MVT firstMVT;
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
const Value *ArgVal = CLI.OutVals[VA.getValNo()];
MVT ArgVT = OutVTs[VA.getValNo()];
if (i == 0) {
firstMVT = ArgVT;
if (ArgVT == MVT::f32) {
VA.convertToReg(Mips::F12);
} else if (ArgVT == MVT::f64) {
VA.convertToReg(Mips::D6);
}
} else if (i == 1) {
if ((firstMVT == MVT::f32) || (firstMVT == MVT::f64)) {
if (ArgVT == MVT::f32) {
VA.convertToReg(Mips::F14);
} else if (ArgVT == MVT::f64) {
VA.convertToReg(Mips::D7);
}
}
}
if (((ArgVT == MVT::i32) || (ArgVT == MVT::f32) || (ArgVT == MVT::i16) ||
(ArgVT == MVT::i8)) &&
VA.isMemLoc()) {
switch (VA.getLocMemOffset()) {
case 0:
VA.convertToReg(Mips::A0);
break;
case 4:
VA.convertToReg(Mips::A1);
break;
case 8:
VA.convertToReg(Mips::A2);
break;
case 12:
VA.convertToReg(Mips::A3);
break;
default:
break;
}
}
unsigned ArgReg = getRegForValue(ArgVal);
if (!ArgReg)
return false;
// Handle arg promotion: SExt, ZExt, AExt.
switch (VA.getLocInfo()) {
case CCValAssign::Full:
break;
case CCValAssign::AExt:
case CCValAssign::SExt: {
MVT DestVT = VA.getLocVT();
MVT SrcVT = ArgVT;
ArgReg = emitIntExt(SrcVT, ArgReg, DestVT, /*isZExt=*/false);
if (!ArgReg)
return false;
break;
}
case CCValAssign::ZExt: {
MVT DestVT = VA.getLocVT();
MVT SrcVT = ArgVT;
ArgReg = emitIntExt(SrcVT, ArgReg, DestVT, /*isZExt=*/true);
if (!ArgReg)
return false;
break;
}
default:
llvm_unreachable("Unknown arg promotion!");
}
// Now copy/store arg to correct locations.
if (VA.isRegLoc() && !VA.needsCustom()) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), VA.getLocReg()).addReg(ArgReg);
CLI.OutRegs.push_back(VA.getLocReg());
} else if (VA.needsCustom()) {
llvm_unreachable("Mips does not use custom args.");
return false;
} else {
//
// FIXME: This path will currently return false. It was copied
// from the AArch64 port and should be essentially fine for Mips too.
// The work to finish up this path will be done in a follow-on patch.
//
assert(VA.isMemLoc() && "Assuming store on stack.");
// Don't emit stores for undef values.
if (isa<UndefValue>(ArgVal))
continue;
// Need to store on the stack.
// FIXME: This alignment is incorrect but this path is disabled
// for now (will return false). We need to determine the right alignment
// based on the normal alignment for the underlying machine type.
//
unsigned ArgSize = alignTo(ArgVT.getSizeInBits(), 4);
unsigned BEAlign = 0;
if (ArgSize < 8 && !Subtarget->isLittle())
BEAlign = 8 - ArgSize;
Address Addr;
Addr.setKind(Address::RegBase);
Addr.setReg(Mips::SP);
Addr.setOffset(VA.getLocMemOffset() + BEAlign);
unsigned Alignment = DL.getABITypeAlignment(ArgVal->getType());
MachineMemOperand *MMO = FuncInfo.MF->getMachineMemOperand(
MachinePointerInfo::getStack(*FuncInfo.MF, Addr.getOffset()),
MachineMemOperand::MOStore, ArgVT.getStoreSize(), Alignment);
(void)(MMO);
// if (!emitStore(ArgVT, ArgReg, Addr, MMO))
return false; // can't store on the stack yet.
}
}
return true;
}
bool MipsFastISel::finishCall(CallLoweringInfo &CLI, MVT RetVT,
unsigned NumBytes) {
CallingConv::ID CC = CLI.CallConv;
emitInst(Mips::ADJCALLSTACKUP).addImm(16).addImm(0);
if (RetVT != MVT::isVoid) {
SmallVector<CCValAssign, 16> RVLocs;
MipsCCState CCInfo(CC, false, *FuncInfo.MF, RVLocs, *Context);
CCInfo.AnalyzeCallResult(CLI.Ins, RetCC_Mips, CLI.RetTy,
CLI.Symbol ? CLI.Symbol->getName().data()
: nullptr);
// Only handle a single return value.
if (RVLocs.size() != 1)
return false;
// Copy all of the result registers out of their specified physreg.
MVT CopyVT = RVLocs[0].getValVT();
// Special handling for extended integers.
if (RetVT == MVT::i1 || RetVT == MVT::i8 || RetVT == MVT::i16)
CopyVT = MVT::i32;
unsigned ResultReg = createResultReg(TLI.getRegClassFor(CopyVT));
if (!ResultReg)
return false;
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY),
ResultReg).addReg(RVLocs[0].getLocReg());
CLI.InRegs.push_back(RVLocs[0].getLocReg());
CLI.ResultReg = ResultReg;
CLI.NumResultRegs = 1;
}
return true;
}
bool MipsFastISel::fastLowerArguments() {
LLVM_DEBUG(dbgs() << "fastLowerArguments\n");
if (!FuncInfo.CanLowerReturn) {
LLVM_DEBUG(dbgs() << ".. gave up (!CanLowerReturn)\n");
return false;
}
const Function *F = FuncInfo.Fn;
if (F->isVarArg()) {
LLVM_DEBUG(dbgs() << ".. gave up (varargs)\n");
return false;
}
CallingConv::ID CC = F->getCallingConv();
if (CC != CallingConv::C) {
LLVM_DEBUG(dbgs() << ".. gave up (calling convention is not C)\n");
return false;
}
std::array<MCPhysReg, 4> GPR32ArgRegs = {{Mips::A0, Mips::A1, Mips::A2,
Mips::A3}};
std::array<MCPhysReg, 2> FGR32ArgRegs = {{Mips::F12, Mips::F14}};
std::array<MCPhysReg, 2> AFGR64ArgRegs = {{Mips::D6, Mips::D7}};
auto NextGPR32 = GPR32ArgRegs.begin();
auto NextFGR32 = FGR32ArgRegs.begin();
auto NextAFGR64 = AFGR64ArgRegs.begin();
struct AllocatedReg {
const TargetRegisterClass *RC;
unsigned Reg;
AllocatedReg(const TargetRegisterClass *RC, unsigned Reg)
: RC(RC), Reg(Reg) {}
};
// Only handle simple cases. i.e. All arguments are directly mapped to
// registers of the appropriate type.
SmallVector<AllocatedReg, 4> Allocation;
for (const auto &FormalArg : F->args()) {
if (FormalArg.hasAttribute(Attribute::InReg) ||
FormalArg.hasAttribute(Attribute::StructRet) ||
FormalArg.hasAttribute(Attribute::ByVal)) {
LLVM_DEBUG(dbgs() << ".. gave up (inreg, structret, byval)\n");
return false;
}
Type *ArgTy = FormalArg.getType();
if (ArgTy->isStructTy() || ArgTy->isArrayTy() || ArgTy->isVectorTy()) {
LLVM_DEBUG(dbgs() << ".. gave up (struct, array, or vector)\n");
return false;
}
EVT ArgVT = TLI.getValueType(DL, ArgTy);
LLVM_DEBUG(dbgs() << ".. " << FormalArg.getArgNo() << ": "
<< ArgVT.getEVTString() << "\n");
if (!ArgVT.isSimple()) {
LLVM_DEBUG(dbgs() << ".. .. gave up (not a simple type)\n");
return false;
}
switch (ArgVT.getSimpleVT().SimpleTy) {
case MVT::i1:
case MVT::i8:
case MVT::i16:
if (!FormalArg.hasAttribute(Attribute::SExt) &&
!FormalArg.hasAttribute(Attribute::ZExt)) {
// It must be any extend, this shouldn't happen for clang-generated IR
// so just fall back on SelectionDAG.
LLVM_DEBUG(dbgs() << ".. .. gave up (i8/i16 arg is not extended)\n");
return false;
}
if (NextGPR32 == GPR32ArgRegs.end()) {
LLVM_DEBUG(dbgs() << ".. .. gave up (ran out of GPR32 arguments)\n");
return false;
}
LLVM_DEBUG(dbgs() << ".. .. GPR32(" << *NextGPR32 << ")\n");
Allocation.emplace_back(&Mips::GPR32RegClass, *NextGPR32++);
// Allocating any GPR32 prohibits further use of floating point arguments.
NextFGR32 = FGR32ArgRegs.end();
NextAFGR64 = AFGR64ArgRegs.end();
break;
case MVT::i32:
if (FormalArg.hasAttribute(Attribute::ZExt)) {
// The O32 ABI does not permit a zero-extended i32.
LLVM_DEBUG(dbgs() << ".. .. gave up (i32 arg is zero extended)\n");
return false;
}
if (NextGPR32 == GPR32ArgRegs.end()) {
LLVM_DEBUG(dbgs() << ".. .. gave up (ran out of GPR32 arguments)\n");
return false;
}
LLVM_DEBUG(dbgs() << ".. .. GPR32(" << *NextGPR32 << ")\n");
Allocation.emplace_back(&Mips::GPR32RegClass, *NextGPR32++);
// Allocating any GPR32 prohibits further use of floating point arguments.
NextFGR32 = FGR32ArgRegs.end();
NextAFGR64 = AFGR64ArgRegs.end();
break;
case MVT::f32:
if (UnsupportedFPMode) {
LLVM_DEBUG(dbgs() << ".. .. gave up (UnsupportedFPMode)\n");
return false;
}
if (NextFGR32 == FGR32ArgRegs.end()) {
LLVM_DEBUG(dbgs() << ".. .. gave up (ran out of FGR32 arguments)\n");
return false;
}
LLVM_DEBUG(dbgs() << ".. .. FGR32(" << *NextFGR32 << ")\n");
Allocation.emplace_back(&Mips::FGR32RegClass, *NextFGR32++);
// Allocating an FGR32 also allocates the super-register AFGR64, and
// ABI rules require us to skip the corresponding GPR32.
if (NextGPR32 != GPR32ArgRegs.end())
NextGPR32++;
if (NextAFGR64 != AFGR64ArgRegs.end())
NextAFGR64++;
break;
case MVT::f64:
if (UnsupportedFPMode) {
LLVM_DEBUG(dbgs() << ".. .. gave up (UnsupportedFPMode)\n");
return false;
}
if (NextAFGR64 == AFGR64ArgRegs.end()) {
LLVM_DEBUG(dbgs() << ".. .. gave up (ran out of AFGR64 arguments)\n");
return false;
}
LLVM_DEBUG(dbgs() << ".. .. AFGR64(" << *NextAFGR64 << ")\n");
Allocation.emplace_back(&Mips::AFGR64RegClass, *NextAFGR64++);
// Allocating an FGR32 also allocates the super-register AFGR64, and
// ABI rules require us to skip the corresponding GPR32 pair.
if (NextGPR32 != GPR32ArgRegs.end())
NextGPR32++;
if (NextGPR32 != GPR32ArgRegs.end())
NextGPR32++;
if (NextFGR32 != FGR32ArgRegs.end())
NextFGR32++;
break;
default:
LLVM_DEBUG(dbgs() << ".. .. gave up (unknown type)\n");
return false;
}
}
for (const auto &FormalArg : F->args()) {
unsigned ArgNo = FormalArg.getArgNo();
unsigned SrcReg = Allocation[ArgNo].Reg;
unsigned DstReg = FuncInfo.MF->addLiveIn(SrcReg, Allocation[ArgNo].RC);
// FIXME: Unfortunately it's necessary to emit a copy from the livein copy.
// Without this, EmitLiveInCopies may eliminate the livein if its only
// use is a bitcast (which isn't turned into an instruction).
unsigned ResultReg = createResultReg(Allocation[ArgNo].RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), ResultReg)
.addReg(DstReg, getKillRegState(true));
updateValueMap(&FormalArg, ResultReg);
}
// Calculate the size of the incoming arguments area.
// We currently reject all the cases where this would be non-zero.
unsigned IncomingArgSizeInBytes = 0;
// Account for the reserved argument area on ABI's that have one (O32).
// It seems strange to do this on the caller side but it's necessary in
// SelectionDAG's implementation.
IncomingArgSizeInBytes = std::min(getABI().GetCalleeAllocdArgSizeInBytes(CC),
IncomingArgSizeInBytes);
MF->getInfo<MipsFunctionInfo>()->setFormalArgInfo(IncomingArgSizeInBytes,
false);
return true;
}
bool MipsFastISel::fastLowerCall(CallLoweringInfo &CLI) {
CallingConv::ID CC = CLI.CallConv;
bool IsTailCall = CLI.IsTailCall;
bool IsVarArg = CLI.IsVarArg;
const Value *Callee = CLI.Callee;
MCSymbol *Symbol = CLI.Symbol;
// Do not handle FastCC.
if (CC == CallingConv::Fast)
return false;
// Allow SelectionDAG isel to handle tail calls.
if (IsTailCall)
return false;
// Let SDISel handle vararg functions.
if (IsVarArg)
return false;
// FIXME: Only handle *simple* calls for now.
MVT RetVT;
if (CLI.RetTy->isVoidTy())
RetVT = MVT::isVoid;
else if (!isTypeSupported(CLI.RetTy, RetVT))
return false;
for (auto Flag : CLI.OutFlags)
if (Flag.isInReg() || Flag.isSRet() || Flag.isNest() || Flag.isByVal())
return false;
// Set up the argument vectors.
SmallVector<MVT, 16> OutVTs;
OutVTs.reserve(CLI.OutVals.size());
for (auto *Val : CLI.OutVals) {
MVT VT;
if (!isTypeLegal(Val->getType(), VT) &&
!(VT == MVT::i1 || VT == MVT::i8 || VT == MVT::i16))
return false;
// We don't handle vector parameters yet.
if (VT.isVector() || VT.getSizeInBits() > 64)
return false;
OutVTs.push_back(VT);
}
Address Addr;
if (!computeCallAddress(Callee, Addr))
return false;
// Handle the arguments now that we've gotten them.
unsigned NumBytes;
if (!processCallArgs(CLI, OutVTs, NumBytes))
return false;
if (!Addr.getGlobalValue())
return false;
// Issue the call.
unsigned DestAddress;
if (Symbol)
DestAddress = materializeExternalCallSym(Symbol);
else
DestAddress = materializeGV(Addr.getGlobalValue(), MVT::i32);
emitInst(TargetOpcode::COPY, Mips::T9).addReg(DestAddress);
MachineInstrBuilder MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::JALR),
Mips::RA).addReg(Mips::T9);
// Add implicit physical register uses to the call.
for (auto Reg : CLI.OutRegs)
MIB.addReg(Reg, RegState::Implicit);
// Add a register mask with the call-preserved registers.
// Proper defs for return values will be added by setPhysRegsDeadExcept().
MIB.addRegMask(TRI.getCallPreservedMask(*FuncInfo.MF, CC));
CLI.Call = MIB;
if (EmitJalrReloc && !Subtarget->inMips16Mode()) {
// Attach callee address to the instruction, let asm printer emit
// .reloc R_MIPS_JALR.
if (Symbol)
MIB.addSym(Symbol, MipsII::MO_JALR);
else
MIB.addSym(FuncInfo.MF->getContext().getOrCreateSymbol(
Addr.getGlobalValue()->getName()), MipsII::MO_JALR);
}
// Finish off the call including any return values.
return finishCall(CLI, RetVT, NumBytes);
}
bool MipsFastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) {
switch (II->getIntrinsicID()) {
default:
return false;
case Intrinsic::bswap: {
Type *RetTy = II->getCalledFunction()->getReturnType();
MVT VT;
if (!isTypeSupported(RetTy, VT))
return false;
unsigned SrcReg = getRegForValue(II->getOperand(0));
if (SrcReg == 0)
return false;
unsigned DestReg = createResultReg(&Mips::GPR32RegClass);
if (DestReg == 0)
return false;
if (VT == MVT::i16) {
if (Subtarget->hasMips32r2()) {
emitInst(Mips::WSBH, DestReg).addReg(SrcReg);
updateValueMap(II, DestReg);
return true;
} else {
unsigned TempReg[3];
for (int i = 0; i < 3; i++) {
TempReg[i] = createResultReg(&Mips::GPR32RegClass);
if (TempReg[i] == 0)
return false;
}
emitInst(Mips::SLL, TempReg[0]).addReg(SrcReg).addImm(8);
emitInst(Mips::SRL, TempReg[1]).addReg(SrcReg).addImm(8);
emitInst(Mips::OR, TempReg[2]).addReg(TempReg[0]).addReg(TempReg[1]);
emitInst(Mips::ANDi, DestReg).addReg(TempReg[2]).addImm(0xFFFF);
updateValueMap(II, DestReg);
return true;
}
} else if (VT == MVT::i32) {
if (Subtarget->hasMips32r2()) {
unsigned TempReg = createResultReg(&Mips::GPR32RegClass);
emitInst(Mips::WSBH, TempReg).addReg(SrcReg);
emitInst(Mips::ROTR, DestReg).addReg(TempReg).addImm(16);
updateValueMap(II, DestReg);
return true;
} else {
unsigned TempReg[8];
for (int i = 0; i < 8; i++) {
TempReg[i] = createResultReg(&Mips::GPR32RegClass);
if (TempReg[i] == 0)
return false;
}
emitInst(Mips::SRL, TempReg[0]).addReg(SrcReg).addImm(8);
emitInst(Mips::SRL, TempReg[1]).addReg(SrcReg).addImm(24);
emitInst(Mips::ANDi, TempReg[2]).addReg(TempReg[0]).addImm(0xFF00);
emitInst(Mips::OR, TempReg[3]).addReg(TempReg[1]).addReg(TempReg[2]);
emitInst(Mips::ANDi, TempReg[4]).addReg(SrcReg).addImm(0xFF00);
emitInst(Mips::SLL, TempReg[5]).addReg(TempReg[4]).addImm(8);
emitInst(Mips::SLL, TempReg[6]).addReg(SrcReg).addImm(24);
emitInst(Mips::OR, TempReg[7]).addReg(TempReg[3]).addReg(TempReg[5]);
emitInst(Mips::OR, DestReg).addReg(TempReg[6]).addReg(TempReg[7]);
updateValueMap(II, DestReg);
return true;
}
}
return false;
}
case Intrinsic::memcpy:
case Intrinsic::memmove: {
const auto *MTI = cast<MemTransferInst>(II);
// Don't handle volatile.
if (MTI->isVolatile())
return false;
if (!MTI->getLength()->getType()->isIntegerTy(32))
return false;
const char *IntrMemName = isa<MemCpyInst>(II) ? "memcpy" : "memmove";
return lowerCallTo(II, IntrMemName, II->getNumArgOperands() - 1);
}
case Intrinsic::memset: {
const MemSetInst *MSI = cast<MemSetInst>(II);
// Don't handle volatile.
if (MSI->isVolatile())
return false;
if (!MSI->getLength()->getType()->isIntegerTy(32))
return false;
return lowerCallTo(II, "memset", II->getNumArgOperands() - 1);
}
}
return false;
}
bool MipsFastISel::selectRet(const Instruction *I) {
const Function &F = *I->getParent()->getParent();
const ReturnInst *Ret = cast<ReturnInst>(I);
LLVM_DEBUG(dbgs() << "selectRet\n");
if (!FuncInfo.CanLowerReturn)
return false;
// Build a list of return value registers.
SmallVector<unsigned, 4> RetRegs;
if (Ret->getNumOperands() > 0) {
CallingConv::ID CC = F.getCallingConv();
// Do not handle FastCC.
if (CC == CallingConv::Fast)
return false;
SmallVector<ISD::OutputArg, 4> Outs;
GetReturnInfo(CC, F.getReturnType(), F.getAttributes(), Outs, TLI, DL);
// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ValLocs;
MipsCCState CCInfo(CC, F.isVarArg(), *FuncInfo.MF, ValLocs,
I->getContext());
CCAssignFn *RetCC = RetCC_Mips;
CCInfo.AnalyzeReturn(Outs, RetCC);
// Only handle a single return value for now.
if (ValLocs.size() != 1)
return false;
CCValAssign &VA = ValLocs[0];
const Value *RV = Ret->getOperand(0);
// Don't bother handling odd stuff for now.
if ((VA.getLocInfo() != CCValAssign::Full) &&
(VA.getLocInfo() != CCValAssign::BCvt))
return false;
// Only handle register returns for now.
if (!VA.isRegLoc())
return false;
unsigned Reg = getRegForValue(RV);
if (Reg == 0)
return false;
unsigned SrcReg = Reg + VA.getValNo();
unsigned DestReg = VA.getLocReg();
// Avoid a cross-class copy. This is very unlikely.
if (!MRI.getRegClass(SrcReg)->contains(DestReg))
return false;
EVT RVEVT = TLI.getValueType(DL, RV->getType());
if (!RVEVT.isSimple())
return false;
if (RVEVT.isVector())
return false;
MVT RVVT = RVEVT.getSimpleVT();
if (RVVT == MVT::f128)
return false;
// Do not handle FGR64 returns for now.
if (RVVT == MVT::f64 && UnsupportedFPMode) {
LLVM_DEBUG(dbgs() << ".. .. gave up (UnsupportedFPMode\n");
return false;
}
MVT DestVT = VA.getValVT();
// Special handling for extended integers.
if (RVVT != DestVT) {
if (RVVT != MVT::i1 && RVVT != MVT::i8 && RVVT != MVT::i16)
return false;
if (Outs[0].Flags.isZExt() || Outs[0].Flags.isSExt()) {
bool IsZExt = Outs[0].Flags.isZExt();
SrcReg = emitIntExt(RVVT, SrcReg, DestVT, IsZExt);
if (SrcReg == 0)
return false;
}
}
// Make the copy.
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), DestReg).addReg(SrcReg);
// Add register to return instruction.
RetRegs.push_back(VA.getLocReg());
}
MachineInstrBuilder MIB = emitInst(Mips::RetRA);
for (unsigned i = 0, e = RetRegs.size(); i != e; ++i)
MIB.addReg(RetRegs[i], RegState::Implicit);
return true;
}
bool MipsFastISel::selectTrunc(const Instruction *I) {
// The high bits for a type smaller than the register size are assumed to be
// undefined.
Value *Op = I->getOperand(0);
EVT SrcVT, DestVT;
SrcVT = TLI.getValueType(DL, Op->getType(), true);
DestVT = TLI.getValueType(DL, I->getType(), true);
if (SrcVT != MVT::i32 && SrcVT != MVT::i16 && SrcVT != MVT::i8)
return false;
if (DestVT != MVT::i16 && DestVT != MVT::i8 && DestVT != MVT::i1)
return false;
unsigned SrcReg = getRegForValue(Op);
if (!SrcReg)
return false;
// Because the high bits are undefined, a truncate doesn't generate
// any code.
updateValueMap(I, SrcReg);
return true;
}
bool MipsFastISel::selectIntExt(const Instruction *I) {
Type *DestTy = I->getType();
Value *Src = I->getOperand(0);
Type *SrcTy = Src->getType();
bool isZExt = isa<ZExtInst>(I);
unsigned SrcReg = getRegForValue(Src);
if (!SrcReg)
return false;
EVT SrcEVT, DestEVT;
SrcEVT = TLI.getValueType(DL, SrcTy, true);
DestEVT = TLI.getValueType(DL, DestTy, true);
if (!SrcEVT.isSimple())
return false;
if (!DestEVT.isSimple())
return false;
MVT SrcVT = SrcEVT.getSimpleVT();
MVT DestVT = DestEVT.getSimpleVT();
unsigned ResultReg = createResultReg(&Mips::GPR32RegClass);
if (!emitIntExt(SrcVT, SrcReg, DestVT, ResultReg, isZExt))
return false;
updateValueMap(I, ResultReg);
return true;
}
bool MipsFastISel::emitIntSExt32r1(MVT SrcVT, unsigned SrcReg, MVT DestVT,
unsigned DestReg) {
unsigned ShiftAmt;
switch (SrcVT.SimpleTy) {
default:
return false;
case MVT::i8:
ShiftAmt = 24;
break;
case MVT::i16:
ShiftAmt = 16;
break;
}
unsigned TempReg = createResultReg(&Mips::GPR32RegClass);
emitInst(Mips::SLL, TempReg).addReg(SrcReg).addImm(ShiftAmt);
emitInst(Mips::SRA, DestReg).addReg(TempReg).addImm(ShiftAmt);
return true;
}
bool MipsFastISel::emitIntSExt32r2(MVT SrcVT, unsigned SrcReg, MVT DestVT,
unsigned DestReg) {
switch (SrcVT.SimpleTy) {
default:
return false;
case MVT::i8:
emitInst(Mips::SEB, DestReg).addReg(SrcReg);
break;
case MVT::i16:
emitInst(Mips::SEH, DestReg).addReg(SrcReg);
break;
}
return true;
}
bool MipsFastISel::emitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT,
unsigned DestReg) {
if ((DestVT != MVT::i32) && (DestVT != MVT::i16))
return false;
if (Subtarget->hasMips32r2())
return emitIntSExt32r2(SrcVT, SrcReg, DestVT, DestReg);
return emitIntSExt32r1(SrcVT, SrcReg, DestVT, DestReg);
}
bool MipsFastISel::emitIntZExt(MVT SrcVT, unsigned SrcReg, MVT DestVT,
unsigned DestReg) {
int64_t Imm;
switch (SrcVT.SimpleTy) {
default:
return false;
case MVT::i1:
Imm = 1;
break;
case MVT::i8:
Imm = 0xff;
break;
case MVT::i16:
Imm = 0xffff;
break;
}
emitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(Imm);
return true;
}
bool MipsFastISel::emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT,
unsigned DestReg, bool IsZExt) {
// FastISel does not have plumbing to deal with extensions where the SrcVT or
// DestVT are odd things, so test to make sure that they are both types we can
// handle (i1/i8/i16/i32 for SrcVT and i8/i16/i32/i64 for DestVT), otherwise
// bail out to SelectionDAG.
if (((DestVT != MVT::i8) && (DestVT != MVT::i16) && (DestVT != MVT::i32)) ||
((SrcVT != MVT::i1) && (SrcVT != MVT::i8) && (SrcVT != MVT::i16)))
return false;
if (IsZExt)
return emitIntZExt(SrcVT, SrcReg, DestVT, DestReg);
return emitIntSExt(SrcVT, SrcReg, DestVT, DestReg);
}
unsigned MipsFastISel::emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT,
bool isZExt) {
unsigned DestReg = createResultReg(&Mips::GPR32RegClass);
bool Success = emitIntExt(SrcVT, SrcReg, DestVT, DestReg, isZExt);
return Success ? DestReg : 0;
}
bool MipsFastISel::selectDivRem(const Instruction *I, unsigned ISDOpcode) {
EVT DestEVT = TLI.getValueType(DL, I->getType(), true);
if (!DestEVT.isSimple())
return false;
MVT DestVT = DestEVT.getSimpleVT();
if (DestVT != MVT::i32)
return false;
unsigned DivOpc;
switch (ISDOpcode) {
default:
return false;
case ISD::SDIV:
case ISD::SREM:
DivOpc = Mips::SDIV;
break;
case ISD::UDIV:
case ISD::UREM:
DivOpc = Mips::UDIV;
break;
}
unsigned Src0Reg = getRegForValue(I->getOperand(0));
unsigned Src1Reg = getRegForValue(I->getOperand(1));
if (!Src0Reg || !Src1Reg)
return false;
emitInst(DivOpc).addReg(Src0Reg).addReg(Src1Reg);
emitInst(Mips::TEQ).addReg(Src1Reg).addReg(Mips::ZERO).addImm(7);
unsigned ResultReg = createResultReg(&Mips::GPR32RegClass);
if (!ResultReg)
return false;
unsigned MFOpc = (ISDOpcode == ISD::SREM || ISDOpcode == ISD::UREM)
? Mips::MFHI
: Mips::MFLO;
emitInst(MFOpc, ResultReg);
updateValueMap(I, ResultReg);
return true;
}
bool MipsFastISel::selectShift(const Instruction *I) {
MVT RetVT;
if (!isTypeSupported(I->getType(), RetVT))
return false;
unsigned ResultReg = createResultReg(&Mips::GPR32RegClass);
if (!ResultReg)
return false;
unsigned Opcode = I->getOpcode();
const Value *Op0 = I->getOperand(0);
unsigned Op0Reg = getRegForValue(Op0);
if (!Op0Reg)
return false;
// If AShr or LShr, then we need to make sure the operand0 is sign extended.
if (Opcode == Instruction::AShr || Opcode == Instruction::LShr) {
unsigned TempReg = createResultReg(&Mips::GPR32RegClass);
if (!TempReg)
return false;
MVT Op0MVT = TLI.getValueType(DL, Op0->getType(), true).getSimpleVT();
bool IsZExt = Opcode == Instruction::LShr;
if (!emitIntExt(Op0MVT, Op0Reg, MVT::i32, TempReg, IsZExt))
return false;
Op0Reg = TempReg;
}
if (const auto *C = dyn_cast<ConstantInt>(I->getOperand(1))) {
uint64_t ShiftVal = C->getZExtValue();
switch (Opcode) {
default:
llvm_unreachable("Unexpected instruction.");
case Instruction::Shl:
Opcode = Mips::SLL;
break;
case Instruction::AShr:
Opcode = Mips::SRA;
break;
case Instruction::LShr:
Opcode = Mips::SRL;
break;
}
emitInst(Opcode, ResultReg).addReg(Op0Reg).addImm(ShiftVal);
updateValueMap(I, ResultReg);
return true;
}
unsigned Op1Reg = getRegForValue(I->getOperand(1));
if (!Op1Reg)
return false;
switch (Opcode) {
default:
llvm_unreachable("Unexpected instruction.");
case Instruction::Shl:
Opcode = Mips::SLLV;
break;
case Instruction::AShr:
Opcode = Mips::SRAV;
break;
case Instruction::LShr:
Opcode = Mips::SRLV;
break;
}
emitInst(Opcode, ResultReg).addReg(Op0Reg).addReg(Op1Reg);
updateValueMap(I, ResultReg);
return true;
}
bool MipsFastISel::fastSelectInstruction(const Instruction *I) {
switch (I->getOpcode()) {
default:
break;
case Instruction::Load:
return selectLoad(I);
case Instruction::Store:
return selectStore(I);
case Instruction::SDiv:
if (!selectBinaryOp(I, ISD::SDIV))
return selectDivRem(I, ISD::SDIV);
return true;
case Instruction::UDiv:
if (!selectBinaryOp(I, ISD::UDIV))
return selectDivRem(I, ISD::UDIV);
return true;
case Instruction::SRem:
if (!selectBinaryOp(I, ISD::SREM))
return selectDivRem(I, ISD::SREM);
return true;
case Instruction::URem:
if (!selectBinaryOp(I, ISD::UREM))
return selectDivRem(I, ISD::UREM);
return true;
case Instruction::Shl:
case Instruction::LShr:
case Instruction::AShr:
return selectShift(I);
case Instruction::And:
case Instruction::Or:
case Instruction::Xor:
return selectLogicalOp(I);
case Instruction::Br:
return selectBranch(I);
case Instruction::Ret:
return selectRet(I);
case Instruction::Trunc:
return selectTrunc(I);
case Instruction::ZExt:
case Instruction::SExt:
return selectIntExt(I);
case Instruction::FPTrunc:
return selectFPTrunc(I);
case Instruction::FPExt:
return selectFPExt(I);
case Instruction::FPToSI:
return selectFPToInt(I, /*isSigned*/ true);
case Instruction::FPToUI:
return selectFPToInt(I, /*isSigned*/ false);
case Instruction::ICmp:
case Instruction::FCmp:
return selectCmp(I);
case Instruction::Select:
return selectSelect(I);
}
return false;
}
unsigned MipsFastISel::getRegEnsuringSimpleIntegerWidening(const Value *V,
bool IsUnsigned) {
unsigned VReg = getRegForValue(V);
if (VReg == 0)
return 0;
MVT VMVT = TLI.getValueType(DL, V->getType(), true).getSimpleVT();
if (VMVT == MVT::i1)
return 0;
if ((VMVT == MVT::i8) || (VMVT == MVT::i16)) {
unsigned TempReg = createResultReg(&Mips::GPR32RegClass);
if (!emitIntExt(VMVT, VReg, MVT::i32, TempReg, IsUnsigned))
return 0;
VReg = TempReg;
}
return VReg;
}
void MipsFastISel::simplifyAddress(Address &Addr) {
if (!isInt<16>(Addr.getOffset())) {
unsigned TempReg =
materialize32BitInt(Addr.getOffset(), &Mips::GPR32RegClass);
unsigned DestReg = createResultReg(&Mips::GPR32RegClass);
emitInst(Mips::ADDu, DestReg).addReg(TempReg).addReg(Addr.getReg());
Addr.setReg(DestReg);
Addr.setOffset(0);
}
}
unsigned MipsFastISel::fastEmitInst_rr(unsigned MachineInstOpcode,
const TargetRegisterClass *RC,
unsigned Op0, bool Op0IsKill,
unsigned Op1, bool Op1IsKill) {
// We treat the MUL instruction in a special way because it clobbers
// the HI0 & LO0 registers. The TableGen definition of this instruction can
// mark these registers only as implicitly defined. As a result, the
// register allocator runs out of registers when this instruction is
// followed by another instruction that defines the same registers too.
// We can fix this by explicitly marking those registers as dead.
if (MachineInstOpcode == Mips::MUL) {
unsigned ResultReg = createResultReg(RC);
const MCInstrDesc &II = TII.get(MachineInstOpcode);
Op0 = constrainOperandRegClass(II, Op0, II.getNumDefs());
Op1 = constrainOperandRegClass(II, Op1, II.getNumDefs() + 1);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, ResultReg)
.addReg(Op0, getKillRegState(Op0IsKill))
.addReg(Op1, getKillRegState(Op1IsKill))
.addReg(Mips::HI0, RegState::ImplicitDefine | RegState::Dead)
.addReg(Mips::LO0, RegState::ImplicitDefine | RegState::Dead);
return ResultReg;
}
return FastISel::fastEmitInst_rr(MachineInstOpcode, RC, Op0, Op0IsKill, Op1,
Op1IsKill);
}
namespace llvm {
FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo,
const TargetLibraryInfo *libInfo) {
return new MipsFastISel(funcInfo, libInfo);
}
} // end namespace llvm
Index: stable/11/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp (revision 350259)
@@ -1,904 +1,907 @@
//===-- MipsSEInstrInfo.cpp - Mips32/64 Instruction Information -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Mips32/64 implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//
#include "MipsSEInstrInfo.h"
#include "InstPrinter/MipsInstPrinter.h"
#include "MipsAnalyzeImmediate.h"
#include "MipsMachineFunction.h"
#include "MipsTargetMachine.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
static unsigned getUnconditionalBranch(const MipsSubtarget &STI) {
if (STI.inMicroMipsMode())
return STI.isPositionIndependent() ? Mips::B_MM : Mips::J_MM;
return STI.isPositionIndependent() ? Mips::B : Mips::J;
}
MipsSEInstrInfo::MipsSEInstrInfo(const MipsSubtarget &STI)
: MipsInstrInfo(STI, getUnconditionalBranch(STI)), RI() {}
const MipsRegisterInfo &MipsSEInstrInfo::getRegisterInfo() const {
return RI;
}
/// isLoadFromStackSlot - If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than loading from the stack slot.
unsigned MipsSEInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
int &FrameIndex) const {
unsigned Opc = MI.getOpcode();
if ((Opc == Mips::LW) || (Opc == Mips::LD) ||
(Opc == Mips::LWC1) || (Opc == Mips::LDC1) || (Opc == Mips::LDC164)) {
if ((MI.getOperand(1).isFI()) && // is a stack slot
(MI.getOperand(2).isImm()) && // the imm is zero
(isZeroImm(MI.getOperand(2)))) {
FrameIndex = MI.getOperand(1).getIndex();
return MI.getOperand(0).getReg();
}
}
return 0;
}
/// isStoreToStackSlot - If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than storing to the stack slot.
unsigned MipsSEInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
int &FrameIndex) const {
unsigned Opc = MI.getOpcode();
if ((Opc == Mips::SW) || (Opc == Mips::SD) ||
(Opc == Mips::SWC1) || (Opc == Mips::SDC1) || (Opc == Mips::SDC164)) {
if ((MI.getOperand(1).isFI()) && // is a stack slot
(MI.getOperand(2).isImm()) && // the imm is zero
(isZeroImm(MI.getOperand(2)))) {
FrameIndex = MI.getOperand(1).getIndex();
return MI.getOperand(0).getReg();
}
}
return 0;
}
void MipsSEInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
const DebugLoc &DL, unsigned DestReg,
unsigned SrcReg, bool KillSrc) const {
unsigned Opc = 0, ZeroReg = 0;
bool isMicroMips = Subtarget.inMicroMipsMode();
if (Mips::GPR32RegClass.contains(DestReg)) { // Copy to CPU Reg.
if (Mips::GPR32RegClass.contains(SrcReg)) {
if (isMicroMips)
Opc = Mips::MOVE16_MM;
else
Opc = Mips::OR, ZeroReg = Mips::ZERO;
} else if (Mips::CCRRegClass.contains(SrcReg))
Opc = Mips::CFC1;
else if (Mips::FGR32RegClass.contains(SrcReg))
Opc = Mips::MFC1;
else if (Mips::HI32RegClass.contains(SrcReg)) {
Opc = isMicroMips ? Mips::MFHI16_MM : Mips::MFHI;
SrcReg = 0;
} else if (Mips::LO32RegClass.contains(SrcReg)) {
Opc = isMicroMips ? Mips::MFLO16_MM : Mips::MFLO;
SrcReg = 0;
} else if (Mips::HI32DSPRegClass.contains(SrcReg))
Opc = Mips::MFHI_DSP;
else if (Mips::LO32DSPRegClass.contains(SrcReg))
Opc = Mips::MFLO_DSP;
else if (Mips::DSPCCRegClass.contains(SrcReg)) {
BuildMI(MBB, I, DL, get(Mips::RDDSP), DestReg).addImm(1 << 4)
.addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc));
return;
}
else if (Mips::MSACtrlRegClass.contains(SrcReg))
Opc = Mips::CFCMSA;
}
else if (Mips::GPR32RegClass.contains(SrcReg)) { // Copy from CPU Reg.
if (Mips::CCRRegClass.contains(DestReg))
Opc = Mips::CTC1;
else if (Mips::FGR32RegClass.contains(DestReg))
Opc = Mips::MTC1;
else if (Mips::HI32RegClass.contains(DestReg))
Opc = Mips::MTHI, DestReg = 0;
else if (Mips::LO32RegClass.contains(DestReg))
Opc = Mips::MTLO, DestReg = 0;
else if (Mips::HI32DSPRegClass.contains(DestReg))
Opc = Mips::MTHI_DSP;
else if (Mips::LO32DSPRegClass.contains(DestReg))
Opc = Mips::MTLO_DSP;
else if (Mips::DSPCCRegClass.contains(DestReg)) {
BuildMI(MBB, I, DL, get(Mips::WRDSP))
.addReg(SrcReg, getKillRegState(KillSrc)).addImm(1 << 4)
.addReg(DestReg, RegState::ImplicitDefine);
return;
} else if (Mips::MSACtrlRegClass.contains(DestReg)) {
BuildMI(MBB, I, DL, get(Mips::CTCMSA))
.addReg(DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
return;
}
}
else if (Mips::FGR32RegClass.contains(DestReg, SrcReg))
Opc = Mips::FMOV_S;
else if (Mips::AFGR64RegClass.contains(DestReg, SrcReg))
Opc = Mips::FMOV_D32;
else if (Mips::FGR64RegClass.contains(DestReg, SrcReg))
Opc = Mips::FMOV_D64;
else if (Mips::GPR64RegClass.contains(DestReg)) { // Copy to CPU64 Reg.
if (Mips::GPR64RegClass.contains(SrcReg))
Opc = Mips::OR64, ZeroReg = Mips::ZERO_64;
else if (Mips::HI64RegClass.contains(SrcReg))
Opc = Mips::MFHI64, SrcReg = 0;
else if (Mips::LO64RegClass.contains(SrcReg))
Opc = Mips::MFLO64, SrcReg = 0;
else if (Mips::FGR64RegClass.contains(SrcReg))
Opc = Mips::DMFC1;
}
else if (Mips::GPR64RegClass.contains(SrcReg)) { // Copy from CPU64 Reg.
if (Mips::HI64RegClass.contains(DestReg))
Opc = Mips::MTHI64, DestReg = 0;
else if (Mips::LO64RegClass.contains(DestReg))
Opc = Mips::MTLO64, DestReg = 0;
else if (Mips::FGR64RegClass.contains(DestReg))
Opc = Mips::DMTC1;
}
else if (Mips::MSA128BRegClass.contains(DestReg)) { // Copy to MSA reg
if (Mips::MSA128BRegClass.contains(SrcReg))
Opc = Mips::MOVE_V;
}
assert(Opc && "Cannot copy registers");
MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(Opc));
if (DestReg)
MIB.addReg(DestReg, RegState::Define);
if (SrcReg)
MIB.addReg(SrcReg, getKillRegState(KillSrc));
if (ZeroReg)
MIB.addReg(ZeroReg);
}
static bool isORCopyInst(const MachineInstr &MI) {
switch (MI.getOpcode()) {
default:
break;
case Mips::OR_MM:
case Mips::OR:
if (MI.getOperand(2).getReg() == Mips::ZERO)
return true;
break;
case Mips::OR64:
if (MI.getOperand(2).getReg() == Mips::ZERO_64)
return true;
break;
}
return false;
}
/// If @MI is WRDSP/RRDSP instruction return true with @isWrite set to true
/// if it is WRDSP instruction.
static bool isReadOrWriteToDSPReg(const MachineInstr &MI, bool &isWrite) {
switch (MI.getOpcode()) {
default:
return false;
case Mips::WRDSP:
case Mips::WRDSP_MM:
isWrite = true;
break;
case Mips::RDDSP:
case Mips::RDDSP_MM:
isWrite = false;
break;
}
return true;
}
/// We check for the common case of 'or', as it's MIPS' preferred instruction
/// for GPRs but we have to check the operands to ensure that is the case.
/// Other move instructions for MIPS are directly identifiable.
bool MipsSEInstrInfo::isCopyInstrImpl(const MachineInstr &MI,
const MachineOperand *&Src,
const MachineOperand *&Dest) const {
bool isDSPControlWrite = false;
// Condition is made to match the creation of WRDSP/RDDSP copy instruction
// from copyPhysReg function.
if (isReadOrWriteToDSPReg(MI, isDSPControlWrite)) {
if (!MI.getOperand(1).isImm() || MI.getOperand(1).getImm() != (1<<4))
return false;
else if (isDSPControlWrite) {
Src = &MI.getOperand(0);
Dest = &MI.getOperand(2);
} else {
Dest = &MI.getOperand(0);
Src = &MI.getOperand(2);
}
return true;
} else if (MI.isMoveReg() || isORCopyInst(MI)) {
Dest = &MI.getOperand(0);
Src = &MI.getOperand(1);
return true;
}
return false;
}
void MipsSEInstrInfo::
storeRegToStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned SrcReg, bool isKill, int FI,
const TargetRegisterClass *RC, const TargetRegisterInfo *TRI,
int64_t Offset) const {
DebugLoc DL;
MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOStore);
unsigned Opc = 0;
if (Mips::GPR32RegClass.hasSubClassEq(RC))
Opc = Mips::SW;
else if (Mips::GPR64RegClass.hasSubClassEq(RC))
Opc = Mips::SD;
else if (Mips::ACC64RegClass.hasSubClassEq(RC))
Opc = Mips::STORE_ACC64;
else if (Mips::ACC64DSPRegClass.hasSubClassEq(RC))
Opc = Mips::STORE_ACC64DSP;
else if (Mips::ACC128RegClass.hasSubClassEq(RC))
Opc = Mips::STORE_ACC128;
else if (Mips::DSPCCRegClass.hasSubClassEq(RC))
Opc = Mips::STORE_CCOND_DSP;
else if (Mips::FGR32RegClass.hasSubClassEq(RC))
Opc = Mips::SWC1;
else if (Mips::AFGR64RegClass.hasSubClassEq(RC))
Opc = Mips::SDC1;
else if (Mips::FGR64RegClass.hasSubClassEq(RC))
Opc = Mips::SDC164;
else if (TRI->isTypeLegalForClass(*RC, MVT::v16i8))
Opc = Mips::ST_B;
else if (TRI->isTypeLegalForClass(*RC, MVT::v8i16) ||
TRI->isTypeLegalForClass(*RC, MVT::v8f16))
Opc = Mips::ST_H;
else if (TRI->isTypeLegalForClass(*RC, MVT::v4i32) ||
TRI->isTypeLegalForClass(*RC, MVT::v4f32))
Opc = Mips::ST_W;
else if (TRI->isTypeLegalForClass(*RC, MVT::v2i64) ||
TRI->isTypeLegalForClass(*RC, MVT::v2f64))
Opc = Mips::ST_D;
else if (Mips::LO32RegClass.hasSubClassEq(RC))
Opc = Mips::SW;
else if (Mips::LO64RegClass.hasSubClassEq(RC))
Opc = Mips::SD;
else if (Mips::HI32RegClass.hasSubClassEq(RC))
Opc = Mips::SW;
else if (Mips::HI64RegClass.hasSubClassEq(RC))
Opc = Mips::SD;
else if (Mips::DSPRRegClass.hasSubClassEq(RC))
Opc = Mips::SWDSP;
// Hi, Lo are normally caller save but they are callee save
// for interrupt handling.
const Function &Func = MBB.getParent()->getFunction();
if (Func.hasFnAttribute("interrupt")) {
if (Mips::HI32RegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(Mips::MFHI), Mips::K0);
SrcReg = Mips::K0;
} else if (Mips::HI64RegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(Mips::MFHI64), Mips::K0_64);
SrcReg = Mips::K0_64;
} else if (Mips::LO32RegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(Mips::MFLO), Mips::K0);
SrcReg = Mips::K0;
} else if (Mips::LO64RegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(Mips::MFLO64), Mips::K0_64);
SrcReg = Mips::K0_64;
}
}
assert(Opc && "Register class not handled!");
BuildMI(MBB, I, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill))
.addFrameIndex(FI).addImm(Offset).addMemOperand(MMO);
}
void MipsSEInstrInfo::
loadRegFromStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned DestReg, int FI, const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI, int64_t Offset) const {
DebugLoc DL;
if (I != MBB.end()) DL = I->getDebugLoc();
MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOLoad);
unsigned Opc = 0;
const Function &Func = MBB.getParent()->getFunction();
bool ReqIndirectLoad = Func.hasFnAttribute("interrupt") &&
(DestReg == Mips::LO0 || DestReg == Mips::LO0_64 ||
DestReg == Mips::HI0 || DestReg == Mips::HI0_64);
if (Mips::GPR32RegClass.hasSubClassEq(RC))
Opc = Mips::LW;
else if (Mips::GPR64RegClass.hasSubClassEq(RC))
Opc = Mips::LD;
else if (Mips::ACC64RegClass.hasSubClassEq(RC))
Opc = Mips::LOAD_ACC64;
else if (Mips::ACC64DSPRegClass.hasSubClassEq(RC))
Opc = Mips::LOAD_ACC64DSP;
else if (Mips::ACC128RegClass.hasSubClassEq(RC))
Opc = Mips::LOAD_ACC128;
else if (Mips::DSPCCRegClass.hasSubClassEq(RC))
Opc = Mips::LOAD_CCOND_DSP;
else if (Mips::FGR32RegClass.hasSubClassEq(RC))
Opc = Mips::LWC1;
else if (Mips::AFGR64RegClass.hasSubClassEq(RC))
Opc = Mips::LDC1;
else if (Mips::FGR64RegClass.hasSubClassEq(RC))
Opc = Mips::LDC164;
else if (TRI->isTypeLegalForClass(*RC, MVT::v16i8))
Opc = Mips::LD_B;
else if (TRI->isTypeLegalForClass(*RC, MVT::v8i16) ||
TRI->isTypeLegalForClass(*RC, MVT::v8f16))
Opc = Mips::LD_H;
else if (TRI->isTypeLegalForClass(*RC, MVT::v4i32) ||
TRI->isTypeLegalForClass(*RC, MVT::v4f32))
Opc = Mips::LD_W;
else if (TRI->isTypeLegalForClass(*RC, MVT::v2i64) ||
TRI->isTypeLegalForClass(*RC, MVT::v2f64))
Opc = Mips::LD_D;
else if (Mips::HI32RegClass.hasSubClassEq(RC))
Opc = Mips::LW;
else if (Mips::HI64RegClass.hasSubClassEq(RC))
Opc = Mips::LD;
else if (Mips::LO32RegClass.hasSubClassEq(RC))
Opc = Mips::LW;
else if (Mips::LO64RegClass.hasSubClassEq(RC))
Opc = Mips::LD;
else if (Mips::DSPRRegClass.hasSubClassEq(RC))
Opc = Mips::LWDSP;
assert(Opc && "Register class not handled!");
if (!ReqIndirectLoad)
BuildMI(MBB, I, DL, get(Opc), DestReg)
.addFrameIndex(FI)
.addImm(Offset)
.addMemOperand(MMO);
else {
// Load HI/LO through K0. Notably the DestReg is encoded into the
// instruction itself.
unsigned Reg = Mips::K0;
unsigned LdOp = Mips::MTLO;
if (DestReg == Mips::HI0)
LdOp = Mips::MTHI;
if (Subtarget.getABI().ArePtrs64bit()) {
Reg = Mips::K0_64;
if (DestReg == Mips::HI0_64)
LdOp = Mips::MTHI64;
else
LdOp = Mips::MTLO64;
}
BuildMI(MBB, I, DL, get(Opc), Reg)
.addFrameIndex(FI)
.addImm(Offset)
.addMemOperand(MMO);
BuildMI(MBB, I, DL, get(LdOp)).addReg(Reg);
}
}
bool MipsSEInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
MachineBasicBlock &MBB = *MI.getParent();
bool isMicroMips = Subtarget.inMicroMipsMode();
unsigned Opc;
switch (MI.getDesc().getOpcode()) {
default:
return false;
case Mips::RetRA:
expandRetRA(MBB, MI);
break;
case Mips::ERet:
expandERet(MBB, MI);
break;
case Mips::PseudoMFHI:
expandPseudoMFHiLo(MBB, MI, Mips::MFHI);
break;
case Mips::PseudoMFHI_MM:
expandPseudoMFHiLo(MBB, MI, Mips::MFHI16_MM);
break;
case Mips::PseudoMFLO:
expandPseudoMFHiLo(MBB, MI, Mips::MFLO);
break;
case Mips::PseudoMFLO_MM:
expandPseudoMFHiLo(MBB, MI, Mips::MFLO16_MM);
break;
case Mips::PseudoMFHI64:
expandPseudoMFHiLo(MBB, MI, Mips::MFHI64);
break;
case Mips::PseudoMFLO64:
expandPseudoMFHiLo(MBB, MI, Mips::MFLO64);
break;
case Mips::PseudoMTLOHI:
expandPseudoMTLoHi(MBB, MI, Mips::MTLO, Mips::MTHI, false);
break;
case Mips::PseudoMTLOHI64:
expandPseudoMTLoHi(MBB, MI, Mips::MTLO64, Mips::MTHI64, false);
break;
case Mips::PseudoMTLOHI_DSP:
expandPseudoMTLoHi(MBB, MI, Mips::MTLO_DSP, Mips::MTHI_DSP, true);
break;
+ case Mips::PseudoMTLOHI_MM:
+ expandPseudoMTLoHi(MBB, MI, Mips::MTLO_MM, Mips::MTHI_MM, false);
+ break;
case Mips::PseudoCVT_S_W:
expandCvtFPInt(MBB, MI, Mips::CVT_S_W, Mips::MTC1, false);
break;
case Mips::PseudoCVT_D32_W:
Opc = isMicroMips ? Mips::CVT_D32_W_MM : Mips::CVT_D32_W;
expandCvtFPInt(MBB, MI, Opc, Mips::MTC1, false);
break;
case Mips::PseudoCVT_S_L:
expandCvtFPInt(MBB, MI, Mips::CVT_S_L, Mips::DMTC1, true);
break;
case Mips::PseudoCVT_D64_W:
Opc = isMicroMips ? Mips::CVT_D64_W_MM : Mips::CVT_D64_W;
expandCvtFPInt(MBB, MI, Opc, Mips::MTC1, true);
break;
case Mips::PseudoCVT_D64_L:
expandCvtFPInt(MBB, MI, Mips::CVT_D64_L, Mips::DMTC1, true);
break;
case Mips::BuildPairF64:
expandBuildPairF64(MBB, MI, isMicroMips, false);
break;
case Mips::BuildPairF64_64:
expandBuildPairF64(MBB, MI, isMicroMips, true);
break;
case Mips::ExtractElementF64:
expandExtractElementF64(MBB, MI, isMicroMips, false);
break;
case Mips::ExtractElementF64_64:
expandExtractElementF64(MBB, MI, isMicroMips, true);
break;
case Mips::MIPSeh_return32:
case Mips::MIPSeh_return64:
expandEhReturn(MBB, MI);
break;
}
MBB.erase(MI);
return true;
}
/// getOppositeBranchOpc - Return the inverse of the specified
/// opcode, e.g. turning BEQ to BNE.
unsigned MipsSEInstrInfo::getOppositeBranchOpc(unsigned Opc) const {
switch (Opc) {
default: llvm_unreachable("Illegal opcode!");
case Mips::BEQ: return Mips::BNE;
case Mips::BEQ_MM: return Mips::BNE_MM;
case Mips::BNE: return Mips::BEQ;
case Mips::BNE_MM: return Mips::BEQ_MM;
case Mips::BGTZ: return Mips::BLEZ;
case Mips::BGEZ: return Mips::BLTZ;
case Mips::BLTZ: return Mips::BGEZ;
case Mips::BLEZ: return Mips::BGTZ;
case Mips::BGTZ_MM: return Mips::BLEZ_MM;
case Mips::BGEZ_MM: return Mips::BLTZ_MM;
case Mips::BLTZ_MM: return Mips::BGEZ_MM;
case Mips::BLEZ_MM: return Mips::BGTZ_MM;
case Mips::BEQ64: return Mips::BNE64;
case Mips::BNE64: return Mips::BEQ64;
case Mips::BGTZ64: return Mips::BLEZ64;
case Mips::BGEZ64: return Mips::BLTZ64;
case Mips::BLTZ64: return Mips::BGEZ64;
case Mips::BLEZ64: return Mips::BGTZ64;
case Mips::BC1T: return Mips::BC1F;
case Mips::BC1F: return Mips::BC1T;
case Mips::BC1T_MM: return Mips::BC1F_MM;
case Mips::BC1F_MM: return Mips::BC1T_MM;
case Mips::BEQZ16_MM: return Mips::BNEZ16_MM;
case Mips::BNEZ16_MM: return Mips::BEQZ16_MM;
case Mips::BEQZC_MM: return Mips::BNEZC_MM;
case Mips::BNEZC_MM: return Mips::BEQZC_MM;
case Mips::BEQZC: return Mips::BNEZC;
case Mips::BNEZC: return Mips::BEQZC;
case Mips::BLEZC: return Mips::BGTZC;
case Mips::BGEZC: return Mips::BLTZC;
case Mips::BGEC: return Mips::BLTC;
case Mips::BGTZC: return Mips::BLEZC;
case Mips::BLTZC: return Mips::BGEZC;
case Mips::BLTC: return Mips::BGEC;
case Mips::BGEUC: return Mips::BLTUC;
case Mips::BLTUC: return Mips::BGEUC;
case Mips::BEQC: return Mips::BNEC;
case Mips::BNEC: return Mips::BEQC;
case Mips::BC1EQZ: return Mips::BC1NEZ;
case Mips::BC1NEZ: return Mips::BC1EQZ;
case Mips::BEQZC_MMR6: return Mips::BNEZC_MMR6;
case Mips::BNEZC_MMR6: return Mips::BEQZC_MMR6;
case Mips::BLEZC_MMR6: return Mips::BGTZC_MMR6;
case Mips::BGEZC_MMR6: return Mips::BLTZC_MMR6;
case Mips::BGEC_MMR6: return Mips::BLTC_MMR6;
case Mips::BGTZC_MMR6: return Mips::BLEZC_MMR6;
case Mips::BLTZC_MMR6: return Mips::BGEZC_MMR6;
case Mips::BLTC_MMR6: return Mips::BGEC_MMR6;
case Mips::BGEUC_MMR6: return Mips::BLTUC_MMR6;
case Mips::BLTUC_MMR6: return Mips::BGEUC_MMR6;
case Mips::BEQC_MMR6: return Mips::BNEC_MMR6;
case Mips::BNEC_MMR6: return Mips::BEQC_MMR6;
case Mips::BC1EQZC_MMR6: return Mips::BC1NEZC_MMR6;
case Mips::BC1NEZC_MMR6: return Mips::BC1EQZC_MMR6;
case Mips::BEQZC64: return Mips::BNEZC64;
case Mips::BNEZC64: return Mips::BEQZC64;
case Mips::BEQC64: return Mips::BNEC64;
case Mips::BNEC64: return Mips::BEQC64;
case Mips::BGEC64: return Mips::BLTC64;
case Mips::BGEUC64: return Mips::BLTUC64;
case Mips::BLTC64: return Mips::BGEC64;
case Mips::BLTUC64: return Mips::BGEUC64;
case Mips::BGTZC64: return Mips::BLEZC64;
case Mips::BGEZC64: return Mips::BLTZC64;
case Mips::BLTZC64: return Mips::BGEZC64;
case Mips::BLEZC64: return Mips::BGTZC64;
case Mips::BBIT0: return Mips::BBIT1;
case Mips::BBIT1: return Mips::BBIT0;
case Mips::BBIT032: return Mips::BBIT132;
case Mips::BBIT132: return Mips::BBIT032;
case Mips::BZ_B: return Mips::BNZ_B;
case Mips::BZ_H: return Mips::BNZ_H;
case Mips::BZ_W: return Mips::BNZ_W;
case Mips::BZ_D: return Mips::BNZ_D;
case Mips::BZ_V: return Mips::BNZ_V;
case Mips::BNZ_B: return Mips::BZ_B;
case Mips::BNZ_H: return Mips::BZ_H;
case Mips::BNZ_W: return Mips::BZ_W;
case Mips::BNZ_D: return Mips::BZ_D;
case Mips::BNZ_V: return Mips::BZ_V;
}
}
/// Adjust SP by Amount bytes.
void MipsSEInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
MipsABIInfo ABI = Subtarget.getABI();
DebugLoc DL;
unsigned ADDiu = ABI.GetPtrAddiuOp();
if (Amount == 0)
return;
if (isInt<16>(Amount)) {
// addi sp, sp, amount
BuildMI(MBB, I, DL, get(ADDiu), SP).addReg(SP).addImm(Amount);
} else {
// For numbers which are not 16bit integers we synthesize Amount inline
// then add or subtract it from sp.
unsigned Opc = ABI.GetPtrAdduOp();
if (Amount < 0) {
Opc = ABI.GetPtrSubuOp();
Amount = -Amount;
}
unsigned Reg = loadImmediate(Amount, MBB, I, DL, nullptr);
BuildMI(MBB, I, DL, get(Opc), SP).addReg(SP).addReg(Reg, RegState::Kill);
}
}
/// This function generates the sequence of instructions needed to get the
/// result of adding register REG and immediate IMM.
unsigned MipsSEInstrInfo::loadImmediate(int64_t Imm, MachineBasicBlock &MBB,
MachineBasicBlock::iterator II,
const DebugLoc &DL,
unsigned *NewImm) const {
MipsAnalyzeImmediate AnalyzeImm;
const MipsSubtarget &STI = Subtarget;
MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo();
unsigned Size = STI.isABI_N64() ? 64 : 32;
unsigned LUi = STI.isABI_N64() ? Mips::LUi64 : Mips::LUi;
unsigned ZEROReg = STI.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO;
const TargetRegisterClass *RC = STI.isABI_N64() ?
&Mips::GPR64RegClass : &Mips::GPR32RegClass;
bool LastInstrIsADDiu = NewImm;
const MipsAnalyzeImmediate::InstSeq &Seq =
AnalyzeImm.Analyze(Imm, Size, LastInstrIsADDiu);
MipsAnalyzeImmediate::InstSeq::const_iterator Inst = Seq.begin();
assert(Seq.size() && (!LastInstrIsADDiu || (Seq.size() > 1)));
// The first instruction can be a LUi, which is different from other
// instructions (ADDiu, ORI and SLL) in that it does not have a register
// operand.
unsigned Reg = RegInfo.createVirtualRegister(RC);
if (Inst->Opc == LUi)
BuildMI(MBB, II, DL, get(LUi), Reg).addImm(SignExtend64<16>(Inst->ImmOpnd));
else
BuildMI(MBB, II, DL, get(Inst->Opc), Reg).addReg(ZEROReg)
.addImm(SignExtend64<16>(Inst->ImmOpnd));
// Build the remaining instructions in Seq.
for (++Inst; Inst != Seq.end() - LastInstrIsADDiu; ++Inst)
BuildMI(MBB, II, DL, get(Inst->Opc), Reg).addReg(Reg, RegState::Kill)
.addImm(SignExtend64<16>(Inst->ImmOpnd));
if (LastInstrIsADDiu)
*NewImm = Inst->ImmOpnd;
return Reg;
}
unsigned MipsSEInstrInfo::getAnalyzableBrOpc(unsigned Opc) const {
return (Opc == Mips::BEQ || Opc == Mips::BEQ_MM || Opc == Mips::BNE ||
Opc == Mips::BNE_MM || Opc == Mips::BGTZ || Opc == Mips::BGEZ ||
Opc == Mips::BLTZ || Opc == Mips::BLEZ || Opc == Mips::BEQ64 ||
Opc == Mips::BNE64 || Opc == Mips::BGTZ64 || Opc == Mips::BGEZ64 ||
Opc == Mips::BLTZ64 || Opc == Mips::BLEZ64 || Opc == Mips::BC1T ||
Opc == Mips::BC1F || Opc == Mips::B || Opc == Mips::J ||
Opc == Mips::J_MM || Opc == Mips::B_MM || Opc == Mips::BEQZC_MM ||
Opc == Mips::BNEZC_MM || Opc == Mips::BEQC || Opc == Mips::BNEC ||
Opc == Mips::BLTC || Opc == Mips::BGEC || Opc == Mips::BLTUC ||
Opc == Mips::BGEUC || Opc == Mips::BGTZC || Opc == Mips::BLEZC ||
Opc == Mips::BGEZC || Opc == Mips::BLTZC || Opc == Mips::BEQZC ||
Opc == Mips::BNEZC || Opc == Mips::BEQZC64 || Opc == Mips::BNEZC64 ||
Opc == Mips::BEQC64 || Opc == Mips::BNEC64 || Opc == Mips::BGEC64 ||
Opc == Mips::BGEUC64 || Opc == Mips::BLTC64 || Opc == Mips::BLTUC64 ||
Opc == Mips::BGTZC64 || Opc == Mips::BGEZC64 ||
Opc == Mips::BLTZC64 || Opc == Mips::BLEZC64 || Opc == Mips::BC ||
Opc == Mips::BBIT0 || Opc == Mips::BBIT1 || Opc == Mips::BBIT032 ||
Opc == Mips::BBIT132 || Opc == Mips::BC_MMR6 ||
Opc == Mips::BEQC_MMR6 || Opc == Mips::BNEC_MMR6 ||
Opc == Mips::BLTC_MMR6 || Opc == Mips::BGEC_MMR6 ||
Opc == Mips::BLTUC_MMR6 || Opc == Mips::BGEUC_MMR6 ||
Opc == Mips::BGTZC_MMR6 || Opc == Mips::BLEZC_MMR6 ||
Opc == Mips::BGEZC_MMR6 || Opc == Mips::BLTZC_MMR6 ||
Opc == Mips::BEQZC_MMR6 || Opc == Mips::BNEZC_MMR6) ? Opc : 0;
}
void MipsSEInstrInfo::expandRetRA(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
MachineInstrBuilder MIB;
if (Subtarget.isGP64bit())
MIB = BuildMI(MBB, I, I->getDebugLoc(), get(Mips::PseudoReturn64))
.addReg(Mips::RA_64, RegState::Undef);
else
MIB = BuildMI(MBB, I, I->getDebugLoc(), get(Mips::PseudoReturn))
.addReg(Mips::RA, RegState::Undef);
// Retain any imp-use flags.
for (auto & MO : I->operands()) {
if (MO.isImplicit())
MIB.add(MO);
}
}
void MipsSEInstrInfo::expandERet(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
BuildMI(MBB, I, I->getDebugLoc(), get(Mips::ERET));
}
std::pair<bool, bool>
MipsSEInstrInfo::compareOpndSize(unsigned Opc,
const MachineFunction &MF) const {
const MCInstrDesc &Desc = get(Opc);
assert(Desc.NumOperands == 2 && "Unary instruction expected.");
const MipsRegisterInfo *RI = &getRegisterInfo();
unsigned DstRegSize = RI->getRegSizeInBits(*getRegClass(Desc, 0, RI, MF));
unsigned SrcRegSize = RI->getRegSizeInBits(*getRegClass(Desc, 1, RI, MF));
return std::make_pair(DstRegSize > SrcRegSize, DstRegSize < SrcRegSize);
}
void MipsSEInstrInfo::expandPseudoMFHiLo(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned NewOpc) const {
BuildMI(MBB, I, I->getDebugLoc(), get(NewOpc), I->getOperand(0).getReg());
}
void MipsSEInstrInfo::expandPseudoMTLoHi(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned LoOpc,
unsigned HiOpc,
bool HasExplicitDef) const {
// Expand
// lo_hi pseudomtlohi $gpr0, $gpr1
// to these two instructions:
// mtlo $gpr0
// mthi $gpr1
DebugLoc DL = I->getDebugLoc();
const MachineOperand &SrcLo = I->getOperand(1), &SrcHi = I->getOperand(2);
MachineInstrBuilder LoInst = BuildMI(MBB, I, DL, get(LoOpc));
MachineInstrBuilder HiInst = BuildMI(MBB, I, DL, get(HiOpc));
// Add lo/hi registers if the mtlo/hi instructions created have explicit
// def registers.
if (HasExplicitDef) {
unsigned DstReg = I->getOperand(0).getReg();
unsigned DstLo = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo);
unsigned DstHi = getRegisterInfo().getSubReg(DstReg, Mips::sub_hi);
LoInst.addReg(DstLo, RegState::Define);
HiInst.addReg(DstHi, RegState::Define);
}
LoInst.addReg(SrcLo.getReg(), getKillRegState(SrcLo.isKill()));
HiInst.addReg(SrcHi.getReg(), getKillRegState(SrcHi.isKill()));
}
void MipsSEInstrInfo::expandCvtFPInt(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned CvtOpc, unsigned MovOpc,
bool IsI64) const {
const MCInstrDesc &CvtDesc = get(CvtOpc), &MovDesc = get(MovOpc);
const MachineOperand &Dst = I->getOperand(0), &Src = I->getOperand(1);
unsigned DstReg = Dst.getReg(), SrcReg = Src.getReg(), TmpReg = DstReg;
unsigned KillSrc = getKillRegState(Src.isKill());
DebugLoc DL = I->getDebugLoc();
bool DstIsLarger, SrcIsLarger;
std::tie(DstIsLarger, SrcIsLarger) =
compareOpndSize(CvtOpc, *MBB.getParent());
if (DstIsLarger)
TmpReg = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo);
if (SrcIsLarger)
DstReg = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo);
BuildMI(MBB, I, DL, MovDesc, TmpReg).addReg(SrcReg, KillSrc);
BuildMI(MBB, I, DL, CvtDesc, DstReg).addReg(TmpReg, RegState::Kill);
}
void MipsSEInstrInfo::expandExtractElementF64(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
bool isMicroMips,
bool FP64) const {
unsigned DstReg = I->getOperand(0).getReg();
unsigned SrcReg = I->getOperand(1).getReg();
unsigned N = I->getOperand(2).getImm();
DebugLoc dl = I->getDebugLoc();
assert(N < 2 && "Invalid immediate");
unsigned SubIdx = N ? Mips::sub_hi : Mips::sub_lo;
unsigned SubReg = getRegisterInfo().getSubReg(SrcReg, SubIdx);
// FPXX on MIPS-II or MIPS32r1 should have been handled with a spill/reload
// in MipsSEFrameLowering.cpp.
assert(!(Subtarget.isABI_FPXX() && !Subtarget.hasMips32r2()));
// FP64A (FP64 with nooddspreg) should have been handled with a spill/reload
// in MipsSEFrameLowering.cpp.
assert(!(Subtarget.isFP64bit() && !Subtarget.useOddSPReg()));
if (SubIdx == Mips::sub_hi && Subtarget.hasMTHC1()) {
// FIXME: Strictly speaking MFHC1 only reads the top 32-bits however, we
// claim to read the whole 64-bits as part of a white lie used to
// temporarily work around a widespread bug in the -mfp64 support.
// The problem is that none of the 32-bit fpu ops mention the fact
// that they clobber the upper 32-bits of the 64-bit FPR. Fixing that
// requires a major overhaul of the FPU implementation which can't
// be done right now due to time constraints.
// MFHC1 is one of two instructions that are affected since they are
// the only instructions that don't read the lower 32-bits.
// We therefore pretend that it reads the bottom 32-bits to
// artificially create a dependency and prevent the scheduler
// changing the behaviour of the code.
BuildMI(MBB, I, dl,
get(isMicroMips ? (FP64 ? Mips::MFHC1_D64_MM : Mips::MFHC1_D32_MM)
: (FP64 ? Mips::MFHC1_D64 : Mips::MFHC1_D32)),
DstReg)
.addReg(SrcReg);
} else
BuildMI(MBB, I, dl, get(Mips::MFC1), DstReg).addReg(SubReg);
}
void MipsSEInstrInfo::expandBuildPairF64(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
bool isMicroMips, bool FP64) const {
unsigned DstReg = I->getOperand(0).getReg();
unsigned LoReg = I->getOperand(1).getReg(), HiReg = I->getOperand(2).getReg();
const MCInstrDesc& Mtc1Tdd = get(Mips::MTC1);
DebugLoc dl = I->getDebugLoc();
const TargetRegisterInfo &TRI = getRegisterInfo();
// When mthc1 is available, use:
// mtc1 Lo, $fp
// mthc1 Hi, $fp
//
// Otherwise, for O32 FPXX ABI:
// spill + reload via ldc1
// This case is handled by the frame lowering code.
//
// Otherwise, for FP32:
// mtc1 Lo, $fp
// mtc1 Hi, $fp + 1
//
// The case where dmtc1 is available doesn't need to be handled here
// because it never creates a BuildPairF64 node.
// FPXX on MIPS-II or MIPS32r1 should have been handled with a spill/reload
// in MipsSEFrameLowering.cpp.
assert(!(Subtarget.isABI_FPXX() && !Subtarget.hasMips32r2()));
// FP64A (FP64 with nooddspreg) should have been handled with a spill/reload
// in MipsSEFrameLowering.cpp.
assert(!(Subtarget.isFP64bit() && !Subtarget.useOddSPReg()));
BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_lo))
.addReg(LoReg);
if (Subtarget.hasMTHC1()) {
// FIXME: The .addReg(DstReg) is a white lie used to temporarily work
// around a widespread bug in the -mfp64 support.
// The problem is that none of the 32-bit fpu ops mention the fact
// that they clobber the upper 32-bits of the 64-bit FPR. Fixing that
// requires a major overhaul of the FPU implementation which can't
// be done right now due to time constraints.
// MTHC1 is one of two instructions that are affected since they are
// the only instructions that don't read the lower 32-bits.
// We therefore pretend that it reads the bottom 32-bits to
// artificially create a dependency and prevent the scheduler
// changing the behaviour of the code.
BuildMI(MBB, I, dl,
get(isMicroMips ? (FP64 ? Mips::MTHC1_D64_MM : Mips::MTHC1_D32_MM)
: (FP64 ? Mips::MTHC1_D64 : Mips::MTHC1_D32)),
DstReg)
.addReg(DstReg)
.addReg(HiReg);
} else if (Subtarget.isABI_FPXX())
llvm_unreachable("BuildPairF64 not expanded in frame lowering code!");
else
BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_hi))
.addReg(HiReg);
}
void MipsSEInstrInfo::expandEhReturn(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
// This pseudo instruction is generated as part of the lowering of
// ISD::EH_RETURN. We convert it to a stack increment by OffsetReg, and
// indirect jump to TargetReg
MipsABIInfo ABI = Subtarget.getABI();
unsigned ADDU = ABI.GetPtrAdduOp();
unsigned SP = Subtarget.isGP64bit() ? Mips::SP_64 : Mips::SP;
unsigned RA = Subtarget.isGP64bit() ? Mips::RA_64 : Mips::RA;
unsigned T9 = Subtarget.isGP64bit() ? Mips::T9_64 : Mips::T9;
unsigned ZERO = Subtarget.isGP64bit() ? Mips::ZERO_64 : Mips::ZERO;
unsigned OffsetReg = I->getOperand(0).getReg();
unsigned TargetReg = I->getOperand(1).getReg();
// addu $ra, $v0, $zero
// addu $sp, $sp, $v1
// jr $ra (via RetRA)
const TargetMachine &TM = MBB.getParent()->getTarget();
if (TM.isPositionIndependent())
BuildMI(MBB, I, I->getDebugLoc(), get(ADDU), T9)
.addReg(TargetReg)
.addReg(ZERO);
BuildMI(MBB, I, I->getDebugLoc(), get(ADDU), RA)
.addReg(TargetReg)
.addReg(ZERO);
BuildMI(MBB, I, I->getDebugLoc(), get(ADDU), SP).addReg(SP).addReg(OffsetReg);
expandRetRA(MBB, I);
}
const MipsInstrInfo *llvm::createMipsSEInstrInfo(const MipsSubtarget &STI) {
return new MipsSEInstrInfo(STI);
}
Index: stable/11/contrib/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp (revision 350259)
@@ -1,357 +1,365 @@
//===------ PPCDisassembler.cpp - Disassembler for PowerPC ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/PPCMCTargetDesc.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
#include "llvm/MC/MCFixedLenDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
DEFINE_PPC_REGCLASSES;
#define DEBUG_TYPE "ppc-disassembler"
typedef MCDisassembler::DecodeStatus DecodeStatus;
namespace {
class PPCDisassembler : public MCDisassembler {
bool IsLittleEndian;
public:
PPCDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
bool IsLittleEndian)
: MCDisassembler(STI, Ctx), IsLittleEndian(IsLittleEndian) {}
DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &VStream,
raw_ostream &CStream) const override;
};
} // end anonymous namespace
static MCDisassembler *createPPCDisassembler(const Target &T,
const MCSubtargetInfo &STI,
MCContext &Ctx) {
return new PPCDisassembler(STI, Ctx, /*IsLittleEndian=*/false);
}
static MCDisassembler *createPPCLEDisassembler(const Target &T,
const MCSubtargetInfo &STI,
MCContext &Ctx) {
return new PPCDisassembler(STI, Ctx, /*IsLittleEndian=*/true);
}
extern "C" void LLVMInitializePowerPCDisassembler() {
// Register the disassembler for each target.
TargetRegistry::RegisterMCDisassembler(getThePPC32Target(),
createPPCDisassembler);
TargetRegistry::RegisterMCDisassembler(getThePPC64Target(),
createPPCDisassembler);
TargetRegistry::RegisterMCDisassembler(getThePPC64LETarget(),
createPPCLEDisassembler);
}
+static DecodeStatus DecodePCRel24BranchTarget(MCInst &Inst, unsigned Imm,
+ uint64_t Addr,
+ const void *Decoder) {
+ int32_t Offset = SignExtend32<24>(Imm);
+ Inst.addOperand(MCOperand::createImm(Offset));
+ return MCDisassembler::Success;
+}
+
// FIXME: These can be generated by TableGen from the existing register
// encoding values!
template <std::size_t N>
static DecodeStatus decodeRegisterClass(MCInst &Inst, uint64_t RegNo,
const MCPhysReg (&Regs)[N]) {
assert(RegNo < N && "Invalid register number");
Inst.addOperand(MCOperand::createReg(Regs[RegNo]));
return MCDisassembler::Success;
}
static DecodeStatus DecodeCRRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, CRRegs);
}
static DecodeStatus DecodeCRRC0RegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, CRRegs);
}
static DecodeStatus DecodeCRBITRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, CRBITRegs);
}
static DecodeStatus DecodeF4RCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, FRegs);
}
static DecodeStatus DecodeF8RCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, FRegs);
}
static DecodeStatus DecodeVFRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, VFRegs);
}
static DecodeStatus DecodeVRRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, VRegs);
}
static DecodeStatus DecodeVSRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, VSRegs);
}
static DecodeStatus DecodeVSFRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, VSFRegs);
}
static DecodeStatus DecodeVSSRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, VSSRegs);
}
static DecodeStatus DecodeGPRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, RRegs);
}
static DecodeStatus DecodeGPRC_NOR0RegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, RRegsNoR0);
}
static DecodeStatus DecodeG8RCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, XRegs);
}
static DecodeStatus DecodeG8RC_NOX0RegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, XRegsNoX0);
}
#define DecodePointerLikeRegClass0 DecodeGPRCRegisterClass
#define DecodePointerLikeRegClass1 DecodeGPRC_NOR0RegisterClass
static DecodeStatus DecodeQFRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, QFRegs);
}
static DecodeStatus DecodeSPE4RCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, RRegs);
}
static DecodeStatus DecodeSPERCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
return decodeRegisterClass(Inst, RegNo, SPERegs);
}
#define DecodeQSRCRegisterClass DecodeQFRCRegisterClass
#define DecodeQBRCRegisterClass DecodeQFRCRegisterClass
template<unsigned N>
static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder) {
assert(isUInt<N>(Imm) && "Invalid immediate");
Inst.addOperand(MCOperand::createImm(Imm));
return MCDisassembler::Success;
}
template<unsigned N>
static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder) {
assert(isUInt<N>(Imm) && "Invalid immediate");
Inst.addOperand(MCOperand::createImm(SignExtend64<N>(Imm)));
return MCDisassembler::Success;
}
static DecodeStatus decodeMemRIOperands(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder) {
// Decode the memri field (imm, reg), which has the low 16-bits as the
// displacement and the next 5 bits as the register #.
uint64_t Base = Imm >> 16;
uint64_t Disp = Imm & 0xFFFF;
assert(Base < 32 && "Invalid base register");
switch (Inst.getOpcode()) {
default: break;
case PPC::LBZU:
case PPC::LHAU:
case PPC::LHZU:
case PPC::LWZU:
case PPC::LFSU:
case PPC::LFDU:
// Add the tied output operand.
Inst.addOperand(MCOperand::createReg(RRegsNoR0[Base]));
break;
case PPC::STBU:
case PPC::STHU:
case PPC::STWU:
case PPC::STFSU:
case PPC::STFDU:
Inst.insert(Inst.begin(), MCOperand::createReg(RRegsNoR0[Base]));
break;
}
Inst.addOperand(MCOperand::createImm(SignExtend64<16>(Disp)));
Inst.addOperand(MCOperand::createReg(RRegsNoR0[Base]));
return MCDisassembler::Success;
}
static DecodeStatus decodeMemRIXOperands(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder) {
// Decode the memrix field (imm, reg), which has the low 14-bits as the
// displacement and the next 5 bits as the register #.
uint64_t Base = Imm >> 14;
uint64_t Disp = Imm & 0x3FFF;
assert(Base < 32 && "Invalid base register");
if (Inst.getOpcode() == PPC::LDU)
// Add the tied output operand.
Inst.addOperand(MCOperand::createReg(RRegsNoR0[Base]));
else if (Inst.getOpcode() == PPC::STDU)
Inst.insert(Inst.begin(), MCOperand::createReg(RRegsNoR0[Base]));
Inst.addOperand(MCOperand::createImm(SignExtend64<16>(Disp << 2)));
Inst.addOperand(MCOperand::createReg(RRegsNoR0[Base]));
return MCDisassembler::Success;
}
static DecodeStatus decodeMemRIX16Operands(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder) {
// Decode the memrix16 field (imm, reg), which has the low 12-bits as the
// displacement with 16-byte aligned, and the next 5 bits as the register #.
uint64_t Base = Imm >> 12;
uint64_t Disp = Imm & 0xFFF;
assert(Base < 32 && "Invalid base register");
Inst.addOperand(MCOperand::createImm(SignExtend64<16>(Disp << 4)));
Inst.addOperand(MCOperand::createReg(RRegsNoR0[Base]));
return MCDisassembler::Success;
}
static DecodeStatus decodeSPE8Operands(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder) {
// Decode the spe8disp field (imm, reg), which has the low 5-bits as the
// displacement with 8-byte aligned, and the next 5 bits as the register #.
uint64_t Base = Imm >> 5;
uint64_t Disp = Imm & 0x1F;
assert(Base < 32 && "Invalid base register");
Inst.addOperand(MCOperand::createImm(Disp << 3));
Inst.addOperand(MCOperand::createReg(RRegsNoR0[Base]));
return MCDisassembler::Success;
}
static DecodeStatus decodeSPE4Operands(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder) {
// Decode the spe4disp field (imm, reg), which has the low 5-bits as the
// displacement with 4-byte aligned, and the next 5 bits as the register #.
uint64_t Base = Imm >> 5;
uint64_t Disp = Imm & 0x1F;
assert(Base < 32 && "Invalid base register");
Inst.addOperand(MCOperand::createImm(Disp << 2));
Inst.addOperand(MCOperand::createReg(RRegsNoR0[Base]));
return MCDisassembler::Success;
}
static DecodeStatus decodeSPE2Operands(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder) {
// Decode the spe2disp field (imm, reg), which has the low 5-bits as the
// displacement with 2-byte aligned, and the next 5 bits as the register #.
uint64_t Base = Imm >> 5;
uint64_t Disp = Imm & 0x1F;
assert(Base < 32 && "Invalid base register");
Inst.addOperand(MCOperand::createImm(Disp << 1));
Inst.addOperand(MCOperand::createReg(RRegsNoR0[Base]));
return MCDisassembler::Success;
}
static DecodeStatus decodeCRBitMOperand(MCInst &Inst, uint64_t Imm,
int64_t Address, const void *Decoder) {
// The cr bit encoding is 0x80 >> cr_reg_num.
unsigned Zeros = countTrailingZeros(Imm);
assert(Zeros < 8 && "Invalid CR bit value");
Inst.addOperand(MCOperand::createReg(CRRegs[7 - Zeros]));
return MCDisassembler::Success;
}
#include "PPCGenDisassemblerTables.inc"
DecodeStatus PPCDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
ArrayRef<uint8_t> Bytes,
uint64_t Address, raw_ostream &OS,
raw_ostream &CS) const {
// Get the four bytes of the instruction.
Size = 4;
if (Bytes.size() < 4) {
Size = 0;
return MCDisassembler::Fail;
}
// Read the instruction in the proper endianness.
uint32_t Inst = IsLittleEndian ? support::endian::read32le(Bytes.data())
: support::endian::read32be(Bytes.data());
if (STI.getFeatureBits()[PPC::FeatureQPX]) {
DecodeStatus result =
decodeInstruction(DecoderTableQPX32, MI, Inst, Address, this, STI);
if (result != MCDisassembler::Fail)
return result;
} else if (STI.getFeatureBits()[PPC::FeatureSPE]) {
DecodeStatus result =
decodeInstruction(DecoderTableSPE32, MI, Inst, Address, this, STI);
if (result != MCDisassembler::Fail)
return result;
}
return decodeInstruction(DecoderTable32, MI, Inst, Address, this, STI);
}
Index: stable/11/contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.cpp (revision 350259)
@@ -1,532 +1,535 @@
//===-- PPCInstPrinter.cpp - Convert PPC MCInst to assembly syntax --------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class prints an PPC MCInst to a .s file.
//
//===----------------------------------------------------------------------===//
#include "PPCInstPrinter.h"
#include "MCTargetDesc/PPCMCTargetDesc.h"
#include "MCTargetDesc/PPCPredicates.h"
#include "PPCInstrInfo.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "asm-printer"
// FIXME: Once the integrated assembler supports full register names, tie this
// to the verbose-asm setting.
static cl::opt<bool>
FullRegNames("ppc-asm-full-reg-names", cl::Hidden, cl::init(false),
cl::desc("Use full register names when printing assembly"));
// Useful for testing purposes. Prints vs{31-63} as v{0-31} respectively.
static cl::opt<bool>
ShowVSRNumsAsVR("ppc-vsr-nums-as-vr", cl::Hidden, cl::init(false),
cl::desc("Prints full register names with vs{31-63} as v{0-31}"));
// Prints full register names with percent symbol.
static cl::opt<bool>
FullRegNamesWithPercent("ppc-reg-with-percent-prefix", cl::Hidden,
cl::init(false),
cl::desc("Prints full register names with percent"));
#define PRINT_ALIAS_INSTR
#include "PPCGenAsmWriter.inc"
void PPCInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
const char *RegName = getRegisterName(RegNo);
if (RegName[0] == 'q' /* QPX */) {
// The system toolchain on the BG/Q does not understand QPX register names
// in .cfi_* directives, so print the name of the floating-point
// subregister instead.
std::string RN(RegName);
RN[0] = 'f';
OS << RN;
return;
}
OS << RegName;
}
void PPCInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
StringRef Annot, const MCSubtargetInfo &STI) {
// Check for slwi/srwi mnemonics.
if (MI->getOpcode() == PPC::RLWINM) {
unsigned char SH = MI->getOperand(2).getImm();
unsigned char MB = MI->getOperand(3).getImm();
unsigned char ME = MI->getOperand(4).getImm();
bool useSubstituteMnemonic = false;
if (SH <= 31 && MB == 0 && ME == (31-SH)) {
O << "\tslwi "; useSubstituteMnemonic = true;
}
if (SH <= 31 && MB == (32-SH) && ME == 31) {
O << "\tsrwi "; useSubstituteMnemonic = true;
SH = 32-SH;
}
if (useSubstituteMnemonic) {
printOperand(MI, 0, O);
O << ", ";
printOperand(MI, 1, O);
O << ", " << (unsigned int)SH;
printAnnotation(O, Annot);
return;
}
}
if ((MI->getOpcode() == PPC::OR || MI->getOpcode() == PPC::OR8) &&
MI->getOperand(1).getReg() == MI->getOperand(2).getReg()) {
O << "\tmr ";
printOperand(MI, 0, O);
O << ", ";
printOperand(MI, 1, O);
printAnnotation(O, Annot);
return;
}
if (MI->getOpcode() == PPC::RLDICR ||
MI->getOpcode() == PPC::RLDICR_32) {
unsigned char SH = MI->getOperand(2).getImm();
unsigned char ME = MI->getOperand(3).getImm();
// rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH
if (63-SH == ME) {
O << "\tsldi ";
printOperand(MI, 0, O);
O << ", ";
printOperand(MI, 1, O);
O << ", " << (unsigned int)SH;
printAnnotation(O, Annot);
return;
}
}
// dcbt[st] is printed manually here because:
// 1. The assembly syntax is different between embedded and server targets
// 2. We must print the short mnemonics for TH == 0 because the
// embedded/server syntax default will not be stable across assemblers
// The syntax for dcbt is:
// dcbt ra, rb, th [server]
// dcbt th, ra, rb [embedded]
// where th can be omitted when it is 0. dcbtst is the same.
if (MI->getOpcode() == PPC::DCBT || MI->getOpcode() == PPC::DCBTST) {
unsigned char TH = MI->getOperand(0).getImm();
O << "\tdcbt";
if (MI->getOpcode() == PPC::DCBTST)
O << "st";
if (TH == 16)
O << "t";
O << " ";
bool IsBookE = STI.getFeatureBits()[PPC::FeatureBookE];
if (IsBookE && TH != 0 && TH != 16)
O << (unsigned int) TH << ", ";
printOperand(MI, 1, O);
O << ", ";
printOperand(MI, 2, O);
if (!IsBookE && TH != 0 && TH != 16)
O << ", " << (unsigned int) TH;
printAnnotation(O, Annot);
return;
}
if (MI->getOpcode() == PPC::DCBF) {
unsigned char L = MI->getOperand(0).getImm();
if (!L || L == 1 || L == 3) {
O << "\tdcbf";
if (L == 1 || L == 3)
O << "l";
if (L == 3)
O << "p";
O << " ";
printOperand(MI, 1, O);
O << ", ";
printOperand(MI, 2, O);
printAnnotation(O, Annot);
return;
}
}
if (!printAliasInstr(MI, O))
printInstruction(MI, O);
printAnnotation(O, Annot);
}
void PPCInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O,
const char *Modifier) {
unsigned Code = MI->getOperand(OpNo).getImm();
if (StringRef(Modifier) == "cc") {
switch ((PPC::Predicate)Code) {
case PPC::PRED_LT_MINUS:
case PPC::PRED_LT_PLUS:
case PPC::PRED_LT:
O << "lt";
return;
case PPC::PRED_LE_MINUS:
case PPC::PRED_LE_PLUS:
case PPC::PRED_LE:
O << "le";
return;
case PPC::PRED_EQ_MINUS:
case PPC::PRED_EQ_PLUS:
case PPC::PRED_EQ:
O << "eq";
return;
case PPC::PRED_GE_MINUS:
case PPC::PRED_GE_PLUS:
case PPC::PRED_GE:
O << "ge";
return;
case PPC::PRED_GT_MINUS:
case PPC::PRED_GT_PLUS:
case PPC::PRED_GT:
O << "gt";
return;
case PPC::PRED_NE_MINUS:
case PPC::PRED_NE_PLUS:
case PPC::PRED_NE:
O << "ne";
return;
case PPC::PRED_UN_MINUS:
case PPC::PRED_UN_PLUS:
case PPC::PRED_UN:
O << "un";
return;
case PPC::PRED_NU_MINUS:
case PPC::PRED_NU_PLUS:
case PPC::PRED_NU:
O << "nu";
return;
case PPC::PRED_BIT_SET:
case PPC::PRED_BIT_UNSET:
llvm_unreachable("Invalid use of bit predicate code");
}
llvm_unreachable("Invalid predicate code");
}
if (StringRef(Modifier) == "pm") {
switch ((PPC::Predicate)Code) {
case PPC::PRED_LT:
case PPC::PRED_LE:
case PPC::PRED_EQ:
case PPC::PRED_GE:
case PPC::PRED_GT:
case PPC::PRED_NE:
case PPC::PRED_UN:
case PPC::PRED_NU:
return;
case PPC::PRED_LT_MINUS:
case PPC::PRED_LE_MINUS:
case PPC::PRED_EQ_MINUS:
case PPC::PRED_GE_MINUS:
case PPC::PRED_GT_MINUS:
case PPC::PRED_NE_MINUS:
case PPC::PRED_UN_MINUS:
case PPC::PRED_NU_MINUS:
O << "-";
return;
case PPC::PRED_LT_PLUS:
case PPC::PRED_LE_PLUS:
case PPC::PRED_EQ_PLUS:
case PPC::PRED_GE_PLUS:
case PPC::PRED_GT_PLUS:
case PPC::PRED_NE_PLUS:
case PPC::PRED_UN_PLUS:
case PPC::PRED_NU_PLUS:
O << "+";
return;
case PPC::PRED_BIT_SET:
case PPC::PRED_BIT_UNSET:
llvm_unreachable("Invalid use of bit predicate code");
}
llvm_unreachable("Invalid predicate code");
}
assert(StringRef(Modifier) == "reg" &&
"Need to specify 'cc', 'pm' or 'reg' as predicate op modifier!");
printOperand(MI, OpNo+1, O);
}
void PPCInstPrinter::printATBitsAsHint(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned Code = MI->getOperand(OpNo).getImm();
if (Code == 2)
O << "-";
else if (Code == 3)
O << "+";
}
void PPCInstPrinter::printU1ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 1 && "Invalid u1imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU2ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 3 && "Invalid u2imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU3ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 8 && "Invalid u3imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU4ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 15 && "Invalid u4imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printS5ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
int Value = MI->getOperand(OpNo).getImm();
Value = SignExtend32<5>(Value);
O << (int)Value;
}
void PPCInstPrinter::printU5ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 31 && "Invalid u5imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU6ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 63 && "Invalid u6imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU7ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 127 && "Invalid u7imm argument!");
O << (unsigned int)Value;
}
// Operands of BUILD_VECTOR are signed and we use this to print operands
// of XXSPLTIB which are unsigned. So we simply truncate to 8 bits and
// print as unsigned.
void PPCInstPrinter::printU8ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned char Value = MI->getOperand(OpNo).getImm();
O << (unsigned int)Value;
}
void PPCInstPrinter::printU10ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned short Value = MI->getOperand(OpNo).getImm();
assert(Value <= 1023 && "Invalid u10imm argument!");
O << (unsigned short)Value;
}
void PPCInstPrinter::printU12ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned short Value = MI->getOperand(OpNo).getImm();
assert(Value <= 4095 && "Invalid u12imm argument!");
O << (unsigned short)Value;
}
void PPCInstPrinter::printS16ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (MI->getOperand(OpNo).isImm())
O << (short)MI->getOperand(OpNo).getImm();
else
printOperand(MI, OpNo, O);
}
void PPCInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (MI->getOperand(OpNo).isImm())
O << (unsigned short)MI->getOperand(OpNo).getImm();
else
printOperand(MI, OpNo, O);
}
void PPCInstPrinter::printBranchOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (!MI->getOperand(OpNo).isImm())
return printOperand(MI, OpNo, O);
// Branches can take an immediate operand. This is used by the branch
// selection pass to print .+8, an eight byte displacement from the PC.
- O << ".+";
- printAbsBranchOperand(MI, OpNo, O);
+ O << ".";
+ int32_t Imm = SignExtend32<32>((unsigned)MI->getOperand(OpNo).getImm() << 2);
+ if (Imm >= 0)
+ O << "+";
+ O << Imm;
}
void PPCInstPrinter::printAbsBranchOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (!MI->getOperand(OpNo).isImm())
return printOperand(MI, OpNo, O);
O << SignExtend32<32>((unsigned)MI->getOperand(OpNo).getImm() << 2);
}
void PPCInstPrinter::printcrbitm(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned CCReg = MI->getOperand(OpNo).getReg();
unsigned RegNo;
switch (CCReg) {
default: llvm_unreachable("Unknown CR register");
case PPC::CR0: RegNo = 0; break;
case PPC::CR1: RegNo = 1; break;
case PPC::CR2: RegNo = 2; break;
case PPC::CR3: RegNo = 3; break;
case PPC::CR4: RegNo = 4; break;
case PPC::CR5: RegNo = 5; break;
case PPC::CR6: RegNo = 6; break;
case PPC::CR7: RegNo = 7; break;
}
O << (0x80 >> RegNo);
}
void PPCInstPrinter::printMemRegImm(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
printS16ImmOperand(MI, OpNo, O);
O << '(';
if (MI->getOperand(OpNo+1).getReg() == PPC::R0)
O << "0";
else
printOperand(MI, OpNo+1, O);
O << ')';
}
void PPCInstPrinter::printMemRegReg(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
// When used as the base register, r0 reads constant zero rather than
// the value contained in the register. For this reason, the darwin
// assembler requires that we print r0 as 0 (no r) when used as the base.
if (MI->getOperand(OpNo).getReg() == PPC::R0)
O << "0";
else
printOperand(MI, OpNo, O);
O << ", ";
printOperand(MI, OpNo+1, O);
}
void PPCInstPrinter::printTLSCall(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
// On PPC64, VariantKind is VK_None, but on PPC32, it's VK_PLT, and it must
// come at the _end_ of the expression.
const MCOperand &Op = MI->getOperand(OpNo);
const MCSymbolRefExpr &refExp = cast<MCSymbolRefExpr>(*Op.getExpr());
O << refExp.getSymbol().getName();
O << '(';
printOperand(MI, OpNo+1, O);
O << ')';
if (refExp.getKind() != MCSymbolRefExpr::VK_None)
O << '@' << MCSymbolRefExpr::getVariantKindName(refExp.getKind());
}
/// showRegistersWithPercentPrefix - Check if this register name should be
/// printed with a percentage symbol as prefix.
bool PPCInstPrinter::showRegistersWithPercentPrefix(const char *RegName) const {
if (!FullRegNamesWithPercent || TT.isOSDarwin() || TT.getOS() == Triple::AIX)
return false;
switch (RegName[0]) {
default:
return false;
case 'r':
case 'f':
case 'q':
case 'v':
case 'c':
return true;
}
}
/// getVerboseConditionalRegName - This method expands the condition register
/// when requested explicitly or targetting Darwin.
const char *PPCInstPrinter::getVerboseConditionRegName(unsigned RegNum,
unsigned RegEncoding)
const {
if (!TT.isOSDarwin() && !FullRegNames)
return nullptr;
if (RegNum < PPC::CR0EQ || RegNum > PPC::CR7UN)
return nullptr;
const char *CRBits[] = {
"lt", "gt", "eq", "un",
"4*cr1+lt", "4*cr1+gt", "4*cr1+eq", "4*cr1+un",
"4*cr2+lt", "4*cr2+gt", "4*cr2+eq", "4*cr2+un",
"4*cr3+lt", "4*cr3+gt", "4*cr3+eq", "4*cr3+un",
"4*cr4+lt", "4*cr4+gt", "4*cr4+eq", "4*cr4+un",
"4*cr5+lt", "4*cr5+gt", "4*cr5+eq", "4*cr5+un",
"4*cr6+lt", "4*cr6+gt", "4*cr6+eq", "4*cr6+un",
"4*cr7+lt", "4*cr7+gt", "4*cr7+eq", "4*cr7+un"
};
return CRBits[RegEncoding];
}
// showRegistersWithPrefix - This method determines whether registers
// should be number-only or include the prefix.
bool PPCInstPrinter::showRegistersWithPrefix() const {
if (TT.getOS() == Triple::AIX)
return false;
return TT.isOSDarwin() || FullRegNamesWithPercent || FullRegNames;
}
void PPCInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isReg()) {
unsigned Reg = Op.getReg();
if (!ShowVSRNumsAsVR)
Reg = PPCInstrInfo::getRegNumForOperand(MII.get(MI->getOpcode()),
Reg, OpNo);
const char *RegName;
RegName = getVerboseConditionRegName(Reg, MRI.getEncodingValue(Reg));
if (RegName == nullptr)
RegName = getRegisterName(Reg);
if (showRegistersWithPercentPrefix(RegName))
O << "%";
if (!showRegistersWithPrefix())
RegName = PPCRegisterInfo::stripRegisterPrefix(RegName);
O << RegName;
return;
}
if (Op.isImm()) {
O << Op.getImm();
return;
}
assert(Op.isExpr() && "unknown operand kind in printOperand");
Op.getExpr()->print(O, &MAI);
}
Index: stable/11/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp (revision 350259)
@@ -1,276 +1,294 @@
//===-- PPCMCTargetDesc.cpp - PowerPC Target Descriptions -----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides PowerPC specific target descriptions.
//
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/PPCMCTargetDesc.h"
#include "InstPrinter/PPCInstPrinter.h"
#include "MCTargetDesc/PPCMCAsmInfo.h"
#include "PPCTargetStreamer.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCELFStreamer.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCSymbolELF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define GET_INSTRINFO_MC_DESC
#include "PPCGenInstrInfo.inc"
#define GET_SUBTARGETINFO_MC_DESC
#include "PPCGenSubtargetInfo.inc"
#define GET_REGINFO_MC_DESC
#include "PPCGenRegisterInfo.inc"
// Pin the vtable to this file.
PPCTargetStreamer::PPCTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
PPCTargetStreamer::~PPCTargetStreamer() = default;
static MCInstrInfo *createPPCMCInstrInfo() {
MCInstrInfo *X = new MCInstrInfo();
InitPPCMCInstrInfo(X);
return X;
}
static MCRegisterInfo *createPPCMCRegisterInfo(const Triple &TT) {
bool isPPC64 =
(TT.getArch() == Triple::ppc64 || TT.getArch() == Triple::ppc64le);
unsigned Flavour = isPPC64 ? 0 : 1;
unsigned RA = isPPC64 ? PPC::LR8 : PPC::LR;
MCRegisterInfo *X = new MCRegisterInfo();
InitPPCMCRegisterInfo(X, RA, Flavour, Flavour);
return X;
}
static MCSubtargetInfo *createPPCMCSubtargetInfo(const Triple &TT,
StringRef CPU, StringRef FS) {
return createPPCMCSubtargetInfoImpl(TT, CPU, FS);
}
static MCAsmInfo *createPPCMCAsmInfo(const MCRegisterInfo &MRI,
const Triple &TheTriple) {
bool isPPC64 = (TheTriple.getArch() == Triple::ppc64 ||
TheTriple.getArch() == Triple::ppc64le);
MCAsmInfo *MAI;
if (TheTriple.isOSDarwin())
MAI = new PPCMCAsmInfoDarwin(isPPC64, TheTriple);
else
MAI = new PPCELFMCAsmInfo(isPPC64, TheTriple);
// Initial state of the frame pointer is R1.
unsigned Reg = isPPC64 ? PPC::X1 : PPC::R1;
MCCFIInstruction Inst =
MCCFIInstruction::createDefCfa(nullptr, MRI.getDwarfRegNum(Reg, true), 0);
MAI->addInitialFrameState(Inst);
return MAI;
}
namespace {
class PPCTargetAsmStreamer : public PPCTargetStreamer {
formatted_raw_ostream &OS;
public:
PPCTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS)
: PPCTargetStreamer(S), OS(OS) {}
void emitTCEntry(const MCSymbol &S) override {
OS << "\t.tc ";
OS << S.getName();
OS << "[TC],";
OS << S.getName();
OS << '\n';
}
void emitMachine(StringRef CPU) override {
OS << "\t.machine " << CPU << '\n';
}
void emitAbiVersion(int AbiVersion) override {
OS << "\t.abiversion " << AbiVersion << '\n';
}
void emitLocalEntry(MCSymbolELF *S, const MCExpr *LocalOffset) override {
const MCAsmInfo *MAI = Streamer.getContext().getAsmInfo();
OS << "\t.localentry\t";
S->print(OS, MAI);
OS << ", ";
LocalOffset->print(OS, MAI);
OS << '\n';
}
};
class PPCTargetELFStreamer : public PPCTargetStreamer {
public:
PPCTargetELFStreamer(MCStreamer &S) : PPCTargetStreamer(S) {}
MCELFStreamer &getStreamer() {
return static_cast<MCELFStreamer &>(Streamer);
}
void emitTCEntry(const MCSymbol &S) override {
// Creates a R_PPC64_TOC relocation
Streamer.EmitValueToAlignment(8);
Streamer.EmitSymbolValue(&S, 8);
}
void emitMachine(StringRef CPU) override {
// FIXME: Is there anything to do in here or does this directive only
// limit the parser?
}
void emitAbiVersion(int AbiVersion) override {
MCAssembler &MCA = getStreamer().getAssembler();
unsigned Flags = MCA.getELFHeaderEFlags();
Flags &= ~ELF::EF_PPC64_ABI;
Flags |= (AbiVersion & ELF::EF_PPC64_ABI);
MCA.setELFHeaderEFlags(Flags);
}
void emitLocalEntry(MCSymbolELF *S, const MCExpr *LocalOffset) override {
MCAssembler &MCA = getStreamer().getAssembler();
int64_t Res;
if (!LocalOffset->evaluateAsAbsolute(Res, MCA))
report_fatal_error(".localentry expression must be absolute.");
unsigned Encoded = ELF::encodePPC64LocalEntryOffset(Res);
if (Res != ELF::decodePPC64LocalEntryOffset(Encoded))
report_fatal_error(".localentry expression cannot be encoded.");
unsigned Other = S->getOther();
Other &= ~ELF::STO_PPC64_LOCAL_MASK;
Other |= Encoded;
S->setOther(Other);
// For GAS compatibility, unless we already saw a .abiversion directive,
// set e_flags to indicate ELFv2 ABI.
unsigned Flags = MCA.getELFHeaderEFlags();
if ((Flags & ELF::EF_PPC64_ABI) == 0)
MCA.setELFHeaderEFlags(Flags | 2);
}
void emitAssignment(MCSymbol *S, const MCExpr *Value) override {
auto *Symbol = cast<MCSymbolELF>(S);
+
// When encoding an assignment to set symbol A to symbol B, also copy
// the st_other bits encoding the local entry point offset.
- if (Value->getKind() != MCExpr::SymbolRef)
- return;
- const auto &RhsSym = cast<MCSymbolELF>(
- static_cast<const MCSymbolRefExpr *>(Value)->getSymbol());
- unsigned Other = Symbol->getOther();
+ if (copyLocalEntry(Symbol, Value))
+ UpdateOther.insert(Symbol);
+ else
+ UpdateOther.erase(Symbol);
+ }
+
+ void finish() override {
+ for (auto *Sym : UpdateOther)
+ copyLocalEntry(Sym, Sym->getVariableValue());
+ }
+
+private:
+ SmallPtrSet<MCSymbolELF *, 32> UpdateOther;
+
+ bool copyLocalEntry(MCSymbolELF *D, const MCExpr *S) {
+ auto *Ref = dyn_cast<const MCSymbolRefExpr>(S);
+ if (!Ref)
+ return false;
+ const auto &RhsSym = cast<MCSymbolELF>(Ref->getSymbol());
+ unsigned Other = D->getOther();
Other &= ~ELF::STO_PPC64_LOCAL_MASK;
Other |= RhsSym.getOther() & ELF::STO_PPC64_LOCAL_MASK;
- Symbol->setOther(Other);
+ D->setOther(Other);
+ return true;
}
};
class PPCTargetMachOStreamer : public PPCTargetStreamer {
public:
PPCTargetMachOStreamer(MCStreamer &S) : PPCTargetStreamer(S) {}
void emitTCEntry(const MCSymbol &S) override {
llvm_unreachable("Unknown pseudo-op: .tc");
}
void emitMachine(StringRef CPU) override {
// FIXME: We should update the CPUType, CPUSubType in the Object file if
// the new values are different from the defaults.
}
void emitAbiVersion(int AbiVersion) override {
llvm_unreachable("Unknown pseudo-op: .abiversion");
}
void emitLocalEntry(MCSymbolELF *S, const MCExpr *LocalOffset) override {
llvm_unreachable("Unknown pseudo-op: .localentry");
}
};
} // end anonymous namespace
static MCTargetStreamer *createAsmTargetStreamer(MCStreamer &S,
formatted_raw_ostream &OS,
MCInstPrinter *InstPrint,
bool isVerboseAsm) {
return new PPCTargetAsmStreamer(S, OS);
}
static MCTargetStreamer *
createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
const Triple &TT = STI.getTargetTriple();
if (TT.isOSBinFormatELF())
return new PPCTargetELFStreamer(S);
return new PPCTargetMachOStreamer(S);
}
static MCInstPrinter *createPPCMCInstPrinter(const Triple &T,
unsigned SyntaxVariant,
const MCAsmInfo &MAI,
const MCInstrInfo &MII,
const MCRegisterInfo &MRI) {
return new PPCInstPrinter(MAI, MII, MRI, T);
}
extern "C" void LLVMInitializePowerPCTargetMC() {
for (Target *T :
{&getThePPC32Target(), &getThePPC64Target(), &getThePPC64LETarget()}) {
// Register the MC asm info.
RegisterMCAsmInfoFn C(*T, createPPCMCAsmInfo);
// Register the MC instruction info.
TargetRegistry::RegisterMCInstrInfo(*T, createPPCMCInstrInfo);
// Register the MC register info.
TargetRegistry::RegisterMCRegInfo(*T, createPPCMCRegisterInfo);
// Register the MC subtarget info.
TargetRegistry::RegisterMCSubtargetInfo(*T, createPPCMCSubtargetInfo);
// Register the MC Code Emitter
TargetRegistry::RegisterMCCodeEmitter(*T, createPPCMCCodeEmitter);
// Register the asm backend.
TargetRegistry::RegisterMCAsmBackend(*T, createPPCAsmBackend);
// Register the object target streamer.
TargetRegistry::RegisterObjectTargetStreamer(*T,
createObjectTargetStreamer);
// Register the asm target streamer.
TargetRegistry::RegisterAsmTargetStreamer(*T, createAsmTargetStreamer);
// Register the MCInstPrinter.
TargetRegistry::RegisterMCInstPrinter(*T, createPPCMCInstPrinter);
}
}
Index: stable/11/contrib/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp (revision 350259)
@@ -1,6511 +1,6511 @@
//===-- PPCISelDAGToDAG.cpp - PPC --pattern matching inst selector --------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a pattern matching instruction selector for PowerPC,
// converting from a legalized dag to a PPC dag.
//
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/PPCMCTargetDesc.h"
#include "MCTargetDesc/PPCPredicates.h"
#include "PPC.h"
#include "PPCISelLowering.h"
#include "PPCMachineFunctionInfo.h"
#include "PPCSubtarget.h"
#include "PPCTargetMachine.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/CodeGen/FunctionLoweringInfo.h"
#include "llvm/CodeGen/ISDOpcodes.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/CodeGen/SelectionDAGNodes.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CodeGen.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/MachineValueType.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <iterator>
#include <limits>
#include <memory>
#include <new>
#include <tuple>
#include <utility>
using namespace llvm;
#define DEBUG_TYPE "ppc-codegen"
STATISTIC(NumSextSetcc,
"Number of (sext(setcc)) nodes expanded into GPR sequence.");
STATISTIC(NumZextSetcc,
"Number of (zext(setcc)) nodes expanded into GPR sequence.");
STATISTIC(SignExtensionsAdded,
"Number of sign extensions for compare inputs added.");
STATISTIC(ZeroExtensionsAdded,
"Number of zero extensions for compare inputs added.");
STATISTIC(NumLogicOpsOnComparison,
"Number of logical ops on i1 values calculated in GPR.");
STATISTIC(OmittedForNonExtendUses,
"Number of compares not eliminated as they have non-extending uses.");
STATISTIC(NumP9Setb,
"Number of compares lowered to setb.");
// FIXME: Remove this once the bug has been fixed!
cl::opt<bool> ANDIGlueBug("expose-ppc-andi-glue-bug",
cl::desc("expose the ANDI glue bug on PPC"), cl::Hidden);
static cl::opt<bool>
UseBitPermRewriter("ppc-use-bit-perm-rewriter", cl::init(true),
cl::desc("use aggressive ppc isel for bit permutations"),
cl::Hidden);
static cl::opt<bool> BPermRewriterNoMasking(
"ppc-bit-perm-rewriter-stress-rotates",
cl::desc("stress rotate selection in aggressive ppc isel for "
"bit permutations"),
cl::Hidden);
static cl::opt<bool> EnableBranchHint(
"ppc-use-branch-hint", cl::init(true),
cl::desc("Enable static hinting of branches on ppc"),
cl::Hidden);
static cl::opt<bool> EnableTLSOpt(
"ppc-tls-opt", cl::init(true),
cl::desc("Enable tls optimization peephole"),
cl::Hidden);
enum ICmpInGPRType { ICGPR_All, ICGPR_None, ICGPR_I32, ICGPR_I64,
ICGPR_NonExtIn, ICGPR_Zext, ICGPR_Sext, ICGPR_ZextI32,
ICGPR_SextI32, ICGPR_ZextI64, ICGPR_SextI64 };
static cl::opt<ICmpInGPRType> CmpInGPR(
"ppc-gpr-icmps", cl::Hidden, cl::init(ICGPR_All),
cl::desc("Specify the types of comparisons to emit GPR-only code for."),
cl::values(clEnumValN(ICGPR_None, "none", "Do not modify integer comparisons."),
clEnumValN(ICGPR_All, "all", "All possible int comparisons in GPRs."),
clEnumValN(ICGPR_I32, "i32", "Only i32 comparisons in GPRs."),
clEnumValN(ICGPR_I64, "i64", "Only i64 comparisons in GPRs."),
clEnumValN(ICGPR_NonExtIn, "nonextin",
"Only comparisons where inputs don't need [sz]ext."),
clEnumValN(ICGPR_Zext, "zext", "Only comparisons with zext result."),
clEnumValN(ICGPR_ZextI32, "zexti32",
"Only i32 comparisons with zext result."),
clEnumValN(ICGPR_ZextI64, "zexti64",
"Only i64 comparisons with zext result."),
clEnumValN(ICGPR_Sext, "sext", "Only comparisons with sext result."),
clEnumValN(ICGPR_SextI32, "sexti32",
"Only i32 comparisons with sext result."),
clEnumValN(ICGPR_SextI64, "sexti64",
"Only i64 comparisons with sext result.")));
namespace {
//===--------------------------------------------------------------------===//
/// PPCDAGToDAGISel - PPC specific code to select PPC machine
/// instructions for SelectionDAG operations.
///
class PPCDAGToDAGISel : public SelectionDAGISel {
const PPCTargetMachine &TM;
const PPCSubtarget *PPCSubTarget;
const PPCTargetLowering *PPCLowering;
unsigned GlobalBaseReg;
public:
explicit PPCDAGToDAGISel(PPCTargetMachine &tm, CodeGenOpt::Level OptLevel)
: SelectionDAGISel(tm, OptLevel), TM(tm) {}
bool runOnMachineFunction(MachineFunction &MF) override {
// Make sure we re-emit a set of the global base reg if necessary
GlobalBaseReg = 0;
PPCSubTarget = &MF.getSubtarget<PPCSubtarget>();
PPCLowering = PPCSubTarget->getTargetLowering();
SelectionDAGISel::runOnMachineFunction(MF);
if (!PPCSubTarget->isSVR4ABI())
InsertVRSaveCode(MF);
return true;
}
void PreprocessISelDAG() override;
void PostprocessISelDAG() override;
/// getI16Imm - Return a target constant with the specified value, of type
/// i16.
inline SDValue getI16Imm(unsigned Imm, const SDLoc &dl) {
return CurDAG->getTargetConstant(Imm, dl, MVT::i16);
}
/// getI32Imm - Return a target constant with the specified value, of type
/// i32.
inline SDValue getI32Imm(unsigned Imm, const SDLoc &dl) {
return CurDAG->getTargetConstant(Imm, dl, MVT::i32);
}
/// getI64Imm - Return a target constant with the specified value, of type
/// i64.
inline SDValue getI64Imm(uint64_t Imm, const SDLoc &dl) {
return CurDAG->getTargetConstant(Imm, dl, MVT::i64);
}
/// getSmallIPtrImm - Return a target constant of pointer type.
inline SDValue getSmallIPtrImm(unsigned Imm, const SDLoc &dl) {
return CurDAG->getTargetConstant(
Imm, dl, PPCLowering->getPointerTy(CurDAG->getDataLayout()));
}
/// isRotateAndMask - Returns true if Mask and Shift can be folded into a
/// rotate and mask opcode and mask operation.
static bool isRotateAndMask(SDNode *N, unsigned Mask, bool isShiftMask,
unsigned &SH, unsigned &MB, unsigned &ME);
/// getGlobalBaseReg - insert code into the entry mbb to materialize the PIC
/// base register. Return the virtual register that holds this value.
SDNode *getGlobalBaseReg();
void selectFrameIndex(SDNode *SN, SDNode *N, unsigned Offset = 0);
// Select - Convert the specified operand from a target-independent to a
// target-specific node if it hasn't already been changed.
void Select(SDNode *N) override;
bool tryBitfieldInsert(SDNode *N);
bool tryBitPermutation(SDNode *N);
bool tryIntCompareInGPR(SDNode *N);
// tryTLSXFormLoad - Convert an ISD::LOAD fed by a PPCISD::ADD_TLS into
// an X-Form load instruction with the offset being a relocation coming from
// the PPCISD::ADD_TLS.
bool tryTLSXFormLoad(LoadSDNode *N);
// tryTLSXFormStore - Convert an ISD::STORE fed by a PPCISD::ADD_TLS into
// an X-Form store instruction with the offset being a relocation coming from
// the PPCISD::ADD_TLS.
bool tryTLSXFormStore(StoreSDNode *N);
/// SelectCC - Select a comparison of the specified values with the
/// specified condition code, returning the CR# of the expression.
SDValue SelectCC(SDValue LHS, SDValue RHS, ISD::CondCode CC,
const SDLoc &dl);
/// SelectAddrImm - Returns true if the address N can be represented by
/// a base register plus a signed 16-bit displacement [r+imm].
bool SelectAddrImm(SDValue N, SDValue &Disp,
SDValue &Base) {
return PPCLowering->SelectAddressRegImm(N, Disp, Base, *CurDAG, 0);
}
/// SelectAddrImmOffs - Return true if the operand is valid for a preinc
/// immediate field. Note that the operand at this point is already the
/// result of a prior SelectAddressRegImm call.
bool SelectAddrImmOffs(SDValue N, SDValue &Out) const {
if (N.getOpcode() == ISD::TargetConstant ||
N.getOpcode() == ISD::TargetGlobalAddress) {
Out = N;
return true;
}
return false;
}
/// SelectAddrIdx - Given the specified addressed, check to see if it can be
/// represented as an indexed [r+r] operation. Returns false if it can
/// be represented by [r+imm], which are preferred.
bool SelectAddrIdx(SDValue N, SDValue &Base, SDValue &Index) {
return PPCLowering->SelectAddressRegReg(N, Base, Index, *CurDAG);
}
/// SelectAddrIdxOnly - Given the specified addressed, force it to be
/// represented as an indexed [r+r] operation.
bool SelectAddrIdxOnly(SDValue N, SDValue &Base, SDValue &Index) {
return PPCLowering->SelectAddressRegRegOnly(N, Base, Index, *CurDAG);
}
/// SelectAddrImmX4 - Returns true if the address N can be represented by
/// a base register plus a signed 16-bit displacement that is a multiple of 4.
/// Suitable for use by STD and friends.
bool SelectAddrImmX4(SDValue N, SDValue &Disp, SDValue &Base) {
return PPCLowering->SelectAddressRegImm(N, Disp, Base, *CurDAG, 4);
}
bool SelectAddrImmX16(SDValue N, SDValue &Disp, SDValue &Base) {
return PPCLowering->SelectAddressRegImm(N, Disp, Base, *CurDAG, 16);
}
// Select an address into a single register.
bool SelectAddr(SDValue N, SDValue &Base) {
Base = N;
return true;
}
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
/// inline asm expressions. It is always correct to compute the value into
/// a register. The case of adding a (possibly relocatable) constant to a
/// register can be improved, but it is wrong to substitute Reg+Reg for
/// Reg in an asm, because the load or store opcode would have to change.
bool SelectInlineAsmMemoryOperand(const SDValue &Op,
unsigned ConstraintID,
std::vector<SDValue> &OutOps) override {
switch(ConstraintID) {
default:
errs() << "ConstraintID: " << ConstraintID << "\n";
llvm_unreachable("Unexpected asm memory constraint");
case InlineAsm::Constraint_es:
case InlineAsm::Constraint_i:
case InlineAsm::Constraint_m:
case InlineAsm::Constraint_o:
case InlineAsm::Constraint_Q:
case InlineAsm::Constraint_Z:
case InlineAsm::Constraint_Zy:
// We need to make sure that this one operand does not end up in r0
// (because we might end up lowering this as 0(%op)).
const TargetRegisterInfo *TRI = PPCSubTarget->getRegisterInfo();
const TargetRegisterClass *TRC = TRI->getPointerRegClass(*MF, /*Kind=*/1);
SDLoc dl(Op);
SDValue RC = CurDAG->getTargetConstant(TRC->getID(), dl, MVT::i32);
SDValue NewOp =
SDValue(CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS,
dl, Op.getValueType(),
Op, RC), 0);
OutOps.push_back(NewOp);
return false;
}
return true;
}
void InsertVRSaveCode(MachineFunction &MF);
StringRef getPassName() const override {
return "PowerPC DAG->DAG Pattern Instruction Selection";
}
// Include the pieces autogenerated from the target description.
#include "PPCGenDAGISel.inc"
private:
bool trySETCC(SDNode *N);
void PeepholePPC64();
void PeepholePPC64ZExt();
void PeepholeCROps();
SDValue combineToCMPB(SDNode *N);
void foldBoolExts(SDValue &Res, SDNode *&N);
bool AllUsersSelectZero(SDNode *N);
void SwapAllSelectUsers(SDNode *N);
bool isOffsetMultipleOf(SDNode *N, unsigned Val) const;
void transferMemOperands(SDNode *N, SDNode *Result);
};
} // end anonymous namespace
/// InsertVRSaveCode - Once the entire function has been instruction selected,
/// all virtual registers are created and all machine instructions are built,
/// check to see if we need to save/restore VRSAVE. If so, do it.
void PPCDAGToDAGISel::InsertVRSaveCode(MachineFunction &Fn) {
// Check to see if this function uses vector registers, which means we have to
// save and restore the VRSAVE register and update it with the regs we use.
//
// In this case, there will be virtual registers of vector type created
// by the scheduler. Detect them now.
bool HasVectorVReg = false;
for (unsigned i = 0, e = RegInfo->getNumVirtRegs(); i != e; ++i) {
unsigned Reg = TargetRegisterInfo::index2VirtReg(i);
if (RegInfo->getRegClass(Reg) == &PPC::VRRCRegClass) {
HasVectorVReg = true;
break;
}
}
if (!HasVectorVReg) return; // nothing to do.
// If we have a vector register, we want to emit code into the entry and exit
// blocks to save and restore the VRSAVE register. We do this here (instead
// of marking all vector instructions as clobbering VRSAVE) for two reasons:
//
// 1. This (trivially) reduces the load on the register allocator, by not
// having to represent the live range of the VRSAVE register.
// 2. This (more significantly) allows us to create a temporary virtual
// register to hold the saved VRSAVE value, allowing this temporary to be
// register allocated, instead of forcing it to be spilled to the stack.
// Create two vregs - one to hold the VRSAVE register that is live-in to the
// function and one for the value after having bits or'd into it.
unsigned InVRSAVE = RegInfo->createVirtualRegister(&PPC::GPRCRegClass);
unsigned UpdatedVRSAVE = RegInfo->createVirtualRegister(&PPC::GPRCRegClass);
const TargetInstrInfo &TII = *PPCSubTarget->getInstrInfo();
MachineBasicBlock &EntryBB = *Fn.begin();
DebugLoc dl;
// Emit the following code into the entry block:
// InVRSAVE = MFVRSAVE
// UpdatedVRSAVE = UPDATE_VRSAVE InVRSAVE
// MTVRSAVE UpdatedVRSAVE
MachineBasicBlock::iterator IP = EntryBB.begin(); // Insert Point
BuildMI(EntryBB, IP, dl, TII.get(PPC::MFVRSAVE), InVRSAVE);
BuildMI(EntryBB, IP, dl, TII.get(PPC::UPDATE_VRSAVE),
UpdatedVRSAVE).addReg(InVRSAVE);
BuildMI(EntryBB, IP, dl, TII.get(PPC::MTVRSAVE)).addReg(UpdatedVRSAVE);
// Find all return blocks, outputting a restore in each epilog.
for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) {
if (BB->isReturnBlock()) {
IP = BB->end(); --IP;
// Skip over all terminator instructions, which are part of the return
// sequence.
MachineBasicBlock::iterator I2 = IP;
while (I2 != BB->begin() && (--I2)->isTerminator())
IP = I2;
// Emit: MTVRSAVE InVRSave
BuildMI(*BB, IP, dl, TII.get(PPC::MTVRSAVE)).addReg(InVRSAVE);
}
}
}
/// getGlobalBaseReg - Output the instructions required to put the
/// base address to use for accessing globals into a register.
///
SDNode *PPCDAGToDAGISel::getGlobalBaseReg() {
if (!GlobalBaseReg) {
const TargetInstrInfo &TII = *PPCSubTarget->getInstrInfo();
// Insert the set of GlobalBaseReg into the first MBB of the function
MachineBasicBlock &FirstMBB = MF->front();
MachineBasicBlock::iterator MBBI = FirstMBB.begin();
const Module *M = MF->getFunction().getParent();
DebugLoc dl;
if (PPCLowering->getPointerTy(CurDAG->getDataLayout()) == MVT::i32) {
if (PPCSubTarget->isTargetELF()) {
GlobalBaseReg = PPC::R30;
if (M->getPICLevel() == PICLevel::SmallPIC) {
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MoveGOTtoLR));
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MFLR), GlobalBaseReg);
MF->getInfo<PPCFunctionInfo>()->setUsesPICBase(true);
} else {
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MovePCtoLR));
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MFLR), GlobalBaseReg);
unsigned TempReg = RegInfo->createVirtualRegister(&PPC::GPRCRegClass);
BuildMI(FirstMBB, MBBI, dl,
TII.get(PPC::UpdateGBR), GlobalBaseReg)
.addReg(TempReg, RegState::Define).addReg(GlobalBaseReg);
MF->getInfo<PPCFunctionInfo>()->setUsesPICBase(true);
}
} else {
GlobalBaseReg =
RegInfo->createVirtualRegister(&PPC::GPRC_and_GPRC_NOR0RegClass);
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MovePCtoLR));
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MFLR), GlobalBaseReg);
}
} else {
// We must ensure that this sequence is dominated by the prologue.
// FIXME: This is a bit of a big hammer since we don't get the benefits
// of shrink-wrapping whenever we emit this instruction. Considering
// this is used in any function where we emit a jump table, this may be
// a significant limitation. We should consider inserting this in the
// block where it is used and then commoning this sequence up if it
// appears in multiple places.
// Note: on ISA 3.0 cores, we can use lnia (addpcis) instead of
// MovePCtoLR8.
MF->getInfo<PPCFunctionInfo>()->setShrinkWrapDisabled(true);
GlobalBaseReg = RegInfo->createVirtualRegister(&PPC::G8RC_and_G8RC_NOX0RegClass);
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MovePCtoLR8));
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MFLR8), GlobalBaseReg);
}
}
return CurDAG->getRegister(GlobalBaseReg,
PPCLowering->getPointerTy(CurDAG->getDataLayout()))
.getNode();
}
/// isInt32Immediate - This method tests to see if the node is a 32-bit constant
/// operand. If so Imm will receive the 32-bit value.
static bool isInt32Immediate(SDNode *N, unsigned &Imm) {
if (N->getOpcode() == ISD::Constant && N->getValueType(0) == MVT::i32) {
Imm = cast<ConstantSDNode>(N)->getZExtValue();
return true;
}
return false;
}
/// isInt64Immediate - This method tests to see if the node is a 64-bit constant
/// operand. If so Imm will receive the 64-bit value.
static bool isInt64Immediate(SDNode *N, uint64_t &Imm) {
if (N->getOpcode() == ISD::Constant && N->getValueType(0) == MVT::i64) {
Imm = cast<ConstantSDNode>(N)->getZExtValue();
return true;
}
return false;
}
// isInt32Immediate - This method tests to see if a constant operand.
// If so Imm will receive the 32 bit value.
static bool isInt32Immediate(SDValue N, unsigned &Imm) {
return isInt32Immediate(N.getNode(), Imm);
}
/// isInt64Immediate - This method tests to see if the value is a 64-bit
/// constant operand. If so Imm will receive the 64-bit value.
static bool isInt64Immediate(SDValue N, uint64_t &Imm) {
return isInt64Immediate(N.getNode(), Imm);
}
static unsigned getBranchHint(unsigned PCC, FunctionLoweringInfo *FuncInfo,
const SDValue &DestMBB) {
assert(isa<BasicBlockSDNode>(DestMBB));
if (!FuncInfo->BPI) return PPC::BR_NO_HINT;
const BasicBlock *BB = FuncInfo->MBB->getBasicBlock();
const Instruction *BBTerm = BB->getTerminator();
if (BBTerm->getNumSuccessors() != 2) return PPC::BR_NO_HINT;
const BasicBlock *TBB = BBTerm->getSuccessor(0);
const BasicBlock *FBB = BBTerm->getSuccessor(1);
auto TProb = FuncInfo->BPI->getEdgeProbability(BB, TBB);
auto FProb = FuncInfo->BPI->getEdgeProbability(BB, FBB);
// We only want to handle cases which are easy to predict at static time, e.g.
// C++ throw statement, that is very likely not taken, or calling never
// returned function, e.g. stdlib exit(). So we set Threshold to filter
// unwanted cases.
//
// Below is LLVM branch weight table, we only want to handle case 1, 2
//
// Case Taken:Nontaken Example
// 1. Unreachable 1048575:1 C++ throw, stdlib exit(),
// 2. Invoke-terminating 1:1048575
// 3. Coldblock 4:64 __builtin_expect
// 4. Loop Branch 124:4 For loop
// 5. PH/ZH/FPH 20:12
const uint32_t Threshold = 10000;
if (std::max(TProb, FProb) / Threshold < std::min(TProb, FProb))
return PPC::BR_NO_HINT;
LLVM_DEBUG(dbgs() << "Use branch hint for '" << FuncInfo->Fn->getName()
<< "::" << BB->getName() << "'\n"
<< " -> " << TBB->getName() << ": " << TProb << "\n"
<< " -> " << FBB->getName() << ": " << FProb << "\n");
const BasicBlockSDNode *BBDN = cast<BasicBlockSDNode>(DestMBB);
// If Dest BasicBlock is False-BasicBlock (FBB), swap branch probabilities,
// because we want 'TProb' stands for 'branch probability' to Dest BasicBlock
if (BBDN->getBasicBlock()->getBasicBlock() != TBB)
std::swap(TProb, FProb);
return (TProb > FProb) ? PPC::BR_TAKEN_HINT : PPC::BR_NONTAKEN_HINT;
}
// isOpcWithIntImmediate - This method tests to see if the node is a specific
// opcode and that it has a immediate integer right operand.
// If so Imm will receive the 32 bit value.
static bool isOpcWithIntImmediate(SDNode *N, unsigned Opc, unsigned& Imm) {
return N->getOpcode() == Opc
&& isInt32Immediate(N->getOperand(1).getNode(), Imm);
}
void PPCDAGToDAGISel::selectFrameIndex(SDNode *SN, SDNode *N, unsigned Offset) {
SDLoc dl(SN);
int FI = cast<FrameIndexSDNode>(N)->getIndex();
SDValue TFI = CurDAG->getTargetFrameIndex(FI, N->getValueType(0));
unsigned Opc = N->getValueType(0) == MVT::i32 ? PPC::ADDI : PPC::ADDI8;
if (SN->hasOneUse())
CurDAG->SelectNodeTo(SN, Opc, N->getValueType(0), TFI,
getSmallIPtrImm(Offset, dl));
else
ReplaceNode(SN, CurDAG->getMachineNode(Opc, dl, N->getValueType(0), TFI,
getSmallIPtrImm(Offset, dl)));
}
bool PPCDAGToDAGISel::isRotateAndMask(SDNode *N, unsigned Mask,
bool isShiftMask, unsigned &SH,
unsigned &MB, unsigned &ME) {
// Don't even go down this path for i64, since different logic will be
// necessary for rldicl/rldicr/rldimi.
if (N->getValueType(0) != MVT::i32)
return false;
unsigned Shift = 32;
unsigned Indeterminant = ~0; // bit mask marking indeterminant results
unsigned Opcode = N->getOpcode();
if (N->getNumOperands() != 2 ||
!isInt32Immediate(N->getOperand(1).getNode(), Shift) || (Shift > 31))
return false;
if (Opcode == ISD::SHL) {
// apply shift left to mask if it comes first
if (isShiftMask) Mask = Mask << Shift;
// determine which bits are made indeterminant by shift
Indeterminant = ~(0xFFFFFFFFu << Shift);
} else if (Opcode == ISD::SRL) {
// apply shift right to mask if it comes first
if (isShiftMask) Mask = Mask >> Shift;
// determine which bits are made indeterminant by shift
Indeterminant = ~(0xFFFFFFFFu >> Shift);
// adjust for the left rotate
Shift = 32 - Shift;
} else if (Opcode == ISD::ROTL) {
Indeterminant = 0;
} else {
return false;
}
// if the mask doesn't intersect any Indeterminant bits
if (Mask && !(Mask & Indeterminant)) {
SH = Shift & 31;
// make sure the mask is still a mask (wrap arounds may not be)
return isRunOfOnes(Mask, MB, ME);
}
return false;
}
bool PPCDAGToDAGISel::tryTLSXFormStore(StoreSDNode *ST) {
SDValue Base = ST->getBasePtr();
if (Base.getOpcode() != PPCISD::ADD_TLS)
return false;
SDValue Offset = ST->getOffset();
if (!Offset.isUndef())
return false;
SDLoc dl(ST);
EVT MemVT = ST->getMemoryVT();
EVT RegVT = ST->getValue().getValueType();
unsigned Opcode;
switch (MemVT.getSimpleVT().SimpleTy) {
default:
return false;
case MVT::i8: {
Opcode = (RegVT == MVT::i32) ? PPC::STBXTLS_32 : PPC::STBXTLS;
break;
}
case MVT::i16: {
Opcode = (RegVT == MVT::i32) ? PPC::STHXTLS_32 : PPC::STHXTLS;
break;
}
case MVT::i32: {
Opcode = (RegVT == MVT::i32) ? PPC::STWXTLS_32 : PPC::STWXTLS;
break;
}
case MVT::i64: {
Opcode = PPC::STDXTLS;
break;
}
}
SDValue Chain = ST->getChain();
SDVTList VTs = ST->getVTList();
SDValue Ops[] = {ST->getValue(), Base.getOperand(0), Base.getOperand(1),
Chain};
SDNode *MN = CurDAG->getMachineNode(Opcode, dl, VTs, Ops);
transferMemOperands(ST, MN);
ReplaceNode(ST, MN);
return true;
}
bool PPCDAGToDAGISel::tryTLSXFormLoad(LoadSDNode *LD) {
SDValue Base = LD->getBasePtr();
if (Base.getOpcode() != PPCISD::ADD_TLS)
return false;
SDValue Offset = LD->getOffset();
if (!Offset.isUndef())
return false;
SDLoc dl(LD);
EVT MemVT = LD->getMemoryVT();
EVT RegVT = LD->getValueType(0);
unsigned Opcode;
switch (MemVT.getSimpleVT().SimpleTy) {
default:
return false;
case MVT::i8: {
Opcode = (RegVT == MVT::i32) ? PPC::LBZXTLS_32 : PPC::LBZXTLS;
break;
}
case MVT::i16: {
Opcode = (RegVT == MVT::i32) ? PPC::LHZXTLS_32 : PPC::LHZXTLS;
break;
}
case MVT::i32: {
Opcode = (RegVT == MVT::i32) ? PPC::LWZXTLS_32 : PPC::LWZXTLS;
break;
}
case MVT::i64: {
Opcode = PPC::LDXTLS;
break;
}
}
SDValue Chain = LD->getChain();
SDVTList VTs = LD->getVTList();
SDValue Ops[] = {Base.getOperand(0), Base.getOperand(1), Chain};
SDNode *MN = CurDAG->getMachineNode(Opcode, dl, VTs, Ops);
transferMemOperands(LD, MN);
ReplaceNode(LD, MN);
return true;
}
/// Turn an or of two masked values into the rotate left word immediate then
/// mask insert (rlwimi) instruction.
bool PPCDAGToDAGISel::tryBitfieldInsert(SDNode *N) {
SDValue Op0 = N->getOperand(0);
SDValue Op1 = N->getOperand(1);
SDLoc dl(N);
KnownBits LKnown = CurDAG->computeKnownBits(Op0);
KnownBits RKnown = CurDAG->computeKnownBits(Op1);
unsigned TargetMask = LKnown.Zero.getZExtValue();
unsigned InsertMask = RKnown.Zero.getZExtValue();
if ((TargetMask | InsertMask) == 0xFFFFFFFF) {
unsigned Op0Opc = Op0.getOpcode();
unsigned Op1Opc = Op1.getOpcode();
unsigned Value, SH = 0;
TargetMask = ~TargetMask;
InsertMask = ~InsertMask;
// If the LHS has a foldable shift and the RHS does not, then swap it to the
// RHS so that we can fold the shift into the insert.
if (Op0Opc == ISD::AND && Op1Opc == ISD::AND) {
if (Op0.getOperand(0).getOpcode() == ISD::SHL ||
Op0.getOperand(0).getOpcode() == ISD::SRL) {
if (Op1.getOperand(0).getOpcode() != ISD::SHL &&
Op1.getOperand(0).getOpcode() != ISD::SRL) {
std::swap(Op0, Op1);
std::swap(Op0Opc, Op1Opc);
std::swap(TargetMask, InsertMask);
}
}
} else if (Op0Opc == ISD::SHL || Op0Opc == ISD::SRL) {
if (Op1Opc == ISD::AND && Op1.getOperand(0).getOpcode() != ISD::SHL &&
Op1.getOperand(0).getOpcode() != ISD::SRL) {
std::swap(Op0, Op1);
std::swap(Op0Opc, Op1Opc);
std::swap(TargetMask, InsertMask);
}
}
unsigned MB, ME;
if (isRunOfOnes(InsertMask, MB, ME)) {
if ((Op1Opc == ISD::SHL || Op1Opc == ISD::SRL) &&
isInt32Immediate(Op1.getOperand(1), Value)) {
Op1 = Op1.getOperand(0);
SH = (Op1Opc == ISD::SHL) ? Value : 32 - Value;
}
if (Op1Opc == ISD::AND) {
// The AND mask might not be a constant, and we need to make sure that
// if we're going to fold the masking with the insert, all bits not
// know to be zero in the mask are known to be one.
KnownBits MKnown = CurDAG->computeKnownBits(Op1.getOperand(1));
bool CanFoldMask = InsertMask == MKnown.One.getZExtValue();
unsigned SHOpc = Op1.getOperand(0).getOpcode();
if ((SHOpc == ISD::SHL || SHOpc == ISD::SRL) && CanFoldMask &&
isInt32Immediate(Op1.getOperand(0).getOperand(1), Value)) {
// Note that Value must be in range here (less than 32) because
// otherwise there would not be any bits set in InsertMask.
Op1 = Op1.getOperand(0).getOperand(0);
SH = (SHOpc == ISD::SHL) ? Value : 32 - Value;
}
}
SH &= 31;
SDValue Ops[] = { Op0, Op1, getI32Imm(SH, dl), getI32Imm(MB, dl),
getI32Imm(ME, dl) };
ReplaceNode(N, CurDAG->getMachineNode(PPC::RLWIMI, dl, MVT::i32, Ops));
return true;
}
}
return false;
}
// Predict the number of instructions that would be generated by calling
// selectI64Imm(N).
static unsigned selectI64ImmInstrCountDirect(int64_t Imm) {
// Assume no remaining bits.
unsigned Remainder = 0;
// Assume no shift required.
unsigned Shift = 0;
// If it can't be represented as a 32 bit value.
if (!isInt<32>(Imm)) {
Shift = countTrailingZeros<uint64_t>(Imm);
int64_t ImmSh = static_cast<uint64_t>(Imm) >> Shift;
// If the shifted value fits 32 bits.
if (isInt<32>(ImmSh)) {
// Go with the shifted value.
Imm = ImmSh;
} else {
// Still stuck with a 64 bit value.
Remainder = Imm;
Shift = 32;
Imm >>= 32;
}
}
// Intermediate operand.
unsigned Result = 0;
// Handle first 32 bits.
unsigned Lo = Imm & 0xFFFF;
// Simple value.
if (isInt<16>(Imm)) {
// Just the Lo bits.
++Result;
} else if (Lo) {
// Handle the Hi bits and Lo bits.
Result += 2;
} else {
// Just the Hi bits.
++Result;
}
// If no shift, we're done.
if (!Shift) return Result;
// If Hi word == Lo word,
// we can use rldimi to insert the Lo word into Hi word.
if ((unsigned)(Imm & 0xFFFFFFFF) == Remainder) {
++Result;
return Result;
}
// Shift for next step if the upper 32-bits were not zero.
if (Imm)
++Result;
// Add in the last bits as required.
if ((Remainder >> 16) & 0xFFFF)
++Result;
if (Remainder & 0xFFFF)
++Result;
return Result;
}
static uint64_t Rot64(uint64_t Imm, unsigned R) {
return (Imm << R) | (Imm >> (64 - R));
}
static unsigned selectI64ImmInstrCount(int64_t Imm) {
unsigned Count = selectI64ImmInstrCountDirect(Imm);
// If the instruction count is 1 or 2, we do not need further analysis
// since rotate + load constant requires at least 2 instructions.
if (Count <= 2)
return Count;
for (unsigned r = 1; r < 63; ++r) {
uint64_t RImm = Rot64(Imm, r);
unsigned RCount = selectI64ImmInstrCountDirect(RImm) + 1;
Count = std::min(Count, RCount);
// See comments in selectI64Imm for an explanation of the logic below.
unsigned LS = findLastSet(RImm);
if (LS != r-1)
continue;
uint64_t OnesMask = -(int64_t) (UINT64_C(1) << (LS+1));
uint64_t RImmWithOnes = RImm | OnesMask;
RCount = selectI64ImmInstrCountDirect(RImmWithOnes) + 1;
Count = std::min(Count, RCount);
}
return Count;
}
// Select a 64-bit constant. For cost-modeling purposes, selectI64ImmInstrCount
// (above) needs to be kept in sync with this function.
static SDNode *selectI64ImmDirect(SelectionDAG *CurDAG, const SDLoc &dl,
int64_t Imm) {
// Assume no remaining bits.
unsigned Remainder = 0;
// Assume no shift required.
unsigned Shift = 0;
// If it can't be represented as a 32 bit value.
if (!isInt<32>(Imm)) {
Shift = countTrailingZeros<uint64_t>(Imm);
int64_t ImmSh = static_cast<uint64_t>(Imm) >> Shift;
// If the shifted value fits 32 bits.
if (isInt<32>(ImmSh)) {
// Go with the shifted value.
Imm = ImmSh;
} else {
// Still stuck with a 64 bit value.
Remainder = Imm;
Shift = 32;
Imm >>= 32;
}
}
// Intermediate operand.
SDNode *Result;
// Handle first 32 bits.
unsigned Lo = Imm & 0xFFFF;
unsigned Hi = (Imm >> 16) & 0xFFFF;
auto getI32Imm = [CurDAG, dl](unsigned Imm) {
return CurDAG->getTargetConstant(Imm, dl, MVT::i32);
};
// Simple value.
if (isInt<16>(Imm)) {
uint64_t SextImm = SignExtend64(Lo, 16);
SDValue SDImm = CurDAG->getTargetConstant(SextImm, dl, MVT::i64);
// Just the Lo bits.
Result = CurDAG->getMachineNode(PPC::LI8, dl, MVT::i64, SDImm);
} else if (Lo) {
// Handle the Hi bits.
unsigned OpC = Hi ? PPC::LIS8 : PPC::LI8;
Result = CurDAG->getMachineNode(OpC, dl, MVT::i64, getI32Imm(Hi));
// And Lo bits.
Result = CurDAG->getMachineNode(PPC::ORI8, dl, MVT::i64,
SDValue(Result, 0), getI32Imm(Lo));
} else {
// Just the Hi bits.
Result = CurDAG->getMachineNode(PPC::LIS8, dl, MVT::i64, getI32Imm(Hi));
}
// If no shift, we're done.
if (!Shift) return Result;
// If Hi word == Lo word,
// we can use rldimi to insert the Lo word into Hi word.
if ((unsigned)(Imm & 0xFFFFFFFF) == Remainder) {
SDValue Ops[] =
{ SDValue(Result, 0), SDValue(Result, 0), getI32Imm(Shift), getI32Imm(0)};
return CurDAG->getMachineNode(PPC::RLDIMI, dl, MVT::i64, Ops);
}
// Shift for next step if the upper 32-bits were not zero.
if (Imm) {
Result = CurDAG->getMachineNode(PPC::RLDICR, dl, MVT::i64,
SDValue(Result, 0),
getI32Imm(Shift),
getI32Imm(63 - Shift));
}
// Add in the last bits as required.
if ((Hi = (Remainder >> 16) & 0xFFFF)) {
Result = CurDAG->getMachineNode(PPC::ORIS8, dl, MVT::i64,
SDValue(Result, 0), getI32Imm(Hi));
}
if ((Lo = Remainder & 0xFFFF)) {
Result = CurDAG->getMachineNode(PPC::ORI8, dl, MVT::i64,
SDValue(Result, 0), getI32Imm(Lo));
}
return Result;
}
static SDNode *selectI64Imm(SelectionDAG *CurDAG, const SDLoc &dl,
int64_t Imm) {
unsigned Count = selectI64ImmInstrCountDirect(Imm);
// If the instruction count is 1 or 2, we do not need further analysis
// since rotate + load constant requires at least 2 instructions.
if (Count <= 2)
return selectI64ImmDirect(CurDAG, dl, Imm);
unsigned RMin = 0;
int64_t MatImm;
unsigned MaskEnd;
for (unsigned r = 1; r < 63; ++r) {
uint64_t RImm = Rot64(Imm, r);
unsigned RCount = selectI64ImmInstrCountDirect(RImm) + 1;
if (RCount < Count) {
Count = RCount;
RMin = r;
MatImm = RImm;
MaskEnd = 63;
}
// If the immediate to generate has many trailing zeros, it might be
// worthwhile to generate a rotated value with too many leading ones
// (because that's free with li/lis's sign-extension semantics), and then
// mask them off after rotation.
unsigned LS = findLastSet(RImm);
// We're adding (63-LS) higher-order ones, and we expect to mask them off
// after performing the inverse rotation by (64-r). So we need that:
// 63-LS == 64-r => LS == r-1
if (LS != r-1)
continue;
uint64_t OnesMask = -(int64_t) (UINT64_C(1) << (LS+1));
uint64_t RImmWithOnes = RImm | OnesMask;
RCount = selectI64ImmInstrCountDirect(RImmWithOnes) + 1;
if (RCount < Count) {
Count = RCount;
RMin = r;
MatImm = RImmWithOnes;
MaskEnd = LS;
}
}
if (!RMin)
return selectI64ImmDirect(CurDAG, dl, Imm);
auto getI32Imm = [CurDAG, dl](unsigned Imm) {
return CurDAG->getTargetConstant(Imm, dl, MVT::i32);
};
SDValue Val = SDValue(selectI64ImmDirect(CurDAG, dl, MatImm), 0);
return CurDAG->getMachineNode(PPC::RLDICR, dl, MVT::i64, Val,
getI32Imm(64 - RMin), getI32Imm(MaskEnd));
}
static unsigned allUsesTruncate(SelectionDAG *CurDAG, SDNode *N) {
unsigned MaxTruncation = 0;
// Cannot use range-based for loop here as we need the actual use (i.e. we
// need the operand number corresponding to the use). A range-based for
// will unbox the use and provide an SDNode*.
for (SDNode::use_iterator Use = N->use_begin(), UseEnd = N->use_end();
Use != UseEnd; ++Use) {
unsigned Opc =
Use->isMachineOpcode() ? Use->getMachineOpcode() : Use->getOpcode();
switch (Opc) {
default: return 0;
case ISD::TRUNCATE:
if (Use->isMachineOpcode())
return 0;
MaxTruncation =
std::max(MaxTruncation, Use->getValueType(0).getSizeInBits());
continue;
case ISD::STORE: {
if (Use->isMachineOpcode())
return 0;
StoreSDNode *STN = cast<StoreSDNode>(*Use);
unsigned MemVTSize = STN->getMemoryVT().getSizeInBits();
if (MemVTSize == 64 || Use.getOperandNo() != 0)
return 0;
MaxTruncation = std::max(MaxTruncation, MemVTSize);
continue;
}
case PPC::STW8:
case PPC::STWX8:
case PPC::STWU8:
case PPC::STWUX8:
if (Use.getOperandNo() != 0)
return 0;
MaxTruncation = std::max(MaxTruncation, 32u);
continue;
case PPC::STH8:
case PPC::STHX8:
case PPC::STHU8:
case PPC::STHUX8:
if (Use.getOperandNo() != 0)
return 0;
MaxTruncation = std::max(MaxTruncation, 16u);
continue;
case PPC::STB8:
case PPC::STBX8:
case PPC::STBU8:
case PPC::STBUX8:
if (Use.getOperandNo() != 0)
return 0;
MaxTruncation = std::max(MaxTruncation, 8u);
continue;
}
}
return MaxTruncation;
}
// Select a 64-bit constant.
static SDNode *selectI64Imm(SelectionDAG *CurDAG, SDNode *N) {
SDLoc dl(N);
// Get 64 bit value.
int64_t Imm = cast<ConstantSDNode>(N)->getZExtValue();
if (unsigned MinSize = allUsesTruncate(CurDAG, N)) {
uint64_t SextImm = SignExtend64(Imm, MinSize);
SDValue SDImm = CurDAG->getTargetConstant(SextImm, dl, MVT::i64);
if (isInt<16>(SextImm))
return CurDAG->getMachineNode(PPC::LI8, dl, MVT::i64, SDImm);
}
return selectI64Imm(CurDAG, dl, Imm);
}
namespace {
class BitPermutationSelector {
struct ValueBit {
SDValue V;
// The bit number in the value, using a convention where bit 0 is the
// lowest-order bit.
unsigned Idx;
// ConstZero means a bit we need to mask off.
// Variable is a bit comes from an input variable.
// VariableKnownToBeZero is also a bit comes from an input variable,
// but it is known to be already zero. So we do not need to mask them.
enum Kind {
ConstZero,
Variable,
VariableKnownToBeZero
} K;
ValueBit(SDValue V, unsigned I, Kind K = Variable)
: V(V), Idx(I), K(K) {}
ValueBit(Kind K = Variable)
: V(SDValue(nullptr, 0)), Idx(UINT32_MAX), K(K) {}
bool isZero() const {
return K == ConstZero || K == VariableKnownToBeZero;
}
bool hasValue() const {
return K == Variable || K == VariableKnownToBeZero;
}
SDValue getValue() const {
assert(hasValue() && "Cannot get the value of a constant bit");
return V;
}
unsigned getValueBitIndex() const {
assert(hasValue() && "Cannot get the value bit index of a constant bit");
return Idx;
}
};
// A bit group has the same underlying value and the same rotate factor.
struct BitGroup {
SDValue V;
unsigned RLAmt;
unsigned StartIdx, EndIdx;
// This rotation amount assumes that the lower 32 bits of the quantity are
// replicated in the high 32 bits by the rotation operator (which is done
// by rlwinm and friends in 64-bit mode).
bool Repl32;
// Did converting to Repl32 == true change the rotation factor? If it did,
// it decreased it by 32.
bool Repl32CR;
// Was this group coalesced after setting Repl32 to true?
bool Repl32Coalesced;
BitGroup(SDValue V, unsigned R, unsigned S, unsigned E)
: V(V), RLAmt(R), StartIdx(S), EndIdx(E), Repl32(false), Repl32CR(false),
Repl32Coalesced(false) {
LLVM_DEBUG(dbgs() << "\tbit group for " << V.getNode() << " RLAmt = " << R
<< " [" << S << ", " << E << "]\n");
}
};
// Information on each (Value, RLAmt) pair (like the number of groups
// associated with each) used to choose the lowering method.
struct ValueRotInfo {
SDValue V;
unsigned RLAmt = std::numeric_limits<unsigned>::max();
unsigned NumGroups = 0;
unsigned FirstGroupStartIdx = std::numeric_limits<unsigned>::max();
bool Repl32 = false;
ValueRotInfo() = default;
// For sorting (in reverse order) by NumGroups, and then by
// FirstGroupStartIdx.
bool operator < (const ValueRotInfo &Other) const {
// We need to sort so that the non-Repl32 come first because, when we're
// doing masking, the Repl32 bit groups might be subsumed into the 64-bit
// masking operation.
if (Repl32 < Other.Repl32)
return true;
else if (Repl32 > Other.Repl32)
return false;
else if (NumGroups > Other.NumGroups)
return true;
else if (NumGroups < Other.NumGroups)
return false;
else if (RLAmt == 0 && Other.RLAmt != 0)
return true;
else if (RLAmt != 0 && Other.RLAmt == 0)
return false;
else if (FirstGroupStartIdx < Other.FirstGroupStartIdx)
return true;
return false;
}
};
using ValueBitsMemoizedValue = std::pair<bool, SmallVector<ValueBit, 64>>;
using ValueBitsMemoizer =
DenseMap<SDValue, std::unique_ptr<ValueBitsMemoizedValue>>;
ValueBitsMemoizer Memoizer;
// Return a pair of bool and a SmallVector pointer to a memoization entry.
// The bool is true if something interesting was deduced, otherwise if we're
// providing only a generic representation of V (or something else likewise
// uninteresting for instruction selection) through the SmallVector.
std::pair<bool, SmallVector<ValueBit, 64> *> getValueBits(SDValue V,
unsigned NumBits) {
auto &ValueEntry = Memoizer[V];
if (ValueEntry)
return std::make_pair(ValueEntry->first, &ValueEntry->second);
ValueEntry.reset(new ValueBitsMemoizedValue());
bool &Interesting = ValueEntry->first;
SmallVector<ValueBit, 64> &Bits = ValueEntry->second;
Bits.resize(NumBits);
switch (V.getOpcode()) {
default: break;
case ISD::ROTL:
if (isa<ConstantSDNode>(V.getOperand(1))) {
unsigned RotAmt = V.getConstantOperandVal(1);
const auto &LHSBits = *getValueBits(V.getOperand(0), NumBits).second;
for (unsigned i = 0; i < NumBits; ++i)
Bits[i] = LHSBits[i < RotAmt ? i + (NumBits - RotAmt) : i - RotAmt];
return std::make_pair(Interesting = true, &Bits);
}
break;
case ISD::SHL:
if (isa<ConstantSDNode>(V.getOperand(1))) {
unsigned ShiftAmt = V.getConstantOperandVal(1);
const auto &LHSBits = *getValueBits(V.getOperand(0), NumBits).second;
for (unsigned i = ShiftAmt; i < NumBits; ++i)
Bits[i] = LHSBits[i - ShiftAmt];
for (unsigned i = 0; i < ShiftAmt; ++i)
Bits[i] = ValueBit(ValueBit::ConstZero);
return std::make_pair(Interesting = true, &Bits);
}
break;
case ISD::SRL:
if (isa<ConstantSDNode>(V.getOperand(1))) {
unsigned ShiftAmt = V.getConstantOperandVal(1);
const auto &LHSBits = *getValueBits(V.getOperand(0), NumBits).second;
for (unsigned i = 0; i < NumBits - ShiftAmt; ++i)
Bits[i] = LHSBits[i + ShiftAmt];
for (unsigned i = NumBits - ShiftAmt; i < NumBits; ++i)
Bits[i] = ValueBit(ValueBit::ConstZero);
return std::make_pair(Interesting = true, &Bits);
}
break;
case ISD::AND:
if (isa<ConstantSDNode>(V.getOperand(1))) {
uint64_t Mask = V.getConstantOperandVal(1);
const SmallVector<ValueBit, 64> *LHSBits;
// Mark this as interesting, only if the LHS was also interesting. This
// prevents the overall procedure from matching a single immediate 'and'
// (which is non-optimal because such an and might be folded with other
// things if we don't select it here).
std::tie(Interesting, LHSBits) = getValueBits(V.getOperand(0), NumBits);
for (unsigned i = 0; i < NumBits; ++i)
if (((Mask >> i) & 1) == 1)
Bits[i] = (*LHSBits)[i];
else {
// AND instruction masks this bit. If the input is already zero,
// we have nothing to do here. Otherwise, make the bit ConstZero.
if ((*LHSBits)[i].isZero())
Bits[i] = (*LHSBits)[i];
else
Bits[i] = ValueBit(ValueBit::ConstZero);
}
return std::make_pair(Interesting, &Bits);
}
break;
case ISD::OR: {
const auto &LHSBits = *getValueBits(V.getOperand(0), NumBits).second;
const auto &RHSBits = *getValueBits(V.getOperand(1), NumBits).second;
bool AllDisjoint = true;
SDValue LastVal = SDValue();
unsigned LastIdx = 0;
for (unsigned i = 0; i < NumBits; ++i) {
if (LHSBits[i].isZero() && RHSBits[i].isZero()) {
// If both inputs are known to be zero and one is ConstZero and
// another is VariableKnownToBeZero, we can select whichever
// we like. To minimize the number of bit groups, we select
// VariableKnownToBeZero if this bit is the next bit of the same
// input variable from the previous bit. Otherwise, we select
// ConstZero.
if (LHSBits[i].hasValue() && LHSBits[i].getValue() == LastVal &&
LHSBits[i].getValueBitIndex() == LastIdx + 1)
Bits[i] = LHSBits[i];
else if (RHSBits[i].hasValue() && RHSBits[i].getValue() == LastVal &&
RHSBits[i].getValueBitIndex() == LastIdx + 1)
Bits[i] = RHSBits[i];
else
Bits[i] = ValueBit(ValueBit::ConstZero);
}
else if (LHSBits[i].isZero())
Bits[i] = RHSBits[i];
else if (RHSBits[i].isZero())
Bits[i] = LHSBits[i];
else {
AllDisjoint = false;
break;
}
// We remember the value and bit index of this bit.
if (Bits[i].hasValue()) {
LastVal = Bits[i].getValue();
LastIdx = Bits[i].getValueBitIndex();
}
else {
if (LastVal) LastVal = SDValue();
LastIdx = 0;
}
}
if (!AllDisjoint)
break;
return std::make_pair(Interesting = true, &Bits);
}
case ISD::ZERO_EXTEND: {
// We support only the case with zero extension from i32 to i64 so far.
if (V.getValueType() != MVT::i64 ||
V.getOperand(0).getValueType() != MVT::i32)
break;
const SmallVector<ValueBit, 64> *LHSBits;
const unsigned NumOperandBits = 32;
std::tie(Interesting, LHSBits) = getValueBits(V.getOperand(0),
NumOperandBits);
for (unsigned i = 0; i < NumOperandBits; ++i)
Bits[i] = (*LHSBits)[i];
for (unsigned i = NumOperandBits; i < NumBits; ++i)
Bits[i] = ValueBit(ValueBit::ConstZero);
return std::make_pair(Interesting, &Bits);
}
case ISD::TRUNCATE: {
EVT FromType = V.getOperand(0).getValueType();
EVT ToType = V.getValueType();
// We support only the case with truncate from i64 to i32.
if (FromType != MVT::i64 || ToType != MVT::i32)
break;
const unsigned NumAllBits = FromType.getSizeInBits();
SmallVector<ValueBit, 64> *InBits;
std::tie(Interesting, InBits) = getValueBits(V.getOperand(0),
NumAllBits);
const unsigned NumValidBits = ToType.getSizeInBits();
// A 32-bit instruction cannot touch upper 32-bit part of 64-bit value.
// So, we cannot include this truncate.
bool UseUpper32bit = false;
for (unsigned i = 0; i < NumValidBits; ++i)
if ((*InBits)[i].hasValue() && (*InBits)[i].getValueBitIndex() >= 32) {
UseUpper32bit = true;
break;
}
if (UseUpper32bit)
break;
for (unsigned i = 0; i < NumValidBits; ++i)
Bits[i] = (*InBits)[i];
return std::make_pair(Interesting, &Bits);
}
case ISD::AssertZext: {
// For AssertZext, we look through the operand and
// mark the bits known to be zero.
const SmallVector<ValueBit, 64> *LHSBits;
std::tie(Interesting, LHSBits) = getValueBits(V.getOperand(0),
NumBits);
EVT FromType = cast<VTSDNode>(V.getOperand(1))->getVT();
const unsigned NumValidBits = FromType.getSizeInBits();
for (unsigned i = 0; i < NumValidBits; ++i)
Bits[i] = (*LHSBits)[i];
// These bits are known to be zero.
for (unsigned i = NumValidBits; i < NumBits; ++i)
Bits[i] = ValueBit((*LHSBits)[i].getValue(),
(*LHSBits)[i].getValueBitIndex(),
ValueBit::VariableKnownToBeZero);
return std::make_pair(Interesting, &Bits);
}
case ISD::LOAD:
LoadSDNode *LD = cast<LoadSDNode>(V);
if (ISD::isZEXTLoad(V.getNode()) && V.getResNo() == 0) {
EVT VT = LD->getMemoryVT();
const unsigned NumValidBits = VT.getSizeInBits();
for (unsigned i = 0; i < NumValidBits; ++i)
Bits[i] = ValueBit(V, i);
// These bits are known to be zero.
for (unsigned i = NumValidBits; i < NumBits; ++i)
Bits[i] = ValueBit(V, i, ValueBit::VariableKnownToBeZero);
// Zero-extending load itself cannot be optimized. So, it is not
// interesting by itself though it gives useful information.
return std::make_pair(Interesting = false, &Bits);
}
break;
}
for (unsigned i = 0; i < NumBits; ++i)
Bits[i] = ValueBit(V, i);
return std::make_pair(Interesting = false, &Bits);
}
// For each value (except the constant ones), compute the left-rotate amount
// to get it from its original to final position.
void computeRotationAmounts() {
NeedMask = false;
RLAmt.resize(Bits.size());
for (unsigned i = 0; i < Bits.size(); ++i)
if (Bits[i].hasValue()) {
unsigned VBI = Bits[i].getValueBitIndex();
if (i >= VBI)
RLAmt[i] = i - VBI;
else
RLAmt[i] = Bits.size() - (VBI - i);
} else if (Bits[i].isZero()) {
NeedMask = true;
RLAmt[i] = UINT32_MAX;
} else {
llvm_unreachable("Unknown value bit type");
}
}
// Collect groups of consecutive bits with the same underlying value and
// rotation factor. If we're doing late masking, we ignore zeros, otherwise
// they break up groups.
void collectBitGroups(bool LateMask) {
BitGroups.clear();
unsigned LastRLAmt = RLAmt[0];
SDValue LastValue = Bits[0].hasValue() ? Bits[0].getValue() : SDValue();
unsigned LastGroupStartIdx = 0;
bool IsGroupOfZeros = !Bits[LastGroupStartIdx].hasValue();
for (unsigned i = 1; i < Bits.size(); ++i) {
unsigned ThisRLAmt = RLAmt[i];
SDValue ThisValue = Bits[i].hasValue() ? Bits[i].getValue() : SDValue();
if (LateMask && !ThisValue) {
ThisValue = LastValue;
ThisRLAmt = LastRLAmt;
// If we're doing late masking, then the first bit group always starts
// at zero (even if the first bits were zero).
if (BitGroups.empty())
LastGroupStartIdx = 0;
}
// If this bit is known to be zero and the current group is a bit group
// of zeros, we do not need to terminate the current bit group even the
// Value or RLAmt does not match here. Instead, we terminate this group
// when the first non-zero bit appears later.
if (IsGroupOfZeros && Bits[i].isZero())
continue;
// If this bit has the same underlying value and the same rotate factor as
// the last one, then they're part of the same group.
if (ThisRLAmt == LastRLAmt && ThisValue == LastValue)
// We cannot continue the current group if this bits is not known to
// be zero in a bit group of zeros.
if (!(IsGroupOfZeros && ThisValue && !Bits[i].isZero()))
continue;
if (LastValue.getNode())
BitGroups.push_back(BitGroup(LastValue, LastRLAmt, LastGroupStartIdx,
i-1));
LastRLAmt = ThisRLAmt;
LastValue = ThisValue;
LastGroupStartIdx = i;
IsGroupOfZeros = !Bits[LastGroupStartIdx].hasValue();
}
if (LastValue.getNode())
BitGroups.push_back(BitGroup(LastValue, LastRLAmt, LastGroupStartIdx,
Bits.size()-1));
if (BitGroups.empty())
return;
// We might be able to combine the first and last groups.
if (BitGroups.size() > 1) {
// If the first and last groups are the same, then remove the first group
// in favor of the last group, making the ending index of the last group
// equal to the ending index of the to-be-removed first group.
if (BitGroups[0].StartIdx == 0 &&
BitGroups[BitGroups.size()-1].EndIdx == Bits.size()-1 &&
BitGroups[0].V == BitGroups[BitGroups.size()-1].V &&
BitGroups[0].RLAmt == BitGroups[BitGroups.size()-1].RLAmt) {
LLVM_DEBUG(dbgs() << "\tcombining final bit group with initial one\n");
BitGroups[BitGroups.size()-1].EndIdx = BitGroups[0].EndIdx;
BitGroups.erase(BitGroups.begin());
}
}
}
// Take all (SDValue, RLAmt) pairs and sort them by the number of groups
// associated with each. If the number of groups are same, we prefer a group
// which does not require rotate, i.e. RLAmt is 0, to avoid the first rotate
// instruction. If there is a degeneracy, pick the one that occurs
// first (in the final value).
void collectValueRotInfo() {
ValueRots.clear();
for (auto &BG : BitGroups) {
unsigned RLAmtKey = BG.RLAmt + (BG.Repl32 ? 64 : 0);
ValueRotInfo &VRI = ValueRots[std::make_pair(BG.V, RLAmtKey)];
VRI.V = BG.V;
VRI.RLAmt = BG.RLAmt;
VRI.Repl32 = BG.Repl32;
VRI.NumGroups += 1;
VRI.FirstGroupStartIdx = std::min(VRI.FirstGroupStartIdx, BG.StartIdx);
}
// Now that we've collected the various ValueRotInfo instances, we need to
// sort them.
ValueRotsVec.clear();
for (auto &I : ValueRots) {
ValueRotsVec.push_back(I.second);
}
llvm::sort(ValueRotsVec);
}
// In 64-bit mode, rlwinm and friends have a rotation operator that
// replicates the low-order 32 bits into the high-order 32-bits. The mask
// indices of these instructions can only be in the lower 32 bits, so they
// can only represent some 64-bit bit groups. However, when they can be used,
// the 32-bit replication can be used to represent, as a single bit group,
// otherwise separate bit groups. We'll convert to replicated-32-bit bit
// groups when possible. Returns true if any of the bit groups were
// converted.
void assignRepl32BitGroups() {
// If we have bits like this:
//
// Indices: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
// V bits: ... 7 6 5 4 3 2 1 0 31 30 29 28 27 26 25 24
// Groups: | RLAmt = 8 | RLAmt = 40 |
//
// But, making use of a 32-bit operation that replicates the low-order 32
// bits into the high-order 32 bits, this can be one bit group with a RLAmt
// of 8.
auto IsAllLow32 = [this](BitGroup & BG) {
if (BG.StartIdx <= BG.EndIdx) {
for (unsigned i = BG.StartIdx; i <= BG.EndIdx; ++i) {
if (!Bits[i].hasValue())
continue;
if (Bits[i].getValueBitIndex() >= 32)
return false;
}
} else {
for (unsigned i = BG.StartIdx; i < Bits.size(); ++i) {
if (!Bits[i].hasValue())
continue;
if (Bits[i].getValueBitIndex() >= 32)
return false;
}
for (unsigned i = 0; i <= BG.EndIdx; ++i) {
if (!Bits[i].hasValue())
continue;
if (Bits[i].getValueBitIndex() >= 32)
return false;
}
}
return true;
};
for (auto &BG : BitGroups) {
// If this bit group has RLAmt of 0 and will not be merged with
// another bit group, we don't benefit from Repl32. We don't mark
// such group to give more freedom for later instruction selection.
if (BG.RLAmt == 0) {
auto PotentiallyMerged = [this](BitGroup & BG) {
for (auto &BG2 : BitGroups)
if (&BG != &BG2 && BG.V == BG2.V &&
(BG2.RLAmt == 0 || BG2.RLAmt == 32))
return true;
return false;
};
if (!PotentiallyMerged(BG))
continue;
}
if (BG.StartIdx < 32 && BG.EndIdx < 32) {
if (IsAllLow32(BG)) {
if (BG.RLAmt >= 32) {
BG.RLAmt -= 32;
BG.Repl32CR = true;
}
BG.Repl32 = true;
LLVM_DEBUG(dbgs() << "\t32-bit replicated bit group for "
<< BG.V.getNode() << " RLAmt = " << BG.RLAmt << " ["
<< BG.StartIdx << ", " << BG.EndIdx << "]\n");
}
}
}
// Now walk through the bit groups, consolidating where possible.
for (auto I = BitGroups.begin(); I != BitGroups.end();) {
// We might want to remove this bit group by merging it with the previous
// group (which might be the ending group).
auto IP = (I == BitGroups.begin()) ?
std::prev(BitGroups.end()) : std::prev(I);
if (I->Repl32 && IP->Repl32 && I->V == IP->V && I->RLAmt == IP->RLAmt &&
I->StartIdx == (IP->EndIdx + 1) % 64 && I != IP) {
LLVM_DEBUG(dbgs() << "\tcombining 32-bit replicated bit group for "
<< I->V.getNode() << " RLAmt = " << I->RLAmt << " ["
<< I->StartIdx << ", " << I->EndIdx
<< "] with group with range [" << IP->StartIdx << ", "
<< IP->EndIdx << "]\n");
IP->EndIdx = I->EndIdx;
IP->Repl32CR = IP->Repl32CR || I->Repl32CR;
IP->Repl32Coalesced = true;
I = BitGroups.erase(I);
continue;
} else {
// There is a special case worth handling: If there is a single group
// covering the entire upper 32 bits, and it can be merged with both
// the next and previous groups (which might be the same group), then
// do so. If it is the same group (so there will be only one group in
// total), then we need to reverse the order of the range so that it
// covers the entire 64 bits.
if (I->StartIdx == 32 && I->EndIdx == 63) {
assert(std::next(I) == BitGroups.end() &&
"bit group ends at index 63 but there is another?");
auto IN = BitGroups.begin();
if (IP->Repl32 && IN->Repl32 && I->V == IP->V && I->V == IN->V &&
(I->RLAmt % 32) == IP->RLAmt && (I->RLAmt % 32) == IN->RLAmt &&
IP->EndIdx == 31 && IN->StartIdx == 0 && I != IP &&
IsAllLow32(*I)) {
LLVM_DEBUG(dbgs() << "\tcombining bit group for " << I->V.getNode()
<< " RLAmt = " << I->RLAmt << " [" << I->StartIdx
<< ", " << I->EndIdx
<< "] with 32-bit replicated groups with ranges ["
<< IP->StartIdx << ", " << IP->EndIdx << "] and ["
<< IN->StartIdx << ", " << IN->EndIdx << "]\n");
if (IP == IN) {
// There is only one other group; change it to cover the whole
// range (backward, so that it can still be Repl32 but cover the
// whole 64-bit range).
IP->StartIdx = 31;
IP->EndIdx = 30;
IP->Repl32CR = IP->Repl32CR || I->RLAmt >= 32;
IP->Repl32Coalesced = true;
I = BitGroups.erase(I);
} else {
// There are two separate groups, one before this group and one
// after us (at the beginning). We're going to remove this group,
// but also the group at the very beginning.
IP->EndIdx = IN->EndIdx;
IP->Repl32CR = IP->Repl32CR || IN->Repl32CR || I->RLAmt >= 32;
IP->Repl32Coalesced = true;
I = BitGroups.erase(I);
BitGroups.erase(BitGroups.begin());
}
// This must be the last group in the vector (and we might have
// just invalidated the iterator above), so break here.
break;
}
}
}
++I;
}
}
SDValue getI32Imm(unsigned Imm, const SDLoc &dl) {
return CurDAG->getTargetConstant(Imm, dl, MVT::i32);
}
uint64_t getZerosMask() {
uint64_t Mask = 0;
for (unsigned i = 0; i < Bits.size(); ++i) {
if (Bits[i].hasValue())
continue;
Mask |= (UINT64_C(1) << i);
}
return ~Mask;
}
// This method extends an input value to 64 bit if input is 32-bit integer.
// While selecting instructions in BitPermutationSelector in 64-bit mode,
// an input value can be a 32-bit integer if a ZERO_EXTEND node is included.
// In such case, we extend it to 64 bit to be consistent with other values.
SDValue ExtendToInt64(SDValue V, const SDLoc &dl) {
if (V.getValueSizeInBits() == 64)
return V;
assert(V.getValueSizeInBits() == 32);
SDValue SubRegIdx = CurDAG->getTargetConstant(PPC::sub_32, dl, MVT::i32);
SDValue ImDef = SDValue(CurDAG->getMachineNode(PPC::IMPLICIT_DEF, dl,
MVT::i64), 0);
SDValue ExtVal = SDValue(CurDAG->getMachineNode(PPC::INSERT_SUBREG, dl,
MVT::i64, ImDef, V,
SubRegIdx), 0);
return ExtVal;
}
SDValue TruncateToInt32(SDValue V, const SDLoc &dl) {
if (V.getValueSizeInBits() == 32)
return V;
assert(V.getValueSizeInBits() == 64);
SDValue SubRegIdx = CurDAG->getTargetConstant(PPC::sub_32, dl, MVT::i32);
SDValue SubVal = SDValue(CurDAG->getMachineNode(PPC::EXTRACT_SUBREG, dl,
MVT::i32, V, SubRegIdx), 0);
return SubVal;
}
// Depending on the number of groups for a particular value, it might be
// better to rotate, mask explicitly (using andi/andis), and then or the
// result. Select this part of the result first.
void SelectAndParts32(const SDLoc &dl, SDValue &Res, unsigned *InstCnt) {
if (BPermRewriterNoMasking)
return;
for (ValueRotInfo &VRI : ValueRotsVec) {
unsigned Mask = 0;
for (unsigned i = 0; i < Bits.size(); ++i) {
if (!Bits[i].hasValue() || Bits[i].getValue() != VRI.V)
continue;
if (RLAmt[i] != VRI.RLAmt)
continue;
Mask |= (1u << i);
}
// Compute the masks for andi/andis that would be necessary.
unsigned ANDIMask = (Mask & UINT16_MAX), ANDISMask = Mask >> 16;
assert((ANDIMask != 0 || ANDISMask != 0) &&
"No set bits in mask for value bit groups");
bool NeedsRotate = VRI.RLAmt != 0;
// We're trying to minimize the number of instructions. If we have one
// group, using one of andi/andis can break even. If we have three
// groups, we can use both andi and andis and break even (to use both
// andi and andis we also need to or the results together). We need four
// groups if we also need to rotate. To use andi/andis we need to do more
// than break even because rotate-and-mask instructions tend to be easier
// to schedule.
// FIXME: We've biased here against using andi/andis, which is right for
// POWER cores, but not optimal everywhere. For example, on the A2,
// andi/andis have single-cycle latency whereas the rotate-and-mask
// instructions take two cycles, and it would be better to bias toward
// andi/andis in break-even cases.
unsigned NumAndInsts = (unsigned) NeedsRotate +
(unsigned) (ANDIMask != 0) +
(unsigned) (ANDISMask != 0) +
(unsigned) (ANDIMask != 0 && ANDISMask != 0) +
(unsigned) (bool) Res;
LLVM_DEBUG(dbgs() << "\t\trotation groups for " << VRI.V.getNode()
<< " RL: " << VRI.RLAmt << ":"
<< "\n\t\t\tisel using masking: " << NumAndInsts
<< " using rotates: " << VRI.NumGroups << "\n");
if (NumAndInsts >= VRI.NumGroups)
continue;
LLVM_DEBUG(dbgs() << "\t\t\t\tusing masking\n");
if (InstCnt) *InstCnt += NumAndInsts;
SDValue VRot;
if (VRI.RLAmt) {
SDValue Ops[] =
{ TruncateToInt32(VRI.V, dl), getI32Imm(VRI.RLAmt, dl),
getI32Imm(0, dl), getI32Imm(31, dl) };
VRot = SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32,
Ops), 0);
} else {
VRot = TruncateToInt32(VRI.V, dl);
}
SDValue ANDIVal, ANDISVal;
if (ANDIMask != 0)
ANDIVal = SDValue(CurDAG->getMachineNode(PPC::ANDIo, dl, MVT::i32,
VRot, getI32Imm(ANDIMask, dl)), 0);
if (ANDISMask != 0)
ANDISVal = SDValue(CurDAG->getMachineNode(PPC::ANDISo, dl, MVT::i32,
VRot, getI32Imm(ANDISMask, dl)), 0);
SDValue TotalVal;
if (!ANDIVal)
TotalVal = ANDISVal;
else if (!ANDISVal)
TotalVal = ANDIVal;
else
TotalVal = SDValue(CurDAG->getMachineNode(PPC::OR, dl, MVT::i32,
ANDIVal, ANDISVal), 0);
if (!Res)
Res = TotalVal;
else
Res = SDValue(CurDAG->getMachineNode(PPC::OR, dl, MVT::i32,
Res, TotalVal), 0);
// Now, remove all groups with this underlying value and rotation
// factor.
eraseMatchingBitGroups([VRI](const BitGroup &BG) {
return BG.V == VRI.V && BG.RLAmt == VRI.RLAmt;
});
}
}
// Instruction selection for the 32-bit case.
SDNode *Select32(SDNode *N, bool LateMask, unsigned *InstCnt) {
SDLoc dl(N);
SDValue Res;
if (InstCnt) *InstCnt = 0;
// Take care of cases that should use andi/andis first.
SelectAndParts32(dl, Res, InstCnt);
// If we've not yet selected a 'starting' instruction, and we have no zeros
// to fill in, select the (Value, RLAmt) with the highest priority (largest
// number of groups), and start with this rotated value.
if ((!NeedMask || LateMask) && !Res) {
ValueRotInfo &VRI = ValueRotsVec[0];
if (VRI.RLAmt) {
if (InstCnt) *InstCnt += 1;
SDValue Ops[] =
{ TruncateToInt32(VRI.V, dl), getI32Imm(VRI.RLAmt, dl),
getI32Imm(0, dl), getI32Imm(31, dl) };
Res = SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, Ops),
0);
} else {
Res = TruncateToInt32(VRI.V, dl);
}
// Now, remove all groups with this underlying value and rotation factor.
eraseMatchingBitGroups([VRI](const BitGroup &BG) {
return BG.V == VRI.V && BG.RLAmt == VRI.RLAmt;
});
}
if (InstCnt) *InstCnt += BitGroups.size();
// Insert the other groups (one at a time).
for (auto &BG : BitGroups) {
if (!Res) {
SDValue Ops[] =
{ TruncateToInt32(BG.V, dl), getI32Imm(BG.RLAmt, dl),
getI32Imm(Bits.size() - BG.EndIdx - 1, dl),
getI32Imm(Bits.size() - BG.StartIdx - 1, dl) };
Res = SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, Ops), 0);
} else {
SDValue Ops[] =
{ Res, TruncateToInt32(BG.V, dl), getI32Imm(BG.RLAmt, dl),
getI32Imm(Bits.size() - BG.EndIdx - 1, dl),
getI32Imm(Bits.size() - BG.StartIdx - 1, dl) };
Res = SDValue(CurDAG->getMachineNode(PPC::RLWIMI, dl, MVT::i32, Ops), 0);
}
}
if (LateMask) {
unsigned Mask = (unsigned) getZerosMask();
unsigned ANDIMask = (Mask & UINT16_MAX), ANDISMask = Mask >> 16;
assert((ANDIMask != 0 || ANDISMask != 0) &&
"No set bits in zeros mask?");
if (InstCnt) *InstCnt += (unsigned) (ANDIMask != 0) +
(unsigned) (ANDISMask != 0) +
(unsigned) (ANDIMask != 0 && ANDISMask != 0);
SDValue ANDIVal, ANDISVal;
if (ANDIMask != 0)
ANDIVal = SDValue(CurDAG->getMachineNode(PPC::ANDIo, dl, MVT::i32,
Res, getI32Imm(ANDIMask, dl)), 0);
if (ANDISMask != 0)
ANDISVal = SDValue(CurDAG->getMachineNode(PPC::ANDISo, dl, MVT::i32,
Res, getI32Imm(ANDISMask, dl)), 0);
if (!ANDIVal)
Res = ANDISVal;
else if (!ANDISVal)
Res = ANDIVal;
else
Res = SDValue(CurDAG->getMachineNode(PPC::OR, dl, MVT::i32,
ANDIVal, ANDISVal), 0);
}
return Res.getNode();
}
unsigned SelectRotMask64Count(unsigned RLAmt, bool Repl32,
unsigned MaskStart, unsigned MaskEnd,
bool IsIns) {
// In the notation used by the instructions, 'start' and 'end' are reversed
// because bits are counted from high to low order.
unsigned InstMaskStart = 64 - MaskEnd - 1,
InstMaskEnd = 64 - MaskStart - 1;
if (Repl32)
return 1;
if ((!IsIns && (InstMaskEnd == 63 || InstMaskStart == 0)) ||
InstMaskEnd == 63 - RLAmt)
return 1;
return 2;
}
// For 64-bit values, not all combinations of rotates and masks are
// available. Produce one if it is available.
SDValue SelectRotMask64(SDValue V, const SDLoc &dl, unsigned RLAmt,
bool Repl32, unsigned MaskStart, unsigned MaskEnd,
unsigned *InstCnt = nullptr) {
// In the notation used by the instructions, 'start' and 'end' are reversed
// because bits are counted from high to low order.
unsigned InstMaskStart = 64 - MaskEnd - 1,
InstMaskEnd = 64 - MaskStart - 1;
if (InstCnt) *InstCnt += 1;
if (Repl32) {
// This rotation amount assumes that the lower 32 bits of the quantity
// are replicated in the high 32 bits by the rotation operator (which is
// done by rlwinm and friends).
assert(InstMaskStart >= 32 && "Mask cannot start out of range");
assert(InstMaskEnd >= 32 && "Mask cannot end out of range");
SDValue Ops[] =
{ ExtendToInt64(V, dl), getI32Imm(RLAmt, dl),
getI32Imm(InstMaskStart - 32, dl), getI32Imm(InstMaskEnd - 32, dl) };
return SDValue(CurDAG->getMachineNode(PPC::RLWINM8, dl, MVT::i64,
Ops), 0);
}
if (InstMaskEnd == 63) {
SDValue Ops[] =
{ ExtendToInt64(V, dl), getI32Imm(RLAmt, dl),
getI32Imm(InstMaskStart, dl) };
return SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, Ops), 0);
}
if (InstMaskStart == 0) {
SDValue Ops[] =
{ ExtendToInt64(V, dl), getI32Imm(RLAmt, dl),
getI32Imm(InstMaskEnd, dl) };
return SDValue(CurDAG->getMachineNode(PPC::RLDICR, dl, MVT::i64, Ops), 0);
}
if (InstMaskEnd == 63 - RLAmt) {
SDValue Ops[] =
{ ExtendToInt64(V, dl), getI32Imm(RLAmt, dl),
getI32Imm(InstMaskStart, dl) };
return SDValue(CurDAG->getMachineNode(PPC::RLDIC, dl, MVT::i64, Ops), 0);
}
// We cannot do this with a single instruction, so we'll use two. The
// problem is that we're not free to choose both a rotation amount and mask
// start and end independently. We can choose an arbitrary mask start and
// end, but then the rotation amount is fixed. Rotation, however, can be
// inverted, and so by applying an "inverse" rotation first, we can get the
// desired result.
if (InstCnt) *InstCnt += 1;
// The rotation mask for the second instruction must be MaskStart.
unsigned RLAmt2 = MaskStart;
// The first instruction must rotate V so that the overall rotation amount
// is RLAmt.
unsigned RLAmt1 = (64 + RLAmt - RLAmt2) % 64;
if (RLAmt1)
V = SelectRotMask64(V, dl, RLAmt1, false, 0, 63);
return SelectRotMask64(V, dl, RLAmt2, false, MaskStart, MaskEnd);
}
// For 64-bit values, not all combinations of rotates and masks are
// available. Produce a rotate-mask-and-insert if one is available.
SDValue SelectRotMaskIns64(SDValue Base, SDValue V, const SDLoc &dl,
unsigned RLAmt, bool Repl32, unsigned MaskStart,
unsigned MaskEnd, unsigned *InstCnt = nullptr) {
// In the notation used by the instructions, 'start' and 'end' are reversed
// because bits are counted from high to low order.
unsigned InstMaskStart = 64 - MaskEnd - 1,
InstMaskEnd = 64 - MaskStart - 1;
if (InstCnt) *InstCnt += 1;
if (Repl32) {
// This rotation amount assumes that the lower 32 bits of the quantity
// are replicated in the high 32 bits by the rotation operator (which is
// done by rlwinm and friends).
assert(InstMaskStart >= 32 && "Mask cannot start out of range");
assert(InstMaskEnd >= 32 && "Mask cannot end out of range");
SDValue Ops[] =
{ ExtendToInt64(Base, dl), ExtendToInt64(V, dl), getI32Imm(RLAmt, dl),
getI32Imm(InstMaskStart - 32, dl), getI32Imm(InstMaskEnd - 32, dl) };
return SDValue(CurDAG->getMachineNode(PPC::RLWIMI8, dl, MVT::i64,
Ops), 0);
}
if (InstMaskEnd == 63 - RLAmt) {
SDValue Ops[] =
{ ExtendToInt64(Base, dl), ExtendToInt64(V, dl), getI32Imm(RLAmt, dl),
getI32Imm(InstMaskStart, dl) };
return SDValue(CurDAG->getMachineNode(PPC::RLDIMI, dl, MVT::i64, Ops), 0);
}
// We cannot do this with a single instruction, so we'll use two. The
// problem is that we're not free to choose both a rotation amount and mask
// start and end independently. We can choose an arbitrary mask start and
// end, but then the rotation amount is fixed. Rotation, however, can be
// inverted, and so by applying an "inverse" rotation first, we can get the
// desired result.
if (InstCnt) *InstCnt += 1;
// The rotation mask for the second instruction must be MaskStart.
unsigned RLAmt2 = MaskStart;
// The first instruction must rotate V so that the overall rotation amount
// is RLAmt.
unsigned RLAmt1 = (64 + RLAmt - RLAmt2) % 64;
if (RLAmt1)
V = SelectRotMask64(V, dl, RLAmt1, false, 0, 63);
return SelectRotMaskIns64(Base, V, dl, RLAmt2, false, MaskStart, MaskEnd);
}
void SelectAndParts64(const SDLoc &dl, SDValue &Res, unsigned *InstCnt) {
if (BPermRewriterNoMasking)
return;
// The idea here is the same as in the 32-bit version, but with additional
// complications from the fact that Repl32 might be true. Because we
// aggressively convert bit groups to Repl32 form (which, for small
// rotation factors, involves no other change), and then coalesce, it might
// be the case that a single 64-bit masking operation could handle both
// some Repl32 groups and some non-Repl32 groups. If converting to Repl32
// form allowed coalescing, then we must use a 32-bit rotaton in order to
// completely capture the new combined bit group.
for (ValueRotInfo &VRI : ValueRotsVec) {
uint64_t Mask = 0;
// We need to add to the mask all bits from the associated bit groups.
// If Repl32 is false, we need to add bits from bit groups that have
// Repl32 true, but are trivially convertable to Repl32 false. Such a
// group is trivially convertable if it overlaps only with the lower 32
// bits, and the group has not been coalesced.
auto MatchingBG = [VRI](const BitGroup &BG) {
if (VRI.V != BG.V)
return false;
unsigned EffRLAmt = BG.RLAmt;
if (!VRI.Repl32 && BG.Repl32) {
if (BG.StartIdx < 32 && BG.EndIdx < 32 && BG.StartIdx <= BG.EndIdx &&
!BG.Repl32Coalesced) {
if (BG.Repl32CR)
EffRLAmt += 32;
} else {
return false;
}
} else if (VRI.Repl32 != BG.Repl32) {
return false;
}
return VRI.RLAmt == EffRLAmt;
};
for (auto &BG : BitGroups) {
if (!MatchingBG(BG))
continue;
if (BG.StartIdx <= BG.EndIdx) {
for (unsigned i = BG.StartIdx; i <= BG.EndIdx; ++i)
Mask |= (UINT64_C(1) << i);
} else {
for (unsigned i = BG.StartIdx; i < Bits.size(); ++i)
Mask |= (UINT64_C(1) << i);
for (unsigned i = 0; i <= BG.EndIdx; ++i)
Mask |= (UINT64_C(1) << i);
}
}
// We can use the 32-bit andi/andis technique if the mask does not
// require any higher-order bits. This can save an instruction compared
// to always using the general 64-bit technique.
bool Use32BitInsts = isUInt<32>(Mask);
// Compute the masks for andi/andis that would be necessary.
unsigned ANDIMask = (Mask & UINT16_MAX),
ANDISMask = (Mask >> 16) & UINT16_MAX;
bool NeedsRotate = VRI.RLAmt || (VRI.Repl32 && !isUInt<32>(Mask));
unsigned NumAndInsts = (unsigned) NeedsRotate +
(unsigned) (bool) Res;
if (Use32BitInsts)
NumAndInsts += (unsigned) (ANDIMask != 0) + (unsigned) (ANDISMask != 0) +
(unsigned) (ANDIMask != 0 && ANDISMask != 0);
else
NumAndInsts += selectI64ImmInstrCount(Mask) + /* and */ 1;
unsigned NumRLInsts = 0;
bool FirstBG = true;
bool MoreBG = false;
for (auto &BG : BitGroups) {
if (!MatchingBG(BG)) {
MoreBG = true;
continue;
}
NumRLInsts +=
SelectRotMask64Count(BG.RLAmt, BG.Repl32, BG.StartIdx, BG.EndIdx,
!FirstBG);
FirstBG = false;
}
LLVM_DEBUG(dbgs() << "\t\trotation groups for " << VRI.V.getNode()
<< " RL: " << VRI.RLAmt << (VRI.Repl32 ? " (32):" : ":")
<< "\n\t\t\tisel using masking: " << NumAndInsts
<< " using rotates: " << NumRLInsts << "\n");
// When we'd use andi/andis, we bias toward using the rotates (andi only
// has a record form, and is cracked on POWER cores). However, when using
// general 64-bit constant formation, bias toward the constant form,
// because that exposes more opportunities for CSE.
if (NumAndInsts > NumRLInsts)
continue;
// When merging multiple bit groups, instruction or is used.
// But when rotate is used, rldimi can inert the rotated value into any
// register, so instruction or can be avoided.
if ((Use32BitInsts || MoreBG) && NumAndInsts == NumRLInsts)
continue;
LLVM_DEBUG(dbgs() << "\t\t\t\tusing masking\n");
if (InstCnt) *InstCnt += NumAndInsts;
SDValue VRot;
// We actually need to generate a rotation if we have a non-zero rotation
// factor or, in the Repl32 case, if we care about any of the
// higher-order replicated bits. In the latter case, we generate a mask
// backward so that it actually includes the entire 64 bits.
if (VRI.RLAmt || (VRI.Repl32 && !isUInt<32>(Mask)))
VRot = SelectRotMask64(VRI.V, dl, VRI.RLAmt, VRI.Repl32,
VRI.Repl32 ? 31 : 0, VRI.Repl32 ? 30 : 63);
else
VRot = VRI.V;
SDValue TotalVal;
if (Use32BitInsts) {
assert((ANDIMask != 0 || ANDISMask != 0) &&
"No set bits in mask when using 32-bit ands for 64-bit value");
SDValue ANDIVal, ANDISVal;
if (ANDIMask != 0)
ANDIVal = SDValue(CurDAG->getMachineNode(PPC::ANDIo8, dl, MVT::i64,
ExtendToInt64(VRot, dl),
getI32Imm(ANDIMask, dl)),
0);
if (ANDISMask != 0)
ANDISVal = SDValue(CurDAG->getMachineNode(PPC::ANDISo8, dl, MVT::i64,
ExtendToInt64(VRot, dl),
getI32Imm(ANDISMask, dl)),
0);
if (!ANDIVal)
TotalVal = ANDISVal;
else if (!ANDISVal)
TotalVal = ANDIVal;
else
TotalVal = SDValue(CurDAG->getMachineNode(PPC::OR8, dl, MVT::i64,
ExtendToInt64(ANDIVal, dl), ANDISVal), 0);
} else {
TotalVal = SDValue(selectI64Imm(CurDAG, dl, Mask), 0);
TotalVal =
SDValue(CurDAG->getMachineNode(PPC::AND8, dl, MVT::i64,
ExtendToInt64(VRot, dl), TotalVal),
0);
}
if (!Res)
Res = TotalVal;
else
Res = SDValue(CurDAG->getMachineNode(PPC::OR8, dl, MVT::i64,
ExtendToInt64(Res, dl), TotalVal),
0);
// Now, remove all groups with this underlying value and rotation
// factor.
eraseMatchingBitGroups(MatchingBG);
}
}
// Instruction selection for the 64-bit case.
SDNode *Select64(SDNode *N, bool LateMask, unsigned *InstCnt) {
SDLoc dl(N);
SDValue Res;
if (InstCnt) *InstCnt = 0;
// Take care of cases that should use andi/andis first.
SelectAndParts64(dl, Res, InstCnt);
// If we've not yet selected a 'starting' instruction, and we have no zeros
// to fill in, select the (Value, RLAmt) with the highest priority (largest
// number of groups), and start with this rotated value.
if ((!NeedMask || LateMask) && !Res) {
// If we have both Repl32 groups and non-Repl32 groups, the non-Repl32
// groups will come first, and so the VRI representing the largest number
// of groups might not be first (it might be the first Repl32 groups).
unsigned MaxGroupsIdx = 0;
if (!ValueRotsVec[0].Repl32) {
for (unsigned i = 0, ie = ValueRotsVec.size(); i < ie; ++i)
if (ValueRotsVec[i].Repl32) {
if (ValueRotsVec[i].NumGroups > ValueRotsVec[0].NumGroups)
MaxGroupsIdx = i;
break;
}
}
ValueRotInfo &VRI = ValueRotsVec[MaxGroupsIdx];
bool NeedsRotate = false;
if (VRI.RLAmt) {
NeedsRotate = true;
} else if (VRI.Repl32) {
for (auto &BG : BitGroups) {
if (BG.V != VRI.V || BG.RLAmt != VRI.RLAmt ||
BG.Repl32 != VRI.Repl32)
continue;
// We don't need a rotate if the bit group is confined to the lower
// 32 bits.
if (BG.StartIdx < 32 && BG.EndIdx < 32 && BG.StartIdx < BG.EndIdx)
continue;
NeedsRotate = true;
break;
}
}
if (NeedsRotate)
Res = SelectRotMask64(VRI.V, dl, VRI.RLAmt, VRI.Repl32,
VRI.Repl32 ? 31 : 0, VRI.Repl32 ? 30 : 63,
InstCnt);
else
Res = VRI.V;
// Now, remove all groups with this underlying value and rotation factor.
if (Res)
eraseMatchingBitGroups([VRI](const BitGroup &BG) {
return BG.V == VRI.V && BG.RLAmt == VRI.RLAmt &&
BG.Repl32 == VRI.Repl32;
});
}
// Because 64-bit rotates are more flexible than inserts, we might have a
// preference regarding which one we do first (to save one instruction).
if (!Res)
for (auto I = BitGroups.begin(), IE = BitGroups.end(); I != IE; ++I) {
if (SelectRotMask64Count(I->RLAmt, I->Repl32, I->StartIdx, I->EndIdx,
false) <
SelectRotMask64Count(I->RLAmt, I->Repl32, I->StartIdx, I->EndIdx,
true)) {
if (I != BitGroups.begin()) {
BitGroup BG = *I;
BitGroups.erase(I);
BitGroups.insert(BitGroups.begin(), BG);
}
break;
}
}
// Insert the other groups (one at a time).
for (auto &BG : BitGroups) {
if (!Res)
Res = SelectRotMask64(BG.V, dl, BG.RLAmt, BG.Repl32, BG.StartIdx,
BG.EndIdx, InstCnt);
else
Res = SelectRotMaskIns64(Res, BG.V, dl, BG.RLAmt, BG.Repl32,
BG.StartIdx, BG.EndIdx, InstCnt);
}
if (LateMask) {
uint64_t Mask = getZerosMask();
// We can use the 32-bit andi/andis technique if the mask does not
// require any higher-order bits. This can save an instruction compared
// to always using the general 64-bit technique.
bool Use32BitInsts = isUInt<32>(Mask);
// Compute the masks for andi/andis that would be necessary.
unsigned ANDIMask = (Mask & UINT16_MAX),
ANDISMask = (Mask >> 16) & UINT16_MAX;
if (Use32BitInsts) {
assert((ANDIMask != 0 || ANDISMask != 0) &&
"No set bits in mask when using 32-bit ands for 64-bit value");
if (InstCnt) *InstCnt += (unsigned) (ANDIMask != 0) +
(unsigned) (ANDISMask != 0) +
(unsigned) (ANDIMask != 0 && ANDISMask != 0);
SDValue ANDIVal, ANDISVal;
if (ANDIMask != 0)
ANDIVal = SDValue(CurDAG->getMachineNode(PPC::ANDIo8, dl, MVT::i64,
ExtendToInt64(Res, dl), getI32Imm(ANDIMask, dl)), 0);
if (ANDISMask != 0)
ANDISVal = SDValue(CurDAG->getMachineNode(PPC::ANDISo8, dl, MVT::i64,
ExtendToInt64(Res, dl), getI32Imm(ANDISMask, dl)), 0);
if (!ANDIVal)
Res = ANDISVal;
else if (!ANDISVal)
Res = ANDIVal;
else
Res = SDValue(CurDAG->getMachineNode(PPC::OR8, dl, MVT::i64,
ExtendToInt64(ANDIVal, dl), ANDISVal), 0);
} else {
if (InstCnt) *InstCnt += selectI64ImmInstrCount(Mask) + /* and */ 1;
SDValue MaskVal = SDValue(selectI64Imm(CurDAG, dl, Mask), 0);
Res =
SDValue(CurDAG->getMachineNode(PPC::AND8, dl, MVT::i64,
ExtendToInt64(Res, dl), MaskVal), 0);
}
}
return Res.getNode();
}
SDNode *Select(SDNode *N, bool LateMask, unsigned *InstCnt = nullptr) {
// Fill in BitGroups.
collectBitGroups(LateMask);
if (BitGroups.empty())
return nullptr;
// For 64-bit values, figure out when we can use 32-bit instructions.
if (Bits.size() == 64)
assignRepl32BitGroups();
// Fill in ValueRotsVec.
collectValueRotInfo();
if (Bits.size() == 32) {
return Select32(N, LateMask, InstCnt);
} else {
assert(Bits.size() == 64 && "Not 64 bits here?");
return Select64(N, LateMask, InstCnt);
}
return nullptr;
}
void eraseMatchingBitGroups(function_ref<bool(const BitGroup &)> F) {
BitGroups.erase(remove_if(BitGroups, F), BitGroups.end());
}
SmallVector<ValueBit, 64> Bits;
bool NeedMask;
SmallVector<unsigned, 64> RLAmt;
SmallVector<BitGroup, 16> BitGroups;
DenseMap<std::pair<SDValue, unsigned>, ValueRotInfo> ValueRots;
SmallVector<ValueRotInfo, 16> ValueRotsVec;
SelectionDAG *CurDAG;
public:
BitPermutationSelector(SelectionDAG *DAG)
: CurDAG(DAG) {}
// Here we try to match complex bit permutations into a set of
// rotate-and-shift/shift/and/or instructions, using a set of heuristics
// known to produce optimial code for common cases (like i32 byte swapping).
SDNode *Select(SDNode *N) {
Memoizer.clear();
auto Result =
getValueBits(SDValue(N, 0), N->getValueType(0).getSizeInBits());
if (!Result.first)
return nullptr;
Bits = std::move(*Result.second);
LLVM_DEBUG(dbgs() << "Considering bit-permutation-based instruction"
" selection for: ");
LLVM_DEBUG(N->dump(CurDAG));
// Fill it RLAmt and set NeedMask.
computeRotationAmounts();
if (!NeedMask)
return Select(N, false);
// We currently have two techniques for handling results with zeros: early
// masking (the default) and late masking. Late masking is sometimes more
// efficient, but because the structure of the bit groups is different, it
// is hard to tell without generating both and comparing the results. With
// late masking, we ignore zeros in the resulting value when inserting each
// set of bit groups, and then mask in the zeros at the end. With early
// masking, we only insert the non-zero parts of the result at every step.
unsigned InstCnt = 0, InstCntLateMask = 0;
LLVM_DEBUG(dbgs() << "\tEarly masking:\n");
SDNode *RN = Select(N, false, &InstCnt);
LLVM_DEBUG(dbgs() << "\t\tisel would use " << InstCnt << " instructions\n");
LLVM_DEBUG(dbgs() << "\tLate masking:\n");
SDNode *RNLM = Select(N, true, &InstCntLateMask);
LLVM_DEBUG(dbgs() << "\t\tisel would use " << InstCntLateMask
<< " instructions\n");
if (InstCnt <= InstCntLateMask) {
LLVM_DEBUG(dbgs() << "\tUsing early-masking for isel\n");
return RN;
}
LLVM_DEBUG(dbgs() << "\tUsing late-masking for isel\n");
return RNLM;
}
};
class IntegerCompareEliminator {
SelectionDAG *CurDAG;
PPCDAGToDAGISel *S;
// Conversion type for interpreting results of a 32-bit instruction as
// a 64-bit value or vice versa.
enum ExtOrTruncConversion { Ext, Trunc };
// Modifiers to guide how an ISD::SETCC node's result is to be computed
// in a GPR.
// ZExtOrig - use the original condition code, zero-extend value
// ZExtInvert - invert the condition code, zero-extend value
// SExtOrig - use the original condition code, sign-extend value
// SExtInvert - invert the condition code, sign-extend value
enum SetccInGPROpts { ZExtOrig, ZExtInvert, SExtOrig, SExtInvert };
// Comparisons against zero to emit GPR code sequences for. Each of these
// sequences may need to be emitted for two or more equivalent patterns.
// For example (a >= 0) == (a > -1). The direction of the comparison (</>)
// matters as well as the extension type: sext (-1/0), zext (1/0).
// GEZExt - (zext (LHS >= 0))
// GESExt - (sext (LHS >= 0))
// LEZExt - (zext (LHS <= 0))
// LESExt - (sext (LHS <= 0))
enum ZeroCompare { GEZExt, GESExt, LEZExt, LESExt };
SDNode *tryEXTEND(SDNode *N);
SDNode *tryLogicOpOfCompares(SDNode *N);
SDValue computeLogicOpInGPR(SDValue LogicOp);
SDValue signExtendInputIfNeeded(SDValue Input);
SDValue zeroExtendInputIfNeeded(SDValue Input);
SDValue addExtOrTrunc(SDValue NatWidthRes, ExtOrTruncConversion Conv);
SDValue getCompoundZeroComparisonInGPR(SDValue LHS, SDLoc dl,
ZeroCompare CmpTy);
SDValue get32BitZExtCompare(SDValue LHS, SDValue RHS, ISD::CondCode CC,
int64_t RHSValue, SDLoc dl);
SDValue get32BitSExtCompare(SDValue LHS, SDValue RHS, ISD::CondCode CC,
int64_t RHSValue, SDLoc dl);
SDValue get64BitZExtCompare(SDValue LHS, SDValue RHS, ISD::CondCode CC,
int64_t RHSValue, SDLoc dl);
SDValue get64BitSExtCompare(SDValue LHS, SDValue RHS, ISD::CondCode CC,
int64_t RHSValue, SDLoc dl);
SDValue getSETCCInGPR(SDValue Compare, SetccInGPROpts ConvOpts);
public:
IntegerCompareEliminator(SelectionDAG *DAG,
PPCDAGToDAGISel *Sel) : CurDAG(DAG), S(Sel) {
assert(CurDAG->getTargetLoweringInfo()
.getPointerTy(CurDAG->getDataLayout()).getSizeInBits() == 64 &&
"Only expecting to use this on 64 bit targets.");
}
SDNode *Select(SDNode *N) {
if (CmpInGPR == ICGPR_None)
return nullptr;
switch (N->getOpcode()) {
default: break;
case ISD::ZERO_EXTEND:
if (CmpInGPR == ICGPR_Sext || CmpInGPR == ICGPR_SextI32 ||
CmpInGPR == ICGPR_SextI64)
return nullptr;
LLVM_FALLTHROUGH;
case ISD::SIGN_EXTEND:
if (CmpInGPR == ICGPR_Zext || CmpInGPR == ICGPR_ZextI32 ||
CmpInGPR == ICGPR_ZextI64)
return nullptr;
return tryEXTEND(N);
case ISD::AND:
case ISD::OR:
case ISD::XOR:
return tryLogicOpOfCompares(N);
}
return nullptr;
}
};
static bool isLogicOp(unsigned Opc) {
return Opc == ISD::AND || Opc == ISD::OR || Opc == ISD::XOR;
}
// The obvious case for wanting to keep the value in a GPR. Namely, the
// result of the comparison is actually needed in a GPR.
SDNode *IntegerCompareEliminator::tryEXTEND(SDNode *N) {
assert((N->getOpcode() == ISD::ZERO_EXTEND ||
N->getOpcode() == ISD::SIGN_EXTEND) &&
"Expecting a zero/sign extend node!");
SDValue WideRes;
// If we are zero-extending the result of a logical operation on i1
// values, we can keep the values in GPRs.
if (isLogicOp(N->getOperand(0).getOpcode()) &&
N->getOperand(0).getValueType() == MVT::i1 &&
N->getOpcode() == ISD::ZERO_EXTEND)
WideRes = computeLogicOpInGPR(N->getOperand(0));
else if (N->getOperand(0).getOpcode() != ISD::SETCC)
return nullptr;
else
WideRes =
getSETCCInGPR(N->getOperand(0),
N->getOpcode() == ISD::SIGN_EXTEND ?
SetccInGPROpts::SExtOrig : SetccInGPROpts::ZExtOrig);
if (!WideRes)
return nullptr;
SDLoc dl(N);
bool Input32Bit = WideRes.getValueType() == MVT::i32;
bool Output32Bit = N->getValueType(0) == MVT::i32;
NumSextSetcc += N->getOpcode() == ISD::SIGN_EXTEND ? 1 : 0;
NumZextSetcc += N->getOpcode() == ISD::SIGN_EXTEND ? 0 : 1;
SDValue ConvOp = WideRes;
if (Input32Bit != Output32Bit)
ConvOp = addExtOrTrunc(WideRes, Input32Bit ? ExtOrTruncConversion::Ext :
ExtOrTruncConversion::Trunc);
return ConvOp.getNode();
}
// Attempt to perform logical operations on the results of comparisons while
// keeping the values in GPRs. Without doing so, these would end up being
// lowered to CR-logical operations which suffer from significant latency and
// low ILP.
SDNode *IntegerCompareEliminator::tryLogicOpOfCompares(SDNode *N) {
if (N->getValueType(0) != MVT::i1)
return nullptr;
assert(isLogicOp(N->getOpcode()) &&
"Expected a logic operation on setcc results.");
SDValue LoweredLogical = computeLogicOpInGPR(SDValue(N, 0));
if (!LoweredLogical)
return nullptr;
SDLoc dl(N);
bool IsBitwiseNegate = LoweredLogical.getMachineOpcode() == PPC::XORI8;
unsigned SubRegToExtract = IsBitwiseNegate ? PPC::sub_eq : PPC::sub_gt;
SDValue CR0Reg = CurDAG->getRegister(PPC::CR0, MVT::i32);
SDValue LHS = LoweredLogical.getOperand(0);
SDValue RHS = LoweredLogical.getOperand(1);
SDValue WideOp;
SDValue OpToConvToRecForm;
// Look through any 32-bit to 64-bit implicit extend nodes to find the
// opcode that is input to the XORI.
if (IsBitwiseNegate &&
LoweredLogical.getOperand(0).getMachineOpcode() == PPC::INSERT_SUBREG)
OpToConvToRecForm = LoweredLogical.getOperand(0).getOperand(1);
else if (IsBitwiseNegate)
// If the input to the XORI isn't an extension, that's what we're after.
OpToConvToRecForm = LoweredLogical.getOperand(0);
else
// If this is not an XORI, it is a reg-reg logical op and we can convert
// it to record-form.
OpToConvToRecForm = LoweredLogical;
// Get the record-form version of the node we're looking to use to get the
// CR result from.
uint16_t NonRecOpc = OpToConvToRecForm.getMachineOpcode();
int NewOpc = PPCInstrInfo::getRecordFormOpcode(NonRecOpc);
// Convert the right node to record-form. This is either the logical we're
// looking at or it is the input node to the negation (if we're looking at
// a bitwise negation).
if (NewOpc != -1 && IsBitwiseNegate) {
// The input to the XORI has a record-form. Use it.
assert(LoweredLogical.getConstantOperandVal(1) == 1 &&
"Expected a PPC::XORI8 only for bitwise negation.");
// Emit the record-form instruction.
std::vector<SDValue> Ops;
for (int i = 0, e = OpToConvToRecForm.getNumOperands(); i < e; i++)
Ops.push_back(OpToConvToRecForm.getOperand(i));
WideOp =
SDValue(CurDAG->getMachineNode(NewOpc, dl,
OpToConvToRecForm.getValueType(),
MVT::Glue, Ops), 0);
} else {
assert((NewOpc != -1 || !IsBitwiseNegate) &&
"No record form available for AND8/OR8/XOR8?");
WideOp =
SDValue(CurDAG->getMachineNode(NewOpc == -1 ? PPC::ANDIo8 : NewOpc, dl,
MVT::i64, MVT::Glue, LHS, RHS), 0);
}
// Select this node to a single bit from CR0 set by the record-form node
// just created. For bitwise negation, use the EQ bit which is the equivalent
// of negating the result (i.e. it is a bit set when the result of the
// operation is zero).
SDValue SRIdxVal =
CurDAG->getTargetConstant(SubRegToExtract, dl, MVT::i32);
SDValue CRBit =
SDValue(CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, dl,
MVT::i1, CR0Reg, SRIdxVal,
WideOp.getValue(1)), 0);
return CRBit.getNode();
}
// Lower a logical operation on i1 values into a GPR sequence if possible.
// The result can be kept in a GPR if requested.
// Three types of inputs can be handled:
// - SETCC
// - TRUNCATE
// - Logical operation (AND/OR/XOR)
// There is also a special case that is handled (namely a complement operation
// achieved with xor %a, -1).
SDValue IntegerCompareEliminator::computeLogicOpInGPR(SDValue LogicOp) {
assert(isLogicOp(LogicOp.getOpcode()) &&
"Can only handle logic operations here.");
assert(LogicOp.getValueType() == MVT::i1 &&
"Can only handle logic operations on i1 values here.");
SDLoc dl(LogicOp);
SDValue LHS, RHS;
// Special case: xor %a, -1
bool IsBitwiseNegation = isBitwiseNot(LogicOp);
// Produces a GPR sequence for each operand of the binary logic operation.
// For SETCC, it produces the respective comparison, for TRUNCATE it truncates
// the value in a GPR and for logic operations, it will recursively produce
// a GPR sequence for the operation.
auto getLogicOperand = [&] (SDValue Operand) -> SDValue {
unsigned OperandOpcode = Operand.getOpcode();
if (OperandOpcode == ISD::SETCC)
return getSETCCInGPR(Operand, SetccInGPROpts::ZExtOrig);
else if (OperandOpcode == ISD::TRUNCATE) {
SDValue InputOp = Operand.getOperand(0);
EVT InVT = InputOp.getValueType();
return SDValue(CurDAG->getMachineNode(InVT == MVT::i32 ? PPC::RLDICL_32 :
PPC::RLDICL, dl, InVT, InputOp,
S->getI64Imm(0, dl),
S->getI64Imm(63, dl)), 0);
} else if (isLogicOp(OperandOpcode))
return computeLogicOpInGPR(Operand);
return SDValue();
};
LHS = getLogicOperand(LogicOp.getOperand(0));
RHS = getLogicOperand(LogicOp.getOperand(1));
// If a GPR sequence can't be produced for the LHS we can't proceed.
// Not producing a GPR sequence for the RHS is only a problem if this isn't
// a bitwise negation operation.
if (!LHS || (!RHS && !IsBitwiseNegation))
return SDValue();
NumLogicOpsOnComparison++;
// We will use the inputs as 64-bit values.
if (LHS.getValueType() == MVT::i32)
LHS = addExtOrTrunc(LHS, ExtOrTruncConversion::Ext);
if (!IsBitwiseNegation && RHS.getValueType() == MVT::i32)
RHS = addExtOrTrunc(RHS, ExtOrTruncConversion::Ext);
unsigned NewOpc;
switch (LogicOp.getOpcode()) {
default: llvm_unreachable("Unknown logic operation.");
case ISD::AND: NewOpc = PPC::AND8; break;
case ISD::OR: NewOpc = PPC::OR8; break;
case ISD::XOR: NewOpc = PPC::XOR8; break;
}
if (IsBitwiseNegation) {
RHS = S->getI64Imm(1, dl);
NewOpc = PPC::XORI8;
}
return SDValue(CurDAG->getMachineNode(NewOpc, dl, MVT::i64, LHS, RHS), 0);
}
/// If the value isn't guaranteed to be sign-extended to 64-bits, extend it.
/// Otherwise just reinterpret it as a 64-bit value.
/// Useful when emitting comparison code for 32-bit values without using
/// the compare instruction (which only considers the lower 32-bits).
SDValue IntegerCompareEliminator::signExtendInputIfNeeded(SDValue Input) {
assert(Input.getValueType() == MVT::i32 &&
"Can only sign-extend 32-bit values here.");
unsigned Opc = Input.getOpcode();
// The value was sign extended and then truncated to 32-bits. No need to
// sign extend it again.
if (Opc == ISD::TRUNCATE &&
(Input.getOperand(0).getOpcode() == ISD::AssertSext ||
Input.getOperand(0).getOpcode() == ISD::SIGN_EXTEND))
return addExtOrTrunc(Input, ExtOrTruncConversion::Ext);
LoadSDNode *InputLoad = dyn_cast<LoadSDNode>(Input);
// The input is a sign-extending load. All ppc sign-extending loads
// sign-extend to the full 64-bits.
if (InputLoad && InputLoad->getExtensionType() == ISD::SEXTLOAD)
return addExtOrTrunc(Input, ExtOrTruncConversion::Ext);
ConstantSDNode *InputConst = dyn_cast<ConstantSDNode>(Input);
// We don't sign-extend constants.
if (InputConst)
return addExtOrTrunc(Input, ExtOrTruncConversion::Ext);
SDLoc dl(Input);
SignExtensionsAdded++;
return SDValue(CurDAG->getMachineNode(PPC::EXTSW_32_64, dl,
MVT::i64, Input), 0);
}
/// If the value isn't guaranteed to be zero-extended to 64-bits, extend it.
/// Otherwise just reinterpret it as a 64-bit value.
/// Useful when emitting comparison code for 32-bit values without using
/// the compare instruction (which only considers the lower 32-bits).
SDValue IntegerCompareEliminator::zeroExtendInputIfNeeded(SDValue Input) {
assert(Input.getValueType() == MVT::i32 &&
"Can only zero-extend 32-bit values here.");
unsigned Opc = Input.getOpcode();
// The only condition under which we can omit the actual extend instruction:
// - The value is a positive constant
// - The value comes from a load that isn't a sign-extending load
// An ISD::TRUNCATE needs to be zero-extended unless it is fed by a zext.
bool IsTruncateOfZExt = Opc == ISD::TRUNCATE &&
(Input.getOperand(0).getOpcode() == ISD::AssertZext ||
Input.getOperand(0).getOpcode() == ISD::ZERO_EXTEND);
if (IsTruncateOfZExt)
return addExtOrTrunc(Input, ExtOrTruncConversion::Ext);
ConstantSDNode *InputConst = dyn_cast<ConstantSDNode>(Input);
if (InputConst && InputConst->getSExtValue() >= 0)
return addExtOrTrunc(Input, ExtOrTruncConversion::Ext);
LoadSDNode *InputLoad = dyn_cast<LoadSDNode>(Input);
// The input is a load that doesn't sign-extend (it will be zero-extended).
if (InputLoad && InputLoad->getExtensionType() != ISD::SEXTLOAD)
return addExtOrTrunc(Input, ExtOrTruncConversion::Ext);
// None of the above, need to zero-extend.
SDLoc dl(Input);
ZeroExtensionsAdded++;
return SDValue(CurDAG->getMachineNode(PPC::RLDICL_32_64, dl, MVT::i64, Input,
S->getI64Imm(0, dl),
S->getI64Imm(32, dl)), 0);
}
// Handle a 32-bit value in a 64-bit register and vice-versa. These are of
// course not actual zero/sign extensions that will generate machine code,
// they're just a way to reinterpret a 32 bit value in a register as a
// 64 bit value and vice-versa.
SDValue IntegerCompareEliminator::addExtOrTrunc(SDValue NatWidthRes,
ExtOrTruncConversion Conv) {
SDLoc dl(NatWidthRes);
// For reinterpreting 32-bit values as 64 bit values, we generate
// INSERT_SUBREG IMPLICIT_DEF:i64, <input>, TargetConstant:i32<1>
if (Conv == ExtOrTruncConversion::Ext) {
SDValue ImDef(CurDAG->getMachineNode(PPC::IMPLICIT_DEF, dl, MVT::i64), 0);
SDValue SubRegIdx =
CurDAG->getTargetConstant(PPC::sub_32, dl, MVT::i32);
return SDValue(CurDAG->getMachineNode(PPC::INSERT_SUBREG, dl, MVT::i64,
ImDef, NatWidthRes, SubRegIdx), 0);
}
assert(Conv == ExtOrTruncConversion::Trunc &&
"Unknown convertion between 32 and 64 bit values.");
// For reinterpreting 64-bit values as 32-bit values, we just need to
// EXTRACT_SUBREG (i.e. extract the low word).
SDValue SubRegIdx =
CurDAG->getTargetConstant(PPC::sub_32, dl, MVT::i32);
return SDValue(CurDAG->getMachineNode(PPC::EXTRACT_SUBREG, dl, MVT::i32,
NatWidthRes, SubRegIdx), 0);
}
// Produce a GPR sequence for compound comparisons (<=, >=) against zero.
// Handle both zero-extensions and sign-extensions.
SDValue
IntegerCompareEliminator::getCompoundZeroComparisonInGPR(SDValue LHS, SDLoc dl,
ZeroCompare CmpTy) {
EVT InVT = LHS.getValueType();
bool Is32Bit = InVT == MVT::i32;
SDValue ToExtend;
// Produce the value that needs to be either zero or sign extended.
switch (CmpTy) {
case ZeroCompare::GEZExt:
case ZeroCompare::GESExt:
ToExtend = SDValue(CurDAG->getMachineNode(Is32Bit ? PPC::NOR : PPC::NOR8,
dl, InVT, LHS, LHS), 0);
break;
case ZeroCompare::LEZExt:
case ZeroCompare::LESExt: {
if (Is32Bit) {
// Upper 32 bits cannot be undefined for this sequence.
LHS = signExtendInputIfNeeded(LHS);
SDValue Neg =
SDValue(CurDAG->getMachineNode(PPC::NEG8, dl, MVT::i64, LHS), 0);
ToExtend =
SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64,
Neg, S->getI64Imm(1, dl),
S->getI64Imm(63, dl)), 0);
} else {
SDValue Addi =
SDValue(CurDAG->getMachineNode(PPC::ADDI8, dl, MVT::i64, LHS,
S->getI64Imm(~0ULL, dl)), 0);
ToExtend = SDValue(CurDAG->getMachineNode(PPC::OR8, dl, MVT::i64,
Addi, LHS), 0);
}
break;
}
}
// For 64-bit sequences, the extensions are the same for the GE/LE cases.
if (!Is32Bit &&
(CmpTy == ZeroCompare::GEZExt || CmpTy == ZeroCompare::LEZExt))
return SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64,
ToExtend, S->getI64Imm(1, dl),
S->getI64Imm(63, dl)), 0);
if (!Is32Bit &&
(CmpTy == ZeroCompare::GESExt || CmpTy == ZeroCompare::LESExt))
return SDValue(CurDAG->getMachineNode(PPC::SRADI, dl, MVT::i64, ToExtend,
S->getI64Imm(63, dl)), 0);
assert(Is32Bit && "Should have handled the 32-bit sequences above.");
// For 32-bit sequences, the extensions differ between GE/LE cases.
switch (CmpTy) {
case ZeroCompare::GEZExt: {
SDValue ShiftOps[] = { ToExtend, S->getI32Imm(1, dl), S->getI32Imm(31, dl),
S->getI32Imm(31, dl) };
return SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32,
ShiftOps), 0);
}
case ZeroCompare::GESExt:
return SDValue(CurDAG->getMachineNode(PPC::SRAWI, dl, MVT::i32, ToExtend,
S->getI32Imm(31, dl)), 0);
case ZeroCompare::LEZExt:
return SDValue(CurDAG->getMachineNode(PPC::XORI8, dl, MVT::i64, ToExtend,
S->getI32Imm(1, dl)), 0);
case ZeroCompare::LESExt:
return SDValue(CurDAG->getMachineNode(PPC::ADDI8, dl, MVT::i64, ToExtend,
S->getI32Imm(-1, dl)), 0);
}
// The above case covers all the enumerators so it can't have a default clause
// to avoid compiler warnings.
llvm_unreachable("Unknown zero-comparison type.");
}
/// Produces a zero-extended result of comparing two 32-bit values according to
/// the passed condition code.
SDValue
IntegerCompareEliminator::get32BitZExtCompare(SDValue LHS, SDValue RHS,
ISD::CondCode CC,
int64_t RHSValue, SDLoc dl) {
if (CmpInGPR == ICGPR_I64 || CmpInGPR == ICGPR_SextI64 ||
CmpInGPR == ICGPR_ZextI64 || CmpInGPR == ICGPR_Sext)
return SDValue();
bool IsRHSZero = RHSValue == 0;
bool IsRHSOne = RHSValue == 1;
bool IsRHSNegOne = RHSValue == -1LL;
switch (CC) {
default: return SDValue();
case ISD::SETEQ: {
// (zext (setcc %a, %b, seteq)) -> (lshr (cntlzw (xor %a, %b)), 5)
// (zext (setcc %a, 0, seteq)) -> (lshr (cntlzw %a), 5)
SDValue Xor = IsRHSZero ? LHS :
SDValue(CurDAG->getMachineNode(PPC::XOR, dl, MVT::i32, LHS, RHS), 0);
SDValue Clz =
SDValue(CurDAG->getMachineNode(PPC::CNTLZW, dl, MVT::i32, Xor), 0);
SDValue ShiftOps[] = { Clz, S->getI32Imm(27, dl), S->getI32Imm(5, dl),
S->getI32Imm(31, dl) };
return SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32,
ShiftOps), 0);
}
case ISD::SETNE: {
// (zext (setcc %a, %b, setne)) -> (xor (lshr (cntlzw (xor %a, %b)), 5), 1)
// (zext (setcc %a, 0, setne)) -> (xor (lshr (cntlzw %a), 5), 1)
SDValue Xor = IsRHSZero ? LHS :
SDValue(CurDAG->getMachineNode(PPC::XOR, dl, MVT::i32, LHS, RHS), 0);
SDValue Clz =
SDValue(CurDAG->getMachineNode(PPC::CNTLZW, dl, MVT::i32, Xor), 0);
SDValue ShiftOps[] = { Clz, S->getI32Imm(27, dl), S->getI32Imm(5, dl),
S->getI32Imm(31, dl) };
SDValue Shift =
SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, ShiftOps), 0);
return SDValue(CurDAG->getMachineNode(PPC::XORI, dl, MVT::i32, Shift,
S->getI32Imm(1, dl)), 0);
}
case ISD::SETGE: {
// (zext (setcc %a, %b, setge)) -> (xor (lshr (sub %a, %b), 63), 1)
// (zext (setcc %a, 0, setge)) -> (lshr (~ %a), 31)
if(IsRHSZero)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::GEZExt);
// Not a special case (i.e. RHS == 0). Handle (%a >= %b) as (%b <= %a)
// by swapping inputs and falling through.
std::swap(LHS, RHS);
ConstantSDNode *RHSConst = dyn_cast<ConstantSDNode>(RHS);
IsRHSZero = RHSConst && RHSConst->isNullValue();
LLVM_FALLTHROUGH;
}
case ISD::SETLE: {
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
// (zext (setcc %a, %b, setle)) -> (xor (lshr (sub %b, %a), 63), 1)
// (zext (setcc %a, 0, setle)) -> (xor (lshr (- %a), 63), 1)
if(IsRHSZero) {
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::LEZExt);
}
// The upper 32-bits of the register can't be undefined for this sequence.
LHS = signExtendInputIfNeeded(LHS);
RHS = signExtendInputIfNeeded(RHS);
SDValue Sub =
SDValue(CurDAG->getMachineNode(PPC::SUBF8, dl, MVT::i64, LHS, RHS), 0);
SDValue Shift =
SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, Sub,
S->getI64Imm(1, dl), S->getI64Imm(63, dl)),
0);
return
SDValue(CurDAG->getMachineNode(PPC::XORI8, dl,
MVT::i64, Shift, S->getI32Imm(1, dl)), 0);
}
case ISD::SETGT: {
// (zext (setcc %a, %b, setgt)) -> (lshr (sub %b, %a), 63)
// (zext (setcc %a, -1, setgt)) -> (lshr (~ %a), 31)
// (zext (setcc %a, 0, setgt)) -> (lshr (- %a), 63)
// Handle SETLT -1 (which is equivalent to SETGE 0).
if (IsRHSNegOne)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::GEZExt);
if (IsRHSZero) {
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
// The upper 32-bits of the register can't be undefined for this sequence.
LHS = signExtendInputIfNeeded(LHS);
RHS = signExtendInputIfNeeded(RHS);
SDValue Neg =
SDValue(CurDAG->getMachineNode(PPC::NEG8, dl, MVT::i64, LHS), 0);
return SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64,
Neg, S->getI32Imm(1, dl), S->getI32Imm(63, dl)), 0);
}
// Not a special case (i.e. RHS == 0 or RHS == -1). Handle (%a > %b) as
// (%b < %a) by swapping inputs and falling through.
std::swap(LHS, RHS);
ConstantSDNode *RHSConst = dyn_cast<ConstantSDNode>(RHS);
IsRHSZero = RHSConst && RHSConst->isNullValue();
IsRHSOne = RHSConst && RHSConst->getSExtValue() == 1;
LLVM_FALLTHROUGH;
}
case ISD::SETLT: {
// (zext (setcc %a, %b, setlt)) -> (lshr (sub %a, %b), 63)
// (zext (setcc %a, 1, setlt)) -> (xor (lshr (- %a), 63), 1)
// (zext (setcc %a, 0, setlt)) -> (lshr %a, 31)
// Handle SETLT 1 (which is equivalent to SETLE 0).
if (IsRHSOne) {
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::LEZExt);
}
if (IsRHSZero) {
SDValue ShiftOps[] = { LHS, S->getI32Imm(1, dl), S->getI32Imm(31, dl),
S->getI32Imm(31, dl) };
return SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32,
ShiftOps), 0);
}
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
// The upper 32-bits of the register can't be undefined for this sequence.
LHS = signExtendInputIfNeeded(LHS);
RHS = signExtendInputIfNeeded(RHS);
SDValue SUBFNode =
SDValue(CurDAG->getMachineNode(PPC::SUBF8, dl, MVT::i64, RHS, LHS), 0);
return SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64,
SUBFNode, S->getI64Imm(1, dl),
S->getI64Imm(63, dl)), 0);
}
case ISD::SETUGE:
// (zext (setcc %a, %b, setuge)) -> (xor (lshr (sub %b, %a), 63), 1)
// (zext (setcc %a, %b, setule)) -> (xor (lshr (sub %a, %b), 63), 1)
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ISD::SETULE: {
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
// The upper 32-bits of the register can't be undefined for this sequence.
LHS = zeroExtendInputIfNeeded(LHS);
RHS = zeroExtendInputIfNeeded(RHS);
SDValue Subtract =
SDValue(CurDAG->getMachineNode(PPC::SUBF8, dl, MVT::i64, LHS, RHS), 0);
SDValue SrdiNode =
SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64,
Subtract, S->getI64Imm(1, dl),
S->getI64Imm(63, dl)), 0);
return SDValue(CurDAG->getMachineNode(PPC::XORI8, dl, MVT::i64, SrdiNode,
S->getI32Imm(1, dl)), 0);
}
case ISD::SETUGT:
// (zext (setcc %a, %b, setugt)) -> (lshr (sub %b, %a), 63)
// (zext (setcc %a, %b, setult)) -> (lshr (sub %a, %b), 63)
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ISD::SETULT: {
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
// The upper 32-bits of the register can't be undefined for this sequence.
LHS = zeroExtendInputIfNeeded(LHS);
RHS = zeroExtendInputIfNeeded(RHS);
SDValue Subtract =
SDValue(CurDAG->getMachineNode(PPC::SUBF8, dl, MVT::i64, RHS, LHS), 0);
return SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64,
Subtract, S->getI64Imm(1, dl),
S->getI64Imm(63, dl)), 0);
}
}
}
/// Produces a sign-extended result of comparing two 32-bit values according to
/// the passed condition code.
SDValue
IntegerCompareEliminator::get32BitSExtCompare(SDValue LHS, SDValue RHS,
ISD::CondCode CC,
int64_t RHSValue, SDLoc dl) {
if (CmpInGPR == ICGPR_I64 || CmpInGPR == ICGPR_SextI64 ||
CmpInGPR == ICGPR_ZextI64 || CmpInGPR == ICGPR_Zext)
return SDValue();
bool IsRHSZero = RHSValue == 0;
bool IsRHSOne = RHSValue == 1;
bool IsRHSNegOne = RHSValue == -1LL;
switch (CC) {
default: return SDValue();
case ISD::SETEQ: {
// (sext (setcc %a, %b, seteq)) ->
// (ashr (shl (ctlz (xor %a, %b)), 58), 63)
// (sext (setcc %a, 0, seteq)) ->
// (ashr (shl (ctlz %a), 58), 63)
SDValue CountInput = IsRHSZero ? LHS :
SDValue(CurDAG->getMachineNode(PPC::XOR, dl, MVT::i32, LHS, RHS), 0);
SDValue Cntlzw =
SDValue(CurDAG->getMachineNode(PPC::CNTLZW, dl, MVT::i32, CountInput), 0);
SDValue SHLOps[] = { Cntlzw, S->getI32Imm(27, dl),
S->getI32Imm(5, dl), S->getI32Imm(31, dl) };
SDValue Slwi =
SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, SHLOps), 0);
return SDValue(CurDAG->getMachineNode(PPC::NEG, dl, MVT::i32, Slwi), 0);
}
case ISD::SETNE: {
// Bitwise xor the operands, count leading zeros, shift right by 5 bits and
// flip the bit, finally take 2's complement.
// (sext (setcc %a, %b, setne)) ->
// (neg (xor (lshr (ctlz (xor %a, %b)), 5), 1))
// Same as above, but the first xor is not needed.
// (sext (setcc %a, 0, setne)) ->
// (neg (xor (lshr (ctlz %a), 5), 1))
SDValue Xor = IsRHSZero ? LHS :
SDValue(CurDAG->getMachineNode(PPC::XOR, dl, MVT::i32, LHS, RHS), 0);
SDValue Clz =
SDValue(CurDAG->getMachineNode(PPC::CNTLZW, dl, MVT::i32, Xor), 0);
SDValue ShiftOps[] =
{ Clz, S->getI32Imm(27, dl), S->getI32Imm(5, dl), S->getI32Imm(31, dl) };
SDValue Shift =
SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, ShiftOps), 0);
SDValue Xori =
SDValue(CurDAG->getMachineNode(PPC::XORI, dl, MVT::i32, Shift,
S->getI32Imm(1, dl)), 0);
return SDValue(CurDAG->getMachineNode(PPC::NEG, dl, MVT::i32, Xori), 0);
}
case ISD::SETGE: {
// (sext (setcc %a, %b, setge)) -> (add (lshr (sub %a, %b), 63), -1)
// (sext (setcc %a, 0, setge)) -> (ashr (~ %a), 31)
if (IsRHSZero)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::GESExt);
// Not a special case (i.e. RHS == 0). Handle (%a >= %b) as (%b <= %a)
// by swapping inputs and falling through.
std::swap(LHS, RHS);
ConstantSDNode *RHSConst = dyn_cast<ConstantSDNode>(RHS);
IsRHSZero = RHSConst && RHSConst->isNullValue();
LLVM_FALLTHROUGH;
}
case ISD::SETLE: {
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
// (sext (setcc %a, %b, setge)) -> (add (lshr (sub %b, %a), 63), -1)
// (sext (setcc %a, 0, setle)) -> (add (lshr (- %a), 63), -1)
if (IsRHSZero)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::LESExt);
// The upper 32-bits of the register can't be undefined for this sequence.
LHS = signExtendInputIfNeeded(LHS);
RHS = signExtendInputIfNeeded(RHS);
SDValue SUBFNode =
SDValue(CurDAG->getMachineNode(PPC::SUBF8, dl, MVT::i64, MVT::Glue,
LHS, RHS), 0);
SDValue Srdi =
SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64,
SUBFNode, S->getI64Imm(1, dl),
S->getI64Imm(63, dl)), 0);
return SDValue(CurDAG->getMachineNode(PPC::ADDI8, dl, MVT::i64, Srdi,
S->getI32Imm(-1, dl)), 0);
}
case ISD::SETGT: {
// (sext (setcc %a, %b, setgt)) -> (ashr (sub %b, %a), 63)
// (sext (setcc %a, -1, setgt)) -> (ashr (~ %a), 31)
// (sext (setcc %a, 0, setgt)) -> (ashr (- %a), 63)
if (IsRHSNegOne)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::GESExt);
if (IsRHSZero) {
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
// The upper 32-bits of the register can't be undefined for this sequence.
LHS = signExtendInputIfNeeded(LHS);
RHS = signExtendInputIfNeeded(RHS);
SDValue Neg =
SDValue(CurDAG->getMachineNode(PPC::NEG8, dl, MVT::i64, LHS), 0);
return SDValue(CurDAG->getMachineNode(PPC::SRADI, dl, MVT::i64, Neg,
S->getI64Imm(63, dl)), 0);
}
// Not a special case (i.e. RHS == 0 or RHS == -1). Handle (%a > %b) as
// (%b < %a) by swapping inputs and falling through.
std::swap(LHS, RHS);
ConstantSDNode *RHSConst = dyn_cast<ConstantSDNode>(RHS);
IsRHSZero = RHSConst && RHSConst->isNullValue();
IsRHSOne = RHSConst && RHSConst->getSExtValue() == 1;
LLVM_FALLTHROUGH;
}
case ISD::SETLT: {
// (sext (setcc %a, %b, setgt)) -> (ashr (sub %a, %b), 63)
// (sext (setcc %a, 1, setgt)) -> (add (lshr (- %a), 63), -1)
// (sext (setcc %a, 0, setgt)) -> (ashr %a, 31)
if (IsRHSOne) {
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::LESExt);
}
if (IsRHSZero)
return SDValue(CurDAG->getMachineNode(PPC::SRAWI, dl, MVT::i32, LHS,
S->getI32Imm(31, dl)), 0);
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
// The upper 32-bits of the register can't be undefined for this sequence.
LHS = signExtendInputIfNeeded(LHS);
RHS = signExtendInputIfNeeded(RHS);
SDValue SUBFNode =
SDValue(CurDAG->getMachineNode(PPC::SUBF8, dl, MVT::i64, RHS, LHS), 0);
return SDValue(CurDAG->getMachineNode(PPC::SRADI, dl, MVT::i64,
SUBFNode, S->getI64Imm(63, dl)), 0);
}
case ISD::SETUGE:
// (sext (setcc %a, %b, setuge)) -> (add (lshr (sub %a, %b), 63), -1)
// (sext (setcc %a, %b, setule)) -> (add (lshr (sub %b, %a), 63), -1)
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ISD::SETULE: {
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
// The upper 32-bits of the register can't be undefined for this sequence.
LHS = zeroExtendInputIfNeeded(LHS);
RHS = zeroExtendInputIfNeeded(RHS);
SDValue Subtract =
SDValue(CurDAG->getMachineNode(PPC::SUBF8, dl, MVT::i64, LHS, RHS), 0);
SDValue Shift =
SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, Subtract,
S->getI32Imm(1, dl), S->getI32Imm(63,dl)),
0);
return SDValue(CurDAG->getMachineNode(PPC::ADDI8, dl, MVT::i64, Shift,
S->getI32Imm(-1, dl)), 0);
}
case ISD::SETUGT:
// (sext (setcc %a, %b, setugt)) -> (ashr (sub %b, %a), 63)
// (sext (setcc %a, %b, setugt)) -> (ashr (sub %a, %b), 63)
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ISD::SETULT: {
if (CmpInGPR == ICGPR_NonExtIn)
return SDValue();
// The upper 32-bits of the register can't be undefined for this sequence.
LHS = zeroExtendInputIfNeeded(LHS);
RHS = zeroExtendInputIfNeeded(RHS);
SDValue Subtract =
SDValue(CurDAG->getMachineNode(PPC::SUBF8, dl, MVT::i64, RHS, LHS), 0);
return SDValue(CurDAG->getMachineNode(PPC::SRADI, dl, MVT::i64,
Subtract, S->getI64Imm(63, dl)), 0);
}
}
}
/// Produces a zero-extended result of comparing two 64-bit values according to
/// the passed condition code.
SDValue
IntegerCompareEliminator::get64BitZExtCompare(SDValue LHS, SDValue RHS,
ISD::CondCode CC,
int64_t RHSValue, SDLoc dl) {
if (CmpInGPR == ICGPR_I32 || CmpInGPR == ICGPR_SextI32 ||
CmpInGPR == ICGPR_ZextI32 || CmpInGPR == ICGPR_Sext)
return SDValue();
bool IsRHSZero = RHSValue == 0;
bool IsRHSOne = RHSValue == 1;
bool IsRHSNegOne = RHSValue == -1LL;
switch (CC) {
default: return SDValue();
case ISD::SETEQ: {
// (zext (setcc %a, %b, seteq)) -> (lshr (ctlz (xor %a, %b)), 6)
// (zext (setcc %a, 0, seteq)) -> (lshr (ctlz %a), 6)
SDValue Xor = IsRHSZero ? LHS :
SDValue(CurDAG->getMachineNode(PPC::XOR8, dl, MVT::i64, LHS, RHS), 0);
SDValue Clz =
SDValue(CurDAG->getMachineNode(PPC::CNTLZD, dl, MVT::i64, Xor), 0);
return SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, Clz,
S->getI64Imm(58, dl),
S->getI64Imm(63, dl)), 0);
}
case ISD::SETNE: {
// {addc.reg, addc.CA} = (addcarry (xor %a, %b), -1)
// (zext (setcc %a, %b, setne)) -> (sube addc.reg, addc.reg, addc.CA)
// {addcz.reg, addcz.CA} = (addcarry %a, -1)
// (zext (setcc %a, 0, setne)) -> (sube addcz.reg, addcz.reg, addcz.CA)
SDValue Xor = IsRHSZero ? LHS :
SDValue(CurDAG->getMachineNode(PPC::XOR8, dl, MVT::i64, LHS, RHS), 0);
SDValue AC =
SDValue(CurDAG->getMachineNode(PPC::ADDIC8, dl, MVT::i64, MVT::Glue,
Xor, S->getI32Imm(~0U, dl)), 0);
return SDValue(CurDAG->getMachineNode(PPC::SUBFE8, dl, MVT::i64, AC,
Xor, AC.getValue(1)), 0);
}
case ISD::SETGE: {
// {subc.reg, subc.CA} = (subcarry %a, %b)
// (zext (setcc %a, %b, setge)) ->
// (adde (lshr %b, 63), (ashr %a, 63), subc.CA)
// (zext (setcc %a, 0, setge)) -> (lshr (~ %a), 63)
if (IsRHSZero)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::GEZExt);
std::swap(LHS, RHS);
ConstantSDNode *RHSConst = dyn_cast<ConstantSDNode>(RHS);
IsRHSZero = RHSConst && RHSConst->isNullValue();
LLVM_FALLTHROUGH;
}
case ISD::SETLE: {
// {subc.reg, subc.CA} = (subcarry %b, %a)
// (zext (setcc %a, %b, setge)) ->
// (adde (lshr %a, 63), (ashr %b, 63), subc.CA)
// (zext (setcc %a, 0, setge)) -> (lshr (or %a, (add %a, -1)), 63)
if (IsRHSZero)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::LEZExt);
SDValue ShiftL =
SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, LHS,
S->getI64Imm(1, dl),
S->getI64Imm(63, dl)), 0);
SDValue ShiftR =
SDValue(CurDAG->getMachineNode(PPC::SRADI, dl, MVT::i64, RHS,
S->getI64Imm(63, dl)), 0);
SDValue SubtractCarry =
SDValue(CurDAG->getMachineNode(PPC::SUBFC8, dl, MVT::i64, MVT::Glue,
LHS, RHS), 1);
return SDValue(CurDAG->getMachineNode(PPC::ADDE8, dl, MVT::i64, MVT::Glue,
ShiftR, ShiftL, SubtractCarry), 0);
}
case ISD::SETGT: {
// {subc.reg, subc.CA} = (subcarry %b, %a)
// (zext (setcc %a, %b, setgt)) ->
// (xor (adde (lshr %a, 63), (ashr %b, 63), subc.CA), 1)
// (zext (setcc %a, 0, setgt)) -> (lshr (nor (add %a, -1), %a), 63)
if (IsRHSNegOne)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::GEZExt);
if (IsRHSZero) {
SDValue Addi =
SDValue(CurDAG->getMachineNode(PPC::ADDI8, dl, MVT::i64, LHS,
S->getI64Imm(~0ULL, dl)), 0);
SDValue Nor =
SDValue(CurDAG->getMachineNode(PPC::NOR8, dl, MVT::i64, Addi, LHS), 0);
return SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, Nor,
S->getI64Imm(1, dl),
S->getI64Imm(63, dl)), 0);
}
std::swap(LHS, RHS);
ConstantSDNode *RHSConst = dyn_cast<ConstantSDNode>(RHS);
IsRHSZero = RHSConst && RHSConst->isNullValue();
IsRHSOne = RHSConst && RHSConst->getSExtValue() == 1;
LLVM_FALLTHROUGH;
}
case ISD::SETLT: {
// {subc.reg, subc.CA} = (subcarry %a, %b)
// (zext (setcc %a, %b, setlt)) ->
// (xor (adde (lshr %b, 63), (ashr %a, 63), subc.CA), 1)
// (zext (setcc %a, 0, setlt)) -> (lshr %a, 63)
if (IsRHSOne)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::LEZExt);
if (IsRHSZero)
return SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, LHS,
S->getI64Imm(1, dl),
S->getI64Imm(63, dl)), 0);
SDValue SRADINode =
SDValue(CurDAG->getMachineNode(PPC::SRADI, dl, MVT::i64,
LHS, S->getI64Imm(63, dl)), 0);
SDValue SRDINode =
SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64,
RHS, S->getI64Imm(1, dl),
S->getI64Imm(63, dl)), 0);
SDValue SUBFC8Carry =
SDValue(CurDAG->getMachineNode(PPC::SUBFC8, dl, MVT::i64, MVT::Glue,
RHS, LHS), 1);
SDValue ADDE8Node =
SDValue(CurDAG->getMachineNode(PPC::ADDE8, dl, MVT::i64, MVT::Glue,
SRDINode, SRADINode, SUBFC8Carry), 0);
return SDValue(CurDAG->getMachineNode(PPC::XORI8, dl, MVT::i64,
ADDE8Node, S->getI64Imm(1, dl)), 0);
}
case ISD::SETUGE:
// {subc.reg, subc.CA} = (subcarry %a, %b)
// (zext (setcc %a, %b, setuge)) -> (add (sube %b, %b, subc.CA), 1)
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ISD::SETULE: {
// {subc.reg, subc.CA} = (subcarry %b, %a)
// (zext (setcc %a, %b, setule)) -> (add (sube %a, %a, subc.CA), 1)
SDValue SUBFC8Carry =
SDValue(CurDAG->getMachineNode(PPC::SUBFC8, dl, MVT::i64, MVT::Glue,
LHS, RHS), 1);
SDValue SUBFE8Node =
SDValue(CurDAG->getMachineNode(PPC::SUBFE8, dl, MVT::i64, MVT::Glue,
LHS, LHS, SUBFC8Carry), 0);
return SDValue(CurDAG->getMachineNode(PPC::ADDI8, dl, MVT::i64,
SUBFE8Node, S->getI64Imm(1, dl)), 0);
}
case ISD::SETUGT:
// {subc.reg, subc.CA} = (subcarry %b, %a)
// (zext (setcc %a, %b, setugt)) -> -(sube %b, %b, subc.CA)
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ISD::SETULT: {
// {subc.reg, subc.CA} = (subcarry %a, %b)
// (zext (setcc %a, %b, setult)) -> -(sube %a, %a, subc.CA)
SDValue SubtractCarry =
SDValue(CurDAG->getMachineNode(PPC::SUBFC8, dl, MVT::i64, MVT::Glue,
RHS, LHS), 1);
SDValue ExtSub =
SDValue(CurDAG->getMachineNode(PPC::SUBFE8, dl, MVT::i64,
LHS, LHS, SubtractCarry), 0);
return SDValue(CurDAG->getMachineNode(PPC::NEG8, dl, MVT::i64,
ExtSub), 0);
}
}
}
/// Produces a sign-extended result of comparing two 64-bit values according to
/// the passed condition code.
SDValue
IntegerCompareEliminator::get64BitSExtCompare(SDValue LHS, SDValue RHS,
ISD::CondCode CC,
int64_t RHSValue, SDLoc dl) {
if (CmpInGPR == ICGPR_I32 || CmpInGPR == ICGPR_SextI32 ||
CmpInGPR == ICGPR_ZextI32 || CmpInGPR == ICGPR_Zext)
return SDValue();
bool IsRHSZero = RHSValue == 0;
bool IsRHSOne = RHSValue == 1;
bool IsRHSNegOne = RHSValue == -1LL;
switch (CC) {
default: return SDValue();
case ISD::SETEQ: {
// {addc.reg, addc.CA} = (addcarry (xor %a, %b), -1)
// (sext (setcc %a, %b, seteq)) -> (sube addc.reg, addc.reg, addc.CA)
// {addcz.reg, addcz.CA} = (addcarry %a, -1)
// (sext (setcc %a, 0, seteq)) -> (sube addcz.reg, addcz.reg, addcz.CA)
SDValue AddInput = IsRHSZero ? LHS :
SDValue(CurDAG->getMachineNode(PPC::XOR8, dl, MVT::i64, LHS, RHS), 0);
SDValue Addic =
SDValue(CurDAG->getMachineNode(PPC::ADDIC8, dl, MVT::i64, MVT::Glue,
AddInput, S->getI32Imm(~0U, dl)), 0);
return SDValue(CurDAG->getMachineNode(PPC::SUBFE8, dl, MVT::i64, Addic,
Addic, Addic.getValue(1)), 0);
}
case ISD::SETNE: {
// {subfc.reg, subfc.CA} = (subcarry 0, (xor %a, %b))
// (sext (setcc %a, %b, setne)) -> (sube subfc.reg, subfc.reg, subfc.CA)
// {subfcz.reg, subfcz.CA} = (subcarry 0, %a)
// (sext (setcc %a, 0, setne)) -> (sube subfcz.reg, subfcz.reg, subfcz.CA)
SDValue Xor = IsRHSZero ? LHS :
SDValue(CurDAG->getMachineNode(PPC::XOR8, dl, MVT::i64, LHS, RHS), 0);
SDValue SC =
SDValue(CurDAG->getMachineNode(PPC::SUBFIC8, dl, MVT::i64, MVT::Glue,
Xor, S->getI32Imm(0, dl)), 0);
return SDValue(CurDAG->getMachineNode(PPC::SUBFE8, dl, MVT::i64, SC,
SC, SC.getValue(1)), 0);
}
case ISD::SETGE: {
// {subc.reg, subc.CA} = (subcarry %a, %b)
// (zext (setcc %a, %b, setge)) ->
// (- (adde (lshr %b, 63), (ashr %a, 63), subc.CA))
// (zext (setcc %a, 0, setge)) -> (~ (ashr %a, 63))
if (IsRHSZero)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::GESExt);
std::swap(LHS, RHS);
ConstantSDNode *RHSConst = dyn_cast<ConstantSDNode>(RHS);
IsRHSZero = RHSConst && RHSConst->isNullValue();
LLVM_FALLTHROUGH;
}
case ISD::SETLE: {
// {subc.reg, subc.CA} = (subcarry %b, %a)
// (zext (setcc %a, %b, setge)) ->
// (- (adde (lshr %a, 63), (ashr %b, 63), subc.CA))
// (zext (setcc %a, 0, setge)) -> (ashr (or %a, (add %a, -1)), 63)
if (IsRHSZero)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::LESExt);
SDValue ShiftR =
SDValue(CurDAG->getMachineNode(PPC::SRADI, dl, MVT::i64, RHS,
S->getI64Imm(63, dl)), 0);
SDValue ShiftL =
SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, LHS,
S->getI64Imm(1, dl),
S->getI64Imm(63, dl)), 0);
SDValue SubtractCarry =
SDValue(CurDAG->getMachineNode(PPC::SUBFC8, dl, MVT::i64, MVT::Glue,
LHS, RHS), 1);
SDValue Adde =
SDValue(CurDAG->getMachineNode(PPC::ADDE8, dl, MVT::i64, MVT::Glue,
ShiftR, ShiftL, SubtractCarry), 0);
return SDValue(CurDAG->getMachineNode(PPC::NEG8, dl, MVT::i64, Adde), 0);
}
case ISD::SETGT: {
// {subc.reg, subc.CA} = (subcarry %b, %a)
// (zext (setcc %a, %b, setgt)) ->
// -(xor (adde (lshr %a, 63), (ashr %b, 63), subc.CA), 1)
// (zext (setcc %a, 0, setgt)) -> (ashr (nor (add %a, -1), %a), 63)
if (IsRHSNegOne)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::GESExt);
if (IsRHSZero) {
SDValue Add =
SDValue(CurDAG->getMachineNode(PPC::ADDI8, dl, MVT::i64, LHS,
S->getI64Imm(-1, dl)), 0);
SDValue Nor =
SDValue(CurDAG->getMachineNode(PPC::NOR8, dl, MVT::i64, Add, LHS), 0);
return SDValue(CurDAG->getMachineNode(PPC::SRADI, dl, MVT::i64, Nor,
S->getI64Imm(63, dl)), 0);
}
std::swap(LHS, RHS);
ConstantSDNode *RHSConst = dyn_cast<ConstantSDNode>(RHS);
IsRHSZero = RHSConst && RHSConst->isNullValue();
IsRHSOne = RHSConst && RHSConst->getSExtValue() == 1;
LLVM_FALLTHROUGH;
}
case ISD::SETLT: {
// {subc.reg, subc.CA} = (subcarry %a, %b)
// (zext (setcc %a, %b, setlt)) ->
// -(xor (adde (lshr %b, 63), (ashr %a, 63), subc.CA), 1)
// (zext (setcc %a, 0, setlt)) -> (ashr %a, 63)
if (IsRHSOne)
return getCompoundZeroComparisonInGPR(LHS, dl, ZeroCompare::LESExt);
if (IsRHSZero) {
return SDValue(CurDAG->getMachineNode(PPC::SRADI, dl, MVT::i64, LHS,
S->getI64Imm(63, dl)), 0);
}
SDValue SRADINode =
SDValue(CurDAG->getMachineNode(PPC::SRADI, dl, MVT::i64,
LHS, S->getI64Imm(63, dl)), 0);
SDValue SRDINode =
SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64,
RHS, S->getI64Imm(1, dl),
S->getI64Imm(63, dl)), 0);
SDValue SUBFC8Carry =
SDValue(CurDAG->getMachineNode(PPC::SUBFC8, dl, MVT::i64, MVT::Glue,
RHS, LHS), 1);
SDValue ADDE8Node =
SDValue(CurDAG->getMachineNode(PPC::ADDE8, dl, MVT::i64,
SRDINode, SRADINode, SUBFC8Carry), 0);
SDValue XORI8Node =
SDValue(CurDAG->getMachineNode(PPC::XORI8, dl, MVT::i64,
ADDE8Node, S->getI64Imm(1, dl)), 0);
return SDValue(CurDAG->getMachineNode(PPC::NEG8, dl, MVT::i64,
XORI8Node), 0);
}
case ISD::SETUGE:
// {subc.reg, subc.CA} = (subcarry %a, %b)
// (sext (setcc %a, %b, setuge)) -> ~(sube %b, %b, subc.CA)
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ISD::SETULE: {
// {subc.reg, subc.CA} = (subcarry %b, %a)
// (sext (setcc %a, %b, setule)) -> ~(sube %a, %a, subc.CA)
SDValue SubtractCarry =
SDValue(CurDAG->getMachineNode(PPC::SUBFC8, dl, MVT::i64, MVT::Glue,
LHS, RHS), 1);
SDValue ExtSub =
SDValue(CurDAG->getMachineNode(PPC::SUBFE8, dl, MVT::i64, MVT::Glue, LHS,
LHS, SubtractCarry), 0);
return SDValue(CurDAG->getMachineNode(PPC::NOR8, dl, MVT::i64,
ExtSub, ExtSub), 0);
}
case ISD::SETUGT:
// {subc.reg, subc.CA} = (subcarry %b, %a)
// (sext (setcc %a, %b, setugt)) -> (sube %b, %b, subc.CA)
std::swap(LHS, RHS);
LLVM_FALLTHROUGH;
case ISD::SETULT: {
// {subc.reg, subc.CA} = (subcarry %a, %b)
// (sext (setcc %a, %b, setult)) -> (sube %a, %a, subc.CA)
SDValue SubCarry =
SDValue(CurDAG->getMachineNode(PPC::SUBFC8, dl, MVT::i64, MVT::Glue,
RHS, LHS), 1);
return SDValue(CurDAG->getMachineNode(PPC::SUBFE8, dl, MVT::i64,
LHS, LHS, SubCarry), 0);
}
}
}
/// Do all uses of this SDValue need the result in a GPR?
/// This is meant to be used on values that have type i1 since
/// it is somewhat meaningless to ask if values of other types
/// should be kept in GPR's.
static bool allUsesExtend(SDValue Compare, SelectionDAG *CurDAG) {
assert(Compare.getOpcode() == ISD::SETCC &&
"An ISD::SETCC node required here.");
// For values that have a single use, the caller should obviously already have
// checked if that use is an extending use. We check the other uses here.
if (Compare.hasOneUse())
return true;
// We want the value in a GPR if it is being extended, used for a select, or
// used in logical operations.
for (auto CompareUse : Compare.getNode()->uses())
if (CompareUse->getOpcode() != ISD::SIGN_EXTEND &&
CompareUse->getOpcode() != ISD::ZERO_EXTEND &&
CompareUse->getOpcode() != ISD::SELECT &&
!isLogicOp(CompareUse->getOpcode())) {
OmittedForNonExtendUses++;
return false;
}
return true;
}
/// Returns an equivalent of a SETCC node but with the result the same width as
/// the inputs. This can also be used for SELECT_CC if either the true or false
/// values is a power of two while the other is zero.
SDValue IntegerCompareEliminator::getSETCCInGPR(SDValue Compare,
SetccInGPROpts ConvOpts) {
assert((Compare.getOpcode() == ISD::SETCC ||
Compare.getOpcode() == ISD::SELECT_CC) &&
"An ISD::SETCC node required here.");
// Don't convert this comparison to a GPR sequence because there are uses
// of the i1 result (i.e. uses that require the result in the CR).
if ((Compare.getOpcode() == ISD::SETCC) && !allUsesExtend(Compare, CurDAG))
return SDValue();
SDValue LHS = Compare.getOperand(0);
SDValue RHS = Compare.getOperand(1);
// The condition code is operand 2 for SETCC and operand 4 for SELECT_CC.
int CCOpNum = Compare.getOpcode() == ISD::SELECT_CC ? 4 : 2;
ISD::CondCode CC =
cast<CondCodeSDNode>(Compare.getOperand(CCOpNum))->get();
EVT InputVT = LHS.getValueType();
if (InputVT != MVT::i32 && InputVT != MVT::i64)
return SDValue();
if (ConvOpts == SetccInGPROpts::ZExtInvert ||
ConvOpts == SetccInGPROpts::SExtInvert)
CC = ISD::getSetCCInverse(CC, true);
bool Inputs32Bit = InputVT == MVT::i32;
SDLoc dl(Compare);
ConstantSDNode *RHSConst = dyn_cast<ConstantSDNode>(RHS);
int64_t RHSValue = RHSConst ? RHSConst->getSExtValue() : INT64_MAX;
bool IsSext = ConvOpts == SetccInGPROpts::SExtOrig ||
ConvOpts == SetccInGPROpts::SExtInvert;
if (IsSext && Inputs32Bit)
return get32BitSExtCompare(LHS, RHS, CC, RHSValue, dl);
else if (Inputs32Bit)
return get32BitZExtCompare(LHS, RHS, CC, RHSValue, dl);
else if (IsSext)
return get64BitSExtCompare(LHS, RHS, CC, RHSValue, dl);
return get64BitZExtCompare(LHS, RHS, CC, RHSValue, dl);
}
} // end anonymous namespace
bool PPCDAGToDAGISel::tryIntCompareInGPR(SDNode *N) {
if (N->getValueType(0) != MVT::i32 &&
N->getValueType(0) != MVT::i64)
return false;
// This optimization will emit code that assumes 64-bit registers
// so we don't want to run it in 32-bit mode. Also don't run it
// on functions that are not to be optimized.
if (TM.getOptLevel() == CodeGenOpt::None || !TM.isPPC64())
return false;
switch (N->getOpcode()) {
default: break;
case ISD::ZERO_EXTEND:
case ISD::SIGN_EXTEND:
case ISD::AND:
case ISD::OR:
case ISD::XOR: {
IntegerCompareEliminator ICmpElim(CurDAG, this);
if (SDNode *New = ICmpElim.Select(N)) {
ReplaceNode(N, New);
return true;
}
}
}
return false;
}
bool PPCDAGToDAGISel::tryBitPermutation(SDNode *N) {
if (N->getValueType(0) != MVT::i32 &&
N->getValueType(0) != MVT::i64)
return false;
if (!UseBitPermRewriter)
return false;
switch (N->getOpcode()) {
default: break;
case ISD::ROTL:
case ISD::SHL:
case ISD::SRL:
case ISD::AND:
case ISD::OR: {
BitPermutationSelector BPS(CurDAG);
if (SDNode *New = BPS.Select(N)) {
ReplaceNode(N, New);
return true;
}
return false;
}
}
return false;
}
/// SelectCC - Select a comparison of the specified values with the specified
/// condition code, returning the CR# of the expression.
SDValue PPCDAGToDAGISel::SelectCC(SDValue LHS, SDValue RHS, ISD::CondCode CC,
const SDLoc &dl) {
// Always select the LHS.
unsigned Opc;
if (LHS.getValueType() == MVT::i32) {
unsigned Imm;
if (CC == ISD::SETEQ || CC == ISD::SETNE) {
if (isInt32Immediate(RHS, Imm)) {
// SETEQ/SETNE comparison with 16-bit immediate, fold it.
if (isUInt<16>(Imm))
return SDValue(CurDAG->getMachineNode(PPC::CMPLWI, dl, MVT::i32, LHS,
getI32Imm(Imm & 0xFFFF, dl)),
0);
// If this is a 16-bit signed immediate, fold it.
if (isInt<16>((int)Imm))
return SDValue(CurDAG->getMachineNode(PPC::CMPWI, dl, MVT::i32, LHS,
getI32Imm(Imm & 0xFFFF, dl)),
0);
// For non-equality comparisons, the default code would materialize the
// constant, then compare against it, like this:
// lis r2, 4660
// ori r2, r2, 22136
// cmpw cr0, r3, r2
// Since we are just comparing for equality, we can emit this instead:
// xoris r0,r3,0x1234
// cmplwi cr0,r0,0x5678
// beq cr0,L6
SDValue Xor(CurDAG->getMachineNode(PPC::XORIS, dl, MVT::i32, LHS,
getI32Imm(Imm >> 16, dl)), 0);
return SDValue(CurDAG->getMachineNode(PPC::CMPLWI, dl, MVT::i32, Xor,
getI32Imm(Imm & 0xFFFF, dl)), 0);
}
Opc = PPC::CMPLW;
} else if (ISD::isUnsignedIntSetCC(CC)) {
if (isInt32Immediate(RHS, Imm) && isUInt<16>(Imm))
return SDValue(CurDAG->getMachineNode(PPC::CMPLWI, dl, MVT::i32, LHS,
getI32Imm(Imm & 0xFFFF, dl)), 0);
Opc = PPC::CMPLW;
} else {
int16_t SImm;
if (isIntS16Immediate(RHS, SImm))
return SDValue(CurDAG->getMachineNode(PPC::CMPWI, dl, MVT::i32, LHS,
getI32Imm((int)SImm & 0xFFFF,
dl)),
0);
Opc = PPC::CMPW;
}
} else if (LHS.getValueType() == MVT::i64) {
uint64_t Imm;
if (CC == ISD::SETEQ || CC == ISD::SETNE) {
if (isInt64Immediate(RHS.getNode(), Imm)) {
// SETEQ/SETNE comparison with 16-bit immediate, fold it.
if (isUInt<16>(Imm))
return SDValue(CurDAG->getMachineNode(PPC::CMPLDI, dl, MVT::i64, LHS,
getI32Imm(Imm & 0xFFFF, dl)),
0);
// If this is a 16-bit signed immediate, fold it.
if (isInt<16>(Imm))
return SDValue(CurDAG->getMachineNode(PPC::CMPDI, dl, MVT::i64, LHS,
getI32Imm(Imm & 0xFFFF, dl)),
0);
// For non-equality comparisons, the default code would materialize the
// constant, then compare against it, like this:
// lis r2, 4660
// ori r2, r2, 22136
// cmpd cr0, r3, r2
// Since we are just comparing for equality, we can emit this instead:
// xoris r0,r3,0x1234
// cmpldi cr0,r0,0x5678
// beq cr0,L6
if (isUInt<32>(Imm)) {
SDValue Xor(CurDAG->getMachineNode(PPC::XORIS8, dl, MVT::i64, LHS,
getI64Imm(Imm >> 16, dl)), 0);
return SDValue(CurDAG->getMachineNode(PPC::CMPLDI, dl, MVT::i64, Xor,
getI64Imm(Imm & 0xFFFF, dl)),
0);
}
}
Opc = PPC::CMPLD;
} else if (ISD::isUnsignedIntSetCC(CC)) {
if (isInt64Immediate(RHS.getNode(), Imm) && isUInt<16>(Imm))
return SDValue(CurDAG->getMachineNode(PPC::CMPLDI, dl, MVT::i64, LHS,
getI64Imm(Imm & 0xFFFF, dl)), 0);
Opc = PPC::CMPLD;
} else {
int16_t SImm;
if (isIntS16Immediate(RHS, SImm))
return SDValue(CurDAG->getMachineNode(PPC::CMPDI, dl, MVT::i64, LHS,
getI64Imm(SImm & 0xFFFF, dl)),
0);
Opc = PPC::CMPD;
}
} else if (LHS.getValueType() == MVT::f32) {
if (PPCSubTarget->hasSPE()) {
switch (CC) {
default:
case ISD::SETEQ:
case ISD::SETNE:
Opc = PPC::EFSCMPEQ;
break;
case ISD::SETLT:
case ISD::SETGE:
case ISD::SETOLT:
case ISD::SETOGE:
case ISD::SETULT:
case ISD::SETUGE:
Opc = PPC::EFSCMPLT;
break;
case ISD::SETGT:
case ISD::SETLE:
case ISD::SETOGT:
case ISD::SETOLE:
case ISD::SETUGT:
case ISD::SETULE:
Opc = PPC::EFSCMPGT;
break;
}
} else
Opc = PPC::FCMPUS;
} else if (LHS.getValueType() == MVT::f64) {
if (PPCSubTarget->hasSPE()) {
switch (CC) {
default:
case ISD::SETEQ:
case ISD::SETNE:
Opc = PPC::EFDCMPEQ;
break;
case ISD::SETLT:
case ISD::SETGE:
case ISD::SETOLT:
case ISD::SETOGE:
case ISD::SETULT:
case ISD::SETUGE:
Opc = PPC::EFDCMPLT;
break;
case ISD::SETGT:
case ISD::SETLE:
case ISD::SETOGT:
case ISD::SETOLE:
case ISD::SETUGT:
case ISD::SETULE:
Opc = PPC::EFDCMPGT;
break;
}
} else
Opc = PPCSubTarget->hasVSX() ? PPC::XSCMPUDP : PPC::FCMPUD;
} else {
assert(LHS.getValueType() == MVT::f128 && "Unknown vt!");
assert(PPCSubTarget->hasVSX() && "__float128 requires VSX");
Opc = PPC::XSCMPUQP;
}
return SDValue(CurDAG->getMachineNode(Opc, dl, MVT::i32, LHS, RHS), 0);
}
static PPC::Predicate getPredicateForSetCC(ISD::CondCode CC) {
switch (CC) {
case ISD::SETUEQ:
case ISD::SETONE:
case ISD::SETOLE:
case ISD::SETOGE:
llvm_unreachable("Should be lowered by legalize!");
default: llvm_unreachable("Unknown condition!");
case ISD::SETOEQ:
case ISD::SETEQ: return PPC::PRED_EQ;
case ISD::SETUNE:
case ISD::SETNE: return PPC::PRED_NE;
case ISD::SETOLT:
case ISD::SETLT: return PPC::PRED_LT;
case ISD::SETULE:
case ISD::SETLE: return PPC::PRED_LE;
case ISD::SETOGT:
case ISD::SETGT: return PPC::PRED_GT;
case ISD::SETUGE:
case ISD::SETGE: return PPC::PRED_GE;
case ISD::SETO: return PPC::PRED_NU;
case ISD::SETUO: return PPC::PRED_UN;
// These two are invalid for floating point. Assume we have int.
case ISD::SETULT: return PPC::PRED_LT;
case ISD::SETUGT: return PPC::PRED_GT;
}
}
/// getCRIdxForSetCC - Return the index of the condition register field
/// associated with the SetCC condition, and whether or not the field is
/// treated as inverted. That is, lt = 0; ge = 0 inverted.
static unsigned getCRIdxForSetCC(ISD::CondCode CC, bool &Invert) {
Invert = false;
switch (CC) {
default: llvm_unreachable("Unknown condition!");
case ISD::SETOLT:
case ISD::SETLT: return 0; // Bit #0 = SETOLT
case ISD::SETOGT:
case ISD::SETGT: return 1; // Bit #1 = SETOGT
case ISD::SETOEQ:
case ISD::SETEQ: return 2; // Bit #2 = SETOEQ
case ISD::SETUO: return 3; // Bit #3 = SETUO
case ISD::SETUGE:
case ISD::SETGE: Invert = true; return 0; // !Bit #0 = SETUGE
case ISD::SETULE:
case ISD::SETLE: Invert = true; return 1; // !Bit #1 = SETULE
case ISD::SETUNE:
case ISD::SETNE: Invert = true; return 2; // !Bit #2 = SETUNE
case ISD::SETO: Invert = true; return 3; // !Bit #3 = SETO
case ISD::SETUEQ:
case ISD::SETOGE:
case ISD::SETOLE:
case ISD::SETONE:
llvm_unreachable("Invalid branch code: should be expanded by legalize");
// These are invalid for floating point. Assume integer.
case ISD::SETULT: return 0;
case ISD::SETUGT: return 1;
}
}
// getVCmpInst: return the vector compare instruction for the specified
// vector type and condition code. Since this is for altivec specific code,
// only support the altivec types (v16i8, v8i16, v4i32, v2i64, and v4f32).
static unsigned int getVCmpInst(MVT VecVT, ISD::CondCode CC,
bool HasVSX, bool &Swap, bool &Negate) {
Swap = false;
Negate = false;
if (VecVT.isFloatingPoint()) {
/* Handle some cases by swapping input operands. */
switch (CC) {
case ISD::SETLE: CC = ISD::SETGE; Swap = true; break;
case ISD::SETLT: CC = ISD::SETGT; Swap = true; break;
case ISD::SETOLE: CC = ISD::SETOGE; Swap = true; break;
case ISD::SETOLT: CC = ISD::SETOGT; Swap = true; break;
case ISD::SETUGE: CC = ISD::SETULE; Swap = true; break;
case ISD::SETUGT: CC = ISD::SETULT; Swap = true; break;
default: break;
}
/* Handle some cases by negating the result. */
switch (CC) {
case ISD::SETNE: CC = ISD::SETEQ; Negate = true; break;
case ISD::SETUNE: CC = ISD::SETOEQ; Negate = true; break;
case ISD::SETULE: CC = ISD::SETOGT; Negate = true; break;
case ISD::SETULT: CC = ISD::SETOGE; Negate = true; break;
default: break;
}
/* We have instructions implementing the remaining cases. */
switch (CC) {
case ISD::SETEQ:
case ISD::SETOEQ:
if (VecVT == MVT::v4f32)
return HasVSX ? PPC::XVCMPEQSP : PPC::VCMPEQFP;
else if (VecVT == MVT::v2f64)
return PPC::XVCMPEQDP;
break;
case ISD::SETGT:
case ISD::SETOGT:
if (VecVT == MVT::v4f32)
return HasVSX ? PPC::XVCMPGTSP : PPC::VCMPGTFP;
else if (VecVT == MVT::v2f64)
return PPC::XVCMPGTDP;
break;
case ISD::SETGE:
case ISD::SETOGE:
if (VecVT == MVT::v4f32)
return HasVSX ? PPC::XVCMPGESP : PPC::VCMPGEFP;
else if (VecVT == MVT::v2f64)
return PPC::XVCMPGEDP;
break;
default:
break;
}
llvm_unreachable("Invalid floating-point vector compare condition");
} else {
/* Handle some cases by swapping input operands. */
switch (CC) {
case ISD::SETGE: CC = ISD::SETLE; Swap = true; break;
case ISD::SETLT: CC = ISD::SETGT; Swap = true; break;
case ISD::SETUGE: CC = ISD::SETULE; Swap = true; break;
case ISD::SETULT: CC = ISD::SETUGT; Swap = true; break;
default: break;
}
/* Handle some cases by negating the result. */
switch (CC) {
case ISD::SETNE: CC = ISD::SETEQ; Negate = true; break;
case ISD::SETUNE: CC = ISD::SETUEQ; Negate = true; break;
case ISD::SETLE: CC = ISD::SETGT; Negate = true; break;
case ISD::SETULE: CC = ISD::SETUGT; Negate = true; break;
default: break;
}
/* We have instructions implementing the remaining cases. */
switch (CC) {
case ISD::SETEQ:
case ISD::SETUEQ:
if (VecVT == MVT::v16i8)
return PPC::VCMPEQUB;
else if (VecVT == MVT::v8i16)
return PPC::VCMPEQUH;
else if (VecVT == MVT::v4i32)
return PPC::VCMPEQUW;
else if (VecVT == MVT::v2i64)
return PPC::VCMPEQUD;
break;
case ISD::SETGT:
if (VecVT == MVT::v16i8)
return PPC::VCMPGTSB;
else if (VecVT == MVT::v8i16)
return PPC::VCMPGTSH;
else if (VecVT == MVT::v4i32)
return PPC::VCMPGTSW;
else if (VecVT == MVT::v2i64)
return PPC::VCMPGTSD;
break;
case ISD::SETUGT:
if (VecVT == MVT::v16i8)
return PPC::VCMPGTUB;
else if (VecVT == MVT::v8i16)
return PPC::VCMPGTUH;
else if (VecVT == MVT::v4i32)
return PPC::VCMPGTUW;
else if (VecVT == MVT::v2i64)
return PPC::VCMPGTUD;
break;
default:
break;
}
llvm_unreachable("Invalid integer vector compare condition");
}
}
bool PPCDAGToDAGISel::trySETCC(SDNode *N) {
SDLoc dl(N);
unsigned Imm;
ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
EVT PtrVT =
CurDAG->getTargetLoweringInfo().getPointerTy(CurDAG->getDataLayout());
bool isPPC64 = (PtrVT == MVT::i64);
if (!PPCSubTarget->useCRBits() &&
isInt32Immediate(N->getOperand(1), Imm)) {
// We can codegen setcc op, imm very efficiently compared to a brcond.
// Check for those cases here.
// setcc op, 0
if (Imm == 0) {
SDValue Op = N->getOperand(0);
switch (CC) {
default: break;
case ISD::SETEQ: {
Op = SDValue(CurDAG->getMachineNode(PPC::CNTLZW, dl, MVT::i32, Op), 0);
SDValue Ops[] = { Op, getI32Imm(27, dl), getI32Imm(5, dl),
getI32Imm(31, dl) };
CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops);
return true;
}
case ISD::SETNE: {
if (isPPC64) break;
SDValue AD =
SDValue(CurDAG->getMachineNode(PPC::ADDIC, dl, MVT::i32, MVT::Glue,
Op, getI32Imm(~0U, dl)), 0);
CurDAG->SelectNodeTo(N, PPC::SUBFE, MVT::i32, AD, Op, AD.getValue(1));
return true;
}
case ISD::SETLT: {
SDValue Ops[] = { Op, getI32Imm(1, dl), getI32Imm(31, dl),
getI32Imm(31, dl) };
CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops);
return true;
}
case ISD::SETGT: {
SDValue T =
SDValue(CurDAG->getMachineNode(PPC::NEG, dl, MVT::i32, Op), 0);
T = SDValue(CurDAG->getMachineNode(PPC::ANDC, dl, MVT::i32, T, Op), 0);
SDValue Ops[] = { T, getI32Imm(1, dl), getI32Imm(31, dl),
getI32Imm(31, dl) };
CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops);
return true;
}
}
} else if (Imm == ~0U) { // setcc op, -1
SDValue Op = N->getOperand(0);
switch (CC) {
default: break;
case ISD::SETEQ:
if (isPPC64) break;
Op = SDValue(CurDAG->getMachineNode(PPC::ADDIC, dl, MVT::i32, MVT::Glue,
Op, getI32Imm(1, dl)), 0);
CurDAG->SelectNodeTo(N, PPC::ADDZE, MVT::i32,
SDValue(CurDAG->getMachineNode(PPC::LI, dl,
MVT::i32,
getI32Imm(0, dl)),
0), Op.getValue(1));
return true;
case ISD::SETNE: {
if (isPPC64) break;
Op = SDValue(CurDAG->getMachineNode(PPC::NOR, dl, MVT::i32, Op, Op), 0);
SDNode *AD = CurDAG->getMachineNode(PPC::ADDIC, dl, MVT::i32, MVT::Glue,
Op, getI32Imm(~0U, dl));
CurDAG->SelectNodeTo(N, PPC::SUBFE, MVT::i32, SDValue(AD, 0), Op,
SDValue(AD, 1));
return true;
}
case ISD::SETLT: {
SDValue AD = SDValue(CurDAG->getMachineNode(PPC::ADDI, dl, MVT::i32, Op,
getI32Imm(1, dl)), 0);
SDValue AN = SDValue(CurDAG->getMachineNode(PPC::AND, dl, MVT::i32, AD,
Op), 0);
SDValue Ops[] = { AN, getI32Imm(1, dl), getI32Imm(31, dl),
getI32Imm(31, dl) };
CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops);
return true;
}
case ISD::SETGT: {
SDValue Ops[] = { Op, getI32Imm(1, dl), getI32Imm(31, dl),
getI32Imm(31, dl) };
Op = SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, Ops), 0);
CurDAG->SelectNodeTo(N, PPC::XORI, MVT::i32, Op, getI32Imm(1, dl));
return true;
}
}
}
}
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
// Altivec Vector compare instructions do not set any CR register by default and
// vector compare operations return the same type as the operands.
if (LHS.getValueType().isVector()) {
if (PPCSubTarget->hasQPX() || PPCSubTarget->hasSPE())
return false;
EVT VecVT = LHS.getValueType();
bool Swap, Negate;
unsigned int VCmpInst = getVCmpInst(VecVT.getSimpleVT(), CC,
PPCSubTarget->hasVSX(), Swap, Negate);
if (Swap)
std::swap(LHS, RHS);
EVT ResVT = VecVT.changeVectorElementTypeToInteger();
if (Negate) {
SDValue VCmp(CurDAG->getMachineNode(VCmpInst, dl, ResVT, LHS, RHS), 0);
CurDAG->SelectNodeTo(N, PPCSubTarget->hasVSX() ? PPC::XXLNOR : PPC::VNOR,
ResVT, VCmp, VCmp);
return true;
}
CurDAG->SelectNodeTo(N, VCmpInst, ResVT, LHS, RHS);
return true;
}
if (PPCSubTarget->useCRBits())
return false;
bool Inv;
unsigned Idx = getCRIdxForSetCC(CC, Inv);
SDValue CCReg = SelectCC(LHS, RHS, CC, dl);
SDValue IntCR;
// SPE e*cmp* instructions only set the 'gt' bit, so hard-code that
// The correct compare instruction is already set by SelectCC()
if (PPCSubTarget->hasSPE() && LHS.getValueType().isFloatingPoint()) {
Idx = 1;
}
// Force the ccreg into CR7.
SDValue CR7Reg = CurDAG->getRegister(PPC::CR7, MVT::i32);
SDValue InFlag(nullptr, 0); // Null incoming flag value.
CCReg = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, CR7Reg, CCReg,
InFlag).getValue(1);
IntCR = SDValue(CurDAG->getMachineNode(PPC::MFOCRF, dl, MVT::i32, CR7Reg,
CCReg), 0);
SDValue Ops[] = { IntCR, getI32Imm((32 - (3 - Idx)) & 31, dl),
getI32Imm(31, dl), getI32Imm(31, dl) };
if (!Inv) {
CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops);
return true;
}
// Get the specified bit.
SDValue Tmp =
SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, Ops), 0);
CurDAG->SelectNodeTo(N, PPC::XORI, MVT::i32, Tmp, getI32Imm(1, dl));
return true;
}
/// Does this node represent a load/store node whose address can be represented
/// with a register plus an immediate that's a multiple of \p Val:
bool PPCDAGToDAGISel::isOffsetMultipleOf(SDNode *N, unsigned Val) const {
LoadSDNode *LDN = dyn_cast<LoadSDNode>(N);
StoreSDNode *STN = dyn_cast<StoreSDNode>(N);
SDValue AddrOp;
if (LDN)
AddrOp = LDN->getOperand(1);
else if (STN)
AddrOp = STN->getOperand(2);
// If the address points a frame object or a frame object with an offset,
// we need to check the object alignment.
short Imm = 0;
if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(
AddrOp.getOpcode() == ISD::ADD ? AddrOp.getOperand(0) :
AddrOp)) {
// If op0 is a frame index that is under aligned, we can't do it either,
// because it is translated to r31 or r1 + slot + offset. We won't know the
// slot number until the stack frame is finalized.
const MachineFrameInfo &MFI = CurDAG->getMachineFunction().getFrameInfo();
unsigned SlotAlign = MFI.getObjectAlignment(FI->getIndex());
if ((SlotAlign % Val) != 0)
return false;
// If we have an offset, we need further check on the offset.
if (AddrOp.getOpcode() != ISD::ADD)
return true;
}
if (AddrOp.getOpcode() == ISD::ADD)
return isIntS16Immediate(AddrOp.getOperand(1), Imm) && !(Imm % Val);
// If the address comes from the outside, the offset will be zero.
return AddrOp.getOpcode() == ISD::CopyFromReg;
}
void PPCDAGToDAGISel::transferMemOperands(SDNode *N, SDNode *Result) {
// Transfer memoperands.
MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
CurDAG->setNodeMemRefs(cast<MachineSDNode>(Result), {MemOp});
}
static bool mayUseP9Setb(SDNode *N, const ISD::CondCode &CC, SelectionDAG *DAG,
bool &NeedSwapOps, bool &IsUnCmp) {
assert(N->getOpcode() == ISD::SELECT_CC && "Expecting a SELECT_CC here.");
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
SDValue TrueRes = N->getOperand(2);
SDValue FalseRes = N->getOperand(3);
ConstantSDNode *TrueConst = dyn_cast<ConstantSDNode>(TrueRes);
if (!TrueConst)
return false;
assert((N->getSimpleValueType(0) == MVT::i64 ||
N->getSimpleValueType(0) == MVT::i32) &&
"Expecting either i64 or i32 here.");
// We are looking for any of:
// (select_cc lhs, rhs, 1, (sext (setcc [lr]hs, [lr]hs, cc2)), cc1)
// (select_cc lhs, rhs, -1, (zext (setcc [lr]hs, [lr]hs, cc2)), cc1)
// (select_cc lhs, rhs, 0, (select_cc [lr]hs, [lr]hs, 1, -1, cc2), seteq)
// (select_cc lhs, rhs, 0, (select_cc [lr]hs, [lr]hs, -1, 1, cc2), seteq)
int64_t TrueResVal = TrueConst->getSExtValue();
if ((TrueResVal < -1 || TrueResVal > 1) ||
(TrueResVal == -1 && FalseRes.getOpcode() != ISD::ZERO_EXTEND) ||
(TrueResVal == 1 && FalseRes.getOpcode() != ISD::SIGN_EXTEND) ||
(TrueResVal == 0 &&
(FalseRes.getOpcode() != ISD::SELECT_CC || CC != ISD::SETEQ)))
return false;
bool InnerIsSel = FalseRes.getOpcode() == ISD::SELECT_CC;
SDValue SetOrSelCC = InnerIsSel ? FalseRes : FalseRes.getOperand(0);
if (SetOrSelCC.getOpcode() != ISD::SETCC &&
SetOrSelCC.getOpcode() != ISD::SELECT_CC)
return false;
// Without this setb optimization, the outer SELECT_CC will be manually
// selected to SELECT_CC_I4/SELECT_CC_I8 Pseudo, then expand-isel-pseudos pass
// transforms pseduo instruction to isel instruction. When there are more than
// one use for result like zext/sext, with current optimization we only see
// isel is replaced by setb but can't see any significant gain. Since
// setb has longer latency than original isel, we should avoid this. Another
// point is that setb requires comparison always kept, it can break the
// oppotunity to get the comparison away if we have in future.
if (!SetOrSelCC.hasOneUse() || (!InnerIsSel && !FalseRes.hasOneUse()))
return false;
SDValue InnerLHS = SetOrSelCC.getOperand(0);
SDValue InnerRHS = SetOrSelCC.getOperand(1);
ISD::CondCode InnerCC =
cast<CondCodeSDNode>(SetOrSelCC.getOperand(InnerIsSel ? 4 : 2))->get();
// If the inner comparison is a select_cc, make sure the true/false values are
// 1/-1 and canonicalize it if needed.
if (InnerIsSel) {
ConstantSDNode *SelCCTrueConst =
dyn_cast<ConstantSDNode>(SetOrSelCC.getOperand(2));
ConstantSDNode *SelCCFalseConst =
dyn_cast<ConstantSDNode>(SetOrSelCC.getOperand(3));
if (!SelCCTrueConst || !SelCCFalseConst)
return false;
int64_t SelCCTVal = SelCCTrueConst->getSExtValue();
int64_t SelCCFVal = SelCCFalseConst->getSExtValue();
// The values must be -1/1 (requiring a swap) or 1/-1.
if (SelCCTVal == -1 && SelCCFVal == 1) {
std::swap(InnerLHS, InnerRHS);
} else if (SelCCTVal != 1 || SelCCFVal != -1)
return false;
}
// Canonicalize unsigned case
if (InnerCC == ISD::SETULT || InnerCC == ISD::SETUGT) {
IsUnCmp = true;
InnerCC = (InnerCC == ISD::SETULT) ? ISD::SETLT : ISD::SETGT;
}
bool InnerSwapped = false;
if (LHS == InnerRHS && RHS == InnerLHS)
InnerSwapped = true;
else if (LHS != InnerLHS || RHS != InnerRHS)
return false;
switch (CC) {
// (select_cc lhs, rhs, 0, \
// (select_cc [lr]hs, [lr]hs, 1, -1, setlt/setgt), seteq)
case ISD::SETEQ:
if (!InnerIsSel)
return false;
if (InnerCC != ISD::SETLT && InnerCC != ISD::SETGT)
return false;
NeedSwapOps = (InnerCC == ISD::SETGT) ? InnerSwapped : !InnerSwapped;
break;
// (select_cc lhs, rhs, -1, (zext (setcc [lr]hs, [lr]hs, setne)), setu?lt)
// (select_cc lhs, rhs, -1, (zext (setcc lhs, rhs, setgt)), setu?lt)
// (select_cc lhs, rhs, -1, (zext (setcc rhs, lhs, setlt)), setu?lt)
// (select_cc lhs, rhs, 1, (sext (setcc [lr]hs, [lr]hs, setne)), setu?lt)
// (select_cc lhs, rhs, 1, (sext (setcc lhs, rhs, setgt)), setu?lt)
// (select_cc lhs, rhs, 1, (sext (setcc rhs, lhs, setlt)), setu?lt)
case ISD::SETULT:
if (!IsUnCmp && InnerCC != ISD::SETNE)
return false;
IsUnCmp = true;
LLVM_FALLTHROUGH;
case ISD::SETLT:
if (InnerCC == ISD::SETNE || (InnerCC == ISD::SETGT && !InnerSwapped) ||
(InnerCC == ISD::SETLT && InnerSwapped))
NeedSwapOps = (TrueResVal == 1);
else
return false;
break;
// (select_cc lhs, rhs, 1, (sext (setcc [lr]hs, [lr]hs, setne)), setu?gt)
// (select_cc lhs, rhs, 1, (sext (setcc lhs, rhs, setlt)), setu?gt)
// (select_cc lhs, rhs, 1, (sext (setcc rhs, lhs, setgt)), setu?gt)
// (select_cc lhs, rhs, -1, (zext (setcc [lr]hs, [lr]hs, setne)), setu?gt)
// (select_cc lhs, rhs, -1, (zext (setcc lhs, rhs, setlt)), setu?gt)
// (select_cc lhs, rhs, -1, (zext (setcc rhs, lhs, setgt)), setu?gt)
case ISD::SETUGT:
if (!IsUnCmp && InnerCC != ISD::SETNE)
return false;
IsUnCmp = true;
LLVM_FALLTHROUGH;
case ISD::SETGT:
if (InnerCC == ISD::SETNE || (InnerCC == ISD::SETLT && !InnerSwapped) ||
(InnerCC == ISD::SETGT && InnerSwapped))
NeedSwapOps = (TrueResVal == -1);
else
return false;
break;
default:
return false;
}
LLVM_DEBUG(dbgs() << "Found a node that can be lowered to a SETB: ");
LLVM_DEBUG(N->dump());
return true;
}
// Select - Convert the specified operand from a target-independent to a
// target-specific node if it hasn't already been changed.
void PPCDAGToDAGISel::Select(SDNode *N) {
SDLoc dl(N);
if (N->isMachineOpcode()) {
N->setNodeId(-1);
return; // Already selected.
}
// In case any misguided DAG-level optimizations form an ADD with a
// TargetConstant operand, crash here instead of miscompiling (by selecting
// an r+r add instead of some kind of r+i add).
if (N->getOpcode() == ISD::ADD &&
N->getOperand(1).getOpcode() == ISD::TargetConstant)
llvm_unreachable("Invalid ADD with TargetConstant operand");
// Try matching complex bit permutations before doing anything else.
if (tryBitPermutation(N))
return;
// Try to emit integer compares as GPR-only sequences (i.e. no use of CR).
if (tryIntCompareInGPR(N))
return;
switch (N->getOpcode()) {
default: break;
case ISD::Constant:
if (N->getValueType(0) == MVT::i64) {
ReplaceNode(N, selectI64Imm(CurDAG, N));
return;
}
break;
case ISD::SETCC:
if (trySETCC(N))
return;
break;
case PPCISD::CALL: {
const Module *M = MF->getFunction().getParent();
if (PPCLowering->getPointerTy(CurDAG->getDataLayout()) != MVT::i32 ||
- !PPCSubTarget->isSecurePlt() || !PPCSubTarget->isTargetELF() ||
- M->getPICLevel() == PICLevel::SmallPIC)
+ (!TM.isPositionIndependent() || !PPCSubTarget->isSecurePlt()) ||
+ !PPCSubTarget->isTargetELF() || M->getPICLevel() == PICLevel::SmallPIC)
break;
SDValue Op = N->getOperand(1);
if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op)) {
if (GA->getTargetFlags() == PPCII::MO_PLT)
getGlobalBaseReg();
}
else if (ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Op)) {
if (ES->getTargetFlags() == PPCII::MO_PLT)
getGlobalBaseReg();
}
}
break;
case PPCISD::GlobalBaseReg:
ReplaceNode(N, getGlobalBaseReg());
return;
case ISD::FrameIndex:
selectFrameIndex(N, N);
return;
case PPCISD::MFOCRF: {
SDValue InFlag = N->getOperand(1);
ReplaceNode(N, CurDAG->getMachineNode(PPC::MFOCRF, dl, MVT::i32,
N->getOperand(0), InFlag));
return;
}
case PPCISD::READ_TIME_BASE:
ReplaceNode(N, CurDAG->getMachineNode(PPC::ReadTB, dl, MVT::i32, MVT::i32,
MVT::Other, N->getOperand(0)));
return;
case PPCISD::SRA_ADDZE: {
SDValue N0 = N->getOperand(0);
SDValue ShiftAmt =
CurDAG->getTargetConstant(*cast<ConstantSDNode>(N->getOperand(1))->
getConstantIntValue(), dl,
N->getValueType(0));
if (N->getValueType(0) == MVT::i64) {
SDNode *Op =
CurDAG->getMachineNode(PPC::SRADI, dl, MVT::i64, MVT::Glue,
N0, ShiftAmt);
CurDAG->SelectNodeTo(N, PPC::ADDZE8, MVT::i64, SDValue(Op, 0),
SDValue(Op, 1));
return;
} else {
assert(N->getValueType(0) == MVT::i32 &&
"Expecting i64 or i32 in PPCISD::SRA_ADDZE");
SDNode *Op =
CurDAG->getMachineNode(PPC::SRAWI, dl, MVT::i32, MVT::Glue,
N0, ShiftAmt);
CurDAG->SelectNodeTo(N, PPC::ADDZE, MVT::i32, SDValue(Op, 0),
SDValue(Op, 1));
return;
}
}
case ISD::STORE: {
// Change TLS initial-exec D-form stores to X-form stores.
StoreSDNode *ST = cast<StoreSDNode>(N);
if (EnableTLSOpt && PPCSubTarget->isELFv2ABI() &&
ST->getAddressingMode() != ISD::PRE_INC)
if (tryTLSXFormStore(ST))
return;
break;
}
case ISD::LOAD: {
// Handle preincrement loads.
LoadSDNode *LD = cast<LoadSDNode>(N);
EVT LoadedVT = LD->getMemoryVT();
// Normal loads are handled by code generated from the .td file.
if (LD->getAddressingMode() != ISD::PRE_INC) {
// Change TLS initial-exec D-form loads to X-form loads.
if (EnableTLSOpt && PPCSubTarget->isELFv2ABI())
if (tryTLSXFormLoad(LD))
return;
break;
}
SDValue Offset = LD->getOffset();
if (Offset.getOpcode() == ISD::TargetConstant ||
Offset.getOpcode() == ISD::TargetGlobalAddress) {
unsigned Opcode;
bool isSExt = LD->getExtensionType() == ISD::SEXTLOAD;
if (LD->getValueType(0) != MVT::i64) {
// Handle PPC32 integer and normal FP loads.
assert((!isSExt || LoadedVT == MVT::i16) && "Invalid sext update load");
switch (LoadedVT.getSimpleVT().SimpleTy) {
default: llvm_unreachable("Invalid PPC load type!");
case MVT::f64: Opcode = PPC::LFDU; break;
case MVT::f32: Opcode = PPC::LFSU; break;
case MVT::i32: Opcode = PPC::LWZU; break;
case MVT::i16: Opcode = isSExt ? PPC::LHAU : PPC::LHZU; break;
case MVT::i1:
case MVT::i8: Opcode = PPC::LBZU; break;
}
} else {
assert(LD->getValueType(0) == MVT::i64 && "Unknown load result type!");
assert((!isSExt || LoadedVT == MVT::i16) && "Invalid sext update load");
switch (LoadedVT.getSimpleVT().SimpleTy) {
default: llvm_unreachable("Invalid PPC load type!");
case MVT::i64: Opcode = PPC::LDU; break;
case MVT::i32: Opcode = PPC::LWZU8; break;
case MVT::i16: Opcode = isSExt ? PPC::LHAU8 : PPC::LHZU8; break;
case MVT::i1:
case MVT::i8: Opcode = PPC::LBZU8; break;
}
}
SDValue Chain = LD->getChain();
SDValue Base = LD->getBasePtr();
SDValue Ops[] = { Offset, Base, Chain };
SDNode *MN = CurDAG->getMachineNode(
Opcode, dl, LD->getValueType(0),
PPCLowering->getPointerTy(CurDAG->getDataLayout()), MVT::Other, Ops);
transferMemOperands(N, MN);
ReplaceNode(N, MN);
return;
} else {
unsigned Opcode;
bool isSExt = LD->getExtensionType() == ISD::SEXTLOAD;
if (LD->getValueType(0) != MVT::i64) {
// Handle PPC32 integer and normal FP loads.
assert((!isSExt || LoadedVT == MVT::i16) && "Invalid sext update load");
switch (LoadedVT.getSimpleVT().SimpleTy) {
default: llvm_unreachable("Invalid PPC load type!");
case MVT::v4f64: Opcode = PPC::QVLFDUX; break; // QPX
case MVT::v4f32: Opcode = PPC::QVLFSUX; break; // QPX
case MVT::f64: Opcode = PPC::LFDUX; break;
case MVT::f32: Opcode = PPC::LFSUX; break;
case MVT::i32: Opcode = PPC::LWZUX; break;
case MVT::i16: Opcode = isSExt ? PPC::LHAUX : PPC::LHZUX; break;
case MVT::i1:
case MVT::i8: Opcode = PPC::LBZUX; break;
}
} else {
assert(LD->getValueType(0) == MVT::i64 && "Unknown load result type!");
assert((!isSExt || LoadedVT == MVT::i16 || LoadedVT == MVT::i32) &&
"Invalid sext update load");
switch (LoadedVT.getSimpleVT().SimpleTy) {
default: llvm_unreachable("Invalid PPC load type!");
case MVT::i64: Opcode = PPC::LDUX; break;
case MVT::i32: Opcode = isSExt ? PPC::LWAUX : PPC::LWZUX8; break;
case MVT::i16: Opcode = isSExt ? PPC::LHAUX8 : PPC::LHZUX8; break;
case MVT::i1:
case MVT::i8: Opcode = PPC::LBZUX8; break;
}
}
SDValue Chain = LD->getChain();
SDValue Base = LD->getBasePtr();
SDValue Ops[] = { Base, Offset, Chain };
SDNode *MN = CurDAG->getMachineNode(
Opcode, dl, LD->getValueType(0),
PPCLowering->getPointerTy(CurDAG->getDataLayout()), MVT::Other, Ops);
transferMemOperands(N, MN);
ReplaceNode(N, MN);
return;
}
}
case ISD::AND: {
unsigned Imm, Imm2, SH, MB, ME;
uint64_t Imm64;
// If this is an and of a value rotated between 0 and 31 bits and then and'd
// with a mask, emit rlwinm
if (isInt32Immediate(N->getOperand(1), Imm) &&
isRotateAndMask(N->getOperand(0).getNode(), Imm, false, SH, MB, ME)) {
SDValue Val = N->getOperand(0).getOperand(0);
SDValue Ops[] = { Val, getI32Imm(SH, dl), getI32Imm(MB, dl),
getI32Imm(ME, dl) };
CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops);
return;
}
// If this is just a masked value where the input is not handled above, and
// is not a rotate-left (handled by a pattern in the .td file), emit rlwinm
if (isInt32Immediate(N->getOperand(1), Imm) &&
isRunOfOnes(Imm, MB, ME) &&
N->getOperand(0).getOpcode() != ISD::ROTL) {
SDValue Val = N->getOperand(0);
SDValue Ops[] = { Val, getI32Imm(0, dl), getI32Imm(MB, dl),
getI32Imm(ME, dl) };
CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops);
return;
}
// If this is a 64-bit zero-extension mask, emit rldicl.
if (isInt64Immediate(N->getOperand(1).getNode(), Imm64) &&
isMask_64(Imm64)) {
SDValue Val = N->getOperand(0);
MB = 64 - countTrailingOnes(Imm64);
SH = 0;
if (Val.getOpcode() == ISD::ANY_EXTEND) {
auto Op0 = Val.getOperand(0);
if ( Op0.getOpcode() == ISD::SRL &&
isInt32Immediate(Op0.getOperand(1).getNode(), Imm) && Imm <= MB) {
auto ResultType = Val.getNode()->getValueType(0);
auto ImDef = CurDAG->getMachineNode(PPC::IMPLICIT_DEF, dl,
ResultType);
SDValue IDVal (ImDef, 0);
Val = SDValue(CurDAG->getMachineNode(PPC::INSERT_SUBREG, dl,
ResultType, IDVal, Op0.getOperand(0),
getI32Imm(1, dl)), 0);
SH = 64 - Imm;
}
}
// If the operand is a logical right shift, we can fold it into this
// instruction: rldicl(rldicl(x, 64-n, n), 0, mb) -> rldicl(x, 64-n, mb)
// for n <= mb. The right shift is really a left rotate followed by a
// mask, and this mask is a more-restrictive sub-mask of the mask implied
// by the shift.
if (Val.getOpcode() == ISD::SRL &&
isInt32Immediate(Val.getOperand(1).getNode(), Imm) && Imm <= MB) {
assert(Imm < 64 && "Illegal shift amount");
Val = Val.getOperand(0);
SH = 64 - Imm;
}
SDValue Ops[] = { Val, getI32Imm(SH, dl), getI32Imm(MB, dl) };
CurDAG->SelectNodeTo(N, PPC::RLDICL, MVT::i64, Ops);
return;
}
// If this is a negated 64-bit zero-extension mask,
// i.e. the immediate is a sequence of ones from most significant side
// and all zero for reminder, we should use rldicr.
if (isInt64Immediate(N->getOperand(1).getNode(), Imm64) &&
isMask_64(~Imm64)) {
SDValue Val = N->getOperand(0);
MB = 63 - countTrailingOnes(~Imm64);
SH = 0;
SDValue Ops[] = { Val, getI32Imm(SH, dl), getI32Imm(MB, dl) };
CurDAG->SelectNodeTo(N, PPC::RLDICR, MVT::i64, Ops);
return;
}
// AND X, 0 -> 0, not "rlwinm 32".
if (isInt32Immediate(N->getOperand(1), Imm) && (Imm == 0)) {
ReplaceUses(SDValue(N, 0), N->getOperand(1));
return;
}
// ISD::OR doesn't get all the bitfield insertion fun.
// (and (or x, c1), c2) where isRunOfOnes(~(c1^c2)) might be a
// bitfield insert.
if (isInt32Immediate(N->getOperand(1), Imm) &&
N->getOperand(0).getOpcode() == ISD::OR &&
isInt32Immediate(N->getOperand(0).getOperand(1), Imm2)) {
// The idea here is to check whether this is equivalent to:
// (c1 & m) | (x & ~m)
// where m is a run-of-ones mask. The logic here is that, for each bit in
// c1 and c2:
// - if both are 1, then the output will be 1.
// - if both are 0, then the output will be 0.
// - if the bit in c1 is 0, and the bit in c2 is 1, then the output will
// come from x.
// - if the bit in c1 is 1, and the bit in c2 is 0, then the output will
// be 0.
// If that last condition is never the case, then we can form m from the
// bits that are the same between c1 and c2.
unsigned MB, ME;
if (isRunOfOnes(~(Imm^Imm2), MB, ME) && !(~Imm & Imm2)) {
SDValue Ops[] = { N->getOperand(0).getOperand(0),
N->getOperand(0).getOperand(1),
getI32Imm(0, dl), getI32Imm(MB, dl),
getI32Imm(ME, dl) };
ReplaceNode(N, CurDAG->getMachineNode(PPC::RLWIMI, dl, MVT::i32, Ops));
return;
}
}
// Other cases are autogenerated.
break;
}
case ISD::OR: {
if (N->getValueType(0) == MVT::i32)
if (tryBitfieldInsert(N))
return;
int16_t Imm;
if (N->getOperand(0)->getOpcode() == ISD::FrameIndex &&
isIntS16Immediate(N->getOperand(1), Imm)) {
KnownBits LHSKnown = CurDAG->computeKnownBits(N->getOperand(0));
// If this is equivalent to an add, then we can fold it with the
// FrameIndex calculation.
if ((LHSKnown.Zero.getZExtValue()|~(uint64_t)Imm) == ~0ULL) {
selectFrameIndex(N, N->getOperand(0).getNode(), (int)Imm);
return;
}
}
// OR with a 32-bit immediate can be handled by ori + oris
// without creating an immediate in a GPR.
uint64_t Imm64 = 0;
bool IsPPC64 = PPCSubTarget->isPPC64();
if (IsPPC64 && isInt64Immediate(N->getOperand(1), Imm64) &&
(Imm64 & ~0xFFFFFFFFuLL) == 0) {
// If ImmHi (ImmHi) is zero, only one ori (oris) is generated later.
uint64_t ImmHi = Imm64 >> 16;
uint64_t ImmLo = Imm64 & 0xFFFF;
if (ImmHi != 0 && ImmLo != 0) {
SDNode *Lo = CurDAG->getMachineNode(PPC::ORI8, dl, MVT::i64,
N->getOperand(0),
getI16Imm(ImmLo, dl));
SDValue Ops1[] = { SDValue(Lo, 0), getI16Imm(ImmHi, dl)};
CurDAG->SelectNodeTo(N, PPC::ORIS8, MVT::i64, Ops1);
return;
}
}
// Other cases are autogenerated.
break;
}
case ISD::XOR: {
// XOR with a 32-bit immediate can be handled by xori + xoris
// without creating an immediate in a GPR.
uint64_t Imm64 = 0;
bool IsPPC64 = PPCSubTarget->isPPC64();
if (IsPPC64 && isInt64Immediate(N->getOperand(1), Imm64) &&
(Imm64 & ~0xFFFFFFFFuLL) == 0) {
// If ImmHi (ImmHi) is zero, only one xori (xoris) is generated later.
uint64_t ImmHi = Imm64 >> 16;
uint64_t ImmLo = Imm64 & 0xFFFF;
if (ImmHi != 0 && ImmLo != 0) {
SDNode *Lo = CurDAG->getMachineNode(PPC::XORI8, dl, MVT::i64,
N->getOperand(0),
getI16Imm(ImmLo, dl));
SDValue Ops1[] = { SDValue(Lo, 0), getI16Imm(ImmHi, dl)};
CurDAG->SelectNodeTo(N, PPC::XORIS8, MVT::i64, Ops1);
return;
}
}
break;
}
case ISD::ADD: {
int16_t Imm;
if (N->getOperand(0)->getOpcode() == ISD::FrameIndex &&
isIntS16Immediate(N->getOperand(1), Imm)) {
selectFrameIndex(N, N->getOperand(0).getNode(), (int)Imm);
return;
}
break;
}
case ISD::SHL: {
unsigned Imm, SH, MB, ME;
if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::AND, Imm) &&
isRotateAndMask(N, Imm, true, SH, MB, ME)) {
SDValue Ops[] = { N->getOperand(0).getOperand(0),
getI32Imm(SH, dl), getI32Imm(MB, dl),
getI32Imm(ME, dl) };
CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops);
return;
}
// Other cases are autogenerated.
break;
}
case ISD::SRL: {
unsigned Imm, SH, MB, ME;
if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::AND, Imm) &&
isRotateAndMask(N, Imm, true, SH, MB, ME)) {
SDValue Ops[] = { N->getOperand(0).getOperand(0),
getI32Imm(SH, dl), getI32Imm(MB, dl),
getI32Imm(ME, dl) };
CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops);
return;
}
// Other cases are autogenerated.
break;
}
// FIXME: Remove this once the ANDI glue bug is fixed:
case PPCISD::ANDIo_1_EQ_BIT:
case PPCISD::ANDIo_1_GT_BIT: {
if (!ANDIGlueBug)
break;
EVT InVT = N->getOperand(0).getValueType();
assert((InVT == MVT::i64 || InVT == MVT::i32) &&
"Invalid input type for ANDIo_1_EQ_BIT");
unsigned Opcode = (InVT == MVT::i64) ? PPC::ANDIo8 : PPC::ANDIo;
SDValue AndI(CurDAG->getMachineNode(Opcode, dl, InVT, MVT::Glue,
N->getOperand(0),
CurDAG->getTargetConstant(1, dl, InVT)),
0);
SDValue CR0Reg = CurDAG->getRegister(PPC::CR0, MVT::i32);
SDValue SRIdxVal =
CurDAG->getTargetConstant(N->getOpcode() == PPCISD::ANDIo_1_EQ_BIT ?
PPC::sub_eq : PPC::sub_gt, dl, MVT::i32);
CurDAG->SelectNodeTo(N, TargetOpcode::EXTRACT_SUBREG, MVT::i1, CR0Reg,
SRIdxVal, SDValue(AndI.getNode(), 1) /* glue */);
return;
}
case ISD::SELECT_CC: {
ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(4))->get();
EVT PtrVT =
CurDAG->getTargetLoweringInfo().getPointerTy(CurDAG->getDataLayout());
bool isPPC64 = (PtrVT == MVT::i64);
// If this is a select of i1 operands, we'll pattern match it.
if (PPCSubTarget->useCRBits() &&
N->getOperand(0).getValueType() == MVT::i1)
break;
if (PPCSubTarget->isISA3_0() && PPCSubTarget->isPPC64()) {
bool NeedSwapOps = false;
bool IsUnCmp = false;
if (mayUseP9Setb(N, CC, CurDAG, NeedSwapOps, IsUnCmp)) {
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
if (NeedSwapOps)
std::swap(LHS, RHS);
// Make use of SelectCC to generate the comparison to set CR bits, for
// equality comparisons having one literal operand, SelectCC probably
// doesn't need to materialize the whole literal and just use xoris to
// check it first, it leads the following comparison result can't
// exactly represent GT/LT relationship. So to avoid this we specify
// SETGT/SETUGT here instead of SETEQ.
SDValue GenCC =
SelectCC(LHS, RHS, IsUnCmp ? ISD::SETUGT : ISD::SETGT, dl);
CurDAG->SelectNodeTo(
N, N->getSimpleValueType(0) == MVT::i64 ? PPC::SETB8 : PPC::SETB,
N->getValueType(0), GenCC);
NumP9Setb++;
return;
}
}
// Handle the setcc cases here. select_cc lhs, 0, 1, 0, cc
if (!isPPC64)
if (ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N->getOperand(1)))
if (ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N->getOperand(2)))
if (ConstantSDNode *N3C = dyn_cast<ConstantSDNode>(N->getOperand(3)))
if (N1C->isNullValue() && N3C->isNullValue() &&
N2C->getZExtValue() == 1ULL && CC == ISD::SETNE &&
// FIXME: Implement this optzn for PPC64.
N->getValueType(0) == MVT::i32) {
SDNode *Tmp =
CurDAG->getMachineNode(PPC::ADDIC, dl, MVT::i32, MVT::Glue,
N->getOperand(0), getI32Imm(~0U, dl));
CurDAG->SelectNodeTo(N, PPC::SUBFE, MVT::i32, SDValue(Tmp, 0),
N->getOperand(0), SDValue(Tmp, 1));
return;
}
SDValue CCReg = SelectCC(N->getOperand(0), N->getOperand(1), CC, dl);
if (N->getValueType(0) == MVT::i1) {
// An i1 select is: (c & t) | (!c & f).
bool Inv;
unsigned Idx = getCRIdxForSetCC(CC, Inv);
unsigned SRI;
switch (Idx) {
default: llvm_unreachable("Invalid CC index");
case 0: SRI = PPC::sub_lt; break;
case 1: SRI = PPC::sub_gt; break;
case 2: SRI = PPC::sub_eq; break;
case 3: SRI = PPC::sub_un; break;
}
SDValue CCBit = CurDAG->getTargetExtractSubreg(SRI, dl, MVT::i1, CCReg);
SDValue NotCCBit(CurDAG->getMachineNode(PPC::CRNOR, dl, MVT::i1,
CCBit, CCBit), 0);
SDValue C = Inv ? NotCCBit : CCBit,
NotC = Inv ? CCBit : NotCCBit;
SDValue CAndT(CurDAG->getMachineNode(PPC::CRAND, dl, MVT::i1,
C, N->getOperand(2)), 0);
SDValue NotCAndF(CurDAG->getMachineNode(PPC::CRAND, dl, MVT::i1,
NotC, N->getOperand(3)), 0);
CurDAG->SelectNodeTo(N, PPC::CROR, MVT::i1, CAndT, NotCAndF);
return;
}
unsigned BROpc = getPredicateForSetCC(CC);
unsigned SelectCCOp;
if (N->getValueType(0) == MVT::i32)
SelectCCOp = PPC::SELECT_CC_I4;
else if (N->getValueType(0) == MVT::i64)
SelectCCOp = PPC::SELECT_CC_I8;
else if (N->getValueType(0) == MVT::f32) {
if (PPCSubTarget->hasP8Vector())
SelectCCOp = PPC::SELECT_CC_VSSRC;
else if (PPCSubTarget->hasSPE())
SelectCCOp = PPC::SELECT_CC_SPE4;
else
SelectCCOp = PPC::SELECT_CC_F4;
} else if (N->getValueType(0) == MVT::f64) {
if (PPCSubTarget->hasVSX())
SelectCCOp = PPC::SELECT_CC_VSFRC;
else if (PPCSubTarget->hasSPE())
SelectCCOp = PPC::SELECT_CC_SPE;
else
SelectCCOp = PPC::SELECT_CC_F8;
} else if (N->getValueType(0) == MVT::f128)
SelectCCOp = PPC::SELECT_CC_F16;
else if (PPCSubTarget->hasSPE())
SelectCCOp = PPC::SELECT_CC_SPE;
else if (PPCSubTarget->hasQPX() && N->getValueType(0) == MVT::v4f64)
SelectCCOp = PPC::SELECT_CC_QFRC;
else if (PPCSubTarget->hasQPX() && N->getValueType(0) == MVT::v4f32)
SelectCCOp = PPC::SELECT_CC_QSRC;
else if (PPCSubTarget->hasQPX() && N->getValueType(0) == MVT::v4i1)
SelectCCOp = PPC::SELECT_CC_QBRC;
else if (N->getValueType(0) == MVT::v2f64 ||
N->getValueType(0) == MVT::v2i64)
SelectCCOp = PPC::SELECT_CC_VSRC;
else
SelectCCOp = PPC::SELECT_CC_VRRC;
SDValue Ops[] = { CCReg, N->getOperand(2), N->getOperand(3),
getI32Imm(BROpc, dl) };
CurDAG->SelectNodeTo(N, SelectCCOp, N->getValueType(0), Ops);
return;
}
case ISD::VECTOR_SHUFFLE:
if (PPCSubTarget->hasVSX() && (N->getValueType(0) == MVT::v2f64 ||
N->getValueType(0) == MVT::v2i64)) {
ShuffleVectorSDNode *SVN = cast<ShuffleVectorSDNode>(N);
SDValue Op1 = N->getOperand(SVN->getMaskElt(0) < 2 ? 0 : 1),
Op2 = N->getOperand(SVN->getMaskElt(1) < 2 ? 0 : 1);
unsigned DM[2];
for (int i = 0; i < 2; ++i)
if (SVN->getMaskElt(i) <= 0 || SVN->getMaskElt(i) == 2)
DM[i] = 0;
else
DM[i] = 1;
if (Op1 == Op2 && DM[0] == 0 && DM[1] == 0 &&
Op1.getOpcode() == ISD::SCALAR_TO_VECTOR &&
isa<LoadSDNode>(Op1.getOperand(0))) {
LoadSDNode *LD = cast<LoadSDNode>(Op1.getOperand(0));
SDValue Base, Offset;
if (LD->isUnindexed() && LD->hasOneUse() && Op1.hasOneUse() &&
(LD->getMemoryVT() == MVT::f64 ||
LD->getMemoryVT() == MVT::i64) &&
SelectAddrIdxOnly(LD->getBasePtr(), Base, Offset)) {
SDValue Chain = LD->getChain();
SDValue Ops[] = { Base, Offset, Chain };
MachineMemOperand *MemOp = LD->getMemOperand();
SDNode *NewN = CurDAG->SelectNodeTo(N, PPC::LXVDSX,
N->getValueType(0), Ops);
CurDAG->setNodeMemRefs(cast<MachineSDNode>(NewN), {MemOp});
return;
}
}
// For little endian, we must swap the input operands and adjust
// the mask elements (reverse and invert them).
if (PPCSubTarget->isLittleEndian()) {
std::swap(Op1, Op2);
unsigned tmp = DM[0];
DM[0] = 1 - DM[1];
DM[1] = 1 - tmp;
}
SDValue DMV = CurDAG->getTargetConstant(DM[1] | (DM[0] << 1), dl,
MVT::i32);
SDValue Ops[] = { Op1, Op2, DMV };
CurDAG->SelectNodeTo(N, PPC::XXPERMDI, N->getValueType(0), Ops);
return;
}
break;
case PPCISD::BDNZ:
case PPCISD::BDZ: {
bool IsPPC64 = PPCSubTarget->isPPC64();
SDValue Ops[] = { N->getOperand(1), N->getOperand(0) };
CurDAG->SelectNodeTo(N, N->getOpcode() == PPCISD::BDNZ
? (IsPPC64 ? PPC::BDNZ8 : PPC::BDNZ)
: (IsPPC64 ? PPC::BDZ8 : PPC::BDZ),
MVT::Other, Ops);
return;
}
case PPCISD::COND_BRANCH: {
// Op #0 is the Chain.
// Op #1 is the PPC::PRED_* number.
// Op #2 is the CR#
// Op #3 is the Dest MBB
// Op #4 is the Flag.
// Prevent PPC::PRED_* from being selected into LI.
unsigned PCC = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
if (EnableBranchHint)
PCC |= getBranchHint(PCC, FuncInfo, N->getOperand(3));
SDValue Pred = getI32Imm(PCC, dl);
SDValue Ops[] = { Pred, N->getOperand(2), N->getOperand(3),
N->getOperand(0), N->getOperand(4) };
CurDAG->SelectNodeTo(N, PPC::BCC, MVT::Other, Ops);
return;
}
case ISD::BR_CC: {
ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(1))->get();
unsigned PCC = getPredicateForSetCC(CC);
if (N->getOperand(2).getValueType() == MVT::i1) {
unsigned Opc;
bool Swap;
switch (PCC) {
default: llvm_unreachable("Unexpected Boolean-operand predicate");
case PPC::PRED_LT: Opc = PPC::CRANDC; Swap = true; break;
case PPC::PRED_LE: Opc = PPC::CRORC; Swap = true; break;
case PPC::PRED_EQ: Opc = PPC::CREQV; Swap = false; break;
case PPC::PRED_GE: Opc = PPC::CRORC; Swap = false; break;
case PPC::PRED_GT: Opc = PPC::CRANDC; Swap = false; break;
case PPC::PRED_NE: Opc = PPC::CRXOR; Swap = false; break;
}
// A signed comparison of i1 values produces the opposite result to an
// unsigned one if the condition code includes less-than or greater-than.
// This is because 1 is the most negative signed i1 number and the most
// positive unsigned i1 number. The CR-logical operations used for such
// comparisons are non-commutative so for signed comparisons vs. unsigned
// ones, the input operands just need to be swapped.
if (ISD::isSignedIntSetCC(CC))
Swap = !Swap;
SDValue BitComp(CurDAG->getMachineNode(Opc, dl, MVT::i1,
N->getOperand(Swap ? 3 : 2),
N->getOperand(Swap ? 2 : 3)), 0);
CurDAG->SelectNodeTo(N, PPC::BC, MVT::Other, BitComp, N->getOperand(4),
N->getOperand(0));
return;
}
if (EnableBranchHint)
PCC |= getBranchHint(PCC, FuncInfo, N->getOperand(4));
SDValue CondCode = SelectCC(N->getOperand(2), N->getOperand(3), CC, dl);
SDValue Ops[] = { getI32Imm(PCC, dl), CondCode,
N->getOperand(4), N->getOperand(0) };
CurDAG->SelectNodeTo(N, PPC::BCC, MVT::Other, Ops);
return;
}
case ISD::BRIND: {
// FIXME: Should custom lower this.
SDValue Chain = N->getOperand(0);
SDValue Target = N->getOperand(1);
unsigned Opc = Target.getValueType() == MVT::i32 ? PPC::MTCTR : PPC::MTCTR8;
unsigned Reg = Target.getValueType() == MVT::i32 ? PPC::BCTR : PPC::BCTR8;
Chain = SDValue(CurDAG->getMachineNode(Opc, dl, MVT::Glue, Target,
Chain), 0);
CurDAG->SelectNodeTo(N, Reg, MVT::Other, Chain);
return;
}
case PPCISD::TOC_ENTRY: {
assert ((PPCSubTarget->isPPC64() || PPCSubTarget->isSVR4ABI()) &&
"Only supported for 64-bit ABI and 32-bit SVR4");
if (PPCSubTarget->isSVR4ABI() && !PPCSubTarget->isPPC64()) {
SDValue GA = N->getOperand(0);
SDNode *MN = CurDAG->getMachineNode(PPC::LWZtoc, dl, MVT::i32, GA,
N->getOperand(1));
transferMemOperands(N, MN);
ReplaceNode(N, MN);
return;
}
// For medium and large code model, we generate two instructions as
// described below. Otherwise we allow SelectCodeCommon to handle this,
// selecting one of LDtoc, LDtocJTI, LDtocCPT, and LDtocBA.
CodeModel::Model CModel = TM.getCodeModel();
if (CModel != CodeModel::Medium && CModel != CodeModel::Large)
break;
// The first source operand is a TargetGlobalAddress or a TargetJumpTable.
// If it must be toc-referenced according to PPCSubTarget, we generate:
// LDtocL(@sym, ADDIStocHA(%x2, @sym))
// Otherwise we generate:
// ADDItocL(ADDIStocHA(%x2, @sym), @sym)
SDValue GA = N->getOperand(0);
SDValue TOCbase = N->getOperand(1);
SDNode *Tmp = CurDAG->getMachineNode(PPC::ADDIStocHA, dl, MVT::i64,
TOCbase, GA);
if (PPCLowering->isAccessedAsGotIndirect(GA)) {
// If it is access as got-indirect, we need an extra LD to load
// the address.
SDNode *MN = CurDAG->getMachineNode(PPC::LDtocL, dl, MVT::i64, GA,
SDValue(Tmp, 0));
transferMemOperands(N, MN);
ReplaceNode(N, MN);
return;
}
// Build the address relative to the TOC-pointer..
ReplaceNode(N, CurDAG->getMachineNode(PPC::ADDItocL, dl, MVT::i64,
SDValue(Tmp, 0), GA));
return;
}
case PPCISD::PPC32_PICGOT:
// Generate a PIC-safe GOT reference.
assert(!PPCSubTarget->isPPC64() && PPCSubTarget->isSVR4ABI() &&
"PPCISD::PPC32_PICGOT is only supported for 32-bit SVR4");
CurDAG->SelectNodeTo(N, PPC::PPC32PICGOT,
PPCLowering->getPointerTy(CurDAG->getDataLayout()),
MVT::i32);
return;
case PPCISD::VADD_SPLAT: {
// This expands into one of three sequences, depending on whether
// the first operand is odd or even, positive or negative.
assert(isa<ConstantSDNode>(N->getOperand(0)) &&
isa<ConstantSDNode>(N->getOperand(1)) &&
"Invalid operand on VADD_SPLAT!");
int Elt = N->getConstantOperandVal(0);
int EltSize = N->getConstantOperandVal(1);
unsigned Opc1, Opc2, Opc3;
EVT VT;
if (EltSize == 1) {
Opc1 = PPC::VSPLTISB;
Opc2 = PPC::VADDUBM;
Opc3 = PPC::VSUBUBM;
VT = MVT::v16i8;
} else if (EltSize == 2) {
Opc1 = PPC::VSPLTISH;
Opc2 = PPC::VADDUHM;
Opc3 = PPC::VSUBUHM;
VT = MVT::v8i16;
} else {
assert(EltSize == 4 && "Invalid element size on VADD_SPLAT!");
Opc1 = PPC::VSPLTISW;
Opc2 = PPC::VADDUWM;
Opc3 = PPC::VSUBUWM;
VT = MVT::v4i32;
}
if ((Elt & 1) == 0) {
// Elt is even, in the range [-32,-18] + [16,30].
//
// Convert: VADD_SPLAT elt, size
// Into: tmp = VSPLTIS[BHW] elt
// VADDU[BHW]M tmp, tmp
// Where: [BHW] = B for size = 1, H for size = 2, W for size = 4
SDValue EltVal = getI32Imm(Elt >> 1, dl);
SDNode *Tmp = CurDAG->getMachineNode(Opc1, dl, VT, EltVal);
SDValue TmpVal = SDValue(Tmp, 0);
ReplaceNode(N, CurDAG->getMachineNode(Opc2, dl, VT, TmpVal, TmpVal));
return;
} else if (Elt > 0) {
// Elt is odd and positive, in the range [17,31].
//
// Convert: VADD_SPLAT elt, size
// Into: tmp1 = VSPLTIS[BHW] elt-16
// tmp2 = VSPLTIS[BHW] -16
// VSUBU[BHW]M tmp1, tmp2
SDValue EltVal = getI32Imm(Elt - 16, dl);
SDNode *Tmp1 = CurDAG->getMachineNode(Opc1, dl, VT, EltVal);
EltVal = getI32Imm(-16, dl);
SDNode *Tmp2 = CurDAG->getMachineNode(Opc1, dl, VT, EltVal);
ReplaceNode(N, CurDAG->getMachineNode(Opc3, dl, VT, SDValue(Tmp1, 0),
SDValue(Tmp2, 0)));
return;
} else {
// Elt is odd and negative, in the range [-31,-17].
//
// Convert: VADD_SPLAT elt, size
// Into: tmp1 = VSPLTIS[BHW] elt+16
// tmp2 = VSPLTIS[BHW] -16
// VADDU[BHW]M tmp1, tmp2
SDValue EltVal = getI32Imm(Elt + 16, dl);
SDNode *Tmp1 = CurDAG->getMachineNode(Opc1, dl, VT, EltVal);
EltVal = getI32Imm(-16, dl);
SDNode *Tmp2 = CurDAG->getMachineNode(Opc1, dl, VT, EltVal);
ReplaceNode(N, CurDAG->getMachineNode(Opc2, dl, VT, SDValue(Tmp1, 0),
SDValue(Tmp2, 0)));
return;
}
}
}
SelectCode(N);
}
// If the target supports the cmpb instruction, do the idiom recognition here.
// We don't do this as a DAG combine because we don't want to do it as nodes
// are being combined (because we might miss part of the eventual idiom). We
// don't want to do it during instruction selection because we want to reuse
// the logic for lowering the masking operations already part of the
// instruction selector.
SDValue PPCDAGToDAGISel::combineToCMPB(SDNode *N) {
SDLoc dl(N);
assert(N->getOpcode() == ISD::OR &&
"Only OR nodes are supported for CMPB");
SDValue Res;
if (!PPCSubTarget->hasCMPB())
return Res;
if (N->getValueType(0) != MVT::i32 &&
N->getValueType(0) != MVT::i64)
return Res;
EVT VT = N->getValueType(0);
SDValue RHS, LHS;
bool BytesFound[8] = {false, false, false, false, false, false, false, false};
uint64_t Mask = 0, Alt = 0;
auto IsByteSelectCC = [this](SDValue O, unsigned &b,
uint64_t &Mask, uint64_t &Alt,
SDValue &LHS, SDValue &RHS) {
if (O.getOpcode() != ISD::SELECT_CC)
return false;
ISD::CondCode CC = cast<CondCodeSDNode>(O.getOperand(4))->get();
if (!isa<ConstantSDNode>(O.getOperand(2)) ||
!isa<ConstantSDNode>(O.getOperand(3)))
return false;
uint64_t PM = O.getConstantOperandVal(2);
uint64_t PAlt = O.getConstantOperandVal(3);
for (b = 0; b < 8; ++b) {
uint64_t Mask = UINT64_C(0xFF) << (8*b);
if (PM && (PM & Mask) == PM && (PAlt & Mask) == PAlt)
break;
}
if (b == 8)
return false;
Mask |= PM;
Alt |= PAlt;
if (!isa<ConstantSDNode>(O.getOperand(1)) ||
O.getConstantOperandVal(1) != 0) {
SDValue Op0 = O.getOperand(0), Op1 = O.getOperand(1);
if (Op0.getOpcode() == ISD::TRUNCATE)
Op0 = Op0.getOperand(0);
if (Op1.getOpcode() == ISD::TRUNCATE)
Op1 = Op1.getOperand(0);
if (Op0.getOpcode() == ISD::SRL && Op1.getOpcode() == ISD::SRL &&
Op0.getOperand(1) == Op1.getOperand(1) && CC == ISD::SETEQ &&
isa<ConstantSDNode>(Op0.getOperand(1))) {
unsigned Bits = Op0.getValueSizeInBits();
if (b != Bits/8-1)
return false;
if (Op0.getConstantOperandVal(1) != Bits-8)
return false;
LHS = Op0.getOperand(0);
RHS = Op1.getOperand(0);
return true;
}
// When we have small integers (i16 to be specific), the form present
// post-legalization uses SETULT in the SELECT_CC for the
// higher-order byte, depending on the fact that the
// even-higher-order bytes are known to all be zero, for example:
// select_cc (xor $lhs, $rhs), 256, 65280, 0, setult
// (so when the second byte is the same, because all higher-order
// bits from bytes 3 and 4 are known to be zero, the result of the
// xor can be at most 255)
if (Op0.getOpcode() == ISD::XOR && CC == ISD::SETULT &&
isa<ConstantSDNode>(O.getOperand(1))) {
uint64_t ULim = O.getConstantOperandVal(1);
if (ULim != (UINT64_C(1) << b*8))
return false;
// Now we need to make sure that the upper bytes are known to be
// zero.
unsigned Bits = Op0.getValueSizeInBits();
if (!CurDAG->MaskedValueIsZero(
Op0, APInt::getHighBitsSet(Bits, Bits - (b + 1) * 8)))
return false;
LHS = Op0.getOperand(0);
RHS = Op0.getOperand(1);
return true;
}
return false;
}
if (CC != ISD::SETEQ)
return false;
SDValue Op = O.getOperand(0);
if (Op.getOpcode() == ISD::AND) {
if (!isa<ConstantSDNode>(Op.getOperand(1)))
return false;
if (Op.getConstantOperandVal(1) != (UINT64_C(0xFF) << (8*b)))
return false;
SDValue XOR = Op.getOperand(0);
if (XOR.getOpcode() == ISD::TRUNCATE)
XOR = XOR.getOperand(0);
if (XOR.getOpcode() != ISD::XOR)
return false;
LHS = XOR.getOperand(0);
RHS = XOR.getOperand(1);
return true;
} else if (Op.getOpcode() == ISD::SRL) {
if (!isa<ConstantSDNode>(Op.getOperand(1)))
return false;
unsigned Bits = Op.getValueSizeInBits();
if (b != Bits/8-1)
return false;
if (Op.getConstantOperandVal(1) != Bits-8)
return false;
SDValue XOR = Op.getOperand(0);
if (XOR.getOpcode() == ISD::TRUNCATE)
XOR = XOR.getOperand(0);
if (XOR.getOpcode() != ISD::XOR)
return false;
LHS = XOR.getOperand(0);
RHS = XOR.getOperand(1);
return true;
}
return false;
};
SmallVector<SDValue, 8> Queue(1, SDValue(N, 0));
while (!Queue.empty()) {
SDValue V = Queue.pop_back_val();
for (const SDValue &O : V.getNode()->ops()) {
unsigned b;
uint64_t M = 0, A = 0;
SDValue OLHS, ORHS;
if (O.getOpcode() == ISD::OR) {
Queue.push_back(O);
} else if (IsByteSelectCC(O, b, M, A, OLHS, ORHS)) {
if (!LHS) {
LHS = OLHS;
RHS = ORHS;
BytesFound[b] = true;
Mask |= M;
Alt |= A;
} else if ((LHS == ORHS && RHS == OLHS) ||
(RHS == ORHS && LHS == OLHS)) {
BytesFound[b] = true;
Mask |= M;
Alt |= A;
} else {
return Res;
}
} else {
return Res;
}
}
}
unsigned LastB = 0, BCnt = 0;
for (unsigned i = 0; i < 8; ++i)
if (BytesFound[LastB]) {
++BCnt;
LastB = i;
}
if (!LastB || BCnt < 2)
return Res;
// Because we'll be zero-extending the output anyway if don't have a specific
// value for each input byte (via the Mask), we can 'anyext' the inputs.
if (LHS.getValueType() != VT) {
LHS = CurDAG->getAnyExtOrTrunc(LHS, dl, VT);
RHS = CurDAG->getAnyExtOrTrunc(RHS, dl, VT);
}
Res = CurDAG->getNode(PPCISD::CMPB, dl, VT, LHS, RHS);
bool NonTrivialMask = ((int64_t) Mask) != INT64_C(-1);
if (NonTrivialMask && !Alt) {
// Res = Mask & CMPB
Res = CurDAG->getNode(ISD::AND, dl, VT, Res,
CurDAG->getConstant(Mask, dl, VT));
} else if (Alt) {
// Res = (CMPB & Mask) | (~CMPB & Alt)
// Which, as suggested here:
// https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge
// can be written as:
// Res = Alt ^ ((Alt ^ Mask) & CMPB)
// useful because the (Alt ^ Mask) can be pre-computed.
Res = CurDAG->getNode(ISD::AND, dl, VT, Res,
CurDAG->getConstant(Mask ^ Alt, dl, VT));
Res = CurDAG->getNode(ISD::XOR, dl, VT, Res,
CurDAG->getConstant(Alt, dl, VT));
}
return Res;
}
// When CR bit registers are enabled, an extension of an i1 variable to a i32
// or i64 value is lowered in terms of a SELECT_I[48] operation, and thus
// involves constant materialization of a 0 or a 1 or both. If the result of
// the extension is then operated upon by some operator that can be constant
// folded with a constant 0 or 1, and that constant can be materialized using
// only one instruction (like a zero or one), then we should fold in those
// operations with the select.
void PPCDAGToDAGISel::foldBoolExts(SDValue &Res, SDNode *&N) {
if (!PPCSubTarget->useCRBits())
return;
if (N->getOpcode() != ISD::ZERO_EXTEND &&
N->getOpcode() != ISD::SIGN_EXTEND &&
N->getOpcode() != ISD::ANY_EXTEND)
return;
if (N->getOperand(0).getValueType() != MVT::i1)
return;
if (!N->hasOneUse())
return;
SDLoc dl(N);
EVT VT = N->getValueType(0);
SDValue Cond = N->getOperand(0);
SDValue ConstTrue =
CurDAG->getConstant(N->getOpcode() == ISD::SIGN_EXTEND ? -1 : 1, dl, VT);
SDValue ConstFalse = CurDAG->getConstant(0, dl, VT);
do {
SDNode *User = *N->use_begin();
if (User->getNumOperands() != 2)
break;
auto TryFold = [this, N, User, dl](SDValue Val) {
SDValue UserO0 = User->getOperand(0), UserO1 = User->getOperand(1);
SDValue O0 = UserO0.getNode() == N ? Val : UserO0;
SDValue O1 = UserO1.getNode() == N ? Val : UserO1;
return CurDAG->FoldConstantArithmetic(User->getOpcode(), dl,
User->getValueType(0),
O0.getNode(), O1.getNode());
};
// FIXME: When the semantics of the interaction between select and undef
// are clearly defined, it may turn out to be unnecessary to break here.
SDValue TrueRes = TryFold(ConstTrue);
if (!TrueRes || TrueRes.isUndef())
break;
SDValue FalseRes = TryFold(ConstFalse);
if (!FalseRes || FalseRes.isUndef())
break;
// For us to materialize these using one instruction, we must be able to
// represent them as signed 16-bit integers.
uint64_t True = cast<ConstantSDNode>(TrueRes)->getZExtValue(),
False = cast<ConstantSDNode>(FalseRes)->getZExtValue();
if (!isInt<16>(True) || !isInt<16>(False))
break;
// We can replace User with a new SELECT node, and try again to see if we
// can fold the select with its user.
Res = CurDAG->getSelect(dl, User->getValueType(0), Cond, TrueRes, FalseRes);
N = User;
ConstTrue = TrueRes;
ConstFalse = FalseRes;
} while (N->hasOneUse());
}
void PPCDAGToDAGISel::PreprocessISelDAG() {
SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end();
bool MadeChange = false;
while (Position != CurDAG->allnodes_begin()) {
SDNode *N = &*--Position;
if (N->use_empty())
continue;
SDValue Res;
switch (N->getOpcode()) {
default: break;
case ISD::OR:
Res = combineToCMPB(N);
break;
}
if (!Res)
foldBoolExts(Res, N);
if (Res) {
LLVM_DEBUG(dbgs() << "PPC DAG preprocessing replacing:\nOld: ");
LLVM_DEBUG(N->dump(CurDAG));
LLVM_DEBUG(dbgs() << "\nNew: ");
LLVM_DEBUG(Res.getNode()->dump(CurDAG));
LLVM_DEBUG(dbgs() << "\n");
CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), Res);
MadeChange = true;
}
}
if (MadeChange)
CurDAG->RemoveDeadNodes();
}
/// PostprocessISelDAG - Perform some late peephole optimizations
/// on the DAG representation.
void PPCDAGToDAGISel::PostprocessISelDAG() {
// Skip peepholes at -O0.
if (TM.getOptLevel() == CodeGenOpt::None)
return;
PeepholePPC64();
PeepholeCROps();
PeepholePPC64ZExt();
}
// Check if all users of this node will become isel where the second operand
// is the constant zero. If this is so, and if we can negate the condition,
// then we can flip the true and false operands. This will allow the zero to
// be folded with the isel so that we don't need to materialize a register
// containing zero.
bool PPCDAGToDAGISel::AllUsersSelectZero(SDNode *N) {
for (SDNode::use_iterator UI = N->use_begin(), UE = N->use_end();
UI != UE; ++UI) {
SDNode *User = *UI;
if (!User->isMachineOpcode())
return false;
if (User->getMachineOpcode() != PPC::SELECT_I4 &&
User->getMachineOpcode() != PPC::SELECT_I8)
return false;
SDNode *Op2 = User->getOperand(2).getNode();
if (!Op2->isMachineOpcode())
return false;
if (Op2->getMachineOpcode() != PPC::LI &&
Op2->getMachineOpcode() != PPC::LI8)
return false;
ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op2->getOperand(0));
if (!C)
return false;
if (!C->isNullValue())
return false;
}
return true;
}
void PPCDAGToDAGISel::SwapAllSelectUsers(SDNode *N) {
SmallVector<SDNode *, 4> ToReplace;
for (SDNode::use_iterator UI = N->use_begin(), UE = N->use_end();
UI != UE; ++UI) {
SDNode *User = *UI;
assert((User->getMachineOpcode() == PPC::SELECT_I4 ||
User->getMachineOpcode() == PPC::SELECT_I8) &&
"Must have all select users");
ToReplace.push_back(User);
}
for (SmallVector<SDNode *, 4>::iterator UI = ToReplace.begin(),
UE = ToReplace.end(); UI != UE; ++UI) {
SDNode *User = *UI;
SDNode *ResNode =
CurDAG->getMachineNode(User->getMachineOpcode(), SDLoc(User),
User->getValueType(0), User->getOperand(0),
User->getOperand(2),
User->getOperand(1));
LLVM_DEBUG(dbgs() << "CR Peephole replacing:\nOld: ");
LLVM_DEBUG(User->dump(CurDAG));
LLVM_DEBUG(dbgs() << "\nNew: ");
LLVM_DEBUG(ResNode->dump(CurDAG));
LLVM_DEBUG(dbgs() << "\n");
ReplaceUses(User, ResNode);
}
}
void PPCDAGToDAGISel::PeepholeCROps() {
bool IsModified;
do {
IsModified = false;
for (SDNode &Node : CurDAG->allnodes()) {
MachineSDNode *MachineNode = dyn_cast<MachineSDNode>(&Node);
if (!MachineNode || MachineNode->use_empty())
continue;
SDNode *ResNode = MachineNode;
bool Op1Set = false, Op1Unset = false,
Op1Not = false,
Op2Set = false, Op2Unset = false,
Op2Not = false;
unsigned Opcode = MachineNode->getMachineOpcode();
switch (Opcode) {
default: break;
case PPC::CRAND:
case PPC::CRNAND:
case PPC::CROR:
case PPC::CRXOR:
case PPC::CRNOR:
case PPC::CREQV:
case PPC::CRANDC:
case PPC::CRORC: {
SDValue Op = MachineNode->getOperand(1);
if (Op.isMachineOpcode()) {
if (Op.getMachineOpcode() == PPC::CRSET)
Op2Set = true;
else if (Op.getMachineOpcode() == PPC::CRUNSET)
Op2Unset = true;
else if (Op.getMachineOpcode() == PPC::CRNOR &&
Op.getOperand(0) == Op.getOperand(1))
Op2Not = true;
}
LLVM_FALLTHROUGH;
}
case PPC::BC:
case PPC::BCn:
case PPC::SELECT_I4:
case PPC::SELECT_I8:
case PPC::SELECT_F4:
case PPC::SELECT_F8:
case PPC::SELECT_QFRC:
case PPC::SELECT_QSRC:
case PPC::SELECT_QBRC:
case PPC::SELECT_SPE:
case PPC::SELECT_SPE4:
case PPC::SELECT_VRRC:
case PPC::SELECT_VSFRC:
case PPC::SELECT_VSSRC:
case PPC::SELECT_VSRC: {
SDValue Op = MachineNode->getOperand(0);
if (Op.isMachineOpcode()) {
if (Op.getMachineOpcode() == PPC::CRSET)
Op1Set = true;
else if (Op.getMachineOpcode() == PPC::CRUNSET)
Op1Unset = true;
else if (Op.getMachineOpcode() == PPC::CRNOR &&
Op.getOperand(0) == Op.getOperand(1))
Op1Not = true;
}
}
break;
}
bool SelectSwap = false;
switch (Opcode) {
default: break;
case PPC::CRAND:
if (MachineNode->getOperand(0) == MachineNode->getOperand(1))
// x & x = x
ResNode = MachineNode->getOperand(0).getNode();
else if (Op1Set)
// 1 & y = y
ResNode = MachineNode->getOperand(1).getNode();
else if (Op2Set)
// x & 1 = x
ResNode = MachineNode->getOperand(0).getNode();
else if (Op1Unset || Op2Unset)
// x & 0 = 0 & y = 0
ResNode = CurDAG->getMachineNode(PPC::CRUNSET, SDLoc(MachineNode),
MVT::i1);
else if (Op1Not)
// ~x & y = andc(y, x)
ResNode = CurDAG->getMachineNode(PPC::CRANDC, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(1),
MachineNode->getOperand(0).
getOperand(0));
else if (Op2Not)
// x & ~y = andc(x, y)
ResNode = CurDAG->getMachineNode(PPC::CRANDC, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(1).
getOperand(0));
else if (AllUsersSelectZero(MachineNode)) {
ResNode = CurDAG->getMachineNode(PPC::CRNAND, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(1));
SelectSwap = true;
}
break;
case PPC::CRNAND:
if (MachineNode->getOperand(0) == MachineNode->getOperand(1))
// nand(x, x) -> nor(x, x)
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(0));
else if (Op1Set)
// nand(1, y) -> nor(y, y)
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(1),
MachineNode->getOperand(1));
else if (Op2Set)
// nand(x, 1) -> nor(x, x)
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(0));
else if (Op1Unset || Op2Unset)
// nand(x, 0) = nand(0, y) = 1
ResNode = CurDAG->getMachineNode(PPC::CRSET, SDLoc(MachineNode),
MVT::i1);
else if (Op1Not)
// nand(~x, y) = ~(~x & y) = x | ~y = orc(x, y)
ResNode = CurDAG->getMachineNode(PPC::CRORC, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0).
getOperand(0),
MachineNode->getOperand(1));
else if (Op2Not)
// nand(x, ~y) = ~x | y = orc(y, x)
ResNode = CurDAG->getMachineNode(PPC::CRORC, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(1).
getOperand(0),
MachineNode->getOperand(0));
else if (AllUsersSelectZero(MachineNode)) {
ResNode = CurDAG->getMachineNode(PPC::CRAND, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(1));
SelectSwap = true;
}
break;
case PPC::CROR:
if (MachineNode->getOperand(0) == MachineNode->getOperand(1))
// x | x = x
ResNode = MachineNode->getOperand(0).getNode();
else if (Op1Set || Op2Set)
// x | 1 = 1 | y = 1
ResNode = CurDAG->getMachineNode(PPC::CRSET, SDLoc(MachineNode),
MVT::i1);
else if (Op1Unset)
// 0 | y = y
ResNode = MachineNode->getOperand(1).getNode();
else if (Op2Unset)
// x | 0 = x
ResNode = MachineNode->getOperand(0).getNode();
else if (Op1Not)
// ~x | y = orc(y, x)
ResNode = CurDAG->getMachineNode(PPC::CRORC, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(1),
MachineNode->getOperand(0).
getOperand(0));
else if (Op2Not)
// x | ~y = orc(x, y)
ResNode = CurDAG->getMachineNode(PPC::CRORC, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(1).
getOperand(0));
else if (AllUsersSelectZero(MachineNode)) {
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(1));
SelectSwap = true;
}
break;
case PPC::CRXOR:
if (MachineNode->getOperand(0) == MachineNode->getOperand(1))
// xor(x, x) = 0
ResNode = CurDAG->getMachineNode(PPC::CRUNSET, SDLoc(MachineNode),
MVT::i1);
else if (Op1Set)
// xor(1, y) -> nor(y, y)
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(1),
MachineNode->getOperand(1));
else if (Op2Set)
// xor(x, 1) -> nor(x, x)
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(0));
else if (Op1Unset)
// xor(0, y) = y
ResNode = MachineNode->getOperand(1).getNode();
else if (Op2Unset)
// xor(x, 0) = x
ResNode = MachineNode->getOperand(0).getNode();
else if (Op1Not)
// xor(~x, y) = eqv(x, y)
ResNode = CurDAG->getMachineNode(PPC::CREQV, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0).
getOperand(0),
MachineNode->getOperand(1));
else if (Op2Not)
// xor(x, ~y) = eqv(x, y)
ResNode = CurDAG->getMachineNode(PPC::CREQV, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(1).
getOperand(0));
else if (AllUsersSelectZero(MachineNode)) {
ResNode = CurDAG->getMachineNode(PPC::CREQV, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(1));
SelectSwap = true;
}
break;
case PPC::CRNOR:
if (Op1Set || Op2Set)
// nor(1, y) -> 0
ResNode = CurDAG->getMachineNode(PPC::CRUNSET, SDLoc(MachineNode),
MVT::i1);
else if (Op1Unset)
// nor(0, y) = ~y -> nor(y, y)
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(1),
MachineNode->getOperand(1));
else if (Op2Unset)
// nor(x, 0) = ~x
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(0));
else if (Op1Not)
// nor(~x, y) = andc(x, y)
ResNode = CurDAG->getMachineNode(PPC::CRANDC, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0).
getOperand(0),
MachineNode->getOperand(1));
else if (Op2Not)
// nor(x, ~y) = andc(y, x)
ResNode = CurDAG->getMachineNode(PPC::CRANDC, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(1).
getOperand(0),
MachineNode->getOperand(0));
else if (AllUsersSelectZero(MachineNode)) {
ResNode = CurDAG->getMachineNode(PPC::CROR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(1));
SelectSwap = true;
}
break;
case PPC::CREQV:
if (MachineNode->getOperand(0) == MachineNode->getOperand(1))
// eqv(x, x) = 1
ResNode = CurDAG->getMachineNode(PPC::CRSET, SDLoc(MachineNode),
MVT::i1);
else if (Op1Set)
// eqv(1, y) = y
ResNode = MachineNode->getOperand(1).getNode();
else if (Op2Set)
// eqv(x, 1) = x
ResNode = MachineNode->getOperand(0).getNode();
else if (Op1Unset)
// eqv(0, y) = ~y -> nor(y, y)
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(1),
MachineNode->getOperand(1));
else if (Op2Unset)
// eqv(x, 0) = ~x
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(0));
else if (Op1Not)
// eqv(~x, y) = xor(x, y)
ResNode = CurDAG->getMachineNode(PPC::CRXOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0).
getOperand(0),
MachineNode->getOperand(1));
else if (Op2Not)
// eqv(x, ~y) = xor(x, y)
ResNode = CurDAG->getMachineNode(PPC::CRXOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(1).
getOperand(0));
else if (AllUsersSelectZero(MachineNode)) {
ResNode = CurDAG->getMachineNode(PPC::CRXOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(1));
SelectSwap = true;
}
break;
case PPC::CRANDC:
if (MachineNode->getOperand(0) == MachineNode->getOperand(1))
// andc(x, x) = 0
ResNode = CurDAG->getMachineNode(PPC::CRUNSET, SDLoc(MachineNode),
MVT::i1);
else if (Op1Set)
// andc(1, y) = ~y
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(1),
MachineNode->getOperand(1));
else if (Op1Unset || Op2Set)
// andc(0, y) = andc(x, 1) = 0
ResNode = CurDAG->getMachineNode(PPC::CRUNSET, SDLoc(MachineNode),
MVT::i1);
else if (Op2Unset)
// andc(x, 0) = x
ResNode = MachineNode->getOperand(0).getNode();
else if (Op1Not)
// andc(~x, y) = ~(x | y) = nor(x, y)
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0).
getOperand(0),
MachineNode->getOperand(1));
else if (Op2Not)
// andc(x, ~y) = x & y
ResNode = CurDAG->getMachineNode(PPC::CRAND, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(1).
getOperand(0));
else if (AllUsersSelectZero(MachineNode)) {
ResNode = CurDAG->getMachineNode(PPC::CRORC, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(1),
MachineNode->getOperand(0));
SelectSwap = true;
}
break;
case PPC::CRORC:
if (MachineNode->getOperand(0) == MachineNode->getOperand(1))
// orc(x, x) = 1
ResNode = CurDAG->getMachineNode(PPC::CRSET, SDLoc(MachineNode),
MVT::i1);
else if (Op1Set || Op2Unset)
// orc(1, y) = orc(x, 0) = 1
ResNode = CurDAG->getMachineNode(PPC::CRSET, SDLoc(MachineNode),
MVT::i1);
else if (Op2Set)
// orc(x, 1) = x
ResNode = MachineNode->getOperand(0).getNode();
else if (Op1Unset)
// orc(0, y) = ~y
ResNode = CurDAG->getMachineNode(PPC::CRNOR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(1),
MachineNode->getOperand(1));
else if (Op1Not)
// orc(~x, y) = ~(x & y) = nand(x, y)
ResNode = CurDAG->getMachineNode(PPC::CRNAND, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0).
getOperand(0),
MachineNode->getOperand(1));
else if (Op2Not)
// orc(x, ~y) = x | y
ResNode = CurDAG->getMachineNode(PPC::CROR, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(0),
MachineNode->getOperand(1).
getOperand(0));
else if (AllUsersSelectZero(MachineNode)) {
ResNode = CurDAG->getMachineNode(PPC::CRANDC, SDLoc(MachineNode),
MVT::i1, MachineNode->getOperand(1),
MachineNode->getOperand(0));
SelectSwap = true;
}
break;
case PPC::SELECT_I4:
case PPC::SELECT_I8:
case PPC::SELECT_F4:
case PPC::SELECT_F8:
case PPC::SELECT_QFRC:
case PPC::SELECT_QSRC:
case PPC::SELECT_QBRC:
case PPC::SELECT_SPE:
case PPC::SELECT_SPE4:
case PPC::SELECT_VRRC:
case PPC::SELECT_VSFRC:
case PPC::SELECT_VSSRC:
case PPC::SELECT_VSRC:
if (Op1Set)
ResNode = MachineNode->getOperand(1).getNode();
else if (Op1Unset)
ResNode = MachineNode->getOperand(2).getNode();
else if (Op1Not)
ResNode = CurDAG->getMachineNode(MachineNode->getMachineOpcode(),
SDLoc(MachineNode),
MachineNode->getValueType(0),
MachineNode->getOperand(0).
getOperand(0),
MachineNode->getOperand(2),
MachineNode->getOperand(1));
break;
case PPC::BC:
case PPC::BCn:
if (Op1Not)
ResNode = CurDAG->getMachineNode(Opcode == PPC::BC ? PPC::BCn :
PPC::BC,
SDLoc(MachineNode),
MVT::Other,
MachineNode->getOperand(0).
getOperand(0),
MachineNode->getOperand(1),
MachineNode->getOperand(2));
// FIXME: Handle Op1Set, Op1Unset here too.
break;
}
// If we're inverting this node because it is used only by selects that
// we'd like to swap, then swap the selects before the node replacement.
if (SelectSwap)
SwapAllSelectUsers(MachineNode);
if (ResNode != MachineNode) {
LLVM_DEBUG(dbgs() << "CR Peephole replacing:\nOld: ");
LLVM_DEBUG(MachineNode->dump(CurDAG));
LLVM_DEBUG(dbgs() << "\nNew: ");
LLVM_DEBUG(ResNode->dump(CurDAG));
LLVM_DEBUG(dbgs() << "\n");
ReplaceUses(MachineNode, ResNode);
IsModified = true;
}
}
if (IsModified)
CurDAG->RemoveDeadNodes();
} while (IsModified);
}
// Gather the set of 32-bit operations that are known to have their
// higher-order 32 bits zero, where ToPromote contains all such operations.
static bool PeepholePPC64ZExtGather(SDValue Op32,
SmallPtrSetImpl<SDNode *> &ToPromote) {
if (!Op32.isMachineOpcode())
return false;
// First, check for the "frontier" instructions (those that will clear the
// higher-order 32 bits.
// For RLWINM and RLWNM, we need to make sure that the mask does not wrap
// around. If it does not, then these instructions will clear the
// higher-order bits.
if ((Op32.getMachineOpcode() == PPC::RLWINM ||
Op32.getMachineOpcode() == PPC::RLWNM) &&
Op32.getConstantOperandVal(2) <= Op32.getConstantOperandVal(3)) {
ToPromote.insert(Op32.getNode());
return true;
}
// SLW and SRW always clear the higher-order bits.
if (Op32.getMachineOpcode() == PPC::SLW ||
Op32.getMachineOpcode() == PPC::SRW) {
ToPromote.insert(Op32.getNode());
return true;
}
// For LI and LIS, we need the immediate to be positive (so that it is not
// sign extended).
if (Op32.getMachineOpcode() == PPC::LI ||
Op32.getMachineOpcode() == PPC::LIS) {
if (!isUInt<15>(Op32.getConstantOperandVal(0)))
return false;
ToPromote.insert(Op32.getNode());
return true;
}
// LHBRX and LWBRX always clear the higher-order bits.
if (Op32.getMachineOpcode() == PPC::LHBRX ||
Op32.getMachineOpcode() == PPC::LWBRX) {
ToPromote.insert(Op32.getNode());
return true;
}
// CNT[LT]ZW always produce a 64-bit value in [0,32], and so is zero extended.
if (Op32.getMachineOpcode() == PPC::CNTLZW ||
Op32.getMachineOpcode() == PPC::CNTTZW) {
ToPromote.insert(Op32.getNode());
return true;
}
// Next, check for those instructions we can look through.
// Assuming the mask does not wrap around, then the higher-order bits are
// taken directly from the first operand.
if (Op32.getMachineOpcode() == PPC::RLWIMI &&
Op32.getConstantOperandVal(3) <= Op32.getConstantOperandVal(4)) {
SmallPtrSet<SDNode *, 16> ToPromote1;
if (!PeepholePPC64ZExtGather(Op32.getOperand(0), ToPromote1))
return false;
ToPromote.insert(Op32.getNode());
ToPromote.insert(ToPromote1.begin(), ToPromote1.end());
return true;
}
// For OR, the higher-order bits are zero if that is true for both operands.
// For SELECT_I4, the same is true (but the relevant operand numbers are
// shifted by 1).
if (Op32.getMachineOpcode() == PPC::OR ||
Op32.getMachineOpcode() == PPC::SELECT_I4) {
unsigned B = Op32.getMachineOpcode() == PPC::SELECT_I4 ? 1 : 0;
SmallPtrSet<SDNode *, 16> ToPromote1;
if (!PeepholePPC64ZExtGather(Op32.getOperand(B+0), ToPromote1))
return false;
if (!PeepholePPC64ZExtGather(Op32.getOperand(B+1), ToPromote1))
return false;
ToPromote.insert(Op32.getNode());
ToPromote.insert(ToPromote1.begin(), ToPromote1.end());
return true;
}
// For ORI and ORIS, we need the higher-order bits of the first operand to be
// zero, and also for the constant to be positive (so that it is not sign
// extended).
if (Op32.getMachineOpcode() == PPC::ORI ||
Op32.getMachineOpcode() == PPC::ORIS) {
SmallPtrSet<SDNode *, 16> ToPromote1;
if (!PeepholePPC64ZExtGather(Op32.getOperand(0), ToPromote1))
return false;
if (!isUInt<15>(Op32.getConstantOperandVal(1)))
return false;
ToPromote.insert(Op32.getNode());
ToPromote.insert(ToPromote1.begin(), ToPromote1.end());
return true;
}
// The higher-order bits of AND are zero if that is true for at least one of
// the operands.
if (Op32.getMachineOpcode() == PPC::AND) {
SmallPtrSet<SDNode *, 16> ToPromote1, ToPromote2;
bool Op0OK =
PeepholePPC64ZExtGather(Op32.getOperand(0), ToPromote1);
bool Op1OK =
PeepholePPC64ZExtGather(Op32.getOperand(1), ToPromote2);
if (!Op0OK && !Op1OK)
return false;
ToPromote.insert(Op32.getNode());
if (Op0OK)
ToPromote.insert(ToPromote1.begin(), ToPromote1.end());
if (Op1OK)
ToPromote.insert(ToPromote2.begin(), ToPromote2.end());
return true;
}
// For ANDI and ANDIS, the higher-order bits are zero if either that is true
// of the first operand, or if the second operand is positive (so that it is
// not sign extended).
if (Op32.getMachineOpcode() == PPC::ANDIo ||
Op32.getMachineOpcode() == PPC::ANDISo) {
SmallPtrSet<SDNode *, 16> ToPromote1;
bool Op0OK =
PeepholePPC64ZExtGather(Op32.getOperand(0), ToPromote1);
bool Op1OK = isUInt<15>(Op32.getConstantOperandVal(1));
if (!Op0OK && !Op1OK)
return false;
ToPromote.insert(Op32.getNode());
if (Op0OK)
ToPromote.insert(ToPromote1.begin(), ToPromote1.end());
return true;
}
return false;
}
void PPCDAGToDAGISel::PeepholePPC64ZExt() {
if (!PPCSubTarget->isPPC64())
return;
// When we zero-extend from i32 to i64, we use a pattern like this:
// def : Pat<(i64 (zext i32:$in)),
// (RLDICL (INSERT_SUBREG (i64 (IMPLICIT_DEF)), $in, sub_32),
// 0, 32)>;
// There are several 32-bit shift/rotate instructions, however, that will
// clear the higher-order bits of their output, rendering the RLDICL
// unnecessary. When that happens, we remove it here, and redefine the
// relevant 32-bit operation to be a 64-bit operation.
SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end();
bool MadeChange = false;
while (Position != CurDAG->allnodes_begin()) {
SDNode *N = &*--Position;
// Skip dead nodes and any non-machine opcodes.
if (N->use_empty() || !N->isMachineOpcode())
continue;
if (N->getMachineOpcode() != PPC::RLDICL)
continue;
if (N->getConstantOperandVal(1) != 0 ||
N->getConstantOperandVal(2) != 32)
continue;
SDValue ISR = N->getOperand(0);
if (!ISR.isMachineOpcode() ||
ISR.getMachineOpcode() != TargetOpcode::INSERT_SUBREG)
continue;
if (!ISR.hasOneUse())
continue;
if (ISR.getConstantOperandVal(2) != PPC::sub_32)
continue;
SDValue IDef = ISR.getOperand(0);
if (!IDef.isMachineOpcode() ||
IDef.getMachineOpcode() != TargetOpcode::IMPLICIT_DEF)
continue;
// We now know that we're looking at a canonical i32 -> i64 zext. See if we
// can get rid of it.
SDValue Op32 = ISR->getOperand(1);
if (!Op32.isMachineOpcode())
continue;
// There are some 32-bit instructions that always clear the high-order 32
// bits, there are also some instructions (like AND) that we can look
// through.
SmallPtrSet<SDNode *, 16> ToPromote;
if (!PeepholePPC64ZExtGather(Op32, ToPromote))
continue;
// If the ToPromote set contains nodes that have uses outside of the set
// (except for the original INSERT_SUBREG), then abort the transformation.
bool OutsideUse = false;
for (SDNode *PN : ToPromote) {
for (SDNode *UN : PN->uses()) {
if (!ToPromote.count(UN) && UN != ISR.getNode()) {
OutsideUse = true;
break;
}
}
if (OutsideUse)
break;
}
if (OutsideUse)
continue;
MadeChange = true;
// We now know that this zero extension can be removed by promoting to
// nodes in ToPromote to 64-bit operations, where for operations in the
// frontier of the set, we need to insert INSERT_SUBREGs for their
// operands.
for (SDNode *PN : ToPromote) {
unsigned NewOpcode;
switch (PN->getMachineOpcode()) {
default:
llvm_unreachable("Don't know the 64-bit variant of this instruction");
case PPC::RLWINM: NewOpcode = PPC::RLWINM8; break;
case PPC::RLWNM: NewOpcode = PPC::RLWNM8; break;
case PPC::SLW: NewOpcode = PPC::SLW8; break;
case PPC::SRW: NewOpcode = PPC::SRW8; break;
case PPC::LI: NewOpcode = PPC::LI8; break;
case PPC::LIS: NewOpcode = PPC::LIS8; break;
case PPC::LHBRX: NewOpcode = PPC::LHBRX8; break;
case PPC::LWBRX: NewOpcode = PPC::LWBRX8; break;
case PPC::CNTLZW: NewOpcode = PPC::CNTLZW8; break;
case PPC::CNTTZW: NewOpcode = PPC::CNTTZW8; break;
case PPC::RLWIMI: NewOpcode = PPC::RLWIMI8; break;
case PPC::OR: NewOpcode = PPC::OR8; break;
case PPC::SELECT_I4: NewOpcode = PPC::SELECT_I8; break;
case PPC::ORI: NewOpcode = PPC::ORI8; break;
case PPC::ORIS: NewOpcode = PPC::ORIS8; break;
case PPC::AND: NewOpcode = PPC::AND8; break;
case PPC::ANDIo: NewOpcode = PPC::ANDIo8; break;
case PPC::ANDISo: NewOpcode = PPC::ANDISo8; break;
}
// Note: During the replacement process, the nodes will be in an
// inconsistent state (some instructions will have operands with values
// of the wrong type). Once done, however, everything should be right
// again.
SmallVector<SDValue, 4> Ops;
for (const SDValue &V : PN->ops()) {
if (!ToPromote.count(V.getNode()) && V.getValueType() == MVT::i32 &&
!isa<ConstantSDNode>(V)) {
SDValue ReplOpOps[] = { ISR.getOperand(0), V, ISR.getOperand(2) };
SDNode *ReplOp =
CurDAG->getMachineNode(TargetOpcode::INSERT_SUBREG, SDLoc(V),
ISR.getNode()->getVTList(), ReplOpOps);
Ops.push_back(SDValue(ReplOp, 0));
} else {
Ops.push_back(V);
}
}
// Because all to-be-promoted nodes only have users that are other
// promoted nodes (or the original INSERT_SUBREG), we can safely replace
// the i32 result value type with i64.
SmallVector<EVT, 2> NewVTs;
SDVTList VTs = PN->getVTList();
for (unsigned i = 0, ie = VTs.NumVTs; i != ie; ++i)
if (VTs.VTs[i] == MVT::i32)
NewVTs.push_back(MVT::i64);
else
NewVTs.push_back(VTs.VTs[i]);
LLVM_DEBUG(dbgs() << "PPC64 ZExt Peephole morphing:\nOld: ");
LLVM_DEBUG(PN->dump(CurDAG));
CurDAG->SelectNodeTo(PN, NewOpcode, CurDAG->getVTList(NewVTs), Ops);
LLVM_DEBUG(dbgs() << "\nNew: ");
LLVM_DEBUG(PN->dump(CurDAG));
LLVM_DEBUG(dbgs() << "\n");
}
// Now we replace the original zero extend and its associated INSERT_SUBREG
// with the value feeding the INSERT_SUBREG (which has now been promoted to
// return an i64).
LLVM_DEBUG(dbgs() << "PPC64 ZExt Peephole replacing:\nOld: ");
LLVM_DEBUG(N->dump(CurDAG));
LLVM_DEBUG(dbgs() << "\nNew: ");
LLVM_DEBUG(Op32.getNode()->dump(CurDAG));
LLVM_DEBUG(dbgs() << "\n");
ReplaceUses(N, Op32.getNode());
}
if (MadeChange)
CurDAG->RemoveDeadNodes();
}
void PPCDAGToDAGISel::PeepholePPC64() {
// These optimizations are currently supported only for 64-bit SVR4.
if (PPCSubTarget->isDarwin() || !PPCSubTarget->isPPC64())
return;
SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end();
while (Position != CurDAG->allnodes_begin()) {
SDNode *N = &*--Position;
// Skip dead nodes and any non-machine opcodes.
if (N->use_empty() || !N->isMachineOpcode())
continue;
unsigned FirstOp;
unsigned StorageOpcode = N->getMachineOpcode();
bool RequiresMod4Offset = false;
switch (StorageOpcode) {
default: continue;
case PPC::LWA:
case PPC::LD:
case PPC::DFLOADf64:
case PPC::DFLOADf32:
RequiresMod4Offset = true;
LLVM_FALLTHROUGH;
case PPC::LBZ:
case PPC::LBZ8:
case PPC::LFD:
case PPC::LFS:
case PPC::LHA:
case PPC::LHA8:
case PPC::LHZ:
case PPC::LHZ8:
case PPC::LWZ:
case PPC::LWZ8:
FirstOp = 0;
break;
case PPC::STD:
case PPC::DFSTOREf64:
case PPC::DFSTOREf32:
RequiresMod4Offset = true;
LLVM_FALLTHROUGH;
case PPC::STB:
case PPC::STB8:
case PPC::STFD:
case PPC::STFS:
case PPC::STH:
case PPC::STH8:
case PPC::STW:
case PPC::STW8:
FirstOp = 1;
break;
}
// If this is a load or store with a zero offset, or within the alignment,
// we may be able to fold an add-immediate into the memory operation.
// The check against alignment is below, as it can't occur until we check
// the arguments to N
if (!isa<ConstantSDNode>(N->getOperand(FirstOp)))
continue;
SDValue Base = N->getOperand(FirstOp + 1);
if (!Base.isMachineOpcode())
continue;
unsigned Flags = 0;
bool ReplaceFlags = true;
// When the feeding operation is an add-immediate of some sort,
// determine whether we need to add relocation information to the
// target flags on the immediate operand when we fold it into the
// load instruction.
//
// For something like ADDItocL, the relocation information is
// inferred from the opcode; when we process it in the AsmPrinter,
// we add the necessary relocation there. A load, though, can receive
// relocation from various flavors of ADDIxxx, so we need to carry
// the relocation information in the target flags.
switch (Base.getMachineOpcode()) {
default: continue;
case PPC::ADDI8:
case PPC::ADDI:
// In some cases (such as TLS) the relocation information
// is already in place on the operand, so copying the operand
// is sufficient.
ReplaceFlags = false;
// For these cases, the immediate may not be divisible by 4, in
// which case the fold is illegal for DS-form instructions. (The
// other cases provide aligned addresses and are always safe.)
if (RequiresMod4Offset &&
(!isa<ConstantSDNode>(Base.getOperand(1)) ||
Base.getConstantOperandVal(1) % 4 != 0))
continue;
break;
case PPC::ADDIdtprelL:
Flags = PPCII::MO_DTPREL_LO;
break;
case PPC::ADDItlsldL:
Flags = PPCII::MO_TLSLD_LO;
break;
case PPC::ADDItocL:
Flags = PPCII::MO_TOC_LO;
break;
}
SDValue ImmOpnd = Base.getOperand(1);
// On PPC64, the TOC base pointer is guaranteed by the ABI only to have
// 8-byte alignment, and so we can only use offsets less than 8 (otherwise,
// we might have needed different @ha relocation values for the offset
// pointers).
int MaxDisplacement = 7;
if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(ImmOpnd)) {
const GlobalValue *GV = GA->getGlobal();
MaxDisplacement = std::min((int) GV->getAlignment() - 1, MaxDisplacement);
}
bool UpdateHBase = false;
SDValue HBase = Base.getOperand(0);
int Offset = N->getConstantOperandVal(FirstOp);
if (ReplaceFlags) {
if (Offset < 0 || Offset > MaxDisplacement) {
// If we have a addi(toc@l)/addis(toc@ha) pair, and the addis has only
// one use, then we can do this for any offset, we just need to also
// update the offset (i.e. the symbol addend) on the addis also.
if (Base.getMachineOpcode() != PPC::ADDItocL)
continue;
if (!HBase.isMachineOpcode() ||
HBase.getMachineOpcode() != PPC::ADDIStocHA)
continue;
if (!Base.hasOneUse() || !HBase.hasOneUse())
continue;
SDValue HImmOpnd = HBase.getOperand(1);
if (HImmOpnd != ImmOpnd)
continue;
UpdateHBase = true;
}
} else {
// If we're directly folding the addend from an addi instruction, then:
// 1. In general, the offset on the memory access must be zero.
// 2. If the addend is a constant, then it can be combined with a
// non-zero offset, but only if the result meets the encoding
// requirements.
if (auto *C = dyn_cast<ConstantSDNode>(ImmOpnd)) {
Offset += C->getSExtValue();
if (RequiresMod4Offset && (Offset % 4) != 0)
continue;
if (!isInt<16>(Offset))
continue;
ImmOpnd = CurDAG->getTargetConstant(Offset, SDLoc(ImmOpnd),
ImmOpnd.getValueType());
} else if (Offset != 0) {
continue;
}
}
// We found an opportunity. Reverse the operands from the add
// immediate and substitute them into the load or store. If
// needed, update the target flags for the immediate operand to
// reflect the necessary relocation information.
LLVM_DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase: ");
LLVM_DEBUG(Base->dump(CurDAG));
LLVM_DEBUG(dbgs() << "\nN: ");
LLVM_DEBUG(N->dump(CurDAG));
LLVM_DEBUG(dbgs() << "\n");
// If the relocation information isn't already present on the
// immediate operand, add it now.
if (ReplaceFlags) {
if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(ImmOpnd)) {
SDLoc dl(GA);
const GlobalValue *GV = GA->getGlobal();
// We can't perform this optimization for data whose alignment
// is insufficient for the instruction encoding.
if (GV->getAlignment() < 4 &&
(RequiresMod4Offset || (Offset % 4) != 0)) {
LLVM_DEBUG(dbgs() << "Rejected this candidate for alignment.\n\n");
continue;
}
ImmOpnd = CurDAG->getTargetGlobalAddress(GV, dl, MVT::i64, Offset, Flags);
} else if (ConstantPoolSDNode *CP =
dyn_cast<ConstantPoolSDNode>(ImmOpnd)) {
const Constant *C = CP->getConstVal();
ImmOpnd = CurDAG->getTargetConstantPool(C, MVT::i64,
CP->getAlignment(),
Offset, Flags);
}
}
if (FirstOp == 1) // Store
(void)CurDAG->UpdateNodeOperands(N, N->getOperand(0), ImmOpnd,
Base.getOperand(0), N->getOperand(3));
else // Load
(void)CurDAG->UpdateNodeOperands(N, ImmOpnd, Base.getOperand(0),
N->getOperand(2));
if (UpdateHBase)
(void)CurDAG->UpdateNodeOperands(HBase.getNode(), HBase.getOperand(0),
ImmOpnd);
// The add-immediate may now be dead, in which case remove it.
if (Base.getNode()->use_empty())
CurDAG->RemoveDeadNode(Base.getNode());
}
}
/// createPPCISelDag - This pass converts a legalized DAG into a
/// PowerPC-specific DAG, ready for instruction scheduling.
///
FunctionPass *llvm::createPPCISelDag(PPCTargetMachine &TM,
CodeGenOpt::Level OptLevel) {
return new PPCDAGToDAGISel(TM, OptLevel);
}
Index: stable/11/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td
===================================================================
--- stable/11/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td (revision 350259)
@@ -1,4958 +1,4960 @@
//===-- PPCInstrInfo.td - The PowerPC Instruction Set ------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the subset of the 32-bit PowerPC instruction set, as used
// by the PowerPC instruction selector.
//
//===----------------------------------------------------------------------===//
include "PPCInstrFormats.td"
//===----------------------------------------------------------------------===//
// PowerPC specific type constraints.
//
def SDT_PPCstfiwx : SDTypeProfile<0, 2, [ // stfiwx
SDTCisVT<0, f64>, SDTCisPtrTy<1>
]>;
def SDT_PPClfiwx : SDTypeProfile<1, 1, [ // lfiw[az]x
SDTCisVT<0, f64>, SDTCisPtrTy<1>
]>;
def SDT_PPCLxsizx : SDTypeProfile<1, 2, [
SDTCisVT<0, f64>, SDTCisPtrTy<1>, SDTCisPtrTy<2>
]>;
def SDT_PPCstxsix : SDTypeProfile<0, 3, [
SDTCisVT<0, f64>, SDTCisPtrTy<1>, SDTCisPtrTy<2>
]>;
def SDT_PPCcv_fp_to_int : SDTypeProfile<1, 1, [
SDTCisFP<0>, SDTCisFP<1>
]>;
def SDT_PPCstore_scal_int_from_vsr : SDTypeProfile<0, 3, [
SDTCisVT<0, f64>, SDTCisPtrTy<1>, SDTCisPtrTy<2>
]>;
def SDT_PPCVexts : SDTypeProfile<1, 2, [
SDTCisVT<0, f64>, SDTCisVT<1, f64>, SDTCisPtrTy<2>
]>;
def SDT_PPCSExtVElems : SDTypeProfile<1, 1, [
SDTCisVec<0>, SDTCisVec<1>
]>;
def SDT_PPCCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32>,
SDTCisVT<1, i32> ]>;
def SDT_PPCCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>,
SDTCisVT<1, i32> ]>;
def SDT_PPCvperm : SDTypeProfile<1, 3, [
SDTCisVT<3, v16i8>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>
]>;
def SDT_PPCVecSplat : SDTypeProfile<1, 2, [ SDTCisVec<0>,
SDTCisVec<1>, SDTCisInt<2>
]>;
def SDT_PPCVecShift : SDTypeProfile<1, 3, [ SDTCisVec<0>,
SDTCisVec<1>, SDTCisVec<2>, SDTCisPtrTy<3>
]>;
def SDT_PPCVecInsert : SDTypeProfile<1, 3, [ SDTCisVec<0>,
SDTCisVec<1>, SDTCisVec<2>, SDTCisInt<3>
]>;
def SDT_PPCVecReverse: SDTypeProfile<1, 1, [ SDTCisVec<0>,
SDTCisVec<1>
]>;
def SDT_PPCxxpermdi: SDTypeProfile<1, 3, [ SDTCisVec<0>,
SDTCisVec<1>, SDTCisVec<2>, SDTCisInt<3>
]>;
def SDT_PPCvcmp : SDTypeProfile<1, 3, [
SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>, SDTCisVT<3, i32>
]>;
def SDT_PPCcondbr : SDTypeProfile<0, 3, [
SDTCisVT<0, i32>, SDTCisVT<2, OtherVT>
]>;
def SDT_PPClbrx : SDTypeProfile<1, 2, [
SDTCisInt<0>, SDTCisPtrTy<1>, SDTCisVT<2, OtherVT>
]>;
def SDT_PPCstbrx : SDTypeProfile<0, 3, [
SDTCisInt<0>, SDTCisPtrTy<1>, SDTCisVT<2, OtherVT>
]>;
def SDT_PPCTC_ret : SDTypeProfile<0, 2, [
SDTCisPtrTy<0>, SDTCisVT<1, i32>
]>;
def tocentry32 : Operand<iPTR> {
let MIOperandInfo = (ops i32imm:$imm);
}
def SDT_PPCqvfperm : SDTypeProfile<1, 3, [
SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisVec<3>
]>;
def SDT_PPCqvgpci : SDTypeProfile<1, 1, [
SDTCisVec<0>, SDTCisInt<1>
]>;
def SDT_PPCqvaligni : SDTypeProfile<1, 3, [
SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisInt<3>
]>;
def SDT_PPCqvesplati : SDTypeProfile<1, 2, [
SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisInt<2>
]>;
def SDT_PPCqbflt : SDTypeProfile<1, 1, [
SDTCisVec<0>, SDTCisVec<1>
]>;
def SDT_PPCqvlfsb : SDTypeProfile<1, 1, [
SDTCisVec<0>, SDTCisPtrTy<1>
]>;
def SDT_PPCextswsli : SDTypeProfile<1, 2, [ // extswsli
SDTCisInt<0>, SDTCisInt<1>, SDTCisOpSmallerThanOp<1, 0>, SDTCisInt<2>
]>;
//===----------------------------------------------------------------------===//
// PowerPC specific DAG Nodes.
//
def PPCfre : SDNode<"PPCISD::FRE", SDTFPUnaryOp, []>;
def PPCfrsqrte: SDNode<"PPCISD::FRSQRTE", SDTFPUnaryOp, []>;
def PPCfcfid : SDNode<"PPCISD::FCFID", SDTFPUnaryOp, []>;
def PPCfcfidu : SDNode<"PPCISD::FCFIDU", SDTFPUnaryOp, []>;
def PPCfcfids : SDNode<"PPCISD::FCFIDS", SDTFPRoundOp, []>;
def PPCfcfidus: SDNode<"PPCISD::FCFIDUS", SDTFPRoundOp, []>;
def PPCfctidz : SDNode<"PPCISD::FCTIDZ", SDTFPUnaryOp, []>;
def PPCfctiwz : SDNode<"PPCISD::FCTIWZ", SDTFPUnaryOp, []>;
def PPCfctiduz: SDNode<"PPCISD::FCTIDUZ",SDTFPUnaryOp, []>;
def PPCfctiwuz: SDNode<"PPCISD::FCTIWUZ",SDTFPUnaryOp, []>;
def PPCcv_fp_to_uint_in_vsr:
SDNode<"PPCISD::FP_TO_UINT_IN_VSR", SDT_PPCcv_fp_to_int, []>;
def PPCcv_fp_to_sint_in_vsr:
SDNode<"PPCISD::FP_TO_SINT_IN_VSR", SDT_PPCcv_fp_to_int, []>;
def PPCstore_scal_int_from_vsr:
SDNode<"PPCISD::ST_VSR_SCAL_INT", SDT_PPCstore_scal_int_from_vsr,
[SDNPHasChain, SDNPMayStore]>;
def PPCstfiwx : SDNode<"PPCISD::STFIWX", SDT_PPCstfiwx,
[SDNPHasChain, SDNPMayStore]>;
def PPClfiwax : SDNode<"PPCISD::LFIWAX", SDT_PPClfiwx,
[SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
def PPClfiwzx : SDNode<"PPCISD::LFIWZX", SDT_PPClfiwx,
[SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
def PPClxsizx : SDNode<"PPCISD::LXSIZX", SDT_PPCLxsizx,
[SDNPHasChain, SDNPMayLoad]>;
def PPCstxsix : SDNode<"PPCISD::STXSIX", SDT_PPCstxsix,
[SDNPHasChain, SDNPMayStore]>;
def PPCVexts : SDNode<"PPCISD::VEXTS", SDT_PPCVexts, []>;
def PPCSExtVElems : SDNode<"PPCISD::SExtVElems", SDT_PPCSExtVElems, []>;
// Extract FPSCR (not modeled at the DAG level).
def PPCmffs : SDNode<"PPCISD::MFFS",
SDTypeProfile<1, 0, [SDTCisVT<0, f64>]>, []>;
// Perform FADD in round-to-zero mode.
def PPCfaddrtz: SDNode<"PPCISD::FADDRTZ", SDTFPBinOp, []>;
def PPCfsel : SDNode<"PPCISD::FSEL",
// Type constraint for fsel.
SDTypeProfile<1, 3, [SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>,
SDTCisFP<0>, SDTCisVT<1, f64>]>, []>;
def PPChi : SDNode<"PPCISD::Hi", SDTIntBinOp, []>;
def PPClo : SDNode<"PPCISD::Lo", SDTIntBinOp, []>;
def PPCtoc_entry: SDNode<"PPCISD::TOC_ENTRY", SDTIntBinOp,
[SDNPMayLoad, SDNPMemOperand]>;
def PPCvmaddfp : SDNode<"PPCISD::VMADDFP", SDTFPTernaryOp, []>;
def PPCvnmsubfp : SDNode<"PPCISD::VNMSUBFP", SDTFPTernaryOp, []>;
def PPCppc32GOT : SDNode<"PPCISD::PPC32_GOT", SDTIntLeaf, []>;
def PPCaddisGotTprelHA : SDNode<"PPCISD::ADDIS_GOT_TPREL_HA", SDTIntBinOp>;
def PPCldGotTprelL : SDNode<"PPCISD::LD_GOT_TPREL_L", SDTIntBinOp,
[SDNPMayLoad]>;
def PPCaddTls : SDNode<"PPCISD::ADD_TLS", SDTIntBinOp, []>;
def PPCaddisTlsgdHA : SDNode<"PPCISD::ADDIS_TLSGD_HA", SDTIntBinOp>;
def PPCaddiTlsgdL : SDNode<"PPCISD::ADDI_TLSGD_L", SDTIntBinOp>;
def PPCgetTlsAddr : SDNode<"PPCISD::GET_TLS_ADDR", SDTIntBinOp>;
def PPCaddiTlsgdLAddr : SDNode<"PPCISD::ADDI_TLSGD_L_ADDR",
SDTypeProfile<1, 3, [
SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>,
SDTCisSameAs<0, 3>, SDTCisInt<0> ]>>;
def PPCaddisTlsldHA : SDNode<"PPCISD::ADDIS_TLSLD_HA", SDTIntBinOp>;
def PPCaddiTlsldL : SDNode<"PPCISD::ADDI_TLSLD_L", SDTIntBinOp>;
def PPCgetTlsldAddr : SDNode<"PPCISD::GET_TLSLD_ADDR", SDTIntBinOp>;
def PPCaddiTlsldLAddr : SDNode<"PPCISD::ADDI_TLSLD_L_ADDR",
SDTypeProfile<1, 3, [
SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>,
SDTCisSameAs<0, 3>, SDTCisInt<0> ]>>;
def PPCaddisDtprelHA : SDNode<"PPCISD::ADDIS_DTPREL_HA", SDTIntBinOp>;
def PPCaddiDtprelL : SDNode<"PPCISD::ADDI_DTPREL_L", SDTIntBinOp>;
def PPCvperm : SDNode<"PPCISD::VPERM", SDT_PPCvperm, []>;
def PPCxxsplt : SDNode<"PPCISD::XXSPLT", SDT_PPCVecSplat, []>;
def PPCvecinsert : SDNode<"PPCISD::VECINSERT", SDT_PPCVecInsert, []>;
def PPCxxreverse : SDNode<"PPCISD::XXREVERSE", SDT_PPCVecReverse, []>;
def PPCxxpermdi : SDNode<"PPCISD::XXPERMDI", SDT_PPCxxpermdi, []>;
def PPCvecshl : SDNode<"PPCISD::VECSHL", SDT_PPCVecShift, []>;
def PPCqvfperm : SDNode<"PPCISD::QVFPERM", SDT_PPCqvfperm, []>;
def PPCqvgpci : SDNode<"PPCISD::QVGPCI", SDT_PPCqvgpci, []>;
def PPCqvaligni : SDNode<"PPCISD::QVALIGNI", SDT_PPCqvaligni, []>;
def PPCqvesplati : SDNode<"PPCISD::QVESPLATI", SDT_PPCqvesplati, []>;
def PPCqbflt : SDNode<"PPCISD::QBFLT", SDT_PPCqbflt, []>;
def PPCqvlfsb : SDNode<"PPCISD::QVLFSb", SDT_PPCqvlfsb,
[SDNPHasChain, SDNPMayLoad]>;
def PPCcmpb : SDNode<"PPCISD::CMPB", SDTIntBinOp, []>;
// These nodes represent the 32-bit PPC shifts that operate on 6-bit shift
// amounts. These nodes are generated by the multi-precision shift code.
def PPCsrl : SDNode<"PPCISD::SRL" , SDTIntShiftOp>;
def PPCsra : SDNode<"PPCISD::SRA" , SDTIntShiftOp>;
def PPCshl : SDNode<"PPCISD::SHL" , SDTIntShiftOp>;
def PPCextswsli : SDNode<"PPCISD::EXTSWSLI" , SDT_PPCextswsli>;
// Move 2 i64 values into a VSX register
def PPCbuild_fp128: SDNode<"PPCISD::BUILD_FP128",
SDTypeProfile<1, 2,
[SDTCisFP<0>, SDTCisSameSizeAs<1,2>,
SDTCisSameAs<1,2>]>,
[]>;
// These are target-independent nodes, but have target-specific formats.
def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_PPCCallSeqStart,
[SDNPHasChain, SDNPOutGlue]>;
def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_PPCCallSeqEnd,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
def SDT_PPCCall : SDTypeProfile<0, -1, [SDTCisInt<0>]>;
def PPCcall : SDNode<"PPCISD::CALL", SDT_PPCCall,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
SDNPVariadic]>;
def PPCcall_nop : SDNode<"PPCISD::CALL_NOP", SDT_PPCCall,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
SDNPVariadic]>;
def PPCmtctr : SDNode<"PPCISD::MTCTR", SDT_PPCCall,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
def PPCbctrl : SDNode<"PPCISD::BCTRL", SDTNone,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
SDNPVariadic]>;
def PPCbctrl_load_toc : SDNode<"PPCISD::BCTRL_LOAD_TOC",
SDTypeProfile<0, 1, []>,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
SDNPVariadic]>;
def retflag : SDNode<"PPCISD::RET_FLAG", SDTNone,
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
def PPCtc_return : SDNode<"PPCISD::TC_RETURN", SDT_PPCTC_ret,
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
def PPCeh_sjlj_setjmp : SDNode<"PPCISD::EH_SJLJ_SETJMP",
SDTypeProfile<1, 1, [SDTCisInt<0>,
SDTCisPtrTy<1>]>,
[SDNPHasChain, SDNPSideEffect]>;
def PPCeh_sjlj_longjmp : SDNode<"PPCISD::EH_SJLJ_LONGJMP",
SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>,
[SDNPHasChain, SDNPSideEffect]>;
def SDT_PPCsc : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
def PPCsc : SDNode<"PPCISD::SC", SDT_PPCsc,
[SDNPHasChain, SDNPSideEffect]>;
def PPCclrbhrb : SDNode<"PPCISD::CLRBHRB", SDTNone,
[SDNPHasChain, SDNPSideEffect]>;
def PPCmfbhrbe : SDNode<"PPCISD::MFBHRBE", SDTIntBinOp, [SDNPHasChain]>;
def PPCrfebb : SDNode<"PPCISD::RFEBB", SDT_PPCsc,
[SDNPHasChain, SDNPSideEffect]>;
def PPCvcmp : SDNode<"PPCISD::VCMP" , SDT_PPCvcmp, []>;
def PPCvcmp_o : SDNode<"PPCISD::VCMPo", SDT_PPCvcmp, [SDNPOutGlue]>;
def PPCcondbranch : SDNode<"PPCISD::COND_BRANCH", SDT_PPCcondbr,
[SDNPHasChain, SDNPOptInGlue]>;
// PPC-specific atomic operations.
def PPCatomicCmpSwap_8 :
SDNode<"PPCISD::ATOMIC_CMP_SWAP_8", SDTAtomic3,
[SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>;
def PPCatomicCmpSwap_16 :
SDNode<"PPCISD::ATOMIC_CMP_SWAP_16", SDTAtomic3,
[SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>;
def PPClbrx : SDNode<"PPCISD::LBRX", SDT_PPClbrx,
[SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
def PPCstbrx : SDNode<"PPCISD::STBRX", SDT_PPCstbrx,
[SDNPHasChain, SDNPMayStore]>;
// Instructions to set/unset CR bit 6 for SVR4 vararg calls
def PPCcr6set : SDNode<"PPCISD::CR6SET", SDTNone,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
def PPCcr6unset : SDNode<"PPCISD::CR6UNSET", SDTNone,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
// Instructions to support dynamic alloca.
def SDTDynOp : SDTypeProfile<1, 2, []>;
def SDTDynAreaOp : SDTypeProfile<1, 1, []>;
def PPCdynalloc : SDNode<"PPCISD::DYNALLOC", SDTDynOp, [SDNPHasChain]>;
def PPCdynareaoffset : SDNode<"PPCISD::DYNAREAOFFSET", SDTDynAreaOp, [SDNPHasChain]>;
//===----------------------------------------------------------------------===//
// PowerPC specific transformation functions and pattern fragments.
//
def SHL32 : SDNodeXForm<imm, [{
// Transformation function: 31 - imm
return getI32Imm(31 - N->getZExtValue(), SDLoc(N));
}]>;
def SRL32 : SDNodeXForm<imm, [{
// Transformation function: 32 - imm
return N->getZExtValue() ? getI32Imm(32 - N->getZExtValue(), SDLoc(N))
: getI32Imm(0, SDLoc(N));
}]>;
def LO16 : SDNodeXForm<imm, [{
// Transformation function: get the low 16 bits.
return getI32Imm((unsigned short)N->getZExtValue(), SDLoc(N));
}]>;
def HI16 : SDNodeXForm<imm, [{
// Transformation function: shift the immediate value down into the low bits.
return getI32Imm((unsigned)N->getZExtValue() >> 16, SDLoc(N));
}]>;
def HA16 : SDNodeXForm<imm, [{
// Transformation function: shift the immediate value down into the low bits.
long Val = N->getZExtValue();
return getI32Imm((Val - (signed short)Val) >> 16, SDLoc(N));
}]>;
def MB : SDNodeXForm<imm, [{
// Transformation function: get the start bit of a mask
unsigned mb = 0, me;
(void)isRunOfOnes((unsigned)N->getZExtValue(), mb, me);
return getI32Imm(mb, SDLoc(N));
}]>;
def ME : SDNodeXForm<imm, [{
// Transformation function: get the end bit of a mask
unsigned mb, me = 0;
(void)isRunOfOnes((unsigned)N->getZExtValue(), mb, me);
return getI32Imm(me, SDLoc(N));
}]>;
def maskimm32 : PatLeaf<(imm), [{
// maskImm predicate - True if immediate is a run of ones.
unsigned mb, me;
if (N->getValueType(0) == MVT::i32)
return isRunOfOnes((unsigned)N->getZExtValue(), mb, me);
else
return false;
}]>;
def imm32SExt16 : Operand<i32>, ImmLeaf<i32, [{
// imm32SExt16 predicate - True if the i32 immediate fits in a 16-bit
// sign extended field. Used by instructions like 'addi'.
return (int32_t)Imm == (short)Imm;
}]>;
def imm64SExt16 : Operand<i64>, ImmLeaf<i64, [{
// imm64SExt16 predicate - True if the i64 immediate fits in a 16-bit
// sign extended field. Used by instructions like 'addi'.
return (int64_t)Imm == (short)Imm;
}]>;
def immZExt16 : PatLeaf<(imm), [{
// immZExt16 predicate - True if the immediate fits in a 16-bit zero extended
// field. Used by instructions like 'ori'.
return (uint64_t)N->getZExtValue() == (unsigned short)N->getZExtValue();
}], LO16>;
def immAnyExt8 : ImmLeaf<i32, [{ return isInt<8>(Imm) || isUInt<8>(Imm); }]>;
def immSExt5NonZero : ImmLeaf<i32, [{ return Imm && isInt<5>(Imm); }]>;
// imm16Shifted* - These match immediates where the low 16-bits are zero. There
// are two forms: imm16ShiftedSExt and imm16ShiftedZExt. These two forms are
// identical in 32-bit mode, but in 64-bit mode, they return true if the
// immediate fits into a sign/zero extended 32-bit immediate (with the low bits
// clear).
def imm16ShiftedZExt : PatLeaf<(imm), [{
// imm16ShiftedZExt predicate - True if only bits in the top 16-bits of the
// immediate are set. Used by instructions like 'xoris'.
return (N->getZExtValue() & ~uint64_t(0xFFFF0000)) == 0;
}], HI16>;
def imm16ShiftedSExt : PatLeaf<(imm), [{
// imm16ShiftedSExt predicate - True if only bits in the top 16-bits of the
// immediate are set. Used by instructions like 'addis'. Identical to
// imm16ShiftedZExt in 32-bit mode.
if (N->getZExtValue() & 0xFFFF) return false;
if (N->getValueType(0) == MVT::i32)
return true;
// For 64-bit, make sure it is sext right.
return N->getZExtValue() == (uint64_t)(int)N->getZExtValue();
}], HI16>;
def imm64ZExt32 : Operand<i64>, ImmLeaf<i64, [{
// imm64ZExt32 predicate - True if the i64 immediate fits in a 32-bit
// zero extended field.
return isUInt<32>(Imm);
}]>;
// Some r+i load/store instructions (such as LD, STD, LDU, etc.) that require
// restricted memrix (4-aligned) constants are alignment sensitive. If these
// offsets are hidden behind TOC entries than the values of the lower-order
// bits cannot be checked directly. As a result, we need to also incorporate
// an alignment check into the relevant patterns.
def aligned4load : PatFrag<(ops node:$ptr), (load node:$ptr), [{
return cast<LoadSDNode>(N)->getAlignment() >= 4;
}]>;
def aligned4store : PatFrag<(ops node:$val, node:$ptr),
(store node:$val, node:$ptr), [{
return cast<StoreSDNode>(N)->getAlignment() >= 4;
}]>;
def aligned4sextloadi32 : PatFrag<(ops node:$ptr), (sextloadi32 node:$ptr), [{
return cast<LoadSDNode>(N)->getAlignment() >= 4;
}]>;
def aligned4pre_store : PatFrag<
(ops node:$val, node:$base, node:$offset),
(pre_store node:$val, node:$base, node:$offset), [{
return cast<StoreSDNode>(N)->getAlignment() >= 4;
}]>;
def unaligned4load : PatFrag<(ops node:$ptr), (load node:$ptr), [{
return cast<LoadSDNode>(N)->getAlignment() < 4;
}]>;
def unaligned4store : PatFrag<(ops node:$val, node:$ptr),
(store node:$val, node:$ptr), [{
return cast<StoreSDNode>(N)->getAlignment() < 4;
}]>;
def unaligned4sextloadi32 : PatFrag<(ops node:$ptr), (sextloadi32 node:$ptr), [{
return cast<LoadSDNode>(N)->getAlignment() < 4;
}]>;
// This is a somewhat weaker condition than actually checking for 16-byte
// alignment. It is simply checking that the displacement can be represented
// as an immediate that is a multiple of 16 (i.e. the requirements for DQ-Form
// instructions).
def quadwOffsetLoad : PatFrag<(ops node:$ptr), (load node:$ptr), [{
return isOffsetMultipleOf(N, 16);
}]>;
def quadwOffsetStore : PatFrag<(ops node:$val, node:$ptr),
(store node:$val, node:$ptr), [{
return isOffsetMultipleOf(N, 16);
}]>;
def nonQuadwOffsetLoad : PatFrag<(ops node:$ptr), (load node:$ptr), [{
return !isOffsetMultipleOf(N, 16);
}]>;
def nonQuadwOffsetStore : PatFrag<(ops node:$val, node:$ptr),
(store node:$val, node:$ptr), [{
return !isOffsetMultipleOf(N, 16);
}]>;
//===----------------------------------------------------------------------===//
// PowerPC Flag Definitions.
class isPPC64 { bit PPC64 = 1; }
class isDOT { bit RC = 1; }
class RegConstraint<string C> {
string Constraints = C;
}
class NoEncode<string E> {
string DisableEncoding = E;
}
//===----------------------------------------------------------------------===//
// PowerPC Operand Definitions.
// In the default PowerPC assembler syntax, registers are specified simply
// by number, so they cannot be distinguished from immediate values (without
// looking at the opcode). This means that the default operand matching logic
// for the asm parser does not work, and we need to specify custom matchers.
// Since those can only be specified with RegisterOperand classes and not
// directly on the RegisterClass, all instructions patterns used by the asm
// parser need to use a RegisterOperand (instead of a RegisterClass) for
// all their register operands.
// For this purpose, we define one RegisterOperand for each RegisterClass,
// using the same name as the class, just in lower case.
def PPCRegGPRCAsmOperand : AsmOperandClass {
let Name = "RegGPRC"; let PredicateMethod = "isRegNumber";
}
def gprc : RegisterOperand<GPRC> {
let ParserMatchClass = PPCRegGPRCAsmOperand;
}
def PPCRegG8RCAsmOperand : AsmOperandClass {
let Name = "RegG8RC"; let PredicateMethod = "isRegNumber";
}
def g8rc : RegisterOperand<G8RC> {
let ParserMatchClass = PPCRegG8RCAsmOperand;
}
def PPCRegGPRCNoR0AsmOperand : AsmOperandClass {
let Name = "RegGPRCNoR0"; let PredicateMethod = "isRegNumber";
}
def gprc_nor0 : RegisterOperand<GPRC_NOR0> {
let ParserMatchClass = PPCRegGPRCNoR0AsmOperand;
}
def PPCRegG8RCNoX0AsmOperand : AsmOperandClass {
let Name = "RegG8RCNoX0"; let PredicateMethod = "isRegNumber";
}
def g8rc_nox0 : RegisterOperand<G8RC_NOX0> {
let ParserMatchClass = PPCRegG8RCNoX0AsmOperand;
}
def PPCRegF8RCAsmOperand : AsmOperandClass {
let Name = "RegF8RC"; let PredicateMethod = "isRegNumber";
}
def f8rc : RegisterOperand<F8RC> {
let ParserMatchClass = PPCRegF8RCAsmOperand;
}
def PPCRegF4RCAsmOperand : AsmOperandClass {
let Name = "RegF4RC"; let PredicateMethod = "isRegNumber";
}
def f4rc : RegisterOperand<F4RC> {
let ParserMatchClass = PPCRegF4RCAsmOperand;
}
def PPCRegVRRCAsmOperand : AsmOperandClass {
let Name = "RegVRRC"; let PredicateMethod = "isRegNumber";
}
def vrrc : RegisterOperand<VRRC> {
let ParserMatchClass = PPCRegVRRCAsmOperand;
}
def PPCRegVFRCAsmOperand : AsmOperandClass {
let Name = "RegVFRC"; let PredicateMethod = "isRegNumber";
}
def vfrc : RegisterOperand<VFRC> {
let ParserMatchClass = PPCRegVFRCAsmOperand;
}
def PPCRegCRBITRCAsmOperand : AsmOperandClass {
let Name = "RegCRBITRC"; let PredicateMethod = "isCRBitNumber";
}
def crbitrc : RegisterOperand<CRBITRC> {
let ParserMatchClass = PPCRegCRBITRCAsmOperand;
}
def PPCRegCRRCAsmOperand : AsmOperandClass {
let Name = "RegCRRC"; let PredicateMethod = "isCCRegNumber";
}
def crrc : RegisterOperand<CRRC> {
let ParserMatchClass = PPCRegCRRCAsmOperand;
}
def crrc0 : RegisterOperand<CRRC0> {
let ParserMatchClass = PPCRegCRRCAsmOperand;
}
def PPCRegSPERCAsmOperand : AsmOperandClass {
let Name = "RegSPERC"; let PredicateMethod = "isRegNumber";
}
def sperc : RegisterOperand<SPERC> {
let ParserMatchClass = PPCRegSPERCAsmOperand;
}
def PPCRegSPE4RCAsmOperand : AsmOperandClass {
let Name = "RegSPE4RC"; let PredicateMethod = "isRegNumber";
}
def spe4rc : RegisterOperand<SPE4RC> {
let ParserMatchClass = PPCRegSPE4RCAsmOperand;
}
def PPCU1ImmAsmOperand : AsmOperandClass {
let Name = "U1Imm"; let PredicateMethod = "isU1Imm";
let RenderMethod = "addImmOperands";
}
def u1imm : Operand<i32> {
let PrintMethod = "printU1ImmOperand";
let ParserMatchClass = PPCU1ImmAsmOperand;
}
def PPCU2ImmAsmOperand : AsmOperandClass {
let Name = "U2Imm"; let PredicateMethod = "isU2Imm";
let RenderMethod = "addImmOperands";
}
def u2imm : Operand<i32> {
let PrintMethod = "printU2ImmOperand";
let ParserMatchClass = PPCU2ImmAsmOperand;
}
def PPCATBitsAsHintAsmOperand : AsmOperandClass {
let Name = "ATBitsAsHint"; let PredicateMethod = "isATBitsAsHint";
let RenderMethod = "addImmOperands"; // Irrelevant, predicate always fails.
}
def atimm : Operand<i32> {
let PrintMethod = "printATBitsAsHint";
let ParserMatchClass = PPCATBitsAsHintAsmOperand;
}
def PPCU3ImmAsmOperand : AsmOperandClass {
let Name = "U3Imm"; let PredicateMethod = "isU3Imm";
let RenderMethod = "addImmOperands";
}
def u3imm : Operand<i32> {
let PrintMethod = "printU3ImmOperand";
let ParserMatchClass = PPCU3ImmAsmOperand;
}
def PPCU4ImmAsmOperand : AsmOperandClass {
let Name = "U4Imm"; let PredicateMethod = "isU4Imm";
let RenderMethod = "addImmOperands";
}
def u4imm : Operand<i32> {
let PrintMethod = "printU4ImmOperand";
let ParserMatchClass = PPCU4ImmAsmOperand;
}
def PPCS5ImmAsmOperand : AsmOperandClass {
let Name = "S5Imm"; let PredicateMethod = "isS5Imm";
let RenderMethod = "addImmOperands";
}
def s5imm : Operand<i32> {
let PrintMethod = "printS5ImmOperand";
let ParserMatchClass = PPCS5ImmAsmOperand;
let DecoderMethod = "decodeSImmOperand<5>";
}
def PPCU5ImmAsmOperand : AsmOperandClass {
let Name = "U5Imm"; let PredicateMethod = "isU5Imm";
let RenderMethod = "addImmOperands";
}
def u5imm : Operand<i32> {
let PrintMethod = "printU5ImmOperand";
let ParserMatchClass = PPCU5ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<5>";
}
def PPCU6ImmAsmOperand : AsmOperandClass {
let Name = "U6Imm"; let PredicateMethod = "isU6Imm";
let RenderMethod = "addImmOperands";
}
def u6imm : Operand<i32> {
let PrintMethod = "printU6ImmOperand";
let ParserMatchClass = PPCU6ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<6>";
}
def PPCU7ImmAsmOperand : AsmOperandClass {
let Name = "U7Imm"; let PredicateMethod = "isU7Imm";
let RenderMethod = "addImmOperands";
}
def u7imm : Operand<i32> {
let PrintMethod = "printU7ImmOperand";
let ParserMatchClass = PPCU7ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<7>";
}
def PPCU8ImmAsmOperand : AsmOperandClass {
let Name = "U8Imm"; let PredicateMethod = "isU8Imm";
let RenderMethod = "addImmOperands";
}
def u8imm : Operand<i32> {
let PrintMethod = "printU8ImmOperand";
let ParserMatchClass = PPCU8ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<8>";
}
def PPCU10ImmAsmOperand : AsmOperandClass {
let Name = "U10Imm"; let PredicateMethod = "isU10Imm";
let RenderMethod = "addImmOperands";
}
def u10imm : Operand<i32> {
let PrintMethod = "printU10ImmOperand";
let ParserMatchClass = PPCU10ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<10>";
}
def PPCU12ImmAsmOperand : AsmOperandClass {
let Name = "U12Imm"; let PredicateMethod = "isU12Imm";
let RenderMethod = "addImmOperands";
}
def u12imm : Operand<i32> {
let PrintMethod = "printU12ImmOperand";
let ParserMatchClass = PPCU12ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<12>";
}
def PPCS16ImmAsmOperand : AsmOperandClass {
let Name = "S16Imm"; let PredicateMethod = "isS16Imm";
let RenderMethod = "addS16ImmOperands";
}
def s16imm : Operand<i32> {
let PrintMethod = "printS16ImmOperand";
let EncoderMethod = "getImm16Encoding";
let ParserMatchClass = PPCS16ImmAsmOperand;
let DecoderMethod = "decodeSImmOperand<16>";
}
def PPCU16ImmAsmOperand : AsmOperandClass {
let Name = "U16Imm"; let PredicateMethod = "isU16Imm";
let RenderMethod = "addU16ImmOperands";
}
def u16imm : Operand<i32> {
let PrintMethod = "printU16ImmOperand";
let EncoderMethod = "getImm16Encoding";
let ParserMatchClass = PPCU16ImmAsmOperand;
let DecoderMethod = "decodeUImmOperand<16>";
}
def PPCS17ImmAsmOperand : AsmOperandClass {
let Name = "S17Imm"; let PredicateMethod = "isS17Imm";
let RenderMethod = "addS16ImmOperands";
}
def s17imm : Operand<i32> {
// This operand type is used for addis/lis to allow the assembler parser
// to accept immediates in the range -65536..65535 for compatibility with
// the GNU assembler. The operand is treated as 16-bit otherwise.
let PrintMethod = "printS16ImmOperand";
let EncoderMethod = "getImm16Encoding";
let ParserMatchClass = PPCS17ImmAsmOperand;
let DecoderMethod = "decodeSImmOperand<16>";
}
def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>;
def PPCDirectBrAsmOperand : AsmOperandClass {
let Name = "DirectBr"; let PredicateMethod = "isDirectBr";
let RenderMethod = "addBranchTargetOperands";
}
def directbrtarget : Operand<OtherVT> {
let PrintMethod = "printBranchOperand";
let EncoderMethod = "getDirectBrEncoding";
let ParserMatchClass = PPCDirectBrAsmOperand;
}
def absdirectbrtarget : Operand<OtherVT> {
let PrintMethod = "printAbsBranchOperand";
let EncoderMethod = "getAbsDirectBrEncoding";
let ParserMatchClass = PPCDirectBrAsmOperand;
}
def PPCCondBrAsmOperand : AsmOperandClass {
let Name = "CondBr"; let PredicateMethod = "isCondBr";
let RenderMethod = "addBranchTargetOperands";
}
def condbrtarget : Operand<OtherVT> {
let PrintMethod = "printBranchOperand";
let EncoderMethod = "getCondBrEncoding";
let ParserMatchClass = PPCCondBrAsmOperand;
}
def abscondbrtarget : Operand<OtherVT> {
let PrintMethod = "printAbsBranchOperand";
let EncoderMethod = "getAbsCondBrEncoding";
let ParserMatchClass = PPCCondBrAsmOperand;
}
def calltarget : Operand<iPTR> {
let PrintMethod = "printBranchOperand";
let EncoderMethod = "getDirectBrEncoding";
+ let DecoderMethod = "DecodePCRel24BranchTarget";
let ParserMatchClass = PPCDirectBrAsmOperand;
+ let OperandType = "OPERAND_PCREL";
}
def abscalltarget : Operand<iPTR> {
let PrintMethod = "printAbsBranchOperand";
let EncoderMethod = "getAbsDirectBrEncoding";
let ParserMatchClass = PPCDirectBrAsmOperand;
}
def PPCCRBitMaskOperand : AsmOperandClass {
let Name = "CRBitMask"; let PredicateMethod = "isCRBitMask";
}
def crbitm: Operand<i8> {
let PrintMethod = "printcrbitm";
let EncoderMethod = "get_crbitm_encoding";
let DecoderMethod = "decodeCRBitMOperand";
let ParserMatchClass = PPCCRBitMaskOperand;
}
// Address operands
// A version of ptr_rc which excludes R0 (or X0 in 64-bit mode).
def PPCRegGxRCNoR0Operand : AsmOperandClass {
let Name = "RegGxRCNoR0"; let PredicateMethod = "isRegNumber";
}
def ptr_rc_nor0 : Operand<iPTR>, PointerLikeRegClass<1> {
let ParserMatchClass = PPCRegGxRCNoR0Operand;
}
// A version of ptr_rc usable with the asm parser.
def PPCRegGxRCOperand : AsmOperandClass {
let Name = "RegGxRC"; let PredicateMethod = "isRegNumber";
}
def ptr_rc_idx : Operand<iPTR>, PointerLikeRegClass<0> {
let ParserMatchClass = PPCRegGxRCOperand;
}
def PPCDispRIOperand : AsmOperandClass {
let Name = "DispRI"; let PredicateMethod = "isS16Imm";
let RenderMethod = "addS16ImmOperands";
}
def dispRI : Operand<iPTR> {
let ParserMatchClass = PPCDispRIOperand;
}
def PPCDispRIXOperand : AsmOperandClass {
let Name = "DispRIX"; let PredicateMethod = "isS16ImmX4";
let RenderMethod = "addImmOperands";
}
def dispRIX : Operand<iPTR> {
let ParserMatchClass = PPCDispRIXOperand;
}
def PPCDispRIX16Operand : AsmOperandClass {
let Name = "DispRIX16"; let PredicateMethod = "isS16ImmX16";
let RenderMethod = "addImmOperands";
}
def dispRIX16 : Operand<iPTR> {
let ParserMatchClass = PPCDispRIX16Operand;
}
def PPCDispSPE8Operand : AsmOperandClass {
let Name = "DispSPE8"; let PredicateMethod = "isU8ImmX8";
let RenderMethod = "addImmOperands";
}
def dispSPE8 : Operand<iPTR> {
let ParserMatchClass = PPCDispSPE8Operand;
}
def PPCDispSPE4Operand : AsmOperandClass {
let Name = "DispSPE4"; let PredicateMethod = "isU7ImmX4";
let RenderMethod = "addImmOperands";
}
def dispSPE4 : Operand<iPTR> {
let ParserMatchClass = PPCDispSPE4Operand;
}
def PPCDispSPE2Operand : AsmOperandClass {
let Name = "DispSPE2"; let PredicateMethod = "isU6ImmX2";
let RenderMethod = "addImmOperands";
}
def dispSPE2 : Operand<iPTR> {
let ParserMatchClass = PPCDispSPE2Operand;
}
def memri : Operand<iPTR> {
let PrintMethod = "printMemRegImm";
let MIOperandInfo = (ops dispRI:$imm, ptr_rc_nor0:$reg);
let EncoderMethod = "getMemRIEncoding";
let DecoderMethod = "decodeMemRIOperands";
}
def memrr : Operand<iPTR> {
let PrintMethod = "printMemRegReg";
let MIOperandInfo = (ops ptr_rc_nor0:$ptrreg, ptr_rc_idx:$offreg);
}
def memrix : Operand<iPTR> { // memri where the imm is 4-aligned.
let PrintMethod = "printMemRegImm";
let MIOperandInfo = (ops dispRIX:$imm, ptr_rc_nor0:$reg);
let EncoderMethod = "getMemRIXEncoding";
let DecoderMethod = "decodeMemRIXOperands";
}
def memrix16 : Operand<iPTR> { // memri, imm is 16-aligned, 12-bit, Inst{16:27}
let PrintMethod = "printMemRegImm";
let MIOperandInfo = (ops dispRIX16:$imm, ptr_rc_nor0:$reg);
let EncoderMethod = "getMemRIX16Encoding";
let DecoderMethod = "decodeMemRIX16Operands";
}
def spe8dis : Operand<iPTR> { // SPE displacement where the imm is 8-aligned.
let PrintMethod = "printMemRegImm";
let MIOperandInfo = (ops dispSPE8:$imm, ptr_rc_nor0:$reg);
let EncoderMethod = "getSPE8DisEncoding";
let DecoderMethod = "decodeSPE8Operands";
}
def spe4dis : Operand<iPTR> { // SPE displacement where the imm is 4-aligned.
let PrintMethod = "printMemRegImm";
let MIOperandInfo = (ops dispSPE4:$imm, ptr_rc_nor0:$reg);
let EncoderMethod = "getSPE4DisEncoding";
let DecoderMethod = "decodeSPE4Operands";
}
def spe2dis : Operand<iPTR> { // SPE displacement where the imm is 2-aligned.
let PrintMethod = "printMemRegImm";
let MIOperandInfo = (ops dispSPE2:$imm, ptr_rc_nor0:$reg);
let EncoderMethod = "getSPE2DisEncoding";
let DecoderMethod = "decodeSPE2Operands";
}
// A single-register address. This is used with the SjLj
// pseudo-instructions which tranlates to LD/LWZ. These instructions requires
// G8RC_NOX0 registers.
def memr : Operand<iPTR> {
let MIOperandInfo = (ops ptr_rc_nor0:$ptrreg);
}
def PPCTLSRegOperand : AsmOperandClass {
let Name = "TLSReg"; let PredicateMethod = "isTLSReg";
let RenderMethod = "addTLSRegOperands";
}
def tlsreg32 : Operand<i32> {
let EncoderMethod = "getTLSRegEncoding";
let ParserMatchClass = PPCTLSRegOperand;
}
def tlsgd32 : Operand<i32> {}
def tlscall32 : Operand<i32> {
let PrintMethod = "printTLSCall";
let MIOperandInfo = (ops calltarget:$func, tlsgd32:$sym);
let EncoderMethod = "getTLSCallEncoding";
}
// PowerPC Predicate operand.
def pred : Operand<OtherVT> {
let PrintMethod = "printPredicateOperand";
let MIOperandInfo = (ops i32imm:$bibo, crrc:$reg);
}
// Define PowerPC specific addressing mode.
def iaddr : ComplexPattern<iPTR, 2, "SelectAddrImm", [], []>;
def xaddr : ComplexPattern<iPTR, 2, "SelectAddrIdx", [], []>;
def xoaddr : ComplexPattern<iPTR, 2, "SelectAddrIdxOnly",[], []>;
def ixaddr : ComplexPattern<iPTR, 2, "SelectAddrImmX4", [], []>; // "std"
def iqaddr : ComplexPattern<iPTR, 2, "SelectAddrImmX16", [], []>; // "stxv"
// The address in a single register. This is used with the SjLj
// pseudo-instructions.
def addr : ComplexPattern<iPTR, 1, "SelectAddr",[], []>;
/// This is just the offset part of iaddr, used for preinc.
def iaddroff : ComplexPattern<iPTR, 1, "SelectAddrImmOffs", [], []>;
//===----------------------------------------------------------------------===//
// PowerPC Instruction Predicate Definitions.
def In32BitMode : Predicate<"!PPCSubTarget->isPPC64()">;
def In64BitMode : Predicate<"PPCSubTarget->isPPC64()">;
def IsBookE : Predicate<"PPCSubTarget->isBookE()">;
def IsNotBookE : Predicate<"!PPCSubTarget->isBookE()">;
def HasOnlyMSYNC : Predicate<"PPCSubTarget->hasOnlyMSYNC()">;
def HasSYNC : Predicate<"!PPCSubTarget->hasOnlyMSYNC()">;
def IsPPC4xx : Predicate<"PPCSubTarget->isPPC4xx()">;
def IsPPC6xx : Predicate<"PPCSubTarget->isPPC6xx()">;
def IsE500 : Predicate<"PPCSubTarget->isE500()">;
def HasSPE : Predicate<"PPCSubTarget->hasSPE()">;
def HasICBT : Predicate<"PPCSubTarget->hasICBT()">;
def HasPartwordAtomics : Predicate<"PPCSubTarget->hasPartwordAtomics()">;
def NoNaNsFPMath : Predicate<"TM.Options.NoNaNsFPMath">;
def NaNsFPMath : Predicate<"!TM.Options.NoNaNsFPMath">;
def HasBPERMD : Predicate<"PPCSubTarget->hasBPERMD()">;
def HasExtDiv : Predicate<"PPCSubTarget->hasExtDiv()">;
def IsISA3_0 : Predicate<"PPCSubTarget->isISA3_0()">;
def HasFPU : Predicate<"PPCSubTarget->hasFPU()">;
//===----------------------------------------------------------------------===//
// PowerPC Multiclass Definitions.
multiclass XForm_6r<bits<6> opcode, bits<10> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : XForm_6<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR0] in
def o : XForm_6<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass XForm_6rc<bits<6> opcode, bits<10> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
let Defs = [CARRY] in
def NAME : XForm_6<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CARRY, CR0] in
def o : XForm_6<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass XForm_10rc<bits<6> opcode, bits<10> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
let Defs = [CARRY] in
def NAME : XForm_10<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CARRY, CR0] in
def o : XForm_10<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass XForm_11r<bits<6> opcode, bits<10> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : XForm_11<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR0] in
def o : XForm_11<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass XOForm_1r<bits<6> opcode, bits<9> xo, bit oe, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : XOForm_1<opcode, xo, oe, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR0] in
def o : XOForm_1<opcode, xo, oe, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
// Multiclass for instructions for which the non record form is not cracked
// and the record form is cracked (i.e. divw, mullw, etc.)
multiclass XOForm_1rcr<bits<6> opcode, bits<9> xo, bit oe, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : XOForm_1<opcode, xo, oe, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR0] in
def o : XOForm_1<opcode, xo, oe, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel, PPC970_DGroup_First,
PPC970_DGroup_Cracked;
}
}
multiclass XOForm_1rc<bits<6> opcode, bits<9> xo, bit oe, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
let Defs = [CARRY] in
def NAME : XOForm_1<opcode, xo, oe, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CARRY, CR0] in
def o : XOForm_1<opcode, xo, oe, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass XOForm_3r<bits<6> opcode, bits<9> xo, bit oe, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : XOForm_3<opcode, xo, oe, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR0] in
def o : XOForm_3<opcode, xo, oe, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass XOForm_3rc<bits<6> opcode, bits<9> xo, bit oe, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
let Defs = [CARRY] in
def NAME : XOForm_3<opcode, xo, oe, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CARRY, CR0] in
def o : XOForm_3<opcode, xo, oe, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass MForm_2r<bits<6> opcode, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : MForm_2<opcode, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR0] in
def o : MForm_2<opcode, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass MDForm_1r<bits<6> opcode, bits<3> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : MDForm_1<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR0] in
def o : MDForm_1<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass MDSForm_1r<bits<6> opcode, bits<4> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : MDSForm_1<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR0] in
def o : MDSForm_1<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass XSForm_1rc<bits<6> opcode, bits<9> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
let Defs = [CARRY] in
def NAME : XSForm_1<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CARRY, CR0] in
def o : XSForm_1<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass XSForm_1r<bits<6> opcode, bits<9> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : XSForm_1<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR0] in
def o : XSForm_1<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass XForm_26r<bits<6> opcode, bits<10> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : XForm_26<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR1] in
def o : XForm_26<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass XForm_28r<bits<6> opcode, bits<10> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : XForm_28<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR1] in
def o : XForm_28<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass AForm_1r<bits<6> opcode, bits<5> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : AForm_1<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR1] in
def o : AForm_1<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass AForm_2r<bits<6> opcode, bits<5> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : AForm_2<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR1] in
def o : AForm_2<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
multiclass AForm_3r<bits<6> opcode, bits<5> xo, dag OOL, dag IOL,
string asmbase, string asmstr, InstrItinClass itin,
list<dag> pattern> {
let BaseName = asmbase in {
def NAME : AForm_3<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(" ", asmstr)), itin,
pattern>, RecFormRel;
let Defs = [CR1] in
def o : AForm_3<opcode, xo, OOL, IOL,
!strconcat(asmbase, !strconcat(". ", asmstr)), itin,
[]>, isDOT, RecFormRel;
}
}
//===----------------------------------------------------------------------===//
// PowerPC Instruction Definitions.
// Pseudo instructions:
let hasCtrlDep = 1 in {
let Defs = [R1], Uses = [R1] in {
def ADJCALLSTACKDOWN : PPCEmitTimePseudo<(outs), (ins u16imm:$amt1, u16imm:$amt2),
"#ADJCALLSTACKDOWN $amt1 $amt2",
[(callseq_start timm:$amt1, timm:$amt2)]>;
def ADJCALLSTACKUP : PPCEmitTimePseudo<(outs), (ins u16imm:$amt1, u16imm:$amt2),
"#ADJCALLSTACKUP $amt1 $amt2",
[(callseq_end timm:$amt1, timm:$amt2)]>;
}
def UPDATE_VRSAVE : PPCEmitTimePseudo<(outs gprc:$rD), (ins gprc:$rS),
"UPDATE_VRSAVE $rD, $rS", []>;
}
let Defs = [R1], Uses = [R1] in
def DYNALLOC : PPCEmitTimePseudo<(outs gprc:$result), (ins gprc:$negsize, memri:$fpsi), "#DYNALLOC",
[(set i32:$result,
(PPCdynalloc i32:$negsize, iaddr:$fpsi))]>;
def DYNAREAOFFSET : PPCEmitTimePseudo<(outs i32imm:$result), (ins memri:$fpsi), "#DYNAREAOFFSET",
[(set i32:$result, (PPCdynareaoffset iaddr:$fpsi))]>;
// SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded after
// instruction selection into a branch sequence.
let PPC970_Single = 1 in {
// Note that SELECT_CC_I4 and SELECT_CC_I8 use the no-r0 register classes
// because either operand might become the first operand in an isel, and
// that operand cannot be r0.
def SELECT_CC_I4 : PPCCustomInserterPseudo<(outs gprc:$dst), (ins crrc:$cond,
gprc_nor0:$T, gprc_nor0:$F,
i32imm:$BROPC), "#SELECT_CC_I4",
[]>;
def SELECT_CC_I8 : PPCCustomInserterPseudo<(outs g8rc:$dst), (ins crrc:$cond,
g8rc_nox0:$T, g8rc_nox0:$F,
i32imm:$BROPC), "#SELECT_CC_I8",
[]>;
def SELECT_CC_F4 : PPCCustomInserterPseudo<(outs f4rc:$dst), (ins crrc:$cond, f4rc:$T, f4rc:$F,
i32imm:$BROPC), "#SELECT_CC_F4",
[]>;
def SELECT_CC_F8 : PPCCustomInserterPseudo<(outs f8rc:$dst), (ins crrc:$cond, f8rc:$T, f8rc:$F,
i32imm:$BROPC), "#SELECT_CC_F8",
[]>;
def SELECT_CC_F16 : PPCCustomInserterPseudo<(outs vrrc:$dst), (ins crrc:$cond, vrrc:$T, vrrc:$F,
i32imm:$BROPC), "#SELECT_CC_F16",
[]>;
def SELECT_CC_VRRC: PPCCustomInserterPseudo<(outs vrrc:$dst), (ins crrc:$cond, vrrc:$T, vrrc:$F,
i32imm:$BROPC), "#SELECT_CC_VRRC",
[]>;
// SELECT_* pseudo instructions, like SELECT_CC_* but taking condition
// register bit directly.
def SELECT_I4 : PPCCustomInserterPseudo<(outs gprc:$dst), (ins crbitrc:$cond,
gprc_nor0:$T, gprc_nor0:$F), "#SELECT_I4",
[(set i32:$dst, (select i1:$cond, i32:$T, i32:$F))]>;
def SELECT_I8 : PPCCustomInserterPseudo<(outs g8rc:$dst), (ins crbitrc:$cond,
g8rc_nox0:$T, g8rc_nox0:$F), "#SELECT_I8",
[(set i64:$dst, (select i1:$cond, i64:$T, i64:$F))]>;
let Predicates = [HasFPU] in {
def SELECT_F4 : PPCCustomInserterPseudo<(outs f4rc:$dst), (ins crbitrc:$cond,
f4rc:$T, f4rc:$F), "#SELECT_F4",
[(set f32:$dst, (select i1:$cond, f32:$T, f32:$F))]>;
def SELECT_F8 : PPCCustomInserterPseudo<(outs f8rc:$dst), (ins crbitrc:$cond,
f8rc:$T, f8rc:$F), "#SELECT_F8",
[(set f64:$dst, (select i1:$cond, f64:$T, f64:$F))]>;
def SELECT_F16 : PPCCustomInserterPseudo<(outs vrrc:$dst), (ins crbitrc:$cond,
vrrc:$T, vrrc:$F), "#SELECT_F16",
[(set f128:$dst, (select i1:$cond, f128:$T, f128:$F))]>;
}
def SELECT_VRRC: PPCCustomInserterPseudo<(outs vrrc:$dst), (ins crbitrc:$cond,
vrrc:$T, vrrc:$F), "#SELECT_VRRC",
[(set v4i32:$dst,
(select i1:$cond, v4i32:$T, v4i32:$F))]>;
}
// SPILL_CR - Indicate that we're dumping the CR register, so we'll need to
// scavenge a register for it.
let mayStore = 1 in {
def SPILL_CR : PPCEmitTimePseudo<(outs), (ins crrc:$cond, memri:$F),
"#SPILL_CR", []>;
def SPILL_CRBIT : PPCEmitTimePseudo<(outs), (ins crbitrc:$cond, memri:$F),
"#SPILL_CRBIT", []>;
}
// RESTORE_CR - Indicate that we're restoring the CR register (previously
// spilled), so we'll need to scavenge a register for it.
let mayLoad = 1 in {
def RESTORE_CR : PPCEmitTimePseudo<(outs crrc:$cond), (ins memri:$F),
"#RESTORE_CR", []>;
def RESTORE_CRBIT : PPCEmitTimePseudo<(outs crbitrc:$cond), (ins memri:$F),
"#RESTORE_CRBIT", []>;
}
let isTerminator = 1, isBarrier = 1, PPC970_Unit = 7 in {
let isReturn = 1, Uses = [LR, RM] in
def BLR : XLForm_2_ext<19, 16, 20, 0, 0, (outs), (ins), "blr", IIC_BrB,
[(retflag)]>, Requires<[In32BitMode]>;
let isBranch = 1, isIndirectBranch = 1, Uses = [CTR] in {
def BCTR : XLForm_2_ext<19, 528, 20, 0, 0, (outs), (ins), "bctr", IIC_BrB,
[]>;
let isCodeGenOnly = 1 in {
def BCCCTR : XLForm_2_br<19, 528, 0, (outs), (ins pred:$cond),
"b${cond:cc}ctr${cond:pm} ${cond:reg}", IIC_BrB,
[]>;
def BCCTR : XLForm_2_br2<19, 528, 12, 0, (outs), (ins crbitrc:$bi),
"bcctr 12, $bi, 0", IIC_BrB, []>;
def BCCTRn : XLForm_2_br2<19, 528, 4, 0, (outs), (ins crbitrc:$bi),
"bcctr 4, $bi, 0", IIC_BrB, []>;
}
}
}
let Defs = [LR] in
def MovePCtoLR : PPCEmitTimePseudo<(outs), (ins), "#MovePCtoLR", []>,
PPC970_Unit_BRU;
let Defs = [LR] in
def MoveGOTtoLR : PPCEmitTimePseudo<(outs), (ins), "#MoveGOTtoLR", []>,
PPC970_Unit_BRU;
let isBranch = 1, isTerminator = 1, hasCtrlDep = 1, PPC970_Unit = 7 in {
let isBarrier = 1 in {
def B : IForm<18, 0, 0, (outs), (ins directbrtarget:$dst),
"b $dst", IIC_BrB,
[(br bb:$dst)]>;
def BA : IForm<18, 1, 0, (outs), (ins absdirectbrtarget:$dst),
"ba $dst", IIC_BrB, []>;
}
// BCC represents an arbitrary conditional branch on a predicate.
// FIXME: should be able to write a pattern for PPCcondbranch, but can't use
// a two-value operand where a dag node expects two operands. :(
let isCodeGenOnly = 1 in {
class BCC_class : BForm<16, 0, 0, (outs), (ins pred:$cond, condbrtarget:$dst),
"b${cond:cc}${cond:pm} ${cond:reg}, $dst"
/*[(PPCcondbranch crrc:$crS, imm:$opc, bb:$dst)]*/>;
def BCC : BCC_class;
// The same as BCC, except that it's not a terminator. Used for introducing
// control flow dependency without creating new blocks.
let isTerminator = 0 in def CTRL_DEP : BCC_class;
def BCCA : BForm<16, 1, 0, (outs), (ins pred:$cond, abscondbrtarget:$dst),
"b${cond:cc}a${cond:pm} ${cond:reg}, $dst">;
let isReturn = 1, Uses = [LR, RM] in
def BCCLR : XLForm_2_br<19, 16, 0, (outs), (ins pred:$cond),
"b${cond:cc}lr${cond:pm} ${cond:reg}", IIC_BrB, []>;
}
let isCodeGenOnly = 1 in {
let Pattern = [(brcond i1:$bi, bb:$dst)] in
def BC : BForm_4<16, 12, 0, 0, (outs), (ins crbitrc:$bi, condbrtarget:$dst),
"bc 12, $bi, $dst">;
let Pattern = [(brcond (not i1:$bi), bb:$dst)] in
def BCn : BForm_4<16, 4, 0, 0, (outs), (ins crbitrc:$bi, condbrtarget:$dst),
"bc 4, $bi, $dst">;
let isReturn = 1, Uses = [LR, RM] in
def BCLR : XLForm_2_br2<19, 16, 12, 0, (outs), (ins crbitrc:$bi),
"bclr 12, $bi, 0", IIC_BrB, []>;
def BCLRn : XLForm_2_br2<19, 16, 4, 0, (outs), (ins crbitrc:$bi),
"bclr 4, $bi, 0", IIC_BrB, []>;
}
let isReturn = 1, Defs = [CTR], Uses = [CTR, LR, RM] in {
def BDZLR : XLForm_2_ext<19, 16, 18, 0, 0, (outs), (ins),
"bdzlr", IIC_BrB, []>;
def BDNZLR : XLForm_2_ext<19, 16, 16, 0, 0, (outs), (ins),
"bdnzlr", IIC_BrB, []>;
def BDZLRp : XLForm_2_ext<19, 16, 27, 0, 0, (outs), (ins),
"bdzlr+", IIC_BrB, []>;
def BDNZLRp: XLForm_2_ext<19, 16, 25, 0, 0, (outs), (ins),
"bdnzlr+", IIC_BrB, []>;
def BDZLRm : XLForm_2_ext<19, 16, 26, 0, 0, (outs), (ins),
"bdzlr-", IIC_BrB, []>;
def BDNZLRm: XLForm_2_ext<19, 16, 24, 0, 0, (outs), (ins),
"bdnzlr-", IIC_BrB, []>;
}
let Defs = [CTR], Uses = [CTR] in {
def BDZ : BForm_1<16, 18, 0, 0, (outs), (ins condbrtarget:$dst),
"bdz $dst">;
def BDNZ : BForm_1<16, 16, 0, 0, (outs), (ins condbrtarget:$dst),
"bdnz $dst">;
def BDZA : BForm_1<16, 18, 1, 0, (outs), (ins abscondbrtarget:$dst),
"bdza $dst">;
def BDNZA : BForm_1<16, 16, 1, 0, (outs), (ins abscondbrtarget:$dst),
"bdnza $dst">;
def BDZp : BForm_1<16, 27, 0, 0, (outs), (ins condbrtarget:$dst),
"bdz+ $dst">;
def BDNZp: BForm_1<16, 25, 0, 0, (outs), (ins condbrtarget:$dst),
"bdnz+ $dst">;
def BDZAp : BForm_1<16, 27, 1, 0, (outs), (ins abscondbrtarget:$dst),
"bdza+ $dst">;
def BDNZAp: BForm_1<16, 25, 1, 0, (outs), (ins abscondbrtarget:$dst),
"bdnza+ $dst">;
def BDZm : BForm_1<16, 26, 0, 0, (outs), (ins condbrtarget:$dst),
"bdz- $dst">;
def BDNZm: BForm_1<16, 24, 0, 0, (outs), (ins condbrtarget:$dst),
"bdnz- $dst">;
def BDZAm : BForm_1<16, 26, 1, 0, (outs), (ins abscondbrtarget:$dst),
"bdza- $dst">;
def BDNZAm: BForm_1<16, 24, 1, 0, (outs), (ins abscondbrtarget:$dst),
"bdnza- $dst">;
}
}
// The unconditional BCL used by the SjLj setjmp code.
let isCall = 1, hasCtrlDep = 1, isCodeGenOnly = 1, PPC970_Unit = 7 in {
let Defs = [LR], Uses = [RM] in {
def BCLalways : BForm_2<16, 20, 31, 0, 1, (outs), (ins condbrtarget:$dst),
"bcl 20, 31, $dst">;
}
}
let isCall = 1, PPC970_Unit = 7, Defs = [LR] in {
// Convenient aliases for call instructions
let Uses = [RM] in {
def BL : IForm<18, 0, 1, (outs), (ins calltarget:$func),
"bl $func", IIC_BrB, []>; // See Pat patterns below.
def BLA : IForm<18, 1, 1, (outs), (ins abscalltarget:$func),
"bla $func", IIC_BrB, [(PPCcall (i32 imm:$func))]>;
let isCodeGenOnly = 1 in {
def BL_TLS : IForm<18, 0, 1, (outs), (ins tlscall32:$func),
"bl $func", IIC_BrB, []>;
def BCCL : BForm<16, 0, 1, (outs), (ins pred:$cond, condbrtarget:$dst),
"b${cond:cc}l${cond:pm} ${cond:reg}, $dst">;
def BCCLA : BForm<16, 1, 1, (outs), (ins pred:$cond, abscondbrtarget:$dst),
"b${cond:cc}la${cond:pm} ${cond:reg}, $dst">;
def BCL : BForm_4<16, 12, 0, 1, (outs),
(ins crbitrc:$bi, condbrtarget:$dst),
"bcl 12, $bi, $dst">;
def BCLn : BForm_4<16, 4, 0, 1, (outs),
(ins crbitrc:$bi, condbrtarget:$dst),
"bcl 4, $bi, $dst">;
}
}
let Uses = [CTR, RM] in {
def BCTRL : XLForm_2_ext<19, 528, 20, 0, 1, (outs), (ins),
"bctrl", IIC_BrB, [(PPCbctrl)]>,
Requires<[In32BitMode]>;
let isCodeGenOnly = 1 in {
def BCCCTRL : XLForm_2_br<19, 528, 1, (outs), (ins pred:$cond),
"b${cond:cc}ctrl${cond:pm} ${cond:reg}", IIC_BrB,
[]>;
def BCCTRL : XLForm_2_br2<19, 528, 12, 1, (outs), (ins crbitrc:$bi),
"bcctrl 12, $bi, 0", IIC_BrB, []>;
def BCCTRLn : XLForm_2_br2<19, 528, 4, 1, (outs), (ins crbitrc:$bi),
"bcctrl 4, $bi, 0", IIC_BrB, []>;
}
}
let Uses = [LR, RM] in {
def BLRL : XLForm_2_ext<19, 16, 20, 0, 1, (outs), (ins),
"blrl", IIC_BrB, []>;
let isCodeGenOnly = 1 in {
def BCCLRL : XLForm_2_br<19, 16, 1, (outs), (ins pred:$cond),
"b${cond:cc}lrl${cond:pm} ${cond:reg}", IIC_BrB,
[]>;
def BCLRL : XLForm_2_br2<19, 16, 12, 1, (outs), (ins crbitrc:$bi),
"bclrl 12, $bi, 0", IIC_BrB, []>;
def BCLRLn : XLForm_2_br2<19, 16, 4, 1, (outs), (ins crbitrc:$bi),
"bclrl 4, $bi, 0", IIC_BrB, []>;
}
}
let Defs = [CTR], Uses = [CTR, RM] in {
def BDZL : BForm_1<16, 18, 0, 1, (outs), (ins condbrtarget:$dst),
"bdzl $dst">;
def BDNZL : BForm_1<16, 16, 0, 1, (outs), (ins condbrtarget:$dst),
"bdnzl $dst">;
def BDZLA : BForm_1<16, 18, 1, 1, (outs), (ins abscondbrtarget:$dst),
"bdzla $dst">;
def BDNZLA : BForm_1<16, 16, 1, 1, (outs), (ins abscondbrtarget:$dst),
"bdnzla $dst">;
def BDZLp : BForm_1<16, 27, 0, 1, (outs), (ins condbrtarget:$dst),
"bdzl+ $dst">;
def BDNZLp: BForm_1<16, 25, 0, 1, (outs), (ins condbrtarget:$dst),
"bdnzl+ $dst">;
def BDZLAp : BForm_1<16, 27, 1, 1, (outs), (ins abscondbrtarget:$dst),
"bdzla+ $dst">;
def BDNZLAp: BForm_1<16, 25, 1, 1, (outs), (ins abscondbrtarget:$dst),
"bdnzla+ $dst">;
def BDZLm : BForm_1<16, 26, 0, 1, (outs), (ins condbrtarget:$dst),
"bdzl- $dst">;
def BDNZLm: BForm_1<16, 24, 0, 1, (outs), (ins condbrtarget:$dst),
"bdnzl- $dst">;
def BDZLAm : BForm_1<16, 26, 1, 1, (outs), (ins abscondbrtarget:$dst),
"bdzla- $dst">;
def BDNZLAm: BForm_1<16, 24, 1, 1, (outs), (ins abscondbrtarget:$dst),
"bdnzla- $dst">;
}
let Defs = [CTR], Uses = [CTR, LR, RM] in {
def BDZLRL : XLForm_2_ext<19, 16, 18, 0, 1, (outs), (ins),
"bdzlrl", IIC_BrB, []>;
def BDNZLRL : XLForm_2_ext<19, 16, 16, 0, 1, (outs), (ins),
"bdnzlrl", IIC_BrB, []>;
def BDZLRLp : XLForm_2_ext<19, 16, 27, 0, 1, (outs), (ins),
"bdzlrl+", IIC_BrB, []>;
def BDNZLRLp: XLForm_2_ext<19, 16, 25, 0, 1, (outs), (ins),
"bdnzlrl+", IIC_BrB, []>;
def BDZLRLm : XLForm_2_ext<19, 16, 26, 0, 1, (outs), (ins),
"bdzlrl-", IIC_BrB, []>;
def BDNZLRLm: XLForm_2_ext<19, 16, 24, 0, 1, (outs), (ins),
"bdnzlrl-", IIC_BrB, []>;
}
}
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [RM] in
def TCRETURNdi :PPCEmitTimePseudo< (outs),
(ins calltarget:$dst, i32imm:$offset),
"#TC_RETURNd $dst $offset",
[]>;
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [RM] in
def TCRETURNai :PPCEmitTimePseudo<(outs), (ins abscalltarget:$func, i32imm:$offset),
"#TC_RETURNa $func $offset",
[(PPCtc_return (i32 imm:$func), imm:$offset)]>;
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [RM] in
def TCRETURNri : PPCEmitTimePseudo<(outs), (ins CTRRC:$dst, i32imm:$offset),
"#TC_RETURNr $dst $offset",
[]>;
let isCodeGenOnly = 1 in {
let isTerminator = 1, isBarrier = 1, PPC970_Unit = 7, isBranch = 1,
isIndirectBranch = 1, isCall = 1, isReturn = 1, Uses = [CTR, RM] in
def TAILBCTR : XLForm_2_ext<19, 528, 20, 0, 0, (outs), (ins), "bctr", IIC_BrB,
[]>, Requires<[In32BitMode]>;
let isBranch = 1, isTerminator = 1, hasCtrlDep = 1, PPC970_Unit = 7,
isBarrier = 1, isCall = 1, isReturn = 1, Uses = [RM] in
def TAILB : IForm<18, 0, 0, (outs), (ins calltarget:$dst),
"b $dst", IIC_BrB,
[]>;
let isBranch = 1, isTerminator = 1, hasCtrlDep = 1, PPC970_Unit = 7,
isBarrier = 1, isCall = 1, isReturn = 1, Uses = [RM] in
def TAILBA : IForm<18, 0, 0, (outs), (ins abscalltarget:$dst),
"ba $dst", IIC_BrB,
[]>;
}
// While longjmp is a control-flow barrier (fallthrough isn't allowed), setjmp
// is not.
let hasSideEffects = 1 in {
let Defs = [CTR] in
def EH_SjLj_SetJmp32 : PPCCustomInserterPseudo<(outs gprc:$dst), (ins memr:$buf),
"#EH_SJLJ_SETJMP32",
[(set i32:$dst, (PPCeh_sjlj_setjmp addr:$buf))]>,
Requires<[In32BitMode]>;
}
let hasSideEffects = 1, isBarrier = 1 in {
let isTerminator = 1 in
def EH_SjLj_LongJmp32 : PPCCustomInserterPseudo<(outs), (ins memr:$buf),
"#EH_SJLJ_LONGJMP32",
[(PPCeh_sjlj_longjmp addr:$buf)]>,
Requires<[In32BitMode]>;
}
// This pseudo is never removed from the function, as it serves as
// a terminator. Size is set to 0 to prevent the builtin assembler
// from emitting it.
let isBranch = 1, isTerminator = 1, Size = 0 in {
def EH_SjLj_Setup : PPCEmitTimePseudo<(outs), (ins directbrtarget:$dst),
"#EH_SjLj_Setup\t$dst", []>;
}
// System call.
let PPC970_Unit = 7 in {
def SC : SCForm<17, 1, (outs), (ins i32imm:$lev),
"sc $lev", IIC_BrB, [(PPCsc (i32 imm:$lev))]>;
}
// Branch history rolling buffer.
def CLRBHRB : XForm_0<31, 430, (outs), (ins), "clrbhrb", IIC_BrB,
[(PPCclrbhrb)]>,
PPC970_DGroup_Single;
// The $dmy argument used for MFBHRBE is not needed; however, including
// it avoids automatic generation of PPCFastISel::fastEmit_i(), which
// interferes with necessary special handling (see PPCFastISel.cpp).
def MFBHRBE : XFXForm_3p<31, 302, (outs gprc:$rD),
(ins u10imm:$imm, u10imm:$dmy),
"mfbhrbe $rD, $imm", IIC_BrB,
[(set i32:$rD,
(PPCmfbhrbe imm:$imm, imm:$dmy))]>,
PPC970_DGroup_First;
def RFEBB : XLForm_S<19, 146, (outs), (ins u1imm:$imm), "rfebb $imm",
IIC_BrB, [(PPCrfebb (i32 imm:$imm))]>,
PPC970_DGroup_Single;
// DCB* instructions.
def DCBA : DCB_Form<758, 0, (outs), (ins memrr:$dst), "dcba $dst",
IIC_LdStDCBF, [(int_ppc_dcba xoaddr:$dst)]>,
PPC970_DGroup_Single;
def DCBI : DCB_Form<470, 0, (outs), (ins memrr:$dst), "dcbi $dst",
IIC_LdStDCBF, [(int_ppc_dcbi xoaddr:$dst)]>,
PPC970_DGroup_Single;
def DCBST : DCB_Form<54, 0, (outs), (ins memrr:$dst), "dcbst $dst",
IIC_LdStDCBF, [(int_ppc_dcbst xoaddr:$dst)]>,
PPC970_DGroup_Single;
def DCBZ : DCB_Form<1014, 0, (outs), (ins memrr:$dst), "dcbz $dst",
IIC_LdStDCBF, [(int_ppc_dcbz xoaddr:$dst)]>,
PPC970_DGroup_Single;
def DCBZL : DCB_Form<1014, 1, (outs), (ins memrr:$dst), "dcbzl $dst",
IIC_LdStDCBF, [(int_ppc_dcbzl xoaddr:$dst)]>,
PPC970_DGroup_Single;
def DCBF : DCB_Form_hint<86, (outs), (ins u5imm:$TH, memrr:$dst),
"dcbf $dst, $TH", IIC_LdStDCBF, []>,
PPC970_DGroup_Single;
let hasSideEffects = 0, mayLoad = 1, mayStore = 1 in {
def DCBT : DCB_Form_hint<278, (outs), (ins u5imm:$TH, memrr:$dst),
"dcbt $dst, $TH", IIC_LdStDCBF, []>,
PPC970_DGroup_Single;
def DCBTST : DCB_Form_hint<246, (outs), (ins u5imm:$TH, memrr:$dst),
"dcbtst $dst, $TH", IIC_LdStDCBF, []>,
PPC970_DGroup_Single;
} // hasSideEffects = 0
def ICBLC : XForm_icbt<31, 230, (outs), (ins u4imm:$CT, memrr:$src),
"icblc $CT, $src", IIC_LdStStore>, Requires<[HasICBT]>;
def ICBLQ : XForm_icbt<31, 198, (outs), (ins u4imm:$CT, memrr:$src),
"icblq. $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>;
def ICBT : XForm_icbt<31, 22, (outs), (ins u4imm:$CT, memrr:$src),
"icbt $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>;
def ICBTLS : XForm_icbt<31, 486, (outs), (ins u4imm:$CT, memrr:$src),
"icbtls $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>;
def : Pat<(int_ppc_dcbt xoaddr:$dst),
(DCBT 0, xoaddr:$dst)>;
def : Pat<(int_ppc_dcbtst xoaddr:$dst),
(DCBTST 0, xoaddr:$dst)>;
def : Pat<(int_ppc_dcbf xoaddr:$dst),
(DCBF 0, xoaddr:$dst)>;
def : Pat<(prefetch xoaddr:$dst, (i32 0), imm, (i32 1)),
(DCBT 0, xoaddr:$dst)>; // data prefetch for loads
def : Pat<(prefetch xoaddr:$dst, (i32 1), imm, (i32 1)),
(DCBTST 0, xoaddr:$dst)>; // data prefetch for stores
def : Pat<(prefetch xoaddr:$dst, (i32 0), imm, (i32 0)),
(ICBT 0, xoaddr:$dst)>, Requires<[HasICBT]>; // inst prefetch (for read)
// Atomic operations
// FIXME: some of these might be used with constant operands. This will result
// in constant materialization instructions that may be redundant. We currently
// clean this up in PPCMIPeephole with calls to
// PPCInstrInfo::convertToImmediateForm() but we should probably not emit them
// in the first place.
let Defs = [CR0] in {
def ATOMIC_LOAD_ADD_I8 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_ADD_I8",
[(set i32:$dst, (atomic_load_add_8 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_SUB_I8 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_SUB_I8",
[(set i32:$dst, (atomic_load_sub_8 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_AND_I8 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_AND_I8",
[(set i32:$dst, (atomic_load_and_8 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_OR_I8 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_OR_I8",
[(set i32:$dst, (atomic_load_or_8 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_XOR_I8 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "ATOMIC_LOAD_XOR_I8",
[(set i32:$dst, (atomic_load_xor_8 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_NAND_I8 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_NAND_I8",
[(set i32:$dst, (atomic_load_nand_8 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_MIN_I8 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_MIN_I8",
[(set i32:$dst, (atomic_load_min_8 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_MAX_I8 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_MAX_I8",
[(set i32:$dst, (atomic_load_max_8 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_UMIN_I8 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_UMIN_I8",
[(set i32:$dst, (atomic_load_umin_8 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_UMAX_I8 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_UMAX_I8",
[(set i32:$dst, (atomic_load_umax_8 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_ADD_I16 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_ADD_I16",
[(set i32:$dst, (atomic_load_add_16 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_SUB_I16 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_SUB_I16",
[(set i32:$dst, (atomic_load_sub_16 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_AND_I16 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_AND_I16",
[(set i32:$dst, (atomic_load_and_16 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_OR_I16 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_OR_I16",
[(set i32:$dst, (atomic_load_or_16 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_XOR_I16 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_XOR_I16",
[(set i32:$dst, (atomic_load_xor_16 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_NAND_I16 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_NAND_I16",
[(set i32:$dst, (atomic_load_nand_16 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_MIN_I16 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_MIN_I16",
[(set i32:$dst, (atomic_load_min_16 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_MAX_I16 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_MAX_I16",
[(set i32:$dst, (atomic_load_max_16 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_UMIN_I16 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_UMIN_I16",
[(set i32:$dst, (atomic_load_umin_16 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_UMAX_I16 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_UMAX_I16",
[(set i32:$dst, (atomic_load_umax_16 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_ADD_I32 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_ADD_I32",
[(set i32:$dst, (atomic_load_add_32 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_SUB_I32 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_SUB_I32",
[(set i32:$dst, (atomic_load_sub_32 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_AND_I32 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_AND_I32",
[(set i32:$dst, (atomic_load_and_32 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_OR_I32 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_OR_I32",
[(set i32:$dst, (atomic_load_or_32 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_XOR_I32 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_XOR_I32",
[(set i32:$dst, (atomic_load_xor_32 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_NAND_I32 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_NAND_I32",
[(set i32:$dst, (atomic_load_nand_32 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_MIN_I32 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_MIN_I32",
[(set i32:$dst, (atomic_load_min_32 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_MAX_I32 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_MAX_I32",
[(set i32:$dst, (atomic_load_max_32 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_UMIN_I32 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_UMIN_I32",
[(set i32:$dst, (atomic_load_umin_32 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_LOAD_UMAX_I32 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_UMAX_I32",
[(set i32:$dst, (atomic_load_umax_32 xoaddr:$ptr, i32:$incr))]>;
def ATOMIC_CMP_SWAP_I8 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$old, gprc:$new), "#ATOMIC_CMP_SWAP_I8",
[(set i32:$dst, (atomic_cmp_swap_8 xoaddr:$ptr, i32:$old, i32:$new))]>;
def ATOMIC_CMP_SWAP_I16 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$old, gprc:$new), "#ATOMIC_CMP_SWAP_I16 $dst $ptr $old $new",
[(set i32:$dst, (atomic_cmp_swap_16 xoaddr:$ptr, i32:$old, i32:$new))]>;
def ATOMIC_CMP_SWAP_I32 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$old, gprc:$new), "#ATOMIC_CMP_SWAP_I32 $dst $ptr $old $new",
[(set i32:$dst, (atomic_cmp_swap_32 xoaddr:$ptr, i32:$old, i32:$new))]>;
def ATOMIC_SWAP_I8 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$new), "#ATOMIC_SWAP_i8",
[(set i32:$dst, (atomic_swap_8 xoaddr:$ptr, i32:$new))]>;
def ATOMIC_SWAP_I16 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$new), "#ATOMIC_SWAP_I16",
[(set i32:$dst, (atomic_swap_16 xoaddr:$ptr, i32:$new))]>;
def ATOMIC_SWAP_I32 : PPCCustomInserterPseudo<
(outs gprc:$dst), (ins memrr:$ptr, gprc:$new), "#ATOMIC_SWAP_I32",
[(set i32:$dst, (atomic_swap_32 xoaddr:$ptr, i32:$new))]>;
}
def : Pat<(PPCatomicCmpSwap_8 xoaddr:$ptr, i32:$old, i32:$new),
(ATOMIC_CMP_SWAP_I8 xoaddr:$ptr, i32:$old, i32:$new)>;
def : Pat<(PPCatomicCmpSwap_16 xoaddr:$ptr, i32:$old, i32:$new),
(ATOMIC_CMP_SWAP_I16 xoaddr:$ptr, i32:$old, i32:$new)>;
// Instructions to support atomic operations
let mayLoad = 1, mayStore = 0, hasSideEffects = 0 in {
def LBARX : XForm_1_memOp<31, 52, (outs gprc:$rD), (ins memrr:$src),
"lbarx $rD, $src", IIC_LdStLWARX, []>,
Requires<[HasPartwordAtomics]>;
def LHARX : XForm_1_memOp<31, 116, (outs gprc:$rD), (ins memrr:$src),
"lharx $rD, $src", IIC_LdStLWARX, []>,
Requires<[HasPartwordAtomics]>;
def LWARX : XForm_1_memOp<31, 20, (outs gprc:$rD), (ins memrr:$src),
"lwarx $rD, $src", IIC_LdStLWARX, []>;
// Instructions to support lock versions of atomics
// (EH=1 - see Power ISA 2.07 Book II 4.4.2)
def LBARXL : XForm_1_memOp<31, 52, (outs gprc:$rD), (ins memrr:$src),
"lbarx $rD, $src, 1", IIC_LdStLWARX, []>, isDOT,
Requires<[HasPartwordAtomics]>;
def LHARXL : XForm_1_memOp<31, 116, (outs gprc:$rD), (ins memrr:$src),
"lharx $rD, $src, 1", IIC_LdStLWARX, []>, isDOT,
Requires<[HasPartwordAtomics]>;
def LWARXL : XForm_1_memOp<31, 20, (outs gprc:$rD), (ins memrr:$src),
"lwarx $rD, $src, 1", IIC_LdStLWARX, []>, isDOT;
// The atomic instructions use the destination register as well as the next one
// or two registers in order (modulo 31).
let hasExtraSrcRegAllocReq = 1 in
def LWAT : X_RD5_RS5_IM5<31, 582, (outs gprc:$rD), (ins gprc:$rA, u5imm:$FC),
"lwat $rD, $rA, $FC", IIC_LdStLoad>,
Requires<[IsISA3_0]>;
}
let Defs = [CR0], mayStore = 1, mayLoad = 0, hasSideEffects = 0 in {
def STBCX : XForm_1_memOp<31, 694, (outs), (ins gprc:$rS, memrr:$dst),
"stbcx. $rS, $dst", IIC_LdStSTWCX, []>,
isDOT, Requires<[HasPartwordAtomics]>;
def STHCX : XForm_1_memOp<31, 726, (outs), (ins gprc:$rS, memrr:$dst),
"sthcx. $rS, $dst", IIC_LdStSTWCX, []>,
isDOT, Requires<[HasPartwordAtomics]>;
def STWCX : XForm_1_memOp<31, 150, (outs), (ins gprc:$rS, memrr:$dst),
"stwcx. $rS, $dst", IIC_LdStSTWCX, []>, isDOT;
}
let mayStore = 1, mayLoad = 0, hasSideEffects = 0 in
def STWAT : X_RD5_RS5_IM5<31, 710, (outs), (ins gprc:$rS, gprc:$rA, u5imm:$FC),
"stwat $rS, $rA, $FC", IIC_LdStStore>,
Requires<[IsISA3_0]>;
let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1 in
def TRAP : XForm_24<31, 4, (outs), (ins), "trap", IIC_LdStLoad, [(trap)]>;
def TWI : DForm_base<3, (outs), (ins u5imm:$to, gprc:$rA, s16imm:$imm),
"twi $to, $rA, $imm", IIC_IntTrapW, []>;
def TW : XForm_1<31, 4, (outs), (ins u5imm:$to, gprc:$rA, gprc:$rB),
"tw $to, $rA, $rB", IIC_IntTrapW, []>;
def TDI : DForm_base<2, (outs), (ins u5imm:$to, g8rc:$rA, s16imm:$imm),
"tdi $to, $rA, $imm", IIC_IntTrapD, []>;
def TD : XForm_1<31, 68, (outs), (ins u5imm:$to, g8rc:$rA, g8rc:$rB),
"td $to, $rA, $rB", IIC_IntTrapD, []>;
//===----------------------------------------------------------------------===//
// PPC32 Load Instructions.
//
// Unindexed (r+i) Loads.
let PPC970_Unit = 2 in {
def LBZ : DForm_1<34, (outs gprc:$rD), (ins memri:$src),
"lbz $rD, $src", IIC_LdStLoad,
[(set i32:$rD, (zextloadi8 iaddr:$src))]>;
def LHA : DForm_1<42, (outs gprc:$rD), (ins memri:$src),
"lha $rD, $src", IIC_LdStLHA,
[(set i32:$rD, (sextloadi16 iaddr:$src))]>,
PPC970_DGroup_Cracked;
def LHZ : DForm_1<40, (outs gprc:$rD), (ins memri:$src),
"lhz $rD, $src", IIC_LdStLoad,
[(set i32:$rD, (zextloadi16 iaddr:$src))]>;
def LWZ : DForm_1<32, (outs gprc:$rD), (ins memri:$src),
"lwz $rD, $src", IIC_LdStLoad,
[(set i32:$rD, (load iaddr:$src))]>;
let Predicates = [HasFPU] in {
def LFS : DForm_1<48, (outs f4rc:$rD), (ins memri:$src),
"lfs $rD, $src", IIC_LdStLFD,
[(set f32:$rD, (load iaddr:$src))]>;
def LFD : DForm_1<50, (outs f8rc:$rD), (ins memri:$src),
"lfd $rD, $src", IIC_LdStLFD,
[(set f64:$rD, (load iaddr:$src))]>;
}
// Unindexed (r+i) Loads with Update (preinc).
let mayLoad = 1, mayStore = 0, hasSideEffects = 0 in {
def LBZU : DForm_1<35, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr),
"lbzu $rD, $addr", IIC_LdStLoadUpd,
[]>, RegConstraint<"$addr.reg = $ea_result">,
NoEncode<"$ea_result">;
def LHAU : DForm_1<43, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr),
"lhau $rD, $addr", IIC_LdStLHAU,
[]>, RegConstraint<"$addr.reg = $ea_result">,
NoEncode<"$ea_result">;
def LHZU : DForm_1<41, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr),
"lhzu $rD, $addr", IIC_LdStLoadUpd,
[]>, RegConstraint<"$addr.reg = $ea_result">,
NoEncode<"$ea_result">;
def LWZU : DForm_1<33, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr),
"lwzu $rD, $addr", IIC_LdStLoadUpd,
[]>, RegConstraint<"$addr.reg = $ea_result">,
NoEncode<"$ea_result">;
let Predicates = [HasFPU] in {
def LFSU : DForm_1<49, (outs f4rc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr),
"lfsu $rD, $addr", IIC_LdStLFDU,
[]>, RegConstraint<"$addr.reg = $ea_result">,
NoEncode<"$ea_result">;
def LFDU : DForm_1<51, (outs f8rc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr),
"lfdu $rD, $addr", IIC_LdStLFDU,
[]>, RegConstraint<"$addr.reg = $ea_result">,
NoEncode<"$ea_result">;
}
// Indexed (r+r) Loads with Update (preinc).
def LBZUX : XForm_1_memOp<31, 119, (outs gprc:$rD, ptr_rc_nor0:$ea_result),
(ins memrr:$addr),
"lbzux $rD, $addr", IIC_LdStLoadUpdX,
[]>, RegConstraint<"$addr.ptrreg = $ea_result">,
NoEncode<"$ea_result">;
def LHAUX : XForm_1_memOp<31, 375, (outs gprc:$rD, ptr_rc_nor0:$ea_result),
(ins memrr:$addr),
"lhaux $rD, $addr", IIC_LdStLHAUX,
[]>, RegConstraint<"$addr.ptrreg = $ea_result">,
NoEncode<"$ea_result">;
def LHZUX : XForm_1_memOp<31, 311, (outs gprc:$rD, ptr_rc_nor0:$ea_result),
(ins memrr:$addr),
"lhzux $rD, $addr", IIC_LdStLoadUpdX,
[]>, RegConstraint<"$addr.ptrreg = $ea_result">,
NoEncode<"$ea_result">;
def LWZUX : XForm_1_memOp<31, 55, (outs gprc:$rD, ptr_rc_nor0:$ea_result),
(ins memrr:$addr),
"lwzux $rD, $addr", IIC_LdStLoadUpdX,
[]>, RegConstraint<"$addr.ptrreg = $ea_result">,
NoEncode<"$ea_result">;
let Predicates = [HasFPU] in {
def LFSUX : XForm_1_memOp<31, 567, (outs f4rc:$rD, ptr_rc_nor0:$ea_result),
(ins memrr:$addr),
"lfsux $rD, $addr", IIC_LdStLFDUX,
[]>, RegConstraint<"$addr.ptrreg = $ea_result">,
NoEncode<"$ea_result">;
def LFDUX : XForm_1_memOp<31, 631, (outs f8rc:$rD, ptr_rc_nor0:$ea_result),
(ins memrr:$addr),
"lfdux $rD, $addr", IIC_LdStLFDUX,
[]>, RegConstraint<"$addr.ptrreg = $ea_result">,
NoEncode<"$ea_result">;
}
}
}
// Indexed (r+r) Loads.
//
let PPC970_Unit = 2, mayLoad = 1, mayStore = 0 in {
def LBZX : XForm_1_memOp<31, 87, (outs gprc:$rD), (ins memrr:$src),
"lbzx $rD, $src", IIC_LdStLoad,
[(set i32:$rD, (zextloadi8 xaddr:$src))]>;
def LHAX : XForm_1_memOp<31, 343, (outs gprc:$rD), (ins memrr:$src),
"lhax $rD, $src", IIC_LdStLHA,
[(set i32:$rD, (sextloadi16 xaddr:$src))]>,
PPC970_DGroup_Cracked;
def LHZX : XForm_1_memOp<31, 279, (outs gprc:$rD), (ins memrr:$src),
"lhzx $rD, $src", IIC_LdStLoad,
[(set i32:$rD, (zextloadi16 xaddr:$src))]>;
def LWZX : XForm_1_memOp<31, 23, (outs gprc:$rD), (ins memrr:$src),
"lwzx $rD, $src", IIC_LdStLoad,
[(set i32:$rD, (load xaddr:$src))]>;
def LHBRX : XForm_1_memOp<31, 790, (outs gprc:$rD), (ins memrr:$src),
"lhbrx $rD, $src", IIC_LdStLoad,
[(set i32:$rD, (PPClbrx xoaddr:$src, i16))]>;
def LWBRX : XForm_1_memOp<31, 534, (outs gprc:$rD), (ins memrr:$src),
"lwbrx $rD, $src", IIC_LdStLoad,
[(set i32:$rD, (PPClbrx xoaddr:$src, i32))]>;
let Predicates = [HasFPU] in {
def LFSX : XForm_25_memOp<31, 535, (outs f4rc:$frD), (ins memrr:$src),
"lfsx $frD, $src", IIC_LdStLFD,
[(set f32:$frD, (load xaddr:$src))]>;
def LFDX : XForm_25_memOp<31, 599, (outs f8rc:$frD), (ins memrr:$src),
"lfdx $frD, $src", IIC_LdStLFD,
[(set f64:$frD, (load xaddr:$src))]>;
def LFIWAX : XForm_25_memOp<31, 855, (outs f8rc:$frD), (ins memrr:$src),
"lfiwax $frD, $src", IIC_LdStLFD,
[(set f64:$frD, (PPClfiwax xoaddr:$src))]>;
def LFIWZX : XForm_25_memOp<31, 887, (outs f8rc:$frD), (ins memrr:$src),
"lfiwzx $frD, $src", IIC_LdStLFD,
[(set f64:$frD, (PPClfiwzx xoaddr:$src))]>;
}
}
// Load Multiple
def LMW : DForm_1<46, (outs gprc:$rD), (ins memri:$src),
"lmw $rD, $src", IIC_LdStLMW, []>;
//===----------------------------------------------------------------------===//
// PPC32 Store Instructions.
//
// Unindexed (r+i) Stores.
let PPC970_Unit = 2, mayStore = 1, mayLoad = 0 in {
def STB : DForm_1<38, (outs), (ins gprc:$rS, memri:$dst),
"stb $rS, $dst", IIC_LdStStore,
[(truncstorei8 i32:$rS, iaddr:$dst)]>;
def STH : DForm_1<44, (outs), (ins gprc:$rS, memri:$dst),
"sth $rS, $dst", IIC_LdStStore,
[(truncstorei16 i32:$rS, iaddr:$dst)]>;
def STW : DForm_1<36, (outs), (ins gprc:$rS, memri:$dst),
"stw $rS, $dst", IIC_LdStStore,
[(store i32:$rS, iaddr:$dst)]>;
let Predicates = [HasFPU] in {
def STFS : DForm_1<52, (outs), (ins f4rc:$rS, memri:$dst),
"stfs $rS, $dst", IIC_LdStSTFD,
[(store f32:$rS, iaddr:$dst)]>;
def STFD : DForm_1<54, (outs), (ins f8rc:$rS, memri:$dst),
"stfd $rS, $dst", IIC_LdStSTFD,
[(store f64:$rS, iaddr:$dst)]>;
}
}
// Unindexed (r+i) Stores with Update (preinc).
let PPC970_Unit = 2, mayStore = 1, mayLoad = 0 in {
def STBU : DForm_1<39, (outs ptr_rc_nor0:$ea_res), (ins gprc:$rS, memri:$dst),
"stbu $rS, $dst", IIC_LdStSTU, []>,
RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">;
def STHU : DForm_1<45, (outs ptr_rc_nor0:$ea_res), (ins gprc:$rS, memri:$dst),
"sthu $rS, $dst", IIC_LdStSTU, []>,
RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">;
def STWU : DForm_1<37, (outs ptr_rc_nor0:$ea_res), (ins gprc:$rS, memri:$dst),
"stwu $rS, $dst", IIC_LdStSTU, []>,
RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">;
let Predicates = [HasFPU] in {
def STFSU : DForm_1<53, (outs ptr_rc_nor0:$ea_res), (ins f4rc:$rS, memri:$dst),
"stfsu $rS, $dst", IIC_LdStSTFDU, []>,
RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">;
def STFDU : DForm_1<55, (outs ptr_rc_nor0:$ea_res), (ins f8rc:$rS, memri:$dst),
"stfdu $rS, $dst", IIC_LdStSTFDU, []>,
RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">;
}
}
// Patterns to match the pre-inc stores. We can't put the patterns on
// the instruction definitions directly as ISel wants the address base
// and offset to be separate operands, not a single complex operand.
def : Pat<(pre_truncsti8 i32:$rS, iPTR:$ptrreg, iaddroff:$ptroff),
(STBU $rS, iaddroff:$ptroff, $ptrreg)>;
def : Pat<(pre_truncsti16 i32:$rS, iPTR:$ptrreg, iaddroff:$ptroff),
(STHU $rS, iaddroff:$ptroff, $ptrreg)>;
def : Pat<(pre_store i32:$rS, iPTR:$ptrreg, iaddroff:$ptroff),
(STWU $rS, iaddroff:$ptroff, $ptrreg)>;
def : Pat<(pre_store f32:$rS, iPTR:$ptrreg, iaddroff:$ptroff),
(STFSU $rS, iaddroff:$ptroff, $ptrreg)>;
def : Pat<(pre_store f64:$rS, iPTR:$ptrreg, iaddroff:$ptroff),
(STFDU $rS, iaddroff:$ptroff, $ptrreg)>;
// Indexed (r+r) Stores.
let PPC970_Unit = 2 in {
def STBX : XForm_8_memOp<31, 215, (outs), (ins gprc:$rS, memrr:$dst),
"stbx $rS, $dst", IIC_LdStStore,
[(truncstorei8 i32:$rS, xaddr:$dst)]>,
PPC970_DGroup_Cracked;
def STHX : XForm_8_memOp<31, 407, (outs), (ins gprc:$rS, memrr:$dst),
"sthx $rS, $dst", IIC_LdStStore,
[(truncstorei16 i32:$rS, xaddr:$dst)]>,
PPC970_DGroup_Cracked;
def STWX : XForm_8_memOp<31, 151, (outs), (ins gprc:$rS, memrr:$dst),
"stwx $rS, $dst", IIC_LdStStore,
[(store i32:$rS, xaddr:$dst)]>,
PPC970_DGroup_Cracked;
def STHBRX: XForm_8_memOp<31, 918, (outs), (ins gprc:$rS, memrr:$dst),
"sthbrx $rS, $dst", IIC_LdStStore,
[(PPCstbrx i32:$rS, xoaddr:$dst, i16)]>,
PPC970_DGroup_Cracked;
def STWBRX: XForm_8_memOp<31, 662, (outs), (ins gprc:$rS, memrr:$dst),
"stwbrx $rS, $dst", IIC_LdStStore,
[(PPCstbrx i32:$rS, xoaddr:$dst, i32)]>,
PPC970_DGroup_Cracked;
let Predicates = [HasFPU] in {
def STFIWX: XForm_28_memOp<31, 983, (outs), (ins f8rc:$frS, memrr:$dst),
"stfiwx $frS, $dst", IIC_LdStSTFD,
[(PPCstfiwx f64:$frS, xoaddr:$dst)]>;
def STFSX : XForm_28_memOp<31, 663, (outs), (ins f4rc:$frS, memrr:$dst),
"stfsx $frS, $dst", IIC_LdStSTFD,
[(store f32:$frS, xaddr:$dst)]>;
def STFDX : XForm_28_memOp<31, 727, (outs), (ins f8rc:$frS, memrr:$dst),
"stfdx $frS, $dst", IIC_LdStSTFD,
[(store f64:$frS, xaddr:$dst)]>;
}
}
// Indexed (r+r) Stores with Update (preinc).
let PPC970_Unit = 2, mayStore = 1, mayLoad = 0 in {
def STBUX : XForm_8_memOp<31, 247, (outs ptr_rc_nor0:$ea_res),
(ins gprc:$rS, memrr:$dst),
"stbux $rS, $dst", IIC_LdStSTUX, []>,
RegConstraint<"$dst.ptrreg = $ea_res">,
NoEncode<"$ea_res">,
PPC970_DGroup_Cracked;
def STHUX : XForm_8_memOp<31, 439, (outs ptr_rc_nor0:$ea_res),
(ins gprc:$rS, memrr:$dst),
"sthux $rS, $dst", IIC_LdStSTUX, []>,
RegConstraint<"$dst.ptrreg = $ea_res">,
NoEncode<"$ea_res">,
PPC970_DGroup_Cracked;
def STWUX : XForm_8_memOp<31, 183, (outs ptr_rc_nor0:$ea_res),
(ins gprc:$rS, memrr:$dst),
"stwux $rS, $dst", IIC_LdStSTUX, []>,
RegConstraint<"$dst.ptrreg = $ea_res">,
NoEncode<"$ea_res">,
PPC970_DGroup_Cracked;
let Predicates = [HasFPU] in {
def STFSUX: XForm_8_memOp<31, 695, (outs ptr_rc_nor0:$ea_res),
(ins f4rc:$rS, memrr:$dst),
"stfsux $rS, $dst", IIC_LdStSTFDU, []>,
RegConstraint<"$dst.ptrreg = $ea_res">,
NoEncode<"$ea_res">,
PPC970_DGroup_Cracked;
def STFDUX: XForm_8_memOp<31, 759, (outs ptr_rc_nor0:$ea_res),
(ins f8rc:$rS, memrr:$dst),
"stfdux $rS, $dst", IIC_LdStSTFDU, []>,
RegConstraint<"$dst.ptrreg = $ea_res">,
NoEncode<"$ea_res">,
PPC970_DGroup_Cracked;
}
}
// Patterns to match the pre-inc stores. We can't put the patterns on
// the instruction definitions directly as ISel wants the address base
// and offset to be separate operands, not a single complex operand.
def : Pat<(pre_truncsti8 i32:$rS, iPTR:$ptrreg, iPTR:$ptroff),
(STBUX $rS, $ptrreg, $ptroff)>;
def : Pat<(pre_truncsti16 i32:$rS, iPTR:$ptrreg, iPTR:$ptroff),
(STHUX $rS, $ptrreg, $ptroff)>;
def : Pat<(pre_store i32:$rS, iPTR:$ptrreg, iPTR:$ptroff),
(STWUX $rS, $ptrreg, $ptroff)>;
let Predicates = [HasFPU] in {
def : Pat<(pre_store f32:$rS, iPTR:$ptrreg, iPTR:$ptroff),
(STFSUX $rS, $ptrreg, $ptroff)>;
def : Pat<(pre_store f64:$rS, iPTR:$ptrreg, iPTR:$ptroff),
(STFDUX $rS, $ptrreg, $ptroff)>;
}
// Store Multiple
def STMW : DForm_1<47, (outs), (ins gprc:$rS, memri:$dst),
"stmw $rS, $dst", IIC_LdStLMW, []>;
def SYNC : XForm_24_sync<31, 598, (outs), (ins i32imm:$L),
"sync $L", IIC_LdStSync, []>;
let isCodeGenOnly = 1 in {
def MSYNC : XForm_24_sync<31, 598, (outs), (ins),
"msync", IIC_LdStSync, []> {
let L = 0;
}
}
def : Pat<(int_ppc_sync), (SYNC 0)>, Requires<[HasSYNC]>;
def : Pat<(int_ppc_lwsync), (SYNC 1)>, Requires<[HasSYNC]>;
def : Pat<(int_ppc_sync), (MSYNC)>, Requires<[HasOnlyMSYNC]>;
def : Pat<(int_ppc_lwsync), (MSYNC)>, Requires<[HasOnlyMSYNC]>;
//===----------------------------------------------------------------------===//
// PPC32 Arithmetic Instructions.
//
let PPC970_Unit = 1 in { // FXU Operations.
def ADDI : DForm_2<14, (outs gprc:$rD), (ins gprc_nor0:$rA, s16imm:$imm),
"addi $rD, $rA, $imm", IIC_IntSimple,
[(set i32:$rD, (add i32:$rA, imm32SExt16:$imm))]>;
let BaseName = "addic" in {
let Defs = [CARRY] in
def ADDIC : DForm_2<12, (outs gprc:$rD), (ins gprc:$rA, s16imm:$imm),
"addic $rD, $rA, $imm", IIC_IntGeneral,
[(set i32:$rD, (addc i32:$rA, imm32SExt16:$imm))]>,
RecFormRel, PPC970_DGroup_Cracked;
let Defs = [CARRY, CR0] in
def ADDICo : DForm_2<13, (outs gprc:$rD), (ins gprc:$rA, s16imm:$imm),
"addic. $rD, $rA, $imm", IIC_IntGeneral,
[]>, isDOT, RecFormRel;
}
def ADDIS : DForm_2<15, (outs gprc:$rD), (ins gprc_nor0:$rA, s17imm:$imm),
"addis $rD, $rA, $imm", IIC_IntSimple,
[(set i32:$rD, (add i32:$rA, imm16ShiftedSExt:$imm))]>;
let isCodeGenOnly = 1 in
def LA : DForm_2<14, (outs gprc:$rD), (ins gprc_nor0:$rA, s16imm:$sym),
"la $rD, $sym($rA)", IIC_IntGeneral,
[(set i32:$rD, (add i32:$rA,
(PPClo tglobaladdr:$sym, 0)))]>;
def MULLI : DForm_2< 7, (outs gprc:$rD), (ins gprc:$rA, s16imm:$imm),
"mulli $rD, $rA, $imm", IIC_IntMulLI,
[(set i32:$rD, (mul i32:$rA, imm32SExt16:$imm))]>;
let Defs = [CARRY] in
def SUBFIC : DForm_2< 8, (outs gprc:$rD), (ins gprc:$rA, s16imm:$imm),
"subfic $rD, $rA, $imm", IIC_IntGeneral,
[(set i32:$rD, (subc imm32SExt16:$imm, i32:$rA))]>;
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in {
def LI : DForm_2_r0<14, (outs gprc:$rD), (ins s16imm:$imm),
"li $rD, $imm", IIC_IntSimple,
[(set i32:$rD, imm32SExt16:$imm)]>;
def LIS : DForm_2_r0<15, (outs gprc:$rD), (ins s17imm:$imm),
"lis $rD, $imm", IIC_IntSimple,
[(set i32:$rD, imm16ShiftedSExt:$imm)]>;
}
}
let PPC970_Unit = 1 in { // FXU Operations.
let Defs = [CR0] in {
def ANDIo : DForm_4<28, (outs gprc:$dst), (ins gprc:$src1, u16imm:$src2),
"andi. $dst, $src1, $src2", IIC_IntGeneral,
[(set i32:$dst, (and i32:$src1, immZExt16:$src2))]>,
isDOT;
def ANDISo : DForm_4<29, (outs gprc:$dst), (ins gprc:$src1, u16imm:$src2),
"andis. $dst, $src1, $src2", IIC_IntGeneral,
[(set i32:$dst, (and i32:$src1, imm16ShiftedZExt:$src2))]>,
isDOT;
}
def ORI : DForm_4<24, (outs gprc:$dst), (ins gprc:$src1, u16imm:$src2),
"ori $dst, $src1, $src2", IIC_IntSimple,
[(set i32:$dst, (or i32:$src1, immZExt16:$src2))]>;
def ORIS : DForm_4<25, (outs gprc:$dst), (ins gprc:$src1, u16imm:$src2),
"oris $dst, $src1, $src2", IIC_IntSimple,
[(set i32:$dst, (or i32:$src1, imm16ShiftedZExt:$src2))]>;
def XORI : DForm_4<26, (outs gprc:$dst), (ins gprc:$src1, u16imm:$src2),
"xori $dst, $src1, $src2", IIC_IntSimple,
[(set i32:$dst, (xor i32:$src1, immZExt16:$src2))]>;
def XORIS : DForm_4<27, (outs gprc:$dst), (ins gprc:$src1, u16imm:$src2),
"xoris $dst, $src1, $src2", IIC_IntSimple,
[(set i32:$dst, (xor i32:$src1, imm16ShiftedZExt:$src2))]>;
def NOP : DForm_4_zero<24, (outs), (ins), "nop", IIC_IntSimple,
[]>;
let isCodeGenOnly = 1 in {
// The POWER6 and POWER7 have special group-terminating nops.
def NOP_GT_PWR6 : DForm_4_fixedreg_zero<24, 1, (outs), (ins),
"ori 1, 1, 0", IIC_IntSimple, []>;
def NOP_GT_PWR7 : DForm_4_fixedreg_zero<24, 2, (outs), (ins),
"ori 2, 2, 0", IIC_IntSimple, []>;
}
let isCompare = 1, hasSideEffects = 0 in {
def CMPWI : DForm_5_ext<11, (outs crrc:$crD), (ins gprc:$rA, s16imm:$imm),
"cmpwi $crD, $rA, $imm", IIC_IntCompare>;
def CMPLWI : DForm_6_ext<10, (outs crrc:$dst), (ins gprc:$src1, u16imm:$src2),
"cmplwi $dst, $src1, $src2", IIC_IntCompare>;
def CMPRB : X_BF3_L1_RS5_RS5<31, 192, (outs crbitrc:$BF),
(ins u1imm:$L, g8rc:$rA, g8rc:$rB),
"cmprb $BF, $L, $rA, $rB", IIC_IntCompare, []>,
Requires<[IsISA3_0]>;
}
}
let PPC970_Unit = 1, hasSideEffects = 0 in { // FXU Operations.
let isCommutable = 1 in {
defm NAND : XForm_6r<31, 476, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB),
"nand", "$rA, $rS, $rB", IIC_IntSimple,
[(set i32:$rA, (not (and i32:$rS, i32:$rB)))]>;
defm AND : XForm_6r<31, 28, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB),
"and", "$rA, $rS, $rB", IIC_IntSimple,
[(set i32:$rA, (and i32:$rS, i32:$rB))]>;
} // isCommutable
defm ANDC : XForm_6r<31, 60, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB),
"andc", "$rA, $rS, $rB", IIC_IntSimple,
[(set i32:$rA, (and i32:$rS, (not i32:$rB)))]>;
let isCommutable = 1 in {
defm OR : XForm_6r<31, 444, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB),
"or", "$rA, $rS, $rB", IIC_IntSimple,
[(set i32:$rA, (or i32:$rS, i32:$rB))]>;
defm NOR : XForm_6r<31, 124, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB),
"nor", "$rA, $rS, $rB", IIC_IntSimple,
[(set i32:$rA, (not (or i32:$rS, i32:$rB)))]>;
} // isCommutable
defm ORC : XForm_6r<31, 412, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB),
"orc", "$rA, $rS, $rB", IIC_IntSimple,
[(set i32:$rA, (or i32:$rS, (not i32:$rB)))]>;
let isCommutable = 1 in {
defm EQV : XForm_6r<31, 284, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB),
"eqv", "$rA, $rS, $rB", IIC_IntSimple,
[(set i32:$rA, (not (xor i32:$rS, i32:$rB)))]>;
defm XOR : XForm_6r<31, 316, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB),
"xor", "$rA, $rS, $rB", IIC_IntSimple,
[(set i32:$rA, (xor i32:$rS, i32:$rB))]>;
} // isCommutable
defm SLW : XForm_6r<31, 24, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB),
"slw", "$rA, $rS, $rB", IIC_IntGeneral,
[(set i32:$rA, (PPCshl i32:$rS, i32:$rB))]>;
defm SRW : XForm_6r<31, 536, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB),
"srw", "$rA, $rS, $rB", IIC_IntGeneral,
[(set i32:$rA, (PPCsrl i32:$rS, i32:$rB))]>;
defm SRAW : XForm_6rc<31, 792, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB),
"sraw", "$rA, $rS, $rB", IIC_IntShift,
[(set i32:$rA, (PPCsra i32:$rS, i32:$rB))]>;
}
let PPC970_Unit = 1 in { // FXU Operations.
let hasSideEffects = 0 in {
defm SRAWI : XForm_10rc<31, 824, (outs gprc:$rA), (ins gprc:$rS, u5imm:$SH),
"srawi", "$rA, $rS, $SH", IIC_IntShift,
[(set i32:$rA, (sra i32:$rS, (i32 imm:$SH)))]>;
defm CNTLZW : XForm_11r<31, 26, (outs gprc:$rA), (ins gprc:$rS),
"cntlzw", "$rA, $rS", IIC_IntGeneral,
[(set i32:$rA, (ctlz i32:$rS))]>;
defm CNTTZW : XForm_11r<31, 538, (outs gprc:$rA), (ins gprc:$rS),
"cnttzw", "$rA, $rS", IIC_IntGeneral,
[(set i32:$rA, (cttz i32:$rS))]>, Requires<[IsISA3_0]>;
defm EXTSB : XForm_11r<31, 954, (outs gprc:$rA), (ins gprc:$rS),
"extsb", "$rA, $rS", IIC_IntSimple,
[(set i32:$rA, (sext_inreg i32:$rS, i8))]>;
defm EXTSH : XForm_11r<31, 922, (outs gprc:$rA), (ins gprc:$rS),
"extsh", "$rA, $rS", IIC_IntSimple,
[(set i32:$rA, (sext_inreg i32:$rS, i16))]>;
let isCommutable = 1 in
def CMPB : XForm_6<31, 508, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB),
"cmpb $rA, $rS, $rB", IIC_IntGeneral,
[(set i32:$rA, (PPCcmpb i32:$rS, i32:$rB))]>;
}
let isCompare = 1, hasSideEffects = 0 in {
def CMPW : XForm_16_ext<31, 0, (outs crrc:$crD), (ins gprc:$rA, gprc:$rB),
"cmpw $crD, $rA, $rB", IIC_IntCompare>;
def CMPLW : XForm_16_ext<31, 32, (outs crrc:$crD), (ins gprc:$rA, gprc:$rB),
"cmplw $crD, $rA, $rB", IIC_IntCompare>;
}
}
let PPC970_Unit = 3, Predicates = [HasFPU] in { // FPU Operations.
//def FCMPO : XForm_17<63, 32, (outs CRRC:$crD), (ins FPRC:$fA, FPRC:$fB),
// "fcmpo $crD, $fA, $fB", IIC_FPCompare>;
let isCompare = 1, hasSideEffects = 0 in {
def FCMPUS : XForm_17<63, 0, (outs crrc:$crD), (ins f4rc:$fA, f4rc:$fB),
"fcmpu $crD, $fA, $fB", IIC_FPCompare>;
let Interpretation64Bit = 1, isCodeGenOnly = 1 in
def FCMPUD : XForm_17<63, 0, (outs crrc:$crD), (ins f8rc:$fA, f8rc:$fB),
"fcmpu $crD, $fA, $fB", IIC_FPCompare>;
}
def FTDIV: XForm_17<63, 128, (outs crrc:$crD), (ins f8rc:$fA, f8rc:$fB),
"ftdiv $crD, $fA, $fB", IIC_FPCompare>;
def FTSQRT: XForm_17a<63, 160, (outs crrc:$crD), (ins f8rc:$fB),
"ftsqrt $crD, $fB", IIC_FPCompare>;
let Uses = [RM] in {
let hasSideEffects = 0 in {
defm FCTIW : XForm_26r<63, 14, (outs f8rc:$frD), (ins f8rc:$frB),
"fctiw", "$frD, $frB", IIC_FPGeneral,
[]>;
defm FCTIWU : XForm_26r<63, 142, (outs f8rc:$frD), (ins f8rc:$frB),
"fctiwu", "$frD, $frB", IIC_FPGeneral,
[]>;
defm FCTIWZ : XForm_26r<63, 15, (outs f8rc:$frD), (ins f8rc:$frB),
"fctiwz", "$frD, $frB", IIC_FPGeneral,
[(set f64:$frD, (PPCfctiwz f64:$frB))]>;
defm FRSP : XForm_26r<63, 12, (outs f4rc:$frD), (ins f8rc:$frB),
"frsp", "$frD, $frB", IIC_FPGeneral,
[(set f32:$frD, (fpround f64:$frB))]>;
let Interpretation64Bit = 1, isCodeGenOnly = 1 in
defm FRIND : XForm_26r<63, 392, (outs f8rc:$frD), (ins f8rc:$frB),
"frin", "$frD, $frB", IIC_FPGeneral,
[(set f64:$frD, (fround f64:$frB))]>;
defm FRINS : XForm_26r<63, 392, (outs f4rc:$frD), (ins f4rc:$frB),
"frin", "$frD, $frB", IIC_FPGeneral,
[(set f32:$frD, (fround f32:$frB))]>;
}
let hasSideEffects = 0 in {
let Interpretation64Bit = 1, isCodeGenOnly = 1 in
defm FRIPD : XForm_26r<63, 456, (outs f8rc:$frD), (ins f8rc:$frB),
"frip", "$frD, $frB", IIC_FPGeneral,
[(set f64:$frD, (fceil f64:$frB))]>;
defm FRIPS : XForm_26r<63, 456, (outs f4rc:$frD), (ins f4rc:$frB),
"frip", "$frD, $frB", IIC_FPGeneral,
[(set f32:$frD, (fceil f32:$frB))]>;
let Interpretation64Bit = 1, isCodeGenOnly = 1 in
defm FRIZD : XForm_26r<63, 424, (outs f8rc:$frD), (ins f8rc:$frB),
"friz", "$frD, $frB", IIC_FPGeneral,
[(set f64:$frD, (ftrunc f64:$frB))]>;
defm FRIZS : XForm_26r<63, 424, (outs f4rc:$frD), (ins f4rc:$frB),
"friz", "$frD, $frB", IIC_FPGeneral,
[(set f32:$frD, (ftrunc f32:$frB))]>;
let Interpretation64Bit = 1, isCodeGenOnly = 1 in
defm FRIMD : XForm_26r<63, 488, (outs f8rc:$frD), (ins f8rc:$frB),
"frim", "$frD, $frB", IIC_FPGeneral,
[(set f64:$frD, (ffloor f64:$frB))]>;
defm FRIMS : XForm_26r<63, 488, (outs f4rc:$frD), (ins f4rc:$frB),
"frim", "$frD, $frB", IIC_FPGeneral,
[(set f32:$frD, (ffloor f32:$frB))]>;
defm FSQRT : XForm_26r<63, 22, (outs f8rc:$frD), (ins f8rc:$frB),
"fsqrt", "$frD, $frB", IIC_FPSqrtD,
[(set f64:$frD, (fsqrt f64:$frB))]>;
defm FSQRTS : XForm_26r<59, 22, (outs f4rc:$frD), (ins f4rc:$frB),
"fsqrts", "$frD, $frB", IIC_FPSqrtS,
[(set f32:$frD, (fsqrt f32:$frB))]>;
}
}
}
/// Note that FMR is defined as pseudo-ops on the PPC970 because they are
/// often coalesced away and we don't want the dispatch group builder to think
/// that they will fill slots (which could cause the load of a LSU reject to
/// sneak into a d-group with a store).
let hasSideEffects = 0, Predicates = [HasFPU] in
defm FMR : XForm_26r<63, 72, (outs f4rc:$frD), (ins f4rc:$frB),
"fmr", "$frD, $frB", IIC_FPGeneral,
[]>, // (set f32:$frD, f32:$frB)
PPC970_Unit_Pseudo;
let PPC970_Unit = 3, hasSideEffects = 0, Predicates = [HasFPU] in { // FPU Operations.
// These are artificially split into two different forms, for 4/8 byte FP.
defm FABSS : XForm_26r<63, 264, (outs f4rc:$frD), (ins f4rc:$frB),
"fabs", "$frD, $frB", IIC_FPGeneral,
[(set f32:$frD, (fabs f32:$frB))]>;
let Interpretation64Bit = 1, isCodeGenOnly = 1 in
defm FABSD : XForm_26r<63, 264, (outs f8rc:$frD), (ins f8rc:$frB),
"fabs", "$frD, $frB", IIC_FPGeneral,
[(set f64:$frD, (fabs f64:$frB))]>;
defm FNABSS : XForm_26r<63, 136, (outs f4rc:$frD), (ins f4rc:$frB),
"fnabs", "$frD, $frB", IIC_FPGeneral,
[(set f32:$frD, (fneg (fabs f32:$frB)))]>;
let Interpretation64Bit = 1, isCodeGenOnly = 1 in
defm FNABSD : XForm_26r<63, 136, (outs f8rc:$frD), (ins f8rc:$frB),
"fnabs", "$frD, $frB", IIC_FPGeneral,
[(set f64:$frD, (fneg (fabs f64:$frB)))]>;
defm FNEGS : XForm_26r<63, 40, (outs f4rc:$frD), (ins f4rc:$frB),
"fneg", "$frD, $frB", IIC_FPGeneral,
[(set f32:$frD, (fneg f32:$frB))]>;
let Interpretation64Bit = 1, isCodeGenOnly = 1 in
defm FNEGD : XForm_26r<63, 40, (outs f8rc:$frD), (ins f8rc:$frB),
"fneg", "$frD, $frB", IIC_FPGeneral,
[(set f64:$frD, (fneg f64:$frB))]>;
defm FCPSGNS : XForm_28r<63, 8, (outs f4rc:$frD), (ins f4rc:$frA, f4rc:$frB),
"fcpsgn", "$frD, $frA, $frB", IIC_FPGeneral,
[(set f32:$frD, (fcopysign f32:$frB, f32:$frA))]>;
let Interpretation64Bit = 1, isCodeGenOnly = 1 in
defm FCPSGND : XForm_28r<63, 8, (outs f8rc:$frD), (ins f8rc:$frA, f8rc:$frB),
"fcpsgn", "$frD, $frA, $frB", IIC_FPGeneral,
[(set f64:$frD, (fcopysign f64:$frB, f64:$frA))]>;
// Reciprocal estimates.
defm FRE : XForm_26r<63, 24, (outs f8rc:$frD), (ins f8rc:$frB),
"fre", "$frD, $frB", IIC_FPGeneral,
[(set f64:$frD, (PPCfre f64:$frB))]>;
defm FRES : XForm_26r<59, 24, (outs f4rc:$frD), (ins f4rc:$frB),
"fres", "$frD, $frB", IIC_FPGeneral,
[(set f32:$frD, (PPCfre f32:$frB))]>;
defm FRSQRTE : XForm_26r<63, 26, (outs f8rc:$frD), (ins f8rc:$frB),
"frsqrte", "$frD, $frB", IIC_FPGeneral,
[(set f64:$frD, (PPCfrsqrte f64:$frB))]>;
defm FRSQRTES : XForm_26r<59, 26, (outs f4rc:$frD), (ins f4rc:$frB),
"frsqrtes", "$frD, $frB", IIC_FPGeneral,
[(set f32:$frD, (PPCfrsqrte f32:$frB))]>;
}
// XL-Form instructions. condition register logical ops.
//
let hasSideEffects = 0 in
def MCRF : XLForm_3<19, 0, (outs crrc:$BF), (ins crrc:$BFA),
"mcrf $BF, $BFA", IIC_BrMCR>,
PPC970_DGroup_First, PPC970_Unit_CRU;
// FIXME: According to the ISA (section 2.5.1 of version 2.06), the
// condition-register logical instructions have preferred forms. Specifically,
// it is preferred that the bit specified by the BT field be in the same
// condition register as that specified by the bit BB. We might want to account
// for this via hinting the register allocator and anti-dep breakers, or we
// could constrain the register class to force this constraint and then loosen
// it during register allocation via convertToThreeAddress or some similar
// mechanism.
let isCommutable = 1 in {
def CRAND : XLForm_1<19, 257, (outs crbitrc:$CRD),
(ins crbitrc:$CRA, crbitrc:$CRB),
"crand $CRD, $CRA, $CRB", IIC_BrCR,
[(set i1:$CRD, (and i1:$CRA, i1:$CRB))]>;
def CRNAND : XLForm_1<19, 225, (outs crbitrc:$CRD),
(ins crbitrc:$CRA, crbitrc:$CRB),
"crnand $CRD, $CRA, $CRB", IIC_BrCR,
[(set i1:$CRD, (not (and i1:$CRA, i1:$CRB)))]>;
def CROR : XLForm_1<19, 449, (outs crbitrc:$CRD),
(ins crbitrc:$CRA, crbitrc:$CRB),
"cror $CRD, $CRA, $CRB", IIC_BrCR,
[(set i1:$CRD, (or i1:$CRA, i1:$CRB))]>;
def CRXOR : XLForm_1<19, 193, (outs crbitrc:$CRD),
(ins crbitrc:$CRA, crbitrc:$CRB),
"crxor $CRD, $CRA, $CRB", IIC_BrCR,
[(set i1:$CRD, (xor i1:$CRA, i1:$CRB))]>;
def CRNOR : XLForm_1<19, 33, (outs crbitrc:$CRD),
(ins crbitrc:$CRA, crbitrc:$CRB),
"crnor $CRD, $CRA, $CRB", IIC_BrCR,
[(set i1:$CRD, (not (or i1:$CRA, i1:$CRB)))]>;
def CREQV : XLForm_1<19, 289, (outs crbitrc:$CRD),
(ins crbitrc:$CRA, crbitrc:$CRB),
"creqv $CRD, $CRA, $CRB", IIC_BrCR,
[(set i1:$CRD, (not (xor i1:$CRA, i1:$CRB)))]>;
} // isCommutable
def CRANDC : XLForm_1<19, 129, (outs crbitrc:$CRD),
(ins crbitrc:$CRA, crbitrc:$CRB),
"crandc $CRD, $CRA, $CRB", IIC_BrCR,
[(set i1:$CRD, (and i1:$CRA, (not i1:$CRB)))]>;
def CRORC : XLForm_1<19, 417, (outs crbitrc:$CRD),
(ins crbitrc:$CRA, crbitrc:$CRB),
"crorc $CRD, $CRA, $CRB", IIC_BrCR,
[(set i1:$CRD, (or i1:$CRA, (not i1:$CRB)))]>;
let isCodeGenOnly = 1 in {
def CRSET : XLForm_1_ext<19, 289, (outs crbitrc:$dst), (ins),
"creqv $dst, $dst, $dst", IIC_BrCR,
[(set i1:$dst, 1)]>;
def CRUNSET: XLForm_1_ext<19, 193, (outs crbitrc:$dst), (ins),
"crxor $dst, $dst, $dst", IIC_BrCR,
[(set i1:$dst, 0)]>;
let Defs = [CR1EQ], CRD = 6 in {
def CR6SET : XLForm_1_ext<19, 289, (outs), (ins),
"creqv 6, 6, 6", IIC_BrCR,
[(PPCcr6set)]>;
def CR6UNSET: XLForm_1_ext<19, 193, (outs), (ins),
"crxor 6, 6, 6", IIC_BrCR,
[(PPCcr6unset)]>;
}
}
// XFX-Form instructions. Instructions that deal with SPRs.
//
def MFSPR : XFXForm_1<31, 339, (outs gprc:$RT), (ins i32imm:$SPR),
"mfspr $RT, $SPR", IIC_SprMFSPR>;
def MTSPR : XFXForm_1<31, 467, (outs), (ins i32imm:$SPR, gprc:$RT),
"mtspr $SPR, $RT", IIC_SprMTSPR>;
def MFTB : XFXForm_1<31, 371, (outs gprc:$RT), (ins i32imm:$SPR),
"mftb $RT, $SPR", IIC_SprMFTB>;
def MFPMR : XFXForm_1<31, 334, (outs gprc:$RT), (ins i32imm:$SPR),
"mfpmr $RT, $SPR", IIC_SprMFPMR>;
def MTPMR : XFXForm_1<31, 462, (outs), (ins i32imm:$SPR, gprc:$RT),
"mtpmr $SPR, $RT", IIC_SprMTPMR>;
// A pseudo-instruction used to implement the read of the 64-bit cycle counter
// on a 32-bit target.
let hasSideEffects = 1 in
def ReadTB : PPCCustomInserterPseudo<(outs gprc:$lo, gprc:$hi), (ins),
"#ReadTB", []>;
let Uses = [CTR] in {
def MFCTR : XFXForm_1_ext<31, 339, 9, (outs gprc:$rT), (ins),
"mfctr $rT", IIC_SprMFSPR>,
PPC970_DGroup_First, PPC970_Unit_FXU;
}
let Defs = [CTR], Pattern = [(PPCmtctr i32:$rS)] in {
def MTCTR : XFXForm_7_ext<31, 467, 9, (outs), (ins gprc:$rS),
"mtctr $rS", IIC_SprMTSPR>,
PPC970_DGroup_First, PPC970_Unit_FXU;
}
let hasSideEffects = 1, isCodeGenOnly = 1, Defs = [CTR] in {
let Pattern = [(int_ppc_mtctr i32:$rS)] in
def MTCTRloop : XFXForm_7_ext<31, 467, 9, (outs), (ins gprc:$rS),
"mtctr $rS", IIC_SprMTSPR>,
PPC970_DGroup_First, PPC970_Unit_FXU;
}
let Defs = [LR] in {
def MTLR : XFXForm_7_ext<31, 467, 8, (outs), (ins gprc:$rS),
"mtlr $rS", IIC_SprMTSPR>,
PPC970_DGroup_First, PPC970_Unit_FXU;
}
let Uses = [LR] in {
def MFLR : XFXForm_1_ext<31, 339, 8, (outs gprc:$rT), (ins),
"mflr $rT", IIC_SprMFSPR>,
PPC970_DGroup_First, PPC970_Unit_FXU;
}
let isCodeGenOnly = 1 in {
// Move to/from VRSAVE: despite being a SPR, the VRSAVE register is renamed
// like a GPR on the PPC970. As such, copies in and out have the same
// performance characteristics as an OR instruction.
def MTVRSAVE : XFXForm_7_ext<31, 467, 256, (outs), (ins gprc:$rS),
"mtspr 256, $rS", IIC_IntGeneral>,
PPC970_DGroup_Single, PPC970_Unit_FXU;
def MFVRSAVE : XFXForm_1_ext<31, 339, 256, (outs gprc:$rT), (ins),
"mfspr $rT, 256", IIC_IntGeneral>,
PPC970_DGroup_First, PPC970_Unit_FXU;
def MTVRSAVEv : XFXForm_7_ext<31, 467, 256,
(outs VRSAVERC:$reg), (ins gprc:$rS),
"mtspr 256, $rS", IIC_IntGeneral>,
PPC970_DGroup_Single, PPC970_Unit_FXU;
def MFVRSAVEv : XFXForm_1_ext<31, 339, 256, (outs gprc:$rT),
(ins VRSAVERC:$reg),
"mfspr $rT, 256", IIC_IntGeneral>,
PPC970_DGroup_First, PPC970_Unit_FXU;
}
// Aliases for mtvrsave/mfvrsave to mfspr/mtspr.
def : InstAlias<"mtvrsave $rS", (MTVRSAVE gprc:$rS)>;
def : InstAlias<"mfvrsave $rS", (MFVRSAVE gprc:$rS)>;
// SPILL_VRSAVE - Indicate that we're dumping the VRSAVE register,
// so we'll need to scavenge a register for it.
let mayStore = 1 in
def SPILL_VRSAVE : PPCEmitTimePseudo<(outs), (ins VRSAVERC:$vrsave, memri:$F),
"#SPILL_VRSAVE", []>;
// RESTORE_VRSAVE - Indicate that we're restoring the VRSAVE register (previously
// spilled), so we'll need to scavenge a register for it.
let mayLoad = 1 in
def RESTORE_VRSAVE : PPCEmitTimePseudo<(outs VRSAVERC:$vrsave), (ins memri:$F),
"#RESTORE_VRSAVE", []>;
let hasSideEffects = 0 in {
// mtocrf's input needs to be prepared by shifting by an amount dependent
// on the cr register selected. Thus, post-ra anti-dep breaking must not
// later change that register assignment.
let hasExtraDefRegAllocReq = 1 in {
def MTOCRF: XFXForm_5a<31, 144, (outs crbitm:$FXM), (ins gprc:$ST),
"mtocrf $FXM, $ST", IIC_BrMCRX>,
PPC970_DGroup_First, PPC970_Unit_CRU;
// Similarly to mtocrf, the mask for mtcrf must be prepared in a way that
// is dependent on the cr fields being set.
def MTCRF : XFXForm_5<31, 144, (outs), (ins i32imm:$FXM, gprc:$rS),
"mtcrf $FXM, $rS", IIC_BrMCRX>,
PPC970_MicroCode, PPC970_Unit_CRU;
} // hasExtraDefRegAllocReq = 1
// mfocrf's input needs to be prepared by shifting by an amount dependent
// on the cr register selected. Thus, post-ra anti-dep breaking must not
// later change that register assignment.
let hasExtraSrcRegAllocReq = 1 in {
def MFOCRF: XFXForm_5a<31, 19, (outs gprc:$rT), (ins crbitm:$FXM),
"mfocrf $rT, $FXM", IIC_SprMFCRF>,
PPC970_DGroup_First, PPC970_Unit_CRU;
// Similarly to mfocrf, the mask for mfcrf must be prepared in a way that
// is dependent on the cr fields being copied.
def MFCR : XFXForm_3<31, 19, (outs gprc:$rT), (ins),
"mfcr $rT", IIC_SprMFCR>,
PPC970_MicroCode, PPC970_Unit_CRU;
} // hasExtraSrcRegAllocReq = 1
def MCRXRX : X_BF3<31, 576, (outs crrc:$BF), (ins),
"mcrxrx $BF", IIC_BrMCRX>, Requires<[IsISA3_0]>;
} // hasSideEffects = 0
let Predicates = [HasFPU] in {
// Custom inserter instruction to perform FADD in round-to-zero mode.
let Uses = [RM] in {
def FADDrtz: PPCCustomInserterPseudo<(outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), "",
[(set f64:$FRT, (PPCfaddrtz f64:$FRA, f64:$FRB))]>;
}
// The above pseudo gets expanded to make use of the following instructions
// to manipulate FPSCR. Note that FPSCR is not modeled at the DAG level.
let Uses = [RM], Defs = [RM] in {
def MTFSB0 : XForm_43<63, 70, (outs), (ins u5imm:$FM),
"mtfsb0 $FM", IIC_IntMTFSB0, []>,
PPC970_DGroup_Single, PPC970_Unit_FPU;
def MTFSB1 : XForm_43<63, 38, (outs), (ins u5imm:$FM),
"mtfsb1 $FM", IIC_IntMTFSB0, []>,
PPC970_DGroup_Single, PPC970_Unit_FPU;
let isCodeGenOnly = 1 in
def MTFSFb : XFLForm<63, 711, (outs), (ins i32imm:$FM, f8rc:$rT),
"mtfsf $FM, $rT", IIC_IntMTFSB0, []>,
PPC970_DGroup_Single, PPC970_Unit_FPU;
}
let Uses = [RM] in {
def MFFS : XForm_42<63, 583, (outs f8rc:$rT), (ins),
"mffs $rT", IIC_IntMFFS,
[(set f64:$rT, (PPCmffs))]>,
PPC970_DGroup_Single, PPC970_Unit_FPU;
let Defs = [CR1] in
def MFFSo : XForm_42<63, 583, (outs f8rc:$rT), (ins),
"mffs. $rT", IIC_IntMFFS, []>, isDOT;
def MFFSCE : X_FRT5_XO2_XO3_XO10<63, 0, 1, 583, (outs f8rc:$rT), (ins),
"mffsce $rT", IIC_IntMFFS, []>,
PPC970_DGroup_Single, PPC970_Unit_FPU;
def MFFSCDRN : X_FRT5_XO2_XO3_FRB5_XO10<63, 2, 4, 583, (outs f8rc:$rT),
(ins f8rc:$FRB), "mffscdrn $rT, $FRB",
IIC_IntMFFS, []>,
PPC970_DGroup_Single, PPC970_Unit_FPU;
def MFFSCDRNI : X_FRT5_XO2_XO3_DRM3_XO10<63, 2, 5, 583, (outs f8rc:$rT),
(ins u3imm:$DRM),
"mffscdrni $rT, $DRM",
IIC_IntMFFS, []>,
PPC970_DGroup_Single, PPC970_Unit_FPU;
def MFFSCRN : X_FRT5_XO2_XO3_FRB5_XO10<63, 2, 6, 583, (outs f8rc:$rT),
(ins f8rc:$FRB), "mffscrn $rT, $FRB",
IIC_IntMFFS, []>,
PPC970_DGroup_Single, PPC970_Unit_FPU;
def MFFSCRNI : X_FRT5_XO2_XO3_RM2_X10<63, 2, 7, 583, (outs f8rc:$rT),
(ins u2imm:$RM), "mffscrni $rT, $RM",
IIC_IntMFFS, []>,
PPC970_DGroup_Single, PPC970_Unit_FPU;
def MFFSL : X_FRT5_XO2_XO3_XO10<63, 3, 0, 583, (outs f8rc:$rT), (ins),
"mffsl $rT", IIC_IntMFFS, []>,
PPC970_DGroup_Single, PPC970_Unit_FPU;
}
}
let Predicates = [IsISA3_0] in {
def MODSW : XForm_8<31, 779, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"modsw $rT, $rA, $rB", IIC_IntDivW,
[(set i32:$rT, (srem i32:$rA, i32:$rB))]>;
def MODUW : XForm_8<31, 267, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"moduw $rT, $rA, $rB", IIC_IntDivW,
[(set i32:$rT, (urem i32:$rA, i32:$rB))]>;
}
let PPC970_Unit = 1, hasSideEffects = 0 in { // FXU Operations.
// XO-Form instructions. Arithmetic instructions that can set overflow bit
let isCommutable = 1 in
defm ADD4 : XOForm_1r<31, 266, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"add", "$rT, $rA, $rB", IIC_IntSimple,
[(set i32:$rT, (add i32:$rA, i32:$rB))]>;
let isCodeGenOnly = 1 in
def ADD4TLS : XOForm_1<31, 266, 0, (outs gprc:$rT), (ins gprc:$rA, tlsreg32:$rB),
"add $rT, $rA, $rB", IIC_IntSimple,
[(set i32:$rT, (add i32:$rA, tglobaltlsaddr:$rB))]>;
let isCommutable = 1 in
defm ADDC : XOForm_1rc<31, 10, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"addc", "$rT, $rA, $rB", IIC_IntGeneral,
[(set i32:$rT, (addc i32:$rA, i32:$rB))]>,
PPC970_DGroup_Cracked;
defm DIVW : XOForm_1rcr<31, 491, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"divw", "$rT, $rA, $rB", IIC_IntDivW,
[(set i32:$rT, (sdiv i32:$rA, i32:$rB))]>;
defm DIVWU : XOForm_1rcr<31, 459, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"divwu", "$rT, $rA, $rB", IIC_IntDivW,
[(set i32:$rT, (udiv i32:$rA, i32:$rB))]>;
def DIVWE : XOForm_1<31, 427, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"divwe $rT, $rA, $rB", IIC_IntDivW,
[(set i32:$rT, (int_ppc_divwe gprc:$rA, gprc:$rB))]>,
Requires<[HasExtDiv]>;
let Defs = [CR0] in
def DIVWEo : XOForm_1<31, 427, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"divwe. $rT, $rA, $rB", IIC_IntDivW,
[]>, isDOT, PPC970_DGroup_Cracked, PPC970_DGroup_First,
Requires<[HasExtDiv]>;
def DIVWEU : XOForm_1<31, 395, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"divweu $rT, $rA, $rB", IIC_IntDivW,
[(set i32:$rT, (int_ppc_divweu gprc:$rA, gprc:$rB))]>,
Requires<[HasExtDiv]>;
let Defs = [CR0] in
def DIVWEUo : XOForm_1<31, 395, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"divweu. $rT, $rA, $rB", IIC_IntDivW,
[]>, isDOT, PPC970_DGroup_Cracked, PPC970_DGroup_First,
Requires<[HasExtDiv]>;
let isCommutable = 1 in {
defm MULHW : XOForm_1r<31, 75, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"mulhw", "$rT, $rA, $rB", IIC_IntMulHW,
[(set i32:$rT, (mulhs i32:$rA, i32:$rB))]>;
defm MULHWU : XOForm_1r<31, 11, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"mulhwu", "$rT, $rA, $rB", IIC_IntMulHWU,
[(set i32:$rT, (mulhu i32:$rA, i32:$rB))]>;
defm MULLW : XOForm_1r<31, 235, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"mullw", "$rT, $rA, $rB", IIC_IntMulHW,
[(set i32:$rT, (mul i32:$rA, i32:$rB))]>;
} // isCommutable
defm SUBF : XOForm_1r<31, 40, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"subf", "$rT, $rA, $rB", IIC_IntGeneral,
[(set i32:$rT, (sub i32:$rB, i32:$rA))]>;
defm SUBFC : XOForm_1rc<31, 8, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"subfc", "$rT, $rA, $rB", IIC_IntGeneral,
[(set i32:$rT, (subc i32:$rB, i32:$rA))]>,
PPC970_DGroup_Cracked;
defm NEG : XOForm_3r<31, 104, 0, (outs gprc:$rT), (ins gprc:$rA),
"neg", "$rT, $rA", IIC_IntSimple,
[(set i32:$rT, (ineg i32:$rA))]>;
let Uses = [CARRY] in {
let isCommutable = 1 in
defm ADDE : XOForm_1rc<31, 138, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"adde", "$rT, $rA, $rB", IIC_IntGeneral,
[(set i32:$rT, (adde i32:$rA, i32:$rB))]>;
defm ADDME : XOForm_3rc<31, 234, 0, (outs gprc:$rT), (ins gprc:$rA),
"addme", "$rT, $rA", IIC_IntGeneral,
[(set i32:$rT, (adde i32:$rA, -1))]>;
defm ADDZE : XOForm_3rc<31, 202, 0, (outs gprc:$rT), (ins gprc:$rA),
"addze", "$rT, $rA", IIC_IntGeneral,
[(set i32:$rT, (adde i32:$rA, 0))]>;
defm SUBFE : XOForm_1rc<31, 136, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
"subfe", "$rT, $rA, $rB", IIC_IntGeneral,
[(set i32:$rT, (sube i32:$rB, i32:$rA))]>;
defm SUBFME : XOForm_3rc<31, 232, 0, (outs gprc:$rT), (ins gprc:$rA),
"subfme", "$rT, $rA", IIC_IntGeneral,
[(set i32:$rT, (sube -1, i32:$rA))]>;
defm SUBFZE : XOForm_3rc<31, 200, 0, (outs gprc:$rT), (ins gprc:$rA),
"subfze", "$rT, $rA", IIC_IntGeneral,
[(set i32:$rT, (sube 0, i32:$rA))]>;
}
}
// A-Form instructions. Most of the instructions executed in the FPU are of
// this type.
//
let PPC970_Unit = 3, hasSideEffects = 0, Predicates = [HasFPU] in { // FPU Operations.
let Uses = [RM] in {
let isCommutable = 1 in {
defm FMADD : AForm_1r<63, 29,
(outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
"fmadd", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
[(set f64:$FRT, (fma f64:$FRA, f64:$FRC, f64:$FRB))]>;
defm FMADDS : AForm_1r<59, 29,
(outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRC, f4rc:$FRB),
"fmadds", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral,
[(set f32:$FRT, (fma f32:$FRA, f32:$FRC, f32:$FRB))]>;
defm FMSUB : AForm_1r<63, 28,
(outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
"fmsub", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
[(set f64:$FRT,
(fma f64:$FRA, f64:$FRC, (fneg f64:$FRB)))]>;
defm FMSUBS : AForm_1r<59, 28,
(outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRC, f4rc:$FRB),
"fmsubs", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral,
[(set f32:$FRT,
(fma f32:$FRA, f32:$FRC, (fneg f32:$FRB)))]>;
defm FNMADD : AForm_1r<63, 31,
(outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
"fnmadd", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
[(set f64:$FRT,
(fneg (fma f64:$FRA, f64:$FRC, f64:$FRB)))]>;
defm FNMADDS : AForm_1r<59, 31,
(outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRC, f4rc:$FRB),
"fnmadds", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral,
[(set f32:$FRT,
(fneg (fma f32:$FRA, f32:$FRC, f32:$FRB)))]>;
defm FNMSUB : AForm_1r<63, 30,
(outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
"fnmsub", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
[(set f64:$FRT, (fneg (fma f64:$FRA, f64:$FRC,
(fneg f64:$FRB))))]>;
defm FNMSUBS : AForm_1r<59, 30,
(outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRC, f4rc:$FRB),
"fnmsubs", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral,
[(set f32:$FRT, (fneg (fma f32:$FRA, f32:$FRC,
(fneg f32:$FRB))))]>;
} // isCommutable
}
// FSEL is artificially split into 4 and 8-byte forms for the result. To avoid
// having 4 of these, force the comparison to always be an 8-byte double (code
// should use an FMRSD if the input comparison value really wants to be a float)
// and 4/8 byte forms for the result and operand type..
let Interpretation64Bit = 1, isCodeGenOnly = 1 in
defm FSELD : AForm_1r<63, 23,
(outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
"fsel", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral,
[(set f64:$FRT, (PPCfsel f64:$FRA, f64:$FRC, f64:$FRB))]>;
defm FSELS : AForm_1r<63, 23,
(outs f4rc:$FRT), (ins f8rc:$FRA, f4rc:$FRC, f4rc:$FRB),
"fsel", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral,
[(set f32:$FRT, (PPCfsel f64:$FRA, f32:$FRC, f32:$FRB))]>;
let Uses = [RM] in {
let isCommutable = 1 in {
defm FADD : AForm_2r<63, 21,
(outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB),
"fadd", "$FRT, $FRA, $FRB", IIC_FPAddSub,
[(set f64:$FRT, (fadd f64:$FRA, f64:$FRB))]>;
defm FADDS : AForm_2r<59, 21,
(outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRB),
"fadds", "$FRT, $FRA, $FRB", IIC_FPGeneral,
[(set f32:$FRT, (fadd f32:$FRA, f32:$FRB))]>;
} // isCommutable
defm FDIV : AForm_2r<63, 18,
(outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB),
"fdiv", "$FRT, $FRA, $FRB", IIC_FPDivD,
[(set f64:$FRT, (fdiv f64:$FRA, f64:$FRB))]>;
defm FDIVS : AForm_2r<59, 18,
(outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRB),
"fdivs", "$FRT, $FRA, $FRB", IIC_FPDivS,
[(set f32:$FRT, (fdiv f32:$FRA, f32:$FRB))]>;
let isCommutable = 1 in {
defm FMUL : AForm_3r<63, 25,
(outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC),
"fmul", "$FRT, $FRA, $FRC", IIC_FPFused,
[(set f64:$FRT, (fmul f64:$FRA, f64:$FRC))]>;
defm FMULS : AForm_3r<59, 25,
(outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRC),
"fmuls", "$FRT, $FRA, $FRC", IIC_FPGeneral,
[(set f32:$FRT, (fmul f32:$FRA, f32:$FRC))]>;
} // isCommutable
defm FSUB : AForm_2r<63, 20,
(outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB),
"fsub", "$FRT, $FRA, $FRB", IIC_FPAddSub,
[(set f64:$FRT, (fsub f64:$FRA, f64:$FRB))]>;
defm FSUBS : AForm_2r<59, 20,
(outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRB),
"fsubs", "$FRT, $FRA, $FRB", IIC_FPGeneral,
[(set f32:$FRT, (fsub f32:$FRA, f32:$FRB))]>;
}
}
let hasSideEffects = 0 in {
let PPC970_Unit = 1 in { // FXU Operations.
let isSelect = 1 in
def ISEL : AForm_4<31, 15,
(outs gprc:$rT), (ins gprc_nor0:$rA, gprc:$rB, crbitrc:$cond),
"isel $rT, $rA, $rB, $cond", IIC_IntISEL,
[]>;
}
let PPC970_Unit = 1 in { // FXU Operations.
// M-Form instructions. rotate and mask instructions.
//
let isCommutable = 1 in {
// RLWIMI can be commuted if the rotate amount is zero.
defm RLWIMI : MForm_2r<20, (outs gprc:$rA),
(ins gprc:$rSi, gprc:$rS, u5imm:$SH, u5imm:$MB,
u5imm:$ME), "rlwimi", "$rA, $rS, $SH, $MB, $ME",
IIC_IntRotate, []>, PPC970_DGroup_Cracked,
RegConstraint<"$rSi = $rA">, NoEncode<"$rSi">;
}
let BaseName = "rlwinm" in {
def RLWINM : MForm_2<21,
(outs gprc:$rA), (ins gprc:$rS, u5imm:$SH, u5imm:$MB, u5imm:$ME),
"rlwinm $rA, $rS, $SH, $MB, $ME", IIC_IntGeneral,
[]>, RecFormRel;
let Defs = [CR0] in
def RLWINMo : MForm_2<21,
(outs gprc:$rA), (ins gprc:$rS, u5imm:$SH, u5imm:$MB, u5imm:$ME),
"rlwinm. $rA, $rS, $SH, $MB, $ME", IIC_IntGeneral,
[]>, isDOT, RecFormRel, PPC970_DGroup_Cracked;
}
defm RLWNM : MForm_2r<23, (outs gprc:$rA),
(ins gprc:$rS, gprc:$rB, u5imm:$MB, u5imm:$ME),
"rlwnm", "$rA, $rS, $rB, $MB, $ME", IIC_IntGeneral,
[]>;
}
} // hasSideEffects = 0
//===----------------------------------------------------------------------===//
// PowerPC Instruction Patterns
//
// Arbitrary immediate support. Implement in terms of LIS/ORI.
def : Pat<(i32 imm:$imm),
(ORI (LIS (HI16 imm:$imm)), (LO16 imm:$imm))>;
// Implement the 'not' operation with the NOR instruction.
def i32not : OutPatFrag<(ops node:$in),
(NOR $in, $in)>;
def : Pat<(not i32:$in),
(i32not $in)>;
// ADD an arbitrary immediate.
def : Pat<(add i32:$in, imm:$imm),
(ADDIS (ADDI $in, (LO16 imm:$imm)), (HA16 imm:$imm))>;
// OR an arbitrary immediate.
def : Pat<(or i32:$in, imm:$imm),
(ORIS (ORI $in, (LO16 imm:$imm)), (HI16 imm:$imm))>;
// XOR an arbitrary immediate.
def : Pat<(xor i32:$in, imm:$imm),
(XORIS (XORI $in, (LO16 imm:$imm)), (HI16 imm:$imm))>;
// SUBFIC
def : Pat<(sub imm32SExt16:$imm, i32:$in),
(SUBFIC $in, imm:$imm)>;
// SHL/SRL
def : Pat<(shl i32:$in, (i32 imm:$imm)),
(RLWINM $in, imm:$imm, 0, (SHL32 imm:$imm))>;
def : Pat<(srl i32:$in, (i32 imm:$imm)),
(RLWINM $in, (SRL32 imm:$imm), imm:$imm, 31)>;
// ROTL
def : Pat<(rotl i32:$in, i32:$sh),
(RLWNM $in, $sh, 0, 31)>;
def : Pat<(rotl i32:$in, (i32 imm:$imm)),
(RLWINM $in, imm:$imm, 0, 31)>;
// RLWNM
def : Pat<(and (rotl i32:$in, i32:$sh), maskimm32:$imm),
(RLWNM $in, $sh, (MB maskimm32:$imm), (ME maskimm32:$imm))>;
// Calls
def : Pat<(PPCcall (i32 tglobaladdr:$dst)),
(BL tglobaladdr:$dst)>;
def : Pat<(PPCcall (i32 texternalsym:$dst)),
(BL texternalsym:$dst)>;
def : Pat<(PPCtc_return (i32 tglobaladdr:$dst), imm:$imm),
(TCRETURNdi tglobaladdr:$dst, imm:$imm)>;
def : Pat<(PPCtc_return (i32 texternalsym:$dst), imm:$imm),
(TCRETURNdi texternalsym:$dst, imm:$imm)>;
def : Pat<(PPCtc_return CTRRC:$dst, imm:$imm),
(TCRETURNri CTRRC:$dst, imm:$imm)>;
// Hi and Lo for Darwin Global Addresses.
def : Pat<(PPChi tglobaladdr:$in, 0), (LIS tglobaladdr:$in)>;
def : Pat<(PPClo tglobaladdr:$in, 0), (LI tglobaladdr:$in)>;
def : Pat<(PPChi tconstpool:$in, 0), (LIS tconstpool:$in)>;
def : Pat<(PPClo tconstpool:$in, 0), (LI tconstpool:$in)>;
def : Pat<(PPChi tjumptable:$in, 0), (LIS tjumptable:$in)>;
def : Pat<(PPClo tjumptable:$in, 0), (LI tjumptable:$in)>;
def : Pat<(PPChi tblockaddress:$in, 0), (LIS tblockaddress:$in)>;
def : Pat<(PPClo tblockaddress:$in, 0), (LI tblockaddress:$in)>;
def : Pat<(PPChi tglobaltlsaddr:$g, i32:$in),
(ADDIS $in, tglobaltlsaddr:$g)>;
def : Pat<(PPClo tglobaltlsaddr:$g, i32:$in),
(ADDI $in, tglobaltlsaddr:$g)>;
def : Pat<(add i32:$in, (PPChi tglobaladdr:$g, 0)),
(ADDIS $in, tglobaladdr:$g)>;
def : Pat<(add i32:$in, (PPChi tconstpool:$g, 0)),
(ADDIS $in, tconstpool:$g)>;
def : Pat<(add i32:$in, (PPChi tjumptable:$g, 0)),
(ADDIS $in, tjumptable:$g)>;
def : Pat<(add i32:$in, (PPChi tblockaddress:$g, 0)),
(ADDIS $in, tblockaddress:$g)>;
// Support for thread-local storage.
def PPC32GOT: PPCEmitTimePseudo<(outs gprc:$rD), (ins), "#PPC32GOT",
[(set i32:$rD, (PPCppc32GOT))]>;
// Get the _GLOBAL_OFFSET_TABLE_ in PIC mode.
// This uses two output registers, the first as the real output, the second as a
// temporary register, used internally in code generation.
def PPC32PICGOT: PPCEmitTimePseudo<(outs gprc:$rD, gprc:$rT), (ins), "#PPC32PICGOT",
[]>, NoEncode<"$rT">;
def LDgotTprelL32: PPCEmitTimePseudo<(outs gprc:$rD), (ins s16imm:$disp, gprc_nor0:$reg),
"#LDgotTprelL32",
[(set i32:$rD,
(PPCldGotTprelL tglobaltlsaddr:$disp, i32:$reg))]>;
def : Pat<(PPCaddTls i32:$in, tglobaltlsaddr:$g),
(ADD4TLS $in, tglobaltlsaddr:$g)>;
def ADDItlsgdL32 : PPCEmitTimePseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, s16imm:$disp),
"#ADDItlsgdL32",
[(set i32:$rD,
(PPCaddiTlsgdL i32:$reg, tglobaltlsaddr:$disp))]>;
// LR is a true define, while the rest of the Defs are clobbers. R3 is
// explicitly defined when this op is created, so not mentioned here.
let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1,
Defs = [R0,R4,R5,R6,R7,R8,R9,R10,R11,R12,LR,CTR,CR0,CR1,CR5,CR6,CR7] in
def GETtlsADDR32 : PPCEmitTimePseudo<(outs gprc:$rD), (ins gprc:$reg, tlsgd32:$sym),
"GETtlsADDR32",
[(set i32:$rD,
(PPCgetTlsAddr i32:$reg, tglobaltlsaddr:$sym))]>;
// Combined op for ADDItlsgdL32 and GETtlsADDR32, late expanded. R3 and LR
// are true defines while the rest of the Defs are clobbers.
let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1,
Defs = [R0,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,LR,CTR,CR0,CR1,CR5,CR6,CR7] in
def ADDItlsgdLADDR32 : PPCEmitTimePseudo<(outs gprc:$rD),
(ins gprc_nor0:$reg, s16imm:$disp, tlsgd32:$sym),
"#ADDItlsgdLADDR32",
[(set i32:$rD,
(PPCaddiTlsgdLAddr i32:$reg,
tglobaltlsaddr:$disp,
tglobaltlsaddr:$sym))]>;
def ADDItlsldL32 : PPCEmitTimePseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, s16imm:$disp),
"#ADDItlsldL32",
[(set i32:$rD,
(PPCaddiTlsldL i32:$reg, tglobaltlsaddr:$disp))]>;
// LR is a true define, while the rest of the Defs are clobbers. R3 is
// explicitly defined when this op is created, so not mentioned here.
let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1,
Defs = [R0,R4,R5,R6,R7,R8,R9,R10,R11,R12,LR,CTR,CR0,CR1,CR5,CR6,CR7] in
def GETtlsldADDR32 : PPCEmitTimePseudo<(outs gprc:$rD), (ins gprc:$reg, tlsgd32:$sym),
"GETtlsldADDR32",
[(set i32:$rD,
(PPCgetTlsldAddr i32:$reg,
tglobaltlsaddr:$sym))]>;
// Combined op for ADDItlsldL32 and GETtlsADDR32, late expanded. R3 and LR
// are true defines while the rest of the Defs are clobbers.
let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1,
Defs = [R0,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,LR,CTR,CR0,CR1,CR5,CR6,CR7] in
def ADDItlsldLADDR32 : PPCEmitTimePseudo<(outs gprc:$rD),
(ins gprc_nor0:$reg, s16imm:$disp, tlsgd32:$sym),
"#ADDItlsldLADDR32",
[(set i32:$rD,
(PPCaddiTlsldLAddr i32:$reg,
tglobaltlsaddr:$disp,
tglobaltlsaddr:$sym))]>;
def ADDIdtprelL32 : PPCEmitTimePseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, s16imm:$disp),
"#ADDIdtprelL32",
[(set i32:$rD,
(PPCaddiDtprelL i32:$reg, tglobaltlsaddr:$disp))]>;
def ADDISdtprelHA32 : PPCEmitTimePseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, s16imm:$disp),
"#ADDISdtprelHA32",
[(set i32:$rD,
(PPCaddisDtprelHA i32:$reg,
tglobaltlsaddr:$disp))]>;
// Support for Position-independent code
def LWZtoc : PPCEmitTimePseudo<(outs gprc:$rD), (ins tocentry32:$disp, gprc:$reg),
"#LWZtoc",
[(set i32:$rD,
(PPCtoc_entry tglobaladdr:$disp, i32:$reg))]>;
// Get Global (GOT) Base Register offset, from the word immediately preceding
// the function label.
def UpdateGBR : PPCEmitTimePseudo<(outs gprc:$rD, gprc:$rT), (ins gprc:$rI), "#UpdateGBR", []>;
// Standard shifts. These are represented separately from the real shifts above
// so that we can distinguish between shifts that allow 5-bit and 6-bit shift
// amounts.
def : Pat<(sra i32:$rS, i32:$rB),
(SRAW $rS, $rB)>;
def : Pat<(srl i32:$rS, i32:$rB),
(SRW $rS, $rB)>;
def : Pat<(shl i32:$rS, i32:$rB),
(SLW $rS, $rB)>;
def : Pat<(zextloadi1 iaddr:$src),
(LBZ iaddr:$src)>;
def : Pat<(zextloadi1 xaddr:$src),
(LBZX xaddr:$src)>;
def : Pat<(extloadi1 iaddr:$src),
(LBZ iaddr:$src)>;
def : Pat<(extloadi1 xaddr:$src),
(LBZX xaddr:$src)>;
def : Pat<(extloadi8 iaddr:$src),
(LBZ iaddr:$src)>;
def : Pat<(extloadi8 xaddr:$src),
(LBZX xaddr:$src)>;
def : Pat<(extloadi16 iaddr:$src),
(LHZ iaddr:$src)>;
def : Pat<(extloadi16 xaddr:$src),
(LHZX xaddr:$src)>;
let Predicates = [HasFPU] in {
def : Pat<(f64 (extloadf32 iaddr:$src)),
(COPY_TO_REGCLASS (LFS iaddr:$src), F8RC)>;
def : Pat<(f64 (extloadf32 xaddr:$src)),
(COPY_TO_REGCLASS (LFSX xaddr:$src), F8RC)>;
def : Pat<(f64 (fpextend f32:$src)),
(COPY_TO_REGCLASS $src, F8RC)>;
}
// Only seq_cst fences require the heavyweight sync (SYNC 0).
// All others can use the lightweight sync (SYNC 1).
// source: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
// The rule for seq_cst is duplicated to work with both 64 bits and 32 bits
// versions of Power.
def : Pat<(atomic_fence (i64 7), (imm)), (SYNC 0)>, Requires<[HasSYNC]>;
def : Pat<(atomic_fence (i32 7), (imm)), (SYNC 0)>, Requires<[HasSYNC]>;
def : Pat<(atomic_fence (imm), (imm)), (SYNC 1)>, Requires<[HasSYNC]>;
def : Pat<(atomic_fence (imm), (imm)), (MSYNC)>, Requires<[HasOnlyMSYNC]>;
let Predicates = [HasFPU] in {
// Additional FNMSUB patterns: -a*c + b == -(a*c - b)
def : Pat<(fma (fneg f64:$A), f64:$C, f64:$B),
(FNMSUB $A, $C, $B)>;
def : Pat<(fma f64:$A, (fneg f64:$C), f64:$B),
(FNMSUB $A, $C, $B)>;
def : Pat<(fma (fneg f32:$A), f32:$C, f32:$B),
(FNMSUBS $A, $C, $B)>;
def : Pat<(fma f32:$A, (fneg f32:$C), f32:$B),
(FNMSUBS $A, $C, $B)>;
// FCOPYSIGN's operand types need not agree.
def : Pat<(fcopysign f64:$frB, f32:$frA),
(FCPSGND (COPY_TO_REGCLASS $frA, F8RC), $frB)>;
def : Pat<(fcopysign f32:$frB, f64:$frA),
(FCPSGNS (COPY_TO_REGCLASS $frA, F4RC), $frB)>;
}
include "PPCInstrAltivec.td"
include "PPCInstrSPE.td"
include "PPCInstr64Bit.td"
include "PPCInstrVSX.td"
include "PPCInstrQPX.td"
include "PPCInstrHTM.td"
def crnot : OutPatFrag<(ops node:$in),
(CRNOR $in, $in)>;
def : Pat<(not i1:$in),
(crnot $in)>;
// Patterns for arithmetic i1 operations.
def : Pat<(add i1:$a, i1:$b),
(CRXOR $a, $b)>;
def : Pat<(sub i1:$a, i1:$b),
(CRXOR $a, $b)>;
def : Pat<(mul i1:$a, i1:$b),
(CRAND $a, $b)>;
// We're sometimes asked to materialize i1 -1, which is just 1 in this case
// (-1 is used to mean all bits set).
def : Pat<(i1 -1), (CRSET)>;
// i1 extensions, implemented in terms of isel.
def : Pat<(i32 (zext i1:$in)),
(SELECT_I4 $in, (LI 1), (LI 0))>;
def : Pat<(i32 (sext i1:$in)),
(SELECT_I4 $in, (LI -1), (LI 0))>;
def : Pat<(i64 (zext i1:$in)),
(SELECT_I8 $in, (LI8 1), (LI8 0))>;
def : Pat<(i64 (sext i1:$in)),
(SELECT_I8 $in, (LI8 -1), (LI8 0))>;
// FIXME: We should choose either a zext or a sext based on other constants
// already around.
def : Pat<(i32 (anyext i1:$in)),
(SELECT_I4 $in, (LI 1), (LI 0))>;
def : Pat<(i64 (anyext i1:$in)),
(SELECT_I8 $in, (LI8 1), (LI8 0))>;
// match setcc on i1 variables.
// CRANDC is:
// 1 1 : F
// 1 0 : T
// 0 1 : F
// 0 0 : F
//
// LT is:
// -1 -1 : F
// -1 0 : T
// 0 -1 : F
// 0 0 : F
//
// ULT is:
// 1 1 : F
// 1 0 : F
// 0 1 : T
// 0 0 : F
def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETLT)),
(CRANDC $s1, $s2)>;
def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETULT)),
(CRANDC $s2, $s1)>;
// CRORC is:
// 1 1 : T
// 1 0 : T
// 0 1 : F
// 0 0 : T
//
// LE is:
// -1 -1 : T
// -1 0 : T
// 0 -1 : F
// 0 0 : T
//
// ULE is:
// 1 1 : T
// 1 0 : F
// 0 1 : T
// 0 0 : T
def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETLE)),
(CRORC $s1, $s2)>;
def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETULE)),
(CRORC $s2, $s1)>;
def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETEQ)),
(CREQV $s1, $s2)>;
// GE is:
// -1 -1 : T
// -1 0 : F
// 0 -1 : T
// 0 0 : T
//
// UGE is:
// 1 1 : T
// 1 0 : T
// 0 1 : F
// 0 0 : T
def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETGE)),
(CRORC $s2, $s1)>;
def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETUGE)),
(CRORC $s1, $s2)>;
// GT is:
// -1 -1 : F
// -1 0 : F
// 0 -1 : T
// 0 0 : F
//
// UGT is:
// 1 1 : F
// 1 0 : T
// 0 1 : F
// 0 0 : F
def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETGT)),
(CRANDC $s2, $s1)>;
def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETUGT)),
(CRANDC $s1, $s2)>;
def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETNE)),
(CRXOR $s1, $s2)>;
// match setcc on non-i1 (non-vector) variables. Note that SETUEQ, SETOGE,
// SETOLE, SETONE, SETULT and SETUGT should be expanded by legalize for
// floating-point types.
multiclass CRNotPat<dag pattern, dag result> {
def : Pat<pattern, (crnot result)>;
def : Pat<(not pattern), result>;
// We can also fold the crnot into an extension:
def : Pat<(i32 (zext pattern)),
(SELECT_I4 result, (LI 0), (LI 1))>;
def : Pat<(i32 (sext pattern)),
(SELECT_I4 result, (LI 0), (LI -1))>;
// We can also fold the crnot into an extension:
def : Pat<(i64 (zext pattern)),
(SELECT_I8 result, (LI8 0), (LI8 1))>;
def : Pat<(i64 (sext pattern)),
(SELECT_I8 result, (LI8 0), (LI8 -1))>;
// FIXME: We should choose either a zext or a sext based on other constants
// already around.
def : Pat<(i32 (anyext pattern)),
(SELECT_I4 result, (LI 0), (LI 1))>;
def : Pat<(i64 (anyext pattern)),
(SELECT_I8 result, (LI8 0), (LI8 1))>;
}
// FIXME: Because of what seems like a bug in TableGen's type-inference code,
// we need to write imm:$imm in the output patterns below, not just $imm, or
// else the resulting matcher will not correctly add the immediate operand
// (making it a register operand instead).
// extended SETCC.
multiclass ExtSetCCPat<CondCode cc, PatFrag pfrag,
OutPatFrag rfrag, OutPatFrag rfrag8> {
def : Pat<(i32 (zext (i1 (pfrag i32:$s1, cc)))),
(rfrag $s1)>;
def : Pat<(i64 (zext (i1 (pfrag i64:$s1, cc)))),
(rfrag8 $s1)>;
def : Pat<(i64 (zext (i1 (pfrag i32:$s1, cc)))),
(INSERT_SUBREG (i64 (IMPLICIT_DEF)), (rfrag $s1), sub_32)>;
def : Pat<(i32 (zext (i1 (pfrag i64:$s1, cc)))),
(EXTRACT_SUBREG (rfrag8 $s1), sub_32)>;
def : Pat<(i32 (anyext (i1 (pfrag i32:$s1, cc)))),
(rfrag $s1)>;
def : Pat<(i64 (anyext (i1 (pfrag i64:$s1, cc)))),
(rfrag8 $s1)>;
def : Pat<(i64 (anyext (i1 (pfrag i32:$s1, cc)))),
(INSERT_SUBREG (i64 (IMPLICIT_DEF)), (rfrag $s1), sub_32)>;
def : Pat<(i32 (anyext (i1 (pfrag i64:$s1, cc)))),
(EXTRACT_SUBREG (rfrag8 $s1), sub_32)>;
}
// Note that we do all inversions below with i(32|64)not, instead of using
// (xori x, 1) because on the A2 nor has single-cycle latency while xori
// has 2-cycle latency.
defm : ExtSetCCPat<SETEQ,
PatFrag<(ops node:$in, node:$cc),
(setcc $in, 0, $cc)>,
OutPatFrag<(ops node:$in),
(RLWINM (CNTLZW $in), 27, 31, 31)>,
OutPatFrag<(ops node:$in),
(RLDICL (CNTLZD $in), 58, 63)> >;
defm : ExtSetCCPat<SETNE,
PatFrag<(ops node:$in, node:$cc),
(setcc $in, 0, $cc)>,
OutPatFrag<(ops node:$in),
(RLWINM (i32not (CNTLZW $in)), 27, 31, 31)>,
OutPatFrag<(ops node:$in),
(RLDICL (i64not (CNTLZD $in)), 58, 63)> >;
defm : ExtSetCCPat<SETLT,
PatFrag<(ops node:$in, node:$cc),
(setcc $in, 0, $cc)>,
OutPatFrag<(ops node:$in),
(RLWINM $in, 1, 31, 31)>,
OutPatFrag<(ops node:$in),
(RLDICL $in, 1, 63)> >;
defm : ExtSetCCPat<SETGE,
PatFrag<(ops node:$in, node:$cc),
(setcc $in, 0, $cc)>,
OutPatFrag<(ops node:$in),
(RLWINM (i32not $in), 1, 31, 31)>,
OutPatFrag<(ops node:$in),
(RLDICL (i64not $in), 1, 63)> >;
defm : ExtSetCCPat<SETGT,
PatFrag<(ops node:$in, node:$cc),
(setcc $in, 0, $cc)>,
OutPatFrag<(ops node:$in),
(RLWINM (ANDC (NEG $in), $in), 1, 31, 31)>,
OutPatFrag<(ops node:$in),
(RLDICL (ANDC8 (NEG8 $in), $in), 1, 63)> >;
defm : ExtSetCCPat<SETLE,
PatFrag<(ops node:$in, node:$cc),
(setcc $in, 0, $cc)>,
OutPatFrag<(ops node:$in),
(RLWINM (ORC $in, (NEG $in)), 1, 31, 31)>,
OutPatFrag<(ops node:$in),
(RLDICL (ORC8 $in, (NEG8 $in)), 1, 63)> >;
defm : ExtSetCCPat<SETLT,
PatFrag<(ops node:$in, node:$cc),
(setcc $in, -1, $cc)>,
OutPatFrag<(ops node:$in),
(RLWINM (AND $in, (ADDI $in, 1)), 1, 31, 31)>,
OutPatFrag<(ops node:$in),
(RLDICL (AND8 $in, (ADDI8 $in, 1)), 1, 63)> >;
defm : ExtSetCCPat<SETGE,
PatFrag<(ops node:$in, node:$cc),
(setcc $in, -1, $cc)>,
OutPatFrag<(ops node:$in),
(RLWINM (NAND $in, (ADDI $in, 1)), 1, 31, 31)>,
OutPatFrag<(ops node:$in),
(RLDICL (NAND8 $in, (ADDI8 $in, 1)), 1, 63)> >;
defm : ExtSetCCPat<SETGT,
PatFrag<(ops node:$in, node:$cc),
(setcc $in, -1, $cc)>,
OutPatFrag<(ops node:$in),
(RLWINM (i32not $in), 1, 31, 31)>,
OutPatFrag<(ops node:$in),
(RLDICL (i64not $in), 1, 63)> >;
defm : ExtSetCCPat<SETLE,
PatFrag<(ops node:$in, node:$cc),
(setcc $in, -1, $cc)>,
OutPatFrag<(ops node:$in),
(RLWINM $in, 1, 31, 31)>,
OutPatFrag<(ops node:$in),
(RLDICL $in, 1, 63)> >;
// An extended SETCC with shift amount.
multiclass ExtSetCCShiftPat<CondCode cc, PatFrag pfrag,
OutPatFrag rfrag, OutPatFrag rfrag8> {
def : Pat<(i32 (zext (i1 (pfrag i32:$s1, i32:$sa, cc)))),
(rfrag $s1, $sa)>;
def : Pat<(i64 (zext (i1 (pfrag i64:$s1, i32:$sa, cc)))),
(rfrag8 $s1, $sa)>;
def : Pat<(i64 (zext (i1 (pfrag i32:$s1, i32:$sa, cc)))),
(INSERT_SUBREG (i64 (IMPLICIT_DEF)), (rfrag $s1, $sa), sub_32)>;
def : Pat<(i32 (zext (i1 (pfrag i64:$s1, i32:$sa, cc)))),
(EXTRACT_SUBREG (rfrag8 $s1, $sa), sub_32)>;
def : Pat<(i32 (anyext (i1 (pfrag i32:$s1, i32:$sa, cc)))),
(rfrag $s1, $sa)>;
def : Pat<(i64 (anyext (i1 (pfrag i64:$s1, i32:$sa, cc)))),
(rfrag8 $s1, $sa)>;
def : Pat<(i64 (anyext (i1 (pfrag i32:$s1, i32:$sa, cc)))),
(INSERT_SUBREG (i64 (IMPLICIT_DEF)), (rfrag $s1, $sa), sub_32)>;
def : Pat<(i32 (anyext (i1 (pfrag i64:$s1, i32:$sa, cc)))),
(EXTRACT_SUBREG (rfrag8 $s1, $sa), sub_32)>;
}
defm : ExtSetCCShiftPat<SETNE,
PatFrag<(ops node:$in, node:$sa, node:$cc),
(setcc (and $in, (shl 1, $sa)), 0, $cc)>,
OutPatFrag<(ops node:$in, node:$sa),
(RLWNM $in, (SUBFIC $sa, 32), 31, 31)>,
OutPatFrag<(ops node:$in, node:$sa),
(RLDCL $in, (SUBFIC $sa, 64), 63)> >;
defm : ExtSetCCShiftPat<SETEQ,
PatFrag<(ops node:$in, node:$sa, node:$cc),
(setcc (and $in, (shl 1, $sa)), 0, $cc)>,
OutPatFrag<(ops node:$in, node:$sa),
(RLWNM (i32not $in),
(SUBFIC $sa, 32), 31, 31)>,
OutPatFrag<(ops node:$in, node:$sa),
(RLDCL (i64not $in),
(SUBFIC $sa, 64), 63)> >;
// SETCC for i32.
def : Pat<(i1 (setcc i32:$s1, immZExt16:$imm, SETULT)),
(EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_lt)>;
def : Pat<(i1 (setcc i32:$s1, imm32SExt16:$imm, SETLT)),
(EXTRACT_SUBREG (CMPWI $s1, imm:$imm), sub_lt)>;
def : Pat<(i1 (setcc i32:$s1, immZExt16:$imm, SETUGT)),
(EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_gt)>;
def : Pat<(i1 (setcc i32:$s1, imm32SExt16:$imm, SETGT)),
(EXTRACT_SUBREG (CMPWI $s1, imm:$imm), sub_gt)>;
def : Pat<(i1 (setcc i32:$s1, imm32SExt16:$imm, SETEQ)),
(EXTRACT_SUBREG (CMPWI $s1, imm:$imm), sub_eq)>;
def : Pat<(i1 (setcc i32:$s1, immZExt16:$imm, SETEQ)),
(EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_eq)>;
// For non-equality comparisons, the default code would materialize the
// constant, then compare against it, like this:
// lis r2, 4660
// ori r2, r2, 22136
// cmpw cr0, r3, r2
// beq cr0,L6
// Since we are just comparing for equality, we can emit this instead:
// xoris r0,r3,0x1234
// cmplwi cr0,r0,0x5678
// beq cr0,L6
def : Pat<(i1 (setcc i32:$s1, imm:$imm, SETEQ)),
(EXTRACT_SUBREG (CMPLWI (XORIS $s1, (HI16 imm:$imm)),
(LO16 imm:$imm)), sub_eq)>;
defm : CRNotPat<(i1 (setcc i32:$s1, immZExt16:$imm, SETUGE)),
(EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_lt)>;
defm : CRNotPat<(i1 (setcc i32:$s1, imm32SExt16:$imm, SETGE)),
(EXTRACT_SUBREG (CMPWI $s1, imm:$imm), sub_lt)>;
defm : CRNotPat<(i1 (setcc i32:$s1, immZExt16:$imm, SETULE)),
(EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_gt)>;
defm : CRNotPat<(i1 (setcc i32:$s1, imm32SExt16:$imm, SETLE)),
(EXTRACT_SUBREG (CMPWI $s1, imm:$imm), sub_gt)>;
defm : CRNotPat<(i1 (setcc i32:$s1, imm32SExt16:$imm, SETNE)),
(EXTRACT_SUBREG (CMPWI $s1, imm:$imm), sub_eq)>;
defm : CRNotPat<(i1 (setcc i32:$s1, immZExt16:$imm, SETNE)),
(EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_eq)>;
defm : CRNotPat<(i1 (setcc i32:$s1, imm:$imm, SETNE)),
(EXTRACT_SUBREG (CMPLWI (XORIS $s1, (HI16 imm:$imm)),
(LO16 imm:$imm)), sub_eq)>;
def : Pat<(i1 (setcc i32:$s1, i32:$s2, SETULT)),
(EXTRACT_SUBREG (CMPLW $s1, $s2), sub_lt)>;
def : Pat<(i1 (setcc i32:$s1, i32:$s2, SETLT)),
(EXTRACT_SUBREG (CMPW $s1, $s2), sub_lt)>;
def : Pat<(i1 (setcc i32:$s1, i32:$s2, SETUGT)),
(EXTRACT_SUBREG (CMPLW $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc i32:$s1, i32:$s2, SETGT)),
(EXTRACT_SUBREG (CMPW $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc i32:$s1, i32:$s2, SETEQ)),
(EXTRACT_SUBREG (CMPW $s1, $s2), sub_eq)>;
defm : CRNotPat<(i1 (setcc i32:$s1, i32:$s2, SETUGE)),
(EXTRACT_SUBREG (CMPLW $s1, $s2), sub_lt)>;
defm : CRNotPat<(i1 (setcc i32:$s1, i32:$s2, SETGE)),
(EXTRACT_SUBREG (CMPW $s1, $s2), sub_lt)>;
defm : CRNotPat<(i1 (setcc i32:$s1, i32:$s2, SETULE)),
(EXTRACT_SUBREG (CMPLW $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc i32:$s1, i32:$s2, SETLE)),
(EXTRACT_SUBREG (CMPW $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc i32:$s1, i32:$s2, SETNE)),
(EXTRACT_SUBREG (CMPW $s1, $s2), sub_eq)>;
// SETCC for i64.
def : Pat<(i1 (setcc i64:$s1, immZExt16:$imm, SETULT)),
(EXTRACT_SUBREG (CMPLDI $s1, imm:$imm), sub_lt)>;
def : Pat<(i1 (setcc i64:$s1, imm64SExt16:$imm, SETLT)),
(EXTRACT_SUBREG (CMPDI $s1, imm:$imm), sub_lt)>;
def : Pat<(i1 (setcc i64:$s1, immZExt16:$imm, SETUGT)),
(EXTRACT_SUBREG (CMPLDI $s1, imm:$imm), sub_gt)>;
def : Pat<(i1 (setcc i64:$s1, imm64SExt16:$imm, SETGT)),
(EXTRACT_SUBREG (CMPDI $s1, imm:$imm), sub_gt)>;
def : Pat<(i1 (setcc i64:$s1, imm64SExt16:$imm, SETEQ)),
(EXTRACT_SUBREG (CMPDI $s1, imm:$imm), sub_eq)>;
def : Pat<(i1 (setcc i64:$s1, immZExt16:$imm, SETEQ)),
(EXTRACT_SUBREG (CMPLDI $s1, imm:$imm), sub_eq)>;
// For non-equality comparisons, the default code would materialize the
// constant, then compare against it, like this:
// lis r2, 4660
// ori r2, r2, 22136
// cmpd cr0, r3, r2
// beq cr0,L6
// Since we are just comparing for equality, we can emit this instead:
// xoris r0,r3,0x1234
// cmpldi cr0,r0,0x5678
// beq cr0,L6
def : Pat<(i1 (setcc i64:$s1, imm64ZExt32:$imm, SETEQ)),
(EXTRACT_SUBREG (CMPLDI (XORIS8 $s1, (HI16 imm:$imm)),
(LO16 imm:$imm)), sub_eq)>;
defm : CRNotPat<(i1 (setcc i64:$s1, immZExt16:$imm, SETUGE)),
(EXTRACT_SUBREG (CMPLDI $s1, imm:$imm), sub_lt)>;
defm : CRNotPat<(i1 (setcc i64:$s1, imm64SExt16:$imm, SETGE)),
(EXTRACT_SUBREG (CMPDI $s1, imm:$imm), sub_lt)>;
defm : CRNotPat<(i1 (setcc i64:$s1, immZExt16:$imm, SETULE)),
(EXTRACT_SUBREG (CMPLDI $s1, imm:$imm), sub_gt)>;
defm : CRNotPat<(i1 (setcc i64:$s1, imm64SExt16:$imm, SETLE)),
(EXTRACT_SUBREG (CMPDI $s1, imm:$imm), sub_gt)>;
defm : CRNotPat<(i1 (setcc i64:$s1, imm64SExt16:$imm, SETNE)),
(EXTRACT_SUBREG (CMPDI $s1, imm:$imm), sub_eq)>;
defm : CRNotPat<(i1 (setcc i64:$s1, immZExt16:$imm, SETNE)),
(EXTRACT_SUBREG (CMPLDI $s1, imm:$imm), sub_eq)>;
defm : CRNotPat<(i1 (setcc i64:$s1, imm64ZExt32:$imm, SETNE)),
(EXTRACT_SUBREG (CMPLDI (XORIS8 $s1, (HI16 imm:$imm)),
(LO16 imm:$imm)), sub_eq)>;
def : Pat<(i1 (setcc i64:$s1, i64:$s2, SETULT)),
(EXTRACT_SUBREG (CMPLD $s1, $s2), sub_lt)>;
def : Pat<(i1 (setcc i64:$s1, i64:$s2, SETLT)),
(EXTRACT_SUBREG (CMPD $s1, $s2), sub_lt)>;
def : Pat<(i1 (setcc i64:$s1, i64:$s2, SETUGT)),
(EXTRACT_SUBREG (CMPLD $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc i64:$s1, i64:$s2, SETGT)),
(EXTRACT_SUBREG (CMPD $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc i64:$s1, i64:$s2, SETEQ)),
(EXTRACT_SUBREG (CMPD $s1, $s2), sub_eq)>;
defm : CRNotPat<(i1 (setcc i64:$s1, i64:$s2, SETUGE)),
(EXTRACT_SUBREG (CMPLD $s1, $s2), sub_lt)>;
defm : CRNotPat<(i1 (setcc i64:$s1, i64:$s2, SETGE)),
(EXTRACT_SUBREG (CMPD $s1, $s2), sub_lt)>;
defm : CRNotPat<(i1 (setcc i64:$s1, i64:$s2, SETULE)),
(EXTRACT_SUBREG (CMPLD $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc i64:$s1, i64:$s2, SETLE)),
(EXTRACT_SUBREG (CMPD $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc i64:$s1, i64:$s2, SETNE)),
(EXTRACT_SUBREG (CMPD $s1, $s2), sub_eq)>;
// SETCC for f32.
let Predicates = [HasFPU] in {
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOLT)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_lt)>;
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETLT)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_lt)>;
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOGT)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETGT)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOEQ)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_eq)>;
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETEQ)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_eq)>;
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETUO)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_un)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETUGE)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_lt)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETGE)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_lt)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETULE)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETLE)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETUNE)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_eq)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETNE)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_eq)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETO)),
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_un)>;
// SETCC for f64.
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETOLT)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_lt)>;
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETLT)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_lt)>;
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETOGT)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETGT)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETOEQ)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_eq)>;
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETEQ)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_eq)>;
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETUO)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_un)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETUGE)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_lt)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETGE)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_lt)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETULE)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETLE)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETUNE)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_eq)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETNE)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_eq)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETO)),
(EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_un)>;
// SETCC for f128.
def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETOLT)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_lt)>;
def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETLT)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_lt)>;
def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETOGT)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETGT)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETOEQ)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_eq)>;
def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETEQ)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_eq)>;
def : Pat<(i1 (setcc f128:$s1, f128:$s2, SETUO)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_un)>;
defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETUGE)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_lt)>;
defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETGE)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_lt)>;
defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETULE)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETLE)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETUNE)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_eq)>;
defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETNE)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_eq)>;
defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETO)),
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_un)>;
}
// This must be in this file because it relies on patterns defined in this file
// after the inclusion of the instruction sets.
let Predicates = [HasSPE] in {
// SETCC for f32.
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOLT)),
(EXTRACT_SUBREG (EFSCMPLT $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETLT)),
(EXTRACT_SUBREG (EFSCMPLT $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOGT)),
(EXTRACT_SUBREG (EFSCMPGT $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETGT)),
(EXTRACT_SUBREG (EFSCMPGT $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOEQ)),
(EXTRACT_SUBREG (EFSCMPEQ $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETEQ)),
(EXTRACT_SUBREG (EFSCMPEQ $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETUGE)),
(EXTRACT_SUBREG (EFSCMPLT $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETGE)),
(EXTRACT_SUBREG (EFSCMPLT $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETULE)),
(EXTRACT_SUBREG (EFSCMPGT $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETLE)),
(EXTRACT_SUBREG (EFSCMPGT $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETUNE)),
(EXTRACT_SUBREG (EFSCMPEQ $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETNE)),
(EXTRACT_SUBREG (EFSCMPEQ $s1, $s2), sub_gt)>;
// SETCC for f64.
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETOLT)),
(EXTRACT_SUBREG (EFDCMPLT $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETLT)),
(EXTRACT_SUBREG (EFDCMPLT $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETOGT)),
(EXTRACT_SUBREG (EFDCMPGT $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETGT)),
(EXTRACT_SUBREG (EFDCMPGT $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETOEQ)),
(EXTRACT_SUBREG (EFDCMPEQ $s1, $s2), sub_gt)>;
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETEQ)),
(EXTRACT_SUBREG (EFDCMPEQ $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETUGE)),
(EXTRACT_SUBREG (EFDCMPLT $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETGE)),
(EXTRACT_SUBREG (EFDCMPLT $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETULE)),
(EXTRACT_SUBREG (EFDCMPGT $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETLE)),
(EXTRACT_SUBREG (EFDCMPGT $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETUNE)),
(EXTRACT_SUBREG (EFDCMPEQ $s1, $s2), sub_gt)>;
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETNE)),
(EXTRACT_SUBREG (EFDCMPEQ $s1, $s2), sub_gt)>;
}
// match select on i1 variables:
def : Pat<(i1 (select i1:$cond, i1:$tval, i1:$fval)),
(CROR (CRAND $cond , $tval),
(CRAND (crnot $cond), $fval))>;
// match selectcc on i1 variables:
// select (lhs == rhs), tval, fval is:
// ((lhs == rhs) & tval) | (!(lhs == rhs) & fval)
def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETLT)),
(CROR (CRAND (CRANDC $lhs, $rhs), $tval),
(CRAND (CRORC $rhs, $lhs), $fval))>;
def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETULT)),
(CROR (CRAND (CRANDC $rhs, $lhs), $tval),
(CRAND (CRORC $lhs, $rhs), $fval))>;
def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETLE)),
(CROR (CRAND (CRORC $lhs, $rhs), $tval),
(CRAND (CRANDC $rhs, $lhs), $fval))>;
def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETULE)),
(CROR (CRAND (CRORC $rhs, $lhs), $tval),
(CRAND (CRANDC $lhs, $rhs), $fval))>;
def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETEQ)),
(CROR (CRAND (CREQV $lhs, $rhs), $tval),
(CRAND (CRXOR $lhs, $rhs), $fval))>;
def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETGE)),
(CROR (CRAND (CRORC $rhs, $lhs), $tval),
(CRAND (CRANDC $lhs, $rhs), $fval))>;
def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETUGE)),
(CROR (CRAND (CRORC $lhs, $rhs), $tval),
(CRAND (CRANDC $rhs, $lhs), $fval))>;
def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETGT)),
(CROR (CRAND (CRANDC $rhs, $lhs), $tval),
(CRAND (CRORC $lhs, $rhs), $fval))>;
def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETUGT)),
(CROR (CRAND (CRANDC $lhs, $rhs), $tval),
(CRAND (CRORC $rhs, $lhs), $fval))>;
def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETNE)),
(CROR (CRAND (CREQV $lhs, $rhs), $fval),
(CRAND (CRXOR $lhs, $rhs), $tval))>;
// match selectcc on i1 variables with non-i1 output.
def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETLT)),
(SELECT_I4 (CRANDC $lhs, $rhs), $tval, $fval)>;
def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETULT)),
(SELECT_I4 (CRANDC $rhs, $lhs), $tval, $fval)>;
def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETLE)),
(SELECT_I4 (CRORC $lhs, $rhs), $tval, $fval)>;
def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETULE)),
(SELECT_I4 (CRORC $rhs, $lhs), $tval, $fval)>;
def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETEQ)),
(SELECT_I4 (CREQV $lhs, $rhs), $tval, $fval)>;
def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETGE)),
(SELECT_I4 (CRORC $rhs, $lhs), $tval, $fval)>;
def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETUGE)),
(SELECT_I4 (CRORC $lhs, $rhs), $tval, $fval)>;
def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETGT)),
(SELECT_I4 (CRANDC $rhs, $lhs), $tval, $fval)>;
def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETUGT)),
(SELECT_I4 (CRANDC $lhs, $rhs), $tval, $fval)>;
def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETNE)),
(SELECT_I4 (CRXOR $lhs, $rhs), $tval, $fval)>;
def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETLT)),
(SELECT_I8 (CRANDC $lhs, $rhs), $tval, $fval)>;
def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETULT)),
(SELECT_I8 (CRANDC $rhs, $lhs), $tval, $fval)>;
def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETLE)),
(SELECT_I8 (CRORC $lhs, $rhs), $tval, $fval)>;
def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETULE)),
(SELECT_I8 (CRORC $rhs, $lhs), $tval, $fval)>;
def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETEQ)),
(SELECT_I8 (CREQV $lhs, $rhs), $tval, $fval)>;
def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETGE)),
(SELECT_I8 (CRORC $rhs, $lhs), $tval, $fval)>;
def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETUGE)),
(SELECT_I8 (CRORC $lhs, $rhs), $tval, $fval)>;
def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETGT)),
(SELECT_I8 (CRANDC $rhs, $lhs), $tval, $fval)>;
def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETUGT)),
(SELECT_I8 (CRANDC $lhs, $rhs), $tval, $fval)>;
def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETNE)),
(SELECT_I8 (CRXOR $lhs, $rhs), $tval, $fval)>;
let Predicates = [HasFPU] in {
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETLT)),
(SELECT_F4 (CRANDC $lhs, $rhs), $tval, $fval)>;
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETULT)),
(SELECT_F4 (CRANDC $rhs, $lhs), $tval, $fval)>;
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETLE)),
(SELECT_F4 (CRORC $lhs, $rhs), $tval, $fval)>;
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETULE)),
(SELECT_F4 (CRORC $rhs, $lhs), $tval, $fval)>;
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETEQ)),
(SELECT_F4 (CREQV $lhs, $rhs), $tval, $fval)>;
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETGE)),
(SELECT_F4 (CRORC $rhs, $lhs), $tval, $fval)>;
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETUGE)),
(SELECT_F4 (CRORC $lhs, $rhs), $tval, $fval)>;
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETGT)),
(SELECT_F4 (CRANDC $rhs, $lhs), $tval, $fval)>;
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETUGT)),
(SELECT_F4 (CRANDC $lhs, $rhs), $tval, $fval)>;
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETNE)),
(SELECT_F4 (CRXOR $lhs, $rhs), $tval, $fval)>;
def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETLT)),
(SELECT_F8 (CRANDC $lhs, $rhs), $tval, $fval)>;
def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETULT)),
(SELECT_F8 (CRANDC $rhs, $lhs), $tval, $fval)>;
def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETLE)),
(SELECT_F8 (CRORC $lhs, $rhs), $tval, $fval)>;
def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETULE)),
(SELECT_F8 (CRORC $rhs, $lhs), $tval, $fval)>;
def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETEQ)),
(SELECT_F8 (CREQV $lhs, $rhs), $tval, $fval)>;
def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETGE)),
(SELECT_F8 (CRORC $rhs, $lhs), $tval, $fval)>;
def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETUGE)),
(SELECT_F8 (CRORC $lhs, $rhs), $tval, $fval)>;
def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETGT)),
(SELECT_F8 (CRANDC $rhs, $lhs), $tval, $fval)>;
def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETUGT)),
(SELECT_F8 (CRANDC $lhs, $rhs), $tval, $fval)>;
def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETNE)),
(SELECT_F8 (CRXOR $lhs, $rhs), $tval, $fval)>;
}
def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETLT)),
(SELECT_F16 (CRANDC $lhs, $rhs), $tval, $fval)>;
def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETULT)),
(SELECT_F16 (CRANDC $rhs, $lhs), $tval, $fval)>;
def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETLE)),
(SELECT_F16 (CRORC $lhs, $rhs), $tval, $fval)>;
def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETULE)),
(SELECT_F16 (CRORC $rhs, $lhs), $tval, $fval)>;
def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETEQ)),
(SELECT_F16 (CREQV $lhs, $rhs), $tval, $fval)>;
def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETGE)),
(SELECT_F16 (CRORC $rhs, $lhs), $tval, $fval)>;
def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETUGE)),
(SELECT_F16 (CRORC $lhs, $rhs), $tval, $fval)>;
def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETGT)),
(SELECT_F16 (CRANDC $rhs, $lhs), $tval, $fval)>;
def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETUGT)),
(SELECT_F16 (CRANDC $lhs, $rhs), $tval, $fval)>;
def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETNE)),
(SELECT_F16 (CRXOR $lhs, $rhs), $tval, $fval)>;
def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETLT)),
(SELECT_VRRC (CRANDC $lhs, $rhs), $tval, $fval)>;
def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETULT)),
(SELECT_VRRC (CRANDC $rhs, $lhs), $tval, $fval)>;
def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETLE)),
(SELECT_VRRC (CRORC $lhs, $rhs), $tval, $fval)>;
def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETULE)),
(SELECT_VRRC (CRORC $rhs, $lhs), $tval, $fval)>;
def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETEQ)),
(SELECT_VRRC (CREQV $lhs, $rhs), $tval, $fval)>;
def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETGE)),
(SELECT_VRRC (CRORC $rhs, $lhs), $tval, $fval)>;
def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETUGE)),
(SELECT_VRRC (CRORC $lhs, $rhs), $tval, $fval)>;
def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETGT)),
(SELECT_VRRC (CRANDC $rhs, $lhs), $tval, $fval)>;
def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETUGT)),
(SELECT_VRRC (CRANDC $lhs, $rhs), $tval, $fval)>;
def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETNE)),
(SELECT_VRRC (CRXOR $lhs, $rhs), $tval, $fval)>;
def ANDIo_1_EQ_BIT : PPCCustomInserterPseudo<(outs crbitrc:$dst), (ins gprc:$in),
"#ANDIo_1_EQ_BIT",
[(set i1:$dst, (trunc (not i32:$in)))]>;
def ANDIo_1_GT_BIT : PPCCustomInserterPseudo<(outs crbitrc:$dst), (ins gprc:$in),
"#ANDIo_1_GT_BIT",
[(set i1:$dst, (trunc i32:$in))]>;
def ANDIo_1_EQ_BIT8 : PPCCustomInserterPseudo<(outs crbitrc:$dst), (ins g8rc:$in),
"#ANDIo_1_EQ_BIT8",
[(set i1:$dst, (trunc (not i64:$in)))]>;
def ANDIo_1_GT_BIT8 : PPCCustomInserterPseudo<(outs crbitrc:$dst), (ins g8rc:$in),
"#ANDIo_1_GT_BIT8",
[(set i1:$dst, (trunc i64:$in))]>;
def : Pat<(i1 (not (trunc i32:$in))),
(ANDIo_1_EQ_BIT $in)>;
def : Pat<(i1 (not (trunc i64:$in))),
(ANDIo_1_EQ_BIT8 $in)>;
//===----------------------------------------------------------------------===//
// PowerPC Instructions used for assembler/disassembler only
//
// FIXME: For B=0 or B > 8, the registers following RT are used.
// WARNING: Do not add patterns for this instruction without fixing this.
def LSWI : XForm_base_r3xo_memOp<31, 597, (outs gprc:$RT),
(ins gprc:$A, u5imm:$B),
"lswi $RT, $A, $B", IIC_LdStLoad, []>;
// FIXME: For B=0 or B > 8, the registers following RT are used.
// WARNING: Do not add patterns for this instruction without fixing this.
def STSWI : XForm_base_r3xo_memOp<31, 725, (outs),
(ins gprc:$RT, gprc:$A, u5imm:$B),
"stswi $RT, $A, $B", IIC_LdStLoad, []>;
def ISYNC : XLForm_2_ext<19, 150, 0, 0, 0, (outs), (ins),
"isync", IIC_SprISYNC, []>;
def ICBI : XForm_1a<31, 982, (outs), (ins memrr:$src),
"icbi $src", IIC_LdStICBI, []>;
// We used to have EIEIO as value but E[0-9A-Z] is a reserved name
def EnforceIEIO : XForm_24_eieio<31, 854, (outs), (ins),
"eieio", IIC_LdStLoad, []>;
def WAIT : XForm_24_sync<31, 30, (outs), (ins i32imm:$L),
"wait $L", IIC_LdStLoad, []>;
def MBAR : XForm_mbar<31, 854, (outs), (ins u5imm:$MO),
"mbar $MO", IIC_LdStLoad>, Requires<[IsBookE]>;
def MTSR: XForm_sr<31, 210, (outs), (ins gprc:$RS, u4imm:$SR),
"mtsr $SR, $RS", IIC_SprMTSR>;
def MFSR: XForm_sr<31, 595, (outs gprc:$RS), (ins u4imm:$SR),
"mfsr $RS, $SR", IIC_SprMFSR>;
def MTSRIN: XForm_srin<31, 242, (outs), (ins gprc:$RS, gprc:$RB),
"mtsrin $RS, $RB", IIC_SprMTSR>;
def MFSRIN: XForm_srin<31, 659, (outs gprc:$RS), (ins gprc:$RB),
"mfsrin $RS, $RB", IIC_SprMFSR>;
def MTMSR: XForm_mtmsr<31, 146, (outs), (ins gprc:$RS, i32imm:$L),
"mtmsr $RS, $L", IIC_SprMTMSR>;
def WRTEE: XForm_mtmsr<31, 131, (outs), (ins gprc:$RS),
"wrtee $RS", IIC_SprMTMSR>, Requires<[IsBookE]> {
let L = 0;
}
def WRTEEI: I<31, (outs), (ins i1imm:$E), "wrteei $E", IIC_SprMTMSR>,
Requires<[IsBookE]> {
bits<1> E;
let Inst{16} = E;
let Inst{21-30} = 163;
}
def DCCCI : XForm_tlb<454, (outs), (ins gprc:$A, gprc:$B),
"dccci $A, $B", IIC_LdStLoad>, Requires<[IsPPC4xx]>;
def ICCCI : XForm_tlb<966, (outs), (ins gprc:$A, gprc:$B),
"iccci $A, $B", IIC_LdStLoad>, Requires<[IsPPC4xx]>;
def : InstAlias<"dci 0", (DCCCI R0, R0)>, Requires<[IsPPC4xx]>;
def : InstAlias<"dccci", (DCCCI R0, R0)>, Requires<[IsPPC4xx]>;
def : InstAlias<"ici 0", (ICCCI R0, R0)>, Requires<[IsPPC4xx]>;
def : InstAlias<"iccci", (ICCCI R0, R0)>, Requires<[IsPPC4xx]>;
def MFMSR : XForm_rs<31, 83, (outs gprc:$RT), (ins),
"mfmsr $RT", IIC_SprMFMSR, []>;
def MTMSRD : XForm_mtmsr<31, 178, (outs), (ins gprc:$RS, i32imm:$L),
"mtmsrd $RS, $L", IIC_SprMTMSRD>;
def MCRFS : XLForm_3<63, 64, (outs crrc:$BF), (ins crrc:$BFA),
"mcrfs $BF, $BFA", IIC_BrMCR>;
def MTFSFI : XLForm_4<63, 134, (outs crrc:$BF), (ins i32imm:$U, i32imm:$W),
"mtfsfi $BF, $U, $W", IIC_IntMFFS>;
def MTFSFIo : XLForm_4<63, 134, (outs crrc:$BF), (ins i32imm:$U, i32imm:$W),
"mtfsfi. $BF, $U, $W", IIC_IntMFFS>, isDOT;
def : InstAlias<"mtfsfi $BF, $U", (MTFSFI crrc:$BF, i32imm:$U, 0)>;
def : InstAlias<"mtfsfi. $BF, $U", (MTFSFIo crrc:$BF, i32imm:$U, 0)>;
let Predicates = [HasFPU] in {
def MTFSF : XFLForm_1<63, 711, (outs),
(ins i32imm:$FLM, f8rc:$FRB, i32imm:$L, i32imm:$W),
"mtfsf $FLM, $FRB, $L, $W", IIC_IntMFFS, []>;
def MTFSFo : XFLForm_1<63, 711, (outs),
(ins i32imm:$FLM, f8rc:$FRB, i32imm:$L, i32imm:$W),
"mtfsf. $FLM, $FRB, $L, $W", IIC_IntMFFS, []>, isDOT;
def : InstAlias<"mtfsf $FLM, $FRB", (MTFSF i32imm:$FLM, f8rc:$FRB, 0, 0)>;
def : InstAlias<"mtfsf. $FLM, $FRB", (MTFSFo i32imm:$FLM, f8rc:$FRB, 0, 0)>;
}
def SLBIE : XForm_16b<31, 434, (outs), (ins gprc:$RB),
"slbie $RB", IIC_SprSLBIE, []>;
def SLBMTE : XForm_26<31, 402, (outs), (ins gprc:$RS, gprc:$RB),
"slbmte $RS, $RB", IIC_SprSLBMTE, []>;
def SLBMFEE : XForm_26<31, 915, (outs gprc:$RT), (ins gprc:$RB),
"slbmfee $RT, $RB", IIC_SprSLBMFEE, []>;
def SLBMFEV : XLForm_1_gen<31, 851, (outs gprc:$RT), (ins gprc:$RB),
"slbmfev $RT, $RB", IIC_SprSLBMFEV, []>;
def SLBIA : XForm_0<31, 498, (outs), (ins), "slbia", IIC_SprSLBIA, []>;
def TLBIA : XForm_0<31, 370, (outs), (ins),
"tlbia", IIC_SprTLBIA, []>;
def TLBSYNC : XForm_0<31, 566, (outs), (ins),
"tlbsync", IIC_SprTLBSYNC, []>;
def TLBIEL : XForm_16b<31, 274, (outs), (ins gprc:$RB),
"tlbiel $RB", IIC_SprTLBIEL, []>;
def TLBLD : XForm_16b<31, 978, (outs), (ins gprc:$RB),
"tlbld $RB", IIC_LdStLoad, []>, Requires<[IsPPC6xx]>;
def TLBLI : XForm_16b<31, 1010, (outs), (ins gprc:$RB),
"tlbli $RB", IIC_LdStLoad, []>, Requires<[IsPPC6xx]>;
def TLBIE : XForm_26<31, 306, (outs), (ins gprc:$RS, gprc:$RB),
"tlbie $RB,$RS", IIC_SprTLBIE, []>;
def TLBSX : XForm_tlb<914, (outs), (ins gprc:$A, gprc:$B), "tlbsx $A, $B",
IIC_LdStLoad>, Requires<[IsBookE]>;
def TLBIVAX : XForm_tlb<786, (outs), (ins gprc:$A, gprc:$B), "tlbivax $A, $B",
IIC_LdStLoad>, Requires<[IsBookE]>;
def TLBRE : XForm_24_eieio<31, 946, (outs), (ins),
"tlbre", IIC_LdStLoad, []>, Requires<[IsBookE]>;
def TLBWE : XForm_24_eieio<31, 978, (outs), (ins),
"tlbwe", IIC_LdStLoad, []>, Requires<[IsBookE]>;
def TLBRE2 : XForm_tlbws<31, 946, (outs gprc:$RS), (ins gprc:$A, i1imm:$WS),
"tlbre $RS, $A, $WS", IIC_LdStLoad, []>, Requires<[IsPPC4xx]>;
def TLBWE2 : XForm_tlbws<31, 978, (outs), (ins gprc:$RS, gprc:$A, i1imm:$WS),
"tlbwe $RS, $A, $WS", IIC_LdStLoad, []>, Requires<[IsPPC4xx]>;
def TLBSX2 : XForm_base_r3xo<31, 914, (outs), (ins gprc:$RST, gprc:$A, gprc:$B),
"tlbsx $RST, $A, $B", IIC_LdStLoad, []>,
Requires<[IsPPC4xx]>;
def TLBSX2D : XForm_base_r3xo<31, 914, (outs),
(ins gprc:$RST, gprc:$A, gprc:$B),
"tlbsx. $RST, $A, $B", IIC_LdStLoad, []>,
Requires<[IsPPC4xx]>, isDOT;
def RFID : XForm_0<19, 18, (outs), (ins), "rfid", IIC_IntRFID, []>;
def RFI : XForm_0<19, 50, (outs), (ins), "rfi", IIC_SprRFI, []>,
Requires<[IsBookE]>;
def RFCI : XForm_0<19, 51, (outs), (ins), "rfci", IIC_BrB, []>,
Requires<[IsBookE]>;
def RFDI : XForm_0<19, 39, (outs), (ins), "rfdi", IIC_BrB, []>,
Requires<[IsE500]>;
def RFMCI : XForm_0<19, 38, (outs), (ins), "rfmci", IIC_BrB, []>,
Requires<[IsE500]>;
def MFDCR : XFXForm_1<31, 323, (outs gprc:$RT), (ins i32imm:$SPR),
"mfdcr $RT, $SPR", IIC_SprMFSPR>, Requires<[IsPPC4xx]>;
def MTDCR : XFXForm_1<31, 451, (outs), (ins gprc:$RT, i32imm:$SPR),
"mtdcr $SPR, $RT", IIC_SprMTSPR>, Requires<[IsPPC4xx]>;
def HRFID : XLForm_1_np<19, 274, (outs), (ins), "hrfid", IIC_BrB, []>;
def NAP : XLForm_1_np<19, 434, (outs), (ins), "nap", IIC_BrB, []>;
def ATTN : XForm_attn<0, 256, (outs), (ins), "attn", IIC_BrB>;
def LBZCIX : XForm_base_r3xo_memOp<31, 853, (outs gprc:$RST),
(ins gprc:$A, gprc:$B),
"lbzcix $RST, $A, $B", IIC_LdStLoad, []>;
def LHZCIX : XForm_base_r3xo_memOp<31, 821, (outs gprc:$RST),
(ins gprc:$A, gprc:$B),
"lhzcix $RST, $A, $B", IIC_LdStLoad, []>;
def LWZCIX : XForm_base_r3xo_memOp<31, 789, (outs gprc:$RST),
(ins gprc:$A, gprc:$B),
"lwzcix $RST, $A, $B", IIC_LdStLoad, []>;
def LDCIX : XForm_base_r3xo_memOp<31, 885, (outs gprc:$RST),
(ins gprc:$A, gprc:$B),
"ldcix $RST, $A, $B", IIC_LdStLoad, []>;
def STBCIX : XForm_base_r3xo_memOp<31, 981, (outs),
(ins gprc:$RST, gprc:$A, gprc:$B),
"stbcix $RST, $A, $B", IIC_LdStLoad, []>;
def STHCIX : XForm_base_r3xo_memOp<31, 949, (outs),
(ins gprc:$RST, gprc:$A, gprc:$B),
"sthcix $RST, $A, $B", IIC_LdStLoad, []>;
def STWCIX : XForm_base_r3xo_memOp<31, 917, (outs),
(ins gprc:$RST, gprc:$A, gprc:$B),
"stwcix $RST, $A, $B", IIC_LdStLoad, []>;
def STDCIX : XForm_base_r3xo_memOp<31, 1013, (outs),
(ins gprc:$RST, gprc:$A, gprc:$B),
"stdcix $RST, $A, $B", IIC_LdStLoad, []>;
// External PID Load Store Instructions
def LBEPX : XForm_1<31, 95, (outs gprc:$rD), (ins memrr:$src),
"lbepx $rD, $src", IIC_LdStLoad, []>,
Requires<[IsE500]>;
def LFDEPX : XForm_25<31, 607, (outs f8rc:$frD), (ins memrr:$src),
"lfdepx $frD, $src", IIC_LdStLFD, []>,
Requires<[IsE500]>;
def LHEPX : XForm_1<31, 287, (outs gprc:$rD), (ins memrr:$src),
"lhepx $rD, $src", IIC_LdStLoad, []>,
Requires<[IsE500]>;
def LWEPX : XForm_1<31, 31, (outs gprc:$rD), (ins memrr:$src),
"lwepx $rD, $src", IIC_LdStLoad, []>,
Requires<[IsE500]>;
def STBEPX : XForm_8<31, 223, (outs), (ins gprc:$rS, memrr:$dst),
"stbepx $rS, $dst", IIC_LdStStore, []>,
Requires<[IsE500]>;
def STFDEPX : XForm_28_memOp<31, 735, (outs), (ins f8rc:$frS, memrr:$dst),
"stfdepx $frS, $dst", IIC_LdStSTFD, []>,
Requires<[IsE500]>;
def STHEPX : XForm_8<31, 415, (outs), (ins gprc:$rS, memrr:$dst),
"sthepx $rS, $dst", IIC_LdStStore, []>,
Requires<[IsE500]>;
def STWEPX : XForm_8<31, 159, (outs), (ins gprc:$rS, memrr:$dst),
"stwepx $rS, $dst", IIC_LdStStore, []>,
Requires<[IsE500]>;
def DCBFEP : DCB_Form<127, 0, (outs), (ins memrr:$dst), "dcbfep $dst",
IIC_LdStDCBF, []>, Requires<[IsE500]>;
def DCBSTEP : DCB_Form<63, 0, (outs), (ins memrr:$dst), "dcbstep $dst",
IIC_LdStDCBF, []>, Requires<[IsE500]>;
def DCBTEP : DCB_Form_hint<319, (outs), (ins memrr:$dst, u5imm:$TH),
"dcbtep $TH, $dst", IIC_LdStDCBF, []>,
Requires<[IsE500]>;
def DCBTSTEP : DCB_Form_hint<255, (outs), (ins memrr:$dst, u5imm:$TH),
"dcbtstep $TH, $dst", IIC_LdStDCBF, []>,
Requires<[IsE500]>;
def DCBZEP : DCB_Form<1023, 0, (outs), (ins memrr:$dst), "dcbzep $dst",
IIC_LdStDCBF, []>, Requires<[IsE500]>;
def DCBZLEP : DCB_Form<1023, 1, (outs), (ins memrr:$dst), "dcbzlep $dst",
IIC_LdStDCBF, []>, Requires<[IsE500]>;
def ICBIEP : XForm_1a<31, 991, (outs), (ins memrr:$src), "icbiep $src",
IIC_LdStICBI, []>, Requires<[IsE500]>;
//===----------------------------------------------------------------------===//
// PowerPC Assembler Instruction Aliases
//
// Pseudo-instructions for alternate assembly syntax (never used by codegen).
// These are aliases that require C++ handling to convert to the target
// instruction, while InstAliases can be handled directly by tblgen.
class PPCAsmPseudo<string asm, dag iops>
: Instruction {
let Namespace = "PPC";
bit PPC64 = 0; // Default value, override with isPPC64
let OutOperandList = (outs);
let InOperandList = iops;
let Pattern = [];
let AsmString = asm;
let isAsmParserOnly = 1;
let isPseudo = 1;
let hasNoSchedulingInfo = 1;
}
def : InstAlias<"sc", (SC 0)>;
def : InstAlias<"sync", (SYNC 0)>, Requires<[HasSYNC]>;
def : InstAlias<"msync", (SYNC 0), 0>, Requires<[HasSYNC]>;
def : InstAlias<"lwsync", (SYNC 1)>, Requires<[HasSYNC]>;
def : InstAlias<"ptesync", (SYNC 2)>, Requires<[HasSYNC]>;
def : InstAlias<"wait", (WAIT 0)>;
def : InstAlias<"waitrsv", (WAIT 1)>;
def : InstAlias<"waitimpl", (WAIT 2)>;
def : InstAlias<"mbar", (MBAR 0)>, Requires<[IsBookE]>;
def DCBTx : PPCAsmPseudo<"dcbt $dst", (ins memrr:$dst)>;
def DCBTSTx : PPCAsmPseudo<"dcbtst $dst", (ins memrr:$dst)>;
def DCBTCT : PPCAsmPseudo<"dcbtct $dst, $TH", (ins memrr:$dst, u5imm:$TH)>;
def DCBTDS : PPCAsmPseudo<"dcbtds $dst, $TH", (ins memrr:$dst, u5imm:$TH)>;
def DCBTT : PPCAsmPseudo<"dcbtt $dst", (ins memrr:$dst)>;
def DCBTSTCT : PPCAsmPseudo<"dcbtstct $dst, $TH", (ins memrr:$dst, u5imm:$TH)>;
def DCBTSTDS : PPCAsmPseudo<"dcbtstds $dst, $TH", (ins memrr:$dst, u5imm:$TH)>;
def DCBTSTT : PPCAsmPseudo<"dcbtstt $dst", (ins memrr:$dst)>;
def DCBFx : PPCAsmPseudo<"dcbf $dst", (ins memrr:$dst)>;
def DCBFL : PPCAsmPseudo<"dcbfl $dst", (ins memrr:$dst)>;
def DCBFLP : PPCAsmPseudo<"dcbflp $dst", (ins memrr:$dst)>;
def : InstAlias<"crset $bx", (CREQV crbitrc:$bx, crbitrc:$bx, crbitrc:$bx)>;
def : InstAlias<"crclr $bx", (CRXOR crbitrc:$bx, crbitrc:$bx, crbitrc:$bx)>;
def : InstAlias<"crmove $bx, $by", (CROR crbitrc:$bx, crbitrc:$by, crbitrc:$by)>;
def : InstAlias<"crnot $bx, $by", (CRNOR crbitrc:$bx, crbitrc:$by, crbitrc:$by)>;
def : InstAlias<"mtxer $Rx", (MTSPR 1, gprc:$Rx)>;
def : InstAlias<"mfxer $Rx", (MFSPR gprc:$Rx, 1)>;
def : InstAlias<"mfrtcu $Rx", (MFSPR gprc:$Rx, 4)>;
def : InstAlias<"mfrtcl $Rx", (MFSPR gprc:$Rx, 5)>;
def : InstAlias<"mtdscr $Rx", (MTSPR 17, gprc:$Rx)>;
def : InstAlias<"mfdscr $Rx", (MFSPR gprc:$Rx, 17)>;
def : InstAlias<"mtdsisr $Rx", (MTSPR 18, gprc:$Rx)>;
def : InstAlias<"mfdsisr $Rx", (MFSPR gprc:$Rx, 18)>;
def : InstAlias<"mtdar $Rx", (MTSPR 19, gprc:$Rx)>;
def : InstAlias<"mfdar $Rx", (MFSPR gprc:$Rx, 19)>;
def : InstAlias<"mtdec $Rx", (MTSPR 22, gprc:$Rx)>;
def : InstAlias<"mfdec $Rx", (MFSPR gprc:$Rx, 22)>;
def : InstAlias<"mtsdr1 $Rx", (MTSPR 25, gprc:$Rx)>;
def : InstAlias<"mfsdr1 $Rx", (MFSPR gprc:$Rx, 25)>;
def : InstAlias<"mtsrr0 $Rx", (MTSPR 26, gprc:$Rx)>;
def : InstAlias<"mfsrr0 $Rx", (MFSPR gprc:$Rx, 26)>;
def : InstAlias<"mtsrr1 $Rx", (MTSPR 27, gprc:$Rx)>;
def : InstAlias<"mfsrr1 $Rx", (MFSPR gprc:$Rx, 27)>;
def : InstAlias<"mtsrr2 $Rx", (MTSPR 990, gprc:$Rx)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mfsrr2 $Rx", (MFSPR gprc:$Rx, 990)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mtsrr3 $Rx", (MTSPR 991, gprc:$Rx)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mfsrr3 $Rx", (MFSPR gprc:$Rx, 991)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mtcfar $Rx", (MTSPR 28, gprc:$Rx)>;
def : InstAlias<"mfcfar $Rx", (MFSPR gprc:$Rx, 28)>;
def : InstAlias<"mtamr $Rx", (MTSPR 29, gprc:$Rx)>;
def : InstAlias<"mfamr $Rx", (MFSPR gprc:$Rx, 29)>;
def : InstAlias<"mtpid $Rx", (MTSPR 48, gprc:$Rx)>, Requires<[IsBookE]>;
def : InstAlias<"mfpid $Rx", (MFSPR gprc:$Rx, 48)>, Requires<[IsBookE]>;
def : InstAlias<"mftb $Rx", (MFTB gprc:$Rx, 268)>;
def : InstAlias<"mftbl $Rx", (MFTB gprc:$Rx, 268)>;
def : InstAlias<"mftbu $Rx", (MFTB gprc:$Rx, 269)>;
def : InstAlias<"mttbl $Rx", (MTSPR 284, gprc:$Rx)>;
def : InstAlias<"mttbu $Rx", (MTSPR 285, gprc:$Rx)>;
def : InstAlias<"mftblo $Rx", (MFSPR gprc:$Rx, 989)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mttblo $Rx", (MTSPR 989, gprc:$Rx)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mftbhi $Rx", (MFSPR gprc:$Rx, 988)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mttbhi $Rx", (MTSPR 988, gprc:$Rx)>, Requires<[IsPPC4xx]>;
def : InstAlias<"xnop", (XORI R0, R0, 0)>;
def : InstAlias<"mr $rA, $rB", (OR8 g8rc:$rA, g8rc:$rB, g8rc:$rB)>;
def : InstAlias<"mr. $rA, $rB", (OR8o g8rc:$rA, g8rc:$rB, g8rc:$rB)>;
def : InstAlias<"not $rA, $rB", (NOR8 g8rc:$rA, g8rc:$rB, g8rc:$rB)>;
def : InstAlias<"not. $rA, $rB", (NOR8o g8rc:$rA, g8rc:$rB, g8rc:$rB)>;
def : InstAlias<"mtcr $rA", (MTCRF8 255, g8rc:$rA)>;
foreach BATR = 0-3 in {
def : InstAlias<"mtdbatu "#BATR#", $Rx",
(MTSPR !add(BATR, !add(BATR, 536)), gprc:$Rx)>,
Requires<[IsPPC6xx]>;
def : InstAlias<"mfdbatu $Rx, "#BATR,
(MFSPR gprc:$Rx, !add(BATR, !add(BATR, 536)))>,
Requires<[IsPPC6xx]>;
def : InstAlias<"mtdbatl "#BATR#", $Rx",
(MTSPR !add(BATR, !add(BATR, 537)), gprc:$Rx)>,
Requires<[IsPPC6xx]>;
def : InstAlias<"mfdbatl $Rx, "#BATR,
(MFSPR gprc:$Rx, !add(BATR, !add(BATR, 537)))>,
Requires<[IsPPC6xx]>;
def : InstAlias<"mtibatu "#BATR#", $Rx",
(MTSPR !add(BATR, !add(BATR, 528)), gprc:$Rx)>,
Requires<[IsPPC6xx]>;
def : InstAlias<"mfibatu $Rx, "#BATR,
(MFSPR gprc:$Rx, !add(BATR, !add(BATR, 528)))>,
Requires<[IsPPC6xx]>;
def : InstAlias<"mtibatl "#BATR#", $Rx",
(MTSPR !add(BATR, !add(BATR, 529)), gprc:$Rx)>,
Requires<[IsPPC6xx]>;
def : InstAlias<"mfibatl $Rx, "#BATR,
(MFSPR gprc:$Rx, !add(BATR, !add(BATR, 529)))>,
Requires<[IsPPC6xx]>;
}
foreach BR = 0-7 in {
def : InstAlias<"mfbr"#BR#" $Rx",
(MFDCR gprc:$Rx, !add(BR, 0x80))>,
Requires<[IsPPC4xx]>;
def : InstAlias<"mtbr"#BR#" $Rx",
(MTDCR gprc:$Rx, !add(BR, 0x80))>,
Requires<[IsPPC4xx]>;
}
def : InstAlias<"mtdccr $Rx", (MTSPR 1018, gprc:$Rx)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mfdccr $Rx", (MFSPR gprc:$Rx, 1018)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mticcr $Rx", (MTSPR 1019, gprc:$Rx)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mficcr $Rx", (MFSPR gprc:$Rx, 1019)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mtdear $Rx", (MTSPR 981, gprc:$Rx)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mfdear $Rx", (MFSPR gprc:$Rx, 981)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mtesr $Rx", (MTSPR 980, gprc:$Rx)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mfesr $Rx", (MFSPR gprc:$Rx, 980)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mfspefscr $Rx", (MFSPR gprc:$Rx, 512)>;
def : InstAlias<"mtspefscr $Rx", (MTSPR 512, gprc:$Rx)>;
def : InstAlias<"mttcr $Rx", (MTSPR 986, gprc:$Rx)>, Requires<[IsPPC4xx]>;
def : InstAlias<"mftcr $Rx", (MFSPR gprc:$Rx, 986)>, Requires<[IsPPC4xx]>;
def LAx : PPCAsmPseudo<"la $rA, $addr", (ins gprc:$rA, memri:$addr)>;
def SUBI : PPCAsmPseudo<"subi $rA, $rB, $imm",
(ins gprc:$rA, gprc:$rB, s16imm:$imm)>;
def SUBIS : PPCAsmPseudo<"subis $rA, $rB, $imm",
(ins gprc:$rA, gprc:$rB, s16imm:$imm)>;
def SUBIC : PPCAsmPseudo<"subic $rA, $rB, $imm",
(ins gprc:$rA, gprc:$rB, s16imm:$imm)>;
def SUBICo : PPCAsmPseudo<"subic. $rA, $rB, $imm",
(ins gprc:$rA, gprc:$rB, s16imm:$imm)>;
def : InstAlias<"sub $rA, $rB, $rC", (SUBF8 g8rc:$rA, g8rc:$rC, g8rc:$rB)>;
def : InstAlias<"sub. $rA, $rB, $rC", (SUBF8o g8rc:$rA, g8rc:$rC, g8rc:$rB)>;
def : InstAlias<"subc $rA, $rB, $rC", (SUBFC8 g8rc:$rA, g8rc:$rC, g8rc:$rB)>;
def : InstAlias<"subc. $rA, $rB, $rC", (SUBFC8o g8rc:$rA, g8rc:$rC, g8rc:$rB)>;
def : InstAlias<"mtmsrd $RS", (MTMSRD gprc:$RS, 0)>;
def : InstAlias<"mtmsr $RS", (MTMSR gprc:$RS, 0)>;
def : InstAlias<"mfasr $RT", (MFSPR gprc:$RT, 280)>;
def : InstAlias<"mtasr $RT", (MTSPR 280, gprc:$RT)>;
foreach SPRG = 0-3 in {
def : InstAlias<"mfsprg $RT, "#SPRG, (MFSPR gprc:$RT, !add(SPRG, 272))>;
def : InstAlias<"mfsprg"#SPRG#" $RT", (MFSPR gprc:$RT, !add(SPRG, 272))>;
def : InstAlias<"mtsprg "#SPRG#", $RT", (MTSPR !add(SPRG, 272), gprc:$RT)>;
def : InstAlias<"mtsprg"#SPRG#" $RT", (MTSPR !add(SPRG, 272), gprc:$RT)>;
}
foreach SPRG = 4-7 in {
def : InstAlias<"mfsprg $RT, "#SPRG, (MFSPR gprc:$RT, !add(SPRG, 256))>,
Requires<[IsBookE]>;
def : InstAlias<"mfsprg"#SPRG#" $RT", (MFSPR gprc:$RT, !add(SPRG, 256))>,
Requires<[IsBookE]>;
def : InstAlias<"mtsprg "#SPRG#", $RT", (MTSPR !add(SPRG, 256), gprc:$RT)>,
Requires<[IsBookE]>;
def : InstAlias<"mtsprg"#SPRG#" $RT", (MTSPR !add(SPRG, 256), gprc:$RT)>,
Requires<[IsBookE]>;
}
def : InstAlias<"mtasr $RS", (MTSPR 280, gprc:$RS)>;
def : InstAlias<"mfdec $RT", (MFSPR gprc:$RT, 22)>;
def : InstAlias<"mtdec $RT", (MTSPR 22, gprc:$RT)>;
def : InstAlias<"mfpvr $RT", (MFSPR gprc:$RT, 287)>;
def : InstAlias<"mfsdr1 $RT", (MFSPR gprc:$RT, 25)>;
def : InstAlias<"mtsdr1 $RT", (MTSPR 25, gprc:$RT)>;
def : InstAlias<"mfsrr0 $RT", (MFSPR gprc:$RT, 26)>;
def : InstAlias<"mfsrr1 $RT", (MFSPR gprc:$RT, 27)>;
def : InstAlias<"mtsrr0 $RT", (MTSPR 26, gprc:$RT)>;
def : InstAlias<"mtsrr1 $RT", (MTSPR 27, gprc:$RT)>;
def : InstAlias<"tlbie $RB", (TLBIE R0, gprc:$RB)>;
def : InstAlias<"tlbrehi $RS, $A", (TLBRE2 gprc:$RS, gprc:$A, 0)>,
Requires<[IsPPC4xx]>;
def : InstAlias<"tlbrelo $RS, $A", (TLBRE2 gprc:$RS, gprc:$A, 1)>,
Requires<[IsPPC4xx]>;
def : InstAlias<"tlbwehi $RS, $A", (TLBWE2 gprc:$RS, gprc:$A, 0)>,
Requires<[IsPPC4xx]>;
def : InstAlias<"tlbwelo $RS, $A", (TLBWE2 gprc:$RS, gprc:$A, 1)>,
Requires<[IsPPC4xx]>;
def EXTLWI : PPCAsmPseudo<"extlwi $rA, $rS, $n, $b",
(ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>;
def EXTLWIo : PPCAsmPseudo<"extlwi. $rA, $rS, $n, $b",
(ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>;
def EXTRWI : PPCAsmPseudo<"extrwi $rA, $rS, $n, $b",
(ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>;
def EXTRWIo : PPCAsmPseudo<"extrwi. $rA, $rS, $n, $b",
(ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>;
def INSLWI : PPCAsmPseudo<"inslwi $rA, $rS, $n, $b",
(ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>;
def INSLWIo : PPCAsmPseudo<"inslwi. $rA, $rS, $n, $b",
(ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>;
def INSRWI : PPCAsmPseudo<"insrwi $rA, $rS, $n, $b",
(ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>;
def INSRWIo : PPCAsmPseudo<"insrwi. $rA, $rS, $n, $b",
(ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>;
def ROTRWI : PPCAsmPseudo<"rotrwi $rA, $rS, $n",
(ins gprc:$rA, gprc:$rS, u5imm:$n)>;
def ROTRWIo : PPCAsmPseudo<"rotrwi. $rA, $rS, $n",
(ins gprc:$rA, gprc:$rS, u5imm:$n)>;
def SLWI : PPCAsmPseudo<"slwi $rA, $rS, $n",
(ins gprc:$rA, gprc:$rS, u5imm:$n)>;
def SLWIo : PPCAsmPseudo<"slwi. $rA, $rS, $n",
(ins gprc:$rA, gprc:$rS, u5imm:$n)>;
def SRWI : PPCAsmPseudo<"srwi $rA, $rS, $n",
(ins gprc:$rA, gprc:$rS, u5imm:$n)>;
def SRWIo : PPCAsmPseudo<"srwi. $rA, $rS, $n",
(ins gprc:$rA, gprc:$rS, u5imm:$n)>;
def CLRRWI : PPCAsmPseudo<"clrrwi $rA, $rS, $n",
(ins gprc:$rA, gprc:$rS, u5imm:$n)>;
def CLRRWIo : PPCAsmPseudo<"clrrwi. $rA, $rS, $n",
(ins gprc:$rA, gprc:$rS, u5imm:$n)>;
def CLRLSLWI : PPCAsmPseudo<"clrlslwi $rA, $rS, $b, $n",
(ins gprc:$rA, gprc:$rS, u5imm:$b, u5imm:$n)>;
def CLRLSLWIo : PPCAsmPseudo<"clrlslwi. $rA, $rS, $b, $n",
(ins gprc:$rA, gprc:$rS, u5imm:$b, u5imm:$n)>;
def : InstAlias<"rotlwi $rA, $rS, $n", (RLWINM gprc:$rA, gprc:$rS, u5imm:$n, 0, 31)>;
def : InstAlias<"rotlwi. $rA, $rS, $n", (RLWINMo gprc:$rA, gprc:$rS, u5imm:$n, 0, 31)>;
def : InstAlias<"rotlw $rA, $rS, $rB", (RLWNM gprc:$rA, gprc:$rS, gprc:$rB, 0, 31)>;
def : InstAlias<"rotlw. $rA, $rS, $rB", (RLWNMo gprc:$rA, gprc:$rS, gprc:$rB, 0, 31)>;
def : InstAlias<"clrlwi $rA, $rS, $n", (RLWINM gprc:$rA, gprc:$rS, 0, u5imm:$n, 31)>;
def : InstAlias<"clrlwi. $rA, $rS, $n", (RLWINMo gprc:$rA, gprc:$rS, 0, u5imm:$n, 31)>;
def : InstAlias<"cntlzw $rA, $rS", (CNTLZW gprc:$rA, gprc:$rS)>;
def : InstAlias<"cntlzw. $rA, $rS", (CNTLZWo gprc:$rA, gprc:$rS)>;
// The POWER variant
def : MnemonicAlias<"cntlz", "cntlzw">;
def : MnemonicAlias<"cntlz.", "cntlzw.">;
def EXTLDI : PPCAsmPseudo<"extldi $rA, $rS, $n, $b",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n, u6imm:$b)>;
def EXTLDIo : PPCAsmPseudo<"extldi. $rA, $rS, $n, $b",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n, u6imm:$b)>;
def EXTRDI : PPCAsmPseudo<"extrdi $rA, $rS, $n, $b",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n, u6imm:$b)>;
def EXTRDIo : PPCAsmPseudo<"extrdi. $rA, $rS, $n, $b",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n, u6imm:$b)>;
def INSRDI : PPCAsmPseudo<"insrdi $rA, $rS, $n, $b",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n, u6imm:$b)>;
def INSRDIo : PPCAsmPseudo<"insrdi. $rA, $rS, $n, $b",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n, u6imm:$b)>;
def ROTRDI : PPCAsmPseudo<"rotrdi $rA, $rS, $n",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n)>;
def ROTRDIo : PPCAsmPseudo<"rotrdi. $rA, $rS, $n",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n)>;
def SLDI : PPCAsmPseudo<"sldi $rA, $rS, $n",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n)>;
def SLDIo : PPCAsmPseudo<"sldi. $rA, $rS, $n",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n)>;
def SRDI : PPCAsmPseudo<"srdi $rA, $rS, $n",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n)>;
def SRDIo : PPCAsmPseudo<"srdi. $rA, $rS, $n",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n)>;
def CLRRDI : PPCAsmPseudo<"clrrdi $rA, $rS, $n",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n)>;
def CLRRDIo : PPCAsmPseudo<"clrrdi. $rA, $rS, $n",
(ins g8rc:$rA, g8rc:$rS, u6imm:$n)>;
def CLRLSLDI : PPCAsmPseudo<"clrlsldi $rA, $rS, $b, $n",
(ins g8rc:$rA, g8rc:$rS, u6imm:$b, u6imm:$n)>;
def CLRLSLDIo : PPCAsmPseudo<"clrlsldi. $rA, $rS, $b, $n",
(ins g8rc:$rA, g8rc:$rS, u6imm:$b, u6imm:$n)>;
def SUBPCIS : PPCAsmPseudo<"subpcis $RT, $D", (ins g8rc:$RT, s16imm:$D)>;
def : InstAlias<"rotldi $rA, $rS, $n", (RLDICL g8rc:$rA, g8rc:$rS, u6imm:$n, 0)>;
def : InstAlias<"rotldi. $rA, $rS, $n", (RLDICLo g8rc:$rA, g8rc:$rS, u6imm:$n, 0)>;
def : InstAlias<"rotld $rA, $rS, $rB", (RLDCL g8rc:$rA, g8rc:$rS, gprc:$rB, 0)>;
def : InstAlias<"rotld. $rA, $rS, $rB", (RLDCLo g8rc:$rA, g8rc:$rS, gprc:$rB, 0)>;
def : InstAlias<"clrldi $rA, $rS, $n", (RLDICL g8rc:$rA, g8rc:$rS, 0, u6imm:$n)>;
def : InstAlias<"clrldi $rA, $rS, $n",
(RLDICL_32_64 g8rc:$rA, gprc:$rS, 0, u6imm:$n)>;
def : InstAlias<"clrldi. $rA, $rS, $n", (RLDICLo g8rc:$rA, g8rc:$rS, 0, u6imm:$n)>;
def : InstAlias<"lnia $RT", (ADDPCIS g8rc:$RT, 0)>;
def RLWINMbm : PPCAsmPseudo<"rlwinm $rA, $rS, $n, $b",
(ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>;
def RLWINMobm : PPCAsmPseudo<"rlwinm. $rA, $rS, $n, $b",
(ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>;
def RLWIMIbm : PPCAsmPseudo<"rlwimi $rA, $rS, $n, $b",
(ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>;
def RLWIMIobm : PPCAsmPseudo<"rlwimi. $rA, $rS, $n, $b",
(ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>;
def RLWNMbm : PPCAsmPseudo<"rlwnm $rA, $rS, $n, $b",
(ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>;
def RLWNMobm : PPCAsmPseudo<"rlwnm. $rA, $rS, $n, $b",
(ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>;
// These generic branch instruction forms are used for the assembler parser only.
// Defs and Uses are conservative, since we don't know the BO value.
let PPC970_Unit = 7, isBranch = 1 in {
let Defs = [CTR], Uses = [CTR, RM] in {
def gBC : BForm_3<16, 0, 0, (outs),
(ins u5imm:$bo, crbitrc:$bi, condbrtarget:$dst),
"bc $bo, $bi, $dst">;
def gBCA : BForm_3<16, 1, 0, (outs),
(ins u5imm:$bo, crbitrc:$bi, abscondbrtarget:$dst),
"bca $bo, $bi, $dst">;
let isAsmParserOnly = 1 in {
def gBCat : BForm_3_at<16, 0, 0, (outs),
(ins u5imm:$bo, atimm:$at, crbitrc:$bi,
condbrtarget:$dst),
"bc$at $bo, $bi, $dst">;
def gBCAat : BForm_3_at<16, 1, 0, (outs),
(ins u5imm:$bo, atimm:$at, crbitrc:$bi,
abscondbrtarget:$dst),
"bca$at $bo, $bi, $dst">;
} // isAsmParserOnly = 1
}
let Defs = [LR, CTR], Uses = [CTR, RM] in {
def gBCL : BForm_3<16, 0, 1, (outs),
(ins u5imm:$bo, crbitrc:$bi, condbrtarget:$dst),
"bcl $bo, $bi, $dst">;
def gBCLA : BForm_3<16, 1, 1, (outs),
(ins u5imm:$bo, crbitrc:$bi, abscondbrtarget:$dst),
"bcla $bo, $bi, $dst">;
let isAsmParserOnly = 1 in {
def gBCLat : BForm_3_at<16, 0, 1, (outs),
(ins u5imm:$bo, atimm:$at, crbitrc:$bi,
condbrtarget:$dst),
"bcl$at $bo, $bi, $dst">;
def gBCLAat : BForm_3_at<16, 1, 1, (outs),
(ins u5imm:$bo, atimm:$at, crbitrc:$bi,
abscondbrtarget:$dst),
"bcla$at $bo, $bi, $dst">;
} // // isAsmParserOnly = 1
}
let Defs = [CTR], Uses = [CTR, LR, RM] in
def gBCLR : XLForm_2<19, 16, 0, (outs),
(ins u5imm:$bo, crbitrc:$bi, i32imm:$bh),
"bclr $bo, $bi, $bh", IIC_BrB, []>;
let Defs = [LR, CTR], Uses = [CTR, LR, RM] in
def gBCLRL : XLForm_2<19, 16, 1, (outs),
(ins u5imm:$bo, crbitrc:$bi, i32imm:$bh),
"bclrl $bo, $bi, $bh", IIC_BrB, []>;
let Defs = [CTR], Uses = [CTR, LR, RM] in
def gBCCTR : XLForm_2<19, 528, 0, (outs),
(ins u5imm:$bo, crbitrc:$bi, i32imm:$bh),
"bcctr $bo, $bi, $bh", IIC_BrB, []>;
let Defs = [LR, CTR], Uses = [CTR, LR, RM] in
def gBCCTRL : XLForm_2<19, 528, 1, (outs),
(ins u5imm:$bo, crbitrc:$bi, i32imm:$bh),
"bcctrl $bo, $bi, $bh", IIC_BrB, []>;
}
multiclass BranchSimpleMnemonicAT<string pm, int at> {
def : InstAlias<"bc"#pm#" $bo, $bi, $dst", (gBCat u5imm:$bo, at, crbitrc:$bi,
condbrtarget:$dst)>;
def : InstAlias<"bca"#pm#" $bo, $bi, $dst", (gBCAat u5imm:$bo, at, crbitrc:$bi,
condbrtarget:$dst)>;
def : InstAlias<"bcl"#pm#" $bo, $bi, $dst", (gBCLat u5imm:$bo, at, crbitrc:$bi,
condbrtarget:$dst)>;
def : InstAlias<"bcla"#pm#" $bo, $bi, $dst", (gBCLAat u5imm:$bo, at, crbitrc:$bi,
condbrtarget:$dst)>;
}
defm : BranchSimpleMnemonicAT<"+", 3>;
defm : BranchSimpleMnemonicAT<"-", 2>;
def : InstAlias<"bclr $bo, $bi", (gBCLR u5imm:$bo, crbitrc:$bi, 0)>;
def : InstAlias<"bclrl $bo, $bi", (gBCLRL u5imm:$bo, crbitrc:$bi, 0)>;
def : InstAlias<"bcctr $bo, $bi", (gBCCTR u5imm:$bo, crbitrc:$bi, 0)>;
def : InstAlias<"bcctrl $bo, $bi", (gBCCTRL u5imm:$bo, crbitrc:$bi, 0)>;
multiclass BranchSimpleMnemonic1<string name, string pm, int bo> {
def : InstAlias<"b"#name#pm#" $bi, $dst", (gBC bo, crbitrc:$bi, condbrtarget:$dst)>;
def : InstAlias<"b"#name#"a"#pm#" $bi, $dst", (gBCA bo, crbitrc:$bi, abscondbrtarget:$dst)>;
def : InstAlias<"b"#name#"lr"#pm#" $bi", (gBCLR bo, crbitrc:$bi, 0)>;
def : InstAlias<"b"#name#"l"#pm#" $bi, $dst", (gBCL bo, crbitrc:$bi, condbrtarget:$dst)>;
def : InstAlias<"b"#name#"la"#pm#" $bi, $dst", (gBCLA bo, crbitrc:$bi, abscondbrtarget:$dst)>;
def : InstAlias<"b"#name#"lrl"#pm#" $bi", (gBCLRL bo, crbitrc:$bi, 0)>;
}
multiclass BranchSimpleMnemonic2<string name, string pm, int bo>
: BranchSimpleMnemonic1<name, pm, bo> {
def : InstAlias<"b"#name#"ctr"#pm#" $bi", (gBCCTR bo, crbitrc:$bi, 0)>;
def : InstAlias<"b"#name#"ctrl"#pm#" $bi", (gBCCTRL bo, crbitrc:$bi, 0)>;
}
defm : BranchSimpleMnemonic2<"t", "", 12>;
defm : BranchSimpleMnemonic2<"f", "", 4>;
defm : BranchSimpleMnemonic2<"t", "-", 14>;
defm : BranchSimpleMnemonic2<"f", "-", 6>;
defm : BranchSimpleMnemonic2<"t", "+", 15>;
defm : BranchSimpleMnemonic2<"f", "+", 7>;
defm : BranchSimpleMnemonic1<"dnzt", "", 8>;
defm : BranchSimpleMnemonic1<"dnzf", "", 0>;
defm : BranchSimpleMnemonic1<"dzt", "", 10>;
defm : BranchSimpleMnemonic1<"dzf", "", 2>;
multiclass BranchExtendedMnemonicPM<string name, string pm, int bibo> {
def : InstAlias<"b"#name#pm#" $cc, $dst",
(BCC bibo, crrc:$cc, condbrtarget:$dst)>;
def : InstAlias<"b"#name#pm#" $dst",
(BCC bibo, CR0, condbrtarget:$dst)>;
def : InstAlias<"b"#name#"a"#pm#" $cc, $dst",
(BCCA bibo, crrc:$cc, abscondbrtarget:$dst)>;
def : InstAlias<"b"#name#"a"#pm#" $dst",
(BCCA bibo, CR0, abscondbrtarget:$dst)>;
def : InstAlias<"b"#name#"lr"#pm#" $cc",
(BCCLR bibo, crrc:$cc)>;
def : InstAlias<"b"#name#"lr"#pm,
(BCCLR bibo, CR0)>;
def : InstAlias<"b"#name#"ctr"#pm#" $cc",
(BCCCTR bibo, crrc:$cc)>;
def : InstAlias<"b"#name#"ctr"#pm,
(BCCCTR bibo, CR0)>;
def : InstAlias<"b"#name#"l"#pm#" $cc, $dst",
(BCCL bibo, crrc:$cc, condbrtarget:$dst)>;
def : InstAlias<"b"#name#"l"#pm#" $dst",
(BCCL bibo, CR0, condbrtarget:$dst)>;
def : InstAlias<"b"#name#"la"#pm#" $cc, $dst",
(BCCLA bibo, crrc:$cc, abscondbrtarget:$dst)>;
def : InstAlias<"b"#name#"la"#pm#" $dst",
(BCCLA bibo, CR0, abscondbrtarget:$dst)>;
def : InstAlias<"b"#name#"lrl"#pm#" $cc",
(BCCLRL bibo, crrc:$cc)>;
def : InstAlias<"b"#name#"lrl"#pm,
(BCCLRL bibo, CR0)>;
def : InstAlias<"b"#name#"ctrl"#pm#" $cc",
(BCCCTRL bibo, crrc:$cc)>;
def : InstAlias<"b"#name#"ctrl"#pm,
(BCCCTRL bibo, CR0)>;
}
multiclass BranchExtendedMnemonic<string name, int bibo> {
defm : BranchExtendedMnemonicPM<name, "", bibo>;
defm : BranchExtendedMnemonicPM<name, "-", !add(bibo, 2)>;
defm : BranchExtendedMnemonicPM<name, "+", !add(bibo, 3)>;
}
defm : BranchExtendedMnemonic<"lt", 12>;
defm : BranchExtendedMnemonic<"gt", 44>;
defm : BranchExtendedMnemonic<"eq", 76>;
defm : BranchExtendedMnemonic<"un", 108>;
defm : BranchExtendedMnemonic<"so", 108>;
defm : BranchExtendedMnemonic<"ge", 4>;
defm : BranchExtendedMnemonic<"nl", 4>;
defm : BranchExtendedMnemonic<"le", 36>;
defm : BranchExtendedMnemonic<"ng", 36>;
defm : BranchExtendedMnemonic<"ne", 68>;
defm : BranchExtendedMnemonic<"nu", 100>;
defm : BranchExtendedMnemonic<"ns", 100>;
def : InstAlias<"cmpwi $rA, $imm", (CMPWI CR0, gprc:$rA, s16imm:$imm)>;
def : InstAlias<"cmpw $rA, $rB", (CMPW CR0, gprc:$rA, gprc:$rB)>;
def : InstAlias<"cmplwi $rA, $imm", (CMPLWI CR0, gprc:$rA, u16imm:$imm)>;
def : InstAlias<"cmplw $rA, $rB", (CMPLW CR0, gprc:$rA, gprc:$rB)>;
def : InstAlias<"cmpdi $rA, $imm", (CMPDI CR0, g8rc:$rA, s16imm64:$imm)>;
def : InstAlias<"cmpd $rA, $rB", (CMPD CR0, g8rc:$rA, g8rc:$rB)>;
def : InstAlias<"cmpldi $rA, $imm", (CMPLDI CR0, g8rc:$rA, u16imm64:$imm)>;
def : InstAlias<"cmpld $rA, $rB", (CMPLD CR0, g8rc:$rA, g8rc:$rB)>;
def : InstAlias<"cmpi $bf, 0, $rA, $imm", (CMPWI crrc:$bf, gprc:$rA, s16imm:$imm)>;
def : InstAlias<"cmp $bf, 0, $rA, $rB", (CMPW crrc:$bf, gprc:$rA, gprc:$rB)>;
def : InstAlias<"cmpli $bf, 0, $rA, $imm", (CMPLWI crrc:$bf, gprc:$rA, u16imm:$imm)>;
def : InstAlias<"cmpl $bf, 0, $rA, $rB", (CMPLW crrc:$bf, gprc:$rA, gprc:$rB)>;
def : InstAlias<"cmpi $bf, 1, $rA, $imm", (CMPDI crrc:$bf, g8rc:$rA, s16imm64:$imm)>;
def : InstAlias<"cmp $bf, 1, $rA, $rB", (CMPD crrc:$bf, g8rc:$rA, g8rc:$rB)>;
def : InstAlias<"cmpli $bf, 1, $rA, $imm", (CMPLDI crrc:$bf, g8rc:$rA, u16imm64:$imm)>;
def : InstAlias<"cmpl $bf, 1, $rA, $rB", (CMPLD crrc:$bf, g8rc:$rA, g8rc:$rB)>;
multiclass TrapExtendedMnemonic<string name, int to> {
def : InstAlias<"td"#name#"i $rA, $imm", (TDI to, g8rc:$rA, s16imm:$imm)>;
def : InstAlias<"td"#name#" $rA, $rB", (TD to, g8rc:$rA, g8rc:$rB)>;
def : InstAlias<"tw"#name#"i $rA, $imm", (TWI to, gprc:$rA, s16imm:$imm)>;
def : InstAlias<"tw"#name#" $rA, $rB", (TW to, gprc:$rA, gprc:$rB)>;
}
defm : TrapExtendedMnemonic<"lt", 16>;
defm : TrapExtendedMnemonic<"le", 20>;
defm : TrapExtendedMnemonic<"eq", 4>;
defm : TrapExtendedMnemonic<"ge", 12>;
defm : TrapExtendedMnemonic<"gt", 8>;
defm : TrapExtendedMnemonic<"nl", 12>;
defm : TrapExtendedMnemonic<"ne", 24>;
defm : TrapExtendedMnemonic<"ng", 20>;
defm : TrapExtendedMnemonic<"llt", 2>;
defm : TrapExtendedMnemonic<"lle", 6>;
defm : TrapExtendedMnemonic<"lge", 5>;
defm : TrapExtendedMnemonic<"lgt", 1>;
defm : TrapExtendedMnemonic<"lnl", 5>;
defm : TrapExtendedMnemonic<"lng", 6>;
defm : TrapExtendedMnemonic<"u", 31>;
// Atomic loads
def : Pat<(atomic_load_8 iaddr:$src), (LBZ memri:$src)>;
def : Pat<(atomic_load_16 iaddr:$src), (LHZ memri:$src)>;
def : Pat<(atomic_load_32 iaddr:$src), (LWZ memri:$src)>;
def : Pat<(atomic_load_8 xaddr:$src), (LBZX memrr:$src)>;
def : Pat<(atomic_load_16 xaddr:$src), (LHZX memrr:$src)>;
def : Pat<(atomic_load_32 xaddr:$src), (LWZX memrr:$src)>;
// Atomic stores
def : Pat<(atomic_store_8 iaddr:$ptr, i32:$val), (STB gprc:$val, memri:$ptr)>;
def : Pat<(atomic_store_16 iaddr:$ptr, i32:$val), (STH gprc:$val, memri:$ptr)>;
def : Pat<(atomic_store_32 iaddr:$ptr, i32:$val), (STW gprc:$val, memri:$ptr)>;
def : Pat<(atomic_store_8 xaddr:$ptr, i32:$val), (STBX gprc:$val, memrr:$ptr)>;
def : Pat<(atomic_store_16 xaddr:$ptr, i32:$val), (STHX gprc:$val, memrr:$ptr)>;
def : Pat<(atomic_store_32 xaddr:$ptr, i32:$val), (STWX gprc:$val, memrr:$ptr)>;
let Predicates = [IsISA3_0] in {
// Copy-Paste Facility
// We prefix 'CP' to COPY due to name conflict in Target.td. We also prefix to
// PASTE for naming consistency.
let mayLoad = 1 in
def CP_COPY : X_L1_RA5_RB5<31, 774, "copy" , gprc, IIC_LdStCOPY, []>;
let mayStore = 1 in
def CP_PASTE : X_L1_RA5_RB5<31, 902, "paste" , gprc, IIC_LdStPASTE, []>;
let mayStore = 1, Defs = [CR0] in
def CP_PASTEo : X_L1_RA5_RB5<31, 902, "paste.", gprc, IIC_LdStPASTE, []>, isDOT;
def CP_COPYx : PPCAsmPseudo<"copy $rA, $rB" , (ins gprc:$rA, gprc:$rB)>;
def CP_PASTEx : PPCAsmPseudo<"paste $rA, $rB", (ins gprc:$rA, gprc:$rB)>;
def CP_COPY_FIRST : PPCAsmPseudo<"copy_first $rA, $rB",
(ins gprc:$rA, gprc:$rB)>;
def CP_PASTE_LAST : PPCAsmPseudo<"paste_last $rA, $rB",
(ins gprc:$rA, gprc:$rB)>;
def CP_ABORT : XForm_0<31, 838, (outs), (ins), "cp_abort", IIC_SprABORT, []>;
// Message Synchronize
def MSGSYNC : XForm_0<31, 886, (outs), (ins), "msgsync", IIC_SprMSGSYNC, []>;
// Power-Saving Mode Instruction:
def STOP : XForm_0<19, 370, (outs), (ins), "stop", IIC_SprSTOP, []>;
} // IsISA3_0
// Fast 32-bit reverse bits algorithm:
// Step 1: 1-bit swap (swap odd 1-bit and even 1-bit):
// n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xAAAAAAAA);
// Step 2: 2-bit swap (swap odd 2-bit and even 2-bit):
// n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xCCCCCCCC);
// Step 3: 4-bit swap (swap odd 4-bit and even 4-bit):
// n = ((n >> 4) & 0x0F0F0F0F) | ((n << 4) & 0xF0F0F0F0);
// Step 4: byte reverse (Suppose n = [B1,B2,B3,B4]):
// Step 4.1: Put B4,B2 in the right position (rotate left 3 bytes):
// n' = (n rotl 24); After which n' = [B4, B1, B2, B3]
// Step 4.2: Insert B3 to the right position:
// n' = rlwimi n', n, 8, 8, 15; After which n' = [B4, B3, B2, B3]
// Step 4.3: Insert B1 to the right position:
// n' = rlwimi n', n, 8, 24, 31; After which n' = [B4, B3, B2, B1]
def MaskValues {
dag Lo1 = (ORI (LIS 0x5555), 0x5555);
dag Hi1 = (ORI (LIS 0xAAAA), 0xAAAA);
dag Lo2 = (ORI (LIS 0x3333), 0x3333);
dag Hi2 = (ORI (LIS 0xCCCC), 0xCCCC);
dag Lo4 = (ORI (LIS 0x0F0F), 0x0F0F);
dag Hi4 = (ORI (LIS 0xF0F0), 0xF0F0);
}
def Shift1 {
dag Right = (RLWINM $A, 31, 1, 31);
dag Left = (RLWINM $A, 1, 0, 30);
}
def Swap1 {
dag Bit = (OR (AND Shift1.Right, MaskValues.Lo1),
(AND Shift1.Left, MaskValues.Hi1));
}
def Shift2 {
dag Right = (RLWINM Swap1.Bit, 30, 2, 31);
dag Left = (RLWINM Swap1.Bit, 2, 0, 29);
}
def Swap2 {
dag Bits = (OR (AND Shift2.Right, MaskValues.Lo2),
(AND Shift2.Left, MaskValues.Hi2));
}
def Shift4 {
dag Right = (RLWINM Swap2.Bits, 28, 4, 31);
dag Left = (RLWINM Swap2.Bits, 4, 0, 27);
}
def Swap4 {
dag Bits = (OR (AND Shift4.Right, MaskValues.Lo4),
(AND Shift4.Left, MaskValues.Hi4));
}
def Rotate {
dag Left3Bytes = (RLWINM Swap4.Bits, 24, 0, 31);
}
def RotateInsertByte3 {
dag Left = (RLWIMI Rotate.Left3Bytes, Swap4.Bits, 8, 8, 15);
}
def RotateInsertByte1 {
dag Left = (RLWIMI RotateInsertByte3.Left, Swap4.Bits, 8, 24, 31);
}
def : Pat<(i32 (bitreverse i32:$A)),
(RLDICL_32 RotateInsertByte1.Left, 0, 32)>;
// Fast 64-bit reverse bits algorithm:
// Step 1: 1-bit swap (swap odd 1-bit and even 1-bit):
// n = ((n >> 1) & 0x5555555555555555) | ((n << 1) & 0xAAAAAAAAAAAAAAAA);
// Step 2: 2-bit swap (swap odd 2-bit and even 2-bit):
// n = ((n >> 2) & 0x3333333333333333) | ((n << 2) & 0xCCCCCCCCCCCCCCCC);
// Step 3: 4-bit swap (swap odd 4-bit and even 4-bit):
// n = ((n >> 4) & 0x0F0F0F0F0F0F0F0F) | ((n << 4) & 0xF0F0F0F0F0F0F0F0);
// Step 4: byte reverse (Suppose n = [B0,B1,B2,B3,B4,B5,B6,B7]):
// Apply the same byte reverse algorithm mentioned above for the fast 32-bit
// reverse to both the high 32 bit and low 32 bit of the 64 bit value. And
// then OR them together to get the final result.
def MaskValues64 {
dag Lo1 = (i64 (INSERT_SUBREG (i64 (IMPLICIT_DEF)), MaskValues.Lo1, sub_32));
dag Hi1 = (i64 (INSERT_SUBREG (i64 (IMPLICIT_DEF)), MaskValues.Hi1, sub_32));
dag Lo2 = (i64 (INSERT_SUBREG (i64 (IMPLICIT_DEF)), MaskValues.Lo2, sub_32));
dag Hi2 = (i64 (INSERT_SUBREG (i64 (IMPLICIT_DEF)), MaskValues.Hi2, sub_32));
dag Lo4 = (i64 (INSERT_SUBREG (i64 (IMPLICIT_DEF)), MaskValues.Lo4, sub_32));
dag Hi4 = (i64 (INSERT_SUBREG (i64 (IMPLICIT_DEF)), MaskValues.Hi4, sub_32));
}
def DWMaskValues {
dag Lo1 = (ORI8 (ORIS8 (RLDICR MaskValues64.Lo1, 32, 31), 0x5555), 0x5555);
dag Hi1 = (ORI8 (ORIS8 (RLDICR MaskValues64.Hi1, 32, 31), 0xAAAA), 0xAAAA);
dag Lo2 = (ORI8 (ORIS8 (RLDICR MaskValues64.Lo2, 32, 31), 0x3333), 0x3333);
dag Hi2 = (ORI8 (ORIS8 (RLDICR MaskValues64.Hi2, 32, 31), 0xCCCC), 0xCCCC);
dag Lo4 = (ORI8 (ORIS8 (RLDICR MaskValues64.Lo4, 32, 31), 0x0F0F), 0x0F0F);
dag Hi4 = (ORI8 (ORIS8 (RLDICR MaskValues64.Hi4, 32, 31), 0xF0F0), 0xF0F0);
}
def DWSwapInByte {
dag Swap1 = (OR8 (AND8 (RLDICL $A, 63, 1), DWMaskValues.Lo1),
(AND8 (RLDICR $A, 1, 62), DWMaskValues.Hi1));
dag Swap2 = (OR8 (AND8 (RLDICL Swap1, 62, 2), DWMaskValues.Lo2),
(AND8 (RLDICR Swap1, 2, 61), DWMaskValues.Hi2));
dag Swap4 = (OR8 (AND8 (RLDICL Swap2, 60, 4), DWMaskValues.Lo4),
(AND8 (RLDICR Swap2, 4, 59), DWMaskValues.Hi4));
}
// Intra-byte swap is done, now start inter-byte swap.
def DWBytes4567 {
dag Word = (i32 (EXTRACT_SUBREG DWSwapInByte.Swap4, sub_32));
}
def DWBytes7456 {
dag Word = (RLWINM DWBytes4567.Word, 24, 0, 31);
}
def DWBytes7656 {
dag Word = (RLWIMI DWBytes7456.Word, DWBytes4567.Word, 8, 8, 15);
}
// B7 B6 B5 B4 in the right order
def DWBytes7654 {
dag Word = (RLWIMI DWBytes7656.Word, DWBytes4567.Word, 8, 24, 31);
dag DWord =
(i64 (INSERT_SUBREG (i64 (IMPLICIT_DEF)), Word, sub_32));
}
def DWBytes0123 {
dag Word = (i32 (EXTRACT_SUBREG (RLDICL DWSwapInByte.Swap4, 32, 32), sub_32));
}
def DWBytes3012 {
dag Word = (RLWINM DWBytes0123.Word, 24, 0, 31);
}
def DWBytes3212 {
dag Word = (RLWIMI DWBytes3012.Word, DWBytes0123.Word, 8, 8, 15);
}
// B3 B2 B1 B0 in the right order
def DWBytes3210 {
dag Word = (RLWIMI DWBytes3212.Word, DWBytes0123.Word, 8, 24, 31);
dag DWord =
(i64 (INSERT_SUBREG (i64 (IMPLICIT_DEF)), Word, sub_32));
}
// Now both high word and low word are reversed, next
// swap the high word and low word.
def : Pat<(i64 (bitreverse i64:$A)),
(OR8 (RLDICR DWBytes7654.DWord, 32, 31), DWBytes3210.DWord)>;
Index: stable/11/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.cpp (revision 350259)
@@ -1,231 +1,235 @@
//===-- PowerPCSubtarget.cpp - PPC Subtarget Information ------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the PPC specific subclass of TargetSubtargetInfo.
//
//===----------------------------------------------------------------------===//
#include "PPCSubtarget.h"
#include "PPC.h"
#include "PPCRegisterInfo.h"
#include "PPCTargetMachine.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"
#include <cstdlib>
using namespace llvm;
#define DEBUG_TYPE "ppc-subtarget"
#define GET_SUBTARGETINFO_TARGET_DESC
#define GET_SUBTARGETINFO_CTOR
#include "PPCGenSubtargetInfo.inc"
static cl::opt<bool> UseSubRegLiveness("ppc-track-subreg-liveness",
cl::desc("Enable subregister liveness tracking for PPC"), cl::Hidden);
static cl::opt<bool> QPXStackUnaligned("qpx-stack-unaligned",
cl::desc("Even when QPX is enabled the stack is not 32-byte aligned"),
cl::Hidden);
PPCSubtarget &PPCSubtarget::initializeSubtargetDependencies(StringRef CPU,
StringRef FS) {
initializeEnvironment();
initSubtargetFeatures(CPU, FS);
return *this;
}
PPCSubtarget::PPCSubtarget(const Triple &TT, const std::string &CPU,
const std::string &FS, const PPCTargetMachine &TM)
: PPCGenSubtargetInfo(TT, CPU, FS), TargetTriple(TT),
IsPPC64(TargetTriple.getArch() == Triple::ppc64 ||
TargetTriple.getArch() == Triple::ppc64le),
TM(TM), FrameLowering(initializeSubtargetDependencies(CPU, FS)),
InstrInfo(*this), TLInfo(TM, *this) {}
void PPCSubtarget::initializeEnvironment() {
StackAlignment = 16;
DarwinDirective = PPC::DIR_NONE;
HasMFOCRF = false;
Has64BitSupport = false;
Use64BitRegs = false;
UseCRBits = false;
HasHardFloat = false;
HasAltivec = false;
HasSPE = false;
HasFPU = false;
HasQPX = false;
HasVSX = false;
HasP8Vector = false;
HasP8Altivec = false;
HasP8Crypto = false;
HasP9Vector = false;
HasP9Altivec = false;
HasFCPSGN = false;
HasFSQRT = false;
HasFRE = false;
HasFRES = false;
HasFRSQRTE = false;
HasFRSQRTES = false;
HasRecipPrec = false;
HasSTFIWX = false;
HasLFIWAX = false;
HasFPRND = false;
HasFPCVT = false;
HasISEL = false;
HasBPERMD = false;
HasExtDiv = false;
HasCMPB = false;
HasLDBRX = false;
IsBookE = false;
HasOnlyMSYNC = false;
IsPPC4xx = false;
IsPPC6xx = false;
IsE500 = false;
FeatureMFTB = false;
DeprecatedDST = false;
HasLazyResolverStubs = false;
HasICBT = false;
HasInvariantFunctionDescriptors = false;
HasPartwordAtomics = false;
HasDirectMove = false;
IsQPXStackUnaligned = false;
HasHTM = false;
HasFusion = false;
HasFloat128 = false;
IsISA3_0 = false;
UseLongCalls = false;
SecurePlt = false;
HasPOPCNTD = POPCNTD_Unavailable;
}
void PPCSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
// Determine default and user specified characteristics
std::string CPUName = CPU;
if (CPUName.empty() || CPU == "generic") {
// If cross-compiling with -march=ppc64le without -mcpu
if (TargetTriple.getArch() == Triple::ppc64le)
CPUName = "ppc64le";
else
CPUName = "generic";
}
// Initialize scheduling itinerary for the specified CPU.
InstrItins = getInstrItineraryForCPU(CPUName);
// Parse features string.
ParseSubtargetFeatures(CPUName, FS);
// If the user requested use of 64-bit regs, but the cpu selected doesn't
// support it, ignore.
if (IsPPC64 && has64BitSupport())
Use64BitRegs = true;
// Set up darwin-specific properties.
if (isDarwin())
HasLazyResolverStubs = true;
+ if ((TargetTriple.isOSFreeBSD() && TargetTriple.getOSMajorVersion() >= 13)
+ || TargetTriple.isOSNetBSD() || TargetTriple.isOSOpenBSD())
+ SecurePlt = true;
+
if (HasSPE && IsPPC64)
report_fatal_error( "SPE is only supported for 32-bit targets.\n", false);
if (HasSPE && (HasAltivec || HasQPX || HasVSX || HasFPU))
report_fatal_error(
"SPE and traditional floating point cannot both be enabled.\n", false);
// If not SPE, set standard FPU
if (!HasSPE)
HasFPU = true;
// QPX requires a 32-byte aligned stack. Note that we need to do this if
// we're compiling for a BG/Q system regardless of whether or not QPX
// is enabled because external functions will assume this alignment.
IsQPXStackUnaligned = QPXStackUnaligned;
StackAlignment = getPlatformStackAlignment();
// Determine endianness.
// FIXME: Part of the TargetMachine.
IsLittleEndian = (TargetTriple.getArch() == Triple::ppc64le);
}
/// Return true if accesses to the specified global have to go through a dyld
/// lazy resolution stub. This means that an extra load is required to get the
/// address of the global.
bool PPCSubtarget::hasLazyResolverStub(const GlobalValue *GV) const {
if (!HasLazyResolverStubs)
return false;
if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
return true;
// 32 bit macho has no relocation for a-b if a is undefined, even if b is in
// the section that is being relocated. This means we have to use o load even
// for GVs that are known to be local to the dso.
if (GV->isDeclarationForLinker() || GV->hasCommonLinkage())
return true;
return false;
}
bool PPCSubtarget::enableMachineScheduler() const {
return true;
}
// This overrides the PostRAScheduler bit in the SchedModel for each CPU.
bool PPCSubtarget::enablePostRAScheduler() const { return true; }
PPCGenSubtargetInfo::AntiDepBreakMode PPCSubtarget::getAntiDepBreakMode() const {
return TargetSubtargetInfo::ANTIDEP_ALL;
}
void PPCSubtarget::getCriticalPathRCs(RegClassVector &CriticalPathRCs) const {
CriticalPathRCs.clear();
CriticalPathRCs.push_back(isPPC64() ?
&PPC::G8RCRegClass : &PPC::GPRCRegClass);
}
void PPCSubtarget::overrideSchedPolicy(MachineSchedPolicy &Policy,
unsigned NumRegionInstrs) const {
// The GenericScheduler that we use defaults to scheduling bottom up only.
// We want to schedule from both the top and the bottom and so we set
// OnlyBottomUp to false.
// We want to do bi-directional scheduling since it provides a more balanced
// schedule leading to better performance.
Policy.OnlyBottomUp = false;
// Spilling is generally expensive on all PPC cores, so always enable
// register-pressure tracking.
Policy.ShouldTrackPressure = true;
}
bool PPCSubtarget::useAA() const {
return true;
}
bool PPCSubtarget::enableSubRegLiveness() const {
return UseSubRegLiveness;
}
unsigned char
PPCSubtarget::classifyGlobalReference(const GlobalValue *GV) const {
// Note that currently we don't generate non-pic references.
// If a caller wants that, this will have to be updated.
// Large code model always uses the TOC even for local symbols.
if (TM.getCodeModel() == CodeModel::Large)
return PPCII::MO_PIC_FLAG | PPCII::MO_NLP_FLAG;
if (TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
return PPCII::MO_PIC_FLAG;
return PPCII::MO_PIC_FLAG | PPCII::MO_NLP_FLAG;
}
bool PPCSubtarget::isELFv2ABI() const { return TM.isELFv2ABI(); }
bool PPCSubtarget::isPPC64() const { return TM.isPPC64(); }
Index: stable/11/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp (revision 350259)
@@ -1,241 +1,241 @@
//===-- SparcRegisterInfo.cpp - SPARC Register Information ----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the SPARC implementation of the TargetRegisterInfo class.
//
//===----------------------------------------------------------------------===//
#include "SparcRegisterInfo.h"
#include "Sparc.h"
#include "SparcMachineFunctionInfo.h"
#include "SparcSubtarget.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
#define GET_REGINFO_TARGET_DESC
#include "SparcGenRegisterInfo.inc"
static cl::opt<bool>
ReserveAppRegisters("sparc-reserve-app-registers", cl::Hidden, cl::init(false),
cl::desc("Reserve application registers (%g2-%g4)"));
SparcRegisterInfo::SparcRegisterInfo() : SparcGenRegisterInfo(SP::O7) {}
const MCPhysReg*
SparcRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
return CSR_SaveList;
}
const uint32_t *
SparcRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const {
return CSR_RegMask;
}
const uint32_t*
SparcRegisterInfo::getRTCallPreservedMask(CallingConv::ID CC) const {
return RTCSR_RegMask;
}
BitVector SparcRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
BitVector Reserved(getNumRegs());
const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
// FIXME: G1 reserved for now for large imm generation by frame code.
Reserved.set(SP::G1);
// G1-G4 can be used in applications.
if (ReserveAppRegisters) {
Reserved.set(SP::G2);
Reserved.set(SP::G3);
Reserved.set(SP::G4);
}
// G5 is not reserved in 64 bit mode.
if (!Subtarget.is64Bit())
Reserved.set(SP::G5);
Reserved.set(SP::O6);
Reserved.set(SP::I6);
Reserved.set(SP::I7);
Reserved.set(SP::G0);
Reserved.set(SP::G6);
Reserved.set(SP::G7);
// Also reserve the register pair aliases covering the above
// registers, with the same conditions.
Reserved.set(SP::G0_G1);
if (ReserveAppRegisters)
Reserved.set(SP::G2_G3);
if (ReserveAppRegisters || !Subtarget.is64Bit())
Reserved.set(SP::G4_G5);
Reserved.set(SP::O6_O7);
Reserved.set(SP::I6_I7);
Reserved.set(SP::G6_G7);
// Unaliased double registers are not available in non-V9 targets.
if (!Subtarget.isV9()) {
for (unsigned n = 0; n != 16; ++n) {
for (MCRegAliasIterator AI(SP::D16 + n, this, true); AI.isValid(); ++AI)
Reserved.set(*AI);
}
}
// Reserve ASR1-ASR31
for (unsigned n = 0; n < 31; n++)
Reserved.set(SP::ASR1 + n);
return Reserved;
}
const TargetRegisterClass*
SparcRegisterInfo::getPointerRegClass(const MachineFunction &MF,
unsigned Kind) const {
const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
return Subtarget.is64Bit() ? &SP::I64RegsRegClass : &SP::IntRegsRegClass;
}
static void replaceFI(MachineFunction &MF, MachineBasicBlock::iterator II,
MachineInstr &MI, const DebugLoc &dl,
unsigned FIOperandNum, int Offset, unsigned FramePtr) {
// Replace frame index with a frame pointer reference.
if (Offset >= -4096 && Offset <= 4095) {
// If the offset is small enough to fit in the immediate field, directly
// encode it.
MI.getOperand(FIOperandNum).ChangeToRegister(FramePtr, false);
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
return;
}
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
// FIXME: it would be better to scavenge a register here instead of
// reserving G1 all of the time.
if (Offset >= 0) {
// Emit nonnegaive immediates with sethi + or.
// sethi %hi(Offset), %g1
// add %g1, %fp, %g1
// Insert G1+%lo(offset) into the user.
BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1)
.addImm(HI22(Offset));
// Emit G1 = G1 + I6
BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1)
.addReg(FramePtr);
// Insert: G1+%lo(offset) into the user.
MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false);
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(LO10(Offset));
return;
}
// Emit Negative numbers with sethi + xor
// sethi %hix(Offset), %g1
// xor %g1, %lox(offset), %g1
// add %g1, %fp, %g1
// Insert: G1 + 0 into the user.
BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1)
.addImm(HIX22(Offset));
BuildMI(*MI.getParent(), II, dl, TII.get(SP::XORri), SP::G1)
.addReg(SP::G1).addImm(LOX10(Offset));
BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1)
.addReg(FramePtr);
// Insert: G1+%lo(offset) into the user.
MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false);
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(0);
}
void
SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, unsigned FIOperandNum,
RegScavenger *RS) const {
assert(SPAdj == 0 && "Unexpected");
MachineInstr &MI = *II;
DebugLoc dl = MI.getDebugLoc();
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
MachineFunction &MF = *MI.getParent()->getParent();
const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
const SparcFrameLowering *TFI = getFrameLowering(MF);
unsigned FrameReg;
int Offset;
Offset = TFI->getFrameIndexReference(MF, FrameIndex, FrameReg);
Offset += MI.getOperand(FIOperandNum + 1).getImm();
if (!Subtarget.isV9() || !Subtarget.hasHardQuad()) {
if (MI.getOpcode() == SP::STQFri) {
const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
unsigned SrcReg = MI.getOperand(2).getReg();
unsigned SrcEvenReg = getSubReg(SrcReg, SP::sub_even64);
unsigned SrcOddReg = getSubReg(SrcReg, SP::sub_odd64);
MachineInstr *StMI =
BuildMI(*MI.getParent(), II, dl, TII.get(SP::STDFri))
.addReg(FrameReg).addImm(0).addReg(SrcEvenReg);
- replaceFI(MF, II, *StMI, dl, 0, Offset, FrameReg);
+ replaceFI(MF, *StMI, *StMI, dl, 0, Offset, FrameReg);
MI.setDesc(TII.get(SP::STDFri));
MI.getOperand(2).setReg(SrcOddReg);
Offset += 8;
} else if (MI.getOpcode() == SP::LDQFri) {
const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
unsigned DestReg = MI.getOperand(0).getReg();
unsigned DestEvenReg = getSubReg(DestReg, SP::sub_even64);
unsigned DestOddReg = getSubReg(DestReg, SP::sub_odd64);
MachineInstr *StMI =
BuildMI(*MI.getParent(), II, dl, TII.get(SP::LDDFri), DestEvenReg)
.addReg(FrameReg).addImm(0);
- replaceFI(MF, II, *StMI, dl, 1, Offset, FrameReg);
+ replaceFI(MF, *StMI, *StMI, dl, 1, Offset, FrameReg);
MI.setDesc(TII.get(SP::LDDFri));
MI.getOperand(0).setReg(DestOddReg);
Offset += 8;
}
}
replaceFI(MF, II, MI, dl, FIOperandNum, Offset, FrameReg);
}
unsigned SparcRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
return SP::I6;
}
// Sparc has no architectural need for stack realignment support,
// except that LLVM unfortunately currently implements overaligned
// stack objects by depending upon stack realignment support.
// If that ever changes, this can probably be deleted.
bool SparcRegisterInfo::canRealignStack(const MachineFunction &MF) const {
if (!TargetRegisterInfo::canRealignStack(MF))
return false;
// Sparc always has a fixed frame pointer register, so don't need to
// worry about needing to reserve it. [even if we don't have a frame
// pointer for our frame, it still cannot be used for other things,
// or register window traps will be SADNESS.]
// If there's a reserved call frame, we can use SP to access locals.
if (getFrameLowering(MF)->hasReservedCallFrame(MF))
return true;
// Otherwise, we'd need a base pointer, but those aren't implemented
// for SPARC at the moment.
return false;
}
Index: stable/11/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp (revision 350259)
@@ -1,1229 +1,1232 @@
//=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file implements the WebAssemblyTargetLowering class.
///
//===----------------------------------------------------------------------===//
#include "WebAssemblyISelLowering.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblySubtarget.h"
#include "WebAssemblyTargetMachine.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/WasmEHFuncInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetOptions.h"
using namespace llvm;
#define DEBUG_TYPE "wasm-lower"
WebAssemblyTargetLowering::WebAssemblyTargetLowering(
const TargetMachine &TM, const WebAssemblySubtarget &STI)
: TargetLowering(TM), Subtarget(&STI) {
auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
// Booleans always contain 0 or 1.
setBooleanContents(ZeroOrOneBooleanContent);
// Except in SIMD vectors
setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
// WebAssembly does not produce floating-point exceptions on normal floating
// point operations.
setHasFloatingPointExceptions(false);
// We don't know the microarchitecture here, so just reduce register pressure.
setSchedulingPreference(Sched::RegPressure);
// Tell ISel that we have a stack pointer.
setStackPointerRegisterToSaveRestore(
Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32);
// Set up the register classes.
addRegisterClass(MVT::i32, &WebAssembly::I32RegClass);
addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
if (Subtarget->hasSIMD128()) {
addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass);
addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass);
addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass);
addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass);
if (Subtarget->hasUnimplementedSIMD128()) {
addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
}
}
// Compute derived properties from the register classes.
computeRegisterProperties(Subtarget->getRegisterInfo());
setOperationAction(ISD::GlobalAddress, MVTPtr, Custom);
setOperationAction(ISD::ExternalSymbol, MVTPtr, Custom);
setOperationAction(ISD::JumpTable, MVTPtr, Custom);
setOperationAction(ISD::BlockAddress, MVTPtr, Custom);
setOperationAction(ISD::BRIND, MVT::Other, Custom);
// Take the default expansion for va_arg, va_copy, and va_end. There is no
// default action for va_start, so we do that custom.
setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction(ISD::VAARG, MVT::Other, Expand);
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
setOperationAction(ISD::VAEND, MVT::Other, Expand);
for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) {
// Don't expand the floating-point types to constant pools.
setOperationAction(ISD::ConstantFP, T, Legal);
// Expand floating-point comparisons.
for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE,
ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE})
setCondCodeAction(CC, T, Expand);
// Expand floating-point library function operators.
for (auto Op :
{ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA})
setOperationAction(Op, T, Expand);
// Note supported floating-point library function operators that otherwise
// default to expand.
for (auto Op :
{ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT, ISD::FRINT})
setOperationAction(Op, T, Legal);
// Support minimum and maximum, which otherwise default to expand.
setOperationAction(ISD::FMINIMUM, T, Legal);
setOperationAction(ISD::FMAXIMUM, T, Legal);
// WebAssembly currently has no builtin f16 support.
setOperationAction(ISD::FP16_TO_FP, T, Expand);
setOperationAction(ISD::FP_TO_FP16, T, Expand);
setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand);
setTruncStoreAction(T, MVT::f16, Expand);
}
// Support saturating add for i8x16 and i16x8
if (Subtarget->hasSIMD128())
for (auto T : {MVT::v16i8, MVT::v8i16})
for (auto Op : {ISD::SADDSAT, ISD::UADDSAT})
setOperationAction(Op, T, Legal);
// Expand unavailable integer operations.
for (auto Op :
{ISD::BSWAP, ISD::SMUL_LOHI, ISD::UMUL_LOHI, ISD::MULHS, ISD::MULHU,
ISD::SDIVREM, ISD::UDIVREM, ISD::SHL_PARTS, ISD::SRA_PARTS,
ISD::SRL_PARTS, ISD::ADDC, ISD::ADDE, ISD::SUBC, ISD::SUBE}) {
for (auto T : {MVT::i32, MVT::i64}) {
setOperationAction(Op, T, Expand);
}
if (Subtarget->hasSIMD128()) {
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32}) {
setOperationAction(Op, T, Expand);
}
if (Subtarget->hasUnimplementedSIMD128()) {
setOperationAction(Op, MVT::v2i64, Expand);
}
}
}
// There is no i64x2.mul instruction
setOperationAction(ISD::MUL, MVT::v2i64, Expand);
// We have custom shuffle lowering to expose the shuffle mask
if (Subtarget->hasSIMD128()) {
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32}) {
setOperationAction(ISD::VECTOR_SHUFFLE, T, Custom);
}
if (Subtarget->hasUnimplementedSIMD128()) {
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v2i64, Custom);
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v2f64, Custom);
}
}
// Custom lowering since wasm shifts must have a scalar shift amount
if (Subtarget->hasSIMD128()) {
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL})
setOperationAction(Op, T, Custom);
if (Subtarget->hasUnimplementedSIMD128())
for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL})
setOperationAction(Op, MVT::v2i64, Custom);
}
// There are no select instructions for vectors
if (Subtarget->hasSIMD128())
for (auto Op : {ISD::VSELECT, ISD::SELECT_CC, ISD::SELECT}) {
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32})
setOperationAction(Op, T, Expand);
if (Subtarget->hasUnimplementedSIMD128())
for (auto T : {MVT::v2i64, MVT::v2f64})
setOperationAction(Op, T, Expand);
}
// As a special case, these operators use the type to mean the type to
// sign-extend from.
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
if (!Subtarget->hasSignExt()) {
// Sign extends are legal only when extending a vector extract
auto Action = Subtarget->hasSIMD128() ? Custom : Expand;
for (auto T : {MVT::i8, MVT::i16, MVT::i32})
setOperationAction(ISD::SIGN_EXTEND_INREG, T, Action);
}
for (auto T : MVT::integer_vector_valuetypes())
setOperationAction(ISD::SIGN_EXTEND_INREG, T, Expand);
// Dynamic stack allocation: use the default expansion.
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
setOperationAction(ISD::FrameIndex, MVT::i32, Custom);
setOperationAction(ISD::CopyToReg, MVT::Other, Custom);
// Expand these forms; we pattern-match the forms that we can handle in isel.
for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
setOperationAction(Op, T, Expand);
// We have custom switch handling.
setOperationAction(ISD::BR_JT, MVT::Other, Custom);
// WebAssembly doesn't have:
// - Floating-point extending loads.
// - Floating-point truncating stores.
// - i1 extending loads.
// - extending/truncating SIMD loads/stores
setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
setTruncStoreAction(MVT::f64, MVT::f32, Expand);
for (auto T : MVT::integer_valuetypes())
for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
setLoadExtAction(Ext, T, MVT::i1, Promote);
if (Subtarget->hasSIMD128()) {
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32,
MVT::v2f64}) {
for (auto MemT : MVT::vector_valuetypes()) {
if (MVT(T) != MemT) {
setTruncStoreAction(T, MemT, Expand);
for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
setLoadExtAction(Ext, T, MemT, Expand);
}
}
}
}
// Expand additional SIMD ops that V8 hasn't implemented yet
if (Subtarget->hasSIMD128() && !Subtarget->hasUnimplementedSIMD128()) {
setOperationAction(ISD::FSQRT, MVT::v4f32, Expand);
setOperationAction(ISD::FDIV, MVT::v4f32, Expand);
}
// Custom lower lane accesses to expand out variable indices
if (Subtarget->hasSIMD128()) {
for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32}) {
setOperationAction(ISD::EXTRACT_VECTOR_ELT, T, Custom);
setOperationAction(ISD::INSERT_VECTOR_ELT, T, Custom);
}
if (Subtarget->hasUnimplementedSIMD128()) {
for (auto T : {MVT::v2i64, MVT::v2f64}) {
setOperationAction(ISD::EXTRACT_VECTOR_ELT, T, Custom);
setOperationAction(ISD::INSERT_VECTOR_ELT, T, Custom);
}
}
}
// Trap lowers to wasm unreachable
setOperationAction(ISD::TRAP, MVT::Other, Legal);
// Exception handling intrinsics
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
setMaxAtomicSizeInBitsSupported(64);
}
TargetLowering::AtomicExpansionKind
WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
// We have wasm instructions for these
switch (AI->getOperation()) {
case AtomicRMWInst::Add:
case AtomicRMWInst::Sub:
case AtomicRMWInst::And:
case AtomicRMWInst::Or:
case AtomicRMWInst::Xor:
case AtomicRMWInst::Xchg:
return AtomicExpansionKind::None;
default:
break;
}
return AtomicExpansionKind::CmpXChg;
}
FastISel *WebAssemblyTargetLowering::createFastISel(
FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
return WebAssembly::createFastISel(FuncInfo, LibInfo);
}
bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
const GlobalAddressSDNode * /*GA*/) const {
// All offsets can be folded.
return true;
}
MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
EVT VT) const {
unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1);
if (BitWidth > 1 && BitWidth < 8)
BitWidth = 8;
if (BitWidth > 64) {
// The shift will be lowered to a libcall, and compiler-rt libcalls expect
// the count to be an i32.
BitWidth = 32;
assert(BitWidth >= Log2_32_Ceil(VT.getSizeInBits()) &&
"32-bit shift counts ought to be enough for anyone");
}
MVT Result = MVT::getIntegerVT(BitWidth);
assert(Result != MVT::INVALID_SIMPLE_VALUE_TYPE &&
"Unable to represent scalar shift amount type");
return Result;
}
// Lower an fp-to-int conversion operator from the LLVM opcode, which has an
// undefined result on invalid/overflow, to the WebAssembly opcode, which
// traps on invalid/overflow.
static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL,
MachineBasicBlock *BB,
const TargetInstrInfo &TII,
bool IsUnsigned, bool Int64,
bool Float64, unsigned LoweredOpcode) {
MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
unsigned OutReg = MI.getOperand(0).getReg();
unsigned InReg = MI.getOperand(1).getReg();
unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32;
unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
unsigned Eqz = WebAssembly::EQZ_I32;
unsigned And = WebAssembly::AND_I32;
int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
int64_t Substitute = IsUnsigned ? 0 : Limit;
double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
auto &Context = BB->getParent()->getFunction().getContext();
Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context);
const BasicBlock *LLVM_BB = BB->getBasicBlock();
MachineFunction *F = BB->getParent();
MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVM_BB);
MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVM_BB);
MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVM_BB);
MachineFunction::iterator It = ++BB->getIterator();
F->insert(It, FalseMBB);
F->insert(It, TrueMBB);
F->insert(It, DoneMBB);
// Transfer the remainder of BB and its successor edges to DoneMBB.
DoneMBB->splice(DoneMBB->begin(), BB,
std::next(MachineBasicBlock::iterator(MI)), BB->end());
DoneMBB->transferSuccessorsAndUpdatePHIs(BB);
BB->addSuccessor(TrueMBB);
BB->addSuccessor(FalseMBB);
TrueMBB->addSuccessor(DoneMBB);
FalseMBB->addSuccessor(DoneMBB);
unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg;
Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
MI.eraseFromParent();
// For signed numbers, we can do a single comparison to determine whether
// fabs(x) is within range.
if (IsUnsigned) {
Tmp0 = InReg;
} else {
BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg);
}
BuildMI(BB, DL, TII.get(FConst), Tmp1)
.addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal)));
BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1);
// For unsigned numbers, we have to do a separate comparison with zero.
if (IsUnsigned) {
Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
unsigned SecondCmpReg =
MRI.createVirtualRegister(&WebAssembly::I32RegClass);
unsigned AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
BuildMI(BB, DL, TII.get(FConst), Tmp1)
.addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0)));
BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1);
BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg);
CmpReg = AndReg;
}
BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg);
// Create the CFG diamond to select between doing the conversion or using
// the substitute value.
BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg);
BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg);
BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute);
BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
.addReg(FalseReg)
.addMBB(FalseMBB)
.addReg(TrueReg)
.addMBB(TrueMBB);
return DoneMBB;
}
MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
MachineInstr &MI, MachineBasicBlock *BB) const {
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
DebugLoc DL = MI.getDebugLoc();
switch (MI.getOpcode()) {
default:
llvm_unreachable("Unexpected instr type to insert");
case WebAssembly::FP_TO_SINT_I32_F32:
return LowerFPToInt(MI, DL, BB, TII, false, false, false,
WebAssembly::I32_TRUNC_S_F32);
case WebAssembly::FP_TO_UINT_I32_F32:
return LowerFPToInt(MI, DL, BB, TII, true, false, false,
WebAssembly::I32_TRUNC_U_F32);
case WebAssembly::FP_TO_SINT_I64_F32:
return LowerFPToInt(MI, DL, BB, TII, false, true, false,
WebAssembly::I64_TRUNC_S_F32);
case WebAssembly::FP_TO_UINT_I64_F32:
return LowerFPToInt(MI, DL, BB, TII, true, true, false,
WebAssembly::I64_TRUNC_U_F32);
case WebAssembly::FP_TO_SINT_I32_F64:
return LowerFPToInt(MI, DL, BB, TII, false, false, true,
WebAssembly::I32_TRUNC_S_F64);
case WebAssembly::FP_TO_UINT_I32_F64:
return LowerFPToInt(MI, DL, BB, TII, true, false, true,
WebAssembly::I32_TRUNC_U_F64);
case WebAssembly::FP_TO_SINT_I64_F64:
return LowerFPToInt(MI, DL, BB, TII, false, true, true,
WebAssembly::I64_TRUNC_S_F64);
case WebAssembly::FP_TO_UINT_I64_F64:
return LowerFPToInt(MI, DL, BB, TII, true, true, true,
WebAssembly::I64_TRUNC_U_F64);
llvm_unreachable("Unexpected instruction to emit with custom inserter");
}
}
const char *
WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
case WebAssemblyISD::FIRST_NUMBER:
break;
#define HANDLE_NODETYPE(NODE) \
case WebAssemblyISD::NODE: \
return "WebAssemblyISD::" #NODE;
#include "WebAssemblyISD.def"
#undef HANDLE_NODETYPE
}
return nullptr;
}
std::pair<unsigned, const TargetRegisterClass *>
WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
// First, see if this is a constraint that directly corresponds to a
// WebAssembly register class.
if (Constraint.size() == 1) {
switch (Constraint[0]) {
case 'r':
assert(VT != MVT::iPTR && "Pointer MVT not expected here");
if (Subtarget->hasSIMD128() && VT.isVector()) {
if (VT.getSizeInBits() == 128)
return std::make_pair(0U, &WebAssembly::V128RegClass);
}
if (VT.isInteger() && !VT.isVector()) {
if (VT.getSizeInBits() <= 32)
return std::make_pair(0U, &WebAssembly::I32RegClass);
if (VT.getSizeInBits() <= 64)
return std::make_pair(0U, &WebAssembly::I64RegClass);
}
break;
default:
break;
}
}
return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
}
bool WebAssemblyTargetLowering::isCheapToSpeculateCttz() const {
// Assume ctz is a relatively cheap operation.
return true;
}
bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz() const {
// Assume clz is a relatively cheap operation.
return true;
}
bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL,
const AddrMode &AM,
Type *Ty, unsigned AS,
Instruction *I) const {
// WebAssembly offsets are added as unsigned without wrapping. The
// isLegalAddressingMode gives us no way to determine if wrapping could be
// happening, so we approximate this by accepting only non-negative offsets.
if (AM.BaseOffs < 0)
return false;
// WebAssembly has no scale register operands.
if (AM.Scale != 0)
return false;
// Everything else is legal.
return true;
}
bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses(
EVT /*VT*/, unsigned /*AddrSpace*/, unsigned /*Align*/, bool *Fast) const {
// WebAssembly supports unaligned accesses, though it should be declared
// with the p2align attribute on loads and stores which do so, and there
// may be a performance impact. We tell LLVM they're "fast" because
// for the kinds of things that LLVM uses this for (merging adjacent stores
// of constants, etc.), WebAssembly implementations will either want the
// unaligned access or they'll split anyway.
if (Fast)
*Fast = true;
return true;
}
bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT,
AttributeList Attr) const {
// The current thinking is that wasm engines will perform this optimization,
// so we can save on code size.
return true;
}
EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL,
LLVMContext &C,
EVT VT) const {
if (VT.isVector())
return VT.changeVectorElementTypeToInteger();
return TargetLowering::getSetCCResultType(DL, C, VT);
}
bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
const CallInst &I,
MachineFunction &MF,
unsigned Intrinsic) const {
switch (Intrinsic) {
case Intrinsic::wasm_atomic_notify:
Info.opc = ISD::INTRINSIC_W_CHAIN;
Info.memVT = MVT::i32;
Info.ptrVal = I.getArgOperand(0);
Info.offset = 0;
Info.align = 4;
// atomic.notify instruction does not really load the memory specified with
// this argument, but MachineMemOperand should either be load or store, so
// we set this to a load.
// FIXME Volatile isn't really correct, but currently all LLVM atomic
// instructions are treated as volatiles in the backend, so we should be
// consistent. The same applies for wasm_atomic_wait intrinsics too.
Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
return true;
case Intrinsic::wasm_atomic_wait_i32:
Info.opc = ISD::INTRINSIC_W_CHAIN;
Info.memVT = MVT::i32;
Info.ptrVal = I.getArgOperand(0);
Info.offset = 0;
Info.align = 4;
Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
return true;
case Intrinsic::wasm_atomic_wait_i64:
Info.opc = ISD::INTRINSIC_W_CHAIN;
Info.memVT = MVT::i64;
Info.ptrVal = I.getArgOperand(0);
Info.offset = 0;
Info.align = 8;
Info.flags = MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad;
return true;
default:
return false;
}
}
//===----------------------------------------------------------------------===//
// WebAssembly Lowering private implementation.
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Lowering Code
//===----------------------------------------------------------------------===//
static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *msg) {
MachineFunction &MF = DAG.getMachineFunction();
DAG.getContext()->diagnose(
DiagnosticInfoUnsupported(MF.getFunction(), msg, DL.getDebugLoc()));
}
// Test whether the given calling convention is supported.
static bool CallingConvSupported(CallingConv::ID CallConv) {
// We currently support the language-independent target-independent
// conventions. We don't yet have a way to annotate calls with properties like
// "cold", and we don't have any call-clobbered registers, so these are mostly
// all handled the same.
return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
CallConv == CallingConv::Cold ||
CallConv == CallingConv::PreserveMost ||
CallConv == CallingConv::PreserveAll ||
CallConv == CallingConv::CXX_FAST_TLS;
}
SDValue
WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const {
SelectionDAG &DAG = CLI.DAG;
SDLoc DL = CLI.DL;
SDValue Chain = CLI.Chain;
SDValue Callee = CLI.Callee;
MachineFunction &MF = DAG.getMachineFunction();
auto Layout = MF.getDataLayout();
CallingConv::ID CallConv = CLI.CallConv;
if (!CallingConvSupported(CallConv))
fail(DL, DAG,
"WebAssembly doesn't support language-specific or target-specific "
"calling conventions yet");
if (CLI.IsPatchPoint)
fail(DL, DAG, "WebAssembly doesn't support patch point yet");
// WebAssembly doesn't currently support explicit tail calls. If they are
// required, fail. Otherwise, just disable them.
if ((CallConv == CallingConv::Fast && CLI.IsTailCall &&
MF.getTarget().Options.GuaranteedTailCallOpt) ||
(CLI.CS && CLI.CS.isMustTailCall()))
fail(DL, DAG, "WebAssembly doesn't support tail call yet");
CLI.IsTailCall = false;
SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
if (Ins.size() > 1)
fail(DL, DAG, "WebAssembly doesn't support more than 1 returned value yet");
SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
unsigned NumFixedArgs = 0;
for (unsigned i = 0; i < Outs.size(); ++i) {
const ISD::OutputArg &Out = Outs[i];
SDValue &OutVal = OutVals[i];
if (Out.Flags.isNest())
fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
if (Out.Flags.isInAlloca())
fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
if (Out.Flags.isInConsecutiveRegs())
fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
if (Out.Flags.isInConsecutiveRegsLast())
fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) {
auto &MFI = MF.getFrameInfo();
int FI = MFI.CreateStackObject(Out.Flags.getByValSize(),
Out.Flags.getByValAlign(),
/*isSS=*/false);
SDValue SizeNode =
DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
Chain = DAG.getMemcpy(
Chain, DL, FINode, OutVal, SizeNode, Out.Flags.getByValAlign(),
/*isVolatile*/ false, /*AlwaysInline=*/false,
/*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo());
OutVal = FINode;
}
// Count the number of fixed args *after* legalization.
NumFixedArgs += Out.IsFixed;
}
bool IsVarArg = CLI.IsVarArg;
auto PtrVT = getPointerTy(Layout);
// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
if (IsVarArg) {
// Outgoing non-fixed arguments are placed in a buffer. First
// compute their offsets and the total amount of buffer space needed.
- for (SDValue Arg :
- make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
+ for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) {
+ const ISD::OutputArg &Out = Outs[I];
+ SDValue &Arg = OutVals[I];
EVT VT = Arg.getValueType();
assert(VT != MVT::iPTR && "Legalized args should be concrete");
Type *Ty = VT.getTypeForEVT(*DAG.getContext());
+ unsigned Align = std::max(Out.Flags.getOrigAlign(),
+ Layout.getABITypeAlignment(Ty));
unsigned Offset = CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty),
- Layout.getABITypeAlignment(Ty));
+ Align);
CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
Offset, VT.getSimpleVT(),
CCValAssign::Full));
}
}
unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
SDValue FINode;
if (IsVarArg && NumBytes) {
// For non-fixed arguments, next emit stores to store the argument values
// to the stack buffer at the offsets computed above.
int FI = MF.getFrameInfo().CreateStackObject(NumBytes,
Layout.getStackAlignment(),
/*isSS=*/false);
unsigned ValNo = 0;
SmallVector<SDValue, 8> Chains;
for (SDValue Arg :
make_range(OutVals.begin() + NumFixedArgs, OutVals.end())) {
assert(ArgLocs[ValNo].getValNo() == ValNo &&
"ArgLocs should remain in order and only hold varargs args");
unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode,
DAG.getConstant(Offset, DL, PtrVT));
Chains.push_back(
DAG.getStore(Chain, DL, Arg, Add,
MachinePointerInfo::getFixedStack(MF, FI, Offset), 0));
}
if (!Chains.empty())
Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
} else if (IsVarArg) {
FINode = DAG.getIntPtrConstant(0, DL);
}
// Compute the operands for the CALLn node.
SmallVector<SDValue, 16> Ops;
Ops.push_back(Chain);
Ops.push_back(Callee);
// Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
// isn't reliable.
Ops.append(OutVals.begin(),
IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
// Add a pointer to the vararg buffer.
if (IsVarArg)
Ops.push_back(FINode);
SmallVector<EVT, 8> InTys;
for (const auto &In : Ins) {
assert(!In.Flags.isByVal() && "byval is not valid for return values");
assert(!In.Flags.isNest() && "nest is not valid for return values");
if (In.Flags.isInAlloca())
fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values");
if (In.Flags.isInConsecutiveRegs())
fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values");
if (In.Flags.isInConsecutiveRegsLast())
fail(DL, DAG,
"WebAssembly hasn't implemented cons regs last return values");
// Ignore In.getOrigAlign() because all our arguments are passed in
// registers.
InTys.push_back(In.VT);
}
InTys.push_back(MVT::Other);
SDVTList InTyList = DAG.getVTList(InTys);
SDValue Res =
DAG.getNode(Ins.empty() ? WebAssemblyISD::CALL0 : WebAssemblyISD::CALL1,
DL, InTyList, Ops);
if (Ins.empty()) {
Chain = Res;
} else {
InVals.push_back(Res);
Chain = Res.getValue(1);
}
return Chain;
}
bool WebAssemblyTargetLowering::CanLowerReturn(
CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
const SmallVectorImpl<ISD::OutputArg> &Outs,
LLVMContext & /*Context*/) const {
// WebAssembly can't currently handle returning tuples.
return Outs.size() <= 1;
}
SDValue WebAssemblyTargetLowering::LowerReturn(
SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
SelectionDAG &DAG) const {
assert(Outs.size() <= 1 && "WebAssembly can only return up to one value");
if (!CallingConvSupported(CallConv))
fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
SmallVector<SDValue, 4> RetOps(1, Chain);
RetOps.append(OutVals.begin(), OutVals.end());
Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
// Record the number and types of the return values.
for (const ISD::OutputArg &Out : Outs) {
assert(!Out.Flags.isByVal() && "byval is not valid for return values");
assert(!Out.Flags.isNest() && "nest is not valid for return values");
assert(Out.IsFixed && "non-fixed return value is not valid");
if (Out.Flags.isInAlloca())
fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
if (Out.Flags.isInConsecutiveRegs())
fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
if (Out.Flags.isInConsecutiveRegsLast())
fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
}
return Chain;
}
SDValue WebAssemblyTargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
if (!CallingConvSupported(CallConv))
fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
MachineFunction &MF = DAG.getMachineFunction();
auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
// Set up the incoming ARGUMENTS value, which serves to represent the liveness
// of the incoming values before they're represented by virtual registers.
MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
for (const ISD::InputArg &In : Ins) {
if (In.Flags.isInAlloca())
fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
if (In.Flags.isNest())
fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
if (In.Flags.isInConsecutiveRegs())
fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
if (In.Flags.isInConsecutiveRegsLast())
fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
// Ignore In.getOrigAlign() because all our arguments are passed in
// registers.
InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
DAG.getTargetConstant(InVals.size(),
DL, MVT::i32))
: DAG.getUNDEF(In.VT));
// Record the number and types of arguments.
MFI->addParam(In.VT);
}
// Varargs are copied into a buffer allocated by the caller, and a pointer to
// the buffer is passed as an argument.
if (IsVarArg) {
MVT PtrVT = getPointerTy(MF.getDataLayout());
unsigned VarargVreg =
MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrVT));
MFI->setVarargBufferVreg(VarargVreg);
Chain = DAG.getCopyToReg(
Chain, DL, VarargVreg,
DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT,
DAG.getTargetConstant(Ins.size(), DL, MVT::i32)));
MFI->addParam(PtrVT);
}
// Record the number and types of arguments and results.
SmallVector<MVT, 4> Params;
SmallVector<MVT, 4> Results;
ComputeSignatureVTs(MF.getFunction().getFunctionType(), MF.getFunction(),
DAG.getTarget(), Params, Results);
for (MVT VT : Results)
MFI->addResult(VT);
// TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
// the param logic here with ComputeSignatureVTs
assert(MFI->getParams().size() == Params.size() &&
std::equal(MFI->getParams().begin(), MFI->getParams().end(),
Params.begin()));
return Chain;
}
//===----------------------------------------------------------------------===//
// Custom lowering hooks.
//===----------------------------------------------------------------------===//
SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
switch (Op.getOpcode()) {
default:
llvm_unreachable("unimplemented operation lowering");
return SDValue();
case ISD::FrameIndex:
return LowerFrameIndex(Op, DAG);
case ISD::GlobalAddress:
return LowerGlobalAddress(Op, DAG);
case ISD::ExternalSymbol:
return LowerExternalSymbol(Op, DAG);
case ISD::JumpTable:
return LowerJumpTable(Op, DAG);
case ISD::BR_JT:
return LowerBR_JT(Op, DAG);
case ISD::VASTART:
return LowerVASTART(Op, DAG);
case ISD::BlockAddress:
case ISD::BRIND:
fail(DL, DAG, "WebAssembly hasn't implemented computed gotos");
return SDValue();
case ISD::RETURNADDR: // Probably nothing meaningful can be returned here.
fail(DL, DAG, "WebAssembly hasn't implemented __builtin_return_address");
return SDValue();
case ISD::FRAMEADDR:
return LowerFRAMEADDR(Op, DAG);
case ISD::CopyToReg:
return LowerCopyToReg(Op, DAG);
case ISD::INTRINSIC_WO_CHAIN:
return LowerINTRINSIC_WO_CHAIN(Op, DAG);
case ISD::EXTRACT_VECTOR_ELT:
case ISD::INSERT_VECTOR_ELT:
return LowerAccessVectorElement(Op, DAG);
case ISD::INTRINSIC_VOID:
return LowerINTRINSIC_VOID(Op, DAG);
case ISD::SIGN_EXTEND_INREG:
return LowerSIGN_EXTEND_INREG(Op, DAG);
case ISD::VECTOR_SHUFFLE:
return LowerVECTOR_SHUFFLE(Op, DAG);
case ISD::SHL:
case ISD::SRA:
case ISD::SRL:
return LowerShift(Op, DAG);
}
}
SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
SelectionDAG &DAG) const {
SDValue Src = Op.getOperand(2);
if (isa<FrameIndexSDNode>(Src.getNode())) {
// CopyToReg nodes don't support FrameIndex operands. Other targets select
// the FI to some LEA-like instruction, but since we don't have that, we
// need to insert some kind of instruction that can take an FI operand and
// produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
// local.copy between Op and its FI operand.
SDValue Chain = Op.getOperand(0);
SDLoc DL(Op);
unsigned Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
EVT VT = Src.getValueType();
SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32
: WebAssembly::COPY_I64,
DL, VT, Src),
0);
return Op.getNode()->getNumValues() == 1
? DAG.getCopyToReg(Chain, DL, Reg, Copy)
: DAG.getCopyToReg(Chain, DL, Reg, Copy,
Op.getNumOperands() == 4 ? Op.getOperand(3)
: SDValue());
}
return SDValue();
}
SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op,
SelectionDAG &DAG) const {
int FI = cast<FrameIndexSDNode>(Op)->getIndex();
return DAG.getTargetFrameIndex(FI, Op.getValueType());
}
SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
SelectionDAG &DAG) const {
// Non-zero depths are not supported by WebAssembly currently. Use the
// legalizer's default expansion, which is to return 0 (what this function is
// documented to do).
if (Op.getConstantOperandVal(0) > 0)
return SDValue();
DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true);
EVT VT = Op.getValueType();
unsigned FP =
Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT);
}
SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
const auto *GA = cast<GlobalAddressSDNode>(Op);
EVT VT = Op.getValueType();
assert(GA->getTargetFlags() == 0 &&
"Unexpected target flags on generic GlobalAddressSDNode");
if (GA->getAddressSpace() != 0)
fail(DL, DAG, "WebAssembly only expects the 0 address space");
return DAG.getNode(
WebAssemblyISD::Wrapper, DL, VT,
DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset()));
}
SDValue
WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
const auto *ES = cast<ExternalSymbolSDNode>(Op);
EVT VT = Op.getValueType();
assert(ES->getTargetFlags() == 0 &&
"Unexpected target flags on generic ExternalSymbolSDNode");
// Set the TargetFlags to 0x1 which indicates that this is a "function"
// symbol rather than a data symbol. We do this unconditionally even though
// we don't know anything about the symbol other than its name, because all
// external symbols used in target-independent SelectionDAG code are for
// functions.
return DAG.getNode(
WebAssemblyISD::Wrapper, DL, VT,
DAG.getTargetExternalSymbol(ES->getSymbol(), VT,
WebAssemblyII::MO_SYMBOL_FUNCTION));
}
SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
SelectionDAG &DAG) const {
// There's no need for a Wrapper node because we always incorporate a jump
// table operand into a BR_TABLE instruction, rather than ever
// materializing it in a register.
const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
JT->getTargetFlags());
}
SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
SDValue Chain = Op.getOperand(0);
const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
SDValue Index = Op.getOperand(2);
assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
SmallVector<SDValue, 8> Ops;
Ops.push_back(Chain);
Ops.push_back(Index);
MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
// Add an operand for each case.
for (auto MBB : MBBs)
Ops.push_back(DAG.getBasicBlock(MBB));
// TODO: For now, we just pick something arbitrary for a default case for now.
// We really want to sniff out the guard and put in the real default case (and
// delete the guard).
Ops.push_back(DAG.getBasicBlock(MBBs[0]));
return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops);
}
SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>();
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL,
MFI->getVarargBufferVreg(), PtrVT);
return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1),
MachinePointerInfo(SV), 0);
}
SDValue
WebAssemblyTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
SelectionDAG &DAG) const {
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
SDLoc DL(Op);
switch (IntNo) {
default:
return {}; // Don't custom lower most intrinsics.
case Intrinsic::wasm_lsda: {
MachineFunction &MF = DAG.getMachineFunction();
EVT VT = Op.getValueType();
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
auto &Context = MF.getMMI().getContext();
MCSymbol *S = Context.getOrCreateSymbol(Twine("GCC_except_table") +
Twine(MF.getFunctionNumber()));
return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
DAG.getMCSymbol(S, PtrVT));
}
}
}
SDValue
WebAssemblyTargetLowering::LowerINTRINSIC_VOID(SDValue Op,
SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
SDLoc DL(Op);
switch (IntNo) {
default:
return {}; // Don't custom lower most intrinsics.
case Intrinsic::wasm_throw: {
int Tag = cast<ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue();
switch (Tag) {
case CPP_EXCEPTION: {
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
const char *SymName = MF.createExternalSymbolName("__cpp_exception");
SDValue SymNode =
DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
DAG.getTargetExternalSymbol(
SymName, PtrVT, WebAssemblyII::MO_SYMBOL_EVENT));
return DAG.getNode(WebAssemblyISD::THROW, DL,
MVT::Other, // outchain type
{
Op.getOperand(0), // inchain
SymNode, // exception symbol
Op.getOperand(3) // thrown value
});
}
default:
llvm_unreachable("Invalid tag!");
}
break;
}
}
}
SDValue
WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
SelectionDAG &DAG) const {
// If sign extension operations are disabled, allow sext_inreg only if operand
// is a vector extract. SIMD does not depend on sign extension operations, but
// allowing sext_inreg in this context lets us have simple patterns to select
// extract_lane_s instructions. Expanding sext_inreg everywhere would be
// simpler in this file, but would necessitate large and brittle patterns to
// undo the expansion and select extract_lane_s instructions.
assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128());
if (Op.getOperand(0).getOpcode() == ISD::EXTRACT_VECTOR_ELT)
return Op;
// Otherwise expand
return SDValue();
}
SDValue
WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask();
MVT VecType = Op.getOperand(0).getSimpleValueType();
assert(VecType.is128BitVector() && "Unexpected shuffle vector type");
size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8;
// Space for two vector args and sixteen mask indices
SDValue Ops[18];
size_t OpIdx = 0;
Ops[OpIdx++] = Op.getOperand(0);
Ops[OpIdx++] = Op.getOperand(1);
// Expand mask indices to byte indices and materialize them as operands
for (size_t I = 0, Lanes = Mask.size(); I < Lanes; ++I) {
for (size_t J = 0; J < LaneBytes; ++J) {
// Lower undefs (represented by -1 in mask) to zero
uint64_t ByteIndex =
Mask[I] == -1 ? 0 : (uint64_t)Mask[I] * LaneBytes + J;
Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32);
}
}
return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
}
SDValue
WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op,
SelectionDAG &DAG) const {
// Allow constant lane indices, expand variable lane indices
SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode();
if (isa<ConstantSDNode>(IdxNode) || IdxNode->isUndef())
return Op;
else
// Perform default expansion
return SDValue();
}
static SDValue UnrollVectorShift(SDValue Op, SelectionDAG &DAG) {
EVT LaneT = Op.getSimpleValueType().getVectorElementType();
// 32-bit and 64-bit unrolled shifts will have proper semantics
if (LaneT.bitsGE(MVT::i32))
return DAG.UnrollVectorOp(Op.getNode());
// Otherwise mask the shift value to get proper semantics from 32-bit shift
SDLoc DL(Op);
SDValue ShiftVal = Op.getOperand(1);
uint64_t MaskVal = LaneT.getSizeInBits() - 1;
SDValue MaskedShiftVal = DAG.getNode(
ISD::AND, // mask opcode
DL, ShiftVal.getValueType(), // masked value type
ShiftVal, // original shift value operand
DAG.getConstant(MaskVal, DL, ShiftVal.getValueType()) // mask operand
);
return DAG.UnrollVectorOp(
DAG.getNode(Op.getOpcode(), // original shift opcode
DL, Op.getValueType(), // original return type
Op.getOperand(0), // original vector operand,
MaskedShiftVal // new masked shift value operand
)
.getNode());
}
SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
// Only manually lower vector shifts
assert(Op.getSimpleValueType().isVector());
// Expand all vector shifts until V8 fixes its implementation
// TODO: remove this once V8 is fixed
if (!Subtarget->hasUnimplementedSIMD128())
return UnrollVectorShift(Op, DAG);
// Unroll non-splat vector shifts
BuildVectorSDNode *ShiftVec;
SDValue SplatVal;
if (!(ShiftVec = dyn_cast<BuildVectorSDNode>(Op.getOperand(1).getNode())) ||
!(SplatVal = ShiftVec->getSplatValue()))
return UnrollVectorShift(Op, DAG);
// All splats except i64x2 const splats are handled by patterns
ConstantSDNode *SplatConst = dyn_cast<ConstantSDNode>(SplatVal);
if (!SplatConst || Op.getSimpleValueType() != MVT::v2i64)
return Op;
// i64x2 const splats are custom lowered to avoid unnecessary wraps
unsigned Opcode;
switch (Op.getOpcode()) {
case ISD::SHL:
Opcode = WebAssemblyISD::VEC_SHL;
break;
case ISD::SRA:
Opcode = WebAssemblyISD::VEC_SHR_S;
break;
case ISD::SRL:
Opcode = WebAssemblyISD::VEC_SHR_U;
break;
default:
llvm_unreachable("unexpected opcode");
}
APInt Shift = SplatConst->getAPIntValue().zextOrTrunc(32);
return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0),
DAG.getConstant(Shift, DL, MVT::i32));
}
//===----------------------------------------------------------------------===//
// WebAssembly Optimization Hooks
//===----------------------------------------------------------------------===//
Index: stable/11/contrib/llvm/lib/Target/X86/X86FastISel.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/X86/X86FastISel.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/X86/X86FastISel.cpp (revision 350259)
@@ -1,4038 +1,4038 @@
//===-- X86FastISel.cpp - X86 FastISel implementation ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the X86-specific support for the FastISel class. Much
// of the target-specific code is generated by tablegen in the file
// X86GenFastISel.inc, which is #included here.
//
//===----------------------------------------------------------------------===//
#include "X86.h"
#include "X86CallingConv.h"
#include "X86InstrBuilder.h"
#include "X86InstrInfo.h"
#include "X86MachineFunctionInfo.h"
#include "X86RegisterInfo.h"
#include "X86Subtarget.h"
#include "X86TargetMachine.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/CodeGen/FastISel.h"
#include "llvm/CodeGen/FunctionLoweringInfo.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Operator.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Target/TargetOptions.h"
using namespace llvm;
namespace {
class X86FastISel final : public FastISel {
/// Subtarget - Keep a pointer to the X86Subtarget around so that we can
/// make the right decision when generating code for different targets.
const X86Subtarget *Subtarget;
/// X86ScalarSSEf32, X86ScalarSSEf64 - Select between SSE or x87
/// floating point ops.
/// When SSE is available, use it for f32 operations.
/// When SSE2 is available, use it for f64 operations.
bool X86ScalarSSEf64;
bool X86ScalarSSEf32;
public:
explicit X86FastISel(FunctionLoweringInfo &funcInfo,
const TargetLibraryInfo *libInfo)
: FastISel(funcInfo, libInfo) {
Subtarget = &funcInfo.MF->getSubtarget<X86Subtarget>();
X86ScalarSSEf64 = Subtarget->hasSSE2();
X86ScalarSSEf32 = Subtarget->hasSSE1();
}
bool fastSelectInstruction(const Instruction *I) override;
/// The specified machine instr operand is a vreg, and that
/// vreg is being provided by the specified load instruction. If possible,
/// try to fold the load as an operand to the instruction, returning true if
/// possible.
bool tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
const LoadInst *LI) override;
bool fastLowerArguments() override;
bool fastLowerCall(CallLoweringInfo &CLI) override;
bool fastLowerIntrinsicCall(const IntrinsicInst *II) override;
#include "X86GenFastISel.inc"
private:
bool X86FastEmitCompare(const Value *LHS, const Value *RHS, EVT VT,
const DebugLoc &DL);
bool X86FastEmitLoad(EVT VT, X86AddressMode &AM, MachineMemOperand *MMO,
unsigned &ResultReg, unsigned Alignment = 1);
bool X86FastEmitStore(EVT VT, const Value *Val, X86AddressMode &AM,
MachineMemOperand *MMO = nullptr, bool Aligned = false);
bool X86FastEmitStore(EVT VT, unsigned ValReg, bool ValIsKill,
X86AddressMode &AM,
MachineMemOperand *MMO = nullptr, bool Aligned = false);
bool X86FastEmitExtend(ISD::NodeType Opc, EVT DstVT, unsigned Src, EVT SrcVT,
unsigned &ResultReg);
bool X86SelectAddress(const Value *V, X86AddressMode &AM);
bool X86SelectCallAddress(const Value *V, X86AddressMode &AM);
bool X86SelectLoad(const Instruction *I);
bool X86SelectStore(const Instruction *I);
bool X86SelectRet(const Instruction *I);
bool X86SelectCmp(const Instruction *I);
bool X86SelectZExt(const Instruction *I);
bool X86SelectSExt(const Instruction *I);
bool X86SelectBranch(const Instruction *I);
bool X86SelectShift(const Instruction *I);
bool X86SelectDivRem(const Instruction *I);
bool X86FastEmitCMoveSelect(MVT RetVT, const Instruction *I);
bool X86FastEmitSSESelect(MVT RetVT, const Instruction *I);
bool X86FastEmitPseudoSelect(MVT RetVT, const Instruction *I);
bool X86SelectSelect(const Instruction *I);
bool X86SelectTrunc(const Instruction *I);
bool X86SelectFPExtOrFPTrunc(const Instruction *I, unsigned Opc,
const TargetRegisterClass *RC);
bool X86SelectFPExt(const Instruction *I);
bool X86SelectFPTrunc(const Instruction *I);
bool X86SelectSIToFP(const Instruction *I);
bool X86SelectUIToFP(const Instruction *I);
bool X86SelectIntToFP(const Instruction *I, bool IsSigned);
const X86InstrInfo *getInstrInfo() const {
return Subtarget->getInstrInfo();
}
const X86TargetMachine *getTargetMachine() const {
return static_cast<const X86TargetMachine *>(&TM);
}
bool handleConstantAddresses(const Value *V, X86AddressMode &AM);
unsigned X86MaterializeInt(const ConstantInt *CI, MVT VT);
unsigned X86MaterializeFP(const ConstantFP *CFP, MVT VT);
unsigned X86MaterializeGV(const GlobalValue *GV, MVT VT);
unsigned fastMaterializeConstant(const Constant *C) override;
unsigned fastMaterializeAlloca(const AllocaInst *C) override;
unsigned fastMaterializeFloatZero(const ConstantFP *CF) override;
/// isScalarFPTypeInSSEReg - Return true if the specified scalar FP type is
/// computed in an SSE register, not on the X87 floating point stack.
bool isScalarFPTypeInSSEReg(EVT VT) const {
return (VT == MVT::f64 && X86ScalarSSEf64) || // f64 is when SSE2
(VT == MVT::f32 && X86ScalarSSEf32); // f32 is when SSE1
}
bool isTypeLegal(Type *Ty, MVT &VT, bool AllowI1 = false);
bool IsMemcpySmall(uint64_t Len);
bool TryEmitSmallMemcpy(X86AddressMode DestAM,
X86AddressMode SrcAM, uint64_t Len);
bool foldX86XALUIntrinsic(X86::CondCode &CC, const Instruction *I,
const Value *Cond);
const MachineInstrBuilder &addFullAddress(const MachineInstrBuilder &MIB,
X86AddressMode &AM);
unsigned fastEmitInst_rrrr(unsigned MachineInstOpcode,
const TargetRegisterClass *RC, unsigned Op0,
bool Op0IsKill, unsigned Op1, bool Op1IsKill,
unsigned Op2, bool Op2IsKill, unsigned Op3,
bool Op3IsKill);
};
} // end anonymous namespace.
static std::pair<unsigned, bool>
getX86SSEConditionCode(CmpInst::Predicate Predicate) {
unsigned CC;
bool NeedSwap = false;
// SSE Condition code mapping:
// 0 - EQ
// 1 - LT
// 2 - LE
// 3 - UNORD
// 4 - NEQ
// 5 - NLT
// 6 - NLE
// 7 - ORD
switch (Predicate) {
default: llvm_unreachable("Unexpected predicate");
case CmpInst::FCMP_OEQ: CC = 0; break;
case CmpInst::FCMP_OGT: NeedSwap = true; LLVM_FALLTHROUGH;
case CmpInst::FCMP_OLT: CC = 1; break;
case CmpInst::FCMP_OGE: NeedSwap = true; LLVM_FALLTHROUGH;
case CmpInst::FCMP_OLE: CC = 2; break;
case CmpInst::FCMP_UNO: CC = 3; break;
case CmpInst::FCMP_UNE: CC = 4; break;
case CmpInst::FCMP_ULE: NeedSwap = true; LLVM_FALLTHROUGH;
case CmpInst::FCMP_UGE: CC = 5; break;
case CmpInst::FCMP_ULT: NeedSwap = true; LLVM_FALLTHROUGH;
case CmpInst::FCMP_UGT: CC = 6; break;
case CmpInst::FCMP_ORD: CC = 7; break;
case CmpInst::FCMP_UEQ: CC = 8; break;
case CmpInst::FCMP_ONE: CC = 12; break;
}
return std::make_pair(CC, NeedSwap);
}
/// Adds a complex addressing mode to the given machine instr builder.
/// Note, this will constrain the index register. If its not possible to
/// constrain the given index register, then a new one will be created. The
/// IndexReg field of the addressing mode will be updated to match in this case.
const MachineInstrBuilder &
X86FastISel::addFullAddress(const MachineInstrBuilder &MIB,
X86AddressMode &AM) {
// First constrain the index register. It needs to be a GR64_NOSP.
AM.IndexReg = constrainOperandRegClass(MIB->getDesc(), AM.IndexReg,
MIB->getNumOperands() +
X86::AddrIndexReg);
return ::addFullAddress(MIB, AM);
}
/// Check if it is possible to fold the condition from the XALU intrinsic
/// into the user. The condition code will only be updated on success.
bool X86FastISel::foldX86XALUIntrinsic(X86::CondCode &CC, const Instruction *I,
const Value *Cond) {
if (!isa<ExtractValueInst>(Cond))
return false;
const auto *EV = cast<ExtractValueInst>(Cond);
if (!isa<IntrinsicInst>(EV->getAggregateOperand()))
return false;
const auto *II = cast<IntrinsicInst>(EV->getAggregateOperand());
MVT RetVT;
const Function *Callee = II->getCalledFunction();
Type *RetTy =
cast<StructType>(Callee->getReturnType())->getTypeAtIndex(0U);
if (!isTypeLegal(RetTy, RetVT))
return false;
if (RetVT != MVT::i32 && RetVT != MVT::i64)
return false;
X86::CondCode TmpCC;
switch (II->getIntrinsicID()) {
default: return false;
case Intrinsic::sadd_with_overflow:
case Intrinsic::ssub_with_overflow:
case Intrinsic::smul_with_overflow:
case Intrinsic::umul_with_overflow: TmpCC = X86::COND_O; break;
case Intrinsic::uadd_with_overflow:
case Intrinsic::usub_with_overflow: TmpCC = X86::COND_B; break;
}
// Check if both instructions are in the same basic block.
if (II->getParent() != I->getParent())
return false;
// Make sure nothing is in the way
BasicBlock::const_iterator Start(I);
BasicBlock::const_iterator End(II);
for (auto Itr = std::prev(Start); Itr != End; --Itr) {
// We only expect extractvalue instructions between the intrinsic and the
// instruction to be selected.
if (!isa<ExtractValueInst>(Itr))
return false;
// Check that the extractvalue operand comes from the intrinsic.
const auto *EVI = cast<ExtractValueInst>(Itr);
if (EVI->getAggregateOperand() != II)
return false;
}
CC = TmpCC;
return true;
}
bool X86FastISel::isTypeLegal(Type *Ty, MVT &VT, bool AllowI1) {
EVT evt = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true);
if (evt == MVT::Other || !evt.isSimple())
// Unhandled type. Halt "fast" selection and bail.
return false;
VT = evt.getSimpleVT();
// For now, require SSE/SSE2 for performing floating-point operations,
// since x87 requires additional work.
if (VT == MVT::f64 && !X86ScalarSSEf64)
return false;
if (VT == MVT::f32 && !X86ScalarSSEf32)
return false;
// Similarly, no f80 support yet.
if (VT == MVT::f80)
return false;
// We only handle legal types. For example, on x86-32 the instruction
// selector contains all of the 64-bit instructions from x86-64,
// under the assumption that i64 won't be used if the target doesn't
// support it.
return (AllowI1 && VT == MVT::i1) || TLI.isTypeLegal(VT);
}
#include "X86GenCallingConv.inc"
/// X86FastEmitLoad - Emit a machine instruction to load a value of type VT.
/// The address is either pre-computed, i.e. Ptr, or a GlobalAddress, i.e. GV.
/// Return true and the result register by reference if it is possible.
bool X86FastISel::X86FastEmitLoad(EVT VT, X86AddressMode &AM,
MachineMemOperand *MMO, unsigned &ResultReg,
unsigned Alignment) {
bool HasSSE41 = Subtarget->hasSSE41();
bool HasAVX = Subtarget->hasAVX();
bool HasAVX2 = Subtarget->hasAVX2();
bool HasAVX512 = Subtarget->hasAVX512();
bool HasVLX = Subtarget->hasVLX();
bool IsNonTemporal = MMO && MMO->isNonTemporal();
// Get opcode and regclass of the output for the given load instruction.
unsigned Opc = 0;
const TargetRegisterClass *RC = nullptr;
switch (VT.getSimpleVT().SimpleTy) {
default: return false;
case MVT::i1:
case MVT::i8:
Opc = X86::MOV8rm;
RC = &X86::GR8RegClass;
break;
case MVT::i16:
Opc = X86::MOV16rm;
RC = &X86::GR16RegClass;
break;
case MVT::i32:
Opc = X86::MOV32rm;
RC = &X86::GR32RegClass;
break;
case MVT::i64:
// Must be in x86-64 mode.
Opc = X86::MOV64rm;
RC = &X86::GR64RegClass;
break;
case MVT::f32:
if (X86ScalarSSEf32) {
Opc = HasAVX512 ? X86::VMOVSSZrm : HasAVX ? X86::VMOVSSrm : X86::MOVSSrm;
RC = HasAVX512 ? &X86::FR32XRegClass : &X86::FR32RegClass;
} else {
Opc = X86::LD_Fp32m;
RC = &X86::RFP32RegClass;
}
break;
case MVT::f64:
if (X86ScalarSSEf64) {
Opc = HasAVX512 ? X86::VMOVSDZrm : HasAVX ? X86::VMOVSDrm : X86::MOVSDrm;
RC = HasAVX512 ? &X86::FR64XRegClass : &X86::FR64RegClass;
} else {
Opc = X86::LD_Fp64m;
RC = &X86::RFP64RegClass;
}
break;
case MVT::f80:
// No f80 support yet.
return false;
case MVT::v4f32:
if (IsNonTemporal && Alignment >= 16 && HasSSE41)
Opc = HasVLX ? X86::VMOVNTDQAZ128rm :
HasAVX ? X86::VMOVNTDQArm : X86::MOVNTDQArm;
else if (Alignment >= 16)
Opc = HasVLX ? X86::VMOVAPSZ128rm :
HasAVX ? X86::VMOVAPSrm : X86::MOVAPSrm;
else
Opc = HasVLX ? X86::VMOVUPSZ128rm :
HasAVX ? X86::VMOVUPSrm : X86::MOVUPSrm;
RC = HasVLX ? &X86::VR128XRegClass : &X86::VR128RegClass;
break;
case MVT::v2f64:
if (IsNonTemporal && Alignment >= 16 && HasSSE41)
Opc = HasVLX ? X86::VMOVNTDQAZ128rm :
HasAVX ? X86::VMOVNTDQArm : X86::MOVNTDQArm;
else if (Alignment >= 16)
Opc = HasVLX ? X86::VMOVAPDZ128rm :
HasAVX ? X86::VMOVAPDrm : X86::MOVAPDrm;
else
Opc = HasVLX ? X86::VMOVUPDZ128rm :
HasAVX ? X86::VMOVUPDrm : X86::MOVUPDrm;
RC = HasVLX ? &X86::VR128XRegClass : &X86::VR128RegClass;
break;
case MVT::v4i32:
case MVT::v2i64:
case MVT::v8i16:
case MVT::v16i8:
- if (IsNonTemporal && Alignment >= 16)
+ if (IsNonTemporal && Alignment >= 16 && HasSSE41)
Opc = HasVLX ? X86::VMOVNTDQAZ128rm :
HasAVX ? X86::VMOVNTDQArm : X86::MOVNTDQArm;
else if (Alignment >= 16)
Opc = HasVLX ? X86::VMOVDQA64Z128rm :
HasAVX ? X86::VMOVDQArm : X86::MOVDQArm;
else
Opc = HasVLX ? X86::VMOVDQU64Z128rm :
HasAVX ? X86::VMOVDQUrm : X86::MOVDQUrm;
RC = HasVLX ? &X86::VR128XRegClass : &X86::VR128RegClass;
break;
case MVT::v8f32:
assert(HasAVX);
if (IsNonTemporal && Alignment >= 32 && HasAVX2)
Opc = HasVLX ? X86::VMOVNTDQAZ256rm : X86::VMOVNTDQAYrm;
else if (IsNonTemporal && Alignment >= 16)
return false; // Force split for X86::VMOVNTDQArm
else if (Alignment >= 32)
Opc = HasVLX ? X86::VMOVAPSZ256rm : X86::VMOVAPSYrm;
else
Opc = HasVLX ? X86::VMOVUPSZ256rm : X86::VMOVUPSYrm;
RC = HasVLX ? &X86::VR256XRegClass : &X86::VR256RegClass;
break;
case MVT::v4f64:
assert(HasAVX);
if (IsNonTemporal && Alignment >= 32 && HasAVX2)
Opc = HasVLX ? X86::VMOVNTDQAZ256rm : X86::VMOVNTDQAYrm;
else if (IsNonTemporal && Alignment >= 16)
return false; // Force split for X86::VMOVNTDQArm
else if (Alignment >= 32)
Opc = HasVLX ? X86::VMOVAPDZ256rm : X86::VMOVAPDYrm;
else
Opc = HasVLX ? X86::VMOVUPDZ256rm : X86::VMOVUPDYrm;
RC = HasVLX ? &X86::VR256XRegClass : &X86::VR256RegClass;
break;
case MVT::v8i32:
case MVT::v4i64:
case MVT::v16i16:
case MVT::v32i8:
assert(HasAVX);
if (IsNonTemporal && Alignment >= 32 && HasAVX2)
Opc = HasVLX ? X86::VMOVNTDQAZ256rm : X86::VMOVNTDQAYrm;
else if (IsNonTemporal && Alignment >= 16)
return false; // Force split for X86::VMOVNTDQArm
else if (Alignment >= 32)
Opc = HasVLX ? X86::VMOVDQA64Z256rm : X86::VMOVDQAYrm;
else
Opc = HasVLX ? X86::VMOVDQU64Z256rm : X86::VMOVDQUYrm;
RC = HasVLX ? &X86::VR256XRegClass : &X86::VR256RegClass;
break;
case MVT::v16f32:
assert(HasAVX512);
if (IsNonTemporal && Alignment >= 64)
Opc = X86::VMOVNTDQAZrm;
else
Opc = (Alignment >= 64) ? X86::VMOVAPSZrm : X86::VMOVUPSZrm;
RC = &X86::VR512RegClass;
break;
case MVT::v8f64:
assert(HasAVX512);
if (IsNonTemporal && Alignment >= 64)
Opc = X86::VMOVNTDQAZrm;
else
Opc = (Alignment >= 64) ? X86::VMOVAPDZrm : X86::VMOVUPDZrm;
RC = &X86::VR512RegClass;
break;
case MVT::v8i64:
case MVT::v16i32:
case MVT::v32i16:
case MVT::v64i8:
assert(HasAVX512);
// Note: There are a lot more choices based on type with AVX-512, but
// there's really no advantage when the load isn't masked.
if (IsNonTemporal && Alignment >= 64)
Opc = X86::VMOVNTDQAZrm;
else
Opc = (Alignment >= 64) ? X86::VMOVDQA64Zrm : X86::VMOVDQU64Zrm;
RC = &X86::VR512RegClass;
break;
}
ResultReg = createResultReg(RC);
MachineInstrBuilder MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg);
addFullAddress(MIB, AM);
if (MMO)
MIB->addMemOperand(*FuncInfo.MF, MMO);
return true;
}
/// X86FastEmitStore - Emit a machine instruction to store a value Val of
/// type VT. The address is either pre-computed, consisted of a base ptr, Ptr
/// and a displacement offset, or a GlobalAddress,
/// i.e. V. Return true if it is possible.
bool X86FastISel::X86FastEmitStore(EVT VT, unsigned ValReg, bool ValIsKill,
X86AddressMode &AM,
MachineMemOperand *MMO, bool Aligned) {
bool HasSSE1 = Subtarget->hasSSE1();
bool HasSSE2 = Subtarget->hasSSE2();
bool HasSSE4A = Subtarget->hasSSE4A();
bool HasAVX = Subtarget->hasAVX();
bool HasAVX512 = Subtarget->hasAVX512();
bool HasVLX = Subtarget->hasVLX();
bool IsNonTemporal = MMO && MMO->isNonTemporal();
// Get opcode and regclass of the output for the given store instruction.
unsigned Opc = 0;
switch (VT.getSimpleVT().SimpleTy) {
case MVT::f80: // No f80 support yet.
default: return false;
case MVT::i1: {
// Mask out all but lowest bit.
unsigned AndResult = createResultReg(&X86::GR8RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(X86::AND8ri), AndResult)
.addReg(ValReg, getKillRegState(ValIsKill)).addImm(1);
ValReg = AndResult;
LLVM_FALLTHROUGH; // handle i1 as i8.
}
case MVT::i8: Opc = X86::MOV8mr; break;
case MVT::i16: Opc = X86::MOV16mr; break;
case MVT::i32:
Opc = (IsNonTemporal && HasSSE2) ? X86::MOVNTImr : X86::MOV32mr;
break;
case MVT::i64:
// Must be in x86-64 mode.
Opc = (IsNonTemporal && HasSSE2) ? X86::MOVNTI_64mr : X86::MOV64mr;
break;
case MVT::f32:
if (X86ScalarSSEf32) {
if (IsNonTemporal && HasSSE4A)
Opc = X86::MOVNTSS;
else
Opc = HasAVX512 ? X86::VMOVSSZmr :
HasAVX ? X86::VMOVSSmr : X86::MOVSSmr;
} else
Opc = X86::ST_Fp32m;
break;
case MVT::f64:
if (X86ScalarSSEf32) {
if (IsNonTemporal && HasSSE4A)
Opc = X86::MOVNTSD;
else
Opc = HasAVX512 ? X86::VMOVSDZmr :
HasAVX ? X86::VMOVSDmr : X86::MOVSDmr;
} else
Opc = X86::ST_Fp64m;
break;
case MVT::x86mmx:
Opc = (IsNonTemporal && HasSSE1) ? X86::MMX_MOVNTQmr : X86::MMX_MOVQ64mr;
break;
case MVT::v4f32:
if (Aligned) {
if (IsNonTemporal)
Opc = HasVLX ? X86::VMOVNTPSZ128mr :
HasAVX ? X86::VMOVNTPSmr : X86::MOVNTPSmr;
else
Opc = HasVLX ? X86::VMOVAPSZ128mr :
HasAVX ? X86::VMOVAPSmr : X86::MOVAPSmr;
} else
Opc = HasVLX ? X86::VMOVUPSZ128mr :
HasAVX ? X86::VMOVUPSmr : X86::MOVUPSmr;
break;
case MVT::v2f64:
if (Aligned) {
if (IsNonTemporal)
Opc = HasVLX ? X86::VMOVNTPDZ128mr :
HasAVX ? X86::VMOVNTPDmr : X86::MOVNTPDmr;
else
Opc = HasVLX ? X86::VMOVAPDZ128mr :
HasAVX ? X86::VMOVAPDmr : X86::MOVAPDmr;
} else
Opc = HasVLX ? X86::VMOVUPDZ128mr :
HasAVX ? X86::VMOVUPDmr : X86::MOVUPDmr;
break;
case MVT::v4i32:
case MVT::v2i64:
case MVT::v8i16:
case MVT::v16i8:
if (Aligned) {
if (IsNonTemporal)
Opc = HasVLX ? X86::VMOVNTDQZ128mr :
HasAVX ? X86::VMOVNTDQmr : X86::MOVNTDQmr;
else
Opc = HasVLX ? X86::VMOVDQA64Z128mr :
HasAVX ? X86::VMOVDQAmr : X86::MOVDQAmr;
} else
Opc = HasVLX ? X86::VMOVDQU64Z128mr :
HasAVX ? X86::VMOVDQUmr : X86::MOVDQUmr;
break;
case MVT::v8f32:
assert(HasAVX);
if (Aligned) {
if (IsNonTemporal)
Opc = HasVLX ? X86::VMOVNTPSZ256mr : X86::VMOVNTPSYmr;
else
Opc = HasVLX ? X86::VMOVAPSZ256mr : X86::VMOVAPSYmr;
} else
Opc = HasVLX ? X86::VMOVUPSZ256mr : X86::VMOVUPSYmr;
break;
case MVT::v4f64:
assert(HasAVX);
if (Aligned) {
if (IsNonTemporal)
Opc = HasVLX ? X86::VMOVNTPDZ256mr : X86::VMOVNTPDYmr;
else
Opc = HasVLX ? X86::VMOVAPDZ256mr : X86::VMOVAPDYmr;
} else
Opc = HasVLX ? X86::VMOVUPDZ256mr : X86::VMOVUPDYmr;
break;
case MVT::v8i32:
case MVT::v4i64:
case MVT::v16i16:
case MVT::v32i8:
assert(HasAVX);
if (Aligned) {
if (IsNonTemporal)
Opc = HasVLX ? X86::VMOVNTDQZ256mr : X86::VMOVNTDQYmr;
else
Opc = HasVLX ? X86::VMOVDQA64Z256mr : X86::VMOVDQAYmr;
} else
Opc = HasVLX ? X86::VMOVDQU64Z256mr : X86::VMOVDQUYmr;
break;
case MVT::v16f32:
assert(HasAVX512);
if (Aligned)
Opc = IsNonTemporal ? X86::VMOVNTPSZmr : X86::VMOVAPSZmr;
else
Opc = X86::VMOVUPSZmr;
break;
case MVT::v8f64:
assert(HasAVX512);
if (Aligned) {
Opc = IsNonTemporal ? X86::VMOVNTPDZmr : X86::VMOVAPDZmr;
} else
Opc = X86::VMOVUPDZmr;
break;
case MVT::v8i64:
case MVT::v16i32:
case MVT::v32i16:
case MVT::v64i8:
assert(HasAVX512);
// Note: There are a lot more choices based on type with AVX-512, but
// there's really no advantage when the store isn't masked.
if (Aligned)
Opc = IsNonTemporal ? X86::VMOVNTDQZmr : X86::VMOVDQA64Zmr;
else
Opc = X86::VMOVDQU64Zmr;
break;
}
const MCInstrDesc &Desc = TII.get(Opc);
// Some of the instructions in the previous switch use FR128 instead
// of FR32 for ValReg. Make sure the register we feed the instruction
// matches its register class constraints.
// Note: This is fine to do a copy from FR32 to FR128, this is the
// same registers behind the scene and actually why it did not trigger
// any bugs before.
ValReg = constrainOperandRegClass(Desc, ValReg, Desc.getNumOperands() - 1);
MachineInstrBuilder MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, Desc);
addFullAddress(MIB, AM).addReg(ValReg, getKillRegState(ValIsKill));
if (MMO)
MIB->addMemOperand(*FuncInfo.MF, MMO);
return true;
}
bool X86FastISel::X86FastEmitStore(EVT VT, const Value *Val,
X86AddressMode &AM,
MachineMemOperand *MMO, bool Aligned) {
// Handle 'null' like i32/i64 0.
if (isa<ConstantPointerNull>(Val))
Val = Constant::getNullValue(DL.getIntPtrType(Val->getContext()));
// If this is a store of a simple constant, fold the constant into the store.
if (const ConstantInt *CI = dyn_cast<ConstantInt>(Val)) {
unsigned Opc = 0;
bool Signed = true;
switch (VT.getSimpleVT().SimpleTy) {
default: break;
case MVT::i1:
Signed = false;
LLVM_FALLTHROUGH; // Handle as i8.
case MVT::i8: Opc = X86::MOV8mi; break;
case MVT::i16: Opc = X86::MOV16mi; break;
case MVT::i32: Opc = X86::MOV32mi; break;
case MVT::i64:
// Must be a 32-bit sign extended value.
if (isInt<32>(CI->getSExtValue()))
Opc = X86::MOV64mi32;
break;
}
if (Opc) {
MachineInstrBuilder MIB =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
addFullAddress(MIB, AM).addImm(Signed ? (uint64_t) CI->getSExtValue()
: CI->getZExtValue());
if (MMO)
MIB->addMemOperand(*FuncInfo.MF, MMO);
return true;
}
}
unsigned ValReg = getRegForValue(Val);
if (ValReg == 0)
return false;
bool ValKill = hasTrivialKill(Val);
return X86FastEmitStore(VT, ValReg, ValKill, AM, MMO, Aligned);
}
/// X86FastEmitExtend - Emit a machine instruction to extend a value Src of
/// type SrcVT to type DstVT using the specified extension opcode Opc (e.g.
/// ISD::SIGN_EXTEND).
bool X86FastISel::X86FastEmitExtend(ISD::NodeType Opc, EVT DstVT,
unsigned Src, EVT SrcVT,
unsigned &ResultReg) {
unsigned RR = fastEmit_r(SrcVT.getSimpleVT(), DstVT.getSimpleVT(), Opc,
Src, /*TODO: Kill=*/false);
if (RR == 0)
return false;
ResultReg = RR;
return true;
}
bool X86FastISel::handleConstantAddresses(const Value *V, X86AddressMode &AM) {
// Handle constant address.
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
// Can't handle alternate code models yet.
if (TM.getCodeModel() != CodeModel::Small)
return false;
// Can't handle TLS yet.
if (GV->isThreadLocal())
return false;
// Can't handle !absolute_symbol references yet.
if (GV->isAbsoluteSymbolRef())
return false;
// RIP-relative addresses can't have additional register operands, so if
// we've already folded stuff into the addressing mode, just force the
// global value into its own register, which we can use as the basereg.
if (!Subtarget->isPICStyleRIPRel() ||
(AM.Base.Reg == 0 && AM.IndexReg == 0)) {
// Okay, we've committed to selecting this global. Set up the address.
AM.GV = GV;
// Allow the subtarget to classify the global.
unsigned char GVFlags = Subtarget->classifyGlobalReference(GV);
// If this reference is relative to the pic base, set it now.
if (isGlobalRelativeToPICBase(GVFlags)) {
// FIXME: How do we know Base.Reg is free??
AM.Base.Reg = getInstrInfo()->getGlobalBaseReg(FuncInfo.MF);
}
// Unless the ABI requires an extra load, return a direct reference to
// the global.
if (!isGlobalStubReference(GVFlags)) {
if (Subtarget->isPICStyleRIPRel()) {
// Use rip-relative addressing if we can. Above we verified that the
// base and index registers are unused.
assert(AM.Base.Reg == 0 && AM.IndexReg == 0);
AM.Base.Reg = X86::RIP;
}
AM.GVOpFlags = GVFlags;
return true;
}
// Ok, we need to do a load from a stub. If we've already loaded from
// this stub, reuse the loaded pointer, otherwise emit the load now.
DenseMap<const Value *, unsigned>::iterator I = LocalValueMap.find(V);
unsigned LoadReg;
if (I != LocalValueMap.end() && I->second != 0) {
LoadReg = I->second;
} else {
// Issue load from stub.
unsigned Opc = 0;
const TargetRegisterClass *RC = nullptr;
X86AddressMode StubAM;
StubAM.Base.Reg = AM.Base.Reg;
StubAM.GV = GV;
StubAM.GVOpFlags = GVFlags;
// Prepare for inserting code in the local-value area.
SavePoint SaveInsertPt = enterLocalValueArea();
if (TLI.getPointerTy(DL) == MVT::i64) {
Opc = X86::MOV64rm;
RC = &X86::GR64RegClass;
if (Subtarget->isPICStyleRIPRel())
StubAM.Base.Reg = X86::RIP;
} else {
Opc = X86::MOV32rm;
RC = &X86::GR32RegClass;
}
LoadReg = createResultReg(RC);
MachineInstrBuilder LoadMI =
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), LoadReg);
addFullAddress(LoadMI, StubAM);
// Ok, back to normal mode.
leaveLocalValueArea(SaveInsertPt);
// Prevent loading GV stub multiple times in same MBB.
LocalValueMap[V] = LoadReg;
}
// Now construct the final address. Note that the Disp, Scale,
// and Index values may already be set here.
AM.Base.Reg = LoadReg;
AM.GV = nullptr;
return true;
}
}
// If all else fails, try to materialize the value in a register.
if (!AM.GV || !Subtarget->isPICStyleRIPRel()) {
if (AM.Base.Reg == 0) {
AM.Base.Reg = getRegForValue(V);
return AM.Base.Reg != 0;
}
if (AM.IndexReg == 0) {
assert(AM.Scale == 1 && "Scale with no index!");
AM.IndexReg = getRegForValue(V);
return AM.IndexReg != 0;
}
}
return false;
}
/// X86SelectAddress - Attempt to fill in an address from the given value.
///
bool X86FastISel::X86SelectAddress(const Value *V, X86AddressMode &AM) {
SmallVector<const Value *, 32> GEPs;
redo_gep:
const User *U = nullptr;
unsigned Opcode = Instruction::UserOp1;
if (const Instruction *I = dyn_cast<Instruction>(V)) {
// Don't walk into other basic blocks; it's possible we haven't
// visited them yet, so the instructions may not yet be assigned
// virtual registers.
if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(V)) ||
FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
Opcode = I->getOpcode();
U = I;
}
} else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(V)) {
Opcode = C->getOpcode();
U = C;
}
if (PointerType *Ty = dyn_cast<PointerType>(V->getType()))
if (Ty->getAddressSpace() > 255)
// Fast instruction selection doesn't support the special
// address spaces.
return false;
switch (Opcode) {
default: break;
case Instruction::BitCast:
// Look past bitcasts.
return X86SelectAddress(U->getOperand(0), AM);
case Instruction::IntToPtr:
// Look past no-op inttoptrs.
if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
TLI.getPointerTy(DL))
return X86SelectAddress(U->getOperand(0), AM);
break;
case Instruction::PtrToInt:
// Look past no-op ptrtoints.
if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
return X86SelectAddress(U->getOperand(0), AM);
break;
case Instruction::Alloca: {
// Do static allocas.
const AllocaInst *A = cast<AllocaInst>(V);
DenseMap<const AllocaInst *, int>::iterator SI =
FuncInfo.StaticAllocaMap.find(A);
if (SI != FuncInfo.StaticAllocaMap.end()) {
AM.BaseType = X86AddressMode::FrameIndexBase;
AM.Base.FrameIndex = SI->second;
return true;
}
break;
}
case Instruction::Add: {
// Adds of constants are common and easy enough.
if (const ConstantInt *CI = dyn_cast<ConstantInt>(U->getOperand(1))) {
uint64_t Disp = (int32_t)AM.Disp + (uint64_t)CI->getSExtValue();
// They have to fit in the 32-bit signed displacement field though.
if (isInt<32>(Disp)) {
AM.Disp = (uint32_t)Disp;
return X86SelectAddress(U->getOperand(0), AM);
}
}
break;
}
case Instruction::GetElementPtr: {
X86AddressMode SavedAM = AM;
// Pattern-match simple GEPs.
uint64_t Disp = (int32_t)AM.Disp;
unsigned IndexReg = AM.IndexReg;
unsigned Scale = AM.Scale;
gep_type_iterator GTI = gep_type_begin(U);
// Iterate through the indices, folding what we can. Constants can be
// folded, and one dynamic index can be handled, if the scale is supported.
for (User::const_op_iterator i = U->op_begin() + 1, e = U->op_end();
i != e; ++i, ++GTI) {
const Value *Op = *i;
if (StructType *STy = GTI.getStructTypeOrNull()) {
const StructLayout *SL = DL.getStructLayout(STy);
Disp += SL->getElementOffset(cast<ConstantInt>(Op)->getZExtValue());
continue;
}
// A array/variable index is always of the form i*S where S is the
// constant scale size. See if we can push the scale into immediates.
uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
for (;;) {
if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {
// Constant-offset addressing.
Disp += CI->getSExtValue() * S;
break;
}
if (canFoldAddIntoGEP(U, Op)) {
// A compatible add with a constant operand. Fold the constant.
ConstantInt *CI =
cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
Disp += CI->getSExtValue() * S;
// Iterate on the other operand.
Op = cast<AddOperator>(Op)->getOperand(0);
continue;
}
if (IndexReg == 0 &&
(!AM.GV || !Subtarget->isPICStyleRIPRel()) &&
(S == 1 || S == 2 || S == 4 || S == 8)) {
// Scaled-index addressing.
Scale = S;
IndexReg = getRegForGEPIndex(Op).first;
if (IndexReg == 0)
return false;
break;
}
// Unsupported.
goto unsupported_gep;
}
}
// Check for displacement overflow.
if (!isInt<32>(Disp))
break;
AM.IndexReg = IndexReg;
AM.Scale = Scale;
AM.Disp = (uint32_t)Disp;
GEPs.push_back(V);
if (const GetElementPtrInst *GEP =
dyn_cast<GetElementPtrInst>(U->getOperand(0))) {
// Ok, the GEP indices were covered by constant-offset and scaled-index
// addressing. Update the address state and move on to examining the base.
V = GEP;
goto redo_gep;
} else if (X86SelectAddress(U->getOperand(0), AM)) {
return true;
}
// If we couldn't merge the gep value into this addr mode, revert back to
// our address and just match the value instead of completely failing.
AM = SavedAM;
for (const Value *I : reverse(GEPs))
if (handleConstantAddresses(I, AM))
return true;
return false;
unsupported_gep:
// Ok, the GEP indices weren't all covered.
break;
}
}
return handleConstantAddresses(V, AM);
}
/// X86SelectCallAddress - Attempt to fill in an address from the given value.
///
bool X86FastISel::X86SelectCallAddress(const Value *V, X86AddressMode &AM) {
const User *U = nullptr;
unsigned Opcode = Instruction::UserOp1;
const Instruction *I = dyn_cast<Instruction>(V);
// Record if the value is defined in the same basic block.
//
// This information is crucial to know whether or not folding an
// operand is valid.
// Indeed, FastISel generates or reuses a virtual register for all
// operands of all instructions it selects. Obviously, the definition and
// its uses must use the same virtual register otherwise the produced
// code is incorrect.
// Before instruction selection, FunctionLoweringInfo::set sets the virtual
// registers for values that are alive across basic blocks. This ensures
// that the values are consistently set between across basic block, even
// if different instruction selection mechanisms are used (e.g., a mix of
// SDISel and FastISel).
// For values local to a basic block, the instruction selection process
// generates these virtual registers with whatever method is appropriate
// for its needs. In particular, FastISel and SDISel do not share the way
// local virtual registers are set.
// Therefore, this is impossible (or at least unsafe) to share values
// between basic blocks unless they use the same instruction selection
// method, which is not guarantee for X86.
// Moreover, things like hasOneUse could not be used accurately, if we
// allow to reference values across basic blocks whereas they are not
// alive across basic blocks initially.
bool InMBB = true;
if (I) {
Opcode = I->getOpcode();
U = I;
InMBB = I->getParent() == FuncInfo.MBB->getBasicBlock();
} else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(V)) {
Opcode = C->getOpcode();
U = C;
}
switch (Opcode) {
default: break;
case Instruction::BitCast:
// Look past bitcasts if its operand is in the same BB.
if (InMBB)
return X86SelectCallAddress(U->getOperand(0), AM);
break;
case Instruction::IntToPtr:
// Look past no-op inttoptrs if its operand is in the same BB.
if (InMBB &&
TLI.getValueType(DL, U->getOperand(0)->getType()) ==
TLI.getPointerTy(DL))
return X86SelectCallAddress(U->getOperand(0), AM);
break;
case Instruction::PtrToInt:
// Look past no-op ptrtoints if its operand is in the same BB.
if (InMBB && TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
return X86SelectCallAddress(U->getOperand(0), AM);
break;
}
// Handle constant address.
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
// Can't handle alternate code models yet.
if (TM.getCodeModel() != CodeModel::Small)
return false;
// RIP-relative addresses can't have additional register operands.
if (Subtarget->isPICStyleRIPRel() &&
(AM.Base.Reg != 0 || AM.IndexReg != 0))
return false;
// Can't handle TLS.
if (const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV))
if (GVar->isThreadLocal())
return false;
// Okay, we've committed to selecting this global. Set up the basic address.
AM.GV = GV;
// Return a direct reference to the global. Fastisel can handle calls to
// functions that require loads, such as dllimport and nonlazybind
// functions.
if (Subtarget->isPICStyleRIPRel()) {
// Use rip-relative addressing if we can. Above we verified that the
// base and index registers are unused.
assert(AM.Base.Reg == 0 && AM.IndexReg == 0);
AM.Base.Reg = X86::RIP;
} else {
AM.GVOpFlags = Subtarget->classifyLocalReference(nullptr);
}
return true;
}
// If all else fails, try to materialize the value in a register.
if (!AM.GV || !Subtarget->isPICStyleRIPRel()) {
if (AM.Base.Reg == 0) {
AM.Base.Reg = getRegForValue(V);
return AM.Base.Reg != 0;
}
if (AM.IndexReg == 0) {
assert(AM.Scale == 1 && "Scale with no index!");
AM.IndexReg = getRegForValue(V);
return AM.IndexReg != 0;
}
}
return false;
}
/// X86SelectStore - Select and emit code to implement store instructions.
bool X86FastISel::X86SelectStore(const Instruction *I) {
// Atomic stores need special handling.
const StoreInst *S = cast<StoreInst>(I);
if (S->isAtomic())
return false;
const Value *PtrV = I->getOperand(1);
if (TLI.supportSwiftError()) {
// Swifterror values can come from either a function parameter with
// swifterror attribute or an alloca with swifterror attribute.
if (const Argument *Arg = dyn_cast<Argument>(PtrV)) {
if (Arg->hasSwiftErrorAttr())
return false;
}
if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(PtrV)) {
if (Alloca->isSwiftError())
return false;
}
}
const Value *Val = S->getValueOperand();
const Value *Ptr = S->getPointerOperand();
MVT VT;
if (!isTypeLegal(Val->getType(), VT, /*AllowI1=*/true))
return false;
unsigned Alignment = S->getAlignment();
unsigned ABIAlignment = DL.getABITypeAlignment(Val->getType());
if (Alignment == 0) // Ensure that codegen never sees alignment 0
Alignment = ABIAlignment;
bool Aligned = Alignment >= ABIAlignment;
X86AddressMode AM;
if (!X86SelectAddress(Ptr, AM))
return false;
return X86FastEmitStore(VT, Val, AM, createMachineMemOperandFor(I), Aligned);
}
/// X86SelectRet - Select and emit code to implement ret instructions.
bool X86FastISel::X86SelectRet(const Instruction *I) {
const ReturnInst *Ret = cast<ReturnInst>(I);
const Function &F = *I->getParent()->getParent();
const X86MachineFunctionInfo *X86MFInfo =
FuncInfo.MF->getInfo<X86MachineFunctionInfo>();
if (!FuncInfo.CanLowerReturn)
return false;
if (TLI.supportSwiftError() &&
F.getAttributes().hasAttrSomewhere(Attribute::SwiftError))
return false;
if (TLI.supportSplitCSR(FuncInfo.MF))
return false;
CallingConv::ID CC = F.getCallingConv();
if (CC != CallingConv::C &&
CC != CallingConv::Fast &&
CC != CallingConv::X86_FastCall &&
CC != CallingConv::X86_StdCall &&
CC != CallingConv::X86_ThisCall &&
CC != CallingConv::X86_64_SysV &&
CC != CallingConv::Win64)
return false;
// Don't handle popping bytes if they don't fit the ret's immediate.
if (!isUInt<16>(X86MFInfo->getBytesToPopOnReturn()))
return false;
// fastcc with -tailcallopt is intended to provide a guaranteed
// tail call optimization. Fastisel doesn't know how to do that.
if (CC == CallingConv::Fast && TM.Options.GuaranteedTailCallOpt)
return false;
// Let SDISel handle vararg functions.
if (F.isVarArg())
return false;
// Build a list of return value registers.
SmallVector<unsigned, 4> RetRegs;
if (Ret->getNumOperands() > 0) {
SmallVector<ISD::OutputArg, 4> Outs;
GetReturnInfo(CC, F.getReturnType(), F.getAttributes(), Outs, TLI, DL);
// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ValLocs;
CCState CCInfo(CC, F.isVarArg(), *FuncInfo.MF, ValLocs, I->getContext());
CCInfo.AnalyzeReturn(Outs, RetCC_X86);
const Value *RV = Ret->getOperand(0);
unsigned Reg = getRegForValue(RV);
if (Reg == 0)
return false;
// Only handle a single return value for now.
if (ValLocs.size() != 1)
return false;
CCValAssign &VA = ValLocs[0];
// Don't bother handling odd stuff for now.
if (VA.getLocInfo() != CCValAssign::Full)
return false;
// Only handle register returns for now.
if (!VA.isRegLoc())
return false;
// The calling-convention tables for x87 returns don't tell
// the whole story.
if (VA.getLocReg() == X86::FP0 || VA.getLocReg() == X86::FP1)
return false;
unsigned SrcReg = Reg + VA.getValNo();
EVT SrcVT = TLI.getValueType(DL, RV->getType());
EVT DstVT = VA.getValVT();
// Special handling for extended integers.
if (SrcVT != DstVT) {
if (SrcVT != MVT::i1 && SrcVT != MVT::i8 && SrcVT != MVT::i16)
return false;
if (!Outs[0].Flags.isZExt() && !Outs[0].Flags.isSExt())
return false;
assert(DstVT == MVT::i32 && "X86 should always ext to i32");
if (SrcVT == MVT::i1) {
if (Outs[0].Flags.isSExt())
return false;
SrcReg = fastEmitZExtFromI1(MVT::i8, SrcReg, /*TODO: Kill=*/false);
SrcVT = MVT::i8;
}
unsigned Op = Outs[0].Flags.isZExt() ? ISD::ZERO_EXTEND :
ISD::SIGN_EXTEND;
SrcReg = fastEmit_r(SrcVT.getSimpleVT(), DstVT.getSimpleVT(), Op,
SrcReg, /*TODO: Kill=*/false);
}
// Make the copy.
unsigned DstReg = VA.getLocReg();
const TargetRegisterClass *SrcRC = MRI.getRegClass(SrcReg);
// Avoid a cross-class copy. This is very unlikely.
if (!SrcRC->contains(DstReg))
return false;
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), DstReg).addReg(SrcReg);
// Add register to return instruction.
RetRegs.push_back(VA.getLocReg());
}
// Swift calling convention does not require we copy the sret argument
// into %rax/%eax for the return, and SRetReturnReg is not set for Swift.
// All x86 ABIs require that for returning structs by value we copy
// the sret argument into %rax/%eax (depending on ABI) for the return.
// We saved the argument into a virtual register in the entry block,
// so now we copy the value out and into %rax/%eax.
if (F.hasStructRetAttr() && CC != CallingConv::Swift) {
unsigned Reg = X86MFInfo->getSRetReturnReg();
assert(Reg &&
"SRetReturnReg should have been set in LowerFormalArguments()!");
unsigned RetReg = Subtarget->isTarget64BitLP64() ? X86::RAX : X86::EAX;
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), RetReg).addReg(Reg);
RetRegs.push_back(RetReg);
}
// Now emit the RET.
MachineInstrBuilder MIB;
if (X86MFInfo->getBytesToPopOnReturn()) {
MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Subtarget->is64Bit() ? X86::RETIQ : X86::RETIL))
.addImm(X86MFInfo->getBytesToPopOnReturn());
} else {
MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Subtarget->is64Bit() ? X86::RETQ : X86::RETL));
}
for (unsigned i = 0, e = RetRegs.size(); i != e; ++i)
MIB.addReg(RetRegs[i], RegState::Implicit);
return true;
}
/// X86SelectLoad - Select and emit code to implement load instructions.
///
bool X86FastISel::X86SelectLoad(const Instruction *I) {
const LoadInst *LI = cast<LoadInst>(I);
// Atomic loads need special handling.
if (LI->isAtomic())
return false;
const Value *SV = I->getOperand(0);
if (TLI.supportSwiftError()) {
// Swifterror values can come from either a function parameter with
// swifterror attribute or an alloca with swifterror attribute.
if (const Argument *Arg = dyn_cast<Argument>(SV)) {
if (Arg->hasSwiftErrorAttr())
return false;
}
if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(SV)) {
if (Alloca->isSwiftError())
return false;
}
}
MVT VT;
if (!isTypeLegal(LI->getType(), VT, /*AllowI1=*/true))
return false;
const Value *Ptr = LI->getPointerOperand();
X86AddressMode AM;
if (!X86SelectAddress(Ptr, AM))
return false;
unsigned Alignment = LI->getAlignment();
unsigned ABIAlignment = DL.getABITypeAlignment(LI->getType());
if (Alignment == 0) // Ensure that codegen never sees alignment 0
Alignment = ABIAlignment;
unsigned ResultReg = 0;
if (!X86FastEmitLoad(VT, AM, createMachineMemOperandFor(LI), ResultReg,
Alignment))
return false;
updateValueMap(I, ResultReg);
return true;
}
static unsigned X86ChooseCmpOpcode(EVT VT, const X86Subtarget *Subtarget) {
bool HasAVX512 = Subtarget->hasAVX512();
bool HasAVX = Subtarget->hasAVX();
bool X86ScalarSSEf32 = Subtarget->hasSSE1();
bool X86ScalarSSEf64 = Subtarget->hasSSE2();
switch (VT.getSimpleVT().SimpleTy) {
default: return 0;
case MVT::i8: return X86::CMP8rr;
case MVT::i16: return X86::CMP16rr;
case MVT::i32: return X86::CMP32rr;
case MVT::i64: return X86::CMP64rr;
case MVT::f32:
return X86ScalarSSEf32
? (HasAVX512 ? X86::VUCOMISSZrr
: HasAVX ? X86::VUCOMISSrr : X86::UCOMISSrr)
: 0;
case MVT::f64:
return X86ScalarSSEf64
? (HasAVX512 ? X86::VUCOMISDZrr
: HasAVX ? X86::VUCOMISDrr : X86::UCOMISDrr)
: 0;
}
}
/// If we have a comparison with RHS as the RHS of the comparison, return an
/// opcode that works for the compare (e.g. CMP32ri) otherwise return 0.
static unsigned X86ChooseCmpImmediateOpcode(EVT VT, const ConstantInt *RHSC) {
int64_t Val = RHSC->getSExtValue();
switch (VT.getSimpleVT().SimpleTy) {
// Otherwise, we can't fold the immediate into this comparison.
default:
return 0;
case MVT::i8:
return X86::CMP8ri;
case MVT::i16:
if (isInt<8>(Val))
return X86::CMP16ri8;
return X86::CMP16ri;
case MVT::i32:
if (isInt<8>(Val))
return X86::CMP32ri8;
return X86::CMP32ri;
case MVT::i64:
if (isInt<8>(Val))
return X86::CMP64ri8;
// 64-bit comparisons are only valid if the immediate fits in a 32-bit sext
// field.
if (isInt<32>(Val))
return X86::CMP64ri32;
return 0;
}
}
bool X86FastISel::X86FastEmitCompare(const Value *Op0, const Value *Op1, EVT VT,
const DebugLoc &CurDbgLoc) {
unsigned Op0Reg = getRegForValue(Op0);
if (Op0Reg == 0) return false;
// Handle 'null' like i32/i64 0.
if (isa<ConstantPointerNull>(Op1))
Op1 = Constant::getNullValue(DL.getIntPtrType(Op0->getContext()));
// We have two options: compare with register or immediate. If the RHS of
// the compare is an immediate that we can fold into this compare, use
// CMPri, otherwise use CMPrr.
if (const ConstantInt *Op1C = dyn_cast<ConstantInt>(Op1)) {
if (unsigned CompareImmOpc = X86ChooseCmpImmediateOpcode(VT, Op1C)) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, CurDbgLoc, TII.get(CompareImmOpc))
.addReg(Op0Reg)
.addImm(Op1C->getSExtValue());
return true;
}
}
unsigned CompareOpc = X86ChooseCmpOpcode(VT, Subtarget);
if (CompareOpc == 0) return false;
unsigned Op1Reg = getRegForValue(Op1);
if (Op1Reg == 0) return false;
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, CurDbgLoc, TII.get(CompareOpc))
.addReg(Op0Reg)
.addReg(Op1Reg);
return true;
}
bool X86FastISel::X86SelectCmp(const Instruction *I) {
const CmpInst *CI = cast<CmpInst>(I);
MVT VT;
if (!isTypeLegal(I->getOperand(0)->getType(), VT))
return false;
// Try to optimize or fold the cmp.
CmpInst::Predicate Predicate = optimizeCmpPredicate(CI);
unsigned ResultReg = 0;
switch (Predicate) {
default: break;
case CmpInst::FCMP_FALSE: {
ResultReg = createResultReg(&X86::GR32RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::MOV32r0),
ResultReg);
ResultReg = fastEmitInst_extractsubreg(MVT::i8, ResultReg, /*Kill=*/true,
X86::sub_8bit);
if (!ResultReg)
return false;
break;
}
case CmpInst::FCMP_TRUE: {
ResultReg = createResultReg(&X86::GR8RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::MOV8ri),
ResultReg).addImm(1);
break;
}
}
if (ResultReg) {
updateValueMap(I, ResultReg);
return true;
}
const Value *LHS = CI->getOperand(0);
const Value *RHS = CI->getOperand(1);
// The optimizer might have replaced fcmp oeq %x, %x with fcmp ord %x, 0.0.
// We don't have to materialize a zero constant for this case and can just use
// %x again on the RHS.
if (Predicate == CmpInst::FCMP_ORD || Predicate == CmpInst::FCMP_UNO) {
const auto *RHSC = dyn_cast<ConstantFP>(RHS);
if (RHSC && RHSC->isNullValue())
RHS = LHS;
}
// FCMP_OEQ and FCMP_UNE cannot be checked with a single instruction.
static const uint16_t SETFOpcTable[2][3] = {
{ X86::SETEr, X86::SETNPr, X86::AND8rr },
{ X86::SETNEr, X86::SETPr, X86::OR8rr }
};
const uint16_t *SETFOpc = nullptr;
switch (Predicate) {
default: break;
case CmpInst::FCMP_OEQ: SETFOpc = &SETFOpcTable[0][0]; break;
case CmpInst::FCMP_UNE: SETFOpc = &SETFOpcTable[1][0]; break;
}
ResultReg = createResultReg(&X86::GR8RegClass);
if (SETFOpc) {
if (!X86FastEmitCompare(LHS, RHS, VT, I->getDebugLoc()))
return false;
unsigned FlagReg1 = createResultReg(&X86::GR8RegClass);
unsigned FlagReg2 = createResultReg(&X86::GR8RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(SETFOpc[0]),
FlagReg1);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(SETFOpc[1]),
FlagReg2);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(SETFOpc[2]),
ResultReg).addReg(FlagReg1).addReg(FlagReg2);
updateValueMap(I, ResultReg);
return true;
}
X86::CondCode CC;
bool SwapArgs;
std::tie(CC, SwapArgs) = X86::getX86ConditionCode(Predicate);
assert(CC <= X86::LAST_VALID_COND && "Unexpected condition code.");
unsigned Opc = X86::getSETFromCond(CC);
if (SwapArgs)
std::swap(LHS, RHS);
// Emit a compare of LHS/RHS.
if (!X86FastEmitCompare(LHS, RHS, VT, I->getDebugLoc()))
return false;
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg);
updateValueMap(I, ResultReg);
return true;
}
bool X86FastISel::X86SelectZExt(const Instruction *I) {
EVT DstVT = TLI.getValueType(DL, I->getType());
if (!TLI.isTypeLegal(DstVT))
return false;
unsigned ResultReg = getRegForValue(I->getOperand(0));
if (ResultReg == 0)
return false;
// Handle zero-extension from i1 to i8, which is common.
MVT SrcVT = TLI.getSimpleValueType(DL, I->getOperand(0)->getType());
if (SrcVT == MVT::i1) {
// Set the high bits to zero.
ResultReg = fastEmitZExtFromI1(MVT::i8, ResultReg, /*TODO: Kill=*/false);
SrcVT = MVT::i8;
if (ResultReg == 0)
return false;
}
if (DstVT == MVT::i64) {
// Handle extension to 64-bits via sub-register shenanigans.
unsigned MovInst;
switch (SrcVT.SimpleTy) {
case MVT::i8: MovInst = X86::MOVZX32rr8; break;
case MVT::i16: MovInst = X86::MOVZX32rr16; break;
case MVT::i32: MovInst = X86::MOV32rr; break;
default: llvm_unreachable("Unexpected zext to i64 source type");
}
unsigned Result32 = createResultReg(&X86::GR32RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(MovInst), Result32)
.addReg(ResultReg);
ResultReg = createResultReg(&X86::GR64RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(TargetOpcode::SUBREG_TO_REG),
ResultReg)
.addImm(0).addReg(Result32).addImm(X86::sub_32bit);
} else if (DstVT == MVT::i16) {
// i8->i16 doesn't exist in the autogenerated isel table. Need to zero
// extend to 32-bits and then extract down to 16-bits.
unsigned Result32 = createResultReg(&X86::GR32RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::MOVZX32rr8),
Result32).addReg(ResultReg);
ResultReg = fastEmitInst_extractsubreg(MVT::i16, Result32, /*Kill=*/true,
X86::sub_16bit);
} else if (DstVT != MVT::i8) {
ResultReg = fastEmit_r(MVT::i8, DstVT.getSimpleVT(), ISD::ZERO_EXTEND,
ResultReg, /*Kill=*/true);
if (ResultReg == 0)
return false;
}
updateValueMap(I, ResultReg);
return true;
}
bool X86FastISel::X86SelectSExt(const Instruction *I) {
EVT DstVT = TLI.getValueType(DL, I->getType());
if (!TLI.isTypeLegal(DstVT))
return false;
unsigned ResultReg = getRegForValue(I->getOperand(0));
if (ResultReg == 0)
return false;
// Handle sign-extension from i1 to i8.
MVT SrcVT = TLI.getSimpleValueType(DL, I->getOperand(0)->getType());
if (SrcVT == MVT::i1) {
// Set the high bits to zero.
unsigned ZExtReg = fastEmitZExtFromI1(MVT::i8, ResultReg,
/*TODO: Kill=*/false);
if (ZExtReg == 0)
return false;
// Negate the result to make an 8-bit sign extended value.
ResultReg = createResultReg(&X86::GR8RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::NEG8r),
ResultReg).addReg(ZExtReg);
SrcVT = MVT::i8;
}
if (DstVT == MVT::i16) {
// i8->i16 doesn't exist in the autogenerated isel table. Need to sign
// extend to 32-bits and then extract down to 16-bits.
unsigned Result32 = createResultReg(&X86::GR32RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::MOVSX32rr8),
Result32).addReg(ResultReg);
ResultReg = fastEmitInst_extractsubreg(MVT::i16, Result32, /*Kill=*/true,
X86::sub_16bit);
} else if (DstVT != MVT::i8) {
ResultReg = fastEmit_r(MVT::i8, DstVT.getSimpleVT(), ISD::SIGN_EXTEND,
ResultReg, /*Kill=*/true);
if (ResultReg == 0)
return false;
}
updateValueMap(I, ResultReg);
return true;
}
bool X86FastISel::X86SelectBranch(const Instruction *I) {
// Unconditional branches are selected by tablegen-generated code.
// Handle a conditional branch.
const BranchInst *BI = cast<BranchInst>(I);
MachineBasicBlock *TrueMBB = FuncInfo.MBBMap[BI->getSuccessor(0)];
MachineBasicBlock *FalseMBB = FuncInfo.MBBMap[BI->getSuccessor(1)];
// Fold the common case of a conditional branch with a comparison
// in the same block (values defined on other blocks may not have
// initialized registers).
X86::CondCode CC;
if (const CmpInst *CI = dyn_cast<CmpInst>(BI->getCondition())) {
if (CI->hasOneUse() && CI->getParent() == I->getParent()) {
EVT VT = TLI.getValueType(DL, CI->getOperand(0)->getType());
// Try to optimize or fold the cmp.
CmpInst::Predicate Predicate = optimizeCmpPredicate(CI);
switch (Predicate) {
default: break;
case CmpInst::FCMP_FALSE: fastEmitBranch(FalseMBB, DbgLoc); return true;
case CmpInst::FCMP_TRUE: fastEmitBranch(TrueMBB, DbgLoc); return true;
}
const Value *CmpLHS = CI->getOperand(0);
const Value *CmpRHS = CI->getOperand(1);
// The optimizer might have replaced fcmp oeq %x, %x with fcmp ord %x,
// 0.0.
// We don't have to materialize a zero constant for this case and can just
// use %x again on the RHS.
if (Predicate == CmpInst::FCMP_ORD || Predicate == CmpInst::FCMP_UNO) {
const auto *CmpRHSC = dyn_cast<ConstantFP>(CmpRHS);
if (CmpRHSC && CmpRHSC->isNullValue())
CmpRHS = CmpLHS;
}
// Try to take advantage of fallthrough opportunities.
if (FuncInfo.MBB->isLayoutSuccessor(TrueMBB)) {
std::swap(TrueMBB, FalseMBB);
Predicate = CmpInst::getInversePredicate(Predicate);
}
// FCMP_OEQ and FCMP_UNE cannot be expressed with a single flag/condition
// code check. Instead two branch instructions are required to check all
// the flags. First we change the predicate to a supported condition code,
// which will be the first branch. Later one we will emit the second
// branch.
bool NeedExtraBranch = false;
switch (Predicate) {
default: break;
case CmpInst::FCMP_OEQ:
std::swap(TrueMBB, FalseMBB);
LLVM_FALLTHROUGH;
case CmpInst::FCMP_UNE:
NeedExtraBranch = true;
Predicate = CmpInst::FCMP_ONE;
break;
}
bool SwapArgs;
unsigned BranchOpc;
std::tie(CC, SwapArgs) = X86::getX86ConditionCode(Predicate);
assert(CC <= X86::LAST_VALID_COND && "Unexpected condition code.");
BranchOpc = X86::GetCondBranchFromCond(CC);
if (SwapArgs)
std::swap(CmpLHS, CmpRHS);
// Emit a compare of the LHS and RHS, setting the flags.
if (!X86FastEmitCompare(CmpLHS, CmpRHS, VT, CI->getDebugLoc()))
return false;
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(BranchOpc))
.addMBB(TrueMBB);
// X86 requires a second branch to handle UNE (and OEQ, which is mapped
// to UNE above).
if (NeedExtraBranch) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::JP_1))
.addMBB(TrueMBB);
}
finishCondBranch(BI->getParent(), TrueMBB, FalseMBB);
return true;
}
} else if (TruncInst *TI = dyn_cast<TruncInst>(BI->getCondition())) {
// Handle things like "%cond = trunc i32 %X to i1 / br i1 %cond", which
// typically happen for _Bool and C++ bools.
MVT SourceVT;
if (TI->hasOneUse() && TI->getParent() == I->getParent() &&
isTypeLegal(TI->getOperand(0)->getType(), SourceVT)) {
unsigned TestOpc = 0;
switch (SourceVT.SimpleTy) {
default: break;
case MVT::i8: TestOpc = X86::TEST8ri; break;
case MVT::i16: TestOpc = X86::TEST16ri; break;
case MVT::i32: TestOpc = X86::TEST32ri; break;
case MVT::i64: TestOpc = X86::TEST64ri32; break;
}
if (TestOpc) {
unsigned OpReg = getRegForValue(TI->getOperand(0));
if (OpReg == 0) return false;
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(TestOpc))
.addReg(OpReg).addImm(1);
unsigned JmpOpc = X86::JNE_1;
if (FuncInfo.MBB->isLayoutSuccessor(TrueMBB)) {
std::swap(TrueMBB, FalseMBB);
JmpOpc = X86::JE_1;
}
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(JmpOpc))
.addMBB(TrueMBB);
finishCondBranch(BI->getParent(), TrueMBB, FalseMBB);
return true;
}
}
} else if (foldX86XALUIntrinsic(CC, BI, BI->getCondition())) {
// Fake request the condition, otherwise the intrinsic might be completely
// optimized away.
unsigned TmpReg = getRegForValue(BI->getCondition());
if (TmpReg == 0)
return false;
unsigned BranchOpc = X86::GetCondBranchFromCond(CC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(BranchOpc))
.addMBB(TrueMBB);
finishCondBranch(BI->getParent(), TrueMBB, FalseMBB);
return true;
}
// Otherwise do a clumsy setcc and re-test it.
// Note that i1 essentially gets ANY_EXTEND'ed to i8 where it isn't used
// in an explicit cast, so make sure to handle that correctly.
unsigned OpReg = getRegForValue(BI->getCondition());
if (OpReg == 0) return false;
// In case OpReg is a K register, COPY to a GPR
if (MRI.getRegClass(OpReg) == &X86::VK1RegClass) {
unsigned KOpReg = OpReg;
OpReg = createResultReg(&X86::GR32RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), OpReg)
.addReg(KOpReg);
OpReg = fastEmitInst_extractsubreg(MVT::i8, OpReg, /*Kill=*/true,
X86::sub_8bit);
}
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::TEST8ri))
.addReg(OpReg)
.addImm(1);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::JNE_1))
.addMBB(TrueMBB);
finishCondBranch(BI->getParent(), TrueMBB, FalseMBB);
return true;
}
bool X86FastISel::X86SelectShift(const Instruction *I) {
unsigned CReg = 0, OpReg = 0;
const TargetRegisterClass *RC = nullptr;
if (I->getType()->isIntegerTy(8)) {
CReg = X86::CL;
RC = &X86::GR8RegClass;
switch (I->getOpcode()) {
case Instruction::LShr: OpReg = X86::SHR8rCL; break;
case Instruction::AShr: OpReg = X86::SAR8rCL; break;
case Instruction::Shl: OpReg = X86::SHL8rCL; break;
default: return false;
}
} else if (I->getType()->isIntegerTy(16)) {
CReg = X86::CX;
RC = &X86::GR16RegClass;
switch (I->getOpcode()) {
default: llvm_unreachable("Unexpected shift opcode");
case Instruction::LShr: OpReg = X86::SHR16rCL; break;
case Instruction::AShr: OpReg = X86::SAR16rCL; break;
case Instruction::Shl: OpReg = X86::SHL16rCL; break;
}
} else if (I->getType()->isIntegerTy(32)) {
CReg = X86::ECX;
RC = &X86::GR32RegClass;
switch (I->getOpcode()) {
default: llvm_unreachable("Unexpected shift opcode");
case Instruction::LShr: OpReg = X86::SHR32rCL; break;
case Instruction::AShr: OpReg = X86::SAR32rCL; break;
case Instruction::Shl: OpReg = X86::SHL32rCL; break;
}
} else if (I->getType()->isIntegerTy(64)) {
CReg = X86::RCX;
RC = &X86::GR64RegClass;
switch (I->getOpcode()) {
default: llvm_unreachable("Unexpected shift opcode");
case Instruction::LShr: OpReg = X86::SHR64rCL; break;
case Instruction::AShr: OpReg = X86::SAR64rCL; break;
case Instruction::Shl: OpReg = X86::SHL64rCL; break;
}
} else {
return false;
}
MVT VT;
if (!isTypeLegal(I->getType(), VT))
return false;
unsigned Op0Reg = getRegForValue(I->getOperand(0));
if (Op0Reg == 0) return false;
unsigned Op1Reg = getRegForValue(I->getOperand(1));
if (Op1Reg == 0) return false;
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(TargetOpcode::COPY),
CReg).addReg(Op1Reg);
// The shift instruction uses X86::CL. If we defined a super-register
// of X86::CL, emit a subreg KILL to precisely describe what we're doing here.
if (CReg != X86::CL)
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::KILL), X86::CL)
.addReg(CReg, RegState::Kill);
unsigned ResultReg = createResultReg(RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(OpReg), ResultReg)
.addReg(Op0Reg);
updateValueMap(I, ResultReg);
return true;
}
bool X86FastISel::X86SelectDivRem(const Instruction *I) {
const static unsigned NumTypes = 4; // i8, i16, i32, i64
const static unsigned NumOps = 4; // SDiv, SRem, UDiv, URem
const static bool S = true; // IsSigned
const static bool U = false; // !IsSigned
const static unsigned Copy = TargetOpcode::COPY;
// For the X86 DIV/IDIV instruction, in most cases the dividend
// (numerator) must be in a specific register pair highreg:lowreg,
// producing the quotient in lowreg and the remainder in highreg.
// For most data types, to set up the instruction, the dividend is
// copied into lowreg, and lowreg is sign-extended or zero-extended
// into highreg. The exception is i8, where the dividend is defined
// as a single register rather than a register pair, and we
// therefore directly sign-extend or zero-extend the dividend into
// lowreg, instead of copying, and ignore the highreg.
const static struct DivRemEntry {
// The following portion depends only on the data type.
const TargetRegisterClass *RC;
unsigned LowInReg; // low part of the register pair
unsigned HighInReg; // high part of the register pair
// The following portion depends on both the data type and the operation.
struct DivRemResult {
unsigned OpDivRem; // The specific DIV/IDIV opcode to use.
unsigned OpSignExtend; // Opcode for sign-extending lowreg into
// highreg, or copying a zero into highreg.
unsigned OpCopy; // Opcode for copying dividend into lowreg, or
// zero/sign-extending into lowreg for i8.
unsigned DivRemResultReg; // Register containing the desired result.
bool IsOpSigned; // Whether to use signed or unsigned form.
} ResultTable[NumOps];
} OpTable[NumTypes] = {
{ &X86::GR8RegClass, X86::AX, 0, {
{ X86::IDIV8r, 0, X86::MOVSX16rr8, X86::AL, S }, // SDiv
{ X86::IDIV8r, 0, X86::MOVSX16rr8, X86::AH, S }, // SRem
{ X86::DIV8r, 0, X86::MOVZX16rr8, X86::AL, U }, // UDiv
{ X86::DIV8r, 0, X86::MOVZX16rr8, X86::AH, U }, // URem
}
}, // i8
{ &X86::GR16RegClass, X86::AX, X86::DX, {
{ X86::IDIV16r, X86::CWD, Copy, X86::AX, S }, // SDiv
{ X86::IDIV16r, X86::CWD, Copy, X86::DX, S }, // SRem
{ X86::DIV16r, X86::MOV32r0, Copy, X86::AX, U }, // UDiv
{ X86::DIV16r, X86::MOV32r0, Copy, X86::DX, U }, // URem
}
}, // i16
{ &X86::GR32RegClass, X86::EAX, X86::EDX, {
{ X86::IDIV32r, X86::CDQ, Copy, X86::EAX, S }, // SDiv
{ X86::IDIV32r, X86::CDQ, Copy, X86::EDX, S }, // SRem
{ X86::DIV32r, X86::MOV32r0, Copy, X86::EAX, U }, // UDiv
{ X86::DIV32r, X86::MOV32r0, Copy, X86::EDX, U }, // URem
}
}, // i32
{ &X86::GR64RegClass, X86::RAX, X86::RDX, {
{ X86::IDIV64r, X86::CQO, Copy, X86::RAX, S }, // SDiv
{ X86::IDIV64r, X86::CQO, Copy, X86::RDX, S }, // SRem
{ X86::DIV64r, X86::MOV32r0, Copy, X86::RAX, U }, // UDiv
{ X86::DIV64r, X86::MOV32r0, Copy, X86::RDX, U }, // URem
}
}, // i64
};
MVT VT;
if (!isTypeLegal(I->getType(), VT))
return false;
unsigned TypeIndex, OpIndex;
switch (VT.SimpleTy) {
default: return false;
case MVT::i8: TypeIndex = 0; break;
case MVT::i16: TypeIndex = 1; break;
case MVT::i32: TypeIndex = 2; break;
case MVT::i64: TypeIndex = 3;
if (!Subtarget->is64Bit())
return false;
break;
}
switch (I->getOpcode()) {
default: llvm_unreachable("Unexpected div/rem opcode");
case Instruction::SDiv: OpIndex = 0; break;
case Instruction::SRem: OpIndex = 1; break;
case Instruction::UDiv: OpIndex = 2; break;
case Instruction::URem: OpIndex = 3; break;
}
const DivRemEntry &TypeEntry = OpTable[TypeIndex];
const DivRemEntry::DivRemResult &OpEntry = TypeEntry.ResultTable[OpIndex];
unsigned Op0Reg = getRegForValue(I->getOperand(0));
if (Op0Reg == 0)
return false;
unsigned Op1Reg = getRegForValue(I->getOperand(1));
if (Op1Reg == 0)
return false;
// Move op0 into low-order input register.
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(OpEntry.OpCopy), TypeEntry.LowInReg).addReg(Op0Reg);
// Zero-extend or sign-extend into high-order input register.
if (OpEntry.OpSignExtend) {
if (OpEntry.IsOpSigned)
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(OpEntry.OpSignExtend));
else {
unsigned Zero32 = createResultReg(&X86::GR32RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(X86::MOV32r0), Zero32);
// Copy the zero into the appropriate sub/super/identical physical
// register. Unfortunately the operations needed are not uniform enough
// to fit neatly into the table above.
if (VT == MVT::i16) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Copy), TypeEntry.HighInReg)
.addReg(Zero32, 0, X86::sub_16bit);
} else if (VT == MVT::i32) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Copy), TypeEntry.HighInReg)
.addReg(Zero32);
} else if (VT == MVT::i64) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::SUBREG_TO_REG), TypeEntry.HighInReg)
.addImm(0).addReg(Zero32).addImm(X86::sub_32bit);
}
}
}
// Generate the DIV/IDIV instruction.
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(OpEntry.OpDivRem)).addReg(Op1Reg);
// For i8 remainder, we can't reference ah directly, as we'll end
// up with bogus copies like %r9b = COPY %ah. Reference ax
// instead to prevent ah references in a rex instruction.
//
// The current assumption of the fast register allocator is that isel
// won't generate explicit references to the GR8_NOREX registers. If
// the allocator and/or the backend get enhanced to be more robust in
// that regard, this can be, and should be, removed.
unsigned ResultReg = 0;
if ((I->getOpcode() == Instruction::SRem ||
I->getOpcode() == Instruction::URem) &&
OpEntry.DivRemResultReg == X86::AH && Subtarget->is64Bit()) {
unsigned SourceSuperReg = createResultReg(&X86::GR16RegClass);
unsigned ResultSuperReg = createResultReg(&X86::GR16RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Copy), SourceSuperReg).addReg(X86::AX);
// Shift AX right by 8 bits instead of using AH.
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::SHR16ri),
ResultSuperReg).addReg(SourceSuperReg).addImm(8);
// Now reference the 8-bit subreg of the result.
ResultReg = fastEmitInst_extractsubreg(MVT::i8, ResultSuperReg,
/*Kill=*/true, X86::sub_8bit);
}
// Copy the result out of the physreg if we haven't already.
if (!ResultReg) {
ResultReg = createResultReg(TypeEntry.RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Copy), ResultReg)
.addReg(OpEntry.DivRemResultReg);
}
updateValueMap(I, ResultReg);
return true;
}
/// Emit a conditional move instruction (if the are supported) to lower
/// the select.
bool X86FastISel::X86FastEmitCMoveSelect(MVT RetVT, const Instruction *I) {
// Check if the subtarget supports these instructions.
if (!Subtarget->hasCMov())
return false;
// FIXME: Add support for i8.
if (RetVT < MVT::i16 || RetVT > MVT::i64)
return false;
const Value *Cond = I->getOperand(0);
const TargetRegisterClass *RC = TLI.getRegClassFor(RetVT);
bool NeedTest = true;
X86::CondCode CC = X86::COND_NE;
// Optimize conditions coming from a compare if both instructions are in the
// same basic block (values defined in other basic blocks may not have
// initialized registers).
const auto *CI = dyn_cast<CmpInst>(Cond);
if (CI && (CI->getParent() == I->getParent())) {
CmpInst::Predicate Predicate = optimizeCmpPredicate(CI);
// FCMP_OEQ and FCMP_UNE cannot be checked with a single instruction.
static const uint16_t SETFOpcTable[2][3] = {
{ X86::SETNPr, X86::SETEr , X86::TEST8rr },
{ X86::SETPr, X86::SETNEr, X86::OR8rr }
};
const uint16_t *SETFOpc = nullptr;
switch (Predicate) {
default: break;
case CmpInst::FCMP_OEQ:
SETFOpc = &SETFOpcTable[0][0];
Predicate = CmpInst::ICMP_NE;
break;
case CmpInst::FCMP_UNE:
SETFOpc = &SETFOpcTable[1][0];
Predicate = CmpInst::ICMP_NE;
break;
}
bool NeedSwap;
std::tie(CC, NeedSwap) = X86::getX86ConditionCode(Predicate);
assert(CC <= X86::LAST_VALID_COND && "Unexpected condition code.");
const Value *CmpLHS = CI->getOperand(0);
const Value *CmpRHS = CI->getOperand(1);
if (NeedSwap)
std::swap(CmpLHS, CmpRHS);
EVT CmpVT = TLI.getValueType(DL, CmpLHS->getType());
// Emit a compare of the LHS and RHS, setting the flags.
if (!X86FastEmitCompare(CmpLHS, CmpRHS, CmpVT, CI->getDebugLoc()))
return false;
if (SETFOpc) {
unsigned FlagReg1 = createResultReg(&X86::GR8RegClass);
unsigned FlagReg2 = createResultReg(&X86::GR8RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(SETFOpc[0]),
FlagReg1);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(SETFOpc[1]),
FlagReg2);
auto const &II = TII.get(SETFOpc[2]);
if (II.getNumDefs()) {
unsigned TmpReg = createResultReg(&X86::GR8RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, TmpReg)
.addReg(FlagReg2).addReg(FlagReg1);
} else {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
.addReg(FlagReg2).addReg(FlagReg1);
}
}
NeedTest = false;
} else if (foldX86XALUIntrinsic(CC, I, Cond)) {
// Fake request the condition, otherwise the intrinsic might be completely
// optimized away.
unsigned TmpReg = getRegForValue(Cond);
if (TmpReg == 0)
return false;
NeedTest = false;
}
if (NeedTest) {
// Selects operate on i1, however, CondReg is 8 bits width and may contain
// garbage. Indeed, only the less significant bit is supposed to be
// accurate. If we read more than the lsb, we may see non-zero values
// whereas lsb is zero. Therefore, we have to truncate Op0Reg to i1 for
// the select. This is achieved by performing TEST against 1.
unsigned CondReg = getRegForValue(Cond);
if (CondReg == 0)
return false;
bool CondIsKill = hasTrivialKill(Cond);
// In case OpReg is a K register, COPY to a GPR
if (MRI.getRegClass(CondReg) == &X86::VK1RegClass) {
unsigned KCondReg = CondReg;
CondReg = createResultReg(&X86::GR32RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), CondReg)
.addReg(KCondReg, getKillRegState(CondIsKill));
CondReg = fastEmitInst_extractsubreg(MVT::i8, CondReg, /*Kill=*/true,
X86::sub_8bit);
}
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::TEST8ri))
.addReg(CondReg, getKillRegState(CondIsKill))
.addImm(1);
}
const Value *LHS = I->getOperand(1);
const Value *RHS = I->getOperand(2);
unsigned RHSReg = getRegForValue(RHS);
bool RHSIsKill = hasTrivialKill(RHS);
unsigned LHSReg = getRegForValue(LHS);
bool LHSIsKill = hasTrivialKill(LHS);
if (!LHSReg || !RHSReg)
return false;
const TargetRegisterInfo &TRI = *Subtarget->getRegisterInfo();
unsigned Opc = X86::getCMovFromCond(CC, TRI.getRegSizeInBits(*RC)/8);
unsigned ResultReg = fastEmitInst_rr(Opc, RC, RHSReg, RHSIsKill,
LHSReg, LHSIsKill);
updateValueMap(I, ResultReg);
return true;
}
/// Emit SSE or AVX instructions to lower the select.
///
/// Try to use SSE1/SSE2 instructions to simulate a select without branches.
/// This lowers fp selects into a CMP/AND/ANDN/OR sequence when the necessary
/// SSE instructions are available. If AVX is available, try to use a VBLENDV.
bool X86FastISel::X86FastEmitSSESelect(MVT RetVT, const Instruction *I) {
// Optimize conditions coming from a compare if both instructions are in the
// same basic block (values defined in other basic blocks may not have
// initialized registers).
const auto *CI = dyn_cast<FCmpInst>(I->getOperand(0));
if (!CI || (CI->getParent() != I->getParent()))
return false;
if (I->getType() != CI->getOperand(0)->getType() ||
!((Subtarget->hasSSE1() && RetVT == MVT::f32) ||
(Subtarget->hasSSE2() && RetVT == MVT::f64)))
return false;
const Value *CmpLHS = CI->getOperand(0);
const Value *CmpRHS = CI->getOperand(1);
CmpInst::Predicate Predicate = optimizeCmpPredicate(CI);
// The optimizer might have replaced fcmp oeq %x, %x with fcmp ord %x, 0.0.
// We don't have to materialize a zero constant for this case and can just use
// %x again on the RHS.
if (Predicate == CmpInst::FCMP_ORD || Predicate == CmpInst::FCMP_UNO) {
const auto *CmpRHSC = dyn_cast<ConstantFP>(CmpRHS);
if (CmpRHSC && CmpRHSC->isNullValue())
CmpRHS = CmpLHS;
}
unsigned CC;
bool NeedSwap;
std::tie(CC, NeedSwap) = getX86SSEConditionCode(Predicate);
if (CC > 7 && !Subtarget->hasAVX())
return false;
if (NeedSwap)
std::swap(CmpLHS, CmpRHS);
// Choose the SSE instruction sequence based on data type (float or double).
static const uint16_t OpcTable[2][4] = {
{ X86::CMPSSrr, X86::ANDPSrr, X86::ANDNPSrr, X86::ORPSrr },
{ X86::CMPSDrr, X86::ANDPDrr, X86::ANDNPDrr, X86::ORPDrr }
};
const uint16_t *Opc = nullptr;
switch (RetVT.SimpleTy) {
default: return false;
case MVT::f32: Opc = &OpcTable[0][0]; break;
case MVT::f64: Opc = &OpcTable[1][0]; break;
}
const Value *LHS = I->getOperand(1);
const Value *RHS = I->getOperand(2);
unsigned LHSReg = getRegForValue(LHS);
bool LHSIsKill = hasTrivialKill(LHS);
unsigned RHSReg = getRegForValue(RHS);
bool RHSIsKill = hasTrivialKill(RHS);
unsigned CmpLHSReg = getRegForValue(CmpLHS);
bool CmpLHSIsKill = hasTrivialKill(CmpLHS);
unsigned CmpRHSReg = getRegForValue(CmpRHS);
bool CmpRHSIsKill = hasTrivialKill(CmpRHS);
if (!LHSReg || !RHSReg || !CmpLHS || !CmpRHS)
return false;
const TargetRegisterClass *RC = TLI.getRegClassFor(RetVT);
unsigned ResultReg;
if (Subtarget->hasAVX512()) {
// If we have AVX512 we can use a mask compare and masked movss/sd.
const TargetRegisterClass *VR128X = &X86::VR128XRegClass;
const TargetRegisterClass *VK1 = &X86::VK1RegClass;
unsigned CmpOpcode =
(RetVT == MVT::f32) ? X86::VCMPSSZrr : X86::VCMPSDZrr;
unsigned CmpReg = fastEmitInst_rri(CmpOpcode, VK1, CmpLHSReg, CmpLHSIsKill,
CmpRHSReg, CmpRHSIsKill, CC);
// Need an IMPLICIT_DEF for the input that is used to generate the upper
// bits of the result register since its not based on any of the inputs.
unsigned ImplicitDefReg = createResultReg(VR128X);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::IMPLICIT_DEF), ImplicitDefReg);
// Place RHSReg is the passthru of the masked movss/sd operation and put
// LHS in the input. The mask input comes from the compare.
unsigned MovOpcode =
(RetVT == MVT::f32) ? X86::VMOVSSZrrk : X86::VMOVSDZrrk;
unsigned MovReg = fastEmitInst_rrrr(MovOpcode, VR128X, RHSReg, RHSIsKill,
CmpReg, true, ImplicitDefReg, true,
LHSReg, LHSIsKill);
ResultReg = createResultReg(RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), ResultReg).addReg(MovReg);
} else if (Subtarget->hasAVX()) {
const TargetRegisterClass *VR128 = &X86::VR128RegClass;
// If we have AVX, create 1 blendv instead of 3 logic instructions.
// Blendv was introduced with SSE 4.1, but the 2 register form implicitly
// uses XMM0 as the selection register. That may need just as many
// instructions as the AND/ANDN/OR sequence due to register moves, so
// don't bother.
unsigned CmpOpcode =
(RetVT == MVT::f32) ? X86::VCMPSSrr : X86::VCMPSDrr;
unsigned BlendOpcode =
(RetVT == MVT::f32) ? X86::VBLENDVPSrr : X86::VBLENDVPDrr;
unsigned CmpReg = fastEmitInst_rri(CmpOpcode, RC, CmpLHSReg, CmpLHSIsKill,
CmpRHSReg, CmpRHSIsKill, CC);
unsigned VBlendReg = fastEmitInst_rrr(BlendOpcode, VR128, RHSReg, RHSIsKill,
LHSReg, LHSIsKill, CmpReg, true);
ResultReg = createResultReg(RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), ResultReg).addReg(VBlendReg);
} else {
const TargetRegisterClass *VR128 = &X86::VR128RegClass;
unsigned CmpReg = fastEmitInst_rri(Opc[0], RC, CmpLHSReg, CmpLHSIsKill,
CmpRHSReg, CmpRHSIsKill, CC);
unsigned AndReg = fastEmitInst_rr(Opc[1], VR128, CmpReg, /*IsKill=*/false,
LHSReg, LHSIsKill);
unsigned AndNReg = fastEmitInst_rr(Opc[2], VR128, CmpReg, /*IsKill=*/true,
RHSReg, RHSIsKill);
unsigned OrReg = fastEmitInst_rr(Opc[3], VR128, AndNReg, /*IsKill=*/true,
AndReg, /*IsKill=*/true);
ResultReg = createResultReg(RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), ResultReg).addReg(OrReg);
}
updateValueMap(I, ResultReg);
return true;
}
bool X86FastISel::X86FastEmitPseudoSelect(MVT RetVT, const Instruction *I) {
// These are pseudo CMOV instructions and will be later expanded into control-
// flow.
unsigned Opc;
switch (RetVT.SimpleTy) {
default: return false;
case MVT::i8: Opc = X86::CMOV_GR8; break;
case MVT::i16: Opc = X86::CMOV_GR16; break;
case MVT::i32: Opc = X86::CMOV_GR32; break;
case MVT::f32: Opc = X86::CMOV_FR32; break;
case MVT::f64: Opc = X86::CMOV_FR64; break;
}
const Value *Cond = I->getOperand(0);
X86::CondCode CC = X86::COND_NE;
// Optimize conditions coming from a compare if both instructions are in the
// same basic block (values defined in other basic blocks may not have
// initialized registers).
const auto *CI = dyn_cast<CmpInst>(Cond);
if (CI && (CI->getParent() == I->getParent())) {
bool NeedSwap;
std::tie(CC, NeedSwap) = X86::getX86ConditionCode(CI->getPredicate());
if (CC > X86::LAST_VALID_COND)
return false;
const Value *CmpLHS = CI->getOperand(0);
const Value *CmpRHS = CI->getOperand(1);
if (NeedSwap)
std::swap(CmpLHS, CmpRHS);
EVT CmpVT = TLI.getValueType(DL, CmpLHS->getType());
if (!X86FastEmitCompare(CmpLHS, CmpRHS, CmpVT, CI->getDebugLoc()))
return false;
} else {
unsigned CondReg = getRegForValue(Cond);
if (CondReg == 0)
return false;
bool CondIsKill = hasTrivialKill(Cond);
// In case OpReg is a K register, COPY to a GPR
if (MRI.getRegClass(CondReg) == &X86::VK1RegClass) {
unsigned KCondReg = CondReg;
CondReg = createResultReg(&X86::GR32RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), CondReg)
.addReg(KCondReg, getKillRegState(CondIsKill));
CondReg = fastEmitInst_extractsubreg(MVT::i8, CondReg, /*Kill=*/true,
X86::sub_8bit);
}
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::TEST8ri))
.addReg(CondReg, getKillRegState(CondIsKill))
.addImm(1);
}
const Value *LHS = I->getOperand(1);
const Value *RHS = I->getOperand(2);
unsigned LHSReg = getRegForValue(LHS);
bool LHSIsKill = hasTrivialKill(LHS);
unsigned RHSReg = getRegForValue(RHS);
bool RHSIsKill = hasTrivialKill(RHS);
if (!LHSReg || !RHSReg)
return false;
const TargetRegisterClass *RC = TLI.getRegClassFor(RetVT);
unsigned ResultReg =
fastEmitInst_rri(Opc, RC, RHSReg, RHSIsKill, LHSReg, LHSIsKill, CC);
updateValueMap(I, ResultReg);
return true;
}
bool X86FastISel::X86SelectSelect(const Instruction *I) {
MVT RetVT;
if (!isTypeLegal(I->getType(), RetVT))
return false;
// Check if we can fold the select.
if (const auto *CI = dyn_cast<CmpInst>(I->getOperand(0))) {
CmpInst::Predicate Predicate = optimizeCmpPredicate(CI);
const Value *Opnd = nullptr;
switch (Predicate) {
default: break;
case CmpInst::FCMP_FALSE: Opnd = I->getOperand(2); break;
case CmpInst::FCMP_TRUE: Opnd = I->getOperand(1); break;
}
// No need for a select anymore - this is an unconditional move.
if (Opnd) {
unsigned OpReg = getRegForValue(Opnd);
if (OpReg == 0)
return false;
bool OpIsKill = hasTrivialKill(Opnd);
const TargetRegisterClass *RC = TLI.getRegClassFor(RetVT);
unsigned ResultReg = createResultReg(RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), ResultReg)
.addReg(OpReg, getKillRegState(OpIsKill));
updateValueMap(I, ResultReg);
return true;
}
}
// First try to use real conditional move instructions.
if (X86FastEmitCMoveSelect(RetVT, I))
return true;
// Try to use a sequence of SSE instructions to simulate a conditional move.
if (X86FastEmitSSESelect(RetVT, I))
return true;
// Fall-back to pseudo conditional move instructions, which will be later
// converted to control-flow.
if (X86FastEmitPseudoSelect(RetVT, I))
return true;
return false;
}
// Common code for X86SelectSIToFP and X86SelectUIToFP.
bool X86FastISel::X86SelectIntToFP(const Instruction *I, bool IsSigned) {
// The target-independent selection algorithm in FastISel already knows how
// to select a SINT_TO_FP if the target is SSE but not AVX.
// Early exit if the subtarget doesn't have AVX.
// Unsigned conversion requires avx512.
bool HasAVX512 = Subtarget->hasAVX512();
if (!Subtarget->hasAVX() || (!IsSigned && !HasAVX512))
return false;
// TODO: We could sign extend narrower types.
MVT SrcVT = TLI.getSimpleValueType(DL, I->getOperand(0)->getType());
if (SrcVT != MVT::i32 && SrcVT != MVT::i64)
return false;
// Select integer to float/double conversion.
unsigned OpReg = getRegForValue(I->getOperand(0));
if (OpReg == 0)
return false;
unsigned Opcode;
static const uint16_t SCvtOpc[2][2][2] = {
{ { X86::VCVTSI2SSrr, X86::VCVTSI642SSrr },
{ X86::VCVTSI2SDrr, X86::VCVTSI642SDrr } },
{ { X86::VCVTSI2SSZrr, X86::VCVTSI642SSZrr },
{ X86::VCVTSI2SDZrr, X86::VCVTSI642SDZrr } },
};
static const uint16_t UCvtOpc[2][2] = {
{ X86::VCVTUSI2SSZrr, X86::VCVTUSI642SSZrr },
{ X86::VCVTUSI2SDZrr, X86::VCVTUSI642SDZrr },
};
bool Is64Bit = SrcVT == MVT::i64;
if (I->getType()->isDoubleTy()) {
// s/uitofp int -> double
Opcode = IsSigned ? SCvtOpc[HasAVX512][1][Is64Bit] : UCvtOpc[1][Is64Bit];
} else if (I->getType()->isFloatTy()) {
// s/uitofp int -> float
Opcode = IsSigned ? SCvtOpc[HasAVX512][0][Is64Bit] : UCvtOpc[0][Is64Bit];
} else
return false;
MVT DstVT = TLI.getValueType(DL, I->getType()).getSimpleVT();
const TargetRegisterClass *RC = TLI.getRegClassFor(DstVT);
unsigned ImplicitDefReg = createResultReg(RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::IMPLICIT_DEF), ImplicitDefReg);
unsigned ResultReg =
fastEmitInst_rr(Opcode, RC, ImplicitDefReg, true, OpReg, false);
updateValueMap(I, ResultReg);
return true;
}
bool X86FastISel::X86SelectSIToFP(const Instruction *I) {
return X86SelectIntToFP(I, /*IsSigned*/true);
}
bool X86FastISel::X86SelectUIToFP(const Instruction *I) {
return X86SelectIntToFP(I, /*IsSigned*/false);
}
// Helper method used by X86SelectFPExt and X86SelectFPTrunc.
bool X86FastISel::X86SelectFPExtOrFPTrunc(const Instruction *I,
unsigned TargetOpc,
const TargetRegisterClass *RC) {
assert((I->getOpcode() == Instruction::FPExt ||
I->getOpcode() == Instruction::FPTrunc) &&
"Instruction must be an FPExt or FPTrunc!");
unsigned OpReg = getRegForValue(I->getOperand(0));
if (OpReg == 0)
return false;
unsigned ImplicitDefReg;
if (Subtarget->hasAVX()) {
ImplicitDefReg = createResultReg(RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::IMPLICIT_DEF), ImplicitDefReg);
}
unsigned ResultReg = createResultReg(RC);
MachineInstrBuilder MIB;
MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(TargetOpc),
ResultReg);
if (Subtarget->hasAVX())
MIB.addReg(ImplicitDefReg);
MIB.addReg(OpReg);
updateValueMap(I, ResultReg);
return true;
}
bool X86FastISel::X86SelectFPExt(const Instruction *I) {
if (X86ScalarSSEf64 && I->getType()->isDoubleTy() &&
I->getOperand(0)->getType()->isFloatTy()) {
bool HasAVX512 = Subtarget->hasAVX512();
// fpext from float to double.
unsigned Opc =
HasAVX512 ? X86::VCVTSS2SDZrr
: Subtarget->hasAVX() ? X86::VCVTSS2SDrr : X86::CVTSS2SDrr;
return X86SelectFPExtOrFPTrunc(
I, Opc, HasAVX512 ? &X86::FR64XRegClass : &X86::FR64RegClass);
}
return false;
}
bool X86FastISel::X86SelectFPTrunc(const Instruction *I) {
if (X86ScalarSSEf64 && I->getType()->isFloatTy() &&
I->getOperand(0)->getType()->isDoubleTy()) {
bool HasAVX512 = Subtarget->hasAVX512();
// fptrunc from double to float.
unsigned Opc =
HasAVX512 ? X86::VCVTSD2SSZrr
: Subtarget->hasAVX() ? X86::VCVTSD2SSrr : X86::CVTSD2SSrr;
return X86SelectFPExtOrFPTrunc(
I, Opc, HasAVX512 ? &X86::FR32XRegClass : &X86::FR32RegClass);
}
return false;
}
bool X86FastISel::X86SelectTrunc(const Instruction *I) {
EVT SrcVT = TLI.getValueType(DL, I->getOperand(0)->getType());
EVT DstVT = TLI.getValueType(DL, I->getType());
// This code only handles truncation to byte.
if (DstVT != MVT::i8 && DstVT != MVT::i1)
return false;
if (!TLI.isTypeLegal(SrcVT))
return false;
unsigned InputReg = getRegForValue(I->getOperand(0));
if (!InputReg)
// Unhandled operand. Halt "fast" selection and bail.
return false;
if (SrcVT == MVT::i8) {
// Truncate from i8 to i1; no code needed.
updateValueMap(I, InputReg);
return true;
}
// Issue an extract_subreg.
unsigned ResultReg = fastEmitInst_extractsubreg(MVT::i8,
InputReg, false,
X86::sub_8bit);
if (!ResultReg)
return false;
updateValueMap(I, ResultReg);
return true;
}
bool X86FastISel::IsMemcpySmall(uint64_t Len) {
return Len <= (Subtarget->is64Bit() ? 32 : 16);
}
bool X86FastISel::TryEmitSmallMemcpy(X86AddressMode DestAM,
X86AddressMode SrcAM, uint64_t Len) {
// Make sure we don't bloat code by inlining very large memcpy's.
if (!IsMemcpySmall(Len))
return false;
bool i64Legal = Subtarget->is64Bit();
// We don't care about alignment here since we just emit integer accesses.
while (Len) {
MVT VT;
if (Len >= 8 && i64Legal)
VT = MVT::i64;
else if (Len >= 4)
VT = MVT::i32;
else if (Len >= 2)
VT = MVT::i16;
else
VT = MVT::i8;
unsigned Reg;
bool RV = X86FastEmitLoad(VT, SrcAM, nullptr, Reg);
RV &= X86FastEmitStore(VT, Reg, /*Kill=*/true, DestAM);
assert(RV && "Failed to emit load or store??");
unsigned Size = VT.getSizeInBits()/8;
Len -= Size;
DestAM.Disp += Size;
SrcAM.Disp += Size;
}
return true;
}
bool X86FastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) {
// FIXME: Handle more intrinsics.
switch (II->getIntrinsicID()) {
default: return false;
case Intrinsic::convert_from_fp16:
case Intrinsic::convert_to_fp16: {
if (Subtarget->useSoftFloat() || !Subtarget->hasF16C())
return false;
const Value *Op = II->getArgOperand(0);
unsigned InputReg = getRegForValue(Op);
if (InputReg == 0)
return false;
// F16C only allows converting from float to half and from half to float.
bool IsFloatToHalf = II->getIntrinsicID() == Intrinsic::convert_to_fp16;
if (IsFloatToHalf) {
if (!Op->getType()->isFloatTy())
return false;
} else {
if (!II->getType()->isFloatTy())
return false;
}
unsigned ResultReg = 0;
const TargetRegisterClass *RC = TLI.getRegClassFor(MVT::v8i16);
if (IsFloatToHalf) {
// 'InputReg' is implicitly promoted from register class FR32 to
// register class VR128 by method 'constrainOperandRegClass' which is
// directly called by 'fastEmitInst_ri'.
// Instruction VCVTPS2PHrr takes an extra immediate operand which is
// used to provide rounding control: use MXCSR.RC, encoded as 0b100.
// It's consistent with the other FP instructions, which are usually
// controlled by MXCSR.
InputReg = fastEmitInst_ri(X86::VCVTPS2PHrr, RC, InputReg, false, 4);
// Move the lower 32-bits of ResultReg to another register of class GR32.
ResultReg = createResultReg(&X86::GR32RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(X86::VMOVPDI2DIrr), ResultReg)
.addReg(InputReg, RegState::Kill);
// The result value is in the lower 16-bits of ResultReg.
unsigned RegIdx = X86::sub_16bit;
ResultReg = fastEmitInst_extractsubreg(MVT::i16, ResultReg, true, RegIdx);
} else {
assert(Op->getType()->isIntegerTy(16) && "Expected a 16-bit integer!");
// Explicitly sign-extend the input to 32-bit.
InputReg = fastEmit_r(MVT::i16, MVT::i32, ISD::SIGN_EXTEND, InputReg,
/*Kill=*/false);
// The following SCALAR_TO_VECTOR will be expanded into a VMOVDI2PDIrr.
InputReg = fastEmit_r(MVT::i32, MVT::v4i32, ISD::SCALAR_TO_VECTOR,
InputReg, /*Kill=*/true);
InputReg = fastEmitInst_r(X86::VCVTPH2PSrr, RC, InputReg, /*Kill=*/true);
// The result value is in the lower 32-bits of ResultReg.
// Emit an explicit copy from register class VR128 to register class FR32.
ResultReg = createResultReg(&X86::FR32RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), ResultReg)
.addReg(InputReg, RegState::Kill);
}
updateValueMap(II, ResultReg);
return true;
}
case Intrinsic::frameaddress: {
MachineFunction *MF = FuncInfo.MF;
if (MF->getTarget().getMCAsmInfo()->usesWindowsCFI())
return false;
Type *RetTy = II->getCalledFunction()->getReturnType();
MVT VT;
if (!isTypeLegal(RetTy, VT))
return false;
unsigned Opc;
const TargetRegisterClass *RC = nullptr;
switch (VT.SimpleTy) {
default: llvm_unreachable("Invalid result type for frameaddress.");
case MVT::i32: Opc = X86::MOV32rm; RC = &X86::GR32RegClass; break;
case MVT::i64: Opc = X86::MOV64rm; RC = &X86::GR64RegClass; break;
}
// This needs to be set before we call getPtrSizedFrameRegister, otherwise
// we get the wrong frame register.
MachineFrameInfo &MFI = MF->getFrameInfo();
MFI.setFrameAddressIsTaken(true);
const X86RegisterInfo *RegInfo = Subtarget->getRegisterInfo();
unsigned FrameReg = RegInfo->getPtrSizedFrameRegister(*MF);
assert(((FrameReg == X86::RBP && VT == MVT::i64) ||
(FrameReg == X86::EBP && VT == MVT::i32)) &&
"Invalid Frame Register!");
// Always make a copy of the frame register to a vreg first, so that we
// never directly reference the frame register (the TwoAddressInstruction-
// Pass doesn't like that).
unsigned SrcReg = createResultReg(RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), SrcReg).addReg(FrameReg);
// Now recursively load from the frame address.
// movq (%rbp), %rax
// movq (%rax), %rax
// movq (%rax), %rax
// ...
unsigned DestReg;
unsigned Depth = cast<ConstantInt>(II->getOperand(0))->getZExtValue();
while (Depth--) {
DestReg = createResultReg(RC);
addDirectMem(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Opc), DestReg), SrcReg);
SrcReg = DestReg;
}
updateValueMap(II, SrcReg);
return true;
}
case Intrinsic::memcpy: {
const MemCpyInst *MCI = cast<MemCpyInst>(II);
// Don't handle volatile or variable length memcpys.
if (MCI->isVolatile())
return false;
if (isa<ConstantInt>(MCI->getLength())) {
// Small memcpy's are common enough that we want to do them
// without a call if possible.
uint64_t Len = cast<ConstantInt>(MCI->getLength())->getZExtValue();
if (IsMemcpySmall(Len)) {
X86AddressMode DestAM, SrcAM;
if (!X86SelectAddress(MCI->getRawDest(), DestAM) ||
!X86SelectAddress(MCI->getRawSource(), SrcAM))
return false;
TryEmitSmallMemcpy(DestAM, SrcAM, Len);
return true;
}
}
unsigned SizeWidth = Subtarget->is64Bit() ? 64 : 32;
if (!MCI->getLength()->getType()->isIntegerTy(SizeWidth))
return false;
if (MCI->getSourceAddressSpace() > 255 || MCI->getDestAddressSpace() > 255)
return false;
return lowerCallTo(II, "memcpy", II->getNumArgOperands() - 1);
}
case Intrinsic::memset: {
const MemSetInst *MSI = cast<MemSetInst>(II);
if (MSI->isVolatile())
return false;
unsigned SizeWidth = Subtarget->is64Bit() ? 64 : 32;
if (!MSI->getLength()->getType()->isIntegerTy(SizeWidth))
return false;
if (MSI->getDestAddressSpace() > 255)
return false;
return lowerCallTo(II, "memset", II->getNumArgOperands() - 1);
}
case Intrinsic::stackprotector: {
// Emit code to store the stack guard onto the stack.
EVT PtrTy = TLI.getPointerTy(DL);
const Value *Op1 = II->getArgOperand(0); // The guard's value.
const AllocaInst *Slot = cast<AllocaInst>(II->getArgOperand(1));
MFI.setStackProtectorIndex(FuncInfo.StaticAllocaMap[Slot]);
// Grab the frame index.
X86AddressMode AM;
if (!X86SelectAddress(Slot, AM)) return false;
if (!X86FastEmitStore(PtrTy, Op1, AM)) return false;
return true;
}
case Intrinsic::dbg_declare: {
const DbgDeclareInst *DI = cast<DbgDeclareInst>(II);
X86AddressMode AM;
assert(DI->getAddress() && "Null address should be checked earlier!");
if (!X86SelectAddress(DI->getAddress(), AM))
return false;
const MCInstrDesc &II = TII.get(TargetOpcode::DBG_VALUE);
// FIXME may need to add RegState::Debug to any registers produced,
// although ESP/EBP should be the only ones at the moment.
assert(DI->getVariable()->isValidLocationForIntrinsic(DbgLoc) &&
"Expected inlined-at fields to agree");
addFullAddress(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II), AM)
.addImm(0)
.addMetadata(DI->getVariable())
.addMetadata(DI->getExpression());
return true;
}
case Intrinsic::trap: {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::TRAP));
return true;
}
case Intrinsic::sqrt: {
if (!Subtarget->hasSSE1())
return false;
Type *RetTy = II->getCalledFunction()->getReturnType();
MVT VT;
if (!isTypeLegal(RetTy, VT))
return false;
// Unfortunately we can't use fastEmit_r, because the AVX version of FSQRT
// is not generated by FastISel yet.
// FIXME: Update this code once tablegen can handle it.
static const uint16_t SqrtOpc[3][2] = {
{ X86::SQRTSSr, X86::SQRTSDr },
{ X86::VSQRTSSr, X86::VSQRTSDr },
{ X86::VSQRTSSZr, X86::VSQRTSDZr },
};
unsigned AVXLevel = Subtarget->hasAVX512() ? 2 :
Subtarget->hasAVX() ? 1 :
0;
unsigned Opc;
switch (VT.SimpleTy) {
default: return false;
case MVT::f32: Opc = SqrtOpc[AVXLevel][0]; break;
case MVT::f64: Opc = SqrtOpc[AVXLevel][1]; break;
}
const Value *SrcVal = II->getArgOperand(0);
unsigned SrcReg = getRegForValue(SrcVal);
if (SrcReg == 0)
return false;
const TargetRegisterClass *RC = TLI.getRegClassFor(VT);
unsigned ImplicitDefReg = 0;
if (AVXLevel > 0) {
ImplicitDefReg = createResultReg(RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::IMPLICIT_DEF), ImplicitDefReg);
}
unsigned ResultReg = createResultReg(RC);
MachineInstrBuilder MIB;
MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
ResultReg);
if (ImplicitDefReg)
MIB.addReg(ImplicitDefReg);
MIB.addReg(SrcReg);
updateValueMap(II, ResultReg);
return true;
}
case Intrinsic::sadd_with_overflow:
case Intrinsic::uadd_with_overflow:
case Intrinsic::ssub_with_overflow:
case Intrinsic::usub_with_overflow:
case Intrinsic::smul_with_overflow:
case Intrinsic::umul_with_overflow: {
// This implements the basic lowering of the xalu with overflow intrinsics
// into add/sub/mul followed by either seto or setb.
const Function *Callee = II->getCalledFunction();
auto *Ty = cast<StructType>(Callee->getReturnType());
Type *RetTy = Ty->getTypeAtIndex(0U);
assert(Ty->getTypeAtIndex(1)->isIntegerTy() &&
Ty->getTypeAtIndex(1)->getScalarSizeInBits() == 1 &&
"Overflow value expected to be an i1");
MVT VT;
if (!isTypeLegal(RetTy, VT))
return false;
if (VT < MVT::i8 || VT > MVT::i64)
return false;
const Value *LHS = II->getArgOperand(0);
const Value *RHS = II->getArgOperand(1);
// Canonicalize immediate to the RHS.
if (isa<ConstantInt>(LHS) && !isa<ConstantInt>(RHS) &&
isCommutativeIntrinsic(II))
std::swap(LHS, RHS);
unsigned BaseOpc, CondOpc;
switch (II->getIntrinsicID()) {
default: llvm_unreachable("Unexpected intrinsic!");
case Intrinsic::sadd_with_overflow:
BaseOpc = ISD::ADD; CondOpc = X86::SETOr; break;
case Intrinsic::uadd_with_overflow:
BaseOpc = ISD::ADD; CondOpc = X86::SETBr; break;
case Intrinsic::ssub_with_overflow:
BaseOpc = ISD::SUB; CondOpc = X86::SETOr; break;
case Intrinsic::usub_with_overflow:
BaseOpc = ISD::SUB; CondOpc = X86::SETBr; break;
case Intrinsic::smul_with_overflow:
BaseOpc = X86ISD::SMUL; CondOpc = X86::SETOr; break;
case Intrinsic::umul_with_overflow:
BaseOpc = X86ISD::UMUL; CondOpc = X86::SETOr; break;
}
unsigned LHSReg = getRegForValue(LHS);
if (LHSReg == 0)
return false;
bool LHSIsKill = hasTrivialKill(LHS);
unsigned ResultReg = 0;
// Check if we have an immediate version.
if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
static const uint16_t Opc[2][4] = {
{ X86::INC8r, X86::INC16r, X86::INC32r, X86::INC64r },
{ X86::DEC8r, X86::DEC16r, X86::DEC32r, X86::DEC64r }
};
if (CI->isOne() && (BaseOpc == ISD::ADD || BaseOpc == ISD::SUB) &&
CondOpc == X86::SETOr) {
// We can use INC/DEC.
ResultReg = createResultReg(TLI.getRegClassFor(VT));
bool IsDec = BaseOpc == ISD::SUB;
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Opc[IsDec][VT.SimpleTy-MVT::i8]), ResultReg)
.addReg(LHSReg, getKillRegState(LHSIsKill));
} else
ResultReg = fastEmit_ri(VT, VT, BaseOpc, LHSReg, LHSIsKill,
CI->getZExtValue());
}
unsigned RHSReg;
bool RHSIsKill;
if (!ResultReg) {
RHSReg = getRegForValue(RHS);
if (RHSReg == 0)
return false;
RHSIsKill = hasTrivialKill(RHS);
ResultReg = fastEmit_rr(VT, VT, BaseOpc, LHSReg, LHSIsKill, RHSReg,
RHSIsKill);
}
// FastISel doesn't have a pattern for all X86::MUL*r and X86::IMUL*r. Emit
// it manually.
if (BaseOpc == X86ISD::UMUL && !ResultReg) {
static const uint16_t MULOpc[] =
{ X86::MUL8r, X86::MUL16r, X86::MUL32r, X86::MUL64r };
static const MCPhysReg Reg[] = { X86::AL, X86::AX, X86::EAX, X86::RAX };
// First copy the first operand into RAX, which is an implicit input to
// the X86::MUL*r instruction.
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), Reg[VT.SimpleTy-MVT::i8])
.addReg(LHSReg, getKillRegState(LHSIsKill));
ResultReg = fastEmitInst_r(MULOpc[VT.SimpleTy-MVT::i8],
TLI.getRegClassFor(VT), RHSReg, RHSIsKill);
} else if (BaseOpc == X86ISD::SMUL && !ResultReg) {
static const uint16_t MULOpc[] =
{ X86::IMUL8r, X86::IMUL16rr, X86::IMUL32rr, X86::IMUL64rr };
if (VT == MVT::i8) {
// Copy the first operand into AL, which is an implicit input to the
// X86::IMUL8r instruction.
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), X86::AL)
.addReg(LHSReg, getKillRegState(LHSIsKill));
ResultReg = fastEmitInst_r(MULOpc[0], TLI.getRegClassFor(VT), RHSReg,
RHSIsKill);
} else
ResultReg = fastEmitInst_rr(MULOpc[VT.SimpleTy-MVT::i8],
TLI.getRegClassFor(VT), LHSReg, LHSIsKill,
RHSReg, RHSIsKill);
}
if (!ResultReg)
return false;
// Assign to a GPR since the overflow return value is lowered to a SETcc.
unsigned ResultReg2 = createResultReg(&X86::GR8RegClass);
assert((ResultReg+1) == ResultReg2 && "Nonconsecutive result registers.");
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(CondOpc),
ResultReg2);
updateValueMap(II, ResultReg, 2);
return true;
}
case Intrinsic::x86_sse_cvttss2si:
case Intrinsic::x86_sse_cvttss2si64:
case Intrinsic::x86_sse2_cvttsd2si:
case Intrinsic::x86_sse2_cvttsd2si64: {
bool IsInputDouble;
switch (II->getIntrinsicID()) {
default: llvm_unreachable("Unexpected intrinsic.");
case Intrinsic::x86_sse_cvttss2si:
case Intrinsic::x86_sse_cvttss2si64:
if (!Subtarget->hasSSE1())
return false;
IsInputDouble = false;
break;
case Intrinsic::x86_sse2_cvttsd2si:
case Intrinsic::x86_sse2_cvttsd2si64:
if (!Subtarget->hasSSE2())
return false;
IsInputDouble = true;
break;
}
Type *RetTy = II->getCalledFunction()->getReturnType();
MVT VT;
if (!isTypeLegal(RetTy, VT))
return false;
static const uint16_t CvtOpc[3][2][2] = {
{ { X86::CVTTSS2SIrr, X86::CVTTSS2SI64rr },
{ X86::CVTTSD2SIrr, X86::CVTTSD2SI64rr } },
{ { X86::VCVTTSS2SIrr, X86::VCVTTSS2SI64rr },
{ X86::VCVTTSD2SIrr, X86::VCVTTSD2SI64rr } },
{ { X86::VCVTTSS2SIZrr, X86::VCVTTSS2SI64Zrr },
{ X86::VCVTTSD2SIZrr, X86::VCVTTSD2SI64Zrr } },
};
unsigned AVXLevel = Subtarget->hasAVX512() ? 2 :
Subtarget->hasAVX() ? 1 :
0;
unsigned Opc;
switch (VT.SimpleTy) {
default: llvm_unreachable("Unexpected result type.");
case MVT::i32: Opc = CvtOpc[AVXLevel][IsInputDouble][0]; break;
case MVT::i64: Opc = CvtOpc[AVXLevel][IsInputDouble][1]; break;
}
// Check if we can fold insertelement instructions into the convert.
const Value *Op = II->getArgOperand(0);
while (auto *IE = dyn_cast<InsertElementInst>(Op)) {
const Value *Index = IE->getOperand(2);
if (!isa<ConstantInt>(Index))
break;
unsigned Idx = cast<ConstantInt>(Index)->getZExtValue();
if (Idx == 0) {
Op = IE->getOperand(1);
break;
}
Op = IE->getOperand(0);
}
unsigned Reg = getRegForValue(Op);
if (Reg == 0)
return false;
unsigned ResultReg = createResultReg(TLI.getRegClassFor(VT));
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
.addReg(Reg);
updateValueMap(II, ResultReg);
return true;
}
}
}
bool X86FastISel::fastLowerArguments() {
if (!FuncInfo.CanLowerReturn)
return false;
const Function *F = FuncInfo.Fn;
if (F->isVarArg())
return false;
CallingConv::ID CC = F->getCallingConv();
if (CC != CallingConv::C)
return false;
if (Subtarget->isCallingConvWin64(CC))
return false;
if (!Subtarget->is64Bit())
return false;
if (Subtarget->useSoftFloat())
return false;
// Only handle simple cases. i.e. Up to 6 i32/i64 scalar arguments.
unsigned GPRCnt = 0;
unsigned FPRCnt = 0;
for (auto const &Arg : F->args()) {
if (Arg.hasAttribute(Attribute::ByVal) ||
Arg.hasAttribute(Attribute::InReg) ||
Arg.hasAttribute(Attribute::StructRet) ||
Arg.hasAttribute(Attribute::SwiftSelf) ||
Arg.hasAttribute(Attribute::SwiftError) ||
Arg.hasAttribute(Attribute::Nest))
return false;
Type *ArgTy = Arg.getType();
if (ArgTy->isStructTy() || ArgTy->isArrayTy() || ArgTy->isVectorTy())
return false;
EVT ArgVT = TLI.getValueType(DL, ArgTy);
if (!ArgVT.isSimple()) return false;
switch (ArgVT.getSimpleVT().SimpleTy) {
default: return false;
case MVT::i32:
case MVT::i64:
++GPRCnt;
break;
case MVT::f32:
case MVT::f64:
if (!Subtarget->hasSSE1())
return false;
++FPRCnt;
break;
}
if (GPRCnt > 6)
return false;
if (FPRCnt > 8)
return false;
}
static const MCPhysReg GPR32ArgRegs[] = {
X86::EDI, X86::ESI, X86::EDX, X86::ECX, X86::R8D, X86::R9D
};
static const MCPhysReg GPR64ArgRegs[] = {
X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8 , X86::R9
};
static const MCPhysReg XMMArgRegs[] = {
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3,
X86::XMM4, X86::XMM5, X86::XMM6, X86::XMM7
};
unsigned GPRIdx = 0;
unsigned FPRIdx = 0;
for (auto const &Arg : F->args()) {
MVT VT = TLI.getSimpleValueType(DL, Arg.getType());
const TargetRegisterClass *RC = TLI.getRegClassFor(VT);
unsigned SrcReg;
switch (VT.SimpleTy) {
default: llvm_unreachable("Unexpected value type.");
case MVT::i32: SrcReg = GPR32ArgRegs[GPRIdx++]; break;
case MVT::i64: SrcReg = GPR64ArgRegs[GPRIdx++]; break;
case MVT::f32: LLVM_FALLTHROUGH;
case MVT::f64: SrcReg = XMMArgRegs[FPRIdx++]; break;
}
unsigned DstReg = FuncInfo.MF->addLiveIn(SrcReg, RC);
// FIXME: Unfortunately it's necessary to emit a copy from the livein copy.
// Without this, EmitLiveInCopies may eliminate the livein if its only
// use is a bitcast (which isn't turned into an instruction).
unsigned ResultReg = createResultReg(RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), ResultReg)
.addReg(DstReg, getKillRegState(true));
updateValueMap(&Arg, ResultReg);
}
return true;
}
static unsigned computeBytesPoppedByCalleeForSRet(const X86Subtarget *Subtarget,
CallingConv::ID CC,
ImmutableCallSite *CS) {
if (Subtarget->is64Bit())
return 0;
if (Subtarget->getTargetTriple().isOSMSVCRT())
return 0;
if (CC == CallingConv::Fast || CC == CallingConv::GHC ||
CC == CallingConv::HiPE)
return 0;
if (CS)
if (CS->arg_empty() || !CS->paramHasAttr(0, Attribute::StructRet) ||
CS->paramHasAttr(0, Attribute::InReg) || Subtarget->isTargetMCU())
return 0;
return 4;
}
bool X86FastISel::fastLowerCall(CallLoweringInfo &CLI) {
auto &OutVals = CLI.OutVals;
auto &OutFlags = CLI.OutFlags;
auto &OutRegs = CLI.OutRegs;
auto &Ins = CLI.Ins;
auto &InRegs = CLI.InRegs;
CallingConv::ID CC = CLI.CallConv;
bool &IsTailCall = CLI.IsTailCall;
bool IsVarArg = CLI.IsVarArg;
const Value *Callee = CLI.Callee;
MCSymbol *Symbol = CLI.Symbol;
bool Is64Bit = Subtarget->is64Bit();
bool IsWin64 = Subtarget->isCallingConvWin64(CC);
const CallInst *CI =
CLI.CS ? dyn_cast<CallInst>(CLI.CS->getInstruction()) : nullptr;
const Function *CalledFn = CI ? CI->getCalledFunction() : nullptr;
// Call / invoke instructions with NoCfCheck attribute require special
// handling.
const auto *II =
CLI.CS ? dyn_cast<InvokeInst>(CLI.CS->getInstruction()) : nullptr;
if ((CI && CI->doesNoCfCheck()) || (II && II->doesNoCfCheck()))
return false;
// Functions with no_caller_saved_registers that need special handling.
if ((CI && CI->hasFnAttr("no_caller_saved_registers")) ||
(CalledFn && CalledFn->hasFnAttribute("no_caller_saved_registers")))
return false;
// Functions using retpoline for indirect calls need to use SDISel.
if (Subtarget->useRetpolineIndirectCalls())
return false;
// Handle only C, fastcc, and webkit_js calling conventions for now.
switch (CC) {
default: return false;
case CallingConv::C:
case CallingConv::Fast:
case CallingConv::WebKit_JS:
case CallingConv::Swift:
case CallingConv::X86_FastCall:
case CallingConv::X86_StdCall:
case CallingConv::X86_ThisCall:
case CallingConv::Win64:
case CallingConv::X86_64_SysV:
break;
}
// Allow SelectionDAG isel to handle tail calls.
if (IsTailCall)
return false;
// fastcc with -tailcallopt is intended to provide a guaranteed
// tail call optimization. Fastisel doesn't know how to do that.
if (CC == CallingConv::Fast && TM.Options.GuaranteedTailCallOpt)
return false;
// Don't know how to handle Win64 varargs yet. Nothing special needed for
// x86-32. Special handling for x86-64 is implemented.
if (IsVarArg && IsWin64)
return false;
// Don't know about inalloca yet.
if (CLI.CS && CLI.CS->hasInAllocaArgument())
return false;
for (auto Flag : CLI.OutFlags)
if (Flag.isSwiftError())
return false;
SmallVector<MVT, 16> OutVTs;
SmallVector<unsigned, 16> ArgRegs;
// If this is a constant i1/i8/i16 argument, promote to i32 to avoid an extra
// instruction. This is safe because it is common to all FastISel supported
// calling conventions on x86.
for (int i = 0, e = OutVals.size(); i != e; ++i) {
Value *&Val = OutVals[i];
ISD::ArgFlagsTy Flags = OutFlags[i];
if (auto *CI = dyn_cast<ConstantInt>(Val)) {
if (CI->getBitWidth() < 32) {
if (Flags.isSExt())
Val = ConstantExpr::getSExt(CI, Type::getInt32Ty(CI->getContext()));
else
Val = ConstantExpr::getZExt(CI, Type::getInt32Ty(CI->getContext()));
}
}
// Passing bools around ends up doing a trunc to i1 and passing it.
// Codegen this as an argument + "and 1".
MVT VT;
auto *TI = dyn_cast<TruncInst>(Val);
unsigned ResultReg;
if (TI && TI->getType()->isIntegerTy(1) && CLI.CS &&
(TI->getParent() == CLI.CS->getInstruction()->getParent()) &&
TI->hasOneUse()) {
Value *PrevVal = TI->getOperand(0);
ResultReg = getRegForValue(PrevVal);
if (!ResultReg)
return false;
if (!isTypeLegal(PrevVal->getType(), VT))
return false;
ResultReg =
fastEmit_ri(VT, VT, ISD::AND, ResultReg, hasTrivialKill(PrevVal), 1);
} else {
if (!isTypeLegal(Val->getType(), VT))
return false;
ResultReg = getRegForValue(Val);
}
if (!ResultReg)
return false;
ArgRegs.push_back(ResultReg);
OutVTs.push_back(VT);
}
// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CC, IsVarArg, *FuncInfo.MF, ArgLocs, CLI.RetTy->getContext());
// Allocate shadow area for Win64
if (IsWin64)
CCInfo.AllocateStack(32, 8);
CCInfo.AnalyzeCallOperands(OutVTs, OutFlags, CC_X86);
// Get a count of how many bytes are to be pushed on the stack.
unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
// Issue CALLSEQ_START
unsigned AdjStackDown = TII.getCallFrameSetupOpcode();
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AdjStackDown))
.addImm(NumBytes).addImm(0).addImm(0);
// Walk the register/memloc assignments, inserting copies/loads.
const X86RegisterInfo *RegInfo = Subtarget->getRegisterInfo();
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign const &VA = ArgLocs[i];
const Value *ArgVal = OutVals[VA.getValNo()];
MVT ArgVT = OutVTs[VA.getValNo()];
if (ArgVT == MVT::x86mmx)
return false;
unsigned ArgReg = ArgRegs[VA.getValNo()];
// Promote the value if needed.
switch (VA.getLocInfo()) {
case CCValAssign::Full: break;
case CCValAssign::SExt: {
assert(VA.getLocVT().isInteger() && !VA.getLocVT().isVector() &&
"Unexpected extend");
if (ArgVT == MVT::i1)
return false;
bool Emitted = X86FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(), ArgReg,
ArgVT, ArgReg);
assert(Emitted && "Failed to emit a sext!"); (void)Emitted;
ArgVT = VA.getLocVT();
break;
}
case CCValAssign::ZExt: {
assert(VA.getLocVT().isInteger() && !VA.getLocVT().isVector() &&
"Unexpected extend");
// Handle zero-extension from i1 to i8, which is common.
if (ArgVT == MVT::i1) {
// Set the high bits to zero.
ArgReg = fastEmitZExtFromI1(MVT::i8, ArgReg, /*TODO: Kill=*/false);
ArgVT = MVT::i8;
if (ArgReg == 0)
return false;
}
bool Emitted = X86FastEmitExtend(ISD::ZERO_EXTEND, VA.getLocVT(), ArgReg,
ArgVT, ArgReg);
assert(Emitted && "Failed to emit a zext!"); (void)Emitted;
ArgVT = VA.getLocVT();
break;
}
case CCValAssign::AExt: {
assert(VA.getLocVT().isInteger() && !VA.getLocVT().isVector() &&
"Unexpected extend");
bool Emitted = X86FastEmitExtend(ISD::ANY_EXTEND, VA.getLocVT(), ArgReg,
ArgVT, ArgReg);
if (!Emitted)
Emitted = X86FastEmitExtend(ISD::ZERO_EXTEND, VA.getLocVT(), ArgReg,
ArgVT, ArgReg);
if (!Emitted)
Emitted = X86FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(), ArgReg,
ArgVT, ArgReg);
assert(Emitted && "Failed to emit a aext!"); (void)Emitted;
ArgVT = VA.getLocVT();
break;
}
case CCValAssign::BCvt: {
ArgReg = fastEmit_r(ArgVT, VA.getLocVT(), ISD::BITCAST, ArgReg,
/*TODO: Kill=*/false);
assert(ArgReg && "Failed to emit a bitcast!");
ArgVT = VA.getLocVT();
break;
}
case CCValAssign::VExt:
// VExt has not been implemented, so this should be impossible to reach
// for now. However, fallback to Selection DAG isel once implemented.
return false;
case CCValAssign::AExtUpper:
case CCValAssign::SExtUpper:
case CCValAssign::ZExtUpper:
case CCValAssign::FPExt:
llvm_unreachable("Unexpected loc info!");
case CCValAssign::Indirect:
// FIXME: Indirect doesn't need extending, but fast-isel doesn't fully
// support this.
return false;
}
if (VA.isRegLoc()) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), VA.getLocReg()).addReg(ArgReg);
OutRegs.push_back(VA.getLocReg());
} else {
assert(VA.isMemLoc());
// Don't emit stores for undef values.
if (isa<UndefValue>(ArgVal))
continue;
unsigned LocMemOffset = VA.getLocMemOffset();
X86AddressMode AM;
AM.Base.Reg = RegInfo->getStackRegister();
AM.Disp = LocMemOffset;
ISD::ArgFlagsTy Flags = OutFlags[VA.getValNo()];
unsigned Alignment = DL.getABITypeAlignment(ArgVal->getType());
MachineMemOperand *MMO = FuncInfo.MF->getMachineMemOperand(
MachinePointerInfo::getStack(*FuncInfo.MF, LocMemOffset),
MachineMemOperand::MOStore, ArgVT.getStoreSize(), Alignment);
if (Flags.isByVal()) {
X86AddressMode SrcAM;
SrcAM.Base.Reg = ArgReg;
if (!TryEmitSmallMemcpy(AM, SrcAM, Flags.getByValSize()))
return false;
} else if (isa<ConstantInt>(ArgVal) || isa<ConstantPointerNull>(ArgVal)) {
// If this is a really simple value, emit this with the Value* version
// of X86FastEmitStore. If it isn't simple, we don't want to do this,
// as it can cause us to reevaluate the argument.
if (!X86FastEmitStore(ArgVT, ArgVal, AM, MMO))
return false;
} else {
bool ValIsKill = hasTrivialKill(ArgVal);
if (!X86FastEmitStore(ArgVT, ArgReg, ValIsKill, AM, MMO))
return false;
}
}
}
// ELF / PIC requires GOT in the EBX register before function calls via PLT
// GOT pointer.
if (Subtarget->isPICStyleGOT()) {
unsigned Base = getInstrInfo()->getGlobalBaseReg(FuncInfo.MF);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), X86::EBX).addReg(Base);
}
if (Is64Bit && IsVarArg && !IsWin64) {
// From AMD64 ABI document:
// For calls that may call functions that use varargs or stdargs
// (prototype-less calls or calls to functions containing ellipsis (...) in
// the declaration) %al is used as hidden argument to specify the number
// of SSE registers used. The contents of %al do not need to match exactly
// the number of registers, but must be an ubound on the number of SSE
// registers used and is in the range 0 - 8 inclusive.
// Count the number of XMM registers allocated.
static const MCPhysReg XMMArgRegs[] = {
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3,
X86::XMM4, X86::XMM5, X86::XMM6, X86::XMM7
};
unsigned NumXMMRegs = CCInfo.getFirstUnallocated(XMMArgRegs);
assert((Subtarget->hasSSE1() || !NumXMMRegs)
&& "SSE registers cannot be used when SSE is disabled");
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::MOV8ri),
X86::AL).addImm(NumXMMRegs);
}
// Materialize callee address in a register. FIXME: GV address can be
// handled with a CALLpcrel32 instead.
X86AddressMode CalleeAM;
if (!X86SelectCallAddress(Callee, CalleeAM))
return false;
unsigned CalleeOp = 0;
const GlobalValue *GV = nullptr;
if (CalleeAM.GV != nullptr) {
GV = CalleeAM.GV;
} else if (CalleeAM.Base.Reg != 0) {
CalleeOp = CalleeAM.Base.Reg;
} else
return false;
// Issue the call.
MachineInstrBuilder MIB;
if (CalleeOp) {
// Register-indirect call.
unsigned CallOpc = Is64Bit ? X86::CALL64r : X86::CALL32r;
MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(CallOpc))
.addReg(CalleeOp);
} else {
// Direct call.
assert(GV && "Not a direct call");
// See if we need any target-specific flags on the GV operand.
unsigned char OpFlags = Subtarget->classifyGlobalFunctionReference(GV);
// This will be a direct call, or an indirect call through memory for
// NonLazyBind calls or dllimport calls.
bool NeedLoad =
OpFlags == X86II::MO_DLLIMPORT || OpFlags == X86II::MO_GOTPCREL;
unsigned CallOpc = NeedLoad
? (Is64Bit ? X86::CALL64m : X86::CALL32m)
: (Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32);
MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(CallOpc));
if (NeedLoad)
MIB.addReg(Is64Bit ? X86::RIP : 0).addImm(1).addReg(0);
if (Symbol)
MIB.addSym(Symbol, OpFlags);
else
MIB.addGlobalAddress(GV, 0, OpFlags);
if (NeedLoad)
MIB.addReg(0);
}
// Add a register mask operand representing the call-preserved registers.
// Proper defs for return values will be added by setPhysRegsDeadExcept().
MIB.addRegMask(TRI.getCallPreservedMask(*FuncInfo.MF, CC));
// Add an implicit use GOT pointer in EBX.
if (Subtarget->isPICStyleGOT())
MIB.addReg(X86::EBX, RegState::Implicit);
if (Is64Bit && IsVarArg && !IsWin64)
MIB.addReg(X86::AL, RegState::Implicit);
// Add implicit physical register uses to the call.
for (auto Reg : OutRegs)
MIB.addReg(Reg, RegState::Implicit);
// Issue CALLSEQ_END
unsigned NumBytesForCalleeToPop =
X86::isCalleePop(CC, Subtarget->is64Bit(), IsVarArg,
TM.Options.GuaranteedTailCallOpt)
? NumBytes // Callee pops everything.
: computeBytesPoppedByCalleeForSRet(Subtarget, CC, CLI.CS);
unsigned AdjStackUp = TII.getCallFrameDestroyOpcode();
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AdjStackUp))
.addImm(NumBytes).addImm(NumBytesForCalleeToPop);
// Now handle call return values.
SmallVector<CCValAssign, 16> RVLocs;
CCState CCRetInfo(CC, IsVarArg, *FuncInfo.MF, RVLocs,
CLI.RetTy->getContext());
CCRetInfo.AnalyzeCallResult(Ins, RetCC_X86);
// Copy all of the result registers out of their specified physreg.
unsigned ResultReg = FuncInfo.CreateRegs(CLI.RetTy);
for (unsigned i = 0; i != RVLocs.size(); ++i) {
CCValAssign &VA = RVLocs[i];
EVT CopyVT = VA.getValVT();
unsigned CopyReg = ResultReg + i;
unsigned SrcReg = VA.getLocReg();
// If this is x86-64, and we disabled SSE, we can't return FP values
if ((CopyVT == MVT::f32 || CopyVT == MVT::f64) &&
((Is64Bit || Ins[i].Flags.isInReg()) && !Subtarget->hasSSE1())) {
report_fatal_error("SSE register return with SSE disabled");
}
// If we prefer to use the value in xmm registers, copy it out as f80 and
// use a truncate to move it from fp stack reg to xmm reg.
if ((SrcReg == X86::FP0 || SrcReg == X86::FP1) &&
isScalarFPTypeInSSEReg(VA.getValVT())) {
CopyVT = MVT::f80;
CopyReg = createResultReg(&X86::RFP80RegClass);
}
// Copy out the result.
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), CopyReg).addReg(SrcReg);
InRegs.push_back(VA.getLocReg());
// Round the f80 to the right size, which also moves it to the appropriate
// xmm register. This is accomplished by storing the f80 value in memory
// and then loading it back.
if (CopyVT != VA.getValVT()) {
EVT ResVT = VA.getValVT();
unsigned Opc = ResVT == MVT::f32 ? X86::ST_Fp80m32 : X86::ST_Fp80m64;
unsigned MemSize = ResVT.getSizeInBits()/8;
int FI = MFI.CreateStackObject(MemSize, MemSize, false);
addFrameReference(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Opc)), FI)
.addReg(CopyReg);
Opc = ResVT == MVT::f32 ? X86::MOVSSrm : X86::MOVSDrm;
addFrameReference(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Opc), ResultReg + i), FI);
}
}
CLI.ResultReg = ResultReg;
CLI.NumResultRegs = RVLocs.size();
CLI.Call = MIB;
return true;
}
bool
X86FastISel::fastSelectInstruction(const Instruction *I) {
switch (I->getOpcode()) {
default: break;
case Instruction::Load:
return X86SelectLoad(I);
case Instruction::Store:
return X86SelectStore(I);
case Instruction::Ret:
return X86SelectRet(I);
case Instruction::ICmp:
case Instruction::FCmp:
return X86SelectCmp(I);
case Instruction::ZExt:
return X86SelectZExt(I);
case Instruction::SExt:
return X86SelectSExt(I);
case Instruction::Br:
return X86SelectBranch(I);
case Instruction::LShr:
case Instruction::AShr:
case Instruction::Shl:
return X86SelectShift(I);
case Instruction::SDiv:
case Instruction::UDiv:
case Instruction::SRem:
case Instruction::URem:
return X86SelectDivRem(I);
case Instruction::Select:
return X86SelectSelect(I);
case Instruction::Trunc:
return X86SelectTrunc(I);
case Instruction::FPExt:
return X86SelectFPExt(I);
case Instruction::FPTrunc:
return X86SelectFPTrunc(I);
case Instruction::SIToFP:
return X86SelectSIToFP(I);
case Instruction::UIToFP:
return X86SelectUIToFP(I);
case Instruction::IntToPtr: // Deliberate fall-through.
case Instruction::PtrToInt: {
EVT SrcVT = TLI.getValueType(DL, I->getOperand(0)->getType());
EVT DstVT = TLI.getValueType(DL, I->getType());
if (DstVT.bitsGT(SrcVT))
return X86SelectZExt(I);
if (DstVT.bitsLT(SrcVT))
return X86SelectTrunc(I);
unsigned Reg = getRegForValue(I->getOperand(0));
if (Reg == 0) return false;
updateValueMap(I, Reg);
return true;
}
case Instruction::BitCast: {
// Select SSE2/AVX bitcasts between 128/256 bit vector types.
if (!Subtarget->hasSSE2())
return false;
EVT SrcVT = TLI.getValueType(DL, I->getOperand(0)->getType());
EVT DstVT = TLI.getValueType(DL, I->getType());
if (!SrcVT.isSimple() || !DstVT.isSimple())
return false;
MVT SVT = SrcVT.getSimpleVT();
MVT DVT = DstVT.getSimpleVT();
if (!SVT.is128BitVector() &&
!(Subtarget->hasAVX() && SVT.is256BitVector()) &&
!(Subtarget->hasAVX512() && SVT.is512BitVector() &&
(Subtarget->hasBWI() || (SVT.getScalarSizeInBits() >= 32 &&
DVT.getScalarSizeInBits() >= 32))))
return false;
unsigned Reg = getRegForValue(I->getOperand(0));
if (Reg == 0)
return false;
// No instruction is needed for conversion. Reuse the register used by
// the fist operand.
updateValueMap(I, Reg);
return true;
}
}
return false;
}
unsigned X86FastISel::X86MaterializeInt(const ConstantInt *CI, MVT VT) {
if (VT > MVT::i64)
return 0;
uint64_t Imm = CI->getZExtValue();
if (Imm == 0) {
unsigned SrcReg = fastEmitInst_(X86::MOV32r0, &X86::GR32RegClass);
switch (VT.SimpleTy) {
default: llvm_unreachable("Unexpected value type");
case MVT::i1:
case MVT::i8:
return fastEmitInst_extractsubreg(MVT::i8, SrcReg, /*Kill=*/true,
X86::sub_8bit);
case MVT::i16:
return fastEmitInst_extractsubreg(MVT::i16, SrcReg, /*Kill=*/true,
X86::sub_16bit);
case MVT::i32:
return SrcReg;
case MVT::i64: {
unsigned ResultReg = createResultReg(&X86::GR64RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::SUBREG_TO_REG), ResultReg)
.addImm(0).addReg(SrcReg).addImm(X86::sub_32bit);
return ResultReg;
}
}
}
unsigned Opc = 0;
switch (VT.SimpleTy) {
default: llvm_unreachable("Unexpected value type");
case MVT::i1:
VT = MVT::i8;
LLVM_FALLTHROUGH;
case MVT::i8: Opc = X86::MOV8ri; break;
case MVT::i16: Opc = X86::MOV16ri; break;
case MVT::i32: Opc = X86::MOV32ri; break;
case MVT::i64: {
if (isUInt<32>(Imm))
Opc = X86::MOV32ri64;
else if (isInt<32>(Imm))
Opc = X86::MOV64ri32;
else
Opc = X86::MOV64ri;
break;
}
}
return fastEmitInst_i(Opc, TLI.getRegClassFor(VT), Imm);
}
unsigned X86FastISel::X86MaterializeFP(const ConstantFP *CFP, MVT VT) {
if (CFP->isNullValue())
return fastMaterializeFloatZero(CFP);
// Can't handle alternate code models yet.
CodeModel::Model CM = TM.getCodeModel();
if (CM != CodeModel::Small && CM != CodeModel::Large)
return 0;
// Get opcode and regclass of the output for the given load instruction.
unsigned Opc = 0;
const TargetRegisterClass *RC = nullptr;
switch (VT.SimpleTy) {
default: return 0;
case MVT::f32:
if (X86ScalarSSEf32) {
Opc = Subtarget->hasAVX512()
? X86::VMOVSSZrm
: Subtarget->hasAVX() ? X86::VMOVSSrm : X86::MOVSSrm;
RC = Subtarget->hasAVX512() ? &X86::FR32XRegClass : &X86::FR32RegClass;
} else {
Opc = X86::LD_Fp32m;
RC = &X86::RFP32RegClass;
}
break;
case MVT::f64:
if (X86ScalarSSEf64) {
Opc = Subtarget->hasAVX512()
? X86::VMOVSDZrm
: Subtarget->hasAVX() ? X86::VMOVSDrm : X86::MOVSDrm;
RC = Subtarget->hasAVX512() ? &X86::FR64XRegClass : &X86::FR64RegClass;
} else {
Opc = X86::LD_Fp64m;
RC = &X86::RFP64RegClass;
}
break;
case MVT::f80:
// No f80 support yet.
return 0;
}
// MachineConstantPool wants an explicit alignment.
unsigned Align = DL.getPrefTypeAlignment(CFP->getType());
if (Align == 0) {
// Alignment of vector types. FIXME!
Align = DL.getTypeAllocSize(CFP->getType());
}
// x86-32 PIC requires a PIC base register for constant pools.
unsigned PICBase = 0;
unsigned char OpFlag = Subtarget->classifyLocalReference(nullptr);
if (OpFlag == X86II::MO_PIC_BASE_OFFSET)
PICBase = getInstrInfo()->getGlobalBaseReg(FuncInfo.MF);
else if (OpFlag == X86II::MO_GOTOFF)
PICBase = getInstrInfo()->getGlobalBaseReg(FuncInfo.MF);
else if (Subtarget->is64Bit() && TM.getCodeModel() == CodeModel::Small)
PICBase = X86::RIP;
// Create the load from the constant pool.
unsigned CPI = MCP.getConstantPoolIndex(CFP, Align);
unsigned ResultReg = createResultReg(RC);
if (CM == CodeModel::Large) {
unsigned AddrReg = createResultReg(&X86::GR64RegClass);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::MOV64ri),
AddrReg)
.addConstantPoolIndex(CPI, 0, OpFlag);
MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Opc), ResultReg);
addDirectMem(MIB, AddrReg);
MachineMemOperand *MMO = FuncInfo.MF->getMachineMemOperand(
MachinePointerInfo::getConstantPool(*FuncInfo.MF),
MachineMemOperand::MOLoad, DL.getPointerSize(), Align);
MIB->addMemOperand(*FuncInfo.MF, MMO);
return ResultReg;
}
addConstantPoolReference(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Opc), ResultReg),
CPI, PICBase, OpFlag);
return ResultReg;
}
unsigned X86FastISel::X86MaterializeGV(const GlobalValue *GV, MVT VT) {
// Can't handle alternate code models yet.
if (TM.getCodeModel() != CodeModel::Small)
return 0;
// Materialize addresses with LEA/MOV instructions.
X86AddressMode AM;
if (X86SelectAddress(GV, AM)) {
// If the expression is just a basereg, then we're done, otherwise we need
// to emit an LEA.
if (AM.BaseType == X86AddressMode::RegBase &&
AM.IndexReg == 0 && AM.Disp == 0 && AM.GV == nullptr)
return AM.Base.Reg;
unsigned ResultReg = createResultReg(TLI.getRegClassFor(VT));
if (TM.getRelocationModel() == Reloc::Static &&
TLI.getPointerTy(DL) == MVT::i64) {
// The displacement code could be more than 32 bits away so we need to use
// an instruction with a 64 bit immediate
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::MOV64ri),
ResultReg)
.addGlobalAddress(GV);
} else {
unsigned Opc =
TLI.getPointerTy(DL) == MVT::i32
? (Subtarget->isTarget64BitILP32() ? X86::LEA64_32r : X86::LEA32r)
: X86::LEA64r;
addFullAddress(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Opc), ResultReg), AM);
}
return ResultReg;
}
return 0;
}
unsigned X86FastISel::fastMaterializeConstant(const Constant *C) {
EVT CEVT = TLI.getValueType(DL, C->getType(), true);
// Only handle simple types.
if (!CEVT.isSimple())
return 0;
MVT VT = CEVT.getSimpleVT();
if (const auto *CI = dyn_cast<ConstantInt>(C))
return X86MaterializeInt(CI, VT);
else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C))
return X86MaterializeFP(CFP, VT);
else if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
return X86MaterializeGV(GV, VT);
return 0;
}
unsigned X86FastISel::fastMaterializeAlloca(const AllocaInst *C) {
// Fail on dynamic allocas. At this point, getRegForValue has already
// checked its CSE maps, so if we're here trying to handle a dynamic
// alloca, we're not going to succeed. X86SelectAddress has a
// check for dynamic allocas, because it's called directly from
// various places, but targetMaterializeAlloca also needs a check
// in order to avoid recursion between getRegForValue,
// X86SelectAddrss, and targetMaterializeAlloca.
if (!FuncInfo.StaticAllocaMap.count(C))
return 0;
assert(C->isStaticAlloca() && "dynamic alloca in the static alloca map?");
X86AddressMode AM;
if (!X86SelectAddress(C, AM))
return 0;
unsigned Opc =
TLI.getPointerTy(DL) == MVT::i32
? (Subtarget->isTarget64BitILP32() ? X86::LEA64_32r : X86::LEA32r)
: X86::LEA64r;
const TargetRegisterClass *RC = TLI.getRegClassFor(TLI.getPointerTy(DL));
unsigned ResultReg = createResultReg(RC);
addFullAddress(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Opc), ResultReg), AM);
return ResultReg;
}
unsigned X86FastISel::fastMaterializeFloatZero(const ConstantFP *CF) {
MVT VT;
if (!isTypeLegal(CF->getType(), VT))
return 0;
// Get opcode and regclass for the given zero.
bool HasAVX512 = Subtarget->hasAVX512();
unsigned Opc = 0;
const TargetRegisterClass *RC = nullptr;
switch (VT.SimpleTy) {
default: return 0;
case MVT::f32:
if (X86ScalarSSEf32) {
Opc = HasAVX512 ? X86::AVX512_FsFLD0SS : X86::FsFLD0SS;
RC = HasAVX512 ? &X86::FR32XRegClass : &X86::FR32RegClass;
} else {
Opc = X86::LD_Fp032;
RC = &X86::RFP32RegClass;
}
break;
case MVT::f64:
if (X86ScalarSSEf64) {
Opc = HasAVX512 ? X86::AVX512_FsFLD0SD : X86::FsFLD0SD;
RC = HasAVX512 ? &X86::FR64XRegClass : &X86::FR64RegClass;
} else {
Opc = X86::LD_Fp064;
RC = &X86::RFP64RegClass;
}
break;
case MVT::f80:
// No f80 support yet.
return 0;
}
unsigned ResultReg = createResultReg(RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg);
return ResultReg;
}
bool X86FastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
const LoadInst *LI) {
const Value *Ptr = LI->getPointerOperand();
X86AddressMode AM;
if (!X86SelectAddress(Ptr, AM))
return false;
const X86InstrInfo &XII = (const X86InstrInfo &)TII;
unsigned Size = DL.getTypeAllocSize(LI->getType());
unsigned Alignment = LI->getAlignment();
if (Alignment == 0) // Ensure that codegen never sees alignment 0
Alignment = DL.getABITypeAlignment(LI->getType());
SmallVector<MachineOperand, 8> AddrOps;
AM.getFullAddress(AddrOps);
MachineInstr *Result = XII.foldMemoryOperandImpl(
*FuncInfo.MF, *MI, OpNo, AddrOps, FuncInfo.InsertPt, Size, Alignment,
/*AllowCommute=*/true);
if (!Result)
return false;
// The index register could be in the wrong register class. Unfortunately,
// foldMemoryOperandImpl could have commuted the instruction so its not enough
// to just look at OpNo + the offset to the index reg. We actually need to
// scan the instruction to find the index reg and see if its the correct reg
// class.
unsigned OperandNo = 0;
for (MachineInstr::mop_iterator I = Result->operands_begin(),
E = Result->operands_end(); I != E; ++I, ++OperandNo) {
MachineOperand &MO = *I;
if (!MO.isReg() || MO.isDef() || MO.getReg() != AM.IndexReg)
continue;
// Found the index reg, now try to rewrite it.
unsigned IndexReg = constrainOperandRegClass(Result->getDesc(),
MO.getReg(), OperandNo);
if (IndexReg == MO.getReg())
continue;
MO.setReg(IndexReg);
}
Result->addMemOperand(*FuncInfo.MF, createMachineMemOperandFor(LI));
MachineBasicBlock::iterator I(MI);
removeDeadCode(I, std::next(I));
return true;
}
unsigned X86FastISel::fastEmitInst_rrrr(unsigned MachineInstOpcode,
const TargetRegisterClass *RC,
unsigned Op0, bool Op0IsKill,
unsigned Op1, bool Op1IsKill,
unsigned Op2, bool Op2IsKill,
unsigned Op3, bool Op3IsKill) {
const MCInstrDesc &II = TII.get(MachineInstOpcode);
unsigned ResultReg = createResultReg(RC);
Op0 = constrainOperandRegClass(II, Op0, II.getNumDefs());
Op1 = constrainOperandRegClass(II, Op1, II.getNumDefs() + 1);
Op2 = constrainOperandRegClass(II, Op2, II.getNumDefs() + 2);
Op3 = constrainOperandRegClass(II, Op3, II.getNumDefs() + 3);
if (II.getNumDefs() >= 1)
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, ResultReg)
.addReg(Op0, getKillRegState(Op0IsKill))
.addReg(Op1, getKillRegState(Op1IsKill))
.addReg(Op2, getKillRegState(Op2IsKill))
.addReg(Op3, getKillRegState(Op3IsKill));
else {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
.addReg(Op0, getKillRegState(Op0IsKill))
.addReg(Op1, getKillRegState(Op1IsKill))
.addReg(Op2, getKillRegState(Op2IsKill))
.addReg(Op3, getKillRegState(Op3IsKill));
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), ResultReg).addReg(II.ImplicitDefs[0]);
}
return ResultReg;
}
namespace llvm {
FastISel *X86::createFastISel(FunctionLoweringInfo &funcInfo,
const TargetLibraryInfo *libInfo) {
return new X86FastISel(funcInfo, libInfo);
}
}
Index: stable/11/contrib/llvm/lib/Target/X86/X86TargetMachine.cpp
===================================================================
--- stable/11/contrib/llvm/lib/Target/X86/X86TargetMachine.cpp (revision 350258)
+++ stable/11/contrib/llvm/lib/Target/X86/X86TargetMachine.cpp (revision 350259)
@@ -1,517 +1,521 @@
//===-- X86TargetMachine.cpp - Define TargetMachine for the X86 -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the X86 specific subclass of TargetMachine.
//
//===----------------------------------------------------------------------===//
#include "X86TargetMachine.h"
#include "MCTargetDesc/X86MCTargetDesc.h"
#include "X86.h"
#include "X86CallLowering.h"
#include "X86LegalizerInfo.h"
#include "X86MacroFusion.h"
#include "X86Subtarget.h"
#include "X86TargetObjectFile.h"
#include "X86TargetTransformInfo.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/CodeGen/ExecutionDomainFix.h"
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
#include "llvm/CodeGen/GlobalISel/IRTranslator.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
#include "llvm/CodeGen/GlobalISel/Legalizer.h"
#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
+#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Pass.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetOptions.h"
#include <memory>
#include <string>
using namespace llvm;
static cl::opt<bool> EnableMachineCombinerPass("x86-machine-combiner",
cl::desc("Enable the machine combiner pass"),
cl::init(true), cl::Hidden);
static cl::opt<bool> EnableCondBrFoldingPass("x86-condbr-folding",
cl::desc("Enable the conditional branch "
"folding pass"),
cl::init(false), cl::Hidden);
extern "C" void LLVMInitializeX86Target() {
// Register the target.
RegisterTargetMachine<X86TargetMachine> X(getTheX86_32Target());
RegisterTargetMachine<X86TargetMachine> Y(getTheX86_64Target());
PassRegistry &PR = *PassRegistry::getPassRegistry();
initializeGlobalISel(PR);
initializeWinEHStatePassPass(PR);
initializeFixupBWInstPassPass(PR);
initializeEvexToVexInstPassPass(PR);
initializeFixupLEAPassPass(PR);
initializeShadowCallStackPass(PR);
initializeX86CallFrameOptimizationPass(PR);
initializeX86CmovConverterPassPass(PR);
initializeX86ExecutionDomainFixPass(PR);
initializeX86DomainReassignmentPass(PR);
initializeX86AvoidSFBPassPass(PR);
initializeX86SpeculativeLoadHardeningPassPass(PR);
initializeX86FlagsCopyLoweringPassPass(PR);
initializeX86CondBrFoldingPassPass(PR);
}
static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
if (TT.isOSBinFormatMachO()) {
if (TT.getArch() == Triple::x86_64)
return llvm::make_unique<X86_64MachoTargetObjectFile>();
return llvm::make_unique<TargetLoweringObjectFileMachO>();
}
if (TT.isOSFreeBSD())
return llvm::make_unique<X86FreeBSDTargetObjectFile>();
if (TT.isOSLinux() || TT.isOSNaCl() || TT.isOSIAMCU())
return llvm::make_unique<X86LinuxNaClTargetObjectFile>();
if (TT.isOSSolaris())
return llvm::make_unique<X86SolarisTargetObjectFile>();
if (TT.isOSFuchsia())
return llvm::make_unique<X86FuchsiaTargetObjectFile>();
if (TT.isOSBinFormatELF())
return llvm::make_unique<X86ELFTargetObjectFile>();
if (TT.isOSBinFormatCOFF())
return llvm::make_unique<TargetLoweringObjectFileCOFF>();
llvm_unreachable("unknown subtarget type");
}
static std::string computeDataLayout(const Triple &TT) {
// X86 is little endian
std::string Ret = "e";
Ret += DataLayout::getManglingComponent(TT);
// X86 and x32 have 32 bit pointers.
if ((TT.isArch64Bit() &&
(TT.getEnvironment() == Triple::GNUX32 || TT.isOSNaCl())) ||
!TT.isArch64Bit())
Ret += "-p:32:32";
// Some ABIs align 64 bit integers and doubles to 64 bits, others to 32.
if (TT.isArch64Bit() || TT.isOSWindows() || TT.isOSNaCl())
Ret += "-i64:64";
else if (TT.isOSIAMCU())
Ret += "-i64:32-f64:32";
else
Ret += "-f64:32:64";
// Some ABIs align long double to 128 bits, others to 32.
if (TT.isOSNaCl() || TT.isOSIAMCU())
; // No f80
else if (TT.isArch64Bit() || TT.isOSDarwin())
Ret += "-f80:128";
else
Ret += "-f80:32";
if (TT.isOSIAMCU())
Ret += "-f128:32";
// The registers can hold 8, 16, 32 or, in x86-64, 64 bits.
if (TT.isArch64Bit())
Ret += "-n8:16:32:64";
else
Ret += "-n8:16:32";
// The stack is aligned to 32 bits on some ABIs and 128 bits on others.
if ((!TT.isArch64Bit() && TT.isOSWindows()) || TT.isOSIAMCU())
Ret += "-a:0:32-S32";
else
Ret += "-S128";
return Ret;
}
static Reloc::Model getEffectiveRelocModel(const Triple &TT,
bool JIT,
Optional<Reloc::Model> RM) {
bool is64Bit = TT.getArch() == Triple::x86_64;
if (!RM.hasValue()) {
// JIT codegen should use static relocations by default, since it's
// typically executed in process and not relocatable.
if (JIT)
return Reloc::Static;
// Darwin defaults to PIC in 64 bit mode and dynamic-no-pic in 32 bit mode.
// Win64 requires rip-rel addressing, thus we force it to PIC. Otherwise we
// use static relocation model by default.
if (TT.isOSDarwin()) {
if (is64Bit)
return Reloc::PIC_;
return Reloc::DynamicNoPIC;
}
if (TT.isOSWindows() && is64Bit)
return Reloc::PIC_;
return Reloc::Static;
}
// ELF and X86-64 don't have a distinct DynamicNoPIC model. DynamicNoPIC
// is defined as a model for code which may be used in static or dynamic
// executables but not necessarily a shared library. On X86-32 we just
// compile in -static mode, in x86-64 we use PIC.
if (*RM == Reloc::DynamicNoPIC) {
if (is64Bit)
return Reloc::PIC_;
if (!TT.isOSDarwin())
return Reloc::Static;
}
// If we are on Darwin, disallow static relocation model in X86-64 mode, since
// the Mach-O file format doesn't support it.
if (*RM == Reloc::Static && TT.isOSDarwin() && is64Bit)
return Reloc::PIC_;
return *RM;
}
static CodeModel::Model getEffectiveX86CodeModel(Optional<CodeModel::Model> CM,
bool JIT, bool Is64Bit) {
if (CM) {
if (*CM == CodeModel::Tiny)
report_fatal_error("Target does not support the tiny CodeModel");
return *CM;
}
if (JIT)
return Is64Bit ? CodeModel::Large : CodeModel::Small;
return CodeModel::Small;
}
/// Create an X86 target.
///
X86TargetMachine::X86TargetMachine(const Target &T, const Triple &TT,
StringRef CPU, StringRef FS,
const TargetOptions &Options,
Optional<Reloc::Model> RM,
Optional<CodeModel::Model> CM,
CodeGenOpt::Level OL, bool JIT)
: LLVMTargetMachine(
T, computeDataLayout(TT), TT, CPU, FS, Options,
getEffectiveRelocModel(TT, JIT, RM),
getEffectiveX86CodeModel(CM, JIT, TT.getArch() == Triple::x86_64),
OL),
TLOF(createTLOF(getTargetTriple())) {
// Windows stack unwinder gets confused when execution flow "falls through"
// after a call to 'noreturn' function.
// To prevent that, we emit a trap for 'unreachable' IR instructions.
// (which on X86, happens to be the 'ud2' instruction)
// On PS4, the "return address" of a 'noreturn' call must still be within
// the calling function, and TrapUnreachable is an easy way to get that.
// The check here for 64-bit windows is a bit icky, but as we're unlikely
// to ever want to mix 32 and 64-bit windows code in a single module
// this should be fine.
if ((TT.isOSWindows() && TT.getArch() == Triple::x86_64) || TT.isPS4() ||
TT.isOSBinFormatMachO()) {
this->Options.TrapUnreachable = true;
this->Options.NoTrapAfterNoreturn = TT.isOSBinFormatMachO();
}
// Outlining is available for x86-64.
if (TT.getArch() == Triple::x86_64)
setMachineOutliner(true);
initAsmInfo();
}
X86TargetMachine::~X86TargetMachine() = default;
const X86Subtarget *
X86TargetMachine::getSubtargetImpl(const Function &F) const {
Attribute CPUAttr = F.getFnAttribute("target-cpu");
Attribute FSAttr = F.getFnAttribute("target-features");
StringRef CPU = !CPUAttr.hasAttribute(Attribute::None)
? CPUAttr.getValueAsString()
: (StringRef)TargetCPU;
StringRef FS = !FSAttr.hasAttribute(Attribute::None)
? FSAttr.getValueAsString()
: (StringRef)TargetFS;
SmallString<512> Key;
Key.reserve(CPU.size() + FS.size());
Key += CPU;
Key += FS;
// FIXME: This is related to the code below to reset the target options,
// we need to know whether or not the soft float flag is set on the
// function before we can generate a subtarget. We also need to use
// it as a key for the subtarget since that can be the only difference
// between two functions.
bool SoftFloat =
F.getFnAttribute("use-soft-float").getValueAsString() == "true";
// If the soft float attribute is set on the function turn on the soft float
// subtarget feature.
if (SoftFloat)
Key += FS.empty() ? "+soft-float" : ",+soft-float";
// Keep track of the key width after all features are added so we can extract
// the feature string out later.
unsigned CPUFSWidth = Key.size();
// Extract prefer-vector-width attribute.
unsigned PreferVectorWidthOverride = 0;
if (F.hasFnAttribute("prefer-vector-width")) {
StringRef Val = F.getFnAttribute("prefer-vector-width").getValueAsString();
unsigned Width;
if (!Val.getAsInteger(0, Width)) {
Key += ",prefer-vector-width=";
Key += Val;
PreferVectorWidthOverride = Width;
}
}
// Extract min-legal-vector-width attribute.
unsigned RequiredVectorWidth = UINT32_MAX;
if (F.hasFnAttribute("min-legal-vector-width")) {
StringRef Val =
F.getFnAttribute("min-legal-vector-width").getValueAsString();
unsigned Width;
if (!Val.getAsInteger(0, Width)) {
Key += ",min-legal-vector-width=";
Key += Val;
RequiredVectorWidth = Width;
}
}
// Extracted here so that we make sure there is backing for the StringRef. If
// we assigned earlier, its possible the SmallString reallocated leaving a
// dangling StringRef.
FS = Key.slice(CPU.size(), CPUFSWidth);
auto &I = SubtargetMap[Key];
if (!I) {
// This needs to be done before we create a new subtarget since any
// creation will depend on the TM and the code generation flags on the
// function that reside in TargetOptions.
resetTargetOptions(F);
I = llvm::make_unique<X86Subtarget>(TargetTriple, CPU, FS, *this,
Options.StackAlignmentOverride,
PreferVectorWidthOverride,
RequiredVectorWidth);
}
return I.get();
}
//===----------------------------------------------------------------------===//
// Command line options for x86
//===----------------------------------------------------------------------===//
static cl::opt<bool>
UseVZeroUpper("x86-use-vzeroupper", cl::Hidden,
cl::desc("Minimize AVX to SSE transition penalty"),
cl::init(true));
//===----------------------------------------------------------------------===//
// X86 TTI query.
//===----------------------------------------------------------------------===//
TargetTransformInfo
X86TargetMachine::getTargetTransformInfo(const Function &F) {
return TargetTransformInfo(X86TTIImpl(this, F));
}
//===----------------------------------------------------------------------===//
// Pass Pipeline Configuration
//===----------------------------------------------------------------------===//
namespace {
/// X86 Code Generator Pass Configuration Options.
class X86PassConfig : public TargetPassConfig {
public:
X86PassConfig(X86TargetMachine &TM, PassManagerBase &PM)
: TargetPassConfig(TM, PM) {}
X86TargetMachine &getX86TargetMachine() const {
return getTM<X86TargetMachine>();
}
ScheduleDAGInstrs *
createMachineScheduler(MachineSchedContext *C) const override {
ScheduleDAGMILive *DAG = createGenericSchedLive(C);
DAG->addMutation(createX86MacroFusionDAGMutation());
return DAG;
}
void addIRPasses() override;
bool addInstSelector() override;
bool addIRTranslator() override;
bool addLegalizeMachineIR() override;
bool addRegBankSelect() override;
bool addGlobalInstructionSelect() override;
bool addILPOpts() override;
bool addPreISel() override;
void addMachineSSAOptimization() override;
void addPreRegAlloc() override;
void addPostRegAlloc() override;
void addPreEmitPass() override;
void addPreEmitPass2() override;
void addPreSched2() override;
};
class X86ExecutionDomainFix : public ExecutionDomainFix {
public:
static char ID;
X86ExecutionDomainFix() : ExecutionDomainFix(ID, X86::VR128XRegClass) {}
StringRef getPassName() const override {
return "X86 Execution Dependency Fix";
}
};
char X86ExecutionDomainFix::ID;
} // end anonymous namespace
INITIALIZE_PASS_BEGIN(X86ExecutionDomainFix, "x86-execution-domain-fix",
"X86 Execution Domain Fix", false, false)
INITIALIZE_PASS_DEPENDENCY(ReachingDefAnalysis)
INITIALIZE_PASS_END(X86ExecutionDomainFix, "x86-execution-domain-fix",
"X86 Execution Domain Fix", false, false)
TargetPassConfig *X86TargetMachine::createPassConfig(PassManagerBase &PM) {
return new X86PassConfig(*this, PM);
}
void X86PassConfig::addIRPasses() {
addPass(createAtomicExpandPass());
TargetPassConfig::addIRPasses();
if (TM->getOptLevel() != CodeGenOpt::None)
addPass(createInterleavedAccessPass());
// Add passes that handle indirect branch removal and insertion of a retpoline
// thunk. These will be a no-op unless a function subtarget has the retpoline
// feature enabled.
addPass(createIndirectBrExpandPass());
}
bool X86PassConfig::addInstSelector() {
// Install an instruction selector.
addPass(createX86ISelDag(getX86TargetMachine(), getOptLevel()));
// For ELF, cleanup any local-dynamic TLS accesses.
if (TM->getTargetTriple().isOSBinFormatELF() &&
getOptLevel() != CodeGenOpt::None)
addPass(createCleanupLocalDynamicTLSPass());
addPass(createX86GlobalBaseRegPass());
return false;
}
bool X86PassConfig::addIRTranslator() {
addPass(new IRTranslator());
return false;
}
bool X86PassConfig::addLegalizeMachineIR() {
addPass(new Legalizer());
return false;
}
bool X86PassConfig::addRegBankSelect() {
addPass(new RegBankSelect());
return false;
}
bool X86PassConfig::addGlobalInstructionSelect() {
addPass(new InstructionSelect());
return false;
}
bool X86PassConfig::addILPOpts() {
if (EnableCondBrFoldingPass)
addPass(createX86CondBrFolding());
addPass(&EarlyIfConverterID);
if (EnableMachineCombinerPass)
addPass(&MachineCombinerID);
addPass(createX86CmovConverterPass());
return true;
}
bool X86PassConfig::addPreISel() {
// Only add this pass for 32-bit x86 Windows.
const Triple &TT = TM->getTargetTriple();
if (TT.isOSWindows() && TT.getArch() == Triple::x86)
addPass(createX86WinEHStatePass());
return true;
}
void X86PassConfig::addPreRegAlloc() {
if (getOptLevel() != CodeGenOpt::None) {
addPass(&LiveRangeShrinkID);
addPass(createX86FixupSetCC());
addPass(createX86OptimizeLEAs());
addPass(createX86CallFrameOptimization());
addPass(createX86AvoidStoreForwardingBlocks());
}
addPass(createX86SpeculativeLoadHardeningPass());
addPass(createX86FlagsCopyLoweringPass());
addPass(createX86WinAllocaExpander());
}
void X86PassConfig::addMachineSSAOptimization() {
addPass(createX86DomainReassignmentPass());
TargetPassConfig::addMachineSSAOptimization();
}
void X86PassConfig::addPostRegAlloc() {
addPass(createX86FloatingPointStackifierPass());
}
void X86PassConfig::addPreSched2() { addPass(createX86ExpandPseudoPass()); }
void X86PassConfig::addPreEmitPass() {
if (getOptLevel() != CodeGenOpt::None) {
addPass(new X86ExecutionDomainFix());
addPass(createBreakFalseDeps());
}
addPass(createShadowCallStackPass());
addPass(createX86IndirectBranchTrackingPass());
if (UseVZeroUpper)
addPass(createX86IssueVZeroUpperPass());
if (getOptLevel() != CodeGenOpt::None) {
addPass(createX86FixupBWInsts());
addPass(createX86PadShortFunctions());
addPass(createX86FixupLEAs());
addPass(createX86EvexToVexInsts());
}
addPass(createX86DiscriminateMemOpsPass());
addPass(createX86InsertPrefetchPass());
}
void X86PassConfig::addPreEmitPass2() {
addPass(createX86RetpolineThunksPass());
// Verify basic block incoming and outgoing cfa offset and register values and
// correct CFA calculation rule where needed by inserting appropriate CFI
// instructions.
const Triple &TT = TM->getTargetTriple();
- if (!TT.isOSDarwin() && !TT.isOSWindows())
+ const MCAsmInfo *MAI = TM->getMCAsmInfo();
+ if (!TT.isOSDarwin() &&
+ (!TT.isOSWindows() ||
+ MAI->getExceptionHandlingType() == ExceptionHandling::DwarfCFI))
addPass(createCFIInstrInserter());
}
Index: stable/11/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp
===================================================================
--- stable/11/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp (revision 350259)
@@ -1,3488 +1,3491 @@
//===--- MicrosoftMangle.cpp - Microsoft Visual C++ Name Mangling ---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This provides C++ name mangling targeting the Microsoft Visual C++ ABI.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.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/VTableBuilder.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/JamCRC.h"
#include "llvm/Support/xxhash.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
using namespace clang;
namespace {
struct msvc_hashing_ostream : public llvm::raw_svector_ostream {
raw_ostream &OS;
llvm::SmallString<64> Buffer;
msvc_hashing_ostream(raw_ostream &OS)
: llvm::raw_svector_ostream(Buffer), OS(OS) {}
~msvc_hashing_ostream() override {
StringRef MangledName = str();
bool StartsWithEscape = MangledName.startswith("\01");
if (StartsWithEscape)
MangledName = MangledName.drop_front(1);
if (MangledName.size() <= 4096) {
OS << str();
return;
}
llvm::MD5 Hasher;
llvm::MD5::MD5Result Hash;
Hasher.update(MangledName);
Hasher.final(Hash);
SmallString<32> HexString;
llvm::MD5::stringifyResult(Hash, HexString);
if (StartsWithEscape)
OS << '\01';
OS << "??@" << HexString << '@';
}
};
static const DeclContext *
getLambdaDefaultArgumentDeclContext(const Decl *D) {
if (const auto *RD = dyn_cast<CXXRecordDecl>(D))
if (RD->isLambda())
if (const auto *Parm =
dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl()))
return Parm->getDeclContext();
return nullptr;
}
/// Retrieve the declaration context that should be used when mangling
/// the given declaration.
static const DeclContext *getEffectiveDeclContext(const Decl *D) {
// The ABI assumes that lambda closure types that occur within
// default arguments live in the context of the function. However, due to
// the way in which Clang parses and creates function declarations, this is
// not the case: the lambda closure type ends up living in the context
// where the function itself resides, because the function declaration itself
// had not yet been created. Fix the context here.
if (const auto *LDADC = getLambdaDefaultArgumentDeclContext(D))
return LDADC;
// Perform the same check for block literals.
if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
if (ParmVarDecl *ContextParam =
dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl()))
return ContextParam->getDeclContext();
}
const DeclContext *DC = D->getDeclContext();
if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC)) {
return getEffectiveDeclContext(cast<Decl>(DC));
}
return DC->getRedeclContext();
}
static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
return getEffectiveDeclContext(cast<Decl>(DC));
}
static const FunctionDecl *getStructor(const NamedDecl *ND) {
if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(ND))
return FTD->getTemplatedDecl()->getCanonicalDecl();
const auto *FD = cast<FunctionDecl>(ND);
if (const auto *FTD = FD->getPrimaryTemplate())
return FTD->getTemplatedDecl()->getCanonicalDecl();
return FD->getCanonicalDecl();
}
/// MicrosoftMangleContextImpl - Overrides the default MangleContext for the
/// Microsoft Visual C++ ABI.
class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
typedef std::pair<const DeclContext *, IdentifierInfo *> DiscriminatorKeyTy;
llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds;
llvm::DenseMap<const NamedDecl *, unsigned> SEHFinallyIds;
SmallString<16> AnonymousNamespaceHash;
public:
MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags);
bool shouldMangleCXXName(const NamedDecl *D) override;
bool shouldMangleStringLiteral(const StringLiteral *SL) override;
void mangleCXXName(const NamedDecl *D, raw_ostream &Out) override;
void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
const MethodVFTableLocation &ML,
raw_ostream &Out) override;
void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk,
raw_ostream &) override;
void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &ThisAdjustment,
raw_ostream &) override;
void mangleCXXVFTable(const CXXRecordDecl *Derived,
ArrayRef<const CXXRecordDecl *> BasePath,
raw_ostream &Out) override;
void mangleCXXVBTable(const CXXRecordDecl *Derived,
ArrayRef<const CXXRecordDecl *> BasePath,
raw_ostream &Out) override;
void mangleCXXVirtualDisplacementMap(const CXXRecordDecl *SrcRD,
const CXXRecordDecl *DstRD,
raw_ostream &Out) override;
void mangleCXXThrowInfo(QualType T, bool IsConst, bool IsVolatile,
bool IsUnaligned, uint32_t NumEntries,
raw_ostream &Out) override;
void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries,
raw_ostream &Out) override;
void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD,
CXXCtorType CT, uint32_t Size, uint32_t NVOffset,
int32_t VBPtrOffset, uint32_t VBIndex,
raw_ostream &Out) override;
void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
void mangleCXXRTTIName(QualType T, raw_ostream &Out) override;
void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
uint32_t NVOffset, int32_t VBPtrOffset,
uint32_t VBTableOffset, uint32_t Flags,
raw_ostream &Out) override;
void mangleCXXRTTIBaseClassArray(const CXXRecordDecl *Derived,
raw_ostream &Out) override;
void mangleCXXRTTIClassHierarchyDescriptor(const CXXRecordDecl *Derived,
raw_ostream &Out) override;
void
mangleCXXRTTICompleteObjectLocator(const CXXRecordDecl *Derived,
ArrayRef<const CXXRecordDecl *> BasePath,
raw_ostream &Out) override;
void mangleTypeName(QualType T, raw_ostream &) override;
void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
raw_ostream &) override;
void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
raw_ostream &) override;
void mangleReferenceTemporary(const VarDecl *, unsigned ManglingNumber,
raw_ostream &) override;
void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out) override;
void mangleThreadSafeStaticGuardVariable(const VarDecl *D, unsigned GuardNum,
raw_ostream &Out) override;
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) override;
void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
raw_ostream &Out) override;
void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
raw_ostream &Out) override;
void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
const DeclContext *DC = getEffectiveDeclContext(ND);
if (!DC->isFunctionOrMethod())
return false;
// Lambda closure types are already numbered, give out a phony number so
// that they demangle nicely.
if (const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
if (RD->isLambda()) {
disc = 1;
return true;
}
}
// Use the canonical number for externally visible decls.
if (ND->isExternallyVisible()) {
disc = getASTContext().getManglingNumber(ND);
return true;
}
// Anonymous tags are already numbered.
if (const TagDecl *Tag = dyn_cast<TagDecl>(ND)) {
if (!Tag->hasNameForLinkage() &&
!getASTContext().getDeclaratorForUnnamedTagDecl(Tag) &&
!getASTContext().getTypedefNameForUnnamedTagDecl(Tag))
return false;
}
// Make up a reasonable number for internal decls.
unsigned &discriminator = Uniquifier[ND];
if (!discriminator)
discriminator = ++Discriminator[std::make_pair(DC, ND->getIdentifier())];
disc = discriminator + 1;
return true;
}
unsigned getLambdaId(const CXXRecordDecl *RD) {
assert(RD->isLambda() && "RD must be a lambda!");
assert(!RD->isExternallyVisible() && "RD must not be visible!");
assert(RD->getLambdaManglingNumber() == 0 &&
"RD must not have a mangling number!");
std::pair<llvm::DenseMap<const CXXRecordDecl *, unsigned>::iterator, bool>
Result = LambdaIds.insert(std::make_pair(RD, LambdaIds.size()));
return Result.first->second;
}
/// Return a character sequence that is (somewhat) unique to the TU suitable
/// for mangling anonymous namespaces.
StringRef getAnonymousNamespaceHash() const {
return AnonymousNamespaceHash;
}
private:
void mangleInitFiniStub(const VarDecl *D, char CharCode, raw_ostream &Out);
};
/// MicrosoftCXXNameMangler - Manage the mangling of a single name for the
/// Microsoft Visual C++ ABI.
class MicrosoftCXXNameMangler {
MicrosoftMangleContextImpl &Context;
raw_ostream &Out;
/// The "structor" is the top-level declaration being mangled, if
/// that's not a template specialization; otherwise it's the pattern
/// for that specialization.
const NamedDecl *Structor;
unsigned StructorType;
typedef llvm::SmallVector<std::string, 10> BackRefVec;
BackRefVec NameBackReferences;
typedef llvm::DenseMap<const void *, unsigned> ArgBackRefMap;
ArgBackRefMap TypeBackReferences;
typedef std::set<int> PassObjectSizeArgsSet;
PassObjectSizeArgsSet PassObjectSizeArgs;
ASTContext &getASTContext() const { return Context.getASTContext(); }
// FIXME: If we add support for __ptr32/64 qualifiers, then we should push
// this check into mangleQualifiers().
const bool PointersAre64Bit;
public:
enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result };
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_)
: Context(C), Out(Out_), Structor(nullptr), StructorType(-1),
PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
64) {}
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
const CXXConstructorDecl *D, CXXCtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
64) {}
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
64) {}
raw_ostream &getStream() const { return Out; }
void mangle(const NamedDecl *D, StringRef Prefix = "?");
void mangleName(const NamedDecl *ND);
void mangleFunctionEncoding(const FunctionDecl *FD, bool ShouldMangle);
void mangleVariableEncoding(const VarDecl *VD);
void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD);
void mangleMemberFunctionPointer(const CXXRecordDecl *RD,
const CXXMethodDecl *MD);
void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
const MethodVFTableLocation &ML);
void mangleNumber(int64_t Number);
void mangleTagTypeKind(TagTypeKind TK);
void mangleArtificialTagType(TagTypeKind TK, StringRef UnqualifiedName,
ArrayRef<StringRef> NestedNames = None);
void mangleAddressSpaceType(QualType T, Qualifiers Quals, SourceRange Range);
void mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM = QMM_Mangle);
void mangleFunctionType(const FunctionType *T,
const FunctionDecl *D = nullptr,
bool ForceThisQuals = false,
bool MangleExceptionSpec = true);
void mangleNestedName(const NamedDecl *ND);
private:
bool isStructorDecl(const NamedDecl *ND) const {
return ND == Structor || getStructor(ND) == Structor;
}
void mangleUnqualifiedName(const NamedDecl *ND) {
mangleUnqualifiedName(ND, ND->getDeclName());
}
void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name);
void mangleSourceName(StringRef Name);
void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
void mangleCXXDtorType(CXXDtorType T);
void mangleQualifiers(Qualifiers Quals, bool IsMember);
void mangleRefQualifier(RefQualifierKind RefQualifier);
void manglePointerCVQualifiers(Qualifiers Quals);
void manglePointerExtQualifiers(Qualifiers Quals, QualType PointeeType);
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void
mangleTemplateInstantiationName(const TemplateDecl *TD,
const TemplateArgumentList &TemplateArgs);
void mangleObjCMethodName(const ObjCMethodDecl *MD);
void mangleArgumentType(QualType T, SourceRange Range);
void manglePassObjectSizeArg(const PassObjectSizeAttr *POSA);
bool isArtificialTagType(QualType T) const;
// Declare manglers for every type class.
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T, \
Qualifiers Quals, \
SourceRange Range);
#include "clang/AST/TypeNodes.def"
#undef ABSTRACT_TYPE
#undef NON_CANONICAL_TYPE
#undef TYPE
void mangleType(const TagDecl *TD);
void mangleDecayedArrayType(const ArrayType *T);
void mangleArrayType(const ArrayType *T);
void mangleFunctionClass(const FunctionDecl *FD);
void mangleCallingConvention(CallingConv CC);
void mangleCallingConvention(const FunctionType *T);
void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean);
void mangleExpression(const Expr *E);
void mangleThrowSpecification(const FunctionProtoType *T);
void mangleTemplateArgs(const TemplateDecl *TD,
const TemplateArgumentList &TemplateArgs);
void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA,
const NamedDecl *Parm);
void mangleObjCProtocol(const ObjCProtocolDecl *PD);
void mangleObjCLifetime(const QualType T, Qualifiers Quals,
SourceRange Range);
void mangleObjCKindOfType(const ObjCObjectType *T, Qualifiers Quals,
SourceRange Range);
};
}
MicrosoftMangleContextImpl::MicrosoftMangleContextImpl(ASTContext &Context,
DiagnosticsEngine &Diags)
: MicrosoftMangleContext(Context, Diags) {
// To mangle anonymous namespaces, hash the path to the main source file. The
// path should be whatever (probably relative) path was passed on the command
// line. The goal is for the compiler to produce the same output regardless of
// working directory, so use the uncanonicalized relative path.
//
// It's important to make the mangled names unique because, when CodeView
// debug info is in use, the debugger uses mangled type names to distinguish
// between otherwise identically named types in anonymous namespaces.
//
// These symbols are always internal, so there is no need for the hash to
// match what MSVC produces. For the same reason, clang is free to change the
// hash at any time without breaking compatibility with old versions of clang.
// The generated names are intended to look similar to what MSVC generates,
// which are something like "?A0x01234567@".
SourceManager &SM = Context.getSourceManager();
if (const FileEntry *FE = SM.getFileEntryForID(SM.getMainFileID())) {
// Truncate the hash so we get 8 characters of hexadecimal.
uint32_t TruncatedHash = uint32_t(xxHash64(FE->getName()));
AnonymousNamespaceHash = llvm::utohexstr(TruncatedHash);
} else {
// If we don't have a path to the main file, we'll just use 0.
AnonymousNamespaceHash = "0";
}
}
bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
LanguageLinkage L = FD->getLanguageLinkage();
// Overloadable functions need mangling.
if (FD->hasAttr<OverloadableAttr>())
return true;
// The ABI expects that we would never mangle "typical" user-defined entry
// points regardless of visibility or freestanding-ness.
//
// N.B. This is distinct from asking about "main". "main" has a lot of
// special rules associated with it in the standard while these
// user-defined entry points are outside of the purview of the standard.
// For example, there can be only one definition for "main" in a standards
// compliant program; however nothing forbids the existence of wmain and
// WinMain in the same translation unit.
if (FD->isMSVCRTEntryPoint())
return false;
// C++ functions and those whose names are not a simple identifier need
// mangling.
if (!FD->getDeclName().isIdentifier() || L == CXXLanguageLinkage)
return true;
// C functions are not mangled.
if (L == CLanguageLinkage)
return false;
}
// Otherwise, no mangling is done outside C++ mode.
if (!getASTContext().getLangOpts().CPlusPlus)
return false;
const VarDecl *VD = dyn_cast<VarDecl>(D);
if (VD && !isa<DecompositionDecl>(D)) {
// C variables are not mangled.
if (VD->isExternC())
return false;
// Variables at global scope with non-internal linkage are not mangled.
const DeclContext *DC = getEffectiveDeclContext(D);
// Check for extern variable declared locally.
if (DC->isFunctionOrMethod() && D->hasLinkage())
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = getEffectiveParentContext(DC);
if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage &&
!isa<VarTemplateSpecializationDecl>(D) &&
D->getIdentifier() != nullptr)
return false;
}
return true;
}
bool
MicrosoftMangleContextImpl::shouldMangleStringLiteral(const StringLiteral *SL) {
return true;
}
void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
// MSVC doesn't mangle C++ names the same way it mangles extern "C" names.
// Therefore it's really important that we don't decorate the
// name with leading underscores or leading/trailing at signs. So, by
// default, we emit an asm marker at the start so we get the name right.
// Callers can override this with a custom prefix.
// <mangled-name> ::= ? <name> <type-encoding>
Out << Prefix;
mangleName(D);
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
mangleFunctionEncoding(FD, Context.shouldMangleDeclName(FD));
else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
mangleVariableEncoding(VD);
else
llvm_unreachable("Tried to mangle unexpected NamedDecl!");
}
void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD,
bool ShouldMangle) {
// <type-encoding> ::= <function-class> <function-type>
// Since MSVC operates on the type as written and not the canonical type, it
// actually matters which decl we have here. MSVC appears to choose the
// first, since it is most likely to be the declaration in a header file.
FD = FD->getFirstDecl();
// We should never ever see a FunctionNoProtoType at this point.
// We don't even know how to mangle their types anyway :).
const FunctionProtoType *FT = FD->getType()->castAs<FunctionProtoType>();
// extern "C" functions can hold entities that must be mangled.
// As it stands, these functions still need to get expressed in the full
// external name. They have their class and type omitted, replaced with '9'.
if (ShouldMangle) {
// We would like to mangle all extern "C" functions using this additional
// component but this would break compatibility with MSVC's behavior.
// Instead, do this when we know that compatibility isn't important (in
// other words, when it is an overloaded extern "C" function).
if (FD->isExternC() && FD->hasAttr<OverloadableAttr>())
Out << "$$J0";
mangleFunctionClass(FD);
mangleFunctionType(FT, FD, false, false);
} else {
Out << '9';
}
}
void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
// <type-encoding> ::= <storage-class> <variable-type>
// <storage-class> ::= 0 # private static member
// ::= 1 # protected static member
// ::= 2 # public static member
// ::= 3 # global
// ::= 4 # static local
// The first character in the encoding (after the name) is the storage class.
if (VD->isStaticDataMember()) {
// If it's a static member, it also encodes the access level.
switch (VD->getAccess()) {
default:
case AS_private: Out << '0'; break;
case AS_protected: Out << '1'; break;
case AS_public: Out << '2'; break;
}
}
else if (!VD->isStaticLocal())
Out << '3';
else
Out << '4';
// Now mangle the type.
// <variable-type> ::= <type> <cvr-qualifiers>
// ::= <type> <pointee-cvr-qualifiers> # pointers, references
// Pointers and references are odd. The type of 'int * const foo;' gets
// mangled as 'QAHA' instead of 'PAHB', for example.
SourceRange SR = VD->getSourceRange();
QualType Ty = VD->getType();
if (Ty->isPointerType() || Ty->isReferenceType() ||
Ty->isMemberPointerType()) {
mangleType(Ty, SR, QMM_Drop);
manglePointerExtQualifiers(
Ty.getDesugaredType(getASTContext()).getLocalQualifiers(), QualType());
if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()) {
mangleQualifiers(MPT->getPointeeType().getQualifiers(), true);
// Member pointers are suffixed with a back reference to the member
// pointer's class name.
mangleName(MPT->getClass()->getAsCXXRecordDecl());
} else
mangleQualifiers(Ty->getPointeeType().getQualifiers(), false);
} else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) {
// Global arrays are funny, too.
mangleDecayedArrayType(AT);
if (AT->getElementType()->isArrayType())
Out << 'A';
else
mangleQualifiers(Ty.getQualifiers(), false);
} else {
mangleType(Ty, SR, QMM_Drop);
mangleQualifiers(Ty.getQualifiers(), false);
}
}
void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
const ValueDecl *VD) {
// <member-data-pointer> ::= <integer-literal>
// ::= $F <number> <number>
// ::= $G <number> <number> <number>
int64_t FieldOffset;
int64_t VBTableOffset;
MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel();
if (VD) {
FieldOffset = getASTContext().getFieldOffset(VD);
assert(FieldOffset % getASTContext().getCharWidth() == 0 &&
"cannot take address of bitfield");
FieldOffset /= getASTContext().getCharWidth();
VBTableOffset = 0;
if (IM == MSInheritanceAttr::Keyword_virtual_inheritance)
FieldOffset -= getASTContext().getOffsetOfBaseWithVBPtr(RD).getQuantity();
} else {
FieldOffset = RD->nullFieldOffsetIsZero() ? 0 : -1;
VBTableOffset = -1;
}
char Code = '\0';
switch (IM) {
case MSInheritanceAttr::Keyword_single_inheritance: Code = '0'; break;
case MSInheritanceAttr::Keyword_multiple_inheritance: Code = '0'; break;
case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'F'; break;
case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'G'; break;
}
Out << '$' << Code;
mangleNumber(FieldOffset);
// The C++ standard doesn't allow base-to-derived member pointer conversions
// in template parameter contexts, so the vbptr offset of data member pointers
// is always zero.
if (MSInheritanceAttr::hasVBPtrOffsetField(IM))
mangleNumber(0);
if (MSInheritanceAttr::hasVBTableOffsetField(IM))
mangleNumber(VBTableOffset);
}
void
MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
const CXXMethodDecl *MD) {
// <member-function-pointer> ::= $1? <name>
// ::= $H? <name> <number>
// ::= $I? <name> <number> <number>
// ::= $J? <name> <number> <number> <number>
MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel();
char Code = '\0';
switch (IM) {
case MSInheritanceAttr::Keyword_single_inheritance: Code = '1'; break;
case MSInheritanceAttr::Keyword_multiple_inheritance: Code = 'H'; break;
case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'I'; break;
case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'J'; break;
}
// If non-virtual, mangle the name. If virtual, mangle as a virtual memptr
// thunk.
uint64_t NVOffset = 0;
uint64_t VBTableOffset = 0;
uint64_t VBPtrOffset = 0;
if (MD) {
Out << '$' << Code << '?';
if (MD->isVirtual()) {
MicrosoftVTableContext *VTContext =
cast<MicrosoftVTableContext>(getASTContext().getVTableContext());
MethodVFTableLocation ML =
VTContext->getMethodVFTableLocation(GlobalDecl(MD));
mangleVirtualMemPtrThunk(MD, ML);
NVOffset = ML.VFPtrOffset.getQuantity();
VBTableOffset = ML.VBTableIndex * 4;
if (ML.VBase) {
const ASTRecordLayout &Layout = getASTContext().getASTRecordLayout(RD);
VBPtrOffset = Layout.getVBPtrOffset().getQuantity();
}
} else {
mangleName(MD);
mangleFunctionEncoding(MD, /*ShouldMangle=*/true);
}
if (VBTableOffset == 0 &&
IM == MSInheritanceAttr::Keyword_virtual_inheritance)
NVOffset -= getASTContext().getOffsetOfBaseWithVBPtr(RD).getQuantity();
} else {
// Null single inheritance member functions are encoded as a simple nullptr.
if (IM == MSInheritanceAttr::Keyword_single_inheritance) {
Out << "$0A@";
return;
}
if (IM == MSInheritanceAttr::Keyword_unspecified_inheritance)
VBTableOffset = -1;
Out << '$' << Code;
}
if (MSInheritanceAttr::hasNVOffsetField(/*IsMemberFunction=*/true, IM))
mangleNumber(static_cast<uint32_t>(NVOffset));
if (MSInheritanceAttr::hasVBPtrOffsetField(IM))
mangleNumber(VBPtrOffset);
if (MSInheritanceAttr::hasVBTableOffsetField(IM))
mangleNumber(VBTableOffset);
}
void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk(
const CXXMethodDecl *MD, const MethodVFTableLocation &ML) {
// Get the vftable offset.
CharUnits PointerWidth = getASTContext().toCharUnitsFromBits(
getASTContext().getTargetInfo().getPointerWidth(0));
uint64_t OffsetInVFTable = ML.Index * PointerWidth.getQuantity();
Out << "?_9";
mangleName(MD->getParent());
Out << "$B";
mangleNumber(OffsetInVFTable);
Out << 'A';
mangleCallingConvention(MD->getType()->getAs<FunctionProtoType>());
}
void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
// <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @
// Always start with the unqualified name.
mangleUnqualifiedName(ND);
mangleNestedName(ND);
// Terminate the whole name with an '@'.
Out << '@';
}
void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
// <non-negative integer> ::= A@ # when Number == 0
// ::= <decimal digit> # when 1 <= Number <= 10
// ::= <hex digit>+ @ # when Number >= 10
//
// <number> ::= [?] <non-negative integer>
uint64_t Value = static_cast<uint64_t>(Number);
if (Number < 0) {
Value = -Value;
Out << '?';
}
if (Value == 0)
Out << "A@";
else if (Value >= 1 && Value <= 10)
Out << (Value - 1);
else {
// Numbers that are not encoded as decimal digits are represented as nibbles
// in the range of ASCII characters 'A' to 'P'.
// The number 0x123450 would be encoded as 'BCDEFA'
char EncodedNumberBuffer[sizeof(uint64_t) * 2];
MutableArrayRef<char> BufferRef(EncodedNumberBuffer);
MutableArrayRef<char>::reverse_iterator I = BufferRef.rbegin();
for (; Value != 0; Value >>= 4)
*I++ = 'A' + (Value & 0xf);
Out.write(I.base(), I - BufferRef.rbegin());
Out << '@';
}
}
static const TemplateDecl *
isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
// Check if we have a function template.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
TemplateArgs = FD->getTemplateSpecializationArgs();
return TD;
}
}
// Check if we have a class template.
if (const ClassTemplateSpecializationDecl *Spec =
dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
TemplateArgs = &Spec->getTemplateArgs();
return Spec->getSpecializedTemplate();
}
// Check if we have a variable template.
if (const VarTemplateSpecializationDecl *Spec =
dyn_cast<VarTemplateSpecializationDecl>(ND)) {
TemplateArgs = &Spec->getTemplateArgs();
return Spec->getSpecializedTemplate();
}
return nullptr;
}
void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
DeclarationName Name) {
// <unqualified-name> ::= <operator-name>
// ::= <ctor-dtor-name>
// ::= <source-name>
// ::= <template-name>
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = nullptr;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
// Function templates aren't considered for name back referencing. This
// makes sense since function templates aren't likely to occur multiple
// times in a symbol.
if (isa<FunctionTemplateDecl>(TD)) {
mangleTemplateInstantiationName(TD, *TemplateArgs);
Out << '@';
return;
}
// Here comes the tricky thing: if we need to mangle something like
// void foo(A::X<Y>, B::X<Y>),
// the X<Y> part is aliased. However, if you need to mangle
// void foo(A::X<A::Y>, A::X<B::Y>),
// the A::X<> part is not aliased.
// That said, from the mangler's perspective we have a structure like this:
// namespace[s] -> type[ -> template-parameters]
// but from the Clang perspective we have
// type [ -> template-parameters]
// \-> namespace[s]
// What we do is we create a new mangler, mangle the same type (without
// a namespace suffix) to a string using the extra mangler and then use
// the mangled type name as a key to check the mangling of different types
// for aliasing.
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
MicrosoftCXXNameMangler Extra(Context, Stream);
Extra.mangleTemplateInstantiationName(TD, *TemplateArgs);
mangleSourceName(TemplateMangling);
return;
}
switch (Name.getNameKind()) {
case DeclarationName::Identifier: {
if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
mangleSourceName(II->getName());
break;
}
// Otherwise, an anonymous entity. We must have a declaration.
assert(ND && "mangling empty name without declaration");
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
if (NS->isAnonymousNamespace()) {
Out << "?A0x" << Context.getAnonymousNamespaceHash() << '@';
break;
}
}
if (const DecompositionDecl *DD = dyn_cast<DecompositionDecl>(ND)) {
// FIXME: Invented mangling for decomposition declarations:
// [X,Y,Z]
// where X,Y,Z are the names of the bindings.
llvm::SmallString<128> Name("[");
for (auto *BD : DD->bindings()) {
if (Name.size() > 1)
Name += ',';
Name += BD->getDeclName().getAsIdentifierInfo()->getName();
}
Name += ']';
mangleSourceName(Name);
break;
}
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
// We must have an anonymous union or struct declaration.
const CXXRecordDecl *RD = VD->getType()->getAsCXXRecordDecl();
assert(RD && "expected variable decl to have a record type");
// Anonymous types with no tag or typedef get the name of their
// declarator mangled in. If they have no declarator, number them with
// a $S prefix.
llvm::SmallString<64> Name("$S");
// Get a unique id for the anonymous struct.
Name += llvm::utostr(Context.getAnonymousStructId(RD) + 1);
mangleSourceName(Name.str());
break;
}
// We must have an anonymous struct.
const TagDecl *TD = cast<TagDecl>(ND);
if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
assert(TD->getDeclContext() == D->getDeclContext() &&
"Typedef should not be in another decl context!");
assert(D->getDeclName().getAsIdentifierInfo() &&
"Typedef was not named!");
mangleSourceName(D->getDeclName().getAsIdentifierInfo()->getName());
break;
}
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
if (Record->isLambda()) {
llvm::SmallString<10> Name("<lambda_");
Decl *LambdaContextDecl = Record->getLambdaContextDecl();
unsigned LambdaManglingNumber = Record->getLambdaManglingNumber();
unsigned LambdaId;
const ParmVarDecl *Parm =
dyn_cast_or_null<ParmVarDecl>(LambdaContextDecl);
const FunctionDecl *Func =
Parm ? dyn_cast<FunctionDecl>(Parm->getDeclContext()) : nullptr;
if (Func) {
unsigned DefaultArgNo =
Func->getNumParams() - Parm->getFunctionScopeIndex();
Name += llvm::utostr(DefaultArgNo);
Name += "_";
}
if (LambdaManglingNumber)
LambdaId = LambdaManglingNumber;
else
LambdaId = Context.getLambdaId(Record);
Name += llvm::utostr(LambdaId);
Name += ">";
mangleSourceName(Name);
// If the context of a closure type is an initializer for a class
// member (static or nonstatic), it is encoded in a qualified name.
if (LambdaManglingNumber && LambdaContextDecl) {
if ((isa<VarDecl>(LambdaContextDecl) ||
isa<FieldDecl>(LambdaContextDecl)) &&
LambdaContextDecl->getDeclContext()->isRecord()) {
mangleUnqualifiedName(cast<NamedDecl>(LambdaContextDecl));
}
}
break;
}
}
llvm::SmallString<64> Name;
if (DeclaratorDecl *DD =
Context.getASTContext().getDeclaratorForUnnamedTagDecl(TD)) {
// Anonymous types without a name for linkage purposes have their
// declarator mangled in if they have one.
Name += "<unnamed-type-";
Name += DD->getName();
} else if (TypedefNameDecl *TND =
Context.getASTContext().getTypedefNameForUnnamedTagDecl(
TD)) {
// Anonymous types without a name for linkage purposes have their
// associate typedef mangled in if they have one.
Name += "<unnamed-type-";
Name += TND->getName();
} else if (isa<EnumDecl>(TD) &&
cast<EnumDecl>(TD)->enumerator_begin() !=
cast<EnumDecl>(TD)->enumerator_end()) {
// Anonymous non-empty enums mangle in the first enumerator.
auto *ED = cast<EnumDecl>(TD);
Name += "<unnamed-enum-";
Name += ED->enumerator_begin()->getName();
} else {
// Otherwise, number the types using a $S prefix.
Name += "<unnamed-type-$S";
Name += llvm::utostr(Context.getAnonymousStructId(TD) + 1);
}
Name += ">";
mangleSourceName(Name.str());
break;
}
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector: {
// This is reachable only when constructing an outlined SEH finally
// block. Nothing depends on this mangling and it's used only with
// functinos with internal linkage.
llvm::SmallString<64> Name;
mangleSourceName(Name.str());
break;
}
case DeclarationName::CXXConstructorName:
if (isStructorDecl(ND)) {
if (StructorType == Ctor_CopyingClosure) {
Out << "?_O";
return;
}
if (StructorType == Ctor_DefaultClosure) {
Out << "?_F";
return;
}
}
Out << "?0";
return;
case DeclarationName::CXXDestructorName:
if (isStructorDecl(ND))
// If the named decl is the C++ destructor we're mangling,
// use the type we were given.
mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
else
// Otherwise, use the base destructor name. This is relevant if a
// class with a destructor is declared within a destructor.
mangleCXXDtorType(Dtor_Base);
break;
case DeclarationName::CXXConversionFunctionName:
// <operator-name> ::= ?B # (cast)
// The target type is encoded as the return type.
Out << "?B";
break;
case DeclarationName::CXXOperatorName:
mangleOperatorName(Name.getCXXOverloadedOperator(), ND->getLocation());
break;
case DeclarationName::CXXLiteralOperatorName: {
Out << "?__K";
mangleSourceName(Name.getCXXLiteralIdentifier()->getName());
break;
}
case DeclarationName::CXXDeductionGuideName:
llvm_unreachable("Can't mangle a deduction guide name!");
case DeclarationName::CXXUsingDirective:
llvm_unreachable("Can't mangle a using directive name!");
}
}
// <postfix> ::= <unqualified-name> [<postfix>]
// ::= <substitution> [<postfix>]
void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) {
const DeclContext *DC = getEffectiveDeclContext(ND);
while (!DC->isTranslationUnit()) {
if (isa<TagDecl>(ND) || isa<VarDecl>(ND)) {
unsigned Disc;
if (Context.getNextDiscriminator(ND, Disc)) {
Out << '?';
mangleNumber(Disc);
Out << '?';
}
}
if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
auto Discriminate =
[](StringRef Name, const unsigned Discriminator,
const unsigned ParameterDiscriminator) -> std::string {
std::string Buffer;
llvm::raw_string_ostream Stream(Buffer);
Stream << Name;
if (Discriminator)
Stream << '_' << Discriminator;
if (ParameterDiscriminator)
Stream << '_' << ParameterDiscriminator;
return Stream.str();
};
unsigned Discriminator = BD->getBlockManglingNumber();
if (!Discriminator)
Discriminator = Context.getBlockId(BD, /*Local=*/false);
// Mangle the parameter position as a discriminator to deal with unnamed
// parameters. Rather than mangling the unqualified parameter name,
// always use the position to give a uniform mangling.
unsigned ParameterDiscriminator = 0;
if (const auto *MC = BD->getBlockManglingContextDecl())
if (const auto *P = dyn_cast<ParmVarDecl>(MC))
if (const auto *F = dyn_cast<FunctionDecl>(P->getDeclContext()))
ParameterDiscriminator =
F->getNumParams() - P->getFunctionScopeIndex();
DC = getEffectiveDeclContext(BD);
Out << '?';
mangleSourceName(Discriminate("_block_invoke", Discriminator,
ParameterDiscriminator));
// If we have a block mangling context, encode that now. This allows us
// to discriminate between named static data initializers in the same
// scope. This is handled differently from parameters, which use
// positions to discriminate between multiple instances.
if (const auto *MC = BD->getBlockManglingContextDecl())
if (!isa<ParmVarDecl>(MC))
if (const auto *ND = dyn_cast<NamedDecl>(MC))
mangleUnqualifiedName(ND);
// MS ABI and Itanium manglings are in inverted scopes. In the case of a
// RecordDecl, mangle the entire scope hierarchy at this point rather than
// just the unqualified name to get the ordering correct.
if (const auto *RD = dyn_cast<RecordDecl>(DC))
mangleName(RD);
else
Out << '@';
// void __cdecl
Out << "YAX";
// struct __block_literal *
Out << 'P';
// __ptr64
if (PointersAre64Bit)
Out << 'E';
Out << 'A';
mangleArtificialTagType(TTK_Struct,
Discriminate("__block_literal", Discriminator,
ParameterDiscriminator));
Out << "@Z";
// If the effective context was a Record, we have fully mangled the
// qualified name and do not need to continue.
if (isa<RecordDecl>(DC))
break;
continue;
} else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) {
mangleObjCMethodName(Method);
} else if (isa<NamedDecl>(DC)) {
ND = cast<NamedDecl>(DC);
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
mangle(FD, "?");
break;
} else {
mangleUnqualifiedName(ND);
// Lambdas in default arguments conceptually belong to the function the
// parameter corresponds to.
if (const auto *LDADC = getLambdaDefaultArgumentDeclContext(ND)) {
DC = LDADC;
continue;
}
}
}
DC = DC->getParent();
}
}
void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
// Microsoft uses the names on the case labels for these dtor variants. Clang
// uses the Itanium terminology internally. Everything in this ABI delegates
// towards the base dtor.
switch (T) {
// <operator-name> ::= ?1 # destructor
case Dtor_Base: Out << "?1"; return;
// <operator-name> ::= ?_D # vbase destructor
case Dtor_Complete: Out << "?_D"; return;
// <operator-name> ::= ?_G # scalar deleting destructor
case Dtor_Deleting: Out << "?_G"; return;
// <operator-name> ::= ?_E # vector deleting destructor
// FIXME: Add a vector deleting dtor type. It goes in the vtable, so we need
// it.
case Dtor_Comdat:
llvm_unreachable("not expecting a COMDAT");
}
llvm_unreachable("Unsupported dtor type?");
}
void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
SourceLocation Loc) {
switch (OO) {
// ?0 # constructor
// ?1 # destructor
// <operator-name> ::= ?2 # new
case OO_New: Out << "?2"; break;
// <operator-name> ::= ?3 # delete
case OO_Delete: Out << "?3"; break;
// <operator-name> ::= ?4 # =
case OO_Equal: Out << "?4"; break;
// <operator-name> ::= ?5 # >>
case OO_GreaterGreater: Out << "?5"; break;
// <operator-name> ::= ?6 # <<
case OO_LessLess: Out << "?6"; break;
// <operator-name> ::= ?7 # !
case OO_Exclaim: Out << "?7"; break;
// <operator-name> ::= ?8 # ==
case OO_EqualEqual: Out << "?8"; break;
// <operator-name> ::= ?9 # !=
case OO_ExclaimEqual: Out << "?9"; break;
// <operator-name> ::= ?A # []
case OO_Subscript: Out << "?A"; break;
// ?B # conversion
// <operator-name> ::= ?C # ->
case OO_Arrow: Out << "?C"; break;
// <operator-name> ::= ?D # *
case OO_Star: Out << "?D"; break;
// <operator-name> ::= ?E # ++
case OO_PlusPlus: Out << "?E"; break;
// <operator-name> ::= ?F # --
case OO_MinusMinus: Out << "?F"; break;
// <operator-name> ::= ?G # -
case OO_Minus: Out << "?G"; break;
// <operator-name> ::= ?H # +
case OO_Plus: Out << "?H"; break;
// <operator-name> ::= ?I # &
case OO_Amp: Out << "?I"; break;
// <operator-name> ::= ?J # ->*
case OO_ArrowStar: Out << "?J"; break;
// <operator-name> ::= ?K # /
case OO_Slash: Out << "?K"; break;
// <operator-name> ::= ?L # %
case OO_Percent: Out << "?L"; break;
// <operator-name> ::= ?M # <
case OO_Less: Out << "?M"; break;
// <operator-name> ::= ?N # <=
case OO_LessEqual: Out << "?N"; break;
// <operator-name> ::= ?O # >
case OO_Greater: Out << "?O"; break;
// <operator-name> ::= ?P # >=
case OO_GreaterEqual: Out << "?P"; break;
// <operator-name> ::= ?Q # ,
case OO_Comma: Out << "?Q"; break;
// <operator-name> ::= ?R # ()
case OO_Call: Out << "?R"; break;
// <operator-name> ::= ?S # ~
case OO_Tilde: Out << "?S"; break;
// <operator-name> ::= ?T # ^
case OO_Caret: Out << "?T"; break;
// <operator-name> ::= ?U # |
case OO_Pipe: Out << "?U"; break;
// <operator-name> ::= ?V # &&
case OO_AmpAmp: Out << "?V"; break;
// <operator-name> ::= ?W # ||
case OO_PipePipe: Out << "?W"; break;
// <operator-name> ::= ?X # *=
case OO_StarEqual: Out << "?X"; break;
// <operator-name> ::= ?Y # +=
case OO_PlusEqual: Out << "?Y"; break;
// <operator-name> ::= ?Z # -=
case OO_MinusEqual: Out << "?Z"; break;
// <operator-name> ::= ?_0 # /=
case OO_SlashEqual: Out << "?_0"; break;
// <operator-name> ::= ?_1 # %=
case OO_PercentEqual: Out << "?_1"; break;
// <operator-name> ::= ?_2 # >>=
case OO_GreaterGreaterEqual: Out << "?_2"; break;
// <operator-name> ::= ?_3 # <<=
case OO_LessLessEqual: Out << "?_3"; break;
// <operator-name> ::= ?_4 # &=
case OO_AmpEqual: Out << "?_4"; break;
// <operator-name> ::= ?_5 # |=
case OO_PipeEqual: Out << "?_5"; break;
// <operator-name> ::= ?_6 # ^=
case OO_CaretEqual: Out << "?_6"; break;
// ?_7 # vftable
// ?_8 # vbtable
// ?_9 # vcall
// ?_A # typeof
// ?_B # local static guard
// ?_C # string
// ?_D # vbase destructor
// ?_E # vector deleting destructor
// ?_F # default constructor closure
// ?_G # scalar deleting destructor
// ?_H # vector constructor iterator
// ?_I # vector destructor iterator
// ?_J # vector vbase constructor iterator
// ?_K # virtual displacement map
// ?_L # eh vector constructor iterator
// ?_M # eh vector destructor iterator
// ?_N # eh vector vbase constructor iterator
// ?_O # copy constructor closure
// ?_P<name> # udt returning <name>
// ?_Q # <unknown>
// ?_R0 # RTTI Type Descriptor
// ?_R1 # RTTI Base Class Descriptor at (a,b,c,d)
// ?_R2 # RTTI Base Class Array
// ?_R3 # RTTI Class Hierarchy Descriptor
// ?_R4 # RTTI Complete Object Locator
// ?_S # local vftable
// ?_T # local vftable constructor closure
// <operator-name> ::= ?_U # new[]
case OO_Array_New: Out << "?_U"; break;
// <operator-name> ::= ?_V # delete[]
case OO_Array_Delete: Out << "?_V"; break;
// <operator-name> ::= ?__L # co_await
case OO_Coawait: Out << "?__L"; break;
case OO_Spaceship: {
// FIXME: Once MS picks a mangling, use it.
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this three-way comparison operator yet");
Diags.Report(Loc, DiagID);
break;
}
case OO_Conditional: {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this conditional operator yet");
Diags.Report(Loc, DiagID);
break;
}
case OO_None:
case NUM_OVERLOADED_OPERATORS:
llvm_unreachable("Not an overloaded operator");
}
}
void MicrosoftCXXNameMangler::mangleSourceName(StringRef Name) {
// <source name> ::= <identifier> @
BackRefVec::iterator Found =
std::find(NameBackReferences.begin(), NameBackReferences.end(), Name);
if (Found == NameBackReferences.end()) {
if (NameBackReferences.size() < 10)
NameBackReferences.push_back(Name);
Out << Name << '@';
} else {
Out << (Found - NameBackReferences.begin());
}
}
void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
Context.mangleObjCMethodName(MD, Out);
}
void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(
const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) {
// <template-name> ::= <unscoped-template-name> <template-args>
// ::= <substitution>
// Always start with the unqualified name.
// Templates have their own context for back references.
ArgBackRefMap OuterArgsContext;
BackRefVec OuterTemplateContext;
PassObjectSizeArgsSet OuterPassObjectSizeArgs;
NameBackReferences.swap(OuterTemplateContext);
TypeBackReferences.swap(OuterArgsContext);
PassObjectSizeArgs.swap(OuterPassObjectSizeArgs);
mangleUnscopedTemplateName(TD);
mangleTemplateArgs(TD, TemplateArgs);
// Restore the previous back reference contexts.
NameBackReferences.swap(OuterTemplateContext);
TypeBackReferences.swap(OuterArgsContext);
PassObjectSizeArgs.swap(OuterPassObjectSizeArgs);
}
void
MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) {
// <unscoped-template-name> ::= ?$ <unqualified-name>
Out << "?$";
mangleUnqualifiedName(TD);
}
void MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
bool IsBoolean) {
// <integer-literal> ::= $0 <number>
Out << "$0";
// Make sure booleans are encoded as 0/1.
if (IsBoolean && Value.getBoolValue())
mangleNumber(1);
else if (Value.isSigned())
mangleNumber(Value.getSExtValue());
else
mangleNumber(Value.getZExtValue());
}
void MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
// See if this is a constant expression.
llvm::APSInt Value;
if (E->isIntegerConstantExpr(Value, Context.getASTContext())) {
mangleIntegerLiteral(Value, E->getType()->isBooleanType());
return;
}
// Look through no-op casts like template parameter substitutions.
E = E->IgnoreParenNoopCasts(Context.getASTContext());
const CXXUuidofExpr *UE = nullptr;
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
if (UO->getOpcode() == UO_AddrOf)
UE = dyn_cast<CXXUuidofExpr>(UO->getSubExpr());
} else
UE = dyn_cast<CXXUuidofExpr>(E);
if (UE) {
// If we had to peek through an address-of operator, treat this like we are
// dealing with a pointer type. Otherwise, treat it like a const reference.
//
// N.B. This matches up with the handling of TemplateArgument::Declaration
// in mangleTemplateArg
if (UE == E)
Out << "$E?";
else
Out << "$1?";
// This CXXUuidofExpr is mangled as-if it were actually a VarDecl from
// const __s_GUID _GUID_{lower case UUID with underscores}
StringRef Uuid = UE->getUuidStr();
std::string Name = "_GUID_" + Uuid.lower();
std::replace(Name.begin(), Name.end(), '-', '_');
mangleSourceName(Name);
// Terminate the whole name with an '@'.
Out << '@';
// It's a global variable.
Out << '3';
// It's a struct called __s_GUID.
mangleArtificialTagType(TTK_Struct, "__s_GUID");
// It's const.
Out << 'B';
return;
}
// As bad as this diagnostic is, it's better than crashing.
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Error, "cannot yet mangle expression type %0");
Diags.Report(E->getExprLoc(), DiagID) << E->getStmtClassName()
<< E->getSourceRange();
}
void MicrosoftCXXNameMangler::mangleTemplateArgs(
const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) {
// <template-args> ::= <template-arg>+
const TemplateParameterList *TPL = TD->getTemplateParameters();
assert(TPL->size() == TemplateArgs.size() &&
"size mismatch between args and parms!");
for (size_t i = 0; i < TemplateArgs.size(); ++i) {
const TemplateArgument &TA = TemplateArgs[i];
// Separate consecutive packs by $$Z.
if (i > 0 && TA.getKind() == TemplateArgument::Pack &&
TemplateArgs[i - 1].getKind() == TemplateArgument::Pack)
Out << "$$Z";
mangleTemplateArg(TD, TA, TPL->getParam(i));
}
}
void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
const TemplateArgument &TA,
const NamedDecl *Parm) {
// <template-arg> ::= <type>
// ::= <integer-literal>
// ::= <member-data-pointer>
// ::= <member-function-pointer>
// ::= $E? <name> <type-encoding>
// ::= $1? <name> <type-encoding>
// ::= $0A@
// ::= <template-args>
switch (TA.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Can't mangle null template arguments!");
case TemplateArgument::TemplateExpansion:
llvm_unreachable("Can't mangle template expansion arguments!");
case TemplateArgument::Type: {
QualType T = TA.getAsType();
mangleType(T, SourceRange(), QMM_Escape);
break;
}
case TemplateArgument::Declaration: {
const NamedDecl *ND = TA.getAsDecl();
if (isa<FieldDecl>(ND) || isa<IndirectFieldDecl>(ND)) {
mangleMemberDataPointer(cast<CXXRecordDecl>(ND->getDeclContext())
->getMostRecentNonInjectedDecl(),
cast<ValueDecl>(ND));
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
if (MD && MD->isInstance()) {
mangleMemberFunctionPointer(
MD->getParent()->getMostRecentNonInjectedDecl(), MD);
} else {
Out << "$1?";
mangleName(FD);
mangleFunctionEncoding(FD, /*ShouldMangle=*/true);
}
} else {
mangle(ND, TA.getParamTypeForDecl()->isReferenceType() ? "$E?" : "$1?");
}
break;
}
case TemplateArgument::Integral:
mangleIntegerLiteral(TA.getAsIntegral(),
TA.getIntegralType()->isBooleanType());
break;
case TemplateArgument::NullPtr: {
QualType T = TA.getNullPtrType();
if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) {
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
if (MPT->isMemberFunctionPointerType() &&
!isa<FunctionTemplateDecl>(TD)) {
mangleMemberFunctionPointer(RD, nullptr);
return;
}
if (MPT->isMemberDataPointer()) {
if (!isa<FunctionTemplateDecl>(TD)) {
mangleMemberDataPointer(RD, nullptr);
return;
}
// nullptr data pointers are always represented with a single field
// which is initialized with either 0 or -1. Why -1? Well, we need to
// distinguish the case where the data member is at offset zero in the
// record.
// However, we are free to use 0 *if* we would use multiple fields for
// non-nullptr member pointers.
if (!RD->nullFieldOffsetIsZero()) {
mangleIntegerLiteral(llvm::APSInt::get(-1), /*IsBoolean=*/false);
return;
}
}
}
mangleIntegerLiteral(llvm::APSInt::getUnsigned(0), /*IsBoolean=*/false);
break;
}
case TemplateArgument::Expression:
mangleExpression(TA.getAsExpr());
break;
case TemplateArgument::Pack: {
ArrayRef<TemplateArgument> TemplateArgs = TA.getPackAsArray();
if (TemplateArgs.empty()) {
if (isa<TemplateTypeParmDecl>(Parm) ||
isa<TemplateTemplateParmDecl>(Parm))
// MSVC 2015 changed the mangling for empty expanded template packs,
// use the old mangling for link compatibility for old versions.
Out << (Context.getASTContext().getLangOpts().isCompatibleWithMSVC(
LangOptions::MSVC2015)
? "$$V"
: "$$$V");
else if (isa<NonTypeTemplateParmDecl>(Parm))
Out << "$S";
else
llvm_unreachable("unexpected template parameter decl!");
} else {
for (const TemplateArgument &PA : TemplateArgs)
mangleTemplateArg(TD, PA, Parm);
}
break;
}
case TemplateArgument::Template: {
const NamedDecl *ND =
TA.getAsTemplate().getAsTemplateDecl()->getTemplatedDecl();
if (const auto *TD = dyn_cast<TagDecl>(ND)) {
mangleType(TD);
} else if (isa<TypeAliasDecl>(ND)) {
Out << "$$Y";
mangleName(ND);
} else {
llvm_unreachable("unexpected template template NamedDecl!");
}
break;
}
}
}
void MicrosoftCXXNameMangler::mangleObjCProtocol(const ObjCProtocolDecl *PD) {
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
MicrosoftCXXNameMangler Extra(Context, Stream);
Stream << "?$";
Extra.mangleSourceName("Protocol");
Extra.mangleArtificialTagType(TTK_Struct, PD->getName());
mangleArtificialTagType(TTK_Struct, TemplateMangling, {"__ObjC"});
}
void MicrosoftCXXNameMangler::mangleObjCLifetime(const QualType Type,
Qualifiers Quals,
SourceRange Range) {
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
MicrosoftCXXNameMangler Extra(Context, Stream);
Stream << "?$";
switch (Quals.getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
break;
case Qualifiers::OCL_Autoreleasing:
Extra.mangleSourceName("Autoreleasing");
break;
case Qualifiers::OCL_Strong:
Extra.mangleSourceName("Strong");
break;
case Qualifiers::OCL_Weak:
Extra.mangleSourceName("Weak");
break;
}
Extra.manglePointerCVQualifiers(Quals);
Extra.manglePointerExtQualifiers(Quals, Type);
Extra.mangleType(Type, Range);
mangleArtificialTagType(TTK_Struct, TemplateMangling, {"__ObjC"});
}
void MicrosoftCXXNameMangler::mangleObjCKindOfType(const ObjCObjectType *T,
Qualifiers Quals,
SourceRange Range) {
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
MicrosoftCXXNameMangler Extra(Context, Stream);
Stream << "?$";
Extra.mangleSourceName("KindOf");
Extra.mangleType(QualType(T, 0)
.stripObjCKindOfType(getASTContext())
->getAs<ObjCObjectType>(),
Quals, Range);
mangleArtificialTagType(TTK_Struct, TemplateMangling, {"__ObjC"});
}
void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
bool IsMember) {
// <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers>
// 'E' means __ptr64 (32-bit only); 'F' means __unaligned (32/64-bit only);
// 'I' means __restrict (32/64-bit).
// Note that the MSVC __restrict keyword isn't the same as the C99 restrict
// keyword!
// <base-cvr-qualifiers> ::= A # near
// ::= B # near const
// ::= C # near volatile
// ::= D # near const volatile
// ::= E # far (16-bit)
// ::= F # far const (16-bit)
// ::= G # far volatile (16-bit)
// ::= H # far const volatile (16-bit)
// ::= I # huge (16-bit)
// ::= J # huge const (16-bit)
// ::= K # huge volatile (16-bit)
// ::= L # huge const volatile (16-bit)
// ::= M <basis> # based
// ::= N <basis> # based const
// ::= O <basis> # based volatile
// ::= P <basis> # based const volatile
// ::= Q # near member
// ::= R # near const member
// ::= S # near volatile member
// ::= T # near const volatile member
// ::= U # far member (16-bit)
// ::= V # far const member (16-bit)
// ::= W # far volatile member (16-bit)
// ::= X # far const volatile member (16-bit)
// ::= Y # huge member (16-bit)
// ::= Z # huge const member (16-bit)
// ::= 0 # huge volatile member (16-bit)
// ::= 1 # huge const volatile member (16-bit)
// ::= 2 <basis> # based member
// ::= 3 <basis> # based const member
// ::= 4 <basis> # based volatile member
// ::= 5 <basis> # based const volatile member
// ::= 6 # near function (pointers only)
// ::= 7 # far function (pointers only)
// ::= 8 # near method (pointers only)
// ::= 9 # far method (pointers only)
// ::= _A <basis> # based function (pointers only)
// ::= _B <basis> # based function (far?) (pointers only)
// ::= _C <basis> # based method (pointers only)
// ::= _D <basis> # based method (far?) (pointers only)
// ::= _E # block (Clang)
// <basis> ::= 0 # __based(void)
// ::= 1 # __based(segment)?
// ::= 2 <name> # __based(name)
// ::= 3 # ?
// ::= 4 # ?
// ::= 5 # not really based
bool HasConst = Quals.hasConst(),
HasVolatile = Quals.hasVolatile();
if (!IsMember) {
if (HasConst && HasVolatile) {
Out << 'D';
} else if (HasVolatile) {
Out << 'C';
} else if (HasConst) {
Out << 'B';
} else {
Out << 'A';
}
} else {
if (HasConst && HasVolatile) {
Out << 'T';
} else if (HasVolatile) {
Out << 'S';
} else if (HasConst) {
Out << 'R';
} else {
Out << 'Q';
}
}
// FIXME: For now, just drop all extension qualifiers on the floor.
}
void
MicrosoftCXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
// <ref-qualifier> ::= G # lvalue reference
// ::= H # rvalue-reference
switch (RefQualifier) {
case RQ_None:
break;
case RQ_LValue:
Out << 'G';
break;
case RQ_RValue:
Out << 'H';
break;
}
}
void MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals,
QualType PointeeType) {
if (PointersAre64Bit &&
(PointeeType.isNull() || !PointeeType->isFunctionType()))
Out << 'E';
if (Quals.hasRestrict())
Out << 'I';
if (Quals.hasUnaligned() ||
(!PointeeType.isNull() && PointeeType.getLocalQualifiers().hasUnaligned()))
Out << 'F';
}
void MicrosoftCXXNameMangler::manglePointerCVQualifiers(Qualifiers Quals) {
// <pointer-cv-qualifiers> ::= P # no qualifiers
// ::= Q # const
// ::= R # volatile
// ::= S # const volatile
bool HasConst = Quals.hasConst(),
HasVolatile = Quals.hasVolatile();
if (HasConst && HasVolatile) {
Out << 'S';
} else if (HasVolatile) {
Out << 'R';
} else if (HasConst) {
Out << 'Q';
} else {
Out << 'P';
}
}
void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
SourceRange Range) {
// MSVC will backreference two canonically equivalent types that have slightly
// different manglings when mangled alone.
// Decayed types do not match up with non-decayed versions of the same type.
//
// e.g.
// void (*x)(void) will not form a backreference with void x(void)
void *TypePtr;
if (const auto *DT = T->getAs<DecayedType>()) {
QualType OriginalType = DT->getOriginalType();
// All decayed ArrayTypes should be treated identically; as-if they were
// a decayed IncompleteArrayType.
if (const auto *AT = getASTContext().getAsArrayType(OriginalType))
OriginalType = getASTContext().getIncompleteArrayType(
AT->getElementType(), AT->getSizeModifier(),
AT->getIndexTypeCVRQualifiers());
TypePtr = OriginalType.getCanonicalType().getAsOpaquePtr();
// If the original parameter was textually written as an array,
// instead treat the decayed parameter like it's const.
//
// e.g.
// int [] -> int * const
if (OriginalType->isArrayType())
T = T.withConst();
} else {
TypePtr = T.getCanonicalType().getAsOpaquePtr();
}
ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
if (Found == TypeBackReferences.end()) {
size_t OutSizeBefore = Out.tell();
mangleType(T, Range, QMM_Drop);
// See if it's worth creating a back reference.
// Only types longer than 1 character are considered
// and only 10 back references slots are available:
bool LongerThanOneChar = (Out.tell() - OutSizeBefore > 1);
if (LongerThanOneChar && TypeBackReferences.size() < 10) {
size_t Size = TypeBackReferences.size();
TypeBackReferences[TypePtr] = Size;
}
} else {
Out << Found->second;
}
}
void MicrosoftCXXNameMangler::manglePassObjectSizeArg(
const PassObjectSizeAttr *POSA) {
int Type = POSA->getType();
auto Iter = PassObjectSizeArgs.insert(Type).first;
auto *TypePtr = (const void *)&*Iter;
ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
if (Found == TypeBackReferences.end()) {
mangleArtificialTagType(TTK_Enum, "__pass_object_size" + llvm::utostr(Type),
{"__clang"});
if (TypeBackReferences.size() < 10) {
size_t Size = TypeBackReferences.size();
TypeBackReferences[TypePtr] = Size;
}
} else {
Out << Found->second;
}
}
void MicrosoftCXXNameMangler::mangleAddressSpaceType(QualType T,
Qualifiers Quals,
SourceRange Range) {
// Address space is mangled as an unqualified templated type in the __clang
// namespace. The demangled version of this is:
// In the case of a language specific address space:
// __clang::struct _AS[language_addr_space]<Type>
// where:
// <language_addr_space> ::= <OpenCL-addrspace> | <CUDA-addrspace>
// <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant" |
// "private"| "generic" ]
// <CUDA-addrspace> ::= "CU" [ "device" | "constant" | "shared" ]
// Note that the above were chosen to match the Itanium mangling for this.
//
// In the case of a non-language specific address space:
// __clang::struct _AS<TargetAS, Type>
assert(Quals.hasAddressSpace() && "Not valid without address space");
llvm::SmallString<32> ASMangling;
llvm::raw_svector_ostream Stream(ASMangling);
MicrosoftCXXNameMangler Extra(Context, Stream);
Stream << "?$";
LangAS AS = Quals.getAddressSpace();
if (Context.getASTContext().addressSpaceMapManglingFor(AS)) {
unsigned TargetAS = Context.getASTContext().getTargetAddressSpace(AS);
Extra.mangleSourceName("_AS");
Extra.mangleIntegerLiteral(llvm::APSInt::getUnsigned(TargetAS),
/*IsBoolean*/ false);
} else {
switch (AS) {
default:
llvm_unreachable("Not a language specific address space");
case LangAS::opencl_global:
Extra.mangleSourceName("_ASCLglobal");
break;
case LangAS::opencl_local:
Extra.mangleSourceName("_ASCLlocal");
break;
case LangAS::opencl_constant:
Extra.mangleSourceName("_ASCLconstant");
break;
case LangAS::opencl_private:
Extra.mangleSourceName("_ASCLprivate");
break;
case LangAS::opencl_generic:
Extra.mangleSourceName("_ASCLgeneric");
break;
case LangAS::cuda_device:
Extra.mangleSourceName("_ASCUdevice");
break;
case LangAS::cuda_constant:
Extra.mangleSourceName("_ASCUconstant");
break;
case LangAS::cuda_shared:
Extra.mangleSourceName("_ASCUshared");
break;
}
}
Extra.mangleType(T, Range, QMM_Escape);
mangleQualifiers(Qualifiers(), false);
mangleArtificialTagType(TTK_Struct, ASMangling, {"__clang"});
}
void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM) {
// Don't use the canonical types. MSVC includes things like 'const' on
// pointer arguments to function pointers that canonicalization strips away.
T = T.getDesugaredType(getASTContext());
Qualifiers Quals = T.getLocalQualifiers();
if (const ArrayType *AT = getASTContext().getAsArrayType(T)) {
// If there were any Quals, getAsArrayType() pushed them onto the array
// element type.
if (QMM == QMM_Mangle)
Out << 'A';
else if (QMM == QMM_Escape || QMM == QMM_Result)
Out << "$$B";
mangleArrayType(AT);
return;
}
bool IsPointer = T->isAnyPointerType() || T->isMemberPointerType() ||
T->isReferenceType() || T->isBlockPointerType();
switch (QMM) {
case QMM_Drop:
if (Quals.hasObjCLifetime())
Quals = Quals.withoutObjCLifetime();
break;
case QMM_Mangle:
if (const FunctionType *FT = dyn_cast<FunctionType>(T)) {
Out << '6';
mangleFunctionType(FT);
return;
}
mangleQualifiers(Quals, false);
break;
case QMM_Escape:
if (!IsPointer && Quals) {
Out << "$$C";
mangleQualifiers(Quals, false);
}
break;
case QMM_Result:
// Presence of __unaligned qualifier shouldn't affect mangling here.
Quals.removeUnaligned();
if (Quals.hasObjCLifetime())
Quals = Quals.withoutObjCLifetime();
if ((!IsPointer && Quals) || isa<TagType>(T) || isArtificialTagType(T)) {
Out << '?';
mangleQualifiers(Quals, false);
}
break;
}
const Type *ty = T.getTypePtr();
switch (ty->getTypeClass()) {
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT) \
case Type::CLASS: \
llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
return;
#define TYPE(CLASS, PARENT) \
case Type::CLASS: \
mangleType(cast<CLASS##Type>(ty), Quals, Range); \
break;
#include "clang/AST/TypeNodes.def"
#undef ABSTRACT_TYPE
#undef NON_CANONICAL_TYPE
#undef TYPE
}
}
void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
SourceRange Range) {
// <type> ::= <builtin-type>
// <builtin-type> ::= X # void
// ::= C # signed char
// ::= D # char
// ::= E # unsigned char
// ::= F # short
// ::= G # unsigned short (or wchar_t if it's not a builtin)
// ::= H # int
// ::= I # unsigned int
// ::= J # long
// ::= K # unsigned long
// L # <none>
// ::= M # float
// ::= N # double
// ::= O # long double (__float80 is mangled differently)
// ::= _J # long long, __int64
// ::= _K # unsigned long long, __int64
// ::= _L # __int128
// ::= _M # unsigned __int128
// ::= _N # bool
// _O # <array in parameter>
- // ::= _T # __float80 (Intel)
+ // ::= _Q # char8_t
// ::= _S # char16_t
+ // ::= _T # __float80 (Intel)
// ::= _U # char32_t
// ::= _W # wchar_t
// ::= _Z # __float80 (Digital Mars)
switch (T->getKind()) {
case BuiltinType::Void:
Out << 'X';
break;
case BuiltinType::SChar:
Out << 'C';
break;
case BuiltinType::Char_U:
case BuiltinType::Char_S:
Out << 'D';
break;
case BuiltinType::UChar:
Out << 'E';
break;
case BuiltinType::Short:
Out << 'F';
break;
case BuiltinType::UShort:
Out << 'G';
break;
case BuiltinType::Int:
Out << 'H';
break;
case BuiltinType::UInt:
Out << 'I';
break;
case BuiltinType::Long:
Out << 'J';
break;
case BuiltinType::ULong:
Out << 'K';
break;
case BuiltinType::Float:
Out << 'M';
break;
case BuiltinType::Double:
Out << 'N';
break;
// TODO: Determine size and mangle accordingly
case BuiltinType::LongDouble:
Out << 'O';
break;
case BuiltinType::LongLong:
Out << "_J";
break;
case BuiltinType::ULongLong:
Out << "_K";
break;
case BuiltinType::Int128:
Out << "_L";
break;
case BuiltinType::UInt128:
Out << "_M";
break;
case BuiltinType::Bool:
Out << "_N";
break;
+ case BuiltinType::Char8:
+ Out << "_Q";
+ break;
case BuiltinType::Char16:
Out << "_S";
break;
case BuiltinType::Char32:
Out << "_U";
break;
case BuiltinType::WChar_S:
case BuiltinType::WChar_U:
Out << "_W";
break;
#define BUILTIN_TYPE(Id, SingletonId)
#define PLACEHOLDER_TYPE(Id, SingletonId) \
case BuiltinType::Id:
#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
llvm_unreachable("placeholder types shouldn't get to name mangling");
case BuiltinType::ObjCId:
mangleArtificialTagType(TTK_Struct, "objc_object");
break;
case BuiltinType::ObjCClass:
mangleArtificialTagType(TTK_Struct, "objc_class");
break;
case BuiltinType::ObjCSel:
mangleArtificialTagType(TTK_Struct, "objc_selector");
break;
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
case BuiltinType::Id: \
Out << "PAUocl_" #ImgType "_" #Suffix "@@"; \
break;
#include "clang/Basic/OpenCLImageTypes.def"
case BuiltinType::OCLSampler:
Out << "PA";
mangleArtificialTagType(TTK_Struct, "ocl_sampler");
break;
case BuiltinType::OCLEvent:
Out << "PA";
mangleArtificialTagType(TTK_Struct, "ocl_event");
break;
case BuiltinType::OCLClkEvent:
Out << "PA";
mangleArtificialTagType(TTK_Struct, "ocl_clkevent");
break;
case BuiltinType::OCLQueue:
Out << "PA";
mangleArtificialTagType(TTK_Struct, "ocl_queue");
break;
case BuiltinType::OCLReserveID:
Out << "PA";
mangleArtificialTagType(TTK_Struct, "ocl_reserveid");
break;
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id: \
mangleArtificialTagType(TTK_Struct, "ocl_" #ExtType); \
break;
#include "clang/Basic/OpenCLExtensionTypes.def"
case BuiltinType::NullPtr:
Out << "$$T";
break;
case BuiltinType::Float16:
mangleArtificialTagType(TTK_Struct, "_Float16", {"__clang"});
break;
case BuiltinType::Half:
mangleArtificialTagType(TTK_Struct, "_Half", {"__clang"});
break;
case BuiltinType::ShortAccum:
case BuiltinType::Accum:
case BuiltinType::LongAccum:
case BuiltinType::UShortAccum:
case BuiltinType::UAccum:
case BuiltinType::ULongAccum:
case BuiltinType::ShortFract:
case BuiltinType::Fract:
case BuiltinType::LongFract:
case BuiltinType::UShortFract:
case BuiltinType::UFract:
case BuiltinType::ULongFract:
case BuiltinType::SatShortAccum:
case BuiltinType::SatAccum:
case BuiltinType::SatLongAccum:
case BuiltinType::SatUShortAccum:
case BuiltinType::SatUAccum:
case BuiltinType::SatULongAccum:
case BuiltinType::SatShortFract:
case BuiltinType::SatFract:
case BuiltinType::SatLongFract:
case BuiltinType::SatUShortFract:
case BuiltinType::SatUFract:
case BuiltinType::SatULongFract:
- case BuiltinType::Char8:
case BuiltinType::Float128: {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Error, "cannot mangle this built-in %0 type yet");
Diags.Report(Range.getBegin(), DiagID)
<< T->getName(Context.getASTContext().getPrintingPolicy()) << Range;
break;
}
}
}
// <type> ::= <function-type>
void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, Qualifiers,
SourceRange) {
// Structors only appear in decls, so at this point we know it's not a
// structor type.
// FIXME: This may not be lambda-friendly.
if (T->getTypeQuals() || T->getRefQualifier() != RQ_None) {
Out << "$$A8@@";
mangleFunctionType(T, /*D=*/nullptr, /*ForceThisQuals=*/true);
} else {
Out << "$$A6";
mangleFunctionType(T);
}
}
void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T,
Qualifiers, SourceRange) {
Out << "$$A6";
mangleFunctionType(T);
}
void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
const FunctionDecl *D,
bool ForceThisQuals,
bool MangleExceptionSpec) {
// <function-type> ::= <this-cvr-qualifiers> <calling-convention>
// <return-type> <argument-list> <throw-spec>
const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(T);
SourceRange Range;
if (D) Range = D->getSourceRange();
bool IsInLambda = false;
bool IsStructor = false, HasThisQuals = ForceThisQuals, IsCtorClosure = false;
CallingConv CC = T->getCallConv();
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(D)) {
if (MD->getParent()->isLambda())
IsInLambda = true;
if (MD->isInstance())
HasThisQuals = true;
if (isa<CXXDestructorDecl>(MD)) {
IsStructor = true;
} else if (isa<CXXConstructorDecl>(MD)) {
IsStructor = true;
IsCtorClosure = (StructorType == Ctor_CopyingClosure ||
StructorType == Ctor_DefaultClosure) &&
isStructorDecl(MD);
if (IsCtorClosure)
CC = getASTContext().getDefaultCallingConvention(
/*IsVariadic=*/false, /*IsCXXMethod=*/true);
}
}
// If this is a C++ instance method, mangle the CVR qualifiers for the
// this pointer.
if (HasThisQuals) {
Qualifiers Quals = Proto->getTypeQuals();
manglePointerExtQualifiers(Quals, /*PointeeType=*/QualType());
mangleRefQualifier(Proto->getRefQualifier());
mangleQualifiers(Quals, /*IsMember=*/false);
}
mangleCallingConvention(CC);
// <return-type> ::= <type>
// ::= @ # structors (they have no declared return type)
if (IsStructor) {
if (isa<CXXDestructorDecl>(D) && isStructorDecl(D)) {
// The scalar deleting destructor takes an extra int argument which is not
// reflected in the AST.
if (StructorType == Dtor_Deleting) {
Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z");
return;
}
// The vbase destructor returns void which is not reflected in the AST.
if (StructorType == Dtor_Complete) {
Out << "XXZ";
return;
}
}
if (IsCtorClosure) {
// Default constructor closure and copy constructor closure both return
// void.
Out << 'X';
if (StructorType == Ctor_DefaultClosure) {
// Default constructor closure always has no arguments.
Out << 'X';
} else if (StructorType == Ctor_CopyingClosure) {
// Copy constructor closure always takes an unqualified reference.
mangleArgumentType(getASTContext().getLValueReferenceType(
Proto->getParamType(0)
->getAs<LValueReferenceType>()
->getPointeeType(),
/*SpelledAsLValue=*/true),
Range);
Out << '@';
} else {
llvm_unreachable("unexpected constructor closure!");
}
Out << 'Z';
return;
}
Out << '@';
} else {
QualType ResultType = T->getReturnType();
if (const auto *AT =
dyn_cast_or_null<AutoType>(ResultType->getContainedAutoType())) {
Out << '?';
mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
Out << '?';
assert(AT->getKeyword() != AutoTypeKeyword::GNUAutoType &&
"shouldn't need to mangle __auto_type!");
mangleSourceName(AT->isDecltypeAuto() ? "<decltype-auto>" : "<auto>");
Out << '@';
} else if (IsInLambda) {
Out << '@';
} else {
if (ResultType->isVoidType())
ResultType = ResultType.getUnqualifiedType();
mangleType(ResultType, Range, QMM_Result);
}
}
// <argument-list> ::= X # void
// ::= <type>+ @
// ::= <type>* Z # varargs
if (!Proto) {
// Function types without prototypes can arise when mangling a function type
// within an overloadable function in C. We mangle these as the absence of
// any parameter types (not even an empty parameter list).
Out << '@';
} else if (Proto->getNumParams() == 0 && !Proto->isVariadic()) {
Out << 'X';
} else {
// Happens for function pointer type arguments for example.
for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) {
mangleArgumentType(Proto->getParamType(I), Range);
// Mangle each pass_object_size parameter as if it's a parameter of enum
// type passed directly after the parameter with the pass_object_size
// attribute. The aforementioned enum's name is __pass_object_size, and we
// pretend it resides in a top-level namespace called __clang.
//
// FIXME: Is there a defined extension notation for the MS ABI, or is it
// necessary to just cross our fingers and hope this type+namespace
// combination doesn't conflict with anything?
if (D)
if (const auto *P = D->getParamDecl(I)->getAttr<PassObjectSizeAttr>())
manglePassObjectSizeArg(P);
}
// <builtin-type> ::= Z # ellipsis
if (Proto->isVariadic())
Out << 'Z';
else
Out << '@';
}
if (MangleExceptionSpec && getASTContext().getLangOpts().CPlusPlus17 &&
getASTContext().getLangOpts().isCompatibleWithMSVC(
LangOptions::MSVC2017_5))
mangleThrowSpecification(Proto);
else
Out << 'Z';
}
void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
// <function-class> ::= <member-function> E? # E designates a 64-bit 'this'
// # pointer. in 64-bit mode *all*
// # 'this' pointers are 64-bit.
// ::= <global-function>
// <member-function> ::= A # private: near
// ::= B # private: far
// ::= C # private: static near
// ::= D # private: static far
// ::= E # private: virtual near
// ::= F # private: virtual far
// ::= I # protected: near
// ::= J # protected: far
// ::= K # protected: static near
// ::= L # protected: static far
// ::= M # protected: virtual near
// ::= N # protected: virtual far
// ::= Q # public: near
// ::= R # public: far
// ::= S # public: static near
// ::= T # public: static far
// ::= U # public: virtual near
// ::= V # public: virtual far
// <global-function> ::= Y # global near
// ::= Z # global far
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
bool IsVirtual = MD->isVirtual();
// When mangling vbase destructor variants, ignore whether or not the
// underlying destructor was defined to be virtual.
if (isa<CXXDestructorDecl>(MD) && isStructorDecl(MD) &&
StructorType == Dtor_Complete) {
IsVirtual = false;
}
switch (MD->getAccess()) {
case AS_none:
llvm_unreachable("Unsupported access specifier");
case AS_private:
if (MD->isStatic())
Out << 'C';
else if (IsVirtual)
Out << 'E';
else
Out << 'A';
break;
case AS_protected:
if (MD->isStatic())
Out << 'K';
else if (IsVirtual)
Out << 'M';
else
Out << 'I';
break;
case AS_public:
if (MD->isStatic())
Out << 'S';
else if (IsVirtual)
Out << 'U';
else
Out << 'Q';
}
} else {
Out << 'Y';
}
}
void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) {
// <calling-convention> ::= A # __cdecl
// ::= B # __export __cdecl
// ::= C # __pascal
// ::= D # __export __pascal
// ::= E # __thiscall
// ::= F # __export __thiscall
// ::= G # __stdcall
// ::= H # __export __stdcall
// ::= I # __fastcall
// ::= J # __export __fastcall
// ::= Q # __vectorcall
// ::= w # __regcall
// The 'export' calling conventions are from a bygone era
// (*cough*Win16*cough*) when functions were declared for export with
// that keyword. (It didn't actually export them, it just made them so
// that they could be in a DLL and somebody from another module could call
// them.)
switch (CC) {
default:
llvm_unreachable("Unsupported CC for mangling");
case CC_Win64:
case CC_X86_64SysV:
case CC_C: Out << 'A'; break;
case CC_X86Pascal: Out << 'C'; break;
case CC_X86ThisCall: Out << 'E'; break;
case CC_X86StdCall: Out << 'G'; break;
case CC_X86FastCall: Out << 'I'; break;
case CC_X86VectorCall: Out << 'Q'; break;
case CC_Swift: Out << 'S'; break;
case CC_PreserveMost: Out << 'U'; break;
case CC_X86RegCall: Out << 'w'; break;
}
}
void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) {
mangleCallingConvention(T->getCallConv());
}
void MicrosoftCXXNameMangler::mangleThrowSpecification(
const FunctionProtoType *FT) {
// <throw-spec> ::= Z # (default)
// ::= _E # noexcept
if (FT->canThrow())
Out << 'Z';
else
Out << "_E";
}
void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T,
Qualifiers, SourceRange Range) {
// Probably should be mangled as a template instantiation; need to see what
// VC does first.
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this unresolved dependent type yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
// <type> ::= <union-type> | <struct-type> | <class-type> | <enum-type>
// <union-type> ::= T <name>
// <struct-type> ::= U <name>
// <class-type> ::= V <name>
// <enum-type> ::= W4 <name>
void MicrosoftCXXNameMangler::mangleTagTypeKind(TagTypeKind TTK) {
switch (TTK) {
case TTK_Union:
Out << 'T';
break;
case TTK_Struct:
case TTK_Interface:
Out << 'U';
break;
case TTK_Class:
Out << 'V';
break;
case TTK_Enum:
Out << "W4";
break;
}
}
void MicrosoftCXXNameMangler::mangleType(const EnumType *T, Qualifiers,
SourceRange) {
mangleType(cast<TagType>(T)->getDecl());
}
void MicrosoftCXXNameMangler::mangleType(const RecordType *T, Qualifiers,
SourceRange) {
mangleType(cast<TagType>(T)->getDecl());
}
void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) {
mangleTagTypeKind(TD->getTagKind());
mangleName(TD);
}
// If you add a call to this, consider updating isArtificialTagType() too.
void MicrosoftCXXNameMangler::mangleArtificialTagType(
TagTypeKind TK, StringRef UnqualifiedName,
ArrayRef<StringRef> NestedNames) {
// <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @
mangleTagTypeKind(TK);
// Always start with the unqualified name.
mangleSourceName(UnqualifiedName);
for (auto I = NestedNames.rbegin(), E = NestedNames.rend(); I != E; ++I)
mangleSourceName(*I);
// Terminate the whole name with an '@'.
Out << '@';
}
// <type> ::= <array-type>
// <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers>
// [Y <dimension-count> <dimension>+]
// <element-type> # as global, E is never required
// It's supposed to be the other way around, but for some strange reason, it
// isn't. Today this behavior is retained for the sole purpose of backwards
// compatibility.
void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T) {
// This isn't a recursive mangling, so now we have to do it all in this
// one call.
manglePointerCVQualifiers(T->getElementType().getQualifiers());
mangleType(T->getElementType(), SourceRange());
}
void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, Qualifiers,
SourceRange) {
llvm_unreachable("Should have been special cased");
}
void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T, Qualifiers,
SourceRange) {
llvm_unreachable("Should have been special cased");
}
void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T,
Qualifiers, SourceRange) {
llvm_unreachable("Should have been special cased");
}
void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T,
Qualifiers, SourceRange) {
llvm_unreachable("Should have been special cased");
}
void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) {
QualType ElementTy(T, 0);
SmallVector<llvm::APInt, 3> Dimensions;
for (;;) {
if (ElementTy->isConstantArrayType()) {
const ConstantArrayType *CAT =
getASTContext().getAsConstantArrayType(ElementTy);
Dimensions.push_back(CAT->getSize());
ElementTy = CAT->getElementType();
} else if (ElementTy->isIncompleteArrayType()) {
const IncompleteArrayType *IAT =
getASTContext().getAsIncompleteArrayType(ElementTy);
Dimensions.push_back(llvm::APInt(32, 0));
ElementTy = IAT->getElementType();
} else if (ElementTy->isVariableArrayType()) {
const VariableArrayType *VAT =
getASTContext().getAsVariableArrayType(ElementTy);
Dimensions.push_back(llvm::APInt(32, 0));
ElementTy = VAT->getElementType();
} else if (ElementTy->isDependentSizedArrayType()) {
// The dependent expression has to be folded into a constant (TODO).
const DependentSizedArrayType *DSAT =
getASTContext().getAsDependentSizedArrayType(ElementTy);
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this dependent-length array yet");
Diags.Report(DSAT->getSizeExpr()->getExprLoc(), DiagID)
<< DSAT->getBracketsRange();
return;
} else {
break;
}
}
Out << 'Y';
// <dimension-count> ::= <number> # number of extra dimensions
mangleNumber(Dimensions.size());
for (const llvm::APInt &Dimension : Dimensions)
mangleNumber(Dimension.getLimitedValue());
mangleType(ElementTy, SourceRange(), QMM_Escape);
}
// <type> ::= <pointer-to-member-type>
// <pointer-to-member-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers>
// <class name> <type>
void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T,
Qualifiers Quals, SourceRange Range) {
QualType PointeeType = T->getPointeeType();
manglePointerCVQualifiers(Quals);
manglePointerExtQualifiers(Quals, PointeeType);
if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) {
Out << '8';
mangleName(T->getClass()->castAs<RecordType>()->getDecl());
mangleFunctionType(FPT, nullptr, true);
} else {
mangleQualifiers(PointeeType.getQualifiers(), true);
mangleName(T->getClass()->castAs<RecordType>()->getDecl());
mangleType(PointeeType, Range, QMM_Drop);
}
}
void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T,
Qualifiers, SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this template type parameter type yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftCXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T,
Qualifiers, SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this substituted parameter pack yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
// <type> ::= <pointer-type>
// <pointer-type> ::= E? <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
// # the E is required for 64-bit non-static pointers
void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Qualifiers Quals,
SourceRange Range) {
QualType PointeeType = T->getPointeeType();
manglePointerCVQualifiers(Quals);
manglePointerExtQualifiers(Quals, PointeeType);
if (PointeeType.getQualifiers().hasAddressSpace())
mangleAddressSpaceType(PointeeType, PointeeType.getQualifiers(), Range);
else
mangleType(PointeeType, Range);
}
void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T,
Qualifiers Quals, SourceRange Range) {
QualType PointeeType = T->getPointeeType();
switch (Quals.getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
break;
case Qualifiers::OCL_Autoreleasing:
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Weak:
return mangleObjCLifetime(PointeeType, Quals, Range);
}
manglePointerCVQualifiers(Quals);
manglePointerExtQualifiers(Quals, PointeeType);
mangleType(PointeeType, Range);
}
// <type> ::= <reference-type>
// <reference-type> ::= A E? <cvr-qualifiers> <type>
// # the E is required for 64-bit non-static lvalue references
void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T,
Qualifiers Quals, SourceRange Range) {
QualType PointeeType = T->getPointeeType();
assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!");
Out << 'A';
manglePointerExtQualifiers(Quals, PointeeType);
mangleType(PointeeType, Range);
}
// <type> ::= <r-value-reference-type>
// <r-value-reference-type> ::= $$Q E? <cvr-qualifiers> <type>
// # the E is required for 64-bit non-static rvalue references
void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T,
Qualifiers Quals, SourceRange Range) {
QualType PointeeType = T->getPointeeType();
assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!");
Out << "$$Q";
manglePointerExtQualifiers(Quals, PointeeType);
mangleType(PointeeType, Range);
}
void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, Qualifiers,
SourceRange Range) {
QualType ElementType = T->getElementType();
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
MicrosoftCXXNameMangler Extra(Context, Stream);
Stream << "?$";
Extra.mangleSourceName("_Complex");
Extra.mangleType(ElementType, Range, QMM_Escape);
mangleArtificialTagType(TTK_Struct, TemplateMangling, {"__clang"});
}
// Returns true for types that mangleArtificialTagType() gets called for with
// TTK_Union, TTK_Struct, TTK_Class and where compatibility with MSVC's
// mangling matters.
// (It doesn't matter for Objective-C types and the like that cl.exe doesn't
// support.)
bool MicrosoftCXXNameMangler::isArtificialTagType(QualType T) const {
const Type *ty = T.getTypePtr();
switch (ty->getTypeClass()) {
default:
return false;
case Type::Vector: {
// For ABI compatibility only __m64, __m128(id), and __m256(id) matter,
// but since mangleType(VectorType*) always calls mangleArtificialTagType()
// just always return true (the other vector types are clang-only).
return true;
}
}
}
void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals,
SourceRange Range) {
const BuiltinType *ET = T->getElementType()->getAs<BuiltinType>();
assert(ET && "vectors with non-builtin elements are unsupported");
uint64_t Width = getASTContext().getTypeSize(T);
// Pattern match exactly the typedefs in our intrinsic headers. Anything that
// doesn't match the Intel types uses a custom mangling below.
size_t OutSizeBefore = Out.tell();
if (!isa<ExtVectorType>(T)) {
llvm::Triple::ArchType AT =
getASTContext().getTargetInfo().getTriple().getArch();
if (AT == llvm::Triple::x86 || AT == llvm::Triple::x86_64) {
if (Width == 64 && ET->getKind() == BuiltinType::LongLong) {
mangleArtificialTagType(TTK_Union, "__m64");
} else if (Width >= 128) {
if (ET->getKind() == BuiltinType::Float)
mangleArtificialTagType(TTK_Union, "__m" + llvm::utostr(Width));
else if (ET->getKind() == BuiltinType::LongLong)
mangleArtificialTagType(TTK_Union, "__m" + llvm::utostr(Width) + 'i');
else if (ET->getKind() == BuiltinType::Double)
mangleArtificialTagType(TTK_Struct, "__m" + llvm::utostr(Width) + 'd');
}
}
}
bool IsBuiltin = Out.tell() != OutSizeBefore;
if (!IsBuiltin) {
// The MS ABI doesn't have a special mangling for vector types, so we define
// our own mangling to handle uses of __vector_size__ on user-specified
// types, and for extensions like __v4sf.
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
MicrosoftCXXNameMangler Extra(Context, Stream);
Stream << "?$";
Extra.mangleSourceName("__vector");
Extra.mangleType(QualType(ET, 0), Range, QMM_Escape);
Extra.mangleIntegerLiteral(llvm::APSInt::getUnsigned(T->getNumElements()),
/*IsBoolean=*/false);
mangleArtificialTagType(TTK_Union, TemplateMangling, {"__clang"});
}
}
void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T,
Qualifiers Quals, SourceRange Range) {
mangleType(static_cast<const VectorType *>(T), Quals, Range);
}
void MicrosoftCXXNameMangler::mangleType(const DependentVectorType *T,
Qualifiers, SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Error,
"cannot mangle this dependent-sized vector type yet");
Diags.Report(Range.getBegin(), DiagID) << Range;
}
void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T,
Qualifiers, SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this dependent-sized extended vector type yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftCXXNameMangler::mangleType(const DependentAddressSpaceType *T,
Qualifiers, SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Error,
"cannot mangle this dependent address space type yet");
Diags.Report(Range.getBegin(), DiagID) << Range;
}
void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T, Qualifiers,
SourceRange) {
// ObjC interfaces have structs underlying them.
mangleTagTypeKind(TTK_Struct);
mangleName(T->getDecl());
}
void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T,
Qualifiers Quals, SourceRange Range) {
if (T->isKindOfType())
return mangleObjCKindOfType(T, Quals, Range);
if (T->qual_empty() && !T->isSpecialized())
return mangleType(T->getBaseType(), Range, QMM_Drop);
ArgBackRefMap OuterArgsContext;
BackRefVec OuterTemplateContext;
TypeBackReferences.swap(OuterArgsContext);
NameBackReferences.swap(OuterTemplateContext);
mangleTagTypeKind(TTK_Struct);
Out << "?$";
if (T->isObjCId())
mangleSourceName("objc_object");
else if (T->isObjCClass())
mangleSourceName("objc_class");
else
mangleSourceName(T->getInterface()->getName());
for (const auto &Q : T->quals())
mangleObjCProtocol(Q);
if (T->isSpecialized())
for (const auto &TA : T->getTypeArgs())
mangleType(TA, Range, QMM_Drop);
Out << '@';
Out << '@';
TypeBackReferences.swap(OuterArgsContext);
NameBackReferences.swap(OuterTemplateContext);
}
void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T,
Qualifiers Quals, SourceRange Range) {
QualType PointeeType = T->getPointeeType();
manglePointerCVQualifiers(Quals);
manglePointerExtQualifiers(Quals, PointeeType);
Out << "_E";
mangleFunctionType(PointeeType->castAs<FunctionProtoType>());
}
void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *,
Qualifiers, SourceRange) {
llvm_unreachable("Cannot mangle injected class name type.");
}
void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T,
Qualifiers, SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this template specialization type yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T, Qualifiers,
SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this dependent name type yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftCXXNameMangler::mangleType(
const DependentTemplateSpecializationType *T, Qualifiers,
SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this dependent template specialization type yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T, Qualifiers,
SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this pack expansion yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T, Qualifiers,
SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this typeof(type) yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T, Qualifiers,
SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this typeof(expression) yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T, Qualifiers,
SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this decltype() yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T,
Qualifiers, SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this unary transform type yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftCXXNameMangler::mangleType(const AutoType *T, Qualifiers,
SourceRange Range) {
assert(T->getDeducedType().isNull() && "expecting a dependent type!");
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this 'auto' type yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftCXXNameMangler::mangleType(
const DeducedTemplateSpecializationType *T, Qualifiers, SourceRange Range) {
assert(T->getDeducedType().isNull() && "expecting a dependent type!");
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this deduced class template specialization type yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, Qualifiers,
SourceRange Range) {
QualType ValueType = T->getValueType();
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
MicrosoftCXXNameMangler Extra(Context, Stream);
Stream << "?$";
Extra.mangleSourceName("_Atomic");
Extra.mangleType(ValueType, Range, QMM_Escape);
mangleArtificialTagType(TTK_Struct, TemplateMangling, {"__clang"});
}
void MicrosoftCXXNameMangler::mangleType(const PipeType *T, Qualifiers,
SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this OpenCL pipe type yet");
Diags.Report(Range.getBegin(), DiagID)
<< Range;
}
void MicrosoftMangleContextImpl::mangleCXXName(const NamedDecl *D,
raw_ostream &Out) {
assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
"Invalid mangleName() call, argument is not a variable or function!");
assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
"Invalid mangleName() call on 'structor decl!");
PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
getASTContext().getSourceManager(),
"Mangling declaration");
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
return Mangler.mangle(D);
}
// <this-adjustment> ::= <no-adjustment> | <static-adjustment> |
// <virtual-adjustment>
// <no-adjustment> ::= A # private near
// ::= B # private far
// ::= I # protected near
// ::= J # protected far
// ::= Q # public near
// ::= R # public far
// <static-adjustment> ::= G <static-offset> # private near
// ::= H <static-offset> # private far
// ::= O <static-offset> # protected near
// ::= P <static-offset> # protected far
// ::= W <static-offset> # public near
// ::= X <static-offset> # public far
// <virtual-adjustment> ::= $0 <virtual-shift> <static-offset> # private near
// ::= $1 <virtual-shift> <static-offset> # private far
// ::= $2 <virtual-shift> <static-offset> # protected near
// ::= $3 <virtual-shift> <static-offset> # protected far
// ::= $4 <virtual-shift> <static-offset> # public near
// ::= $5 <virtual-shift> <static-offset> # public far
// <virtual-shift> ::= <vtordisp-shift> | <vtordispex-shift>
// <vtordisp-shift> ::= <offset-to-vtordisp>
// <vtordispex-shift> ::= <offset-to-vbptr> <vbase-offset-offset>
// <offset-to-vtordisp>
static void mangleThunkThisAdjustment(AccessSpecifier AS,
const ThisAdjustment &Adjustment,
MicrosoftCXXNameMangler &Mangler,
raw_ostream &Out) {
if (!Adjustment.Virtual.isEmpty()) {
Out << '$';
char AccessSpec;
switch (AS) {
case AS_none:
llvm_unreachable("Unsupported access specifier");
case AS_private:
AccessSpec = '0';
break;
case AS_protected:
AccessSpec = '2';
break;
case AS_public:
AccessSpec = '4';
}
if (Adjustment.Virtual.Microsoft.VBPtrOffset) {
Out << 'R' << AccessSpec;
Mangler.mangleNumber(
static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VBPtrOffset));
Mangler.mangleNumber(
static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VBOffsetOffset));
Mangler.mangleNumber(
static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VtordispOffset));
Mangler.mangleNumber(static_cast<uint32_t>(Adjustment.NonVirtual));
} else {
Out << AccessSpec;
Mangler.mangleNumber(
static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VtordispOffset));
Mangler.mangleNumber(-static_cast<uint32_t>(Adjustment.NonVirtual));
}
} else if (Adjustment.NonVirtual != 0) {
switch (AS) {
case AS_none:
llvm_unreachable("Unsupported access specifier");
case AS_private:
Out << 'G';
break;
case AS_protected:
Out << 'O';
break;
case AS_public:
Out << 'W';
}
Mangler.mangleNumber(-static_cast<uint32_t>(Adjustment.NonVirtual));
} else {
switch (AS) {
case AS_none:
llvm_unreachable("Unsupported access specifier");
case AS_private:
Out << 'A';
break;
case AS_protected:
Out << 'I';
break;
case AS_public:
Out << 'Q';
}
}
}
void MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk(
const CXXMethodDecl *MD, const MethodVFTableLocation &ML,
raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << '?';
Mangler.mangleVirtualMemPtrThunk(MD, ML);
}
void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << '?';
Mangler.mangleName(MD);
// Usually the thunk uses the access specifier of the new method, but if this
// is a covariant return thunk, then MSVC always uses the public access
// specifier, and we do the same.
AccessSpecifier AS = Thunk.Return.isEmpty() ? MD->getAccess() : AS_public;
mangleThunkThisAdjustment(AS, Thunk.This, Mangler, MHO);
if (!Thunk.Return.isEmpty())
assert(Thunk.Method != nullptr &&
"Thunk info should hold the overridee decl");
const CXXMethodDecl *DeclForFPT = Thunk.Method ? Thunk.Method : MD;
Mangler.mangleFunctionType(
DeclForFPT->getType()->castAs<FunctionProtoType>(), MD);
}
void MicrosoftMangleContextImpl::mangleCXXDtorThunk(
const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &Adjustment, raw_ostream &Out) {
// FIXME: Actually, the dtor thunk should be emitted for vector deleting
// dtors rather than scalar deleting dtors. Just use the vector deleting dtor
// mangling manually until we support both deleting dtor types.
assert(Type == Dtor_Deleting);
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO, DD, Type);
Mangler.getStream() << "??_E";
Mangler.mangleName(DD->getParent());
mangleThunkThisAdjustment(DD->getAccess(), Adjustment, Mangler, MHO);
Mangler.mangleFunctionType(DD->getType()->castAs<FunctionProtoType>(), DD);
}
void MicrosoftMangleContextImpl::mangleCXXVFTable(
const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath,
raw_ostream &Out) {
// <mangled-name> ::= ?_7 <class-name> <storage-class>
// <cvr-qualifiers> [<name>] @
// NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
// is always '6' for vftables.
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
if (Derived->hasAttr<DLLImportAttr>())
Mangler.getStream() << "??_S";
else
Mangler.getStream() << "??_7";
Mangler.mangleName(Derived);
Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const.
for (const CXXRecordDecl *RD : BasePath)
Mangler.mangleName(RD);
Mangler.getStream() << '@';
}
void MicrosoftMangleContextImpl::mangleCXXVBTable(
const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath,
raw_ostream &Out) {
// <mangled-name> ::= ?_8 <class-name> <storage-class>
// <cvr-qualifiers> [<name>] @
// NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
// is always '7' for vbtables.
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << "??_8";
Mangler.mangleName(Derived);
Mangler.getStream() << "7B"; // '7' for vbtable, 'B' for const.
for (const CXXRecordDecl *RD : BasePath)
Mangler.mangleName(RD);
Mangler.getStream() << '@';
}
void MicrosoftMangleContextImpl::mangleCXXRTTI(QualType T, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << "??_R0";
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
Mangler.getStream() << "@8";
}
void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T,
raw_ostream &Out) {
MicrosoftCXXNameMangler Mangler(*this, Out);
Mangler.getStream() << '.';
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
}
void MicrosoftMangleContextImpl::mangleCXXVirtualDisplacementMap(
const CXXRecordDecl *SrcRD, const CXXRecordDecl *DstRD, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << "??_K";
Mangler.mangleName(SrcRD);
Mangler.getStream() << "$C";
Mangler.mangleName(DstRD);
}
void MicrosoftMangleContextImpl::mangleCXXThrowInfo(QualType T, bool IsConst,
bool IsVolatile,
bool IsUnaligned,
uint32_t NumEntries,
raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << "_TI";
if (IsConst)
Mangler.getStream() << 'C';
if (IsVolatile)
Mangler.getStream() << 'V';
if (IsUnaligned)
Mangler.getStream() << 'U';
Mangler.getStream() << NumEntries;
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
}
void MicrosoftMangleContextImpl::mangleCXXCatchableTypeArray(
QualType T, uint32_t NumEntries, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << "_CTA";
Mangler.getStream() << NumEntries;
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
}
void MicrosoftMangleContextImpl::mangleCXXCatchableType(
QualType T, const CXXConstructorDecl *CD, CXXCtorType CT, uint32_t Size,
uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBIndex,
raw_ostream &Out) {
MicrosoftCXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_CT";
llvm::SmallString<64> RTTIMangling;
{
llvm::raw_svector_ostream Stream(RTTIMangling);
msvc_hashing_ostream MHO(Stream);
mangleCXXRTTI(T, MHO);
}
Mangler.getStream() << RTTIMangling;
// VS2015 CTP6 omits the copy-constructor in the mangled name. This name is,
// in fact, superfluous but I'm not sure the change was made consciously.
llvm::SmallString<64> CopyCtorMangling;
if (!getASTContext().getLangOpts().isCompatibleWithMSVC(
LangOptions::MSVC2015) &&
CD) {
llvm::raw_svector_ostream Stream(CopyCtorMangling);
msvc_hashing_ostream MHO(Stream);
mangleCXXCtor(CD, CT, MHO);
}
Mangler.getStream() << CopyCtorMangling;
Mangler.getStream() << Size;
if (VBPtrOffset == -1) {
if (NVOffset) {
Mangler.getStream() << NVOffset;
}
} else {
Mangler.getStream() << NVOffset;
Mangler.getStream() << VBPtrOffset;
Mangler.getStream() << VBIndex;
}
}
void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassDescriptor(
const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset,
uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << "??_R1";
Mangler.mangleNumber(NVOffset);
Mangler.mangleNumber(VBPtrOffset);
Mangler.mangleNumber(VBTableOffset);
Mangler.mangleNumber(Flags);
Mangler.mangleName(Derived);
Mangler.getStream() << "8";
}
void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassArray(
const CXXRecordDecl *Derived, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << "??_R2";
Mangler.mangleName(Derived);
Mangler.getStream() << "8";
}
void MicrosoftMangleContextImpl::mangleCXXRTTIClassHierarchyDescriptor(
const CXXRecordDecl *Derived, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << "??_R3";
Mangler.mangleName(Derived);
Mangler.getStream() << "8";
}
void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator(
const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath,
raw_ostream &Out) {
// <mangled-name> ::= ?_R4 <class-name> <storage-class>
// <cvr-qualifiers> [<name>] @
// NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
// is always '6' for vftables.
llvm::SmallString<64> VFTableMangling;
llvm::raw_svector_ostream Stream(VFTableMangling);
mangleCXXVFTable(Derived, BasePath, Stream);
if (VFTableMangling.startswith("??@")) {
assert(VFTableMangling.endswith("@"));
Out << VFTableMangling << "??_R4@";
return;
}
assert(VFTableMangling.startswith("??_7") ||
VFTableMangling.startswith("??_S"));
Out << "??_R4" << StringRef(VFTableMangling).drop_front(4);
}
void MicrosoftMangleContextImpl::mangleSEHFilterExpression(
const NamedDecl *EnclosingDecl, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
// The function body is in the same comdat as the function with the handler,
// so the numbering here doesn't have to be the same across TUs.
//
// <mangled-name> ::= ?filt$ <filter-number> @0
Mangler.getStream() << "?filt$" << SEHFilterIds[EnclosingDecl]++ << "@0@";
Mangler.mangleName(EnclosingDecl);
}
void MicrosoftMangleContextImpl::mangleSEHFinallyBlock(
const NamedDecl *EnclosingDecl, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
// The function body is in the same comdat as the function with the handler,
// so the numbering here doesn't have to be the same across TUs.
//
// <mangled-name> ::= ?fin$ <filter-number> @0
Mangler.getStream() << "?fin$" << SEHFinallyIds[EnclosingDecl]++ << "@0@";
Mangler.mangleName(EnclosingDecl);
}
void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
// This is just a made up unique string for the purposes of tbaa. undname
// does *not* know how to demangle it.
MicrosoftCXXNameMangler Mangler(*this, Out);
Mangler.getStream() << '?';
Mangler.mangleType(T, SourceRange());
}
void MicrosoftMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D,
CXXCtorType Type,
raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler mangler(*this, MHO, D, Type);
mangler.mangle(D);
}
void MicrosoftMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D,
CXXDtorType Type,
raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler mangler(*this, MHO, D, Type);
mangler.mangle(D);
}
void MicrosoftMangleContextImpl::mangleReferenceTemporary(
const VarDecl *VD, unsigned ManglingNumber, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << "?$RT" << ManglingNumber << '@';
Mangler.mangle(VD, "");
}
void MicrosoftMangleContextImpl::mangleThreadSafeStaticGuardVariable(
const VarDecl *VD, unsigned GuardNum, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << "?$TSS" << GuardNum << '@';
Mangler.mangleNestedName(VD);
Mangler.getStream() << "@4HA";
}
void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD,
raw_ostream &Out) {
// <guard-name> ::= ?_B <postfix> @5 <scope-depth>
// ::= ?__J <postfix> @5 <scope-depth>
// ::= ?$S <guard-num> @ <postfix> @4IA
// The first mangling is what MSVC uses to guard static locals in inline
// functions. It uses a different mangling in external functions to support
// guarding more than 32 variables. MSVC rejects inline functions with more
// than 32 static locals. We don't fully implement the second mangling
// because those guards are not externally visible, and instead use LLVM's
// default renaming when creating a new guard variable.
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
bool Visible = VD->isExternallyVisible();
if (Visible) {
Mangler.getStream() << (VD->getTLSKind() ? "??__J" : "??_B");
} else {
Mangler.getStream() << "?$S1@";
}
unsigned ScopeDepth = 0;
if (Visible && !getNextDiscriminator(VD, ScopeDepth))
// If we do not have a discriminator and are emitting a guard variable for
// use at global scope, then mangling the nested name will not be enough to
// remove ambiguities.
Mangler.mangle(VD, "");
else
Mangler.mangleNestedName(VD);
Mangler.getStream() << (Visible ? "@5" : "@4IA");
if (ScopeDepth)
Mangler.mangleNumber(ScopeDepth);
}
void MicrosoftMangleContextImpl::mangleInitFiniStub(const VarDecl *D,
char CharCode,
raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
Mangler.getStream() << "??__" << CharCode;
if (D->isStaticDataMember()) {
Mangler.getStream() << '?';
Mangler.mangleName(D);
Mangler.mangleVariableEncoding(D);
Mangler.getStream() << "@@";
} else {
Mangler.mangleName(D);
}
// This is the function class mangling. These stubs are global, non-variadic,
// cdecl functions that return void and take no args.
Mangler.getStream() << "YAXXZ";
}
void MicrosoftMangleContextImpl::mangleDynamicInitializer(const VarDecl *D,
raw_ostream &Out) {
// <initializer-name> ::= ?__E <name> YAXXZ
mangleInitFiniStub(D, 'E', Out);
}
void
MicrosoftMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) {
// <destructor-name> ::= ?__F <name> YAXXZ
mangleInitFiniStub(D, 'F', Out);
}
void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
raw_ostream &Out) {
// <char-type> ::= 0 # char, char16_t, char32_t
// # (little endian char data in mangling)
// ::= 1 # wchar_t (big endian char data in mangling)
//
// <literal-length> ::= <non-negative integer> # the length of the literal
//
// <encoded-crc> ::= <hex digit>+ @ # crc of the literal including
// # trailing null bytes
//
// <encoded-string> ::= <simple character> # uninteresting character
// ::= '?$' <hex digit> <hex digit> # these two nibbles
// # encode the byte for the
// # character
// ::= '?' [a-z] # \xe1 - \xfa
// ::= '?' [A-Z] # \xc1 - \xda
// ::= '?' [0-9] # [,/\:. \n\t'-]
//
// <literal> ::= '??_C@_' <char-type> <literal-length> <encoded-crc>
// <encoded-string> '@'
MicrosoftCXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "??_C@_";
// The actual string length might be different from that of the string literal
// in cases like:
// char foo[3] = "foobar";
// char bar[42] = "foobar";
// Where it is truncated or zero-padded to fit the array. This is the length
// used for mangling, and any trailing null-bytes also need to be mangled.
unsigned StringLength = getASTContext()
.getAsConstantArrayType(SL->getType())
->getSize()
.getZExtValue();
unsigned StringByteLength = StringLength * SL->getCharByteWidth();
// <char-type>: The "kind" of string literal is encoded into the mangled name.
if (SL->isWide())
Mangler.getStream() << '1';
else
Mangler.getStream() << '0';
// <literal-length>: The next part of the mangled name consists of the length
// of the string in bytes.
Mangler.mangleNumber(StringByteLength);
auto GetLittleEndianByte = [&SL](unsigned Index) {
unsigned CharByteWidth = SL->getCharByteWidth();
if (Index / CharByteWidth >= SL->getLength())
return static_cast<char>(0);
uint32_t CodeUnit = SL->getCodeUnit(Index / CharByteWidth);
unsigned OffsetInCodeUnit = Index % CharByteWidth;
return static_cast<char>((CodeUnit >> (8 * OffsetInCodeUnit)) & 0xff);
};
auto GetBigEndianByte = [&SL](unsigned Index) {
unsigned CharByteWidth = SL->getCharByteWidth();
if (Index / CharByteWidth >= SL->getLength())
return static_cast<char>(0);
uint32_t CodeUnit = SL->getCodeUnit(Index / CharByteWidth);
unsigned OffsetInCodeUnit = (CharByteWidth - 1) - (Index % CharByteWidth);
return static_cast<char>((CodeUnit >> (8 * OffsetInCodeUnit)) & 0xff);
};
// CRC all the bytes of the StringLiteral.
llvm::JamCRC JC;
for (unsigned I = 0, E = StringByteLength; I != E; ++I)
JC.update(GetLittleEndianByte(I));
// <encoded-crc>: The CRC is encoded utilizing the standard number mangling
// scheme.
Mangler.mangleNumber(JC.getCRC());
// <encoded-string>: The mangled name also contains the first 32 bytes
// (including null-terminator bytes) of the encoded StringLiteral.
// Each character is encoded by splitting them into bytes and then encoding
// the constituent bytes.
auto MangleByte = [&Mangler](char Byte) {
// There are five different manglings for characters:
// - [a-zA-Z0-9_$]: A one-to-one mapping.
// - ?[a-z]: The range from \xe1 to \xfa.
// - ?[A-Z]: The range from \xc1 to \xda.
// - ?[0-9]: The set of [,/\:. \n\t'-].
// - ?$XX: A fallback which maps nibbles.
if (isIdentifierBody(Byte, /*AllowDollar=*/true)) {
Mangler.getStream() << Byte;
} else if (isLetter(Byte & 0x7f)) {
Mangler.getStream() << '?' << static_cast<char>(Byte & 0x7f);
} else {
const char SpecialChars[] = {',', '/', '\\', ':', '.',
' ', '\n', '\t', '\'', '-'};
const char *Pos =
std::find(std::begin(SpecialChars), std::end(SpecialChars), Byte);
if (Pos != std::end(SpecialChars)) {
Mangler.getStream() << '?' << (Pos - std::begin(SpecialChars));
} else {
Mangler.getStream() << "?$";
Mangler.getStream() << static_cast<char>('A' + ((Byte >> 4) & 0xf));
Mangler.getStream() << static_cast<char>('A' + (Byte & 0xf));
}
}
};
// Enforce our 32 bytes max, except wchar_t which gets 32 chars instead.
unsigned MaxBytesToMangle = SL->isWide() ? 64U : 32U;
unsigned NumBytesToMangle = std::min(MaxBytesToMangle, StringByteLength);
for (unsigned I = 0; I != NumBytesToMangle; ++I) {
if (SL->isWide())
MangleByte(GetBigEndianByte(I));
else
MangleByte(GetLittleEndianByte(I));
}
Mangler.getStream() << '@';
}
MicrosoftMangleContext *
MicrosoftMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
return new MicrosoftMangleContextImpl(Context, Diags);
}
Index: stable/11/contrib/llvm/tools/clang/lib/Basic/Version.cpp
===================================================================
--- stable/11/contrib/llvm/tools/clang/lib/Basic/Version.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/clang/lib/Basic/Version.cpp (revision 350259)
@@ -1,151 +1,151 @@
//===- Version.cpp - Clang Version Number -----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines several version-related utility functions for Clang.
//
//===----------------------------------------------------------------------===//
#include "clang/Basic/Version.h"
#include "clang/Basic/LLVM.h"
#include "clang/Config/config.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
#include <cstring>
#ifdef HAVE_SVN_VERSION_INC
# include "SVNVersion.inc"
#endif
namespace clang {
std::string getClangRepositoryPath() {
#if defined(CLANG_REPOSITORY_STRING)
return CLANG_REPOSITORY_STRING;
#else
#ifdef SVN_REPOSITORY
StringRef URL(SVN_REPOSITORY);
#else
StringRef URL("");
#endif
// If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us
// pick up a tag in an SVN export, for example.
- StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_800/final/lib/Basic/Version.cpp $");
+ StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_801/final/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
}
// Strip off version from a build from an integration branch.
URL = URL.slice(0, URL.find("/src/tools/clang"));
// Trim path prefix off, assuming path came from standard cfe path.
size_t Start = URL.find("cfe/");
if (Start != StringRef::npos)
URL = URL.substr(Start + 4);
return URL;
#endif
}
std::string getLLVMRepositoryPath() {
#ifdef LLVM_REPOSITORY
StringRef URL(LLVM_REPOSITORY);
#else
StringRef URL("");
#endif
// Trim path prefix off, assuming path came from standard llvm path.
// Leave "llvm/" prefix to distinguish the following llvm revision from the
// clang revision.
size_t Start = URL.find("llvm/");
if (Start != StringRef::npos)
URL = URL.substr(Start);
return URL;
}
std::string getClangRevision() {
#ifdef SVN_REVISION
return SVN_REVISION;
#else
return "";
#endif
}
std::string getLLVMRevision() {
#ifdef LLVM_REVISION
return LLVM_REVISION;
#else
return "";
#endif
}
std::string getClangFullRepositoryVersion() {
std::string buf;
llvm::raw_string_ostream OS(buf);
std::string Path = getClangRepositoryPath();
std::string Revision = getClangRevision();
if (!Path.empty() || !Revision.empty()) {
OS << '(';
if (!Path.empty())
OS << Path;
if (!Revision.empty()) {
if (!Path.empty())
OS << ' ';
OS << Revision;
}
OS << ')';
}
// Support LLVM in a separate repository.
std::string LLVMRev = getLLVMRevision();
if (!LLVMRev.empty() && LLVMRev != Revision) {
OS << " (";
std::string LLVMRepo = getLLVMRepositoryPath();
if (!LLVMRepo.empty())
OS << LLVMRepo << ' ';
OS << LLVMRev << ')';
}
return OS.str();
}
std::string getClangFullVersion() {
return getClangToolFullVersion("clang");
}
std::string getClangToolFullVersion(StringRef ToolName) {
std::string buf;
llvm::raw_string_ostream OS(buf);
#ifdef CLANG_VENDOR
OS << CLANG_VENDOR;
#endif
OS << ToolName << " version " CLANG_VERSION_STRING " "
<< getClangFullRepositoryVersion();
// If vendor supplied, include the base LLVM version as well.
#ifdef CLANG_VENDOR
OS << " (based on " << BACKEND_PACKAGE_STRING << ")";
#endif
return OS.str();
}
std::string getClangFullCPPVersion() {
// The version string we report in __VERSION__ is just a compacted version of
// the one we report on the command line.
std::string buf;
llvm::raw_string_ostream OS(buf);
#ifdef CLANG_VENDOR
OS << CLANG_VENDOR;
#endif
OS << "Clang " CLANG_VERSION_STRING " " << getClangFullRepositoryVersion();
return OS.str();
}
} // end namespace clang
Index: stable/11/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- stable/11/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp (revision 350259)
@@ -1,4505 +1,4497 @@
//===--- CGDebugInfo.cpp - Emit Debug Information for a Module ------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This coordinates the debug information generation while generating code.
//
//===----------------------------------------------------------------------===//
#include "CGDebugInfo.h"
#include "CGBlocks.h"
#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/ModuleMap.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/Path.h"
using namespace clang;
using namespace clang::CodeGen;
static uint32_t getTypeAlignIfRequired(const Type *Ty, const ASTContext &Ctx) {
auto TI = Ctx.getTypeInfo(Ty);
return TI.AlignIsRequired ? TI.Align : 0;
}
static uint32_t getTypeAlignIfRequired(QualType Ty, const ASTContext &Ctx) {
return getTypeAlignIfRequired(Ty.getTypePtr(), Ctx);
}
static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) {
return D->hasAttr<AlignedAttr>() ? D->getMaxAlignment() : 0;
}
CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
: CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()),
DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs),
DBuilder(CGM.getModule()) {
for (const auto &KV : CGM.getCodeGenOpts().DebugPrefixMap)
DebugPrefixMap[KV.first] = KV.second;
CreateCompileUnit();
}
CGDebugInfo::~CGDebugInfo() {
assert(LexicalBlockStack.empty() &&
"Region stack mismatch, stack not empty!");
}
ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF,
SourceLocation TemporaryLocation)
: CGF(&CGF) {
init(TemporaryLocation);
}
ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF,
bool DefaultToEmpty,
SourceLocation TemporaryLocation)
: CGF(&CGF) {
init(TemporaryLocation, DefaultToEmpty);
}
void ApplyDebugLocation::init(SourceLocation TemporaryLocation,
bool DefaultToEmpty) {
auto *DI = CGF->getDebugInfo();
if (!DI) {
CGF = nullptr;
return;
}
OriginalLocation = CGF->Builder.getCurrentDebugLocation();
if (OriginalLocation && !DI->CGM.getExpressionLocationsEnabled())
return;
if (TemporaryLocation.isValid()) {
DI->EmitLocation(CGF->Builder, TemporaryLocation);
return;
}
if (DefaultToEmpty) {
CGF->Builder.SetCurrentDebugLocation(llvm::DebugLoc());
return;
}
// Construct a location that has a valid scope, but no line info.
assert(!DI->LexicalBlockStack.empty());
CGF->Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(
0, 0, DI->LexicalBlockStack.back(), DI->getInlinedAt()));
}
ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, const Expr *E)
: CGF(&CGF) {
init(E->getExprLoc());
}
ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc)
: CGF(&CGF) {
if (!CGF.getDebugInfo()) {
this->CGF = nullptr;
return;
}
OriginalLocation = CGF.Builder.getCurrentDebugLocation();
if (Loc)
CGF.Builder.SetCurrentDebugLocation(std::move(Loc));
}
ApplyDebugLocation::~ApplyDebugLocation() {
// Query CGF so the location isn't overwritten when location updates are
// temporarily disabled (for C++ default function arguments)
if (CGF)
CGF->Builder.SetCurrentDebugLocation(std::move(OriginalLocation));
}
ApplyInlineDebugLocation::ApplyInlineDebugLocation(CodeGenFunction &CGF,
GlobalDecl InlinedFn)
: CGF(&CGF) {
if (!CGF.getDebugInfo()) {
this->CGF = nullptr;
return;
}
auto &DI = *CGF.getDebugInfo();
SavedLocation = DI.getLocation();
assert((DI.getInlinedAt() ==
CGF.Builder.getCurrentDebugLocation()->getInlinedAt()) &&
"CGDebugInfo and IRBuilder are out of sync");
DI.EmitInlineFunctionStart(CGF.Builder, InlinedFn);
}
ApplyInlineDebugLocation::~ApplyInlineDebugLocation() {
if (!CGF)
return;
auto &DI = *CGF->getDebugInfo();
DI.EmitInlineFunctionEnd(CGF->Builder);
DI.EmitLocation(CGF->Builder, SavedLocation);
}
void CGDebugInfo::setLocation(SourceLocation Loc) {
// If the new location isn't valid return.
if (Loc.isInvalid())
return;
CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc);
// If we've changed files in the middle of a lexical scope go ahead
// and create a new lexical scope with file node if it's different
// from the one in the scope.
if (LexicalBlockStack.empty())
return;
SourceManager &SM = CGM.getContext().getSourceManager();
auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back());
PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc);
if (PCLoc.isInvalid() || Scope->getFile() == getOrCreateFile(CurLoc))
return;
if (auto *LBF = dyn_cast<llvm::DILexicalBlockFile>(Scope)) {
LexicalBlockStack.pop_back();
LexicalBlockStack.emplace_back(DBuilder.createLexicalBlockFile(
LBF->getScope(), getOrCreateFile(CurLoc)));
} else if (isa<llvm::DILexicalBlock>(Scope) ||
isa<llvm::DISubprogram>(Scope)) {
LexicalBlockStack.pop_back();
LexicalBlockStack.emplace_back(
DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc)));
}
}
llvm::DIScope *CGDebugInfo::getDeclContextDescriptor(const Decl *D) {
llvm::DIScope *Mod = getParentModuleOrNull(D);
return getContextDescriptor(cast<Decl>(D->getDeclContext()),
Mod ? Mod : TheCU);
}
llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context,
llvm::DIScope *Default) {
if (!Context)
return Default;
auto I = RegionMap.find(Context);
if (I != RegionMap.end()) {
llvm::Metadata *V = I->second;
return dyn_cast_or_null<llvm::DIScope>(V);
}
// Check namespace.
if (const auto *NSDecl = dyn_cast<NamespaceDecl>(Context))
return getOrCreateNamespace(NSDecl);
if (const auto *RDecl = dyn_cast<RecordDecl>(Context))
if (!RDecl->isDependentType())
return getOrCreateType(CGM.getContext().getTypeDeclType(RDecl),
TheCU->getFile());
return Default;
}
PrintingPolicy CGDebugInfo::getPrintingPolicy() const {
PrintingPolicy PP = CGM.getContext().getPrintingPolicy();
// If we're emitting codeview, it's important to try to match MSVC's naming so
// that visualizers written for MSVC will trigger for our class names. In
// particular, we can't have spaces between arguments of standard templates
// like basic_string and vector.
if (CGM.getCodeGenOpts().EmitCodeView)
PP.MSVCFormatting = true;
// Apply -fdebug-prefix-map.
PP.RemapFilePaths = true;
PP.remapPath = [this](StringRef Path) { return remapDIPath(Path); };
return PP;
}
StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
assert(FD && "Invalid FunctionDecl!");
IdentifierInfo *FII = FD->getIdentifier();
FunctionTemplateSpecializationInfo *Info =
FD->getTemplateSpecializationInfo();
// Emit the unqualified name in normal operation. LLVM and the debugger can
// compute the fully qualified name from the scope chain. If we're only
// emitting line table info, there won't be any scope chains, so emit the
// fully qualified name here so that stack traces are more accurate.
// FIXME: Do this when emitting DWARF as well as when emitting CodeView after
// evaluating the size impact.
bool UseQualifiedName = DebugKind == codegenoptions::DebugLineTablesOnly &&
CGM.getCodeGenOpts().EmitCodeView;
if (!Info && FII && !UseQualifiedName)
return FII->getName();
SmallString<128> NS;
llvm::raw_svector_ostream OS(NS);
if (!UseQualifiedName)
FD->printName(OS);
else
FD->printQualifiedName(OS, getPrintingPolicy());
// Add any template specialization args.
if (Info) {
const TemplateArgumentList *TArgs = Info->TemplateArguments;
printTemplateArgumentList(OS, TArgs->asArray(), getPrintingPolicy());
}
// Copy this name on the side and use its reference.
return internString(OS.str());
}
StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
SmallString<256> MethodName;
llvm::raw_svector_ostream OS(MethodName);
OS << (OMD->isInstanceMethod() ? '-' : '+') << '[';
const DeclContext *DC = OMD->getDeclContext();
if (const auto *OID = dyn_cast<ObjCImplementationDecl>(DC)) {
OS << OID->getName();
} else if (const auto *OID = dyn_cast<ObjCInterfaceDecl>(DC)) {
OS << OID->getName();
} else if (const auto *OC = dyn_cast<ObjCCategoryDecl>(DC)) {
if (OC->IsClassExtension()) {
OS << OC->getClassInterface()->getName();
} else {
OS << OC->getIdentifier()->getNameStart() << '('
<< OC->getIdentifier()->getNameStart() << ')';
}
} else if (const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) {
OS << OCD->getClassInterface()->getName() << '(' << OCD->getName() << ')';
} else if (isa<ObjCProtocolDecl>(DC)) {
// We can extract the type of the class from the self pointer.
if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) {
QualType ClassTy =
cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType();
ClassTy.print(OS, PrintingPolicy(LangOptions()));
}
}
OS << ' ' << OMD->getSelector().getAsString() << ']';
return internString(OS.str());
}
StringRef CGDebugInfo::getSelectorName(Selector S) {
return internString(S.getAsString());
}
StringRef CGDebugInfo::getClassName(const RecordDecl *RD) {
if (isa<ClassTemplateSpecializationDecl>(RD)) {
SmallString<128> Name;
llvm::raw_svector_ostream OS(Name);
RD->getNameForDiagnostic(OS, getPrintingPolicy(),
/*Qualified*/ false);
// Copy this name on the side and use its reference.
return internString(Name);
}
// quick optimization to avoid having to intern strings that are already
// stored reliably elsewhere
if (const IdentifierInfo *II = RD->getIdentifier())
return II->getName();
// The CodeView printer in LLVM wants to see the names of unnamed types: it is
// used to reconstruct the fully qualified type names.
if (CGM.getCodeGenOpts().EmitCodeView) {
if (const TypedefNameDecl *D = RD->getTypedefNameForAnonDecl()) {
assert(RD->getDeclContext() == D->getDeclContext() &&
"Typedef should not be in another decl context!");
assert(D->getDeclName().getAsIdentifierInfo() &&
"Typedef was not named!");
return D->getDeclName().getAsIdentifierInfo()->getName();
}
if (CGM.getLangOpts().CPlusPlus) {
StringRef Name;
ASTContext &Context = CGM.getContext();
if (const DeclaratorDecl *DD = Context.getDeclaratorForUnnamedTagDecl(RD))
// Anonymous types without a name for linkage purposes have their
// declarator mangled in if they have one.
Name = DD->getName();
else if (const TypedefNameDecl *TND =
Context.getTypedefNameForUnnamedTagDecl(RD))
// Anonymous types without a name for linkage purposes have their
// associate typedef mangled in if they have one.
Name = TND->getName();
if (!Name.empty()) {
SmallString<256> UnnamedType("<unnamed-type-");
UnnamedType += Name;
UnnamedType += '>';
return internString(UnnamedType);
}
}
}
return StringRef();
}
Optional<llvm::DIFile::ChecksumKind>
CGDebugInfo::computeChecksum(FileID FID, SmallString<32> &Checksum) const {
Checksum.clear();
if (!CGM.getCodeGenOpts().EmitCodeView &&
CGM.getCodeGenOpts().DwarfVersion < 5)
return None;
SourceManager &SM = CGM.getContext().getSourceManager();
bool Invalid;
llvm::MemoryBuffer *MemBuffer = SM.getBuffer(FID, &Invalid);
if (Invalid)
return None;
llvm::MD5 Hash;
llvm::MD5::MD5Result Result;
Hash.update(MemBuffer->getBuffer());
Hash.final(Result);
Hash.stringifyResult(Result, Checksum);
return llvm::DIFile::CSK_MD5;
}
Optional<StringRef> CGDebugInfo::getSource(const SourceManager &SM,
FileID FID) {
if (!CGM.getCodeGenOpts().EmbedSource)
return None;
bool SourceInvalid = false;
StringRef Source = SM.getBufferData(FID, &SourceInvalid);
if (SourceInvalid)
return None;
return Source;
}
llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
if (!Loc.isValid())
// If Location is not valid then use main input file.
return TheCU->getFile();
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
StringRef FileName = PLoc.getFilename();
if (PLoc.isInvalid() || FileName.empty())
// If the location is not valid then use main input file.
return TheCU->getFile();
// Cache the results.
auto It = DIFileCache.find(FileName.data());
if (It != DIFileCache.end()) {
// Verify that the information still exists.
if (llvm::Metadata *V = It->second)
return cast<llvm::DIFile>(V);
}
SmallString<32> Checksum;
Optional<llvm::DIFile::ChecksumKind> CSKind =
computeChecksum(SM.getFileID(Loc), Checksum);
Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo;
if (CSKind)
CSInfo.emplace(*CSKind, Checksum);
return createFile(FileName, CSInfo, getSource(SM, SM.getFileID(Loc)));
}
llvm::DIFile *
CGDebugInfo::createFile(StringRef FileName,
Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo,
Optional<StringRef> Source) {
StringRef Dir;
StringRef File;
std::string RemappedFile = remapDIPath(FileName);
std::string CurDir = remapDIPath(getCurrentDirname());
SmallString<128> DirBuf;
SmallString<128> FileBuf;
if (llvm::sys::path::is_absolute(RemappedFile)) {
// Strip the common prefix (if it is more than just "/") from current
// directory and FileName for a more space-efficient encoding.
auto FileIt = llvm::sys::path::begin(RemappedFile);
auto FileE = llvm::sys::path::end(RemappedFile);
auto CurDirIt = llvm::sys::path::begin(CurDir);
auto CurDirE = llvm::sys::path::end(CurDir);
for (; CurDirIt != CurDirE && *CurDirIt == *FileIt; ++CurDirIt, ++FileIt)
llvm::sys::path::append(DirBuf, *CurDirIt);
if (std::distance(llvm::sys::path::begin(CurDir), CurDirIt) == 1) {
// The common prefix only the root; stripping it would cause
// LLVM diagnostic locations to be more confusing.
Dir = {};
File = RemappedFile;
} else {
for (; FileIt != FileE; ++FileIt)
llvm::sys::path::append(FileBuf, *FileIt);
Dir = DirBuf;
File = FileBuf;
}
} else {
Dir = CurDir;
File = RemappedFile;
}
llvm::DIFile *F = DBuilder.createFile(File, Dir, CSInfo, Source);
DIFileCache[FileName.data()].reset(F);
return F;
}
std::string CGDebugInfo::remapDIPath(StringRef Path) const {
for (const auto &Entry : DebugPrefixMap)
if (Path.startswith(Entry.first))
return (Twine(Entry.second) + Path.substr(Entry.first.size())).str();
return Path.str();
}
unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
if (Loc.isInvalid() && CurLoc.isInvalid())
return 0;
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
return PLoc.isValid() ? PLoc.getLine() : 0;
}
unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) {
// We may not want column information at all.
if (!Force && !CGM.getCodeGenOpts().DebugColumnInfo)
return 0;
// If the location is invalid then use the current column.
if (Loc.isInvalid() && CurLoc.isInvalid())
return 0;
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
return PLoc.isValid() ? PLoc.getColumn() : 0;
}
StringRef CGDebugInfo::getCurrentDirname() {
if (!CGM.getCodeGenOpts().DebugCompilationDir.empty())
return CGM.getCodeGenOpts().DebugCompilationDir;
if (!CWDName.empty())
return CWDName;
SmallString<256> CWD;
llvm::sys::fs::current_path(CWD);
return CWDName = internString(CWD);
}
void CGDebugInfo::CreateCompileUnit() {
SmallString<32> Checksum;
Optional<llvm::DIFile::ChecksumKind> CSKind;
Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo;
// Should we be asking the SourceManager for the main file name, instead of
// accepting it as an argument? This just causes the main file name to
// mismatch with source locations and create extra lexical scopes or
// mismatched debug info (a CU with a DW_AT_file of "-", because that's what
// the driver passed, but functions/other things have DW_AT_file of "<stdin>"
// because that's what the SourceManager says)
// Get absolute path name.
SourceManager &SM = CGM.getContext().getSourceManager();
std::string MainFileName = CGM.getCodeGenOpts().MainFileName;
if (MainFileName.empty())
MainFileName = "<stdin>";
// The main file name provided via the "-main-file-name" option contains just
// the file name itself with no path information. This file name may have had
// a relative path, so we look into the actual file entry for the main
// file to determine the real absolute path for the file.
std::string MainFileDir;
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
MainFileDir = remapDIPath(MainFile->getDir()->getName());
if (MainFileDir != ".") {
llvm::SmallString<1024> MainFileDirSS(MainFileDir);
llvm::sys::path::append(MainFileDirSS, MainFileName);
MainFileName = MainFileDirSS.str();
}
// If the main file name provided is identical to the input file name, and
// if the input file is a preprocessed source, use the module name for
// debug info. The module name comes from the name specified in the first
// linemarker if the input is a preprocessed source.
if (MainFile->getName() == MainFileName &&
FrontendOptions::getInputKindForExtension(
MainFile->getName().rsplit('.').second)
.isPreprocessed())
MainFileName = CGM.getModule().getName().str();
CSKind = computeChecksum(SM.getMainFileID(), Checksum);
}
llvm::dwarf::SourceLanguage LangTag;
const LangOptions &LO = CGM.getLangOpts();
if (LO.CPlusPlus) {
if (LO.ObjC)
LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus;
else
LangTag = llvm::dwarf::DW_LANG_C_plus_plus;
} else if (LO.ObjC) {
LangTag = llvm::dwarf::DW_LANG_ObjC;
} else if (LO.RenderScript) {
LangTag = llvm::dwarf::DW_LANG_GOOGLE_RenderScript;
} else if (LO.C99) {
LangTag = llvm::dwarf::DW_LANG_C99;
} else {
LangTag = llvm::dwarf::DW_LANG_C89;
}
std::string Producer = getClangFullVersion();
// Figure out which version of the ObjC runtime we have.
unsigned RuntimeVers = 0;
if (LO.ObjC)
RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1;
llvm::DICompileUnit::DebugEmissionKind EmissionKind;
switch (DebugKind) {
case codegenoptions::NoDebugInfo:
case codegenoptions::LocTrackingOnly:
EmissionKind = llvm::DICompileUnit::NoDebug;
break;
case codegenoptions::DebugLineTablesOnly:
EmissionKind = llvm::DICompileUnit::LineTablesOnly;
break;
case codegenoptions::DebugDirectivesOnly:
EmissionKind = llvm::DICompileUnit::DebugDirectivesOnly;
break;
case codegenoptions::LimitedDebugInfo:
case codegenoptions::FullDebugInfo:
EmissionKind = llvm::DICompileUnit::FullDebug;
break;
}
uint64_t DwoId = 0;
auto &CGOpts = CGM.getCodeGenOpts();
// The DIFile used by the CU is distinct from the main source
// file. Its directory part specifies what becomes the
// DW_AT_comp_dir (the compilation directory), even if the source
// file was specified with an absolute path.
if (CSKind)
CSInfo.emplace(*CSKind, Checksum);
llvm::DIFile *CUFile = DBuilder.createFile(
remapDIPath(MainFileName), remapDIPath(getCurrentDirname()), CSInfo,
getSource(SM, SM.getMainFileID()));
// Create new compile unit.
TheCU = DBuilder.createCompileUnit(
LangTag, CUFile, CGOpts.EmitVersionIdentMetadata ? Producer : "",
LO.Optimize || CGOpts.PrepareForLTO || CGOpts.PrepareForThinLTO,
CGOpts.DwarfDebugFlags, RuntimeVers,
(CGOpts.getSplitDwarfMode() != CodeGenOptions::NoFission)
? ""
: CGOpts.SplitDwarfFile,
EmissionKind, DwoId, CGOpts.SplitDwarfInlining,
CGOpts.DebugInfoForProfiling,
CGM.getTarget().getTriple().isNVPTX()
? llvm::DICompileUnit::DebugNameTableKind::None
: static_cast<llvm::DICompileUnit::DebugNameTableKind>(
CGOpts.DebugNameTable),
CGOpts.DebugRangesBaseAddress);
}
llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
llvm::dwarf::TypeKind Encoding;
StringRef BTName;
switch (BT->getKind()) {
#define BUILTIN_TYPE(Id, SingletonId)
#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
llvm_unreachable("Unexpected builtin type");
case BuiltinType::NullPtr:
return DBuilder.createNullPtrType();
case BuiltinType::Void:
return nullptr;
case BuiltinType::ObjCClass:
if (!ClassTy)
ClassTy =
DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
"objc_class", TheCU, TheCU->getFile(), 0);
return ClassTy;
case BuiltinType::ObjCId: {
// typedef struct objc_class *Class;
// typedef struct objc_object {
// Class isa;
// } *id;
if (ObjTy)
return ObjTy;
if (!ClassTy)
ClassTy =
DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
"objc_class", TheCU, TheCU->getFile(), 0);
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
auto *ISATy = DBuilder.createPointerType(ClassTy, Size);
ObjTy = DBuilder.createStructType(TheCU, "objc_object", TheCU->getFile(), 0,
0, 0, llvm::DINode::FlagZero, nullptr,
llvm::DINodeArray());
DBuilder.replaceArrays(
ObjTy, DBuilder.getOrCreateArray(&*DBuilder.createMemberType(
ObjTy, "isa", TheCU->getFile(), 0, Size, 0, 0,
llvm::DINode::FlagZero, ISATy)));
return ObjTy;
}
case BuiltinType::ObjCSel: {
if (!SelTy)
SelTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
"objc_selector", TheCU,
TheCU->getFile(), 0);
return SelTy;
}
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
case BuiltinType::Id: \
return getOrCreateStructPtrType("opencl_" #ImgType "_" #Suffix "_t", \
SingletonId);
#include "clang/Basic/OpenCLImageTypes.def"
case BuiltinType::OCLSampler:
return getOrCreateStructPtrType("opencl_sampler_t", OCLSamplerDITy);
case BuiltinType::OCLEvent:
return getOrCreateStructPtrType("opencl_event_t", OCLEventDITy);
case BuiltinType::OCLClkEvent:
return getOrCreateStructPtrType("opencl_clk_event_t", OCLClkEventDITy);
case BuiltinType::OCLQueue:
return getOrCreateStructPtrType("opencl_queue_t", OCLQueueDITy);
case BuiltinType::OCLReserveID:
return getOrCreateStructPtrType("opencl_reserve_id_t", OCLReserveIDDITy);
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id: \
return getOrCreateStructPtrType("opencl_" #ExtType, Id##Ty);
#include "clang/Basic/OpenCLExtensionTypes.def"
case BuiltinType::UChar:
case BuiltinType::Char_U:
Encoding = llvm::dwarf::DW_ATE_unsigned_char;
break;
case BuiltinType::Char_S:
case BuiltinType::SChar:
Encoding = llvm::dwarf::DW_ATE_signed_char;
break;
case BuiltinType::Char8:
case BuiltinType::Char16:
case BuiltinType::Char32:
Encoding = llvm::dwarf::DW_ATE_UTF;
break;
case BuiltinType::UShort:
case BuiltinType::UInt:
case BuiltinType::UInt128:
case BuiltinType::ULong:
case BuiltinType::WChar_U:
case BuiltinType::ULongLong:
Encoding = llvm::dwarf::DW_ATE_unsigned;
break;
case BuiltinType::Short:
case BuiltinType::Int:
case BuiltinType::Int128:
case BuiltinType::Long:
case BuiltinType::WChar_S:
case BuiltinType::LongLong:
Encoding = llvm::dwarf::DW_ATE_signed;
break;
case BuiltinType::Bool:
Encoding = llvm::dwarf::DW_ATE_boolean;
break;
case BuiltinType::Half:
case BuiltinType::Float:
case BuiltinType::LongDouble:
case BuiltinType::Float16:
case BuiltinType::Float128:
case BuiltinType::Double:
// FIXME: For targets where long double and __float128 have the same size,
// they are currently indistinguishable in the debugger without some
// special treatment. However, there is currently no consensus on encoding
// and this should be updated once a DWARF encoding exists for distinct
// floating point types of the same size.
Encoding = llvm::dwarf::DW_ATE_float;
break;
case BuiltinType::ShortAccum:
case BuiltinType::Accum:
case BuiltinType::LongAccum:
case BuiltinType::ShortFract:
case BuiltinType::Fract:
case BuiltinType::LongFract:
case BuiltinType::SatShortFract:
case BuiltinType::SatFract:
case BuiltinType::SatLongFract:
case BuiltinType::SatShortAccum:
case BuiltinType::SatAccum:
case BuiltinType::SatLongAccum:
Encoding = llvm::dwarf::DW_ATE_signed_fixed;
break;
case BuiltinType::UShortAccum:
case BuiltinType::UAccum:
case BuiltinType::ULongAccum:
case BuiltinType::UShortFract:
case BuiltinType::UFract:
case BuiltinType::ULongFract:
case BuiltinType::SatUShortAccum:
case BuiltinType::SatUAccum:
case BuiltinType::SatULongAccum:
case BuiltinType::SatUShortFract:
case BuiltinType::SatUFract:
case BuiltinType::SatULongFract:
Encoding = llvm::dwarf::DW_ATE_unsigned_fixed;
break;
}
switch (BT->getKind()) {
case BuiltinType::Long:
BTName = "long int";
break;
case BuiltinType::LongLong:
BTName = "long long int";
break;
case BuiltinType::ULong:
BTName = "long unsigned int";
break;
case BuiltinType::ULongLong:
BTName = "long long unsigned int";
break;
default:
BTName = BT->getName(CGM.getLangOpts());
break;
}
// Bit size and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(BT);
return DBuilder.createBasicType(BTName, Size, Encoding);
}
llvm::DIType *CGDebugInfo::CreateType(const ComplexType *Ty) {
// Bit size and offset of the type.
llvm::dwarf::TypeKind Encoding = llvm::dwarf::DW_ATE_complex_float;
if (Ty->isComplexIntegerType())
Encoding = llvm::dwarf::DW_ATE_lo_user;
uint64_t Size = CGM.getContext().getTypeSize(Ty);
return DBuilder.createBasicType("complex", Size, Encoding);
}
llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty,
llvm::DIFile *Unit) {
QualifierCollector Qc;
const Type *T = Qc.strip(Ty);
// Ignore these qualifiers for now.
Qc.removeObjCGCAttr();
Qc.removeAddressSpace();
Qc.removeObjCLifetime();
// We will create one Derived type for one qualifier and recurse to handle any
// additional ones.
llvm::dwarf::Tag Tag;
if (Qc.hasConst()) {
Tag = llvm::dwarf::DW_TAG_const_type;
Qc.removeConst();
} else if (Qc.hasVolatile()) {
Tag = llvm::dwarf::DW_TAG_volatile_type;
Qc.removeVolatile();
} else if (Qc.hasRestrict()) {
Tag = llvm::dwarf::DW_TAG_restrict_type;
Qc.removeRestrict();
} else {
assert(Qc.empty() && "Unknown type qualifier for debug info");
return getOrCreateType(QualType(T, 0), Unit);
}
auto *FromTy = getOrCreateType(Qc.apply(CGM.getContext(), T), Unit);
// No need to fill in the Name, Line, Size, Alignment, Offset in case of
// CVR derived types.
return DBuilder.createQualifiedType(Tag, FromTy);
}
llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty,
llvm::DIFile *Unit) {
// The frontend treats 'id' as a typedef to an ObjCObjectType,
// whereas 'id<protocol>' is treated as an ObjCPointerType. For the
// debug info, we want to emit 'id' in both cases.
if (Ty->isObjCQualifiedIdType())
return getOrCreateType(CGM.getContext().getObjCIdType(), Unit);
return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
Ty->getPointeeType(), Unit);
}
llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty,
llvm::DIFile *Unit) {
return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
Ty->getPointeeType(), Unit);
}
/// \return whether a C++ mangling exists for the type defined by TD.
static bool hasCXXMangling(const TagDecl *TD, llvm::DICompileUnit *TheCU) {
switch (TheCU->getSourceLanguage()) {
case llvm::dwarf::DW_LANG_C_plus_plus:
return true;
case llvm::dwarf::DW_LANG_ObjC_plus_plus:
return isa<CXXRecordDecl>(TD) || isa<EnumDecl>(TD);
default:
return false;
}
}
// Determines if the debug info for this tag declaration needs a type
// identifier. The purpose of the unique identifier is to deduplicate type
// information for identical types across TUs. Because of the C++ one definition
// rule (ODR), it is valid to assume that the type is defined the same way in
// every TU and its debug info is equivalent.
//
// C does not have the ODR, and it is common for codebases to contain multiple
// different definitions of a struct with the same name in different TUs.
// Therefore, if the type doesn't have a C++ mangling, don't give it an
// identifer. Type information in C is smaller and simpler than C++ type
// information, so the increase in debug info size is negligible.
//
// If the type is not externally visible, it should be unique to the current TU,
// and should not need an identifier to participate in type deduplication.
// However, when emitting CodeView, the format internally uses these
// unique type name identifers for references between debug info. For example,
// the method of a class in an anonymous namespace uses the identifer to refer
// to its parent class. The Microsoft C++ ABI attempts to provide unique names
// for such types, so when emitting CodeView, always use identifiers for C++
// types. This may create problems when attempting to emit CodeView when the MS
// C++ ABI is not in use.
static bool needsTypeIdentifier(const TagDecl *TD, CodeGenModule &CGM,
llvm::DICompileUnit *TheCU) {
// We only add a type identifier for types with C++ name mangling.
if (!hasCXXMangling(TD, TheCU))
return false;
// Externally visible types with C++ mangling need a type identifier.
if (TD->isExternallyVisible())
return true;
// CodeView types with C++ mangling need a type identifier.
if (CGM.getCodeGenOpts().EmitCodeView)
return true;
return false;
}
// Returns a unique type identifier string if one exists, or an empty string.
static SmallString<256> getTypeIdentifier(const TagType *Ty, CodeGenModule &CGM,
llvm::DICompileUnit *TheCU) {
SmallString<256> Identifier;
const TagDecl *TD = Ty->getDecl();
if (!needsTypeIdentifier(TD, CGM, TheCU))
return Identifier;
// TODO: This is using the RTTI name. Is there a better way to get
// a unique string for a type?
llvm::raw_svector_ostream Out(Identifier);
CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(QualType(Ty, 0), Out);
return Identifier;
}
/// \return the appropriate DWARF tag for a composite type.
static llvm::dwarf::Tag getTagForRecord(const RecordDecl *RD) {
llvm::dwarf::Tag Tag;
if (RD->isStruct() || RD->isInterface())
Tag = llvm::dwarf::DW_TAG_structure_type;
else if (RD->isUnion())
Tag = llvm::dwarf::DW_TAG_union_type;
else {
// FIXME: This could be a struct type giving a default visibility different
// than C++ class type, but needs llvm metadata changes first.
assert(RD->isClass());
Tag = llvm::dwarf::DW_TAG_class_type;
}
return Tag;
}
llvm::DICompositeType *
CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
llvm::DIScope *Ctx) {
const RecordDecl *RD = Ty->getDecl();
if (llvm::DIType *T = getTypeOrNull(CGM.getContext().getRecordType(RD)))
return cast<llvm::DICompositeType>(T);
llvm::DIFile *DefUnit = getOrCreateFile(RD->getLocation());
unsigned Line = getLineNumber(RD->getLocation());
StringRef RDName = getClassName(RD);
uint64_t Size = 0;
uint32_t Align = 0;
// Create the type.
SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU);
llvm::DICompositeType *RetTy = DBuilder.createReplaceableCompositeType(
getTagForRecord(RD), RDName, Ctx, DefUnit, Line, 0, Size, Align,
llvm::DINode::FlagFwdDecl, Identifier);
if (CGM.getCodeGenOpts().DebugFwdTemplateParams)
if (auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD))
DBuilder.replaceArrays(RetTy, llvm::DINodeArray(),
CollectCXXTemplateParams(TSpecial, DefUnit));
ReplaceMap.emplace_back(
std::piecewise_construct, std::make_tuple(Ty),
std::make_tuple(static_cast<llvm::Metadata *>(RetTy)));
return RetTy;
}
llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag,
const Type *Ty,
QualType PointeeTy,
llvm::DIFile *Unit) {
// Bit size, align and offset of the type.
// Size is always the size of a pointer. We can't use getTypeSize here
// because that does not return the correct value for references.
unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(PointeeTy);
uint64_t Size = CGM.getTarget().getPointerWidth(AddressSpace);
auto Align = getTypeAlignIfRequired(Ty, CGM.getContext());
Optional<unsigned> DWARFAddressSpace =
CGM.getTarget().getDWARFAddressSpace(AddressSpace);
if (Tag == llvm::dwarf::DW_TAG_reference_type ||
Tag == llvm::dwarf::DW_TAG_rvalue_reference_type)
return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit),
Size, Align, DWARFAddressSpace);
else
return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size,
Align, DWARFAddressSpace);
}
llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name,
llvm::DIType *&Cache) {
if (Cache)
return Cache;
Cache = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, Name,
TheCU, TheCU->getFile(), 0);
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
Cache = DBuilder.createPointerType(Cache, Size);
return Cache;
}
uint64_t CGDebugInfo::collectDefaultElementTypesForBlockPointer(
const BlockPointerType *Ty, llvm::DIFile *Unit, llvm::DIDerivedType *DescTy,
unsigned LineNo, SmallVectorImpl<llvm::Metadata *> &EltTys) {
QualType FType;
// Advanced by calls to CreateMemberType in increments of FType, then
// returned as the overall size of the default elements.
uint64_t FieldOffset = 0;
// Blocks in OpenCL have unique constraints which make the standard fields
// redundant while requiring size and align fields for enqueue_kernel. See
// initializeForBlockHeader in CGBlocks.cpp
if (CGM.getLangOpts().OpenCL) {
FType = CGM.getContext().IntTy;
EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset));
EltTys.push_back(CreateMemberType(Unit, FType, "__align", &FieldOffset));
} else {
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset));
FType = CGM.getContext().IntTy;
EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset));
FType = CGM.getContext().getPointerType(Ty->getPointeeType());
EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset));
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
uint64_t FieldSize = CGM.getContext().getTypeSize(Ty);
uint32_t FieldAlign = CGM.getContext().getTypeAlign(Ty);
EltTys.push_back(DBuilder.createMemberType(
Unit, "__descriptor", nullptr, LineNo, FieldSize, FieldAlign,
FieldOffset, llvm::DINode::FlagZero, DescTy));
FieldOffset += FieldSize;
}
return FieldOffset;
}
llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty,
llvm::DIFile *Unit) {
SmallVector<llvm::Metadata *, 8> EltTys;
QualType FType;
uint64_t FieldOffset;
llvm::DINodeArray Elements;
FieldOffset = 0;
FType = CGM.getContext().UnsignedLongTy;
EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset));
EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset));
Elements = DBuilder.getOrCreateArray(EltTys);
EltTys.clear();
llvm::DINode::DIFlags Flags = llvm::DINode::FlagAppleBlock;
auto *EltTy =
DBuilder.createStructType(Unit, "__block_descriptor", nullptr, 0,
FieldOffset, 0, Flags, nullptr, Elements);
// Bit size, align and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(Ty);
auto *DescTy = DBuilder.createPointerType(EltTy, Size);
FieldOffset = collectDefaultElementTypesForBlockPointer(Ty, Unit, DescTy,
0, EltTys);
Elements = DBuilder.getOrCreateArray(EltTys);
// The __block_literal_generic structs are marked with a special
// DW_AT_APPLE_BLOCK attribute and are an implementation detail only
// the debugger needs to know about. To allow type uniquing, emit
// them without a name or a location.
EltTy = DBuilder.createStructType(Unit, "", nullptr, 0, FieldOffset, 0,
Flags, nullptr, Elements);
return DBuilder.createPointerType(EltTy, Size);
}
llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
llvm::DIFile *Unit) {
assert(Ty->isTypeAlias());
llvm::DIType *Src = getOrCreateType(Ty->getAliasedType(), Unit);
SmallString<128> NS;
llvm::raw_svector_ostream OS(NS);
Ty->getTemplateName().print(OS, getPrintingPolicy(), /*qualified*/ false);
printTemplateArgumentList(OS, Ty->template_arguments(), getPrintingPolicy());
auto *AliasDecl =
cast<TypeAliasTemplateDecl>(Ty->getTemplateName().getAsTemplateDecl())
->getTemplatedDecl();
SourceLocation Loc = AliasDecl->getLocation();
return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc),
getLineNumber(Loc),
getDeclContextDescriptor(AliasDecl));
}
llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty,
llvm::DIFile *Unit) {
// We don't set size information, but do specify where the typedef was
// declared.
SourceLocation Loc = Ty->getDecl()->getLocation();
// Typedefs are derived from some other type.
return DBuilder.createTypedef(
getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit),
Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc),
getDeclContextDescriptor(Ty->getDecl()));
}
static unsigned getDwarfCC(CallingConv CC) {
switch (CC) {
case CC_C:
// Avoid emitting DW_AT_calling_convention if the C convention was used.
return 0;
case CC_X86StdCall:
return llvm::dwarf::DW_CC_BORLAND_stdcall;
case CC_X86FastCall:
return llvm::dwarf::DW_CC_BORLAND_msfastcall;
case CC_X86ThisCall:
return llvm::dwarf::DW_CC_BORLAND_thiscall;
case CC_X86VectorCall:
return llvm::dwarf::DW_CC_LLVM_vectorcall;
case CC_X86Pascal:
return llvm::dwarf::DW_CC_BORLAND_pascal;
case CC_Win64:
return llvm::dwarf::DW_CC_LLVM_Win64;
case CC_X86_64SysV:
return llvm::dwarf::DW_CC_LLVM_X86_64SysV;
case CC_AAPCS:
case CC_AArch64VectorCall:
return llvm::dwarf::DW_CC_LLVM_AAPCS;
case CC_AAPCS_VFP:
return llvm::dwarf::DW_CC_LLVM_AAPCS_VFP;
case CC_IntelOclBicc:
return llvm::dwarf::DW_CC_LLVM_IntelOclBicc;
case CC_SpirFunction:
return llvm::dwarf::DW_CC_LLVM_SpirFunction;
case CC_OpenCLKernel:
return llvm::dwarf::DW_CC_LLVM_OpenCLKernel;
case CC_Swift:
return llvm::dwarf::DW_CC_LLVM_Swift;
case CC_PreserveMost:
return llvm::dwarf::DW_CC_LLVM_PreserveMost;
case CC_PreserveAll:
return llvm::dwarf::DW_CC_LLVM_PreserveAll;
case CC_X86RegCall:
return llvm::dwarf::DW_CC_LLVM_X86RegCall;
}
return 0;
}
llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty,
llvm::DIFile *Unit) {
SmallVector<llvm::Metadata *, 16> EltTys;
// Add the result type at least.
EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit));
// Set up remainder of arguments if there is a prototype.
// otherwise emit it as a variadic function.
if (isa<FunctionNoProtoType>(Ty))
EltTys.push_back(DBuilder.createUnspecifiedParameter());
else if (const auto *FPT = dyn_cast<FunctionProtoType>(Ty)) {
for (const QualType &ParamType : FPT->param_types())
EltTys.push_back(getOrCreateType(ParamType, Unit));
if (FPT->isVariadic())
EltTys.push_back(DBuilder.createUnspecifiedParameter());
}
llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys);
return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero,
getDwarfCC(Ty->getCallConv()));
}
/// Convert an AccessSpecifier into the corresponding DINode flag.
/// As an optimization, return 0 if the access specifier equals the
/// default for the containing type.
static llvm::DINode::DIFlags getAccessFlag(AccessSpecifier Access,
const RecordDecl *RD) {
AccessSpecifier Default = clang::AS_none;
if (RD && RD->isClass())
Default = clang::AS_private;
else if (RD && (RD->isStruct() || RD->isUnion()))
Default = clang::AS_public;
if (Access == Default)
return llvm::DINode::FlagZero;
switch (Access) {
case clang::AS_private:
return llvm::DINode::FlagPrivate;
case clang::AS_protected:
return llvm::DINode::FlagProtected;
case clang::AS_public:
return llvm::DINode::FlagPublic;
case clang::AS_none:
return llvm::DINode::FlagZero;
}
llvm_unreachable("unexpected access enumerator");
}
llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl,
llvm::DIScope *RecordTy,
const RecordDecl *RD) {
StringRef Name = BitFieldDecl->getName();
QualType Ty = BitFieldDecl->getType();
SourceLocation Loc = BitFieldDecl->getLocation();
llvm::DIFile *VUnit = getOrCreateFile(Loc);
llvm::DIType *DebugType = getOrCreateType(Ty, VUnit);
// Get the location for the field.
llvm::DIFile *File = getOrCreateFile(Loc);
unsigned Line = getLineNumber(Loc);
const CGBitFieldInfo &BitFieldInfo =
CGM.getTypes().getCGRecordLayout(RD).getBitFieldInfo(BitFieldDecl);
uint64_t SizeInBits = BitFieldInfo.Size;
assert(SizeInBits > 0 && "found named 0-width bitfield");
uint64_t StorageOffsetInBits =
CGM.getContext().toBits(BitFieldInfo.StorageOffset);
uint64_t Offset = BitFieldInfo.Offset;
// The bit offsets for big endian machines are reversed for big
// endian target, compensate for that as the DIDerivedType requires
// un-reversed offsets.
if (CGM.getDataLayout().isBigEndian())
Offset = BitFieldInfo.StorageSize - BitFieldInfo.Size - Offset;
uint64_t OffsetInBits = StorageOffsetInBits + Offset;
llvm::DINode::DIFlags Flags = getAccessFlag(BitFieldDecl->getAccess(), RD);
return DBuilder.createBitFieldMemberType(
RecordTy, Name, File, Line, SizeInBits, OffsetInBits, StorageOffsetInBits,
Flags, DebugType);
}
llvm::DIType *
CGDebugInfo::createFieldType(StringRef name, QualType type, SourceLocation loc,
AccessSpecifier AS, uint64_t offsetInBits,
uint32_t AlignInBits, llvm::DIFile *tunit,
llvm::DIScope *scope, const RecordDecl *RD) {
llvm::DIType *debugType = getOrCreateType(type, tunit);
// Get the location for the field.
llvm::DIFile *file = getOrCreateFile(loc);
unsigned line = getLineNumber(loc);
uint64_t SizeInBits = 0;
auto Align = AlignInBits;
if (!type->isIncompleteArrayType()) {
TypeInfo TI = CGM.getContext().getTypeInfo(type);
SizeInBits = TI.Width;
if (!Align)
Align = getTypeAlignIfRequired(type, CGM.getContext());
}
llvm::DINode::DIFlags flags = getAccessFlag(AS, RD);
return DBuilder.createMemberType(scope, name, file, line, SizeInBits, Align,
offsetInBits, flags, debugType);
}
void CGDebugInfo::CollectRecordLambdaFields(
const CXXRecordDecl *CXXDecl, SmallVectorImpl<llvm::Metadata *> &elements,
llvm::DIType *RecordTy) {
// For C++11 Lambdas a Field will be the same as a Capture, but the Capture
// has the name and the location of the variable so we should iterate over
// both concurrently.
const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(CXXDecl);
RecordDecl::field_iterator Field = CXXDecl->field_begin();
unsigned fieldno = 0;
for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
E = CXXDecl->captures_end();
I != E; ++I, ++Field, ++fieldno) {
const LambdaCapture &C = *I;
if (C.capturesVariable()) {
SourceLocation Loc = C.getLocation();
assert(!Field->isBitField() && "lambdas don't have bitfield members!");
VarDecl *V = C.getCapturedVar();
StringRef VName = V->getName();
llvm::DIFile *VUnit = getOrCreateFile(Loc);
auto Align = getDeclAlignIfRequired(V, CGM.getContext());
llvm::DIType *FieldType = createFieldType(
VName, Field->getType(), Loc, Field->getAccess(),
layout.getFieldOffset(fieldno), Align, VUnit, RecordTy, CXXDecl);
elements.push_back(FieldType);
} else if (C.capturesThis()) {
// TODO: Need to handle 'this' in some way by probably renaming the
// this of the lambda class and having a field member of 'this' or
// by using AT_object_pointer for the function and having that be
// used as 'this' for semantic references.
FieldDecl *f = *Field;
llvm::DIFile *VUnit = getOrCreateFile(f->getLocation());
QualType type = f->getType();
llvm::DIType *fieldType = createFieldType(
"this", type, f->getLocation(), f->getAccess(),
layout.getFieldOffset(fieldno), VUnit, RecordTy, CXXDecl);
elements.push_back(fieldType);
}
}
}
llvm::DIDerivedType *
CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy,
const RecordDecl *RD) {
// Create the descriptor for the static variable, with or without
// constant initializers.
Var = Var->getCanonicalDecl();
llvm::DIFile *VUnit = getOrCreateFile(Var->getLocation());
llvm::DIType *VTy = getOrCreateType(Var->getType(), VUnit);
unsigned LineNumber = getLineNumber(Var->getLocation());
StringRef VName = Var->getName();
llvm::Constant *C = nullptr;
if (Var->getInit()) {
const APValue *Value = Var->evaluateValue();
if (Value) {
if (Value->isInt())
C = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt());
if (Value->isFloat())
C = llvm::ConstantFP::get(CGM.getLLVMContext(), Value->getFloat());
}
}
llvm::DINode::DIFlags Flags = getAccessFlag(Var->getAccess(), RD);
auto Align = getDeclAlignIfRequired(Var, CGM.getContext());
llvm::DIDerivedType *GV = DBuilder.createStaticMemberType(
RecordTy, VName, VUnit, LineNumber, VTy, Flags, C, Align);
StaticDataMemberCache[Var->getCanonicalDecl()].reset(GV);
return GV;
}
void CGDebugInfo::CollectRecordNormalField(
const FieldDecl *field, uint64_t OffsetInBits, llvm::DIFile *tunit,
SmallVectorImpl<llvm::Metadata *> &elements, llvm::DIType *RecordTy,
const RecordDecl *RD) {
StringRef name = field->getName();
QualType type = field->getType();
// Ignore unnamed fields unless they're anonymous structs/unions.
if (name.empty() && !type->isRecordType())
return;
llvm::DIType *FieldType;
if (field->isBitField()) {
FieldType = createBitFieldType(field, RecordTy, RD);
} else {
auto Align = getDeclAlignIfRequired(field, CGM.getContext());
FieldType =
createFieldType(name, type, field->getLocation(), field->getAccess(),
OffsetInBits, Align, tunit, RecordTy, RD);
}
elements.push_back(FieldType);
}
void CGDebugInfo::CollectRecordNestedType(
const TypeDecl *TD, SmallVectorImpl<llvm::Metadata *> &elements) {
QualType Ty = CGM.getContext().getTypeDeclType(TD);
// Injected class names are not considered nested records.
if (isa<InjectedClassNameType>(Ty))
return;
SourceLocation Loc = TD->getLocation();
llvm::DIType *nestedType = getOrCreateType(Ty, getOrCreateFile(Loc));
elements.push_back(nestedType);
}
void CGDebugInfo::CollectRecordFields(
const RecordDecl *record, llvm::DIFile *tunit,
SmallVectorImpl<llvm::Metadata *> &elements,
llvm::DICompositeType *RecordTy) {
const auto *CXXDecl = dyn_cast<CXXRecordDecl>(record);
if (CXXDecl && CXXDecl->isLambda())
CollectRecordLambdaFields(CXXDecl, elements, RecordTy);
else {
const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
// Field number for non-static fields.
unsigned fieldNo = 0;
// Static and non-static members should appear in the same order as
// the corresponding declarations in the source program.
for (const auto *I : record->decls())
if (const auto *V = dyn_cast<VarDecl>(I)) {
if (V->hasAttr<NoDebugAttr>())
continue;
// Skip variable template specializations when emitting CodeView. MSVC
// doesn't emit them.
if (CGM.getCodeGenOpts().EmitCodeView &&
isa<VarTemplateSpecializationDecl>(V))
continue;
// Reuse the existing static member declaration if one exists
auto MI = StaticDataMemberCache.find(V->getCanonicalDecl());
if (MI != StaticDataMemberCache.end()) {
assert(MI->second &&
"Static data member declaration should still exist");
elements.push_back(MI->second);
} else {
auto Field = CreateRecordStaticField(V, RecordTy, record);
elements.push_back(Field);
}
} else if (const auto *field = dyn_cast<FieldDecl>(I)) {
CollectRecordNormalField(field, layout.getFieldOffset(fieldNo), tunit,
elements, RecordTy, record);
// Bump field number for next field.
++fieldNo;
} else if (CGM.getCodeGenOpts().EmitCodeView) {
// Debug info for nested types is included in the member list only for
// CodeView.
if (const auto *nestedType = dyn_cast<TypeDecl>(I))
if (!nestedType->isImplicit() &&
nestedType->getDeclContext() == record)
CollectRecordNestedType(nestedType, elements);
}
}
}
llvm::DISubroutineType *
CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile *Unit) {
const FunctionProtoType *Func = Method->getType()->getAs<FunctionProtoType>();
if (Method->isStatic())
return cast_or_null<llvm::DISubroutineType>(
getOrCreateType(QualType(Func, 0), Unit));
return getOrCreateInstanceMethodType(Method->getThisType(), Func, Unit);
}
llvm::DISubroutineType *CGDebugInfo::getOrCreateInstanceMethodType(
QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile *Unit) {
// Add "this" pointer.
llvm::DITypeRefArray Args(
cast<llvm::DISubroutineType>(getOrCreateType(QualType(Func, 0), Unit))
->getTypeArray());
assert(Args.size() && "Invalid number of arguments!");
SmallVector<llvm::Metadata *, 16> Elts;
// First element is always return type. For 'void' functions it is NULL.
Elts.push_back(Args[0]);
// "this" pointer is always first argument.
const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl();
if (isa<ClassTemplateSpecializationDecl>(RD)) {
// Create pointer type directly in this case.
const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr);
QualType PointeeTy = ThisPtrTy->getPointeeType();
unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
uint64_t Size = CGM.getTarget().getPointerWidth(AS);
auto Align = getTypeAlignIfRequired(ThisPtrTy, CGM.getContext());
llvm::DIType *PointeeType = getOrCreateType(PointeeTy, Unit);
llvm::DIType *ThisPtrType =
DBuilder.createPointerType(PointeeType, Size, Align);
TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType);
// TODO: This and the artificial type below are misleading, the
// types aren't artificial the argument is, but the current
// metadata doesn't represent that.
ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
Elts.push_back(ThisPtrType);
} else {
llvm::DIType *ThisPtrType = getOrCreateType(ThisPtr, Unit);
TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType);
ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
Elts.push_back(ThisPtrType);
}
// Copy rest of the arguments.
for (unsigned i = 1, e = Args.size(); i != e; ++i)
Elts.push_back(Args[i]);
llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts);
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
if (Func->getExtProtoInfo().RefQualifier == RQ_LValue)
Flags |= llvm::DINode::FlagLValueReference;
if (Func->getExtProtoInfo().RefQualifier == RQ_RValue)
Flags |= llvm::DINode::FlagRValueReference;
return DBuilder.createSubroutineType(EltTypeArray, Flags,
getDwarfCC(Func->getCallConv()));
}
/// isFunctionLocalClass - Return true if CXXRecordDecl is defined
/// inside a function.
static bool isFunctionLocalClass(const CXXRecordDecl *RD) {
if (const auto *NRD = dyn_cast<CXXRecordDecl>(RD->getDeclContext()))
return isFunctionLocalClass(NRD);
if (isa<FunctionDecl>(RD->getDeclContext()))
return true;
return false;
}
llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) {
bool IsCtorOrDtor =
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
StringRef MethodName = getFunctionName(Method);
llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit);
// Since a single ctor/dtor corresponds to multiple functions, it doesn't
// make sense to give a single ctor/dtor a linkage name.
StringRef MethodLinkageName;
// FIXME: 'isFunctionLocalClass' seems like an arbitrary/unintentional
// property to use here. It may've been intended to model "is non-external
// type" but misses cases of non-function-local but non-external classes such
// as those in anonymous namespaces as well as the reverse - external types
// that are function local, such as those in (non-local) inline functions.
if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent()))
MethodLinkageName = CGM.getMangledName(Method);
// Get the location for the method.
llvm::DIFile *MethodDefUnit = nullptr;
unsigned MethodLine = 0;
if (!Method->isImplicit()) {
MethodDefUnit = getOrCreateFile(Method->getLocation());
MethodLine = getLineNumber(Method->getLocation());
}
// Collect virtual method info.
llvm::DIType *ContainingType = nullptr;
unsigned VIndex = 0;
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero;
int ThisAdjustment = 0;
if (Method->isVirtual()) {
if (Method->isPure())
SPFlags |= llvm::DISubprogram::SPFlagPureVirtual;
else
SPFlags |= llvm::DISubprogram::SPFlagVirtual;
if (CGM.getTarget().getCXXABI().isItaniumFamily()) {
// It doesn't make sense to give a virtual destructor a vtable index,
// since a single destructor has two entries in the vtable.
if (!isa<CXXDestructorDecl>(Method))
VIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(Method);
} else {
// Emit MS ABI vftable information. There is only one entry for the
// deleting dtor.
const auto *DD = dyn_cast<CXXDestructorDecl>(Method);
GlobalDecl GD = DD ? GlobalDecl(DD, Dtor_Deleting) : GlobalDecl(Method);
MethodVFTableLocation ML =
CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD);
VIndex = ML.Index;
// CodeView only records the vftable offset in the class that introduces
// the virtual method. This is possible because, unlike Itanium, the MS
// C++ ABI does not include all virtual methods from non-primary bases in
// the vtable for the most derived class. For example, if C inherits from
// A and B, C's primary vftable will not include B's virtual methods.
if (Method->size_overridden_methods() == 0)
Flags |= llvm::DINode::FlagIntroducedVirtual;
// The 'this' adjustment accounts for both the virtual and non-virtual
// portions of the adjustment. Presumably the debugger only uses it when
// it knows the dynamic type of an object.
ThisAdjustment = CGM.getCXXABI()
.getVirtualFunctionPrologueThisAdjustment(GD)
.getQuantity();
}
ContainingType = RecordTy;
}
if (Method->isStatic())
Flags |= llvm::DINode::FlagStaticMember;
if (Method->isImplicit())
Flags |= llvm::DINode::FlagArtificial;
Flags |= getAccessFlag(Method->getAccess(), Method->getParent());
if (const auto *CXXC = dyn_cast<CXXConstructorDecl>(Method)) {
if (CXXC->isExplicit())
Flags |= llvm::DINode::FlagExplicit;
} else if (const auto *CXXC = dyn_cast<CXXConversionDecl>(Method)) {
if (CXXC->isExplicit())
Flags |= llvm::DINode::FlagExplicit;
}
if (Method->hasPrototype())
Flags |= llvm::DINode::FlagPrototyped;
if (Method->getRefQualifier() == RQ_LValue)
Flags |= llvm::DINode::FlagLValueReference;
if (Method->getRefQualifier() == RQ_RValue)
Flags |= llvm::DINode::FlagRValueReference;
if (CGM.getLangOpts().Optimize)
SPFlags |= llvm::DISubprogram::SPFlagOptimized;
llvm::DINodeArray TParamsArray = CollectFunctionTemplateParams(Method, Unit);
llvm::DISubprogram *SP = DBuilder.createMethod(
RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine,
MethodTy, VIndex, ThisAdjustment, ContainingType, Flags, SPFlags,
TParamsArray.get());
SPCache[Method->getCanonicalDecl()].reset(SP);
return SP;
}
void CGDebugInfo::CollectCXXMemberFunctions(
const CXXRecordDecl *RD, llvm::DIFile *Unit,
SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy) {
// Since we want more than just the individual member decls if we
// have templated functions iterate over every declaration to gather
// the functions.
for (const auto *I : RD->decls()) {
const auto *Method = dyn_cast<CXXMethodDecl>(I);
// If the member is implicit, don't add it to the member list. This avoids
// the member being added to type units by LLVM, while still allowing it
// to be emitted into the type declaration/reference inside the compile
// unit.
// Ditto 'nodebug' methods, for consistency with CodeGenFunction.cpp.
// FIXME: Handle Using(Shadow?)Decls here to create
// DW_TAG_imported_declarations inside the class for base decls brought into
// derived classes. GDB doesn't seem to notice/leverage these when I tried
// it, so I'm not rushing to fix this. (GCC seems to produce them, if
// referenced)
if (!Method || Method->isImplicit() || Method->hasAttr<NoDebugAttr>())
continue;
if (Method->getType()->getAs<FunctionProtoType>()->getContainedAutoType())
continue;
// Reuse the existing member function declaration if it exists.
// It may be associated with the declaration of the type & should be
// reused as we're building the definition.
//
// This situation can arise in the vtable-based debug info reduction where
// implicit members are emitted in a non-vtable TU.
auto MI = SPCache.find(Method->getCanonicalDecl());
EltTys.push_back(MI == SPCache.end()
? CreateCXXMemberFunction(Method, Unit, RecordTy)
: static_cast<llvm::Metadata *>(MI->second));
}
}
void CGDebugInfo::CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile *Unit,
SmallVectorImpl<llvm::Metadata *> &EltTys,
llvm::DIType *RecordTy) {
llvm::DenseSet<CanonicalDeclPtr<const CXXRecordDecl>> SeenTypes;
CollectCXXBasesAux(RD, Unit, EltTys, RecordTy, RD->bases(), SeenTypes,
llvm::DINode::FlagZero);
// If we are generating CodeView debug info, we also need to emit records for
// indirect virtual base classes.
if (CGM.getCodeGenOpts().EmitCodeView) {
CollectCXXBasesAux(RD, Unit, EltTys, RecordTy, RD->vbases(), SeenTypes,
llvm::DINode::FlagIndirectVirtualBase);
}
}
void CGDebugInfo::CollectCXXBasesAux(
const CXXRecordDecl *RD, llvm::DIFile *Unit,
SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy,
const CXXRecordDecl::base_class_const_range &Bases,
llvm::DenseSet<CanonicalDeclPtr<const CXXRecordDecl>> &SeenTypes,
llvm::DINode::DIFlags StartingFlags) {
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
for (const auto &BI : Bases) {
const auto *Base =
cast<CXXRecordDecl>(BI.getType()->getAs<RecordType>()->getDecl());
if (!SeenTypes.insert(Base).second)
continue;
auto *BaseTy = getOrCreateType(BI.getType(), Unit);
llvm::DINode::DIFlags BFlags = StartingFlags;
uint64_t BaseOffset;
uint32_t VBPtrOffset = 0;
if (BI.isVirtual()) {
if (CGM.getTarget().getCXXABI().isItaniumFamily()) {
// virtual base offset offset is -ve. The code generator emits dwarf
// expression where it expects +ve number.
BaseOffset = 0 - CGM.getItaniumVTableContext()
.getVirtualBaseOffsetOffset(RD, Base)
.getQuantity();
} else {
// In the MS ABI, store the vbtable offset, which is analogous to the
// vbase offset offset in Itanium.
BaseOffset =
4 * CGM.getMicrosoftVTableContext().getVBTableIndex(RD, Base);
VBPtrOffset = CGM.getContext()
.getASTRecordLayout(RD)
.getVBPtrOffset()
.getQuantity();
}
BFlags |= llvm::DINode::FlagVirtual;
} else
BaseOffset = CGM.getContext().toBits(RL.getBaseClassOffset(Base));
// FIXME: Inconsistent units for BaseOffset. It is in bytes when
// BI->isVirtual() and bits when not.
BFlags |= getAccessFlag(BI.getAccessSpecifier(), RD);
llvm::DIType *DTy = DBuilder.createInheritance(RecordTy, BaseTy, BaseOffset,
VBPtrOffset, BFlags);
EltTys.push_back(DTy);
}
}
llvm::DINodeArray
CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList,
ArrayRef<TemplateArgument> TAList,
llvm::DIFile *Unit) {
SmallVector<llvm::Metadata *, 16> TemplateParams;
for (unsigned i = 0, e = TAList.size(); i != e; ++i) {
const TemplateArgument &TA = TAList[i];
StringRef Name;
if (TPList)
Name = TPList->getParam(i)->getName();
switch (TA.getKind()) {
case TemplateArgument::Type: {
llvm::DIType *TTy = getOrCreateType(TA.getAsType(), Unit);
TemplateParams.push_back(
DBuilder.createTemplateTypeParameter(TheCU, Name, TTy));
} break;
case TemplateArgument::Integral: {
llvm::DIType *TTy = getOrCreateType(TA.getIntegralType(), Unit);
TemplateParams.push_back(DBuilder.createTemplateValueParameter(
TheCU, Name, TTy,
llvm::ConstantInt::get(CGM.getLLVMContext(), TA.getAsIntegral())));
} break;
case TemplateArgument::Declaration: {
const ValueDecl *D = TA.getAsDecl();
QualType T = TA.getParamTypeForDecl().getDesugaredType(CGM.getContext());
llvm::DIType *TTy = getOrCreateType(T, Unit);
llvm::Constant *V = nullptr;
const CXXMethodDecl *MD;
// Variable pointer template parameters have a value that is the address
// of the variable.
if (const auto *VD = dyn_cast<VarDecl>(D))
V = CGM.GetAddrOfGlobalVar(VD);
// Member function pointers have special support for building them, though
// this is currently unsupported in LLVM CodeGen.
else if ((MD = dyn_cast<CXXMethodDecl>(D)) && MD->isInstance())
V = CGM.getCXXABI().EmitMemberFunctionPointer(MD);
else if (const auto *FD = dyn_cast<FunctionDecl>(D))
V = CGM.GetAddrOfFunction(FD);
// Member data pointers have special handling too to compute the fixed
// offset within the object.
else if (const auto *MPT = dyn_cast<MemberPointerType>(T.getTypePtr())) {
// These five lines (& possibly the above member function pointer
// handling) might be able to be refactored to use similar code in
// CodeGenModule::getMemberPointerConstant
uint64_t fieldOffset = CGM.getContext().getFieldOffset(D);
CharUnits chars =
CGM.getContext().toCharUnitsFromBits((int64_t)fieldOffset);
V = CGM.getCXXABI().EmitMemberDataPointer(MPT, chars);
}
TemplateParams.push_back(DBuilder.createTemplateValueParameter(
TheCU, Name, TTy,
cast_or_null<llvm::Constant>(V->stripPointerCasts())));
} break;
case TemplateArgument::NullPtr: {
QualType T = TA.getNullPtrType();
llvm::DIType *TTy = getOrCreateType(T, Unit);
llvm::Constant *V = nullptr;
// Special case member data pointer null values since they're actually -1
// instead of zero.
if (const auto *MPT = dyn_cast<MemberPointerType>(T.getTypePtr()))
// But treat member function pointers as simple zero integers because
// it's easier than having a special case in LLVM's CodeGen. If LLVM
// CodeGen grows handling for values of non-null member function
// pointers then perhaps we could remove this special case and rely on
// EmitNullMemberPointer for member function pointers.
if (MPT->isMemberDataPointer())
V = CGM.getCXXABI().EmitNullMemberPointer(MPT);
if (!V)
V = llvm::ConstantInt::get(CGM.Int8Ty, 0);
TemplateParams.push_back(
DBuilder.createTemplateValueParameter(TheCU, Name, TTy, V));
} break;
case TemplateArgument::Template:
TemplateParams.push_back(DBuilder.createTemplateTemplateParameter(
TheCU, Name, nullptr,
TA.getAsTemplate().getAsTemplateDecl()->getQualifiedNameAsString()));
break;
case TemplateArgument::Pack:
TemplateParams.push_back(DBuilder.createTemplateParameterPack(
TheCU, Name, nullptr,
CollectTemplateParams(nullptr, TA.getPackAsArray(), Unit)));
break;
case TemplateArgument::Expression: {
const Expr *E = TA.getAsExpr();
QualType T = E->getType();
if (E->isGLValue())
T = CGM.getContext().getLValueReferenceType(T);
llvm::Constant *V = ConstantEmitter(CGM).emitAbstract(E, T);
assert(V && "Expression in template argument isn't constant");
llvm::DIType *TTy = getOrCreateType(T, Unit);
TemplateParams.push_back(DBuilder.createTemplateValueParameter(
TheCU, Name, TTy, V->stripPointerCasts()));
} break;
// And the following should never occur:
case TemplateArgument::TemplateExpansion:
case TemplateArgument::Null:
llvm_unreachable(
"These argument types shouldn't exist in concrete types");
}
}
return DBuilder.getOrCreateArray(TemplateParams);
}
llvm::DINodeArray
CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD,
llvm::DIFile *Unit) {
if (FD->getTemplatedKind() ==
FunctionDecl::TK_FunctionTemplateSpecialization) {
const TemplateParameterList *TList = FD->getTemplateSpecializationInfo()
->getTemplate()
->getTemplateParameters();
return CollectTemplateParams(
TList, FD->getTemplateSpecializationArgs()->asArray(), Unit);
}
return llvm::DINodeArray();
}
llvm::DINodeArray CGDebugInfo::CollectVarTemplateParams(const VarDecl *VL,
- llvm::DIFile *Unit) {
- if (auto *TS = dyn_cast<VarTemplateSpecializationDecl>(VL)) {
- auto T = TS->getSpecializedTemplateOrPartial();
- auto TA = TS->getTemplateArgs().asArray();
- // Collect parameters for a partial specialization
- if (T.is<VarTemplatePartialSpecializationDecl *>()) {
- const TemplateParameterList *TList =
- T.get<VarTemplatePartialSpecializationDecl *>()
- ->getTemplateParameters();
- return CollectTemplateParams(TList, TA, Unit);
- }
-
- // Collect parameters for an explicit specialization
- if (T.is<VarTemplateDecl *>()) {
- const TemplateParameterList *TList = T.get<VarTemplateDecl *>()
- ->getTemplateParameters();
- return CollectTemplateParams(TList, TA, Unit);
- }
- }
- return llvm::DINodeArray();
+ llvm::DIFile *Unit) {
+ // Always get the full list of parameters, not just the ones from the
+ // specialization. A partial specialization may have fewer parameters than
+ // there are arguments.
+ auto *TS = dyn_cast<VarTemplateSpecializationDecl>(VL);
+ if (!TS)
+ return llvm::DINodeArray();
+ VarTemplateDecl *T = TS->getSpecializedTemplate();
+ const TemplateParameterList *TList = T->getTemplateParameters();
+ auto TA = TS->getTemplateArgs().asArray();
+ return CollectTemplateParams(TList, TA, Unit);
}
llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams(
const ClassTemplateSpecializationDecl *TSpecial, llvm::DIFile *Unit) {
- // Always get the full list of parameters, not just the ones from
- // the specialization.
+ // Always get the full list of parameters, not just the ones from the
+ // specialization. A partial specialization may have fewer parameters than
+ // there are arguments.
TemplateParameterList *TPList =
TSpecial->getSpecializedTemplate()->getTemplateParameters();
const TemplateArgumentList &TAList = TSpecial->getTemplateArgs();
return CollectTemplateParams(TPList, TAList.asArray(), Unit);
}
llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) {
if (VTablePtrType)
return VTablePtrType;
ASTContext &Context = CGM.getContext();
/* Function type */
llvm::Metadata *STy = getOrCreateType(Context.IntTy, Unit);
llvm::DITypeRefArray SElements = DBuilder.getOrCreateTypeArray(STy);
llvm::DIType *SubTy = DBuilder.createSubroutineType(SElements);
unsigned Size = Context.getTypeSize(Context.VoidPtrTy);
unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace();
Optional<unsigned> DWARFAddressSpace =
CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace);
llvm::DIType *vtbl_ptr_type = DBuilder.createPointerType(
SubTy, Size, 0, DWARFAddressSpace, "__vtbl_ptr_type");
VTablePtrType = DBuilder.createPointerType(vtbl_ptr_type, Size);
return VTablePtrType;
}
StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
// Copy the gdb compatible name on the side and use its reference.
return internString("_vptr$", RD->getNameAsString());
}
void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit,
SmallVectorImpl<llvm::Metadata *> &EltTys,
llvm::DICompositeType *RecordTy) {
// If this class is not dynamic then there is not any vtable info to collect.
if (!RD->isDynamicClass())
return;
// Don't emit any vtable shape or vptr info if this class doesn't have an
// extendable vfptr. This can happen if the class doesn't have virtual
// methods, or in the MS ABI if those virtual methods only come from virtually
// inherited bases.
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
if (!RL.hasExtendableVFPtr())
return;
// CodeView needs to know how large the vtable of every dynamic class is, so
// emit a special named pointer type into the element list. The vptr type
// points to this type as well.
llvm::DIType *VPtrTy = nullptr;
bool NeedVTableShape = CGM.getCodeGenOpts().EmitCodeView &&
CGM.getTarget().getCXXABI().isMicrosoft();
if (NeedVTableShape) {
uint64_t PtrWidth =
CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
const VTableLayout &VFTLayout =
CGM.getMicrosoftVTableContext().getVFTableLayout(RD, CharUnits::Zero());
unsigned VSlotCount =
VFTLayout.vtable_components().size() - CGM.getLangOpts().RTTIData;
unsigned VTableWidth = PtrWidth * VSlotCount;
unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace();
Optional<unsigned> DWARFAddressSpace =
CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace);
// Create a very wide void* type and insert it directly in the element list.
llvm::DIType *VTableType = DBuilder.createPointerType(
nullptr, VTableWidth, 0, DWARFAddressSpace, "__vtbl_ptr_type");
EltTys.push_back(VTableType);
// The vptr is a pointer to this special vtable type.
VPtrTy = DBuilder.createPointerType(VTableType, PtrWidth);
}
// If there is a primary base then the artificial vptr member lives there.
if (RL.getPrimaryBase())
return;
if (!VPtrTy)
VPtrTy = getOrCreateVTablePtrType(Unit);
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
llvm::DIType *VPtrMember =
DBuilder.createMemberType(Unit, getVTableName(RD), Unit, 0, Size, 0, 0,
llvm::DINode::FlagArtificial, VPtrTy);
EltTys.push_back(VPtrMember);
}
llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy,
SourceLocation Loc) {
assert(DebugKind >= codegenoptions::LimitedDebugInfo);
llvm::DIType *T = getOrCreateType(RTy, getOrCreateFile(Loc));
return T;
}
llvm::DIType *CGDebugInfo::getOrCreateInterfaceType(QualType D,
SourceLocation Loc) {
return getOrCreateStandaloneType(D, Loc);
}
llvm::DIType *CGDebugInfo::getOrCreateStandaloneType(QualType D,
SourceLocation Loc) {
assert(DebugKind >= codegenoptions::LimitedDebugInfo);
assert(!D.isNull() && "null type");
llvm::DIType *T = getOrCreateType(D, getOrCreateFile(Loc));
assert(T && "could not create debug info for type");
RetainedTypes.push_back(D.getAsOpaquePtr());
return T;
}
void CGDebugInfo::completeType(const EnumDecl *ED) {
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
return;
QualType Ty = CGM.getContext().getEnumType(ED);
void *TyPtr = Ty.getAsOpaquePtr();
auto I = TypeCache.find(TyPtr);
if (I == TypeCache.end() || !cast<llvm::DIType>(I->second)->isForwardDecl())
return;
llvm::DIType *Res = CreateTypeDefinition(Ty->castAs<EnumType>());
assert(!Res->isForwardDecl());
TypeCache[TyPtr].reset(Res);
}
void CGDebugInfo::completeType(const RecordDecl *RD) {
if (DebugKind > codegenoptions::LimitedDebugInfo ||
!CGM.getLangOpts().CPlusPlus)
completeRequiredType(RD);
}
/// Return true if the class or any of its methods are marked dllimport.
static bool isClassOrMethodDLLImport(const CXXRecordDecl *RD) {
if (RD->hasAttr<DLLImportAttr>())
return true;
for (const CXXMethodDecl *MD : RD->methods())
if (MD->hasAttr<DLLImportAttr>())
return true;
return false;
}
/// Does a type definition exist in an imported clang module?
static bool isDefinedInClangModule(const RecordDecl *RD) {
// Only definitions that where imported from an AST file come from a module.
if (!RD || !RD->isFromASTFile())
return false;
// Anonymous entities cannot be addressed. Treat them as not from module.
if (!RD->isExternallyVisible() && RD->getName().empty())
return false;
if (auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD)) {
if (!CXXDecl->isCompleteDefinition())
return false;
// Check wether RD is a template.
auto TemplateKind = CXXDecl->getTemplateSpecializationKind();
if (TemplateKind != TSK_Undeclared) {
// Unfortunately getOwningModule() isn't accurate enough to find the
// owning module of a ClassTemplateSpecializationDecl that is inside a
// namespace spanning multiple modules.
bool Explicit = false;
if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(CXXDecl))
Explicit = TD->isExplicitInstantiationOrSpecialization();
if (!Explicit && CXXDecl->getEnclosingNamespaceContext())
return false;
// This is a template, check the origin of the first member.
if (CXXDecl->field_begin() == CXXDecl->field_end())
return TemplateKind == TSK_ExplicitInstantiationDeclaration;
if (!CXXDecl->field_begin()->isFromASTFile())
return false;
}
}
return true;
}
void CGDebugInfo::completeClassData(const RecordDecl *RD) {
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
if (CXXRD->isDynamicClass() &&
CGM.getVTableLinkage(CXXRD) ==
llvm::GlobalValue::AvailableExternallyLinkage &&
!isClassOrMethodDLLImport(CXXRD))
return;
if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition()))
return;
completeClass(RD);
}
void CGDebugInfo::completeClass(const RecordDecl *RD) {
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
return;
QualType Ty = CGM.getContext().getRecordType(RD);
void *TyPtr = Ty.getAsOpaquePtr();
auto I = TypeCache.find(TyPtr);
if (I != TypeCache.end() && !cast<llvm::DIType>(I->second)->isForwardDecl())
return;
llvm::DIType *Res = CreateTypeDefinition(Ty->castAs<RecordType>());
assert(!Res->isForwardDecl());
TypeCache[TyPtr].reset(Res);
}
static bool hasExplicitMemberDefinition(CXXRecordDecl::method_iterator I,
CXXRecordDecl::method_iterator End) {
for (CXXMethodDecl *MD : llvm::make_range(I, End))
if (FunctionDecl *Tmpl = MD->getInstantiatedFromMemberFunction())
if (!Tmpl->isImplicit() && Tmpl->isThisDeclarationADefinition() &&
!MD->getMemberSpecializationInfo()->isExplicitSpecialization())
return true;
return false;
}
static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind,
bool DebugTypeExtRefs, const RecordDecl *RD,
const LangOptions &LangOpts) {
if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition()))
return true;
if (auto *ES = RD->getASTContext().getExternalSource())
if (ES->hasExternalDefinitions(RD) == ExternalASTSource::EK_Always)
return true;
if (DebugKind > codegenoptions::LimitedDebugInfo)
return false;
if (!LangOpts.CPlusPlus)
return false;
if (!RD->isCompleteDefinitionRequired())
return true;
const auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
if (!CXXDecl)
return false;
// Only emit complete debug info for a dynamic class when its vtable is
// emitted. However, Microsoft debuggers don't resolve type information
// across DLL boundaries, so skip this optimization if the class or any of its
// methods are marked dllimport. This isn't a complete solution, since objects
// without any dllimport methods can be used in one DLL and constructed in
// another, but it is the current behavior of LimitedDebugInfo.
if (CXXDecl->hasDefinition() && CXXDecl->isDynamicClass() &&
!isClassOrMethodDLLImport(CXXDecl))
return true;
TemplateSpecializationKind Spec = TSK_Undeclared;
if (const auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
Spec = SD->getSpecializationKind();
if (Spec == TSK_ExplicitInstantiationDeclaration &&
hasExplicitMemberDefinition(CXXDecl->method_begin(),
CXXDecl->method_end()))
return true;
return false;
}
void CGDebugInfo::completeRequiredType(const RecordDecl *RD) {
if (shouldOmitDefinition(DebugKind, DebugTypeExtRefs, RD, CGM.getLangOpts()))
return;
QualType Ty = CGM.getContext().getRecordType(RD);
llvm::DIType *T = getTypeOrNull(Ty);
if (T && T->isForwardDecl())
completeClassData(RD);
}
llvm::DIType *CGDebugInfo::CreateType(const RecordType *Ty) {
RecordDecl *RD = Ty->getDecl();
llvm::DIType *T = cast_or_null<llvm::DIType>(getTypeOrNull(QualType(Ty, 0)));
if (T || shouldOmitDefinition(DebugKind, DebugTypeExtRefs, RD,
CGM.getLangOpts())) {
if (!T)
T = getOrCreateRecordFwdDecl(Ty, getDeclContextDescriptor(RD));
return T;
}
return CreateTypeDefinition(Ty);
}
llvm::DIType *CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) {
RecordDecl *RD = Ty->getDecl();
// Get overall information about the record type for the debug info.
llvm::DIFile *DefUnit = getOrCreateFile(RD->getLocation());
// Records and classes and unions can all be recursive. To handle them, we
// first generate a debug descriptor for the struct as a forward declaration.
// Then (if it is a definition) we go through and get debug info for all of
// its members. Finally, we create a descriptor for the complete type (which
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
llvm::DICompositeType *FwdDecl = getOrCreateLimitedType(Ty, DefUnit);
const RecordDecl *D = RD->getDefinition();
if (!D || !D->isCompleteDefinition())
return FwdDecl;
if (const auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD))
CollectContainingType(CXXDecl, FwdDecl);
// Push the struct on region stack.
LexicalBlockStack.emplace_back(&*FwdDecl);
RegionMap[Ty->getDecl()].reset(FwdDecl);
// Convert all the elements.
SmallVector<llvm::Metadata *, 16> EltTys;
// what about nested types?
// Note: The split of CXXDecl information here is intentional, the
// gdb tests will depend on a certain ordering at printout. The debug
// information offsets are still correct if we merge them all together
// though.
const auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
if (CXXDecl) {
CollectCXXBases(CXXDecl, DefUnit, EltTys, FwdDecl);
CollectVTableInfo(CXXDecl, DefUnit, EltTys, FwdDecl);
}
// Collect data fields (including static variables and any initializers).
CollectRecordFields(RD, DefUnit, EltTys, FwdDecl);
if (CXXDecl)
CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl);
LexicalBlockStack.pop_back();
RegionMap.erase(Ty->getDecl());
llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys);
DBuilder.replaceArrays(FwdDecl, Elements);
if (FwdDecl->isTemporary())
FwdDecl =
llvm::MDNode::replaceWithPermanent(llvm::TempDICompositeType(FwdDecl));
RegionMap[Ty->getDecl()].reset(FwdDecl);
return FwdDecl;
}
llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectType *Ty,
llvm::DIFile *Unit) {
// Ignore protocols.
return getOrCreateType(Ty->getBaseType(), Unit);
}
llvm::DIType *CGDebugInfo::CreateType(const ObjCTypeParamType *Ty,
llvm::DIFile *Unit) {
// Ignore protocols.
SourceLocation Loc = Ty->getDecl()->getLocation();
// Use Typedefs to represent ObjCTypeParamType.
return DBuilder.createTypedef(
getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit),
Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc),
getDeclContextDescriptor(Ty->getDecl()));
}
/// \return true if Getter has the default name for the property PD.
static bool hasDefaultGetterName(const ObjCPropertyDecl *PD,
const ObjCMethodDecl *Getter) {
assert(PD);
if (!Getter)
return true;
assert(Getter->getDeclName().isObjCZeroArgSelector());
return PD->getName() ==
Getter->getDeclName().getObjCSelector().getNameForSlot(0);
}
/// \return true if Setter has the default name for the property PD.
static bool hasDefaultSetterName(const ObjCPropertyDecl *PD,
const ObjCMethodDecl *Setter) {
assert(PD);
if (!Setter)
return true;
assert(Setter->getDeclName().isObjCOneArgSelector());
return SelectorTable::constructSetterName(PD->getName()) ==
Setter->getDeclName().getObjCSelector().getNameForSlot(0);
}
llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DIFile *Unit) {
ObjCInterfaceDecl *ID = Ty->getDecl();
if (!ID)
return nullptr;
// Return a forward declaration if this type was imported from a clang module,
// and this is not the compile unit with the implementation of the type (which
// may contain hidden ivars).
if (DebugTypeExtRefs && ID->isFromASTFile() && ID->getDefinition() &&
!ID->getImplementation())
return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
ID->getName(),
getDeclContextDescriptor(ID), Unit, 0);
// Get overall information about the record type for the debug info.
llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation());
unsigned Line = getLineNumber(ID->getLocation());
auto RuntimeLang =
static_cast<llvm::dwarf::SourceLanguage>(TheCU->getSourceLanguage());
// If this is just a forward declaration return a special forward-declaration
// debug type since we won't be able to lay out the entire type.
ObjCInterfaceDecl *Def = ID->getDefinition();
if (!Def || !Def->getImplementation()) {
llvm::DIScope *Mod = getParentModuleOrNull(ID);
llvm::DIType *FwdDecl = DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_structure_type, ID->getName(), Mod ? Mod : TheCU,
DefUnit, Line, RuntimeLang);
ObjCInterfaceCache.push_back(ObjCInterfaceCacheEntry(Ty, FwdDecl, Unit));
return FwdDecl;
}
return CreateTypeDefinition(Ty, Unit);
}
llvm::DIModule *
CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod,
bool CreateSkeletonCU) {
// Use the Module pointer as the key into the cache. This is a
// nullptr if the "Module" is a PCH, which is safe because we don't
// support chained PCH debug info, so there can only be a single PCH.
const Module *M = Mod.getModuleOrNull();
auto ModRef = ModuleCache.find(M);
if (ModRef != ModuleCache.end())
return cast<llvm::DIModule>(ModRef->second);
// Macro definitions that were defined with "-D" on the command line.
SmallString<128> ConfigMacros;
{
llvm::raw_svector_ostream OS(ConfigMacros);
const auto &PPOpts = CGM.getPreprocessorOpts();
unsigned I = 0;
// Translate the macro definitions back into a command line.
for (auto &M : PPOpts.Macros) {
if (++I > 1)
OS << " ";
const std::string &Macro = M.first;
bool Undef = M.second;
OS << "\"-" << (Undef ? 'U' : 'D');
for (char c : Macro)
switch (c) {
case '\\':
OS << "\\\\";
break;
case '"':
OS << "\\\"";
break;
default:
OS << c;
}
OS << '\"';
}
}
bool IsRootModule = M ? !M->Parent : true;
if (CreateSkeletonCU && IsRootModule) {
// PCH files don't have a signature field in the control block,
// but LLVM detects skeleton CUs by looking for a non-zero DWO id.
// We use the lower 64 bits for debug info.
uint64_t Signature =
Mod.getSignature()
? (uint64_t)Mod.getSignature()[1] << 32 | Mod.getSignature()[0]
: ~1ULL;
llvm::DIBuilder DIB(CGM.getModule());
DIB.createCompileUnit(TheCU->getSourceLanguage(),
// TODO: Support "Source" from external AST providers?
DIB.createFile(Mod.getModuleName(), Mod.getPath()),
TheCU->getProducer(), true, StringRef(), 0,
Mod.getASTFile(), llvm::DICompileUnit::FullDebug,
Signature);
DIB.finalize();
}
llvm::DIModule *Parent =
IsRootModule ? nullptr
: getOrCreateModuleRef(
ExternalASTSource::ASTSourceDescriptor(*M->Parent),
CreateSkeletonCU);
llvm::DIModule *DIMod =
DBuilder.createModule(Parent, Mod.getModuleName(), ConfigMacros,
Mod.getPath(), CGM.getHeaderSearchOpts().Sysroot);
ModuleCache[M].reset(DIMod);
return DIMod;
}
llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty,
llvm::DIFile *Unit) {
ObjCInterfaceDecl *ID = Ty->getDecl();
llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation());
unsigned Line = getLineNumber(ID->getLocation());
unsigned RuntimeLang = TheCU->getSourceLanguage();
// Bit size, align and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(Ty);
auto Align = getTypeAlignIfRequired(Ty, CGM.getContext());
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
if (ID->getImplementation())
Flags |= llvm::DINode::FlagObjcClassComplete;
llvm::DIScope *Mod = getParentModuleOrNull(ID);
llvm::DICompositeType *RealDecl = DBuilder.createStructType(
Mod ? Mod : Unit, ID->getName(), DefUnit, Line, Size, Align, Flags,
nullptr, llvm::DINodeArray(), RuntimeLang);
QualType QTy(Ty, 0);
TypeCache[QTy.getAsOpaquePtr()].reset(RealDecl);
// Push the struct on region stack.
LexicalBlockStack.emplace_back(RealDecl);
RegionMap[Ty->getDecl()].reset(RealDecl);
// Convert all the elements.
SmallVector<llvm::Metadata *, 16> EltTys;
ObjCInterfaceDecl *SClass = ID->getSuperClass();
if (SClass) {
llvm::DIType *SClassTy =
getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit);
if (!SClassTy)
return nullptr;
llvm::DIType *InhTag = DBuilder.createInheritance(RealDecl, SClassTy, 0, 0,
llvm::DINode::FlagZero);
EltTys.push_back(InhTag);
}
// Create entries for all of the properties.
auto AddProperty = [&](const ObjCPropertyDecl *PD) {
SourceLocation Loc = PD->getLocation();
llvm::DIFile *PUnit = getOrCreateFile(Loc);
unsigned PLine = getLineNumber(Loc);
ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
llvm::MDNode *PropertyNode = DBuilder.createObjCProperty(
PD->getName(), PUnit, PLine,
hasDefaultGetterName(PD, Getter) ? ""
: getSelectorName(PD->getGetterName()),
hasDefaultSetterName(PD, Setter) ? ""
: getSelectorName(PD->getSetterName()),
PD->getPropertyAttributes(), getOrCreateType(PD->getType(), PUnit));
EltTys.push_back(PropertyNode);
};
{
llvm::SmallPtrSet<const IdentifierInfo *, 16> PropertySet;
for (const ObjCCategoryDecl *ClassExt : ID->known_extensions())
for (auto *PD : ClassExt->properties()) {
PropertySet.insert(PD->getIdentifier());
AddProperty(PD);
}
for (const auto *PD : ID->properties()) {
// Don't emit duplicate metadata for properties that were already in a
// class extension.
if (!PropertySet.insert(PD->getIdentifier()).second)
continue;
AddProperty(PD);
}
}
const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID);
unsigned FieldNo = 0;
for (ObjCIvarDecl *Field = ID->all_declared_ivar_begin(); Field;
Field = Field->getNextIvar(), ++FieldNo) {
llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit);
if (!FieldTy)
return nullptr;
StringRef FieldName = Field->getName();
// Ignore unnamed fields.
if (FieldName.empty())
continue;
// Get the location for the field.
llvm::DIFile *FieldDefUnit = getOrCreateFile(Field->getLocation());
unsigned FieldLine = getLineNumber(Field->getLocation());
QualType FType = Field->getType();
uint64_t FieldSize = 0;
uint32_t FieldAlign = 0;
if (!FType->isIncompleteArrayType()) {
// Bit size, align and offset of the type.
FieldSize = Field->isBitField()
? Field->getBitWidthValue(CGM.getContext())
: CGM.getContext().getTypeSize(FType);
FieldAlign = getTypeAlignIfRequired(FType, CGM.getContext());
}
uint64_t FieldOffset;
if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
// We don't know the runtime offset of an ivar if we're using the
// non-fragile ABI. For bitfields, use the bit offset into the first
// byte of storage of the bitfield. For other fields, use zero.
if (Field->isBitField()) {
FieldOffset =
CGM.getObjCRuntime().ComputeBitfieldBitOffset(CGM, ID, Field);
FieldOffset %= CGM.getContext().getCharWidth();
} else {
FieldOffset = 0;
}
} else {
FieldOffset = RL.getFieldOffset(FieldNo);
}
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
if (Field->getAccessControl() == ObjCIvarDecl::Protected)
Flags = llvm::DINode::FlagProtected;
else if (Field->getAccessControl() == ObjCIvarDecl::Private)
Flags = llvm::DINode::FlagPrivate;
else if (Field->getAccessControl() == ObjCIvarDecl::Public)
Flags = llvm::DINode::FlagPublic;
llvm::MDNode *PropertyNode = nullptr;
if (ObjCImplementationDecl *ImpD = ID->getImplementation()) {
if (ObjCPropertyImplDecl *PImpD =
ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) {
if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) {
SourceLocation Loc = PD->getLocation();
llvm::DIFile *PUnit = getOrCreateFile(Loc);
unsigned PLine = getLineNumber(Loc);
ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
PropertyNode = DBuilder.createObjCProperty(
PD->getName(), PUnit, PLine,
hasDefaultGetterName(PD, Getter)
? ""
: getSelectorName(PD->getGetterName()),
hasDefaultSetterName(PD, Setter)
? ""
: getSelectorName(PD->getSetterName()),
PD->getPropertyAttributes(),
getOrCreateType(PD->getType(), PUnit));
}
}
}
FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit, FieldLine,
FieldSize, FieldAlign, FieldOffset, Flags,
FieldTy, PropertyNode);
EltTys.push_back(FieldTy);
}
llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys);
DBuilder.replaceArrays(RealDecl, Elements);
LexicalBlockStack.pop_back();
return RealDecl;
}
llvm::DIType *CGDebugInfo::CreateType(const VectorType *Ty,
llvm::DIFile *Unit) {
llvm::DIType *ElementTy = getOrCreateType(Ty->getElementType(), Unit);
int64_t Count = Ty->getNumElements();
llvm::Metadata *Subscript;
QualType QTy(Ty, 0);
auto SizeExpr = SizeExprCache.find(QTy);
if (SizeExpr != SizeExprCache.end())
Subscript = DBuilder.getOrCreateSubrange(0, SizeExpr->getSecond());
else
Subscript = DBuilder.getOrCreateSubrange(0, Count ? Count : -1);
llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscript);
uint64_t Size = CGM.getContext().getTypeSize(Ty);
auto Align = getTypeAlignIfRequired(Ty, CGM.getContext());
return DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray);
}
llvm::DIType *CGDebugInfo::CreateType(const ArrayType *Ty, llvm::DIFile *Unit) {
uint64_t Size;
uint32_t Align;
// FIXME: make getTypeAlign() aware of VLAs and incomplete array types
if (const auto *VAT = dyn_cast<VariableArrayType>(Ty)) {
Size = 0;
Align = getTypeAlignIfRequired(CGM.getContext().getBaseElementType(VAT),
CGM.getContext());
} else if (Ty->isIncompleteArrayType()) {
Size = 0;
if (Ty->getElementType()->isIncompleteType())
Align = 0;
else
Align = getTypeAlignIfRequired(Ty->getElementType(), CGM.getContext());
} else if (Ty->isIncompleteType()) {
Size = 0;
Align = 0;
} else {
// Size and align of the whole array, not the element type.
Size = CGM.getContext().getTypeSize(Ty);
Align = getTypeAlignIfRequired(Ty, CGM.getContext());
}
// Add the dimensions of the array. FIXME: This loses CV qualifiers from
// interior arrays, do we care? Why aren't nested arrays represented the
// obvious/recursive way?
SmallVector<llvm::Metadata *, 8> Subscripts;
QualType EltTy(Ty, 0);
while ((Ty = dyn_cast<ArrayType>(EltTy))) {
// If the number of elements is known, then count is that number. Otherwise,
// it's -1. This allows us to represent a subrange with an array of 0
// elements, like this:
//
// struct foo {
// int x[0];
// };
int64_t Count = -1; // Count == -1 is an unbounded array.
if (const auto *CAT = dyn_cast<ConstantArrayType>(Ty))
Count = CAT->getSize().getZExtValue();
else if (const auto *VAT = dyn_cast<VariableArrayType>(Ty)) {
if (Expr *Size = VAT->getSizeExpr()) {
Expr::EvalResult Result;
if (Size->EvaluateAsInt(Result, CGM.getContext()))
Count = Result.Val.getInt().getExtValue();
}
}
auto SizeNode = SizeExprCache.find(EltTy);
if (SizeNode != SizeExprCache.end())
Subscripts.push_back(
DBuilder.getOrCreateSubrange(0, SizeNode->getSecond()));
else
Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count));
EltTy = Ty->getElementType();
}
llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts);
return DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit),
SubscriptArray);
}
llvm::DIType *CGDebugInfo::CreateType(const LValueReferenceType *Ty,
llvm::DIFile *Unit) {
return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type, Ty,
Ty->getPointeeType(), Unit);
}
llvm::DIType *CGDebugInfo::CreateType(const RValueReferenceType *Ty,
llvm::DIFile *Unit) {
return CreatePointerLikeType(llvm::dwarf::DW_TAG_rvalue_reference_type, Ty,
Ty->getPointeeType(), Unit);
}
llvm::DIType *CGDebugInfo::CreateType(const MemberPointerType *Ty,
llvm::DIFile *U) {
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
uint64_t Size = 0;
if (!Ty->isIncompleteType()) {
Size = CGM.getContext().getTypeSize(Ty);
// Set the MS inheritance model. There is no flag for the unspecified model.
if (CGM.getTarget().getCXXABI().isMicrosoft()) {
switch (Ty->getMostRecentCXXRecordDecl()->getMSInheritanceModel()) {
case MSInheritanceAttr::Keyword_single_inheritance:
Flags |= llvm::DINode::FlagSingleInheritance;
break;
case MSInheritanceAttr::Keyword_multiple_inheritance:
Flags |= llvm::DINode::FlagMultipleInheritance;
break;
case MSInheritanceAttr::Keyword_virtual_inheritance:
Flags |= llvm::DINode::FlagVirtualInheritance;
break;
case MSInheritanceAttr::Keyword_unspecified_inheritance:
break;
}
}
}
llvm::DIType *ClassType = getOrCreateType(QualType(Ty->getClass(), 0), U);
if (Ty->isMemberDataPointerType())
return DBuilder.createMemberPointerType(
getOrCreateType(Ty->getPointeeType(), U), ClassType, Size, /*Align=*/0,
Flags);
const FunctionProtoType *FPT =
Ty->getPointeeType()->getAs<FunctionProtoType>();
return DBuilder.createMemberPointerType(
getOrCreateInstanceMethodType(
CXXMethodDecl::getThisType(FPT, Ty->getMostRecentCXXRecordDecl()),
FPT, U),
ClassType, Size, /*Align=*/0, Flags);
}
llvm::DIType *CGDebugInfo::CreateType(const AtomicType *Ty, llvm::DIFile *U) {
auto *FromTy = getOrCreateType(Ty->getValueType(), U);
return DBuilder.createQualifiedType(llvm::dwarf::DW_TAG_atomic_type, FromTy);
}
llvm::DIType *CGDebugInfo::CreateType(const PipeType *Ty, llvm::DIFile *U) {
return getOrCreateType(Ty->getElementType(), U);
}
llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) {
const EnumDecl *ED = Ty->getDecl();
uint64_t Size = 0;
uint32_t Align = 0;
if (!ED->getTypeForDecl()->isIncompleteType()) {
Size = CGM.getContext().getTypeSize(ED->getTypeForDecl());
Align = getDeclAlignIfRequired(ED, CGM.getContext());
}
SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU);
bool isImportedFromModule =
DebugTypeExtRefs && ED->isFromASTFile() && ED->getDefinition();
// If this is just a forward declaration, construct an appropriately
// marked node and just return it.
if (isImportedFromModule || !ED->getDefinition()) {
// Note that it is possible for enums to be created as part of
// their own declcontext. In this case a FwdDecl will be created
// twice. This doesn't cause a problem because both FwdDecls are
// entered into the ReplaceMap: finalize() will replace the first
// FwdDecl with the second and then replace the second with
// complete type.
llvm::DIScope *EDContext = getDeclContextDescriptor(ED);
llvm::DIFile *DefUnit = getOrCreateFile(ED->getLocation());
llvm::TempDIScope TmpContext(DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_enumeration_type, "", TheCU, DefUnit, 0));
unsigned Line = getLineNumber(ED->getLocation());
StringRef EDName = ED->getName();
llvm::DIType *RetTy = DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_enumeration_type, EDName, EDContext, DefUnit, Line,
0, Size, Align, llvm::DINode::FlagFwdDecl, Identifier);
ReplaceMap.emplace_back(
std::piecewise_construct, std::make_tuple(Ty),
std::make_tuple(static_cast<llvm::Metadata *>(RetTy)));
return RetTy;
}
return CreateTypeDefinition(Ty);
}
llvm::DIType *CGDebugInfo::CreateTypeDefinition(const EnumType *Ty) {
const EnumDecl *ED = Ty->getDecl();
uint64_t Size = 0;
uint32_t Align = 0;
if (!ED->getTypeForDecl()->isIncompleteType()) {
Size = CGM.getContext().getTypeSize(ED->getTypeForDecl());
Align = getDeclAlignIfRequired(ED, CGM.getContext());
}
SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU);
// Create elements for each enumerator.
SmallVector<llvm::Metadata *, 16> Enumerators;
ED = ED->getDefinition();
bool IsSigned = ED->getIntegerType()->isSignedIntegerType();
for (const auto *Enum : ED->enumerators()) {
const auto &InitVal = Enum->getInitVal();
auto Value = IsSigned ? InitVal.getSExtValue() : InitVal.getZExtValue();
Enumerators.push_back(
DBuilder.createEnumerator(Enum->getName(), Value, !IsSigned));
}
// Return a CompositeType for the enum itself.
llvm::DINodeArray EltArray = DBuilder.getOrCreateArray(Enumerators);
llvm::DIFile *DefUnit = getOrCreateFile(ED->getLocation());
unsigned Line = getLineNumber(ED->getLocation());
llvm::DIScope *EnumContext = getDeclContextDescriptor(ED);
llvm::DIType *ClassTy = getOrCreateType(ED->getIntegerType(), DefUnit);
return DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit,
Line, Size, Align, EltArray, ClassTy,
Identifier, ED->isScoped());
}
llvm::DIMacro *CGDebugInfo::CreateMacro(llvm::DIMacroFile *Parent,
unsigned MType, SourceLocation LineLoc,
StringRef Name, StringRef Value) {
unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc);
return DBuilder.createMacro(Parent, Line, MType, Name, Value);
}
llvm::DIMacroFile *CGDebugInfo::CreateTempMacroFile(llvm::DIMacroFile *Parent,
SourceLocation LineLoc,
SourceLocation FileLoc) {
llvm::DIFile *FName = getOrCreateFile(FileLoc);
unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc);
return DBuilder.createTempMacroFile(Parent, Line, FName);
}
static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
Qualifiers Quals;
do {
Qualifiers InnerQuals = T.getLocalQualifiers();
// Qualifiers::operator+() doesn't like it if you add a Qualifier
// that is already there.
Quals += Qualifiers::removeCommonQualifiers(Quals, InnerQuals);
Quals += InnerQuals;
QualType LastT = T;
switch (T->getTypeClass()) {
default:
return C.getQualifiedType(T.getTypePtr(), Quals);
case Type::TemplateSpecialization: {
const auto *Spec = cast<TemplateSpecializationType>(T);
if (Spec->isTypeAlias())
return C.getQualifiedType(T.getTypePtr(), Quals);
T = Spec->desugar();
break;
}
case Type::TypeOfExpr:
T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType();
break;
case Type::TypeOf:
T = cast<TypeOfType>(T)->getUnderlyingType();
break;
case Type::Decltype:
T = cast<DecltypeType>(T)->getUnderlyingType();
break;
case Type::UnaryTransform:
T = cast<UnaryTransformType>(T)->getUnderlyingType();
break;
case Type::Attributed:
T = cast<AttributedType>(T)->getEquivalentType();
break;
case Type::Elaborated:
T = cast<ElaboratedType>(T)->getNamedType();
break;
case Type::Paren:
T = cast<ParenType>(T)->getInnerType();
break;
case Type::SubstTemplateTypeParm:
T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
break;
case Type::Auto:
case Type::DeducedTemplateSpecialization: {
QualType DT = cast<DeducedType>(T)->getDeducedType();
assert(!DT.isNull() && "Undeduced types shouldn't reach here.");
T = DT;
break;
}
case Type::Adjusted:
case Type::Decayed:
// Decayed and adjusted types use the adjusted type in LLVM and DWARF.
T = cast<AdjustedType>(T)->getAdjustedType();
break;
}
assert(T != LastT && "Type unwrapping failed to unwrap!");
(void)LastT;
} while (true);
}
llvm::DIType *CGDebugInfo::getTypeOrNull(QualType Ty) {
// Unwrap the type as needed for debug information.
Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
auto It = TypeCache.find(Ty.getAsOpaquePtr());
if (It != TypeCache.end()) {
// Verify that the debug info still exists.
if (llvm::Metadata *V = It->second)
return cast<llvm::DIType>(V);
}
return nullptr;
}
void CGDebugInfo::completeTemplateDefinition(
const ClassTemplateSpecializationDecl &SD) {
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
return;
completeUnusedClass(SD);
}
void CGDebugInfo::completeUnusedClass(const CXXRecordDecl &D) {
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
return;
completeClassData(&D);
// In case this type has no member function definitions being emitted, ensure
// it is retained
RetainedTypes.push_back(CGM.getContext().getRecordType(&D).getAsOpaquePtr());
}
llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
if (Ty.isNull())
return nullptr;
// Unwrap the type as needed for debug information.
Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
if (auto *T = getTypeOrNull(Ty))
return T;
llvm::DIType *Res = CreateTypeNode(Ty, Unit);
void *TyPtr = Ty.getAsOpaquePtr();
// And update the type cache.
TypeCache[TyPtr].reset(Res);
return Res;
}
llvm::DIModule *CGDebugInfo::getParentModuleOrNull(const Decl *D) {
// A forward declaration inside a module header does not belong to the module.
if (isa<RecordDecl>(D) && !cast<RecordDecl>(D)->getDefinition())
return nullptr;
if (DebugTypeExtRefs && D->isFromASTFile()) {
// Record a reference to an imported clang module or precompiled header.
auto *Reader = CGM.getContext().getExternalSource();
auto Idx = D->getOwningModuleID();
auto Info = Reader->getSourceDescriptor(Idx);
if (Info)
return getOrCreateModuleRef(*Info, /*SkeletonCU=*/true);
} else if (ClangModuleMap) {
// We are building a clang module or a precompiled header.
//
// TODO: When D is a CXXRecordDecl or a C++ Enum, the ODR applies
// and it wouldn't be necessary to specify the parent scope
// because the type is already unique by definition (it would look
// like the output of -fno-standalone-debug). On the other hand,
// the parent scope helps a consumer to quickly locate the object
// file where the type's definition is located, so it might be
// best to make this behavior a command line or debugger tuning
// option.
if (Module *M = D->getOwningModule()) {
// This is a (sub-)module.
auto Info = ExternalASTSource::ASTSourceDescriptor(*M);
return getOrCreateModuleRef(Info, /*SkeletonCU=*/false);
} else {
// This the precompiled header being built.
return getOrCreateModuleRef(PCHDescriptor, /*SkeletonCU=*/false);
}
}
return nullptr;
}
llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
// Handle qualifiers, which recursively handles what they refer to.
if (Ty.hasLocalQualifiers())
return CreateQualifiedType(Ty, Unit);
// Work out details of type.
switch (Ty->getTypeClass()) {
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
#define NON_CANONICAL_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
llvm_unreachable("Dependent types cannot show up in debug information");
case Type::ExtVector:
case Type::Vector:
return CreateType(cast<VectorType>(Ty), Unit);
case Type::ObjCObjectPointer:
return CreateType(cast<ObjCObjectPointerType>(Ty), Unit);
case Type::ObjCObject:
return CreateType(cast<ObjCObjectType>(Ty), Unit);
case Type::ObjCTypeParam:
return CreateType(cast<ObjCTypeParamType>(Ty), Unit);
case Type::ObjCInterface:
return CreateType(cast<ObjCInterfaceType>(Ty), Unit);
case Type::Builtin:
return CreateType(cast<BuiltinType>(Ty));
case Type::Complex:
return CreateType(cast<ComplexType>(Ty));
case Type::Pointer:
return CreateType(cast<PointerType>(Ty), Unit);
case Type::BlockPointer:
return CreateType(cast<BlockPointerType>(Ty), Unit);
case Type::Typedef:
return CreateType(cast<TypedefType>(Ty), Unit);
case Type::Record:
return CreateType(cast<RecordType>(Ty));
case Type::Enum:
return CreateEnumType(cast<EnumType>(Ty));
case Type::FunctionProto:
case Type::FunctionNoProto:
return CreateType(cast<FunctionType>(Ty), Unit);
case Type::ConstantArray:
case Type::VariableArray:
case Type::IncompleteArray:
return CreateType(cast<ArrayType>(Ty), Unit);
case Type::LValueReference:
return CreateType(cast<LValueReferenceType>(Ty), Unit);
case Type::RValueReference:
return CreateType(cast<RValueReferenceType>(Ty), Unit);
case Type::MemberPointer:
return CreateType(cast<MemberPointerType>(Ty), Unit);
case Type::Atomic:
return CreateType(cast<AtomicType>(Ty), Unit);
case Type::Pipe:
return CreateType(cast<PipeType>(Ty), Unit);
case Type::TemplateSpecialization:
return CreateType(cast<TemplateSpecializationType>(Ty), Unit);
case Type::Auto:
case Type::Attributed:
case Type::Adjusted:
case Type::Decayed:
case Type::DeducedTemplateSpecialization:
case Type::Elaborated:
case Type::Paren:
case Type::SubstTemplateTypeParm:
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
case Type::UnaryTransform:
case Type::PackExpansion:
break;
}
llvm_unreachable("type should have been unwrapped!");
}
llvm::DICompositeType *CGDebugInfo::getOrCreateLimitedType(const RecordType *Ty,
llvm::DIFile *Unit) {
QualType QTy(Ty, 0);
auto *T = cast_or_null<llvm::DICompositeType>(getTypeOrNull(QTy));
// We may have cached a forward decl when we could have created
// a non-forward decl. Go ahead and create a non-forward decl
// now.
if (T && !T->isForwardDecl())
return T;
// Otherwise create the type.
llvm::DICompositeType *Res = CreateLimitedType(Ty);
// Propagate members from the declaration to the definition
// CreateType(const RecordType*) will overwrite this with the members in the
// correct order if the full type is needed.
DBuilder.replaceArrays(Res, T ? T->getElements() : llvm::DINodeArray());
// And update the type cache.
TypeCache[QTy.getAsOpaquePtr()].reset(Res);
return Res;
}
// TODO: Currently used for context chains when limiting debug info.
llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
RecordDecl *RD = Ty->getDecl();
// Get overall information about the record type for the debug info.
llvm::DIFile *DefUnit = getOrCreateFile(RD->getLocation());
unsigned Line = getLineNumber(RD->getLocation());
StringRef RDName = getClassName(RD);
llvm::DIScope *RDContext = getDeclContextDescriptor(RD);
// If we ended up creating the type during the context chain construction,
// just return that.
auto *T = cast_or_null<llvm::DICompositeType>(
getTypeOrNull(CGM.getContext().getRecordType(RD)));
if (T && (!T->isForwardDecl() || !RD->getDefinition()))
return T;
// If this is just a forward or incomplete declaration, construct an
// appropriately marked node and just return it.
const RecordDecl *D = RD->getDefinition();
if (!D || !D->isCompleteDefinition())
return getOrCreateRecordFwdDecl(Ty, RDContext);
uint64_t Size = CGM.getContext().getTypeSize(Ty);
auto Align = getDeclAlignIfRequired(D, CGM.getContext());
SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU);
// Explicitly record the calling convention for C++ records.
auto Flags = llvm::DINode::FlagZero;
if (auto CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
if (CGM.getCXXABI().getRecordArgABI(CXXRD) == CGCXXABI::RAA_Indirect)
Flags |= llvm::DINode::FlagTypePassByReference;
else
Flags |= llvm::DINode::FlagTypePassByValue;
// Record if a C++ record is trivial type.
if (CXXRD->isTrivial())
Flags |= llvm::DINode::FlagTrivial;
}
llvm::DICompositeType *RealDecl = DBuilder.createReplaceableCompositeType(
getTagForRecord(RD), RDName, RDContext, DefUnit, Line, 0, Size, Align,
Flags, Identifier);
// Elements of composite types usually have back to the type, creating
// uniquing cycles. Distinct nodes are more efficient.
switch (RealDecl->getTag()) {
default:
llvm_unreachable("invalid composite type tag");
case llvm::dwarf::DW_TAG_array_type:
case llvm::dwarf::DW_TAG_enumeration_type:
// Array elements and most enumeration elements don't have back references,
// so they don't tend to be involved in uniquing cycles and there is some
// chance of merging them when linking together two modules. Only make
// them distinct if they are ODR-uniqued.
if (Identifier.empty())
break;
LLVM_FALLTHROUGH;
case llvm::dwarf::DW_TAG_structure_type:
case llvm::dwarf::DW_TAG_union_type:
case llvm::dwarf::DW_TAG_class_type:
// Immediately resolve to a distinct node.
RealDecl =
llvm::MDNode::replaceWithDistinct(llvm::TempDICompositeType(RealDecl));
break;
}
RegionMap[Ty->getDecl()].reset(RealDecl);
TypeCache[QualType(Ty, 0).getAsOpaquePtr()].reset(RealDecl);
if (const auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD))
DBuilder.replaceArrays(RealDecl, llvm::DINodeArray(),
CollectCXXTemplateParams(TSpecial, DefUnit));
return RealDecl;
}
void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD,
llvm::DICompositeType *RealDecl) {
// A class's primary base or the class itself contains the vtable.
llvm::DICompositeType *ContainingType = nullptr;
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
// Seek non-virtual primary base root.
while (1) {
const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
const CXXRecordDecl *PBT = BRL.getPrimaryBase();
if (PBT && !BRL.isPrimaryBaseVirtual())
PBase = PBT;
else
break;
}
ContainingType = cast<llvm::DICompositeType>(
getOrCreateType(QualType(PBase->getTypeForDecl(), 0),
getOrCreateFile(RD->getLocation())));
} else if (RD->isDynamicClass())
ContainingType = RealDecl;
DBuilder.replaceVTableHolder(RealDecl, ContainingType);
}
llvm::DIType *CGDebugInfo::CreateMemberType(llvm::DIFile *Unit, QualType FType,
StringRef Name, uint64_t *Offset) {
llvm::DIType *FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
uint64_t FieldSize = CGM.getContext().getTypeSize(FType);
auto FieldAlign = getTypeAlignIfRequired(FType, CGM.getContext());
llvm::DIType *Ty =
DBuilder.createMemberType(Unit, Name, Unit, 0, FieldSize, FieldAlign,
*Offset, llvm::DINode::FlagZero, FieldTy);
*Offset += FieldSize;
return Ty;
}
void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit,
StringRef &Name,
StringRef &LinkageName,
llvm::DIScope *&FDContext,
llvm::DINodeArray &TParamsArray,
llvm::DINode::DIFlags &Flags) {
const auto *FD = cast<FunctionDecl>(GD.getDecl());
Name = getFunctionName(FD);
// Use mangled name as linkage name for C/C++ functions.
if (FD->hasPrototype()) {
LinkageName = CGM.getMangledName(GD);
Flags |= llvm::DINode::FlagPrototyped;
}
// No need to replicate the linkage name if it isn't different from the
// subprogram name, no need to have it at all unless coverage is enabled or
// debug is set to more than just line tables or extra debug info is needed.
if (LinkageName == Name || (!CGM.getCodeGenOpts().EmitGcovArcs &&
!CGM.getCodeGenOpts().EmitGcovNotes &&
!CGM.getCodeGenOpts().DebugInfoForProfiling &&
DebugKind <= codegenoptions::DebugLineTablesOnly))
LinkageName = StringRef();
if (DebugKind >= codegenoptions::LimitedDebugInfo) {
if (const NamespaceDecl *NSDecl =
dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
FDContext = getOrCreateNamespace(NSDecl);
else if (const RecordDecl *RDecl =
dyn_cast_or_null<RecordDecl>(FD->getDeclContext())) {
llvm::DIScope *Mod = getParentModuleOrNull(RDecl);
FDContext = getContextDescriptor(RDecl, Mod ? Mod : TheCU);
}
// Check if it is a noreturn-marked function
if (FD->isNoReturn())
Flags |= llvm::DINode::FlagNoReturn;
// Collect template parameters.
TParamsArray = CollectFunctionTemplateParams(FD, Unit);
}
}
void CGDebugInfo::collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit,
unsigned &LineNo, QualType &T,
StringRef &Name, StringRef &LinkageName,
llvm::MDTuple *&TemplateParameters,
llvm::DIScope *&VDContext) {
Unit = getOrCreateFile(VD->getLocation());
LineNo = getLineNumber(VD->getLocation());
setLocation(VD->getLocation());
T = VD->getType();
if (T->isIncompleteArrayType()) {
// CodeGen turns int[] into int[1] so we'll do the same here.
llvm::APInt ConstVal(32, 1);
QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal,
0);
}
Name = VD->getName();
if (VD->getDeclContext() && !isa<FunctionDecl>(VD->getDeclContext()) &&
!isa<ObjCMethodDecl>(VD->getDeclContext()))
LinkageName = CGM.getMangledName(VD);
if (LinkageName == Name)
LinkageName = StringRef();
if (isa<VarTemplateSpecializationDecl>(VD)) {
llvm::DINodeArray parameterNodes = CollectVarTemplateParams(VD, &*Unit);
TemplateParameters = parameterNodes.get();
} else {
TemplateParameters = nullptr;
}
// Since we emit declarations (DW_AT_members) for static members, place the
// definition of those static members in the namespace they were declared in
// in the source code (the lexical decl context).
// FIXME: Generalize this for even non-member global variables where the
// declaration and definition may have different lexical decl contexts, once
// we have support for emitting declarations of (non-member) global variables.
const DeclContext *DC = VD->isStaticDataMember() ? VD->getLexicalDeclContext()
: VD->getDeclContext();
// When a record type contains an in-line initialization of a static data
// member, and the record type is marked as __declspec(dllexport), an implicit
// definition of the member will be created in the record context. DWARF
// doesn't seem to have a nice way to describe this in a form that consumers
// are likely to understand, so fake the "normal" situation of a definition
// outside the class by putting it in the global scope.
if (DC->isRecord())
DC = CGM.getContext().getTranslationUnitDecl();
llvm::DIScope *Mod = getParentModuleOrNull(VD);
VDContext = getContextDescriptor(cast<Decl>(DC), Mod ? Mod : TheCU);
}
llvm::DISubprogram *CGDebugInfo::getFunctionFwdDeclOrStub(GlobalDecl GD,
bool Stub) {
llvm::DINodeArray TParamsArray;
StringRef Name, LinkageName;
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero;
SourceLocation Loc = GD.getDecl()->getLocation();
llvm::DIFile *Unit = getOrCreateFile(Loc);
llvm::DIScope *DContext = Unit;
unsigned Line = getLineNumber(Loc);
collectFunctionDeclProps(GD, Unit, Name, LinkageName, DContext, TParamsArray,
Flags);
auto *FD = dyn_cast<FunctionDecl>(GD.getDecl());
// Build function type.
SmallVector<QualType, 16> ArgTypes;
if (FD)
for (const ParmVarDecl *Parm : FD->parameters())
ArgTypes.push_back(Parm->getType());
CallingConv CC = FD->getType()->castAs<FunctionType>()->getCallConv();
QualType FnType = CGM.getContext().getFunctionType(
FD->getReturnType(), ArgTypes, FunctionProtoType::ExtProtoInfo(CC));
if (!FD->isExternallyVisible())
SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit;
if (CGM.getLangOpts().Optimize)
SPFlags |= llvm::DISubprogram::SPFlagOptimized;
if (Stub) {
Flags |= getCallSiteRelatedAttrs();
SPFlags |= llvm::DISubprogram::SPFlagDefinition;
return DBuilder.createFunction(
DContext, Name, LinkageName, Unit, Line,
getOrCreateFunctionType(GD.getDecl(), FnType, Unit), 0, Flags, SPFlags,
TParamsArray.get(), getFunctionDeclaration(FD));
}
llvm::DISubprogram *SP = DBuilder.createTempFunctionFwdDecl(
DContext, Name, LinkageName, Unit, Line,
getOrCreateFunctionType(GD.getDecl(), FnType, Unit), 0, Flags, SPFlags,
TParamsArray.get(), getFunctionDeclaration(FD));
const FunctionDecl *CanonDecl = FD->getCanonicalDecl();
FwdDeclReplaceMap.emplace_back(std::piecewise_construct,
std::make_tuple(CanonDecl),
std::make_tuple(SP));
return SP;
}
llvm::DISubprogram *CGDebugInfo::getFunctionForwardDeclaration(GlobalDecl GD) {
return getFunctionFwdDeclOrStub(GD, /* Stub = */ false);
}
llvm::DISubprogram *CGDebugInfo::getFunctionStub(GlobalDecl GD) {
return getFunctionFwdDeclOrStub(GD, /* Stub = */ true);
}
llvm::DIGlobalVariable *
CGDebugInfo::getGlobalVariableForwardDeclaration(const VarDecl *VD) {
QualType T;
StringRef Name, LinkageName;
SourceLocation Loc = VD->getLocation();
llvm::DIFile *Unit = getOrCreateFile(Loc);
llvm::DIScope *DContext = Unit;
unsigned Line = getLineNumber(Loc);
llvm::MDTuple *TemplateParameters = nullptr;
collectVarDeclProps(VD, Unit, Line, T, Name, LinkageName, TemplateParameters,
DContext);
auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
auto *GV = DBuilder.createTempGlobalVariableFwdDecl(
DContext, Name, LinkageName, Unit, Line, getOrCreateType(T, Unit),
!VD->isExternallyVisible(), nullptr, TemplateParameters, Align);
FwdDeclReplaceMap.emplace_back(
std::piecewise_construct,
std::make_tuple(cast<VarDecl>(VD->getCanonicalDecl())),
std::make_tuple(static_cast<llvm::Metadata *>(GV)));
return GV;
}
llvm::DINode *CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
// We only need a declaration (not a definition) of the type - so use whatever
// we would otherwise do to get a type for a pointee. (forward declarations in
// limited debug info, full definitions (if the type definition is available)
// in unlimited debug info)
if (const auto *TD = dyn_cast<TypeDecl>(D))
return getOrCreateType(CGM.getContext().getTypeDeclType(TD),
getOrCreateFile(TD->getLocation()));
auto I = DeclCache.find(D->getCanonicalDecl());
if (I != DeclCache.end()) {
auto N = I->second;
if (auto *GVE = dyn_cast_or_null<llvm::DIGlobalVariableExpression>(N))
return GVE->getVariable();
return dyn_cast_or_null<llvm::DINode>(N);
}
// No definition for now. Emit a forward definition that might be
// merged with a potential upcoming definition.
if (const auto *FD = dyn_cast<FunctionDecl>(D))
return getFunctionForwardDeclaration(FD);
else if (const auto *VD = dyn_cast<VarDecl>(D))
return getGlobalVariableForwardDeclaration(VD);
return nullptr;
}
llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) {
if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly)
return nullptr;
const auto *FD = dyn_cast<FunctionDecl>(D);
if (!FD)
return nullptr;
// Setup context.
auto *S = getDeclContextDescriptor(D);
auto MI = SPCache.find(FD->getCanonicalDecl());
if (MI == SPCache.end()) {
if (const auto *MD = dyn_cast<CXXMethodDecl>(FD->getCanonicalDecl())) {
return CreateCXXMemberFunction(MD, getOrCreateFile(MD->getLocation()),
cast<llvm::DICompositeType>(S));
}
}
if (MI != SPCache.end()) {
auto *SP = dyn_cast_or_null<llvm::DISubprogram>(MI->second);
if (SP && !SP->isDefinition())
return SP;
}
for (auto NextFD : FD->redecls()) {
auto MI = SPCache.find(NextFD->getCanonicalDecl());
if (MI != SPCache.end()) {
auto *SP = dyn_cast_or_null<llvm::DISubprogram>(MI->second);
if (SP && !SP->isDefinition())
return SP;
}
}
return nullptr;
}
// getOrCreateFunctionType - Construct type. If it is a c++ method, include
// implicit parameter "this".
llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
QualType FnType,
llvm::DIFile *F) {
if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly)
// Create fake but valid subroutine type. Otherwise -verify would fail, and
// subprogram DIE will miss DW_AT_decl_file and DW_AT_decl_line fields.
return DBuilder.createSubroutineType(DBuilder.getOrCreateTypeArray(None));
if (const auto *Method = dyn_cast<CXXMethodDecl>(D))
return getOrCreateMethodType(Method, F);
const auto *FTy = FnType->getAs<FunctionType>();
CallingConv CC = FTy ? FTy->getCallConv() : CallingConv::CC_C;
if (const auto *OMethod = dyn_cast<ObjCMethodDecl>(D)) {
// Add "self" and "_cmd"
SmallVector<llvm::Metadata *, 16> Elts;
// First element is always return type. For 'void' functions it is NULL.
QualType ResultTy = OMethod->getReturnType();
// Replace the instancetype keyword with the actual type.
if (ResultTy == CGM.getContext().getObjCInstanceType())
ResultTy = CGM.getContext().getPointerType(
QualType(OMethod->getClassInterface()->getTypeForDecl(), 0));
Elts.push_back(getOrCreateType(ResultTy, F));
// "self" pointer is always first argument.
QualType SelfDeclTy;
if (auto *SelfDecl = OMethod->getSelfDecl())
SelfDeclTy = SelfDecl->getType();
else if (auto *FPT = dyn_cast<FunctionProtoType>(FnType))
if (FPT->getNumParams() > 1)
SelfDeclTy = FPT->getParamType(0);
if (!SelfDeclTy.isNull())
Elts.push_back(
CreateSelfType(SelfDeclTy, getOrCreateType(SelfDeclTy, F)));
// "_cmd" pointer is always second argument.
Elts.push_back(DBuilder.createArtificialType(
getOrCreateType(CGM.getContext().getObjCSelType(), F)));
// Get rest of the arguments.
for (const auto *PI : OMethod->parameters())
Elts.push_back(getOrCreateType(PI->getType(), F));
// Variadic methods need a special marker at the end of the type list.
if (OMethod->isVariadic())
Elts.push_back(DBuilder.createUnspecifiedParameter());
llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts);
return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero,
getDwarfCC(CC));
}
// Handle variadic function types; they need an additional
// unspecified parameter.
if (const auto *FD = dyn_cast<FunctionDecl>(D))
if (FD->isVariadic()) {
SmallVector<llvm::Metadata *, 16> EltTys;
EltTys.push_back(getOrCreateType(FD->getReturnType(), F));
if (const auto *FPT = dyn_cast<FunctionProtoType>(FnType))
for (QualType ParamType : FPT->param_types())
EltTys.push_back(getOrCreateType(ParamType, F));
EltTys.push_back(DBuilder.createUnspecifiedParameter());
llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys);
return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero,
getDwarfCC(CC));
}
return cast<llvm::DISubroutineType>(getOrCreateType(FnType, F));
}
void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
SourceLocation ScopeLoc, QualType FnType,
llvm::Function *Fn, bool CurFuncIsThunk,
CGBuilderTy &Builder) {
StringRef Name;
StringRef LinkageName;
FnBeginRegionCount.push_back(LexicalBlockStack.size());
const Decl *D = GD.getDecl();
bool HasDecl = (D != nullptr);
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero;
llvm::DIFile *Unit = getOrCreateFile(Loc);
llvm::DIScope *FDContext = Unit;
llvm::DINodeArray TParamsArray;
if (!HasDecl) {
// Use llvm function name.
LinkageName = Fn->getName();
} else if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
// If there is a subprogram for this function available then use it.
auto FI = SPCache.find(FD->getCanonicalDecl());
if (FI != SPCache.end()) {
auto *SP = dyn_cast_or_null<llvm::DISubprogram>(FI->second);
if (SP && SP->isDefinition()) {
LexicalBlockStack.emplace_back(SP);
RegionMap[D].reset(SP);
return;
}
}
collectFunctionDeclProps(GD, Unit, Name, LinkageName, FDContext,
TParamsArray, Flags);
} else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(D)) {
Name = getObjCMethodName(OMD);
Flags |= llvm::DINode::FlagPrototyped;
} else {
// Use llvm function name.
Name = Fn->getName();
Flags |= llvm::DINode::FlagPrototyped;
}
if (Name.startswith("\01"))
Name = Name.substr(1);
if (!HasDecl || D->isImplicit() || D->hasAttr<ArtificialAttr>()) {
Flags |= llvm::DINode::FlagArtificial;
// Artificial functions should not silently reuse CurLoc.
CurLoc = SourceLocation();
}
if (CurFuncIsThunk)
Flags |= llvm::DINode::FlagThunk;
if (Fn->hasLocalLinkage())
SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit;
if (CGM.getLangOpts().Optimize)
SPFlags |= llvm::DISubprogram::SPFlagOptimized;
llvm::DINode::DIFlags FlagsForDef = Flags | getCallSiteRelatedAttrs();
llvm::DISubprogram::DISPFlags SPFlagsForDef =
SPFlags | llvm::DISubprogram::SPFlagDefinition;
unsigned LineNo = getLineNumber(Loc);
unsigned ScopeLine = getLineNumber(ScopeLoc);
// FIXME: The function declaration we're constructing here is mostly reusing
// declarations from CXXMethodDecl and not constructing new ones for arbitrary
// FunctionDecls. When/if we fix this we can have FDContext be TheCU/null for
// all subprograms instead of the actual context since subprogram definitions
// are emitted as CU level entities by the backend.
llvm::DISubprogram *SP = DBuilder.createFunction(
FDContext, Name, LinkageName, Unit, LineNo,
getOrCreateFunctionType(D, FnType, Unit), ScopeLine, FlagsForDef,
SPFlagsForDef, TParamsArray.get(), getFunctionDeclaration(D));
Fn->setSubprogram(SP);
// We might get here with a VarDecl in the case we're generating
// code for the initialization of globals. Do not record these decls
// as they will overwrite the actual VarDecl Decl in the cache.
if (HasDecl && isa<FunctionDecl>(D))
DeclCache[D->getCanonicalDecl()].reset(SP);
if (CGM.getCodeGenOpts().DwarfVersion >= 5) {
// Starting with DWARF V5 method declarations are emitted as children of
// the interface type.
if (const auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
const ObjCInterfaceDecl *ID = OMD->getClassInterface();
QualType QTy(ID->getTypeForDecl(), 0);
auto It = TypeCache.find(QTy.getAsOpaquePtr());
if (It != TypeCache.end()) {
llvm::DICompositeType *InterfaceDecl =
cast<llvm::DICompositeType>(It->second);
llvm::DISubprogram *FD = DBuilder.createFunction(
InterfaceDecl, Name, LinkageName, Unit, LineNo,
getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags,
TParamsArray.get());
DBuilder.finalizeSubprogram(FD);
ObjCMethodCache[ID].push_back(FD);
}
}
}
// Push the function onto the lexical block stack.
LexicalBlockStack.emplace_back(SP);
if (HasDecl)
RegionMap[D].reset(SP);
}
void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
QualType FnType) {
StringRef Name;
StringRef LinkageName;
const Decl *D = GD.getDecl();
if (!D)
return;
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
llvm::DIFile *Unit = getOrCreateFile(Loc);
llvm::DIScope *FDContext = getDeclContextDescriptor(D);
llvm::DINodeArray TParamsArray;
if (isa<FunctionDecl>(D)) {
// If there is a DISubprogram for this function available then use it.
collectFunctionDeclProps(GD, Unit, Name, LinkageName, FDContext,
TParamsArray, Flags);
} else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(D)) {
Name = getObjCMethodName(OMD);
Flags |= llvm::DINode::FlagPrototyped;
} else {
llvm_unreachable("not a function or ObjC method");
}
if (!Name.empty() && Name[0] == '\01')
Name = Name.substr(1);
if (D->isImplicit()) {
Flags |= llvm::DINode::FlagArtificial;
// Artificial functions without a location should not silently reuse CurLoc.
if (Loc.isInvalid())
CurLoc = SourceLocation();
}
unsigned LineNo = getLineNumber(Loc);
unsigned ScopeLine = 0;
llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero;
if (CGM.getLangOpts().Optimize)
SPFlags |= llvm::DISubprogram::SPFlagOptimized;
DBuilder.retainType(DBuilder.createFunction(
FDContext, Name, LinkageName, Unit, LineNo,
getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags,
TParamsArray.get(), getFunctionDeclaration(D)));
}
void CGDebugInfo::EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD) {
const auto *FD = cast<FunctionDecl>(GD.getDecl());
// If there is a subprogram for this function available then use it.
auto FI = SPCache.find(FD->getCanonicalDecl());
llvm::DISubprogram *SP = nullptr;
if (FI != SPCache.end())
SP = dyn_cast_or_null<llvm::DISubprogram>(FI->second);
if (!SP || !SP->isDefinition())
SP = getFunctionStub(GD);
FnBeginRegionCount.push_back(LexicalBlockStack.size());
LexicalBlockStack.emplace_back(SP);
setInlinedAt(Builder.getCurrentDebugLocation());
EmitLocation(Builder, FD->getLocation());
}
void CGDebugInfo::EmitInlineFunctionEnd(CGBuilderTy &Builder) {
assert(CurInlinedAt && "unbalanced inline scope stack");
EmitFunctionEnd(Builder, nullptr);
setInlinedAt(llvm::DebugLoc(CurInlinedAt).getInlinedAt());
}
void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
// Update our current location
setLocation(Loc);
if (CurLoc.isInvalid() || CurLoc.isMacroID() || LexicalBlockStack.empty())
return;
llvm::MDNode *Scope = LexicalBlockStack.back();
Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(
getLineNumber(CurLoc), getColumnNumber(CurLoc), Scope, CurInlinedAt));
}
void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
llvm::MDNode *Back = nullptr;
if (!LexicalBlockStack.empty())
Back = LexicalBlockStack.back().get();
LexicalBlockStack.emplace_back(DBuilder.createLexicalBlock(
cast<llvm::DIScope>(Back), getOrCreateFile(CurLoc), getLineNumber(CurLoc),
getColumnNumber(CurLoc)));
}
void CGDebugInfo::AppendAddressSpaceXDeref(
unsigned AddressSpace, SmallVectorImpl<int64_t> &Expr) const {
Optional<unsigned> DWARFAddressSpace =
CGM.getTarget().getDWARFAddressSpace(AddressSpace);
if (!DWARFAddressSpace)
return;
Expr.push_back(llvm::dwarf::DW_OP_constu);
Expr.push_back(DWARFAddressSpace.getValue());
Expr.push_back(llvm::dwarf::DW_OP_swap);
Expr.push_back(llvm::dwarf::DW_OP_xderef);
}
void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder,
SourceLocation Loc) {
// Set our current location.
setLocation(Loc);
// Emit a line table change for the current location inside the new scope.
Builder.SetCurrentDebugLocation(
llvm::DebugLoc::get(getLineNumber(Loc), getColumnNumber(Loc),
LexicalBlockStack.back(), CurInlinedAt));
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
return;
// Create a new lexical block and push it on the stack.
CreateLexicalBlock(Loc);
}
void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder,
SourceLocation Loc) {
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
// Provide an entry in the line table for the end of the block.
EmitLocation(Builder, Loc);
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
return;
LexicalBlockStack.pop_back();
}
void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn) {
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
unsigned RCount = FnBeginRegionCount.back();
assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch");
// Pop all regions for this function.
while (LexicalBlockStack.size() != RCount) {
// Provide an entry in the line table for the end of the block.
EmitLocation(Builder, CurLoc);
LexicalBlockStack.pop_back();
}
FnBeginRegionCount.pop_back();
if (Fn && Fn->getSubprogram())
DBuilder.finalizeSubprogram(Fn->getSubprogram());
}
CGDebugInfo::BlockByRefType
CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
uint64_t *XOffset) {
SmallVector<llvm::Metadata *, 5> EltTys;
QualType FType;
uint64_t FieldSize, FieldOffset;
uint32_t FieldAlign;
llvm::DIFile *Unit = getOrCreateFile(VD->getLocation());
QualType Type = VD->getType();
FieldOffset = 0;
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset));
EltTys.push_back(CreateMemberType(Unit, FType, "__forwarding", &FieldOffset));
FType = CGM.getContext().IntTy;
EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset));
bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type, VD);
if (HasCopyAndDispose) {
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
EltTys.push_back(
CreateMemberType(Unit, FType, "__copy_helper", &FieldOffset));
EltTys.push_back(
CreateMemberType(Unit, FType, "__destroy_helper", &FieldOffset));
}
bool HasByrefExtendedLayout;
Qualifiers::ObjCLifetime Lifetime;
if (CGM.getContext().getByrefLifetime(Type, Lifetime,
HasByrefExtendedLayout) &&
HasByrefExtendedLayout) {
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
EltTys.push_back(
CreateMemberType(Unit, FType, "__byref_variable_layout", &FieldOffset));
}
CharUnits Align = CGM.getContext().getDeclAlign(VD);
if (Align > CGM.getContext().toCharUnitsFromBits(
CGM.getTarget().getPointerAlign(0))) {
CharUnits FieldOffsetInBytes =
CGM.getContext().toCharUnitsFromBits(FieldOffset);
CharUnits AlignedOffsetInBytes = FieldOffsetInBytes.alignTo(Align);
CharUnits NumPaddingBytes = AlignedOffsetInBytes - FieldOffsetInBytes;
if (NumPaddingBytes.isPositive()) {
llvm::APInt pad(32, NumPaddingBytes.getQuantity());
FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
pad, ArrayType::Normal, 0);
EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset));
}
}
FType = Type;
llvm::DIType *WrappedTy = getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().toBits(Align);
*XOffset = FieldOffset;
llvm::DIType *FieldTy = DBuilder.createMemberType(
Unit, VD->getName(), Unit, 0, FieldSize, FieldAlign, FieldOffset,
llvm::DINode::FlagZero, WrappedTy);
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys);
return {DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0,
llvm::DINode::FlagZero, nullptr, Elements),
WrappedTy};
}
llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD,
llvm::Value *Storage,
llvm::Optional<unsigned> ArgNo,
CGBuilderTy &Builder) {
assert(DebugKind >= codegenoptions::LimitedDebugInfo);
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
if (VD->hasAttr<NoDebugAttr>())
return nullptr;
bool Unwritten =
VD->isImplicit() || (isa<Decl>(VD->getDeclContext()) &&
cast<Decl>(VD->getDeclContext())->isImplicit());
llvm::DIFile *Unit = nullptr;
if (!Unwritten)
Unit = getOrCreateFile(VD->getLocation());
llvm::DIType *Ty;
uint64_t XOffset = 0;
if (VD->hasAttr<BlocksAttr>())
Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset).WrappedType;
else
Ty = getOrCreateType(VD->getType(), Unit);
// If there is no debug info for this type then do not emit debug info
// for this variable.
if (!Ty)
return nullptr;
// Get location information.
unsigned Line = 0;
unsigned Column = 0;
if (!Unwritten) {
Line = getLineNumber(VD->getLocation());
Column = getColumnNumber(VD->getLocation());
}
SmallVector<int64_t, 13> Expr;
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
if (VD->isImplicit())
Flags |= llvm::DINode::FlagArtificial;
auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(VD->getType());
AppendAddressSpaceXDeref(AddressSpace, Expr);
// If this is implicit parameter of CXXThis or ObjCSelf kind, then give it an
// object pointer flag.
if (const auto *IPD = dyn_cast<ImplicitParamDecl>(VD)) {
if (IPD->getParameterKind() == ImplicitParamDecl::CXXThis ||
IPD->getParameterKind() == ImplicitParamDecl::ObjCSelf)
Flags |= llvm::DINode::FlagObjectPointer;
}
// Note: Older versions of clang used to emit byval references with an extra
// DW_OP_deref, because they referenced the IR arg directly instead of
// referencing an alloca. Newer versions of LLVM don't treat allocas
// differently from other function arguments when used in a dbg.declare.
auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back());
StringRef Name = VD->getName();
if (!Name.empty()) {
if (VD->hasAttr<BlocksAttr>()) {
// Here, we need an offset *into* the alloca.
CharUnits offset = CharUnits::fromQuantity(32);
Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of __forwarding field
offset = CGM.getContext().toCharUnitsFromBits(
CGM.getTarget().getPointerWidth(0));
Expr.push_back(offset.getQuantity());
Expr.push_back(llvm::dwarf::DW_OP_deref);
Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of x field
offset = CGM.getContext().toCharUnitsFromBits(XOffset);
Expr.push_back(offset.getQuantity());
}
} else if (const auto *RT = dyn_cast<RecordType>(VD->getType())) {
// If VD is an anonymous union then Storage represents value for
// all union fields.
const RecordDecl *RD = RT->getDecl();
if (RD->isUnion() && RD->isAnonymousStructOrUnion()) {
// GDB has trouble finding local variables in anonymous unions, so we emit
// artificial local variables for each of the members.
//
// FIXME: Remove this code as soon as GDB supports this.
// The debug info verifier in LLVM operates based on the assumption that a
// variable has the same size as its storage and we had to disable the
// check for artificial variables.
for (const auto *Field : RD->fields()) {
llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit);
StringRef FieldName = Field->getName();
// Ignore unnamed fields. Do not ignore unnamed records.
if (FieldName.empty() && !isa<RecordType>(Field->getType()))
continue;
// Use VarDecl's Tag, Scope and Line number.
auto FieldAlign = getDeclAlignIfRequired(Field, CGM.getContext());
auto *D = DBuilder.createAutoVariable(
Scope, FieldName, Unit, Line, FieldTy, CGM.getLangOpts().Optimize,
Flags | llvm::DINode::FlagArtificial, FieldAlign);
// Insert an llvm.dbg.declare into the current block.
DBuilder.insertDeclare(
Storage, D, DBuilder.createExpression(Expr),
llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt),
Builder.GetInsertBlock());
}
}
}
// Create the descriptor for the variable.
auto *D = ArgNo ? DBuilder.createParameterVariable(
Scope, Name, *ArgNo, Unit, Line, Ty,
CGM.getLangOpts().Optimize, Flags)
: DBuilder.createAutoVariable(Scope, Name, Unit, Line, Ty,
CGM.getLangOpts().Optimize,
Flags, Align);
// Insert an llvm.dbg.declare into the current block.
DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr),
llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt),
Builder.GetInsertBlock());
return D;
}
llvm::DILocalVariable *
CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage,
CGBuilderTy &Builder) {
assert(DebugKind >= codegenoptions::LimitedDebugInfo);
return EmitDeclare(VD, Storage, llvm::None, Builder);
}
llvm::DIType *CGDebugInfo::CreateSelfType(const QualType &QualTy,
llvm::DIType *Ty) {
llvm::DIType *CachedTy = getTypeOrNull(QualTy);
if (CachedTy)
Ty = CachedTy;
return DBuilder.createObjectPointerType(Ty);
}
void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder,
const CGBlockInfo &blockInfo, llvm::Instruction *InsertPoint) {
assert(DebugKind >= codegenoptions::LimitedDebugInfo);
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
if (Builder.GetInsertBlock() == nullptr)
return;
if (VD->hasAttr<NoDebugAttr>())
return;
bool isByRef = VD->hasAttr<BlocksAttr>();
uint64_t XOffset = 0;
llvm::DIFile *Unit = getOrCreateFile(VD->getLocation());
llvm::DIType *Ty;
if (isByRef)
Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset).WrappedType;
else
Ty = getOrCreateType(VD->getType(), Unit);
// Self is passed along as an implicit non-arg variable in a
// block. Mark it as the object pointer.
if (const auto *IPD = dyn_cast<ImplicitParamDecl>(VD))
if (IPD->getParameterKind() == ImplicitParamDecl::ObjCSelf)
Ty = CreateSelfType(VD->getType(), Ty);
// Get location information.
unsigned Line = getLineNumber(VD->getLocation());
unsigned Column = getColumnNumber(VD->getLocation());
const llvm::DataLayout &target = CGM.getDataLayout();
CharUnits offset = CharUnits::fromQuantity(
target.getStructLayout(blockInfo.StructureType)
->getElementOffset(blockInfo.getCapture(VD).getIndex()));
SmallVector<int64_t, 9> addr;
addr.push_back(llvm::dwarf::DW_OP_deref);
addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
addr.push_back(offset.getQuantity());
if (isByRef) {
addr.push_back(llvm::dwarf::DW_OP_deref);
addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of __forwarding field
offset =
CGM.getContext().toCharUnitsFromBits(target.getPointerSizeInBits(0));
addr.push_back(offset.getQuantity());
addr.push_back(llvm::dwarf::DW_OP_deref);
addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of x field
offset = CGM.getContext().toCharUnitsFromBits(XOffset);
addr.push_back(offset.getQuantity());
}
// Create the descriptor for the variable.
auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
auto *D = DBuilder.createAutoVariable(
cast<llvm::DILocalScope>(LexicalBlockStack.back()), VD->getName(), Unit,
Line, Ty, false, llvm::DINode::FlagZero, Align);
// Insert an llvm.dbg.declare into the current block.
auto DL =
llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back(), CurInlinedAt);
auto *Expr = DBuilder.createExpression(addr);
if (InsertPoint)
DBuilder.insertDeclare(Storage, D, Expr, DL, InsertPoint);
else
DBuilder.insertDeclare(Storage, D, Expr, DL, Builder.GetInsertBlock());
}
void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
unsigned ArgNo,
CGBuilderTy &Builder) {
assert(DebugKind >= codegenoptions::LimitedDebugInfo);
EmitDeclare(VD, AI, ArgNo, Builder);
}
namespace {
struct BlockLayoutChunk {
uint64_t OffsetInBits;
const BlockDecl::Capture *Capture;
};
bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) {
return l.OffsetInBits < r.OffsetInBits;
}
} // namespace
void CGDebugInfo::collectDefaultFieldsForBlockLiteralDeclare(
const CGBlockInfo &Block, const ASTContext &Context, SourceLocation Loc,
const llvm::StructLayout &BlockLayout, llvm::DIFile *Unit,
SmallVectorImpl<llvm::Metadata *> &Fields) {
// Blocks in OpenCL have unique constraints which make the standard fields
// redundant while requiring size and align fields for enqueue_kernel. See
// initializeForBlockHeader in CGBlocks.cpp
if (CGM.getLangOpts().OpenCL) {
Fields.push_back(createFieldType("__size", Context.IntTy, Loc, AS_public,
BlockLayout.getElementOffsetInBits(0),
Unit, Unit));
Fields.push_back(createFieldType("__align", Context.IntTy, Loc, AS_public,
BlockLayout.getElementOffsetInBits(1),
Unit, Unit));
} else {
Fields.push_back(createFieldType("__isa", Context.VoidPtrTy, Loc, AS_public,
BlockLayout.getElementOffsetInBits(0),
Unit, Unit));
Fields.push_back(createFieldType("__flags", Context.IntTy, Loc, AS_public,
BlockLayout.getElementOffsetInBits(1),
Unit, Unit));
Fields.push_back(
createFieldType("__reserved", Context.IntTy, Loc, AS_public,
BlockLayout.getElementOffsetInBits(2), Unit, Unit));
auto *FnTy = Block.getBlockExpr()->getFunctionType();
auto FnPtrType = CGM.getContext().getPointerType(FnTy->desugar());
Fields.push_back(createFieldType("__FuncPtr", FnPtrType, Loc, AS_public,
BlockLayout.getElementOffsetInBits(3),
Unit, Unit));
Fields.push_back(createFieldType(
"__descriptor",
Context.getPointerType(Block.NeedsCopyDispose
? Context.getBlockDescriptorExtendedType()
: Context.getBlockDescriptorType()),
Loc, AS_public, BlockLayout.getElementOffsetInBits(4), Unit, Unit));
}
}
void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
StringRef Name,
unsigned ArgNo,
llvm::AllocaInst *Alloca,
CGBuilderTy &Builder) {
assert(DebugKind >= codegenoptions::LimitedDebugInfo);
ASTContext &C = CGM.getContext();
const BlockDecl *blockDecl = block.getBlockDecl();
// Collect some general information about the block's location.
SourceLocation loc = blockDecl->getCaretLocation();
llvm::DIFile *tunit = getOrCreateFile(loc);
unsigned line = getLineNumber(loc);
unsigned column = getColumnNumber(loc);
// Build the debug-info type for the block literal.
getDeclContextDescriptor(blockDecl);
const llvm::StructLayout *blockLayout =
CGM.getDataLayout().getStructLayout(block.StructureType);
SmallVector<llvm::Metadata *, 16> fields;
collectDefaultFieldsForBlockLiteralDeclare(block, C, loc, *blockLayout, tunit,
fields);
// We want to sort the captures by offset, not because DWARF
// requires this, but because we're paranoid about debuggers.
SmallVector<BlockLayoutChunk, 8> chunks;
// 'this' capture.
if (blockDecl->capturesCXXThis()) {
BlockLayoutChunk chunk;
chunk.OffsetInBits =
blockLayout->getElementOffsetInBits(block.CXXThisIndex);
chunk.Capture = nullptr;
chunks.push_back(chunk);
}
// Variable captures.
for (const auto &capture : blockDecl->captures()) {
const VarDecl *variable = capture.getVariable();
const CGBlockInfo::Capture &captureInfo = block.getCapture(variable);
// Ignore constant captures.
if (captureInfo.isConstant())
continue;
BlockLayoutChunk chunk;
chunk.OffsetInBits =
blockLayout->getElementOffsetInBits(captureInfo.getIndex());
chunk.Capture = &capture;
chunks.push_back(chunk);
}
// Sort by offset.
llvm::array_pod_sort(chunks.begin(), chunks.end());
for (const BlockLayoutChunk &Chunk : chunks) {
uint64_t offsetInBits = Chunk.OffsetInBits;
const BlockDecl::Capture *capture = Chunk.Capture;
// If we have a null capture, this must be the C++ 'this' capture.
if (!capture) {
QualType type;
if (auto *Method =
cast_or_null<CXXMethodDecl>(blockDecl->getNonClosureContext()))
type = Method->getThisType();
else if (auto *RDecl = dyn_cast<CXXRecordDecl>(blockDecl->getParent()))
type = QualType(RDecl->getTypeForDecl(), 0);
else
llvm_unreachable("unexpected block declcontext");
fields.push_back(createFieldType("this", type, loc, AS_public,
offsetInBits, tunit, tunit));
continue;
}
const VarDecl *variable = capture->getVariable();
StringRef name = variable->getName();
llvm::DIType *fieldType;
if (capture->isByRef()) {
TypeInfo PtrInfo = C.getTypeInfo(C.VoidPtrTy);
auto Align = PtrInfo.AlignIsRequired ? PtrInfo.Align : 0;
// FIXME: This recomputes the layout of the BlockByRefWrapper.
uint64_t xoffset;
fieldType =
EmitTypeForVarWithBlocksAttr(variable, &xoffset).BlockByRefWrapper;
fieldType = DBuilder.createPointerType(fieldType, PtrInfo.Width);
fieldType = DBuilder.createMemberType(tunit, name, tunit, line,
PtrInfo.Width, Align, offsetInBits,
llvm::DINode::FlagZero, fieldType);
} else {
auto Align = getDeclAlignIfRequired(variable, CGM.getContext());
fieldType = createFieldType(name, variable->getType(), loc, AS_public,
offsetInBits, Align, tunit, tunit);
}
fields.push_back(fieldType);
}
SmallString<36> typeName;
llvm::raw_svector_ostream(typeName)
<< "__block_literal_" << CGM.getUniqueBlockCount();
llvm::DINodeArray fieldsArray = DBuilder.getOrCreateArray(fields);
llvm::DIType *type =
DBuilder.createStructType(tunit, typeName.str(), tunit, line,
CGM.getContext().toBits(block.BlockSize), 0,
llvm::DINode::FlagZero, nullptr, fieldsArray);
type = DBuilder.createPointerType(type, CGM.PointerWidthInBits);
// Get overall information about the block.
llvm::DINode::DIFlags flags = llvm::DINode::FlagArtificial;
auto *scope = cast<llvm::DILocalScope>(LexicalBlockStack.back());
// Create the descriptor for the parameter.
auto *debugVar = DBuilder.createParameterVariable(
scope, Name, ArgNo, tunit, line, type, CGM.getLangOpts().Optimize, flags);
// Insert an llvm.dbg.declare into the current block.
DBuilder.insertDeclare(Alloca, debugVar, DBuilder.createExpression(),
llvm::DebugLoc::get(line, column, scope, CurInlinedAt),
Builder.GetInsertBlock());
}
llvm::DIDerivedType *
CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) {
if (!D->isStaticDataMember())
return nullptr;
auto MI = StaticDataMemberCache.find(D->getCanonicalDecl());
if (MI != StaticDataMemberCache.end()) {
assert(MI->second && "Static data member declaration should still exist");
return MI->second;
}
// If the member wasn't found in the cache, lazily construct and add it to the
// type (used when a limited form of the type is emitted).
auto DC = D->getDeclContext();
auto *Ctxt = cast<llvm::DICompositeType>(getDeclContextDescriptor(D));
return CreateRecordStaticField(D, Ctxt, cast<RecordDecl>(DC));
}
llvm::DIGlobalVariableExpression *CGDebugInfo::CollectAnonRecordDecls(
const RecordDecl *RD, llvm::DIFile *Unit, unsigned LineNo,
StringRef LinkageName, llvm::GlobalVariable *Var, llvm::DIScope *DContext) {
llvm::DIGlobalVariableExpression *GVE = nullptr;
for (const auto *Field : RD->fields()) {
llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit);
StringRef FieldName = Field->getName();
// Ignore unnamed fields, but recurse into anonymous records.
if (FieldName.empty()) {
if (const auto *RT = dyn_cast<RecordType>(Field->getType()))
GVE = CollectAnonRecordDecls(RT->getDecl(), Unit, LineNo, LinkageName,
Var, DContext);
continue;
}
// Use VarDecl's Tag, Scope and Line number.
GVE = DBuilder.createGlobalVariableExpression(
DContext, FieldName, LinkageName, Unit, LineNo, FieldTy,
Var->hasLocalLinkage());
Var->addDebugInfo(GVE);
}
return GVE;
}
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
const VarDecl *D) {
assert(DebugKind >= codegenoptions::LimitedDebugInfo);
if (D->hasAttr<NoDebugAttr>())
return;
// If we already created a DIGlobalVariable for this declaration, just attach
// it to the llvm::GlobalVariable.
auto Cached = DeclCache.find(D->getCanonicalDecl());
if (Cached != DeclCache.end())
return Var->addDebugInfo(
cast<llvm::DIGlobalVariableExpression>(Cached->second));
// Create global variable debug descriptor.
llvm::DIFile *Unit = nullptr;
llvm::DIScope *DContext = nullptr;
unsigned LineNo;
StringRef DeclName, LinkageName;
QualType T;
llvm::MDTuple *TemplateParameters = nullptr;
collectVarDeclProps(D, Unit, LineNo, T, DeclName, LinkageName,
TemplateParameters, DContext);
// Attempt to store one global variable for the declaration - even if we
// emit a lot of fields.
llvm::DIGlobalVariableExpression *GVE = nullptr;
// If this is an anonymous union then we'll want to emit a global
// variable for each member of the anonymous union so that it's possible
// to find the name of any field in the union.
if (T->isUnionType() && DeclName.empty()) {
const RecordDecl *RD = T->castAs<RecordType>()->getDecl();
assert(RD->isAnonymousStructOrUnion() &&
"unnamed non-anonymous struct or union?");
GVE = CollectAnonRecordDecls(RD, Unit, LineNo, LinkageName, Var, DContext);
} else {
auto Align = getDeclAlignIfRequired(D, CGM.getContext());
SmallVector<int64_t, 4> Expr;
unsigned AddressSpace =
CGM.getContext().getTargetAddressSpace(D->getType());
AppendAddressSpaceXDeref(AddressSpace, Expr);
GVE = DBuilder.createGlobalVariableExpression(
DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
Var->hasLocalLinkage(),
Expr.empty() ? nullptr : DBuilder.createExpression(Expr),
getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters,
Align);
Var->addDebugInfo(GVE);
}
DeclCache[D->getCanonicalDecl()].reset(GVE);
}
void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) {
assert(DebugKind >= codegenoptions::LimitedDebugInfo);
if (VD->hasAttr<NoDebugAttr>())
return;
auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
// Create the descriptor for the variable.
llvm::DIFile *Unit = getOrCreateFile(VD->getLocation());
StringRef Name = VD->getName();
llvm::DIType *Ty = getOrCreateType(VD->getType(), Unit);
if (const auto *ECD = dyn_cast<EnumConstantDecl>(VD)) {
const auto *ED = cast<EnumDecl>(ECD->getDeclContext());
assert(isa<EnumType>(ED->getTypeForDecl()) && "Enum without EnumType?");
Ty = getOrCreateType(QualType(ED->getTypeForDecl(), 0), Unit);
}
// Do not use global variables for enums.
//
// FIXME: why not?
if (Ty->getTag() == llvm::dwarf::DW_TAG_enumeration_type)
return;
// Do not emit separate definitions for function local const/statics.
if (isa<FunctionDecl>(VD->getDeclContext()))
return;
VD = cast<ValueDecl>(VD->getCanonicalDecl());
auto *VarD = cast<VarDecl>(VD);
if (VarD->isStaticDataMember()) {
auto *RD = cast<RecordDecl>(VarD->getDeclContext());
getDeclContextDescriptor(VarD);
// Ensure that the type is retained even though it's otherwise unreferenced.
//
// FIXME: This is probably unnecessary, since Ty should reference RD
// through its scope.
RetainedTypes.push_back(
CGM.getContext().getRecordType(RD).getAsOpaquePtr());
return;
}
llvm::DIScope *DContext = getDeclContextDescriptor(VD);
auto &GV = DeclCache[VD];
if (GV)
return;
llvm::DIExpression *InitExpr = nullptr;
if (CGM.getContext().getTypeSize(VD->getType()) <= 64) {
// FIXME: Add a representation for integer constants wider than 64 bits.
if (Init.isInt())
InitExpr =
DBuilder.createConstantValueExpression(Init.getInt().getExtValue());
else if (Init.isFloat())
InitExpr = DBuilder.createConstantValueExpression(
Init.getFloat().bitcastToAPInt().getZExtValue());
}
llvm::MDTuple *TemplateParameters = nullptr;
if (isa<VarTemplateSpecializationDecl>(VD))
if (VarD) {
llvm::DINodeArray parameterNodes = CollectVarTemplateParams(VarD, &*Unit);
TemplateParameters = parameterNodes.get();
}
GV.reset(DBuilder.createGlobalVariableExpression(
DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty,
true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD),
TemplateParameters, Align));
}
llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) {
if (!LexicalBlockStack.empty())
return LexicalBlockStack.back();
llvm::DIScope *Mod = getParentModuleOrNull(D);
return getContextDescriptor(D, Mod ? Mod : TheCU);
}
void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) {
if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
return;
const NamespaceDecl *NSDecl = UD.getNominatedNamespace();
if (!NSDecl->isAnonymousNamespace() ||
CGM.getCodeGenOpts().DebugExplicitImport) {
auto Loc = UD.getLocation();
DBuilder.createImportedModule(
getCurrentContextDescriptor(cast<Decl>(UD.getDeclContext())),
getOrCreateNamespace(NSDecl), getOrCreateFile(Loc), getLineNumber(Loc));
}
}
void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) {
if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
return;
assert(UD.shadow_size() &&
"We shouldn't be codegening an invalid UsingDecl containing no decls");
// Emitting one decl is sufficient - debuggers can detect that this is an
// overloaded name & provide lookup for all the overloads.
const UsingShadowDecl &USD = **UD.shadow_begin();
// FIXME: Skip functions with undeduced auto return type for now since we
// don't currently have the plumbing for separate declarations & definitions
// of free functions and mismatched types (auto in the declaration, concrete
// return type in the definition)
if (const auto *FD = dyn_cast<FunctionDecl>(USD.getUnderlyingDecl()))
if (const auto *AT =
FD->getType()->getAs<FunctionProtoType>()->getContainedAutoType())
if (AT->getDeducedType().isNull())
return;
if (llvm::DINode *Target =
getDeclarationOrDefinition(USD.getUnderlyingDecl())) {
auto Loc = USD.getLocation();
DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(USD.getDeclContext())), Target,
getOrCreateFile(Loc), getLineNumber(Loc));
}
}
void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) {
if (CGM.getCodeGenOpts().getDebuggerTuning() != llvm::DebuggerKind::LLDB)
return;
if (Module *M = ID.getImportedModule()) {
auto Info = ExternalASTSource::ASTSourceDescriptor(*M);
auto Loc = ID.getLocation();
DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(ID.getDeclContext())),
getOrCreateModuleRef(Info, DebugTypeExtRefs), getOrCreateFile(Loc),
getLineNumber(Loc));
}
}
llvm::DIImportedEntity *
CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) {
if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
return nullptr;
auto &VH = NamespaceAliasCache[&NA];
if (VH)
return cast<llvm::DIImportedEntity>(VH);
llvm::DIImportedEntity *R;
auto Loc = NA.getLocation();
if (const auto *Underlying =
dyn_cast<NamespaceAliasDecl>(NA.getAliasedNamespace()))
// This could cache & dedup here rather than relying on metadata deduping.
R = DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
EmitNamespaceAlias(*Underlying), getOrCreateFile(Loc),
getLineNumber(Loc), NA.getName());
else
R = DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
getOrCreateNamespace(cast<NamespaceDecl>(NA.getAliasedNamespace())),
getOrCreateFile(Loc), getLineNumber(Loc), NA.getName());
VH.reset(R);
return R;
}
llvm::DINamespace *
CGDebugInfo::getOrCreateNamespace(const NamespaceDecl *NSDecl) {
// Don't canonicalize the NamespaceDecl here: The DINamespace will be uniqued
// if necessary, and this way multiple declarations of the same namespace in
// different parent modules stay distinct.
auto I = NamespaceCache.find(NSDecl);
if (I != NamespaceCache.end())
return cast<llvm::DINamespace>(I->second);
llvm::DIScope *Context = getDeclContextDescriptor(NSDecl);
// Don't trust the context if it is a DIModule (see comment above).
llvm::DINamespace *NS =
DBuilder.createNameSpace(Context, NSDecl->getName(), NSDecl->isInline());
NamespaceCache[NSDecl].reset(NS);
return NS;
}
void CGDebugInfo::setDwoId(uint64_t Signature) {
assert(TheCU && "no main compile unit");
TheCU->setDWOId(Signature);
}
void CGDebugInfo::finalize() {
// Creating types might create further types - invalidating the current
// element and the size(), so don't cache/reference them.
for (size_t i = 0; i != ObjCInterfaceCache.size(); ++i) {
ObjCInterfaceCacheEntry E = ObjCInterfaceCache[i];
llvm::DIType *Ty = E.Type->getDecl()->getDefinition()
? CreateTypeDefinition(E.Type, E.Unit)
: E.Decl;
DBuilder.replaceTemporary(llvm::TempDIType(E.Decl), Ty);
}
if (CGM.getCodeGenOpts().DwarfVersion >= 5) {
// Add methods to interface.
for (const auto &P : ObjCMethodCache) {
if (P.second.empty())
continue;
QualType QTy(P.first->getTypeForDecl(), 0);
auto It = TypeCache.find(QTy.getAsOpaquePtr());
assert(It != TypeCache.end());
llvm::DICompositeType *InterfaceDecl =
cast<llvm::DICompositeType>(It->second);
SmallVector<llvm::Metadata *, 16> EltTys;
auto CurrenetElts = InterfaceDecl->getElements();
EltTys.append(CurrenetElts.begin(), CurrenetElts.end());
for (auto &MD : P.second)
EltTys.push_back(MD);
llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys);
DBuilder.replaceArrays(InterfaceDecl, Elements);
}
}
for (const auto &P : ReplaceMap) {
assert(P.second);
auto *Ty = cast<llvm::DIType>(P.second);
assert(Ty->isForwardDecl());
auto It = TypeCache.find(P.first);
assert(It != TypeCache.end());
assert(It->second);
DBuilder.replaceTemporary(llvm::TempDIType(Ty),
cast<llvm::DIType>(It->second));
}
for (const auto &P : FwdDeclReplaceMap) {
assert(P.second);
llvm::TempMDNode FwdDecl(cast<llvm::MDNode>(P.second));
llvm::Metadata *Repl;
auto It = DeclCache.find(P.first);
// If there has been no definition for the declaration, call RAUW
// with ourselves, that will destroy the temporary MDNode and
// replace it with a standard one, avoiding leaking memory.
if (It == DeclCache.end())
Repl = P.second;
else
Repl = It->second;
if (auto *GVE = dyn_cast_or_null<llvm::DIGlobalVariableExpression>(Repl))
Repl = GVE->getVariable();
DBuilder.replaceTemporary(std::move(FwdDecl), cast<llvm::MDNode>(Repl));
}
// We keep our own list of retained types, because we need to look
// up the final type in the type cache.
for (auto &RT : RetainedTypes)
if (auto MD = TypeCache[RT])
DBuilder.retainType(cast<llvm::DIType>(MD));
DBuilder.finalize();
}
void CGDebugInfo::EmitExplicitCastType(QualType Ty) {
if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
return;
if (auto *DieTy = getOrCreateType(Ty, TheCU->getFile()))
// Don't ignore in case of explicit cast where it is referenced indirectly.
DBuilder.retainType(DieTy);
}
llvm::DebugLoc CGDebugInfo::SourceLocToDebugLoc(SourceLocation Loc) {
if (LexicalBlockStack.empty())
return llvm::DebugLoc();
llvm::MDNode *Scope = LexicalBlockStack.back();
return llvm::DebugLoc::get(getLineNumber(Loc), getColumnNumber(Loc), Scope);
}
llvm::DINode::DIFlags CGDebugInfo::getCallSiteRelatedAttrs() const {
// Call site-related attributes are only useful in optimized programs, and
// when there's a possibility of debugging backtraces.
if (!CGM.getLangOpts().Optimize || DebugKind == codegenoptions::NoDebugInfo ||
DebugKind == codegenoptions::LocTrackingOnly)
return llvm::DINode::FlagZero;
// Call site-related attributes are available in DWARF v5. Some debuggers,
// while not fully DWARF v5-compliant, may accept these attributes as if they
// were part of DWARF v4.
bool SupportsDWARFv4Ext =
CGM.getCodeGenOpts().DwarfVersion == 4 &&
CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB;
if (!SupportsDWARFv4Ext && CGM.getCodeGenOpts().DwarfVersion < 5)
return llvm::DINode::FlagZero;
return llvm::DINode::FlagAllCallsDescribed;
}
Index: stable/11/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp
===================================================================
--- stable/11/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp (revision 350259)
@@ -1,5080 +1,5081 @@
//===--- CGStmtOpenMP.cpp - Emit LLVM Code from Statements ----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This contains code to emit OpenMP nodes as LLVM code.
//
//===----------------------------------------------------------------------===//
#include "CGCleanup.h"
#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/DeclOpenMP.h"
#include "llvm/IR/CallSite.h"
using namespace clang;
using namespace CodeGen;
namespace {
/// Lexical scope for OpenMP executable constructs, that handles correct codegen
/// for captured expressions.
class OMPLexicalScope : public CodeGenFunction::LexicalScope {
void emitPreInitStmt(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
for (const auto *C : S.clauses()) {
if (const auto *CPI = OMPClauseWithPreInit::get(C)) {
if (const auto *PreInit =
cast_or_null<DeclStmt>(CPI->getPreInitStmt())) {
for (const auto *I : PreInit->decls()) {
if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
CGF.EmitVarDecl(cast<VarDecl>(*I));
} else {
CodeGenFunction::AutoVarEmission Emission =
CGF.EmitAutoVarAlloca(cast<VarDecl>(*I));
CGF.EmitAutoVarCleanups(Emission);
}
}
}
}
}
}
CodeGenFunction::OMPPrivateScope InlinedShareds;
static bool isCapturedVar(CodeGenFunction &CGF, const VarDecl *VD) {
return CGF.LambdaCaptureFields.lookup(VD) ||
(CGF.CapturedStmtInfo && CGF.CapturedStmtInfo->lookup(VD)) ||
(CGF.CurCodeDecl && isa<BlockDecl>(CGF.CurCodeDecl));
}
public:
OMPLexicalScope(
CodeGenFunction &CGF, const OMPExecutableDirective &S,
const llvm::Optional<OpenMPDirectiveKind> CapturedRegion = llvm::None,
const bool EmitPreInitStmt = true)
: CodeGenFunction::LexicalScope(CGF, S.getSourceRange()),
InlinedShareds(CGF) {
if (EmitPreInitStmt)
emitPreInitStmt(CGF, S);
if (!CapturedRegion.hasValue())
return;
assert(S.hasAssociatedStmt() &&
"Expected associated statement for inlined directive.");
const CapturedStmt *CS = S.getCapturedStmt(*CapturedRegion);
for (const auto &C : CS->captures()) {
if (C.capturesVariable() || C.capturesVariableByCopy()) {
auto *VD = C.getCapturedVar();
assert(VD == VD->getCanonicalDecl() &&
"Canonical decl must be captured.");
DeclRefExpr DRE(
CGF.getContext(), const_cast<VarDecl *>(VD),
isCapturedVar(CGF, VD) || (CGF.CapturedStmtInfo &&
InlinedShareds.isGlobalVarCaptured(VD)),
VD->getType().getNonReferenceType(), VK_LValue, C.getLocation());
InlinedShareds.addPrivate(VD, [&CGF, &DRE]() -> Address {
return CGF.EmitLValue(&DRE).getAddress();
});
}
}
(void)InlinedShareds.Privatize();
}
};
/// Lexical scope for OpenMP parallel construct, that handles correct codegen
/// for captured expressions.
class OMPParallelScope final : public OMPLexicalScope {
bool EmitPreInitStmt(const OMPExecutableDirective &S) {
OpenMPDirectiveKind Kind = S.getDirectiveKind();
return !(isOpenMPTargetExecutionDirective(Kind) ||
isOpenMPLoopBoundSharingDirective(Kind)) &&
isOpenMPParallelDirective(Kind);
}
public:
OMPParallelScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
: OMPLexicalScope(CGF, S, /*CapturedRegion=*/llvm::None,
EmitPreInitStmt(S)) {}
};
/// Lexical scope for OpenMP teams construct, that handles correct codegen
/// for captured expressions.
class OMPTeamsScope final : public OMPLexicalScope {
bool EmitPreInitStmt(const OMPExecutableDirective &S) {
OpenMPDirectiveKind Kind = S.getDirectiveKind();
return !isOpenMPTargetExecutionDirective(Kind) &&
isOpenMPTeamsDirective(Kind);
}
public:
OMPTeamsScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
: OMPLexicalScope(CGF, S, /*CapturedRegion=*/llvm::None,
EmitPreInitStmt(S)) {}
};
/// Private scope for OpenMP loop-based directives, that supports capturing
/// of used expression from loop statement.
class OMPLoopScope : public CodeGenFunction::RunCleanupsScope {
void emitPreInitStmt(CodeGenFunction &CGF, const OMPLoopDirective &S) {
CodeGenFunction::OMPMapVars PreCondVars;
for (const auto *E : S.counters()) {
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
(void)PreCondVars.setVarAddr(
CGF, VD, CGF.CreateMemTemp(VD->getType().getNonReferenceType()));
}
(void)PreCondVars.apply(CGF);
if (const auto *PreInits = cast_or_null<DeclStmt>(S.getPreInits())) {
for (const auto *I : PreInits->decls())
CGF.EmitVarDecl(cast<VarDecl>(*I));
}
PreCondVars.restore(CGF);
}
public:
OMPLoopScope(CodeGenFunction &CGF, const OMPLoopDirective &S)
: CodeGenFunction::RunCleanupsScope(CGF) {
emitPreInitStmt(CGF, S);
}
};
class OMPSimdLexicalScope : public CodeGenFunction::LexicalScope {
CodeGenFunction::OMPPrivateScope InlinedShareds;
static bool isCapturedVar(CodeGenFunction &CGF, const VarDecl *VD) {
return CGF.LambdaCaptureFields.lookup(VD) ||
(CGF.CapturedStmtInfo && CGF.CapturedStmtInfo->lookup(VD)) ||
(CGF.CurCodeDecl && isa<BlockDecl>(CGF.CurCodeDecl) &&
cast<BlockDecl>(CGF.CurCodeDecl)->capturesVariable(VD));
}
public:
OMPSimdLexicalScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
: CodeGenFunction::LexicalScope(CGF, S.getSourceRange()),
InlinedShareds(CGF) {
for (const auto *C : S.clauses()) {
if (const auto *CPI = OMPClauseWithPreInit::get(C)) {
if (const auto *PreInit =
cast_or_null<DeclStmt>(CPI->getPreInitStmt())) {
for (const auto *I : PreInit->decls()) {
if (!I->hasAttr<OMPCaptureNoInitAttr>()) {
CGF.EmitVarDecl(cast<VarDecl>(*I));
} else {
CodeGenFunction::AutoVarEmission Emission =
CGF.EmitAutoVarAlloca(cast<VarDecl>(*I));
CGF.EmitAutoVarCleanups(Emission);
}
}
}
} else if (const auto *UDP = dyn_cast<OMPUseDevicePtrClause>(C)) {
for (const Expr *E : UDP->varlists()) {
const Decl *D = cast<DeclRefExpr>(E)->getDecl();
if (const auto *OED = dyn_cast<OMPCapturedExprDecl>(D))
CGF.EmitVarDecl(*OED);
}
}
}
if (!isOpenMPSimdDirective(S.getDirectiveKind()))
CGF.EmitOMPPrivateClause(S, InlinedShareds);
if (const auto *TG = dyn_cast<OMPTaskgroupDirective>(&S)) {
if (const Expr *E = TG->getReductionRef())
CGF.EmitVarDecl(*cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl()));
}
const auto *CS = cast_or_null<CapturedStmt>(S.getAssociatedStmt());
while (CS) {
for (auto &C : CS->captures()) {
if (C.capturesVariable() || C.capturesVariableByCopy()) {
auto *VD = C.getCapturedVar();
assert(VD == VD->getCanonicalDecl() &&
"Canonical decl must be captured.");
DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(VD),
isCapturedVar(CGF, VD) ||
(CGF.CapturedStmtInfo &&
InlinedShareds.isGlobalVarCaptured(VD)),
VD->getType().getNonReferenceType(), VK_LValue,
C.getLocation());
InlinedShareds.addPrivate(VD, [&CGF, &DRE]() -> Address {
return CGF.EmitLValue(&DRE).getAddress();
});
}
}
CS = dyn_cast<CapturedStmt>(CS->getCapturedStmt());
}
(void)InlinedShareds.Privatize();
}
};
} // namespace
static void emitCommonOMPTargetDirective(CodeGenFunction &CGF,
const OMPExecutableDirective &S,
const RegionCodeGenTy &CodeGen);
LValue CodeGenFunction::EmitOMPSharedLValue(const Expr *E) {
if (const auto *OrigDRE = dyn_cast<DeclRefExpr>(E)) {
if (const auto *OrigVD = dyn_cast<VarDecl>(OrigDRE->getDecl())) {
OrigVD = OrigVD->getCanonicalDecl();
bool IsCaptured =
LambdaCaptureFields.lookup(OrigVD) ||
(CapturedStmtInfo && CapturedStmtInfo->lookup(OrigVD)) ||
(CurCodeDecl && isa<BlockDecl>(CurCodeDecl));
DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD), IsCaptured,
OrigDRE->getType(), VK_LValue, OrigDRE->getExprLoc());
return EmitLValue(&DRE);
}
}
return EmitLValue(E);
}
llvm::Value *CodeGenFunction::getTypeSize(QualType Ty) {
ASTContext &C = getContext();
llvm::Value *Size = nullptr;
auto SizeInChars = C.getTypeSizeInChars(Ty);
if (SizeInChars.isZero()) {
// getTypeSizeInChars() returns 0 for a VLA.
while (const VariableArrayType *VAT = C.getAsVariableArrayType(Ty)) {
VlaSizePair VlaSize = getVLASize(VAT);
Ty = VlaSize.Type;
Size = Size ? Builder.CreateNUWMul(Size, VlaSize.NumElts)
: VlaSize.NumElts;
}
SizeInChars = C.getTypeSizeInChars(Ty);
if (SizeInChars.isZero())
return llvm::ConstantInt::get(SizeTy, /*V=*/0);
return Builder.CreateNUWMul(Size, CGM.getSize(SizeInChars));
}
return CGM.getSize(SizeInChars);
}
void CodeGenFunction::GenerateOpenMPCapturedVars(
const CapturedStmt &S, SmallVectorImpl<llvm::Value *> &CapturedVars) {
const RecordDecl *RD = S.getCapturedRecordDecl();
auto CurField = RD->field_begin();
auto CurCap = S.captures().begin();
for (CapturedStmt::const_capture_init_iterator I = S.capture_init_begin(),
E = S.capture_init_end();
I != E; ++I, ++CurField, ++CurCap) {
if (CurField->hasCapturedVLAType()) {
const VariableArrayType *VAT = CurField->getCapturedVLAType();
llvm::Value *Val = VLASizeMap[VAT->getSizeExpr()];
CapturedVars.push_back(Val);
} else if (CurCap->capturesThis()) {
CapturedVars.push_back(CXXThisValue);
} else if (CurCap->capturesVariableByCopy()) {
llvm::Value *CV = EmitLoadOfScalar(EmitLValue(*I), CurCap->getLocation());
// If the field is not a pointer, we need to save the actual value
// and load it as a void pointer.
if (!CurField->getType()->isAnyPointerType()) {
ASTContext &Ctx = getContext();
Address DstAddr = CreateMemTemp(
Ctx.getUIntPtrType(),
Twine(CurCap->getCapturedVar()->getName(), ".casted"));
LValue DstLV = MakeAddrLValue(DstAddr, Ctx.getUIntPtrType());
llvm::Value *SrcAddrVal = EmitScalarConversion(
DstAddr.getPointer(), Ctx.getPointerType(Ctx.getUIntPtrType()),
Ctx.getPointerType(CurField->getType()), CurCap->getLocation());
LValue SrcLV =
MakeNaturalAlignAddrLValue(SrcAddrVal, CurField->getType());
// Store the value using the source type pointer.
EmitStoreThroughLValue(RValue::get(CV), SrcLV);
// Load the value using the destination type pointer.
CV = EmitLoadOfScalar(DstLV, CurCap->getLocation());
}
CapturedVars.push_back(CV);
} else {
assert(CurCap->capturesVariable() && "Expected capture by reference.");
CapturedVars.push_back(EmitLValue(*I).getAddress().getPointer());
}
}
}
static Address castValueFromUintptr(CodeGenFunction &CGF, SourceLocation Loc,
QualType DstType, StringRef Name,
LValue AddrLV,
bool isReferenceType = false) {
ASTContext &Ctx = CGF.getContext();
llvm::Value *CastedPtr = CGF.EmitScalarConversion(
AddrLV.getAddress().getPointer(), Ctx.getUIntPtrType(),
Ctx.getPointerType(DstType), Loc);
Address TmpAddr =
CGF.MakeNaturalAlignAddrLValue(CastedPtr, Ctx.getPointerType(DstType))
.getAddress();
// If we are dealing with references we need to return the address of the
// reference instead of the reference of the value.
if (isReferenceType) {
QualType RefType = Ctx.getLValueReferenceType(DstType);
llvm::Value *RefVal = TmpAddr.getPointer();
TmpAddr = CGF.CreateMemTemp(RefType, Twine(Name, ".ref"));
LValue TmpLVal = CGF.MakeAddrLValue(TmpAddr, RefType);
CGF.EmitStoreThroughLValue(RValue::get(RefVal), TmpLVal, /*isInit=*/true);
}
return TmpAddr;
}
static QualType getCanonicalParamType(ASTContext &C, QualType T) {
if (T->isLValueReferenceType())
return C.getLValueReferenceType(
getCanonicalParamType(C, T.getNonReferenceType()),
/*SpelledAsLValue=*/false);
if (T->isPointerType())
return C.getPointerType(getCanonicalParamType(C, T->getPointeeType()));
if (const ArrayType *A = T->getAsArrayTypeUnsafe()) {
if (const auto *VLA = dyn_cast<VariableArrayType>(A))
return getCanonicalParamType(C, VLA->getElementType());
if (!A->isVariablyModifiedType())
return C.getCanonicalType(T);
}
return C.getCanonicalParamType(T);
}
namespace {
/// Contains required data for proper outlined function codegen.
struct FunctionOptions {
/// Captured statement for which the function is generated.
const CapturedStmt *S = nullptr;
/// true if cast to/from UIntPtr is required for variables captured by
/// value.
const bool UIntPtrCastRequired = true;
/// true if only casted arguments must be registered as local args or VLA
/// sizes.
const bool RegisterCastedArgsOnly = false;
/// Name of the generated function.
const StringRef FunctionName;
explicit FunctionOptions(const CapturedStmt *S, bool UIntPtrCastRequired,
bool RegisterCastedArgsOnly,
StringRef FunctionName)
: S(S), UIntPtrCastRequired(UIntPtrCastRequired),
RegisterCastedArgsOnly(UIntPtrCastRequired && RegisterCastedArgsOnly),
FunctionName(FunctionName) {}
};
}
static llvm::Function *emitOutlinedFunctionPrologue(
CodeGenFunction &CGF, FunctionArgList &Args,
llvm::MapVector<const Decl *, std::pair<const VarDecl *, Address>>
&LocalAddrs,
llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>>
&VLASizes,
llvm::Value *&CXXThisValue, const FunctionOptions &FO) {
const CapturedDecl *CD = FO.S->getCapturedDecl();
const RecordDecl *RD = FO.S->getCapturedRecordDecl();
assert(CD->hasBody() && "missing CapturedDecl body");
CXXThisValue = nullptr;
// Build the argument list.
CodeGenModule &CGM = CGF.CGM;
ASTContext &Ctx = CGM.getContext();
FunctionArgList TargetArgs;
Args.append(CD->param_begin(),
std::next(CD->param_begin(), CD->getContextParamPosition()));
TargetArgs.append(
CD->param_begin(),
std::next(CD->param_begin(), CD->getContextParamPosition()));
auto I = FO.S->captures().begin();
FunctionDecl *DebugFunctionDecl = nullptr;
if (!FO.UIntPtrCastRequired) {
FunctionProtoType::ExtProtoInfo EPI;
QualType FunctionTy = Ctx.getFunctionType(Ctx.VoidTy, llvm::None, EPI);
DebugFunctionDecl = FunctionDecl::Create(
Ctx, Ctx.getTranslationUnitDecl(), FO.S->getBeginLoc(),
SourceLocation(), DeclarationName(), FunctionTy,
Ctx.getTrivialTypeSourceInfo(FunctionTy), SC_Static,
/*isInlineSpecified=*/false, /*hasWrittenPrototype=*/false);
}
for (const FieldDecl *FD : RD->fields()) {
QualType ArgType = FD->getType();
IdentifierInfo *II = nullptr;
VarDecl *CapVar = nullptr;
// If this is a capture by copy and the type is not a pointer, the outlined
// function argument type should be uintptr and the value properly casted to
// uintptr. This is necessary given that the runtime library is only able to
// deal with pointers. We can pass in the same way the VLA type sizes to the
// outlined function.
if (FO.UIntPtrCastRequired &&
((I->capturesVariableByCopy() && !ArgType->isAnyPointerType()) ||
I->capturesVariableArrayType()))
ArgType = Ctx.getUIntPtrType();
if (I->capturesVariable() || I->capturesVariableByCopy()) {
CapVar = I->getCapturedVar();
II = CapVar->getIdentifier();
} else if (I->capturesThis()) {
II = &Ctx.Idents.get("this");
} else {
assert(I->capturesVariableArrayType());
II = &Ctx.Idents.get("vla");
}
if (ArgType->isVariablyModifiedType())
ArgType = getCanonicalParamType(Ctx, ArgType);
VarDecl *Arg;
if (DebugFunctionDecl && (CapVar || I->capturesThis())) {
Arg = ParmVarDecl::Create(
Ctx, DebugFunctionDecl,
CapVar ? CapVar->getBeginLoc() : FD->getBeginLoc(),
CapVar ? CapVar->getLocation() : FD->getLocation(), II, ArgType,
/*TInfo=*/nullptr, SC_None, /*DefArg=*/nullptr);
} else {
Arg = ImplicitParamDecl::Create(Ctx, /*DC=*/nullptr, FD->getLocation(),
II, ArgType, ImplicitParamDecl::Other);
}
Args.emplace_back(Arg);
// Do not cast arguments if we emit function with non-original types.
TargetArgs.emplace_back(
FO.UIntPtrCastRequired
? Arg
: CGM.getOpenMPRuntime().translateParameter(FD, Arg));
++I;
}
Args.append(
std::next(CD->param_begin(), CD->getContextParamPosition() + 1),
CD->param_end());
TargetArgs.append(
std::next(CD->param_begin(), CD->getContextParamPosition() + 1),
CD->param_end());
// Create the function declaration.
const CGFunctionInfo &FuncInfo =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, TargetArgs);
llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo);
auto *F =
llvm::Function::Create(FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
FO.FunctionName, &CGM.getModule());
CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
if (CD->isNothrow())
F->setDoesNotThrow();
F->setDoesNotRecurse();
// Generate the function.
CGF.StartFunction(CD, Ctx.VoidTy, F, FuncInfo, TargetArgs,
FO.S->getBeginLoc(), CD->getBody()->getBeginLoc());
unsigned Cnt = CD->getContextParamPosition();
I = FO.S->captures().begin();
for (const FieldDecl *FD : RD->fields()) {
// Do not map arguments if we emit function with non-original types.
Address LocalAddr(Address::invalid());
if (!FO.UIntPtrCastRequired && Args[Cnt] != TargetArgs[Cnt]) {
LocalAddr = CGM.getOpenMPRuntime().getParameterAddress(CGF, Args[Cnt],
TargetArgs[Cnt]);
} else {
LocalAddr = CGF.GetAddrOfLocalVar(Args[Cnt]);
}
// If we are capturing a pointer by copy we don't need to do anything, just
// use the value that we get from the arguments.
if (I->capturesVariableByCopy() && FD->getType()->isAnyPointerType()) {
const VarDecl *CurVD = I->getCapturedVar();
// If the variable is a reference we need to materialize it here.
if (CurVD->getType()->isReferenceType()) {
Address RefAddr = CGF.CreateMemTemp(
CurVD->getType(), CGM.getPointerAlign(), ".materialized_ref");
CGF.EmitStoreOfScalar(LocalAddr.getPointer(), RefAddr,
/*Volatile=*/false, CurVD->getType());
LocalAddr = RefAddr;
}
if (!FO.RegisterCastedArgsOnly)
LocalAddrs.insert({Args[Cnt], {CurVD, LocalAddr}});
++Cnt;
++I;
continue;
}
LValue ArgLVal = CGF.MakeAddrLValue(LocalAddr, Args[Cnt]->getType(),
AlignmentSource::Decl);
if (FD->hasCapturedVLAType()) {
if (FO.UIntPtrCastRequired) {
ArgLVal = CGF.MakeAddrLValue(
castValueFromUintptr(CGF, I->getLocation(), FD->getType(),
Args[Cnt]->getName(), ArgLVal),
FD->getType(), AlignmentSource::Decl);
}
llvm::Value *ExprArg = CGF.EmitLoadOfScalar(ArgLVal, I->getLocation());
const VariableArrayType *VAT = FD->getCapturedVLAType();
VLASizes.try_emplace(Args[Cnt], VAT->getSizeExpr(), ExprArg);
} else if (I->capturesVariable()) {
const VarDecl *Var = I->getCapturedVar();
QualType VarTy = Var->getType();
Address ArgAddr = ArgLVal.getAddress();
if (!VarTy->isReferenceType()) {
if (ArgLVal.getType()->isLValueReferenceType()) {
ArgAddr = CGF.EmitLoadOfReference(ArgLVal);
} else if (!VarTy->isVariablyModifiedType() ||
!VarTy->isPointerType()) {
assert(ArgLVal.getType()->isPointerType());
ArgAddr = CGF.EmitLoadOfPointer(
ArgAddr, ArgLVal.getType()->castAs<PointerType>());
}
}
if (!FO.RegisterCastedArgsOnly) {
LocalAddrs.insert(
{Args[Cnt],
{Var, Address(ArgAddr.getPointer(), Ctx.getDeclAlign(Var))}});
}
} else if (I->capturesVariableByCopy()) {
assert(!FD->getType()->isAnyPointerType() &&
"Not expecting a captured pointer.");
const VarDecl *Var = I->getCapturedVar();
QualType VarTy = Var->getType();
LocalAddrs.insert(
{Args[Cnt],
{Var, FO.UIntPtrCastRequired
? castValueFromUintptr(CGF, I->getLocation(),
FD->getType(), Args[Cnt]->getName(),
ArgLVal, VarTy->isReferenceType())
: ArgLVal.getAddress()}});
} else {
// If 'this' is captured, load it into CXXThisValue.
assert(I->capturesThis());
CXXThisValue = CGF.EmitLoadOfScalar(ArgLVal, I->getLocation());
LocalAddrs.insert({Args[Cnt], {nullptr, ArgLVal.getAddress()}});
}
++Cnt;
++I;
}
return F;
}
llvm::Function *
CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
assert(
CapturedStmtInfo &&
"CapturedStmtInfo should be set when generating the captured function");
const CapturedDecl *CD = S.getCapturedDecl();
// Build the argument list.
bool NeedWrapperFunction =
getDebugInfo() &&
CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo;
FunctionArgList Args;
llvm::MapVector<const Decl *, std::pair<const VarDecl *, Address>> LocalAddrs;
llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>> VLASizes;
SmallString<256> Buffer;
llvm::raw_svector_ostream Out(Buffer);
Out << CapturedStmtInfo->getHelperName();
if (NeedWrapperFunction)
Out << "_debug__";
FunctionOptions FO(&S, !NeedWrapperFunction, /*RegisterCastedArgsOnly=*/false,
Out.str());
llvm::Function *F = emitOutlinedFunctionPrologue(*this, Args, LocalAddrs,
VLASizes, CXXThisValue, FO);
for (const auto &LocalAddrPair : LocalAddrs) {
if (LocalAddrPair.second.first) {
setAddrOfLocalVar(LocalAddrPair.second.first,
LocalAddrPair.second.second);
}
}
for (const auto &VLASizePair : VLASizes)
VLASizeMap[VLASizePair.second.first] = VLASizePair.second.second;
PGO.assignRegionCounters(GlobalDecl(CD), F);
CapturedStmtInfo->EmitBody(*this, CD->getBody());
FinishFunction(CD->getBodyRBrace());
if (!NeedWrapperFunction)
return F;
FunctionOptions WrapperFO(&S, /*UIntPtrCastRequired=*/true,
/*RegisterCastedArgsOnly=*/true,
CapturedStmtInfo->getHelperName());
CodeGenFunction WrapperCGF(CGM, /*suppressNewContext=*/true);
WrapperCGF.CapturedStmtInfo = CapturedStmtInfo;
Args.clear();
LocalAddrs.clear();
VLASizes.clear();
llvm::Function *WrapperF =
emitOutlinedFunctionPrologue(WrapperCGF, Args, LocalAddrs, VLASizes,
WrapperCGF.CXXThisValue, WrapperFO);
llvm::SmallVector<llvm::Value *, 4> CallArgs;
for (const auto *Arg : Args) {
llvm::Value *CallArg;
auto I = LocalAddrs.find(Arg);
if (I != LocalAddrs.end()) {
LValue LV = WrapperCGF.MakeAddrLValue(
I->second.second,
I->second.first ? I->second.first->getType() : Arg->getType(),
AlignmentSource::Decl);
CallArg = WrapperCGF.EmitLoadOfScalar(LV, S.getBeginLoc());
} else {
auto EI = VLASizes.find(Arg);
if (EI != VLASizes.end()) {
CallArg = EI->second.second;
} else {
LValue LV = WrapperCGF.MakeAddrLValue(WrapperCGF.GetAddrOfLocalVar(Arg),
Arg->getType(),
AlignmentSource::Decl);
CallArg = WrapperCGF.EmitLoadOfScalar(LV, S.getBeginLoc());
}
}
CallArgs.emplace_back(WrapperCGF.EmitFromMemory(CallArg, Arg->getType()));
}
CGM.getOpenMPRuntime().emitOutlinedFunctionCall(WrapperCGF, S.getBeginLoc(),
F, CallArgs);
WrapperCGF.FinishFunction();
return WrapperF;
}
//===----------------------------------------------------------------------===//
// OpenMP Directive Emission
//===----------------------------------------------------------------------===//
void CodeGenFunction::EmitOMPAggregateAssign(
Address DestAddr, Address SrcAddr, QualType OriginalType,
const llvm::function_ref<void(Address, Address)> CopyGen) {
// Perform element-by-element initialization.
QualType ElementTy;
// Drill down to the base element type on both arrays.
const ArrayType *ArrayTy = OriginalType->getAsArrayTypeUnsafe();
llvm::Value *NumElements = emitArrayLength(ArrayTy, ElementTy, DestAddr);
SrcAddr = Builder.CreateElementBitCast(SrcAddr, DestAddr.getElementType());
llvm::Value *SrcBegin = SrcAddr.getPointer();
llvm::Value *DestBegin = DestAddr.getPointer();
// Cast from pointer to array type to pointer to single element.
llvm::Value *DestEnd = Builder.CreateGEP(DestBegin, NumElements);
// The basic structure here is a while-do loop.
llvm::BasicBlock *BodyBB = createBasicBlock("omp.arraycpy.body");
llvm::BasicBlock *DoneBB = createBasicBlock("omp.arraycpy.done");
llvm::Value *IsEmpty =
Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty");
Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
// Enter the loop body, making that address the current address.
llvm::BasicBlock *EntryBB = Builder.GetInsertBlock();
EmitBlock(BodyBB);
CharUnits ElementSize = getContext().getTypeSizeInChars(ElementTy);
llvm::PHINode *SrcElementPHI =
Builder.CreatePHI(SrcBegin->getType(), 2, "omp.arraycpy.srcElementPast");
SrcElementPHI->addIncoming(SrcBegin, EntryBB);
Address SrcElementCurrent =
Address(SrcElementPHI,
SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize));
llvm::PHINode *DestElementPHI =
Builder.CreatePHI(DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
DestElementPHI->addIncoming(DestBegin, EntryBB);
Address DestElementCurrent =
Address(DestElementPHI,
DestAddr.getAlignment().alignmentOfArrayElement(ElementSize));
// Emit copy.
CopyGen(DestElementCurrent, SrcElementCurrent);
// Shift the address forward by one element.
llvm::Value *DestElementNext = Builder.CreateConstGEP1_32(
DestElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
llvm::Value *SrcElementNext = Builder.CreateConstGEP1_32(
SrcElementPHI, /*Idx0=*/1, "omp.arraycpy.src.element");
// Check whether we've reached the end.
llvm::Value *Done =
Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
Builder.CreateCondBr(Done, DoneBB, BodyBB);
DestElementPHI->addIncoming(DestElementNext, Builder.GetInsertBlock());
SrcElementPHI->addIncoming(SrcElementNext, Builder.GetInsertBlock());
// Done.
EmitBlock(DoneBB, /*IsFinished=*/true);
}
void CodeGenFunction::EmitOMPCopy(QualType OriginalType, Address DestAddr,
Address SrcAddr, const VarDecl *DestVD,
const VarDecl *SrcVD, const Expr *Copy) {
if (OriginalType->isArrayType()) {
const auto *BO = dyn_cast<BinaryOperator>(Copy);
if (BO && BO->getOpcode() == BO_Assign) {
// Perform simple memcpy for simple copying.
LValue Dest = MakeAddrLValue(DestAddr, OriginalType);
LValue Src = MakeAddrLValue(SrcAddr, OriginalType);
EmitAggregateAssign(Dest, Src, OriginalType);
} else {
// For arrays with complex element types perform element by element
// copying.
EmitOMPAggregateAssign(
DestAddr, SrcAddr, OriginalType,
[this, Copy, SrcVD, DestVD](Address DestElement, Address SrcElement) {
// Working with the single array element, so have to remap
// destination and source variables to corresponding array
// elements.
CodeGenFunction::OMPPrivateScope Remap(*this);
Remap.addPrivate(DestVD, [DestElement]() { return DestElement; });
Remap.addPrivate(SrcVD, [SrcElement]() { return SrcElement; });
(void)Remap.Privatize();
EmitIgnoredExpr(Copy);
});
}
} else {
// Remap pseudo source variable to private copy.
CodeGenFunction::OMPPrivateScope Remap(*this);
Remap.addPrivate(SrcVD, [SrcAddr]() { return SrcAddr; });
Remap.addPrivate(DestVD, [DestAddr]() { return DestAddr; });
(void)Remap.Privatize();
// Emit copying of the whole variable.
EmitIgnoredExpr(Copy);
}
}
bool CodeGenFunction::EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
OMPPrivateScope &PrivateScope) {
if (!HaveInsertPoint())
return false;
bool FirstprivateIsLastprivate = false;
llvm::DenseSet<const VarDecl *> Lastprivates;
for (const auto *C : D.getClausesOfKind<OMPLastprivateClause>()) {
for (const auto *D : C->varlists())
Lastprivates.insert(
cast<VarDecl>(cast<DeclRefExpr>(D)->getDecl())->getCanonicalDecl());
}
llvm::DenseSet<const VarDecl *> EmittedAsFirstprivate;
llvm::SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
getOpenMPCaptureRegions(CaptureRegions, D.getDirectiveKind());
// Force emission of the firstprivate copy if the directive does not emit
// outlined function, like omp for, omp simd, omp distribute etc.
bool MustEmitFirstprivateCopy =
CaptureRegions.size() == 1 && CaptureRegions.back() == OMPD_unknown;
for (const auto *C : D.getClausesOfKind<OMPFirstprivateClause>()) {
auto IRef = C->varlist_begin();
auto InitsRef = C->inits().begin();
for (const Expr *IInit : C->private_copies()) {
const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
bool ThisFirstprivateIsLastprivate =
Lastprivates.count(OrigVD->getCanonicalDecl()) > 0;
const FieldDecl *FD = CapturedStmtInfo->lookup(OrigVD);
if (!MustEmitFirstprivateCopy && !ThisFirstprivateIsLastprivate && FD &&
!FD->getType()->isReferenceType()) {
EmittedAsFirstprivate.insert(OrigVD->getCanonicalDecl());
++IRef;
++InitsRef;
continue;
}
FirstprivateIsLastprivate =
FirstprivateIsLastprivate || ThisFirstprivateIsLastprivate;
if (EmittedAsFirstprivate.insert(OrigVD->getCanonicalDecl()).second) {
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
const auto *VDInit =
cast<VarDecl>(cast<DeclRefExpr>(*InitsRef)->getDecl());
bool IsRegistered;
DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
/*RefersToEnclosingVariableOrCapture=*/FD != nullptr,
(*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
LValue OriginalLVal = EmitLValue(&DRE);
QualType Type = VD->getType();
if (Type->isArrayType()) {
// Emit VarDecl with copy init for arrays.
// Get the address of the original variable captured in current
// captured region.
IsRegistered = PrivateScope.addPrivate(
OrigVD, [this, VD, Type, OriginalLVal, VDInit]() {
AutoVarEmission Emission = EmitAutoVarAlloca(*VD);
const Expr *Init = VD->getInit();
if (!isa<CXXConstructExpr>(Init) ||
isTrivialInitializer(Init)) {
// Perform simple memcpy.
LValue Dest =
MakeAddrLValue(Emission.getAllocatedAddress(), Type);
EmitAggregateAssign(Dest, OriginalLVal, Type);
} else {
EmitOMPAggregateAssign(
Emission.getAllocatedAddress(), OriginalLVal.getAddress(),
Type,
[this, VDInit, Init](Address DestElement,
Address SrcElement) {
// Clean up any temporaries needed by the
// initialization.
RunCleanupsScope InitScope(*this);
// Emit initialization for single element.
setAddrOfLocalVar(VDInit, SrcElement);
EmitAnyExprToMem(Init, DestElement,
Init->getType().getQualifiers(),
/*IsInitializer*/ false);
LocalDeclMap.erase(VDInit);
});
}
EmitAutoVarCleanups(Emission);
return Emission.getAllocatedAddress();
});
} else {
Address OriginalAddr = OriginalLVal.getAddress();
IsRegistered = PrivateScope.addPrivate(
OrigVD, [this, VDInit, OriginalAddr, VD]() {
// Emit private VarDecl with copy init.
// Remap temp VDInit variable to the address of the original
// variable (for proper handling of captured global variables).
setAddrOfLocalVar(VDInit, OriginalAddr);
EmitDecl(*VD);
LocalDeclMap.erase(VDInit);
return GetAddrOfLocalVar(VD);
});
}
assert(IsRegistered &&
"firstprivate var already registered as private");
// Silence the warning about unused variable.
(void)IsRegistered;
}
++IRef;
++InitsRef;
}
}
return FirstprivateIsLastprivate && !EmittedAsFirstprivate.empty();
}
void CodeGenFunction::EmitOMPPrivateClause(
const OMPExecutableDirective &D,
CodeGenFunction::OMPPrivateScope &PrivateScope) {
if (!HaveInsertPoint())
return;
llvm::DenseSet<const VarDecl *> EmittedAsPrivate;
for (const auto *C : D.getClausesOfKind<OMPPrivateClause>()) {
auto IRef = C->varlist_begin();
for (const Expr *IInit : C->private_copies()) {
const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
bool IsRegistered = PrivateScope.addPrivate(OrigVD, [this, VD]() {
// Emit private VarDecl with copy init.
EmitDecl(*VD);
return GetAddrOfLocalVar(VD);
});
assert(IsRegistered && "private var already registered as private");
// Silence the warning about unused variable.
(void)IsRegistered;
}
++IRef;
}
}
}
bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) {
if (!HaveInsertPoint())
return false;
// threadprivate_var1 = master_threadprivate_var1;
// operator=(threadprivate_var2, master_threadprivate_var2);
// ...
// __kmpc_barrier(&loc, global_tid);
llvm::DenseSet<const VarDecl *> CopiedVars;
llvm::BasicBlock *CopyBegin = nullptr, *CopyEnd = nullptr;
for (const auto *C : D.getClausesOfKind<OMPCopyinClause>()) {
auto IRef = C->varlist_begin();
auto ISrcRef = C->source_exprs().begin();
auto IDestRef = C->destination_exprs().begin();
for (const Expr *AssignOp : C->assignment_ops()) {
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
QualType Type = VD->getType();
if (CopiedVars.insert(VD->getCanonicalDecl()).second) {
// Get the address of the master variable. If we are emitting code with
// TLS support, the address is passed from the master as field in the
// captured declaration.
Address MasterAddr = Address::invalid();
if (getLangOpts().OpenMPUseTLS &&
getContext().getTargetInfo().isTLSSupported()) {
assert(CapturedStmtInfo->lookup(VD) &&
"Copyin threadprivates should have been captured!");
DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(VD), true,
(*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
MasterAddr = EmitLValue(&DRE).getAddress();
LocalDeclMap.erase(VD);
} else {
MasterAddr =
Address(VD->isStaticLocal() ? CGM.getStaticLocalDeclAddress(VD)
: CGM.GetAddrOfGlobal(VD),
getContext().getDeclAlign(VD));
}
// Get the address of the threadprivate variable.
Address PrivateAddr = EmitLValue(*IRef).getAddress();
if (CopiedVars.size() == 1) {
// At first check if current thread is a master thread. If it is, no
// need to copy data.
CopyBegin = createBasicBlock("copyin.not.master");
CopyEnd = createBasicBlock("copyin.not.master.end");
Builder.CreateCondBr(
Builder.CreateICmpNE(
Builder.CreatePtrToInt(MasterAddr.getPointer(), CGM.IntPtrTy),
Builder.CreatePtrToInt(PrivateAddr.getPointer(),
CGM.IntPtrTy)),
CopyBegin, CopyEnd);
EmitBlock(CopyBegin);
}
const auto *SrcVD =
cast<VarDecl>(cast<DeclRefExpr>(*ISrcRef)->getDecl());
const auto *DestVD =
cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
EmitOMPCopy(Type, PrivateAddr, MasterAddr, DestVD, SrcVD, AssignOp);
}
++IRef;
++ISrcRef;
++IDestRef;
}
}
if (CopyEnd) {
// Exit out of copying procedure for non-master thread.
EmitBlock(CopyEnd, /*IsFinished=*/true);
return true;
}
return false;
}
bool CodeGenFunction::EmitOMPLastprivateClauseInit(
const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope) {
if (!HaveInsertPoint())
return false;
bool HasAtLeastOneLastprivate = false;
llvm::DenseSet<const VarDecl *> SIMDLCVs;
if (isOpenMPSimdDirective(D.getDirectiveKind())) {
const auto *LoopDirective = cast<OMPLoopDirective>(&D);
for (const Expr *C : LoopDirective->counters()) {
SIMDLCVs.insert(
cast<VarDecl>(cast<DeclRefExpr>(C)->getDecl())->getCanonicalDecl());
}
}
llvm::DenseSet<const VarDecl *> AlreadyEmittedVars;
for (const auto *C : D.getClausesOfKind<OMPLastprivateClause>()) {
HasAtLeastOneLastprivate = true;
if (isOpenMPTaskLoopDirective(D.getDirectiveKind()) &&
!getLangOpts().OpenMPSimd)
break;
auto IRef = C->varlist_begin();
auto IDestRef = C->destination_exprs().begin();
for (const Expr *IInit : C->private_copies()) {
// Keep the address of the original variable for future update at the end
// of the loop.
const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
// Taskloops do not require additional initialization, it is done in
// runtime support library.
if (AlreadyEmittedVars.insert(OrigVD->getCanonicalDecl()).second) {
const auto *DestVD =
cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
PrivateScope.addPrivate(DestVD, [this, OrigVD, IRef]() {
DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
/*RefersToEnclosingVariableOrCapture=*/
CapturedStmtInfo->lookup(OrigVD) != nullptr,
(*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc());
return EmitLValue(&DRE).getAddress();
});
// Check if the variable is also a firstprivate: in this case IInit is
// not generated. Initialization of this variable will happen in codegen
// for 'firstprivate' clause.
if (IInit && !SIMDLCVs.count(OrigVD->getCanonicalDecl())) {
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
bool IsRegistered = PrivateScope.addPrivate(OrigVD, [this, VD]() {
// Emit private VarDecl with copy init.
EmitDecl(*VD);
return GetAddrOfLocalVar(VD);
});
assert(IsRegistered &&
"lastprivate var already registered as private");
(void)IsRegistered;
}
}
++IRef;
++IDestRef;
}
}
return HasAtLeastOneLastprivate;
}
void CodeGenFunction::EmitOMPLastprivateClauseFinal(
const OMPExecutableDirective &D, bool NoFinals,
llvm::Value *IsLastIterCond) {
if (!HaveInsertPoint())
return;
// Emit following code:
// if (<IsLastIterCond>) {
// orig_var1 = private_orig_var1;
// ...
// orig_varn = private_orig_varn;
// }
llvm::BasicBlock *ThenBB = nullptr;
llvm::BasicBlock *DoneBB = nullptr;
if (IsLastIterCond) {
ThenBB = createBasicBlock(".omp.lastprivate.then");
DoneBB = createBasicBlock(".omp.lastprivate.done");
Builder.CreateCondBr(IsLastIterCond, ThenBB, DoneBB);
EmitBlock(ThenBB);
}
llvm::DenseSet<const VarDecl *> AlreadyEmittedVars;
llvm::DenseMap<const VarDecl *, const Expr *> LoopCountersAndUpdates;
if (const auto *LoopDirective = dyn_cast<OMPLoopDirective>(&D)) {
auto IC = LoopDirective->counters().begin();
for (const Expr *F : LoopDirective->finals()) {
const auto *D =
cast<VarDecl>(cast<DeclRefExpr>(*IC)->getDecl())->getCanonicalDecl();
if (NoFinals)
AlreadyEmittedVars.insert(D);
else
LoopCountersAndUpdates[D] = F;
++IC;
}
}
for (const auto *C : D.getClausesOfKind<OMPLastprivateClause>()) {
auto IRef = C->varlist_begin();
auto ISrcRef = C->source_exprs().begin();
auto IDestRef = C->destination_exprs().begin();
for (const Expr *AssignOp : C->assignment_ops()) {
const auto *PrivateVD =
cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
QualType Type = PrivateVD->getType();
const auto *CanonicalVD = PrivateVD->getCanonicalDecl();
if (AlreadyEmittedVars.insert(CanonicalVD).second) {
// If lastprivate variable is a loop control variable for loop-based
// directive, update its value before copyin back to original
// variable.
if (const Expr *FinalExpr = LoopCountersAndUpdates.lookup(CanonicalVD))
EmitIgnoredExpr(FinalExpr);
const auto *SrcVD =
cast<VarDecl>(cast<DeclRefExpr>(*ISrcRef)->getDecl());
const auto *DestVD =
cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl());
// Get the address of the original variable.
Address OriginalAddr = GetAddrOfLocalVar(DestVD);
// Get the address of the private variable.
Address PrivateAddr = GetAddrOfLocalVar(PrivateVD);
if (const auto *RefTy = PrivateVD->getType()->getAs<ReferenceType>())
PrivateAddr =
Address(Builder.CreateLoad(PrivateAddr),
getNaturalTypeAlignment(RefTy->getPointeeType()));
EmitOMPCopy(Type, OriginalAddr, PrivateAddr, DestVD, SrcVD, AssignOp);
}
++IRef;
++ISrcRef;
++IDestRef;
}
if (const Expr *PostUpdate = C->getPostUpdateExpr())
EmitIgnoredExpr(PostUpdate);
}
if (IsLastIterCond)
EmitBlock(DoneBB, /*IsFinished=*/true);
}
void CodeGenFunction::EmitOMPReductionClauseInit(
const OMPExecutableDirective &D,
CodeGenFunction::OMPPrivateScope &PrivateScope) {
if (!HaveInsertPoint())
return;
SmallVector<const Expr *, 4> Shareds;
SmallVector<const Expr *, 4> Privates;
SmallVector<const Expr *, 4> ReductionOps;
SmallVector<const Expr *, 4> LHSs;
SmallVector<const Expr *, 4> RHSs;
for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
auto IPriv = C->privates().begin();
auto IRed = C->reduction_ops().begin();
auto ILHS = C->lhs_exprs().begin();
auto IRHS = C->rhs_exprs().begin();
for (const Expr *Ref : C->varlists()) {
Shareds.emplace_back(Ref);
Privates.emplace_back(*IPriv);
ReductionOps.emplace_back(*IRed);
LHSs.emplace_back(*ILHS);
RHSs.emplace_back(*IRHS);
std::advance(IPriv, 1);
std::advance(IRed, 1);
std::advance(ILHS, 1);
std::advance(IRHS, 1);
}
}
ReductionCodeGen RedCG(Shareds, Privates, ReductionOps);
unsigned Count = 0;
auto ILHS = LHSs.begin();
auto IRHS = RHSs.begin();
auto IPriv = Privates.begin();
for (const Expr *IRef : Shareds) {
const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*IPriv)->getDecl());
// Emit private VarDecl with reduction init.
RedCG.emitSharedLValue(*this, Count);
RedCG.emitAggregateType(*this, Count);
AutoVarEmission Emission = EmitAutoVarAlloca(*PrivateVD);
RedCG.emitInitialization(*this, Count, Emission.getAllocatedAddress(),
RedCG.getSharedLValue(Count),
[&Emission](CodeGenFunction &CGF) {
CGF.EmitAutoVarInit(Emission);
return true;
});
EmitAutoVarCleanups(Emission);
Address BaseAddr = RedCG.adjustPrivateAddress(
*this, Count, Emission.getAllocatedAddress());
bool IsRegistered = PrivateScope.addPrivate(
RedCG.getBaseDecl(Count), [BaseAddr]() { return BaseAddr; });
assert(IsRegistered && "private var already registered as private");
// Silence the warning about unused variable.
(void)IsRegistered;
const auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
const auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
QualType Type = PrivateVD->getType();
bool isaOMPArraySectionExpr = isa<OMPArraySectionExpr>(IRef);
if (isaOMPArraySectionExpr && Type->isVariablyModifiedType()) {
// Store the address of the original variable associated with the LHS
// implicit variable.
PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() {
return RedCG.getSharedLValue(Count).getAddress();
});
PrivateScope.addPrivate(
RHSVD, [this, PrivateVD]() { return GetAddrOfLocalVar(PrivateVD); });
} else if ((isaOMPArraySectionExpr && Type->isScalarType()) ||
isa<ArraySubscriptExpr>(IRef)) {
// Store the address of the original variable associated with the LHS
// implicit variable.
PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() {
return RedCG.getSharedLValue(Count).getAddress();
});
PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD]() {
return Builder.CreateElementBitCast(GetAddrOfLocalVar(PrivateVD),
ConvertTypeForMem(RHSVD->getType()),
"rhs.begin");
});
} else {
QualType Type = PrivateVD->getType();
bool IsArray = getContext().getAsArrayType(Type) != nullptr;
Address OriginalAddr = RedCG.getSharedLValue(Count).getAddress();
// Store the address of the original variable associated with the LHS
// implicit variable.
if (IsArray) {
OriginalAddr = Builder.CreateElementBitCast(
OriginalAddr, ConvertTypeForMem(LHSVD->getType()), "lhs.begin");
}
PrivateScope.addPrivate(LHSVD, [OriginalAddr]() { return OriginalAddr; });
PrivateScope.addPrivate(
RHSVD, [this, PrivateVD, RHSVD, IsArray]() {
return IsArray
? Builder.CreateElementBitCast(
GetAddrOfLocalVar(PrivateVD),
ConvertTypeForMem(RHSVD->getType()), "rhs.begin")
: GetAddrOfLocalVar(PrivateVD);
});
}
++ILHS;
++IRHS;
++IPriv;
++Count;
}
}
void CodeGenFunction::EmitOMPReductionClauseFinal(
const OMPExecutableDirective &D, const OpenMPDirectiveKind ReductionKind) {
if (!HaveInsertPoint())
return;
llvm::SmallVector<const Expr *, 8> Privates;
llvm::SmallVector<const Expr *, 8> LHSExprs;
llvm::SmallVector<const Expr *, 8> RHSExprs;
llvm::SmallVector<const Expr *, 8> ReductionOps;
bool HasAtLeastOneReduction = false;
for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
HasAtLeastOneReduction = true;
Privates.append(C->privates().begin(), C->privates().end());
LHSExprs.append(C->lhs_exprs().begin(), C->lhs_exprs().end());
RHSExprs.append(C->rhs_exprs().begin(), C->rhs_exprs().end());
ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
}
if (HasAtLeastOneReduction) {
bool WithNowait = D.getSingleClause<OMPNowaitClause>() ||
isOpenMPParallelDirective(D.getDirectiveKind()) ||
ReductionKind == OMPD_simd;
bool SimpleReduction = ReductionKind == OMPD_simd;
// Emit nowait reduction if nowait clause is present or directive is a
// parallel directive (it always has implicit barrier).
CGM.getOpenMPRuntime().emitReduction(
*this, D.getEndLoc(), Privates, LHSExprs, RHSExprs, ReductionOps,
{WithNowait, SimpleReduction, ReductionKind});
}
}
static void emitPostUpdateForReductionClause(
CodeGenFunction &CGF, const OMPExecutableDirective &D,
const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen) {
if (!CGF.HaveInsertPoint())
return;
llvm::BasicBlock *DoneBB = nullptr;
for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
if (const Expr *PostUpdate = C->getPostUpdateExpr()) {
if (!DoneBB) {
if (llvm::Value *Cond = CondGen(CGF)) {
// If the first post-update expression is found, emit conditional
// block if it was requested.
llvm::BasicBlock *ThenBB = CGF.createBasicBlock(".omp.reduction.pu");
DoneBB = CGF.createBasicBlock(".omp.reduction.pu.done");
CGF.Builder.CreateCondBr(Cond, ThenBB, DoneBB);
CGF.EmitBlock(ThenBB);
}
}
CGF.EmitIgnoredExpr(PostUpdate);
}
}
if (DoneBB)
CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
}
namespace {
/// Codegen lambda for appending distribute lower and upper bounds to outlined
/// parallel function. This is necessary for combined constructs such as
/// 'distribute parallel for'
typedef llvm::function_ref<void(CodeGenFunction &,
const OMPExecutableDirective &,
llvm::SmallVectorImpl<llvm::Value *> &)>
CodeGenBoundParametersTy;
} // anonymous namespace
static void emitCommonOMPParallelDirective(
CodeGenFunction &CGF, const OMPExecutableDirective &S,
OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
const CodeGenBoundParametersTy &CodeGenBoundParameters) {
const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel);
llvm::Value *OutlinedFn =
CGF.CGM.getOpenMPRuntime().emitParallelOutlinedFunction(
S, *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen);
if (const auto *NumThreadsClause = S.getSingleClause<OMPNumThreadsClause>()) {
CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
llvm::Value *NumThreads =
CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(),
/*IgnoreResultAssign=*/true);
CGF.CGM.getOpenMPRuntime().emitNumThreadsClause(
CGF, NumThreads, NumThreadsClause->getBeginLoc());
}
if (const auto *ProcBindClause = S.getSingleClause<OMPProcBindClause>()) {
CodeGenFunction::RunCleanupsScope ProcBindScope(CGF);
CGF.CGM.getOpenMPRuntime().emitProcBindClause(
CGF, ProcBindClause->getProcBindKind(), ProcBindClause->getBeginLoc());
}
const Expr *IfCond = nullptr;
for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
if (C->getNameModifier() == OMPD_unknown ||
C->getNameModifier() == OMPD_parallel) {
IfCond = C->getCondition();
break;
}
}
OMPParallelScope Scope(CGF, S);
llvm::SmallVector<llvm::Value *, 16> CapturedVars;
// Combining 'distribute' with 'for' requires sharing each 'distribute' chunk
// lower and upper bounds with the pragma 'for' chunking mechanism.
// The following lambda takes care of appending the lower and upper bound
// parameters when necessary
CodeGenBoundParameters(CGF, S, CapturedVars);
CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
CGF.CGM.getOpenMPRuntime().emitParallelCall(CGF, S.getBeginLoc(), OutlinedFn,
CapturedVars, IfCond);
}
static void emitEmptyBoundParameters(CodeGenFunction &,
const OMPExecutableDirective &,
llvm::SmallVectorImpl<llvm::Value *> &) {}
void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
// Emit parallel region as a standalone region.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
OMPPrivateScope PrivateScope(CGF);
bool Copyins = CGF.EmitOMPCopyinClause(S);
(void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
if (Copyins) {
// Emit implicit barrier to synchronize threads and avoid data races on
// propagation master's thread values of threadprivate variables to local
// instances of that variables of all other implicit threads.
CGF.CGM.getOpenMPRuntime().emitBarrierCall(
CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
/*ForceSimpleCall=*/true);
}
CGF.EmitOMPPrivateClause(S, PrivateScope);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.EmitStmt(S.getCapturedStmt(OMPD_parallel)->getCapturedStmt());
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
};
emitCommonOMPParallelDirective(*this, S, OMPD_parallel, CodeGen,
emitEmptyBoundParameters);
emitPostUpdateForReductionClause(*this, S,
[](CodeGenFunction &) { return nullptr; });
}
void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D,
JumpDest LoopExit) {
RunCleanupsScope BodyScope(*this);
// Update counters values on current iteration.
for (const Expr *UE : D.updates())
EmitIgnoredExpr(UE);
// Update the linear variables.
// In distribute directives only loop counters may be marked as linear, no
// need to generate the code for them.
if (!isOpenMPDistributeDirective(D.getDirectiveKind())) {
for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
for (const Expr *UE : C->updates())
EmitIgnoredExpr(UE);
}
}
// On a continue in the body, jump to the end.
JumpDest Continue = getJumpDestInCurrentScope("omp.body.continue");
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
// Emit loop body.
EmitStmt(D.getBody());
// The end (updates/cleanups).
EmitBlock(Continue.getBlock());
BreakContinueStack.pop_back();
}
void CodeGenFunction::EmitOMPInnerLoop(
const Stmt &S, bool RequiresCleanup, const Expr *LoopCond,
const Expr *IncExpr,
const llvm::function_ref<void(CodeGenFunction &)> BodyGen,
const llvm::function_ref<void(CodeGenFunction &)> PostIncGen) {
auto LoopExit = getJumpDestInCurrentScope("omp.inner.for.end");
// Start the loop with a block that tests the condition.
auto CondBlock = createBasicBlock("omp.inner.for.cond");
EmitBlock(CondBlock);
const SourceRange R = S.getSourceRange();
LoopStack.push(CondBlock, 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 (RequiresCleanup)
ExitBlock = createBasicBlock("omp.inner.for.cond.cleanup");
llvm::BasicBlock *LoopBody = createBasicBlock("omp.inner.for.body");
// Emit condition.
EmitBranchOnBoolExpr(LoopCond, LoopBody, ExitBlock, getProfileCount(&S));
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
}
EmitBlock(LoopBody);
incrementProfileCounter(&S);
// Create a block for the increment.
JumpDest Continue = getJumpDestInCurrentScope("omp.inner.for.inc");
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
BodyGen(*this);
// Emit "IV = IV + 1" and a back-edge to the condition block.
EmitBlock(Continue.getBlock());
EmitIgnoredExpr(IncExpr);
PostIncGen(*this);
BreakContinueStack.pop_back();
EmitBranch(CondBlock);
LoopStack.pop();
// Emit the fall-through block.
EmitBlock(LoopExit.getBlock());
}
bool CodeGenFunction::EmitOMPLinearClauseInit(const OMPLoopDirective &D) {
if (!HaveInsertPoint())
return false;
// Emit inits for the linear variables.
bool HasLinears = false;
for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
for (const Expr *Init : C->inits()) {
HasLinears = true;
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(Init)->getDecl());
if (const auto *Ref =
dyn_cast<DeclRefExpr>(VD->getInit()->IgnoreImpCasts())) {
AutoVarEmission Emission = EmitAutoVarAlloca(*VD);
const auto *OrigVD = cast<VarDecl>(Ref->getDecl());
DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
CapturedStmtInfo->lookup(OrigVD) != nullptr,
VD->getInit()->getType(), VK_LValue,
VD->getInit()->getExprLoc());
EmitExprAsInit(&DRE, VD, MakeAddrLValue(Emission.getAllocatedAddress(),
VD->getType()),
/*capturedByInit=*/false);
EmitAutoVarCleanups(Emission);
} else {
EmitVarDecl(*VD);
}
}
// Emit the linear steps for the linear clauses.
// If a step is not constant, it is pre-calculated before the loop.
if (const auto *CS = cast_or_null<BinaryOperator>(C->getCalcStep()))
if (const auto *SaveRef = cast<DeclRefExpr>(CS->getLHS())) {
EmitVarDecl(*cast<VarDecl>(SaveRef->getDecl()));
// Emit calculation of the linear step.
EmitIgnoredExpr(CS);
}
}
return HasLinears;
}
void CodeGenFunction::EmitOMPLinearClauseFinal(
const OMPLoopDirective &D,
const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen) {
if (!HaveInsertPoint())
return;
llvm::BasicBlock *DoneBB = nullptr;
// Emit the final values of the linear variables.
for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
auto IC = C->varlist_begin();
for (const Expr *F : C->finals()) {
if (!DoneBB) {
if (llvm::Value *Cond = CondGen(*this)) {
// If the first post-update expression is found, emit conditional
// block if it was requested.
llvm::BasicBlock *ThenBB = createBasicBlock(".omp.linear.pu");
DoneBB = createBasicBlock(".omp.linear.pu.done");
Builder.CreateCondBr(Cond, ThenBB, DoneBB);
EmitBlock(ThenBB);
}
}
const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IC)->getDecl());
DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD),
CapturedStmtInfo->lookup(OrigVD) != nullptr,
(*IC)->getType(), VK_LValue, (*IC)->getExprLoc());
Address OrigAddr = EmitLValue(&DRE).getAddress();
CodeGenFunction::OMPPrivateScope VarScope(*this);
VarScope.addPrivate(OrigVD, [OrigAddr]() { return OrigAddr; });
(void)VarScope.Privatize();
EmitIgnoredExpr(F);
++IC;
}
if (const Expr *PostUpdate = C->getPostUpdateExpr())
EmitIgnoredExpr(PostUpdate);
}
if (DoneBB)
EmitBlock(DoneBB, /*IsFinished=*/true);
}
static void emitAlignedClause(CodeGenFunction &CGF,
const OMPExecutableDirective &D) {
if (!CGF.HaveInsertPoint())
return;
for (const auto *Clause : D.getClausesOfKind<OMPAlignedClause>()) {
unsigned ClauseAlignment = 0;
if (const Expr *AlignmentExpr = Clause->getAlignment()) {
auto *AlignmentCI =
cast<llvm::ConstantInt>(CGF.EmitScalarExpr(AlignmentExpr));
ClauseAlignment = static_cast<unsigned>(AlignmentCI->getZExtValue());
}
for (const Expr *E : Clause->varlists()) {
unsigned Alignment = ClauseAlignment;
if (Alignment == 0) {
// OpenMP [2.8.1, Description]
// If no optional parameter is specified, implementation-defined default
// alignments for SIMD instructions on the target platforms are assumed.
Alignment =
CGF.getContext()
.toCharUnitsFromBits(CGF.getContext().getOpenMPDefaultSimdAlign(
E->getType()->getPointeeType()))
.getQuantity();
}
assert((Alignment == 0 || llvm::isPowerOf2_32(Alignment)) &&
"alignment is not power of 2");
if (Alignment != 0) {
llvm::Value *PtrValue = CGF.EmitScalarExpr(E);
CGF.EmitAlignmentAssumption(
PtrValue, E, /*No second loc needed*/ SourceLocation(), Alignment);
}
}
}
}
void CodeGenFunction::EmitOMPPrivateLoopCounters(
const OMPLoopDirective &S, CodeGenFunction::OMPPrivateScope &LoopScope) {
if (!HaveInsertPoint())
return;
auto I = S.private_counters().begin();
for (const Expr *E : S.counters()) {
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl());
// Emit var without initialization.
AutoVarEmission VarEmission = EmitAutoVarAlloca(*PrivateVD);
EmitAutoVarCleanups(VarEmission);
LocalDeclMap.erase(PrivateVD);
(void)LoopScope.addPrivate(VD, [&VarEmission]() {
return VarEmission.getAllocatedAddress();
});
if (LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD) ||
VD->hasGlobalStorage()) {
(void)LoopScope.addPrivate(PrivateVD, [this, VD, E]() {
DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(VD),
LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD),
E->getType(), VK_LValue, E->getExprLoc());
return EmitLValue(&DRE).getAddress();
});
} else {
(void)LoopScope.addPrivate(PrivateVD, [&VarEmission]() {
return VarEmission.getAllocatedAddress();
});
}
++I;
}
// Privatize extra loop counters used in loops for ordered(n) clauses.
for (const auto *C : S.getClausesOfKind<OMPOrderedClause>()) {
if (!C->getNumForLoops())
continue;
for (unsigned I = S.getCollapsedNumber(),
E = C->getLoopNumIterations().size();
I < E; ++I) {
const auto *DRE = cast<DeclRefExpr>(C->getLoopCounter(I));
const auto *VD = cast<VarDecl>(DRE->getDecl());
- // Override only those variables that are really emitted already.
- if (LocalDeclMap.count(VD)) {
+ // Override only those variables that can be captured to avoid re-emission
+ // of the variables declared within the loops.
+ if (DRE->refersToEnclosingVariableOrCapture()) {
(void)LoopScope.addPrivate(VD, [this, DRE, VD]() {
return CreateMemTemp(DRE->getType(), VD->getName());
});
}
}
}
}
static void emitPreCond(CodeGenFunction &CGF, const OMPLoopDirective &S,
const Expr *Cond, llvm::BasicBlock *TrueBlock,
llvm::BasicBlock *FalseBlock, uint64_t TrueCount) {
if (!CGF.HaveInsertPoint())
return;
{
CodeGenFunction::OMPPrivateScope PreCondScope(CGF);
CGF.EmitOMPPrivateLoopCounters(S, PreCondScope);
(void)PreCondScope.Privatize();
// Get initial values of real counters.
for (const Expr *I : S.inits()) {
CGF.EmitIgnoredExpr(I);
}
}
// Check that loop is executed at least one time.
CGF.EmitBranchOnBoolExpr(Cond, TrueBlock, FalseBlock, TrueCount);
}
void CodeGenFunction::EmitOMPLinearClause(
const OMPLoopDirective &D, CodeGenFunction::OMPPrivateScope &PrivateScope) {
if (!HaveInsertPoint())
return;
llvm::DenseSet<const VarDecl *> SIMDLCVs;
if (isOpenMPSimdDirective(D.getDirectiveKind())) {
const auto *LoopDirective = cast<OMPLoopDirective>(&D);
for (const Expr *C : LoopDirective->counters()) {
SIMDLCVs.insert(
cast<VarDecl>(cast<DeclRefExpr>(C)->getDecl())->getCanonicalDecl());
}
}
for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
auto CurPrivate = C->privates().begin();
for (const Expr *E : C->varlists()) {
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
const auto *PrivateVD =
cast<VarDecl>(cast<DeclRefExpr>(*CurPrivate)->getDecl());
if (!SIMDLCVs.count(VD->getCanonicalDecl())) {
bool IsRegistered = PrivateScope.addPrivate(VD, [this, PrivateVD]() {
// Emit private VarDecl with copy init.
EmitVarDecl(*PrivateVD);
return GetAddrOfLocalVar(PrivateVD);
});
assert(IsRegistered && "linear var already registered as private");
// Silence the warning about unused variable.
(void)IsRegistered;
} else {
EmitVarDecl(*PrivateVD);
}
++CurPrivate;
}
}
}
static void emitSimdlenSafelenClause(CodeGenFunction &CGF,
const OMPExecutableDirective &D,
bool IsMonotonic) {
if (!CGF.HaveInsertPoint())
return;
if (const auto *C = D.getSingleClause<OMPSimdlenClause>()) {
RValue Len = CGF.EmitAnyExpr(C->getSimdlen(), AggValueSlot::ignored(),
/*ignoreResult=*/true);
auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
CGF.LoopStack.setVectorizeWidth(Val->getZExtValue());
// In presence of finite 'safelen', it may be unsafe to mark all
// the memory instructions parallel, because loop-carried
// dependences of 'safelen' iterations are possible.
if (!IsMonotonic)
CGF.LoopStack.setParallel(!D.getSingleClause<OMPSafelenClause>());
} else if (const auto *C = D.getSingleClause<OMPSafelenClause>()) {
RValue Len = CGF.EmitAnyExpr(C->getSafelen(), AggValueSlot::ignored(),
/*ignoreResult=*/true);
auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
CGF.LoopStack.setVectorizeWidth(Val->getZExtValue());
// In presence of finite 'safelen', it may be unsafe to mark all
// the memory instructions parallel, because loop-carried
// dependences of 'safelen' iterations are possible.
CGF.LoopStack.setParallel(/*Enable=*/false);
}
}
void CodeGenFunction::EmitOMPSimdInit(const OMPLoopDirective &D,
bool IsMonotonic) {
// Walk clauses and process safelen/lastprivate.
LoopStack.setParallel(!IsMonotonic);
LoopStack.setVectorizeEnable();
emitSimdlenSafelenClause(*this, D, IsMonotonic);
}
void CodeGenFunction::EmitOMPSimdFinal(
const OMPLoopDirective &D,
const llvm::function_ref<llvm::Value *(CodeGenFunction &)> CondGen) {
if (!HaveInsertPoint())
return;
llvm::BasicBlock *DoneBB = nullptr;
auto IC = D.counters().begin();
auto IPC = D.private_counters().begin();
for (const Expr *F : D.finals()) {
const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>((*IC))->getDecl());
const auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>((*IPC))->getDecl());
const auto *CED = dyn_cast<OMPCapturedExprDecl>(OrigVD);
if (LocalDeclMap.count(OrigVD) || CapturedStmtInfo->lookup(OrigVD) ||
OrigVD->hasGlobalStorage() || CED) {
if (!DoneBB) {
if (llvm::Value *Cond = CondGen(*this)) {
// If the first post-update expression is found, emit conditional
// block if it was requested.
llvm::BasicBlock *ThenBB = createBasicBlock(".omp.final.then");
DoneBB = createBasicBlock(".omp.final.done");
Builder.CreateCondBr(Cond, ThenBB, DoneBB);
EmitBlock(ThenBB);
}
}
Address OrigAddr = Address::invalid();
if (CED) {
OrigAddr = EmitLValue(CED->getInit()->IgnoreImpCasts()).getAddress();
} else {
DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(PrivateVD),
/*RefersToEnclosingVariableOrCapture=*/false,
(*IPC)->getType(), VK_LValue, (*IPC)->getExprLoc());
OrigAddr = EmitLValue(&DRE).getAddress();
}
OMPPrivateScope VarScope(*this);
VarScope.addPrivate(OrigVD, [OrigAddr]() { return OrigAddr; });
(void)VarScope.Privatize();
EmitIgnoredExpr(F);
}
++IC;
++IPC;
}
if (DoneBB)
EmitBlock(DoneBB, /*IsFinished=*/true);
}
static void emitOMPLoopBodyWithStopPoint(CodeGenFunction &CGF,
const OMPLoopDirective &S,
CodeGenFunction::JumpDest LoopExit) {
CGF.EmitOMPLoopBody(S, LoopExit);
CGF.EmitStopPoint(&S);
}
/// Emit a helper variable and return corresponding lvalue.
static LValue EmitOMPHelperVar(CodeGenFunction &CGF,
const DeclRefExpr *Helper) {
auto VDecl = cast<VarDecl>(Helper->getDecl());
CGF.EmitVarDecl(*VDecl);
return CGF.EmitLValue(Helper);
}
static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S,
PrePostActionTy &Action) {
Action.Enter(CGF);
assert(isOpenMPSimdDirective(S.getDirectiveKind()) &&
"Expected simd directive");
OMPLoopScope PreInitScope(CGF, S);
// if (PreCond) {
// for (IV in 0..LastIteration) BODY;
// <Final counter/linear vars updates>;
// }
//
if (isOpenMPDistributeDirective(S.getDirectiveKind()) ||
isOpenMPWorksharingDirective(S.getDirectiveKind()) ||
isOpenMPTaskLoopDirective(S.getDirectiveKind())) {
(void)EmitOMPHelperVar(CGF, cast<DeclRefExpr>(S.getLowerBoundVariable()));
(void)EmitOMPHelperVar(CGF, cast<DeclRefExpr>(S.getUpperBoundVariable()));
}
// Emit: if (PreCond) - begin.
// If the condition constant folds and can be elided, avoid emitting the
// whole loop.
bool CondConstant;
llvm::BasicBlock *ContBlock = nullptr;
if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
if (!CondConstant)
return;
} else {
llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("simd.if.then");
ContBlock = CGF.createBasicBlock("simd.if.end");
emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock,
CGF.getProfileCount(&S));
CGF.EmitBlock(ThenBlock);
CGF.incrementProfileCounter(&S);
}
// Emit the loop iteration variable.
const Expr *IVExpr = S.getIterationVariable();
const auto *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl());
CGF.EmitVarDecl(*IVDecl);
CGF.EmitIgnoredExpr(S.getInit());
// Emit the iterations count variable.
// If it is not a variable, Sema decided to calculate iterations count on
// each iteration (e.g., it is foldable into a constant).
if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
CGF.EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
// Emit calculation of the iterations count.
CGF.EmitIgnoredExpr(S.getCalcLastIteration());
}
CGF.EmitOMPSimdInit(S);
emitAlignedClause(CGF, S);
(void)CGF.EmitOMPLinearClauseInit(S);
{
CodeGenFunction::OMPPrivateScope LoopScope(CGF);
CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
CGF.EmitOMPLinearClause(S, LoopScope);
CGF.EmitOMPPrivateClause(S, LoopScope);
CGF.EmitOMPReductionClauseInit(S, LoopScope);
bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
(void)LoopScope.Privatize();
if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(),
S.getInc(),
[&S](CodeGenFunction &CGF) {
CGF.EmitOMPLoopBody(S, CodeGenFunction::JumpDest());
CGF.EmitStopPoint(&S);
},
[](CodeGenFunction &) {});
CGF.EmitOMPSimdFinal(S, [](CodeGenFunction &) { return nullptr; });
// Emit final copy of the lastprivate variables at the end of loops.
if (HasLastprivateClause)
CGF.EmitOMPLastprivateClauseFinal(S, /*NoFinals=*/true);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_simd);
emitPostUpdateForReductionClause(CGF, S,
[](CodeGenFunction &) { return nullptr; });
}
CGF.EmitOMPLinearClauseFinal(S, [](CodeGenFunction &) { return nullptr; });
// Emit: if (PreCond) - end.
if (ContBlock) {
CGF.EmitBranch(ContBlock);
CGF.EmitBlock(ContBlock, true);
}
}
void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitOMPSimdRegion(CGF, S, Action);
};
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
}
void CodeGenFunction::EmitOMPOuterLoop(
bool DynamicOrOrdered, bool IsMonotonic, const OMPLoopDirective &S,
CodeGenFunction::OMPPrivateScope &LoopScope,
const CodeGenFunction::OMPLoopArguments &LoopArgs,
const CodeGenFunction::CodeGenLoopTy &CodeGenLoop,
const CodeGenFunction::CodeGenOrderedTy &CodeGenOrdered) {
CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
const Expr *IVExpr = S.getIterationVariable();
const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
JumpDest LoopExit = getJumpDestInCurrentScope("omp.dispatch.end");
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = createBasicBlock("omp.dispatch.cond");
EmitBlock(CondBlock);
const SourceRange R = S.getSourceRange();
LoopStack.push(CondBlock, SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()));
llvm::Value *BoolCondVal = nullptr;
if (!DynamicOrOrdered) {
// UB = min(UB, GlobalUB) or
// UB = min(UB, PrevUB) for combined loop sharing constructs (e.g.
// 'distribute parallel for')
EmitIgnoredExpr(LoopArgs.EUB);
// IV = LB
EmitIgnoredExpr(LoopArgs.Init);
// IV < UB
BoolCondVal = EvaluateExprAsBool(LoopArgs.Cond);
} else {
BoolCondVal =
RT.emitForNext(*this, S.getBeginLoc(), IVSize, IVSigned, LoopArgs.IL,
LoopArgs.LB, LoopArgs.UB, LoopArgs.ST);
}
// 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 (LoopScope.requiresCleanups())
ExitBlock = createBasicBlock("omp.dispatch.cleanup");
llvm::BasicBlock *LoopBody = createBasicBlock("omp.dispatch.body");
Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
}
EmitBlock(LoopBody);
// Emit "IV = LB" (in case of static schedule, we have already calculated new
// LB for loop condition and emitted it above).
if (DynamicOrOrdered)
EmitIgnoredExpr(LoopArgs.Init);
// Create a block for the increment.
JumpDest Continue = getJumpDestInCurrentScope("omp.dispatch.inc");
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
// Generate !llvm.loop.parallel metadata for loads and stores for loops
// with dynamic/guided scheduling and without ordered clause.
if (!isOpenMPSimdDirective(S.getDirectiveKind()))
LoopStack.setParallel(!IsMonotonic);
else
EmitOMPSimdInit(S, IsMonotonic);
SourceLocation Loc = S.getBeginLoc();
// when 'distribute' is not combined with a 'for':
// while (idx <= UB) { BODY; ++idx; }
// when 'distribute' is combined with a 'for'
// (e.g. 'distribute parallel for')
// while (idx <= UB) { <CodeGen rest of pragma>; idx += ST; }
EmitOMPInnerLoop(
S, LoopScope.requiresCleanups(), LoopArgs.Cond, LoopArgs.IncExpr,
[&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
CodeGenLoop(CGF, S, LoopExit);
},
[IVSize, IVSigned, Loc, &CodeGenOrdered](CodeGenFunction &CGF) {
CodeGenOrdered(CGF, Loc, IVSize, IVSigned);
});
EmitBlock(Continue.getBlock());
BreakContinueStack.pop_back();
if (!DynamicOrOrdered) {
// Emit "LB = LB + Stride", "UB = UB + Stride".
EmitIgnoredExpr(LoopArgs.NextLB);
EmitIgnoredExpr(LoopArgs.NextUB);
}
EmitBranch(CondBlock);
LoopStack.pop();
// Emit the fall-through block.
EmitBlock(LoopExit.getBlock());
// Tell the runtime we are done.
auto &&CodeGen = [DynamicOrOrdered, &S](CodeGenFunction &CGF) {
if (!DynamicOrOrdered)
CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getEndLoc(),
S.getDirectiveKind());
};
OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen);
}
void CodeGenFunction::EmitOMPForOuterLoop(
const OpenMPScheduleTy &ScheduleKind, bool IsMonotonic,
const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered,
const OMPLoopArguments &LoopArgs,
const CodeGenDispatchBoundsTy &CGDispatchBounds) {
CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
// Dynamic scheduling of the outer loop (dynamic, guided, auto, runtime).
const bool DynamicOrOrdered =
Ordered || RT.isDynamic(ScheduleKind.Schedule);
assert((Ordered ||
!RT.isStaticNonchunked(ScheduleKind.Schedule,
LoopArgs.Chunk != nullptr)) &&
"static non-chunked schedule does not need outer loop");
// Emit outer loop.
//
// OpenMP [2.7.1, Loop Construct, Description, table 2-1]
// When schedule(dynamic,chunk_size) is specified, the iterations are
// distributed to threads in the team in chunks as the threads request them.
// Each thread executes a chunk of iterations, then requests another chunk,
// until no chunks remain to be distributed. Each chunk contains chunk_size
// iterations, except for the last chunk to be distributed, which may have
// fewer iterations. When no chunk_size is specified, it defaults to 1.
//
// When schedule(guided,chunk_size) is specified, the iterations are assigned
// to threads in the team in chunks as the executing threads request them.
// Each thread executes a chunk of iterations, then requests another chunk,
// until no chunks remain to be assigned. For a chunk_size of 1, the size of
// each chunk is proportional to the number of unassigned iterations divided
// by the number of threads in the team, decreasing to 1. For a chunk_size
// with value k (greater than 1), the size of each chunk is determined in the
// same way, with the restriction that the chunks do not contain fewer than k
// iterations (except for the last chunk to be assigned, which may have fewer
// than k iterations).
//
// When schedule(auto) is specified, the decision regarding scheduling is
// delegated to the compiler and/or runtime system. The programmer gives the
// implementation the freedom to choose any possible mapping of iterations to
// threads in the team.
//
// When schedule(runtime) is specified, the decision regarding scheduling is
// deferred until run time, and the schedule and chunk size are taken from the
// run-sched-var ICV. If the ICV is set to auto, the schedule is
// implementation defined
//
// while(__kmpc_dispatch_next(&LB, &UB)) {
// idx = LB;
// while (idx <= UB) { BODY; ++idx;
// __kmpc_dispatch_fini_(4|8)[u](); // For ordered loops only.
// } // inner loop
// }
//
// OpenMP [2.7.1, Loop Construct, Description, table 2-1]
// When schedule(static, chunk_size) is specified, iterations are divided into
// chunks of size chunk_size, and the chunks are assigned to the threads in
// the team in a round-robin fashion in the order of the thread number.
//
// while(UB = min(UB, GlobalUB), idx = LB, idx < UB) {
// while (idx <= UB) { BODY; ++idx; } // inner loop
// LB = LB + ST;
// UB = UB + ST;
// }
//
const Expr *IVExpr = S.getIterationVariable();
const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
if (DynamicOrOrdered) {
const std::pair<llvm::Value *, llvm::Value *> DispatchBounds =
CGDispatchBounds(*this, S, LoopArgs.LB, LoopArgs.UB);
llvm::Value *LBVal = DispatchBounds.first;
llvm::Value *UBVal = DispatchBounds.second;
CGOpenMPRuntime::DispatchRTInput DipatchRTInputValues = {LBVal, UBVal,
LoopArgs.Chunk};
RT.emitForDispatchInit(*this, S.getBeginLoc(), ScheduleKind, IVSize,
IVSigned, Ordered, DipatchRTInputValues);
} else {
CGOpenMPRuntime::StaticRTInput StaticInit(
IVSize, IVSigned, Ordered, LoopArgs.IL, LoopArgs.LB, LoopArgs.UB,
LoopArgs.ST, LoopArgs.Chunk);
RT.emitForStaticInit(*this, S.getBeginLoc(), S.getDirectiveKind(),
ScheduleKind, StaticInit);
}
auto &&CodeGenOrdered = [Ordered](CodeGenFunction &CGF, SourceLocation Loc,
const unsigned IVSize,
const bool IVSigned) {
if (Ordered) {
CGF.CGM.getOpenMPRuntime().emitForOrderedIterationEnd(CGF, Loc, IVSize,
IVSigned);
}
};
OMPLoopArguments OuterLoopArgs(LoopArgs.LB, LoopArgs.UB, LoopArgs.ST,
LoopArgs.IL, LoopArgs.Chunk, LoopArgs.EUB);
OuterLoopArgs.IncExpr = S.getInc();
OuterLoopArgs.Init = S.getInit();
OuterLoopArgs.Cond = S.getCond();
OuterLoopArgs.NextLB = S.getNextLowerBound();
OuterLoopArgs.NextUB = S.getNextUpperBound();
EmitOMPOuterLoop(DynamicOrOrdered, IsMonotonic, S, LoopScope, OuterLoopArgs,
emitOMPLoopBodyWithStopPoint, CodeGenOrdered);
}
static void emitEmptyOrdered(CodeGenFunction &, SourceLocation Loc,
const unsigned IVSize, const bool IVSigned) {}
void CodeGenFunction::EmitOMPDistributeOuterLoop(
OpenMPDistScheduleClauseKind ScheduleKind, const OMPLoopDirective &S,
OMPPrivateScope &LoopScope, const OMPLoopArguments &LoopArgs,
const CodeGenLoopTy &CodeGenLoopContent) {
CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
// Emit outer loop.
// Same behavior as a OMPForOuterLoop, except that schedule cannot be
// dynamic
//
const Expr *IVExpr = S.getIterationVariable();
const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
CGOpenMPRuntime::StaticRTInput StaticInit(
IVSize, IVSigned, /* Ordered = */ false, LoopArgs.IL, LoopArgs.LB,
LoopArgs.UB, LoopArgs.ST, LoopArgs.Chunk);
RT.emitDistributeStaticInit(*this, S.getBeginLoc(), ScheduleKind, StaticInit);
// for combined 'distribute' and 'for' the increment expression of distribute
// is stored in DistInc. For 'distribute' alone, it is in Inc.
Expr *IncExpr;
if (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind()))
IncExpr = S.getDistInc();
else
IncExpr = S.getInc();
// this routine is shared by 'omp distribute parallel for' and
// 'omp distribute': select the right EUB expression depending on the
// directive
OMPLoopArguments OuterLoopArgs;
OuterLoopArgs.LB = LoopArgs.LB;
OuterLoopArgs.UB = LoopArgs.UB;
OuterLoopArgs.ST = LoopArgs.ST;
OuterLoopArgs.IL = LoopArgs.IL;
OuterLoopArgs.Chunk = LoopArgs.Chunk;
OuterLoopArgs.EUB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
? S.getCombinedEnsureUpperBound()
: S.getEnsureUpperBound();
OuterLoopArgs.IncExpr = IncExpr;
OuterLoopArgs.Init = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
? S.getCombinedInit()
: S.getInit();
OuterLoopArgs.Cond = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
? S.getCombinedCond()
: S.getCond();
OuterLoopArgs.NextLB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
? S.getCombinedNextLowerBound()
: S.getNextLowerBound();
OuterLoopArgs.NextUB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
? S.getCombinedNextUpperBound()
: S.getNextUpperBound();
EmitOMPOuterLoop(/* DynamicOrOrdered = */ false, /* IsMonotonic = */ false, S,
LoopScope, OuterLoopArgs, CodeGenLoopContent,
emitEmptyOrdered);
}
static std::pair<LValue, LValue>
emitDistributeParallelForInnerBounds(CodeGenFunction &CGF,
const OMPExecutableDirective &S) {
const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
LValue LB =
EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getLowerBoundVariable()));
LValue UB =
EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getUpperBoundVariable()));
// When composing 'distribute' with 'for' (e.g. as in 'distribute
// parallel for') we need to use the 'distribute'
// chunk lower and upper bounds rather than the whole loop iteration
// space. These are parameters to the outlined function for 'parallel'
// and we copy the bounds of the previous schedule into the
// the current ones.
LValue PrevLB = CGF.EmitLValue(LS.getPrevLowerBoundVariable());
LValue PrevUB = CGF.EmitLValue(LS.getPrevUpperBoundVariable());
llvm::Value *PrevLBVal = CGF.EmitLoadOfScalar(
PrevLB, LS.getPrevLowerBoundVariable()->getExprLoc());
PrevLBVal = CGF.EmitScalarConversion(
PrevLBVal, LS.getPrevLowerBoundVariable()->getType(),
LS.getIterationVariable()->getType(),
LS.getPrevLowerBoundVariable()->getExprLoc());
llvm::Value *PrevUBVal = CGF.EmitLoadOfScalar(
PrevUB, LS.getPrevUpperBoundVariable()->getExprLoc());
PrevUBVal = CGF.EmitScalarConversion(
PrevUBVal, LS.getPrevUpperBoundVariable()->getType(),
LS.getIterationVariable()->getType(),
LS.getPrevUpperBoundVariable()->getExprLoc());
CGF.EmitStoreOfScalar(PrevLBVal, LB);
CGF.EmitStoreOfScalar(PrevUBVal, UB);
return {LB, UB};
}
/// if the 'for' loop has a dispatch schedule (e.g. dynamic, guided) then
/// we need to use the LB and UB expressions generated by the worksharing
/// code generation support, whereas in non combined situations we would
/// just emit 0 and the LastIteration expression
/// This function is necessary due to the difference of the LB and UB
/// types for the RT emission routines for 'for_static_init' and
/// 'for_dispatch_init'
static std::pair<llvm::Value *, llvm::Value *>
emitDistributeParallelForDispatchBounds(CodeGenFunction &CGF,
const OMPExecutableDirective &S,
Address LB, Address UB) {
const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
const Expr *IVExpr = LS.getIterationVariable();
// when implementing a dynamic schedule for a 'for' combined with a
// 'distribute' (e.g. 'distribute parallel for'), the 'for' loop
// is not normalized as each team only executes its own assigned
// distribute chunk
QualType IteratorTy = IVExpr->getType();
llvm::Value *LBVal =
CGF.EmitLoadOfScalar(LB, /*Volatile=*/false, IteratorTy, S.getBeginLoc());
llvm::Value *UBVal =
CGF.EmitLoadOfScalar(UB, /*Volatile=*/false, IteratorTy, S.getBeginLoc());
return {LBVal, UBVal};
}
static void emitDistributeParallelForDistributeInnerBoundParams(
CodeGenFunction &CGF, const OMPExecutableDirective &S,
llvm::SmallVectorImpl<llvm::Value *> &CapturedVars) {
const auto &Dir = cast<OMPLoopDirective>(S);
LValue LB =
CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedLowerBoundVariable()));
llvm::Value *LBCast = CGF.Builder.CreateIntCast(
CGF.Builder.CreateLoad(LB.getAddress()), CGF.SizeTy, /*isSigned=*/false);
CapturedVars.push_back(LBCast);
LValue UB =
CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedUpperBoundVariable()));
llvm::Value *UBCast = CGF.Builder.CreateIntCast(
CGF.Builder.CreateLoad(UB.getAddress()), CGF.SizeTy, /*isSigned=*/false);
CapturedVars.push_back(UBCast);
}
static void
emitInnerParallelForWhenCombined(CodeGenFunction &CGF,
const OMPLoopDirective &S,
CodeGenFunction::JumpDest LoopExit) {
auto &&CGInlinedWorksharingLoop = [&S](CodeGenFunction &CGF,
PrePostActionTy &Action) {
Action.Enter(CGF);
bool HasCancel = false;
if (!isOpenMPSimdDirective(S.getDirectiveKind())) {
if (const auto *D = dyn_cast<OMPTeamsDistributeParallelForDirective>(&S))
HasCancel = D->hasCancel();
else if (const auto *D = dyn_cast<OMPDistributeParallelForDirective>(&S))
HasCancel = D->hasCancel();
else if (const auto *D =
dyn_cast<OMPTargetTeamsDistributeParallelForDirective>(&S))
HasCancel = D->hasCancel();
}
CodeGenFunction::OMPCancelStackRAII CancelRegion(CGF, S.getDirectiveKind(),
HasCancel);
CGF.EmitOMPWorksharingLoop(S, S.getPrevEnsureUpperBound(),
emitDistributeParallelForInnerBounds,
emitDistributeParallelForDispatchBounds);
};
emitCommonOMPParallelDirective(
CGF, S,
isOpenMPSimdDirective(S.getDirectiveKind()) ? OMPD_for_simd : OMPD_for,
CGInlinedWorksharingLoop,
emitDistributeParallelForDistributeInnerBoundParams);
}
void CodeGenFunction::EmitOMPDistributeParallelForDirective(
const OMPDistributeParallelForDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
S.getDistInc());
};
OMPLexicalScope Scope(*this, S, OMPD_parallel);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen);
}
void CodeGenFunction::EmitOMPDistributeParallelForSimdDirective(
const OMPDistributeParallelForSimdDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
S.getDistInc());
};
OMPLexicalScope Scope(*this, S, OMPD_parallel);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen);
}
void CodeGenFunction::EmitOMPDistributeSimdDirective(
const OMPDistributeSimdDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
};
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
}
void CodeGenFunction::EmitOMPTargetSimdDeviceFunction(
CodeGenModule &CGM, StringRef ParentName, const OMPTargetSimdDirective &S) {
// Emit SPMD target parallel for region as a standalone region.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitOMPSimdRegion(CGF, S, Action);
};
llvm::Function *Fn;
llvm::Constant *Addr;
// Emit target region as a standalone region.
CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
assert(Fn && Addr && "Target device function emission failed.");
}
void CodeGenFunction::EmitOMPTargetSimdDirective(
const OMPTargetSimdDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitOMPSimdRegion(CGF, S, Action);
};
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
namespace {
struct ScheduleKindModifiersTy {
OpenMPScheduleClauseKind Kind;
OpenMPScheduleClauseModifier M1;
OpenMPScheduleClauseModifier M2;
ScheduleKindModifiersTy(OpenMPScheduleClauseKind Kind,
OpenMPScheduleClauseModifier M1,
OpenMPScheduleClauseModifier M2)
: Kind(Kind), M1(M1), M2(M2) {}
};
} // namespace
bool CodeGenFunction::EmitOMPWorksharingLoop(
const OMPLoopDirective &S, Expr *EUB,
const CodeGenLoopBoundsTy &CodeGenLoopBounds,
const CodeGenDispatchBoundsTy &CGDispatchBounds) {
// Emit the loop iteration variable.
const auto *IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
const auto *IVDecl = cast<VarDecl>(IVExpr->getDecl());
EmitVarDecl(*IVDecl);
// Emit the iterations count variable.
// If it is not a variable, Sema decided to calculate iterations count on each
// iteration (e.g., it is foldable into a constant).
if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
// Emit calculation of the iterations count.
EmitIgnoredExpr(S.getCalcLastIteration());
}
CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
bool HasLastprivateClause;
// Check pre-condition.
{
OMPLoopScope PreInitScope(*this, S);
// Skip the entire loop if we don't meet the precondition.
// If the condition constant folds and can be elided, avoid emitting the
// whole loop.
bool CondConstant;
llvm::BasicBlock *ContBlock = nullptr;
if (ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
if (!CondConstant)
return false;
} else {
llvm::BasicBlock *ThenBlock = createBasicBlock("omp.precond.then");
ContBlock = createBasicBlock("omp.precond.end");
emitPreCond(*this, S, S.getPreCond(), ThenBlock, ContBlock,
getProfileCount(&S));
EmitBlock(ThenBlock);
incrementProfileCounter(&S);
}
RunCleanupsScope DoacrossCleanupScope(*this);
bool Ordered = false;
if (const auto *OrderedClause = S.getSingleClause<OMPOrderedClause>()) {
if (OrderedClause->getNumForLoops())
RT.emitDoacrossInit(*this, S, OrderedClause->getLoopNumIterations());
else
Ordered = true;
}
llvm::DenseSet<const Expr *> EmittedFinals;
emitAlignedClause(*this, S);
bool HasLinears = EmitOMPLinearClauseInit(S);
// Emit helper vars inits.
std::pair<LValue, LValue> Bounds = CodeGenLoopBounds(*this, S);
LValue LB = Bounds.first;
LValue UB = Bounds.second;
LValue ST =
EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
LValue IL =
EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getIsLastIterVariable()));
// Emit 'then' code.
{
OMPPrivateScope LoopScope(*this);
if (EmitOMPFirstprivateClause(S, LoopScope) || HasLinears) {
// Emit implicit barrier to synchronize threads and avoid data races on
// initialization of firstprivate variables and post-update of
// lastprivate variables.
CGM.getOpenMPRuntime().emitBarrierCall(
*this, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
/*ForceSimpleCall=*/true);
}
EmitOMPPrivateClause(S, LoopScope);
HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope);
EmitOMPReductionClauseInit(S, LoopScope);
EmitOMPPrivateLoopCounters(S, LoopScope);
EmitOMPLinearClause(S, LoopScope);
(void)LoopScope.Privatize();
if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(*this, S);
// Detect the loop schedule kind and chunk.
const Expr *ChunkExpr = nullptr;
OpenMPScheduleTy ScheduleKind;
if (const auto *C = S.getSingleClause<OMPScheduleClause>()) {
ScheduleKind.Schedule = C->getScheduleKind();
ScheduleKind.M1 = C->getFirstScheduleModifier();
ScheduleKind.M2 = C->getSecondScheduleModifier();
ChunkExpr = C->getChunkSize();
} else {
// Default behaviour for schedule clause.
CGM.getOpenMPRuntime().getDefaultScheduleAndChunk(
*this, S, ScheduleKind.Schedule, ChunkExpr);
}
bool HasChunkSizeOne = false;
llvm::Value *Chunk = nullptr;
if (ChunkExpr) {
Chunk = EmitScalarExpr(ChunkExpr);
Chunk = EmitScalarConversion(Chunk, ChunkExpr->getType(),
S.getIterationVariable()->getType(),
S.getBeginLoc());
Expr::EvalResult Result;
if (ChunkExpr->EvaluateAsInt(Result, getContext())) {
llvm::APSInt EvaluatedChunk = Result.Val.getInt();
HasChunkSizeOne = (EvaluatedChunk.getLimitedValue() == 1);
}
}
const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
// OpenMP 4.5, 2.7.1 Loop Construct, Description.
// If the static schedule kind is specified or if the ordered clause is
// specified, and if no monotonic modifier is specified, the effect will
// be as if the monotonic modifier was specified.
bool StaticChunkedOne = RT.isStaticChunked(ScheduleKind.Schedule,
/* Chunked */ Chunk != nullptr) && HasChunkSizeOne &&
isOpenMPLoopBoundSharingDirective(S.getDirectiveKind());
if ((RT.isStaticNonchunked(ScheduleKind.Schedule,
/* Chunked */ Chunk != nullptr) ||
StaticChunkedOne) &&
!Ordered) {
if (isOpenMPSimdDirective(S.getDirectiveKind()))
EmitOMPSimdInit(S, /*IsMonotonic=*/true);
// OpenMP [2.7.1, Loop Construct, Description, table 2-1]
// When no chunk_size is specified, the iteration space is divided into
// chunks that are approximately equal in size, and at most one chunk is
// distributed to each thread. Note that the size of the chunks is
// unspecified in this case.
CGOpenMPRuntime::StaticRTInput StaticInit(
IVSize, IVSigned, Ordered, IL.getAddress(), LB.getAddress(),
UB.getAddress(), ST.getAddress(),
StaticChunkedOne ? Chunk : nullptr);
RT.emitForStaticInit(*this, S.getBeginLoc(), S.getDirectiveKind(),
ScheduleKind, StaticInit);
JumpDest LoopExit =
getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit"));
// UB = min(UB, GlobalUB);
if (!StaticChunkedOne)
EmitIgnoredExpr(S.getEnsureUpperBound());
// IV = LB;
EmitIgnoredExpr(S.getInit());
// For unchunked static schedule generate:
//
// while (idx <= UB) {
// BODY;
// ++idx;
// }
//
// For static schedule with chunk one:
//
// while (IV <= PrevUB) {
// BODY;
// IV += ST;
// }
EmitOMPInnerLoop(S, LoopScope.requiresCleanups(),
StaticChunkedOne ? S.getCombinedParForInDistCond() : S.getCond(),
StaticChunkedOne ? S.getDistInc() : S.getInc(),
[&S, LoopExit](CodeGenFunction &CGF) {
CGF.EmitOMPLoopBody(S, LoopExit);
CGF.EmitStopPoint(&S);
},
[](CodeGenFunction &) {});
EmitBlock(LoopExit.getBlock());
// Tell the runtime we are done.
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getEndLoc(),
S.getDirectiveKind());
};
OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen);
} else {
const bool IsMonotonic =
Ordered || ScheduleKind.Schedule == OMPC_SCHEDULE_static ||
ScheduleKind.Schedule == OMPC_SCHEDULE_unknown ||
ScheduleKind.M1 == OMPC_SCHEDULE_MODIFIER_monotonic ||
ScheduleKind.M2 == OMPC_SCHEDULE_MODIFIER_monotonic;
// Emit the outer loop, which requests its work chunk [LB..UB] from
// runtime and runs the inner loop to process it.
const OMPLoopArguments LoopArguments(LB.getAddress(), UB.getAddress(),
ST.getAddress(), IL.getAddress(),
Chunk, EUB);
EmitOMPForOuterLoop(ScheduleKind, IsMonotonic, S, LoopScope, Ordered,
LoopArguments, CGDispatchBounds);
}
if (isOpenMPSimdDirective(S.getDirectiveKind())) {
EmitOMPSimdFinal(S, [IL, &S](CodeGenFunction &CGF) {
return CGF.Builder.CreateIsNotNull(
CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
});
}
EmitOMPReductionClauseFinal(
S, /*ReductionKind=*/isOpenMPSimdDirective(S.getDirectiveKind())
? /*Parallel and Simd*/ OMPD_parallel_for_simd
: /*Parallel only*/ OMPD_parallel);
// Emit post-update of the reduction variables if IsLastIter != 0.
emitPostUpdateForReductionClause(
*this, S, [IL, &S](CodeGenFunction &CGF) {
return CGF.Builder.CreateIsNotNull(
CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
});
// Emit final copy of the lastprivate variables if IsLastIter != 0.
if (HasLastprivateClause)
EmitOMPLastprivateClauseFinal(
S, isOpenMPSimdDirective(S.getDirectiveKind()),
Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getBeginLoc())));
}
EmitOMPLinearClauseFinal(S, [IL, &S](CodeGenFunction &CGF) {
return CGF.Builder.CreateIsNotNull(
CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
});
DoacrossCleanupScope.ForceCleanup();
// We're now done with the loop, so jump to the continuation block.
if (ContBlock) {
EmitBranch(ContBlock);
EmitBlock(ContBlock, /*IsFinished=*/true);
}
}
return HasLastprivateClause;
}
/// The following two functions generate expressions for the loop lower
/// and upper bounds in case of static and dynamic (dispatch) schedule
/// of the associated 'for' or 'distribute' loop.
static std::pair<LValue, LValue>
emitForLoopBounds(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
const auto &LS = cast<OMPLoopDirective>(S);
LValue LB =
EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getLowerBoundVariable()));
LValue UB =
EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getUpperBoundVariable()));
return {LB, UB};
}
/// When dealing with dispatch schedules (e.g. dynamic, guided) we do not
/// consider the lower and upper bound expressions generated by the
/// worksharing loop support, but we use 0 and the iteration space size as
/// constants
static std::pair<llvm::Value *, llvm::Value *>
emitDispatchForLoopBounds(CodeGenFunction &CGF, const OMPExecutableDirective &S,
Address LB, Address UB) {
const auto &LS = cast<OMPLoopDirective>(S);
const Expr *IVExpr = LS.getIterationVariable();
const unsigned IVSize = CGF.getContext().getTypeSize(IVExpr->getType());
llvm::Value *LBVal = CGF.Builder.getIntN(IVSize, 0);
llvm::Value *UBVal = CGF.EmitScalarExpr(LS.getLastIteration());
return {LBVal, UBVal};
}
void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) {
bool HasLastprivates = false;
auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF,
PrePostActionTy &) {
OMPCancelStackRAII CancelRegion(CGF, OMPD_for, S.hasCancel());
HasLastprivates = CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
emitForLoopBounds,
emitDispatchForLoopBounds);
};
{
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_for, CodeGen,
S.hasCancel());
}
// Emit an implicit barrier at the end.
if (!S.getSingleClause<OMPNowaitClause>() || HasLastprivates)
CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_for);
}
void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &S) {
bool HasLastprivates = false;
auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF,
PrePostActionTy &) {
HasLastprivates = CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
emitForLoopBounds,
emitDispatchForLoopBounds);
};
{
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
}
// Emit an implicit barrier at the end.
if (!S.getSingleClause<OMPNowaitClause>() || HasLastprivates)
CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_for);
}
static LValue createSectionLVal(CodeGenFunction &CGF, QualType Ty,
const Twine &Name,
llvm::Value *Init = nullptr) {
LValue LVal = CGF.MakeAddrLValue(CGF.CreateMemTemp(Ty, Name), Ty);
if (Init)
CGF.EmitStoreThroughLValue(RValue::get(Init), LVal, /*isInit*/ true);
return LVal;
}
void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
const Stmt *CapturedStmt = S.getInnermostCapturedStmt()->getCapturedStmt();
const auto *CS = dyn_cast<CompoundStmt>(CapturedStmt);
bool HasLastprivates = false;
auto &&CodeGen = [&S, CapturedStmt, CS,
&HasLastprivates](CodeGenFunction &CGF, PrePostActionTy &) {
ASTContext &C = CGF.getContext();
QualType KmpInt32Ty =
C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
// Emit helper vars inits.
LValue LB = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.lb.",
CGF.Builder.getInt32(0));
llvm::ConstantInt *GlobalUBVal = CS != nullptr
? CGF.Builder.getInt32(CS->size() - 1)
: CGF.Builder.getInt32(0);
LValue UB =
createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.ub.", GlobalUBVal);
LValue ST = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.st.",
CGF.Builder.getInt32(1));
LValue IL = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.il.",
CGF.Builder.getInt32(0));
// Loop counter.
LValue IV = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.iv.");
OpaqueValueExpr IVRefExpr(S.getBeginLoc(), KmpInt32Ty, VK_LValue);
CodeGenFunction::OpaqueValueMapping OpaqueIV(CGF, &IVRefExpr, IV);
OpaqueValueExpr UBRefExpr(S.getBeginLoc(), KmpInt32Ty, VK_LValue);
CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB);
// Generate condition for loop.
BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue,
OK_Ordinary, S.getBeginLoc(), FPOptions());
// Increment for loop counter.
UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
S.getBeginLoc(), true);
auto &&BodyGen = [CapturedStmt, CS, &S, &IV](CodeGenFunction &CGF) {
// Iterate through all sections and emit a switch construct:
// switch (IV) {
// case 0:
// <SectionStmt[0]>;
// break;
// ...
// case <NumSection> - 1:
// <SectionStmt[<NumSection> - 1]>;
// break;
// }
// .omp.sections.exit:
llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".omp.sections.exit");
llvm::SwitchInst *SwitchStmt =
CGF.Builder.CreateSwitch(CGF.EmitLoadOfScalar(IV, S.getBeginLoc()),
ExitBB, CS == nullptr ? 1 : CS->size());
if (CS) {
unsigned CaseNumber = 0;
for (const Stmt *SubStmt : CS->children()) {
auto CaseBB = CGF.createBasicBlock(".omp.sections.case");
CGF.EmitBlock(CaseBB);
SwitchStmt->addCase(CGF.Builder.getInt32(CaseNumber), CaseBB);
CGF.EmitStmt(SubStmt);
CGF.EmitBranch(ExitBB);
++CaseNumber;
}
} else {
llvm::BasicBlock *CaseBB = CGF.createBasicBlock(".omp.sections.case");
CGF.EmitBlock(CaseBB);
SwitchStmt->addCase(CGF.Builder.getInt32(0), CaseBB);
CGF.EmitStmt(CapturedStmt);
CGF.EmitBranch(ExitBB);
}
CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
};
CodeGenFunction::OMPPrivateScope LoopScope(CGF);
if (CGF.EmitOMPFirstprivateClause(S, LoopScope)) {
// Emit implicit barrier to synchronize threads and avoid data races on
// initialization of firstprivate variables and post-update of lastprivate
// variables.
CGF.CGM.getOpenMPRuntime().emitBarrierCall(
CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
/*ForceSimpleCall=*/true);
}
CGF.EmitOMPPrivateClause(S, LoopScope);
HasLastprivates = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
CGF.EmitOMPReductionClauseInit(S, LoopScope);
(void)LoopScope.Privatize();
if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
// Emit static non-chunked loop.
OpenMPScheduleTy ScheduleKind;
ScheduleKind.Schedule = OMPC_SCHEDULE_static;
CGOpenMPRuntime::StaticRTInput StaticInit(
/*IVSize=*/32, /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(),
LB.getAddress(), UB.getAddress(), ST.getAddress());
CGF.CGM.getOpenMPRuntime().emitForStaticInit(
CGF, S.getBeginLoc(), S.getDirectiveKind(), ScheduleKind, StaticInit);
// UB = min(UB, GlobalUB);
llvm::Value *UBVal = CGF.EmitLoadOfScalar(UB, S.getBeginLoc());
llvm::Value *MinUBGlobalUB = CGF.Builder.CreateSelect(
CGF.Builder.CreateICmpSLT(UBVal, GlobalUBVal), UBVal, GlobalUBVal);
CGF.EmitStoreOfScalar(MinUBGlobalUB, UB);
// IV = LB;
CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getBeginLoc()), IV);
// while (idx <= UB) { BODY; ++idx; }
CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen,
[](CodeGenFunction &) {});
// Tell the runtime we are done.
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getEndLoc(),
S.getDirectiveKind());
};
CGF.OMPCancelStack.emitExit(CGF, S.getDirectiveKind(), CodeGen);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
// Emit post-update of the reduction variables if IsLastIter != 0.
emitPostUpdateForReductionClause(CGF, S, [IL, &S](CodeGenFunction &CGF) {
return CGF.Builder.CreateIsNotNull(
CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
});
// Emit final copy of the lastprivate variables if IsLastIter != 0.
if (HasLastprivates)
CGF.EmitOMPLastprivateClauseFinal(
S, /*NoFinals=*/false,
CGF.Builder.CreateIsNotNull(
CGF.EmitLoadOfScalar(IL, S.getBeginLoc())));
};
bool HasCancel = false;
if (auto *OSD = dyn_cast<OMPSectionsDirective>(&S))
HasCancel = OSD->hasCancel();
else if (auto *OPSD = dyn_cast<OMPParallelSectionsDirective>(&S))
HasCancel = OPSD->hasCancel();
OMPCancelStackRAII CancelRegion(*this, S.getDirectiveKind(), HasCancel);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_sections, CodeGen,
HasCancel);
// Emit barrier for lastprivates only if 'sections' directive has 'nowait'
// clause. Otherwise the barrier will be generated by the codegen for the
// directive.
if (HasLastprivates && S.getSingleClause<OMPNowaitClause>()) {
// Emit implicit barrier to synchronize threads and avoid data races on
// initialization of firstprivate variables.
CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(),
OMPD_unknown);
}
}
void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) {
{
OMPLexicalScope Scope(*this, S, OMPD_unknown);
EmitSections(S);
}
// Emit an implicit barrier at the end.
if (!S.getSingleClause<OMPNowaitClause>()) {
CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(),
OMPD_sections);
}
}
void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
};
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_section, CodeGen,
S.hasCancel());
}
void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) {
llvm::SmallVector<const Expr *, 8> CopyprivateVars;
llvm::SmallVector<const Expr *, 8> DestExprs;
llvm::SmallVector<const Expr *, 8> SrcExprs;
llvm::SmallVector<const Expr *, 8> AssignmentOps;
// Check if there are any 'copyprivate' clauses associated with this
// 'single' construct.
// Build a list of copyprivate variables along with helper expressions
// (<source>, <destination>, <destination>=<source> expressions)
for (const auto *C : S.getClausesOfKind<OMPCopyprivateClause>()) {
CopyprivateVars.append(C->varlists().begin(), C->varlists().end());
DestExprs.append(C->destination_exprs().begin(),
C->destination_exprs().end());
SrcExprs.append(C->source_exprs().begin(), C->source_exprs().end());
AssignmentOps.append(C->assignment_ops().begin(),
C->assignment_ops().end());
}
// Emit code for 'single' region along with 'copyprivate' clauses
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
OMPPrivateScope SingleScope(CGF);
(void)CGF.EmitOMPFirstprivateClause(S, SingleScope);
CGF.EmitOMPPrivateClause(S, SingleScope);
(void)SingleScope.Privatize();
CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
};
{
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitSingleRegion(*this, CodeGen, S.getBeginLoc(),
CopyprivateVars, DestExprs,
SrcExprs, AssignmentOps);
}
// Emit an implicit barrier at the end (to avoid data race on firstprivate
// init or if no 'nowait' clause was specified and no 'copyprivate' clause).
if (!S.getSingleClause<OMPNowaitClause>() && CopyprivateVars.empty()) {
CGM.getOpenMPRuntime().emitBarrierCall(
*this, S.getBeginLoc(),
S.getSingleClause<OMPNowaitClause>() ? OMPD_unknown : OMPD_single);
}
}
void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
};
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc());
}
void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
};
const Expr *Hint = nullptr;
if (const auto *HintClause = S.getSingleClause<OMPHintClause>())
Hint = HintClause->getHint();
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitCriticalRegion(*this,
S.getDirectiveName().getAsString(),
CodeGen, S.getBeginLoc(), Hint);
}
void CodeGenFunction::EmitOMPParallelForDirective(
const OMPParallelForDirective &S) {
// Emit directive as a combined directive that consists of two implicit
// directives: 'parallel' with 'for' directive.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
OMPCancelStackRAII CancelRegion(CGF, OMPD_parallel_for, S.hasCancel());
CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
emitDispatchForLoopBounds);
};
emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen,
emitEmptyBoundParameters);
}
void CodeGenFunction::EmitOMPParallelForSimdDirective(
const OMPParallelForSimdDirective &S) {
// Emit directive as a combined directive that consists of two implicit
// directives: 'parallel' with 'for' directive.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
emitDispatchForLoopBounds);
};
emitCommonOMPParallelDirective(*this, S, OMPD_simd, CodeGen,
emitEmptyBoundParameters);
}
void CodeGenFunction::EmitOMPParallelSectionsDirective(
const OMPParallelSectionsDirective &S) {
// Emit directive as a combined directive that consists of two implicit
// directives: 'parallel' with 'sections' directive.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
CGF.EmitSections(S);
};
emitCommonOMPParallelDirective(*this, S, OMPD_sections, CodeGen,
emitEmptyBoundParameters);
}
void CodeGenFunction::EmitOMPTaskBasedDirective(
const OMPExecutableDirective &S, const OpenMPDirectiveKind CapturedRegion,
const RegionCodeGenTy &BodyGen, const TaskGenTy &TaskGen,
OMPTaskDataTy &Data) {
// Emit outlined function for task construct.
const CapturedStmt *CS = S.getCapturedStmt(CapturedRegion);
auto I = CS->getCapturedDecl()->param_begin();
auto PartId = std::next(I);
auto TaskT = std::next(I, 4);
// Check if the task is final
if (const auto *Clause = S.getSingleClause<OMPFinalClause>()) {
// If the condition constant folds and can be elided, try to avoid emitting
// the condition and the dead arm of the if/else.
const Expr *Cond = Clause->getCondition();
bool CondConstant;
if (ConstantFoldsToSimpleInteger(Cond, CondConstant))
Data.Final.setInt(CondConstant);
else
Data.Final.setPointer(EvaluateExprAsBool(Cond));
} else {
// By default the task is not final.
Data.Final.setInt(/*IntVal=*/false);
}
// Check if the task has 'priority' clause.
if (const auto *Clause = S.getSingleClause<OMPPriorityClause>()) {
const Expr *Prio = Clause->getPriority();
Data.Priority.setInt(/*IntVal=*/true);
Data.Priority.setPointer(EmitScalarConversion(
EmitScalarExpr(Prio), Prio->getType(),
getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1),
Prio->getExprLoc()));
}
// The first function argument for tasks is a thread id, the second one is a
// part id (0 for tied tasks, >=0 for untied task).
llvm::DenseSet<const VarDecl *> EmittedAsPrivate;
// Get list of private variables.
for (const auto *C : S.getClausesOfKind<OMPPrivateClause>()) {
auto IRef = C->varlist_begin();
for (const Expr *IInit : C->private_copies()) {
const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
Data.PrivateVars.push_back(*IRef);
Data.PrivateCopies.push_back(IInit);
}
++IRef;
}
}
EmittedAsPrivate.clear();
// Get list of firstprivate variables.
for (const auto *C : S.getClausesOfKind<OMPFirstprivateClause>()) {
auto IRef = C->varlist_begin();
auto IElemInitRef = C->inits().begin();
for (const Expr *IInit : C->private_copies()) {
const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
Data.FirstprivateVars.push_back(*IRef);
Data.FirstprivateCopies.push_back(IInit);
Data.FirstprivateInits.push_back(*IElemInitRef);
}
++IRef;
++IElemInitRef;
}
}
// Get list of lastprivate variables (for taskloops).
llvm::DenseMap<const VarDecl *, const DeclRefExpr *> LastprivateDstsOrigs;
for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) {
auto IRef = C->varlist_begin();
auto ID = C->destination_exprs().begin();
for (const Expr *IInit : C->private_copies()) {
const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl());
if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
Data.LastprivateVars.push_back(*IRef);
Data.LastprivateCopies.push_back(IInit);
}
LastprivateDstsOrigs.insert(
{cast<VarDecl>(cast<DeclRefExpr>(*ID)->getDecl()),
cast<DeclRefExpr>(*IRef)});
++IRef;
++ID;
}
}
SmallVector<const Expr *, 4> LHSs;
SmallVector<const Expr *, 4> RHSs;
for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
auto IPriv = C->privates().begin();
auto IRed = C->reduction_ops().begin();
auto ILHS = C->lhs_exprs().begin();
auto IRHS = C->rhs_exprs().begin();
for (const Expr *Ref : C->varlists()) {
Data.ReductionVars.emplace_back(Ref);
Data.ReductionCopies.emplace_back(*IPriv);
Data.ReductionOps.emplace_back(*IRed);
LHSs.emplace_back(*ILHS);
RHSs.emplace_back(*IRHS);
std::advance(IPriv, 1);
std::advance(IRed, 1);
std::advance(ILHS, 1);
std::advance(IRHS, 1);
}
}
Data.Reductions = CGM.getOpenMPRuntime().emitTaskReductionInit(
*this, S.getBeginLoc(), LHSs, RHSs, Data);
// Build list of dependences.
for (const auto *C : S.getClausesOfKind<OMPDependClause>())
for (const Expr *IRef : C->varlists())
Data.Dependences.emplace_back(C->getDependencyKind(), IRef);
auto &&CodeGen = [&Data, &S, CS, &BodyGen, &LastprivateDstsOrigs,
CapturedRegion](CodeGenFunction &CGF,
PrePostActionTy &Action) {
// Set proper addresses for generated private copies.
OMPPrivateScope Scope(CGF);
if (!Data.PrivateVars.empty() || !Data.FirstprivateVars.empty() ||
!Data.LastprivateVars.empty()) {
enum { PrivatesParam = 2, CopyFnParam = 3 };
llvm::Value *CopyFn = CGF.Builder.CreateLoad(
CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(CopyFnParam)));
llvm::Value *PrivatesPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(
CS->getCapturedDecl()->getParam(PrivatesParam)));
// Map privates.
llvm::SmallVector<std::pair<const VarDecl *, Address>, 16> PrivatePtrs;
llvm::SmallVector<llvm::Value *, 16> CallArgs;
CallArgs.push_back(PrivatesPtr);
for (const Expr *E : Data.PrivateVars) {
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
Address PrivatePtr = CGF.CreateMemTemp(
CGF.getContext().getPointerType(E->getType()), ".priv.ptr.addr");
PrivatePtrs.emplace_back(VD, PrivatePtr);
CallArgs.push_back(PrivatePtr.getPointer());
}
for (const Expr *E : Data.FirstprivateVars) {
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
Address PrivatePtr =
CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()),
".firstpriv.ptr.addr");
PrivatePtrs.emplace_back(VD, PrivatePtr);
CallArgs.push_back(PrivatePtr.getPointer());
}
for (const Expr *E : Data.LastprivateVars) {
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
Address PrivatePtr =
CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()),
".lastpriv.ptr.addr");
PrivatePtrs.emplace_back(VD, PrivatePtr);
CallArgs.push_back(PrivatePtr.getPointer());
}
CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, S.getBeginLoc(),
CopyFn, CallArgs);
for (const auto &Pair : LastprivateDstsOrigs) {
const auto *OrigVD = cast<VarDecl>(Pair.second->getDecl());
DeclRefExpr DRE(CGF.getContext(), const_cast<VarDecl *>(OrigVD),
/*RefersToEnclosingVariableOrCapture=*/
CGF.CapturedStmtInfo->lookup(OrigVD) != nullptr,
Pair.second->getType(), VK_LValue,
Pair.second->getExprLoc());
Scope.addPrivate(Pair.first, [&CGF, &DRE]() {
return CGF.EmitLValue(&DRE).getAddress();
});
}
for (const auto &Pair : PrivatePtrs) {
Address Replacement(CGF.Builder.CreateLoad(Pair.second),
CGF.getContext().getDeclAlign(Pair.first));
Scope.addPrivate(Pair.first, [Replacement]() { return Replacement; });
}
}
if (Data.Reductions) {
OMPLexicalScope LexScope(CGF, S, CapturedRegion);
ReductionCodeGen RedCG(Data.ReductionVars, Data.ReductionCopies,
Data.ReductionOps);
llvm::Value *ReductionsPtr = CGF.Builder.CreateLoad(
CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(9)));
for (unsigned Cnt = 0, E = Data.ReductionVars.size(); Cnt < E; ++Cnt) {
RedCG.emitSharedLValue(CGF, Cnt);
RedCG.emitAggregateType(CGF, Cnt);
// FIXME: This must removed once the runtime library is fixed.
// Emit required threadprivate variables for
// initializer/combiner/finalizer.
CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(),
RedCG, Cnt);
Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
Replacement =
Address(CGF.EmitScalarConversion(
Replacement.getPointer(), CGF.getContext().VoidPtrTy,
CGF.getContext().getPointerType(
Data.ReductionCopies[Cnt]->getType()),
Data.ReductionCopies[Cnt]->getExprLoc()),
Replacement.getAlignment());
Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
Scope.addPrivate(RedCG.getBaseDecl(Cnt),
[Replacement]() { return Replacement; });
}
}
// Privatize all private variables except for in_reduction items.
(void)Scope.Privatize();
SmallVector<const Expr *, 4> InRedVars;
SmallVector<const Expr *, 4> InRedPrivs;
SmallVector<const Expr *, 4> InRedOps;
SmallVector<const Expr *, 4> TaskgroupDescriptors;
for (const auto *C : S.getClausesOfKind<OMPInReductionClause>()) {
auto IPriv = C->privates().begin();
auto IRed = C->reduction_ops().begin();
auto ITD = C->taskgroup_descriptors().begin();
for (const Expr *Ref : C->varlists()) {
InRedVars.emplace_back(Ref);
InRedPrivs.emplace_back(*IPriv);
InRedOps.emplace_back(*IRed);
TaskgroupDescriptors.emplace_back(*ITD);
std::advance(IPriv, 1);
std::advance(IRed, 1);
std::advance(ITD, 1);
}
}
// Privatize in_reduction items here, because taskgroup descriptors must be
// privatized earlier.
OMPPrivateScope InRedScope(CGF);
if (!InRedVars.empty()) {
ReductionCodeGen RedCG(InRedVars, InRedPrivs, InRedOps);
for (unsigned Cnt = 0, E = InRedVars.size(); Cnt < E; ++Cnt) {
RedCG.emitSharedLValue(CGF, Cnt);
RedCG.emitAggregateType(CGF, Cnt);
// The taskgroup descriptor variable is always implicit firstprivate and
// privatized already during processing of the firstprivates.
// FIXME: This must removed once the runtime library is fixed.
// Emit required threadprivate variables for
// initializer/combiner/finalizer.
CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(),
RedCG, Cnt);
llvm::Value *ReductionsPtr =
CGF.EmitLoadOfScalar(CGF.EmitLValue(TaskgroupDescriptors[Cnt]),
TaskgroupDescriptors[Cnt]->getExprLoc());
Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
Replacement = Address(
CGF.EmitScalarConversion(
Replacement.getPointer(), CGF.getContext().VoidPtrTy,
CGF.getContext().getPointerType(InRedPrivs[Cnt]->getType()),
InRedPrivs[Cnt]->getExprLoc()),
Replacement.getAlignment());
Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
InRedScope.addPrivate(RedCG.getBaseDecl(Cnt),
[Replacement]() { return Replacement; });
}
}
(void)InRedScope.Privatize();
Action.Enter(CGF);
BodyGen(CGF);
};
llvm::Value *OutlinedFn = CGM.getOpenMPRuntime().emitTaskOutlinedFunction(
S, *I, *PartId, *TaskT, S.getDirectiveKind(), CodeGen, Data.Tied,
Data.NumberOfParts);
OMPLexicalScope Scope(*this, S);
TaskGen(*this, OutlinedFn, Data);
}
static ImplicitParamDecl *
createImplicitFirstprivateForType(ASTContext &C, OMPTaskDataTy &Data,
QualType Ty, CapturedDecl *CD,
SourceLocation Loc) {
auto *OrigVD = ImplicitParamDecl::Create(C, CD, Loc, /*Id=*/nullptr, Ty,
ImplicitParamDecl::Other);
auto *OrigRef = DeclRefExpr::Create(
C, NestedNameSpecifierLoc(), SourceLocation(), OrigVD,
/*RefersToEnclosingVariableOrCapture=*/false, Loc, Ty, VK_LValue);
auto *PrivateVD = ImplicitParamDecl::Create(C, CD, Loc, /*Id=*/nullptr, Ty,
ImplicitParamDecl::Other);
auto *PrivateRef = DeclRefExpr::Create(
C, NestedNameSpecifierLoc(), SourceLocation(), PrivateVD,
/*RefersToEnclosingVariableOrCapture=*/false, Loc, Ty, VK_LValue);
QualType ElemType = C.getBaseElementType(Ty);
auto *InitVD = ImplicitParamDecl::Create(C, CD, Loc, /*Id=*/nullptr, ElemType,
ImplicitParamDecl::Other);
auto *InitRef = DeclRefExpr::Create(
C, NestedNameSpecifierLoc(), SourceLocation(), InitVD,
/*RefersToEnclosingVariableOrCapture=*/false, Loc, ElemType, VK_LValue);
PrivateVD->setInitStyle(VarDecl::CInit);
PrivateVD->setInit(ImplicitCastExpr::Create(C, ElemType, CK_LValueToRValue,
InitRef, /*BasePath=*/nullptr,
VK_RValue));
Data.FirstprivateVars.emplace_back(OrigRef);
Data.FirstprivateCopies.emplace_back(PrivateRef);
Data.FirstprivateInits.emplace_back(InitRef);
return OrigVD;
}
void CodeGenFunction::EmitOMPTargetTaskBasedDirective(
const OMPExecutableDirective &S, const RegionCodeGenTy &BodyGen,
OMPTargetDataInfo &InputInfo) {
// Emit outlined function for task construct.
const CapturedStmt *CS = S.getCapturedStmt(OMPD_task);
Address CapturedStruct = GenerateCapturedStmtArgument(*CS);
QualType SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl());
auto I = CS->getCapturedDecl()->param_begin();
auto PartId = std::next(I);
auto TaskT = std::next(I, 4);
OMPTaskDataTy Data;
// The task is not final.
Data.Final.setInt(/*IntVal=*/false);
// Get list of firstprivate variables.
for (const auto *C : S.getClausesOfKind<OMPFirstprivateClause>()) {
auto IRef = C->varlist_begin();
auto IElemInitRef = C->inits().begin();
for (auto *IInit : C->private_copies()) {
Data.FirstprivateVars.push_back(*IRef);
Data.FirstprivateCopies.push_back(IInit);
Data.FirstprivateInits.push_back(*IElemInitRef);
++IRef;
++IElemInitRef;
}
}
OMPPrivateScope TargetScope(*this);
VarDecl *BPVD = nullptr;
VarDecl *PVD = nullptr;
VarDecl *SVD = nullptr;
if (InputInfo.NumberOfTargetItems > 0) {
auto *CD = CapturedDecl::Create(
getContext(), getContext().getTranslationUnitDecl(), /*NumParams=*/0);
llvm::APInt ArrSize(/*numBits=*/32, InputInfo.NumberOfTargetItems);
QualType BaseAndPointersType = getContext().getConstantArrayType(
getContext().VoidPtrTy, ArrSize, ArrayType::Normal,
/*IndexTypeQuals=*/0);
BPVD = createImplicitFirstprivateForType(
getContext(), Data, BaseAndPointersType, CD, S.getBeginLoc());
PVD = createImplicitFirstprivateForType(
getContext(), Data, BaseAndPointersType, CD, S.getBeginLoc());
QualType SizesType = getContext().getConstantArrayType(
getContext().getSizeType(), ArrSize, ArrayType::Normal,
/*IndexTypeQuals=*/0);
SVD = createImplicitFirstprivateForType(getContext(), Data, SizesType, CD,
S.getBeginLoc());
TargetScope.addPrivate(
BPVD, [&InputInfo]() { return InputInfo.BasePointersArray; });
TargetScope.addPrivate(PVD,
[&InputInfo]() { return InputInfo.PointersArray; });
TargetScope.addPrivate(SVD,
[&InputInfo]() { return InputInfo.SizesArray; });
}
(void)TargetScope.Privatize();
// Build list of dependences.
for (const auto *C : S.getClausesOfKind<OMPDependClause>())
for (const Expr *IRef : C->varlists())
Data.Dependences.emplace_back(C->getDependencyKind(), IRef);
auto &&CodeGen = [&Data, &S, CS, &BodyGen, BPVD, PVD, SVD,
&InputInfo](CodeGenFunction &CGF, PrePostActionTy &Action) {
// Set proper addresses for generated private copies.
OMPPrivateScope Scope(CGF);
if (!Data.FirstprivateVars.empty()) {
enum { PrivatesParam = 2, CopyFnParam = 3 };
llvm::Value *CopyFn = CGF.Builder.CreateLoad(
CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(CopyFnParam)));
llvm::Value *PrivatesPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(
CS->getCapturedDecl()->getParam(PrivatesParam)));
// Map privates.
llvm::SmallVector<std::pair<const VarDecl *, Address>, 16> PrivatePtrs;
llvm::SmallVector<llvm::Value *, 16> CallArgs;
CallArgs.push_back(PrivatesPtr);
for (const Expr *E : Data.FirstprivateVars) {
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
Address PrivatePtr =
CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()),
".firstpriv.ptr.addr");
PrivatePtrs.emplace_back(VD, PrivatePtr);
CallArgs.push_back(PrivatePtr.getPointer());
}
CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, S.getBeginLoc(),
CopyFn, CallArgs);
for (const auto &Pair : PrivatePtrs) {
Address Replacement(CGF.Builder.CreateLoad(Pair.second),
CGF.getContext().getDeclAlign(Pair.first));
Scope.addPrivate(Pair.first, [Replacement]() { return Replacement; });
}
}
// Privatize all private variables except for in_reduction items.
(void)Scope.Privatize();
if (InputInfo.NumberOfTargetItems > 0) {
InputInfo.BasePointersArray = CGF.Builder.CreateConstArrayGEP(
CGF.GetAddrOfLocalVar(BPVD), /*Index=*/0, CGF.getPointerSize());
InputInfo.PointersArray = CGF.Builder.CreateConstArrayGEP(
CGF.GetAddrOfLocalVar(PVD), /*Index=*/0, CGF.getPointerSize());
InputInfo.SizesArray = CGF.Builder.CreateConstArrayGEP(
CGF.GetAddrOfLocalVar(SVD), /*Index=*/0, CGF.getSizeSize());
}
Action.Enter(CGF);
OMPLexicalScope LexScope(CGF, S, OMPD_task, /*EmitPreInitStmt=*/false);
BodyGen(CGF);
};
llvm::Value *OutlinedFn = CGM.getOpenMPRuntime().emitTaskOutlinedFunction(
S, *I, *PartId, *TaskT, S.getDirectiveKind(), CodeGen, /*Tied=*/true,
Data.NumberOfParts);
llvm::APInt TrueOrFalse(32, S.hasClausesOfKind<OMPNowaitClause>() ? 1 : 0);
IntegerLiteral IfCond(getContext(), TrueOrFalse,
getContext().getIntTypeForBitwidth(32, /*Signed=*/0),
SourceLocation());
CGM.getOpenMPRuntime().emitTaskCall(*this, S.getBeginLoc(), S, OutlinedFn,
SharedsTy, CapturedStruct, &IfCond, Data);
}
void CodeGenFunction::EmitOMPTaskDirective(const OMPTaskDirective &S) {
// Emit outlined function for task construct.
const CapturedStmt *CS = S.getCapturedStmt(OMPD_task);
Address CapturedStruct = GenerateCapturedStmtArgument(*CS);
QualType SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl());
const Expr *IfCond = nullptr;
for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
if (C->getNameModifier() == OMPD_unknown ||
C->getNameModifier() == OMPD_task) {
IfCond = C->getCondition();
break;
}
}
OMPTaskDataTy Data;
// Check if we should emit tied or untied task.
Data.Tied = !S.getSingleClause<OMPUntiedClause>();
auto &&BodyGen = [CS](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitStmt(CS->getCapturedStmt());
};
auto &&TaskGen = [&S, SharedsTy, CapturedStruct,
IfCond](CodeGenFunction &CGF, llvm::Value *OutlinedFn,
const OMPTaskDataTy &Data) {
CGF.CGM.getOpenMPRuntime().emitTaskCall(CGF, S.getBeginLoc(), S, OutlinedFn,
SharedsTy, CapturedStruct, IfCond,
Data);
};
EmitOMPTaskBasedDirective(S, OMPD_task, BodyGen, TaskGen, Data);
}
void CodeGenFunction::EmitOMPTaskyieldDirective(
const OMPTaskyieldDirective &S) {
CGM.getOpenMPRuntime().emitTaskyieldCall(*this, S.getBeginLoc());
}
void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) {
CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_barrier);
}
void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) {
CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getBeginLoc());
}
void CodeGenFunction::EmitOMPTaskgroupDirective(
const OMPTaskgroupDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
if (const Expr *E = S.getReductionRef()) {
SmallVector<const Expr *, 4> LHSs;
SmallVector<const Expr *, 4> RHSs;
OMPTaskDataTy Data;
for (const auto *C : S.getClausesOfKind<OMPTaskReductionClause>()) {
auto IPriv = C->privates().begin();
auto IRed = C->reduction_ops().begin();
auto ILHS = C->lhs_exprs().begin();
auto IRHS = C->rhs_exprs().begin();
for (const Expr *Ref : C->varlists()) {
Data.ReductionVars.emplace_back(Ref);
Data.ReductionCopies.emplace_back(*IPriv);
Data.ReductionOps.emplace_back(*IRed);
LHSs.emplace_back(*ILHS);
RHSs.emplace_back(*IRHS);
std::advance(IPriv, 1);
std::advance(IRed, 1);
std::advance(ILHS, 1);
std::advance(IRHS, 1);
}
}
llvm::Value *ReductionDesc =
CGF.CGM.getOpenMPRuntime().emitTaskReductionInit(CGF, S.getBeginLoc(),
LHSs, RHSs, Data);
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
CGF.EmitVarDecl(*VD);
CGF.EmitStoreOfScalar(ReductionDesc, CGF.GetAddrOfLocalVar(VD),
/*Volatile=*/false, E->getType());
}
CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
};
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitTaskgroupRegion(*this, CodeGen, S.getBeginLoc());
}
void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) {
CGM.getOpenMPRuntime().emitFlush(
*this,
[&S]() -> ArrayRef<const Expr *> {
if (const auto *FlushClause = S.getSingleClause<OMPFlushClause>())
return llvm::makeArrayRef(FlushClause->varlist_begin(),
FlushClause->varlist_end());
return llvm::None;
}(),
S.getBeginLoc());
}
void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S,
const CodeGenLoopTy &CodeGenLoop,
Expr *IncExpr) {
// Emit the loop iteration variable.
const auto *IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
const auto *IVDecl = cast<VarDecl>(IVExpr->getDecl());
EmitVarDecl(*IVDecl);
// Emit the iterations count variable.
// If it is not a variable, Sema decided to calculate iterations count on each
// iteration (e.g., it is foldable into a constant).
if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
// Emit calculation of the iterations count.
EmitIgnoredExpr(S.getCalcLastIteration());
}
CGOpenMPRuntime &RT = CGM.getOpenMPRuntime();
bool HasLastprivateClause = false;
// Check pre-condition.
{
OMPLoopScope PreInitScope(*this, S);
// Skip the entire loop if we don't meet the precondition.
// If the condition constant folds and can be elided, avoid emitting the
// whole loop.
bool CondConstant;
llvm::BasicBlock *ContBlock = nullptr;
if (ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
if (!CondConstant)
return;
} else {
llvm::BasicBlock *ThenBlock = createBasicBlock("omp.precond.then");
ContBlock = createBasicBlock("omp.precond.end");
emitPreCond(*this, S, S.getPreCond(), ThenBlock, ContBlock,
getProfileCount(&S));
EmitBlock(ThenBlock);
incrementProfileCounter(&S);
}
emitAlignedClause(*this, S);
// Emit 'then' code.
{
// Emit helper vars inits.
LValue LB = EmitOMPHelperVar(
*this, cast<DeclRefExpr>(
(isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
? S.getCombinedLowerBoundVariable()
: S.getLowerBoundVariable())));
LValue UB = EmitOMPHelperVar(
*this, cast<DeclRefExpr>(
(isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
? S.getCombinedUpperBoundVariable()
: S.getUpperBoundVariable())));
LValue ST =
EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
LValue IL =
EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getIsLastIterVariable()));
OMPPrivateScope LoopScope(*this);
if (EmitOMPFirstprivateClause(S, LoopScope)) {
// Emit implicit barrier to synchronize threads and avoid data races
// on initialization of firstprivate variables and post-update of
// lastprivate variables.
CGM.getOpenMPRuntime().emitBarrierCall(
*this, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
/*ForceSimpleCall=*/true);
}
EmitOMPPrivateClause(S, LoopScope);
if (isOpenMPSimdDirective(S.getDirectiveKind()) &&
!isOpenMPParallelDirective(S.getDirectiveKind()) &&
!isOpenMPTeamsDirective(S.getDirectiveKind()))
EmitOMPReductionClauseInit(S, LoopScope);
HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope);
EmitOMPPrivateLoopCounters(S, LoopScope);
(void)LoopScope.Privatize();
if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(*this, S);
// Detect the distribute schedule kind and chunk.
llvm::Value *Chunk = nullptr;
OpenMPDistScheduleClauseKind ScheduleKind = OMPC_DIST_SCHEDULE_unknown;
if (const auto *C = S.getSingleClause<OMPDistScheduleClause>()) {
ScheduleKind = C->getDistScheduleKind();
if (const Expr *Ch = C->getChunkSize()) {
Chunk = EmitScalarExpr(Ch);
Chunk = EmitScalarConversion(Chunk, Ch->getType(),
S.getIterationVariable()->getType(),
S.getBeginLoc());
}
} else {
// Default behaviour for dist_schedule clause.
CGM.getOpenMPRuntime().getDefaultDistScheduleAndChunk(
*this, S, ScheduleKind, Chunk);
}
const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
// OpenMP [2.10.8, distribute Construct, Description]
// If dist_schedule is specified, kind must be static. If specified,
// iterations are divided into chunks of size chunk_size, chunks are
// assigned to the teams of the league in a round-robin fashion in the
// order of the team number. When no chunk_size is specified, the
// iteration space is divided into chunks that are approximately equal
// in size, and at most one chunk is distributed to each team of the
// league. The size of the chunks is unspecified in this case.
bool StaticChunked = RT.isStaticChunked(
ScheduleKind, /* Chunked */ Chunk != nullptr) &&
isOpenMPLoopBoundSharingDirective(S.getDirectiveKind());
if (RT.isStaticNonchunked(ScheduleKind,
/* Chunked */ Chunk != nullptr) ||
StaticChunked) {
if (isOpenMPSimdDirective(S.getDirectiveKind()))
EmitOMPSimdInit(S, /*IsMonotonic=*/true);
CGOpenMPRuntime::StaticRTInput StaticInit(
IVSize, IVSigned, /* Ordered = */ false, IL.getAddress(),
LB.getAddress(), UB.getAddress(), ST.getAddress(),
StaticChunked ? Chunk : nullptr);
RT.emitDistributeStaticInit(*this, S.getBeginLoc(), ScheduleKind,
StaticInit);
JumpDest LoopExit =
getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit"));
// UB = min(UB, GlobalUB);
EmitIgnoredExpr(isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
? S.getCombinedEnsureUpperBound()
: S.getEnsureUpperBound());
// IV = LB;
EmitIgnoredExpr(isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
? S.getCombinedInit()
: S.getInit());
const Expr *Cond =
isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
? S.getCombinedCond()
: S.getCond();
if (StaticChunked)
Cond = S.getCombinedDistCond();
// For static unchunked schedules generate:
//
// 1. For distribute alone, codegen
// while (idx <= UB) {
// BODY;
// ++idx;
// }
//
// 2. When combined with 'for' (e.g. as in 'distribute parallel for')
// while (idx <= UB) {
// <CodeGen rest of pragma>(LB, UB);
// idx += ST;
// }
//
// For static chunk one schedule generate:
//
// while (IV <= GlobalUB) {
// <CodeGen rest of pragma>(LB, UB);
// LB += ST;
// UB += ST;
// UB = min(UB, GlobalUB);
// IV = LB;
// }
//
EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), Cond, IncExpr,
[&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
CodeGenLoop(CGF, S, LoopExit);
},
[&S, StaticChunked](CodeGenFunction &CGF) {
if (StaticChunked) {
CGF.EmitIgnoredExpr(S.getCombinedNextLowerBound());
CGF.EmitIgnoredExpr(S.getCombinedNextUpperBound());
CGF.EmitIgnoredExpr(S.getCombinedEnsureUpperBound());
CGF.EmitIgnoredExpr(S.getCombinedInit());
}
});
EmitBlock(LoopExit.getBlock());
// Tell the runtime we are done.
RT.emitForStaticFinish(*this, S.getBeginLoc(), S.getDirectiveKind());
} else {
// Emit the outer loop, which requests its work chunk [LB..UB] from
// runtime and runs the inner loop to process it.
const OMPLoopArguments LoopArguments = {
LB.getAddress(), UB.getAddress(), ST.getAddress(), IL.getAddress(),
Chunk};
EmitOMPDistributeOuterLoop(ScheduleKind, S, LoopScope, LoopArguments,
CodeGenLoop);
}
if (isOpenMPSimdDirective(S.getDirectiveKind())) {
EmitOMPSimdFinal(S, [IL, &S](CodeGenFunction &CGF) {
return CGF.Builder.CreateIsNotNull(
CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
});
}
if (isOpenMPSimdDirective(S.getDirectiveKind()) &&
!isOpenMPParallelDirective(S.getDirectiveKind()) &&
!isOpenMPTeamsDirective(S.getDirectiveKind())) {
EmitOMPReductionClauseFinal(S, OMPD_simd);
// Emit post-update of the reduction variables if IsLastIter != 0.
emitPostUpdateForReductionClause(
*this, S, [IL, &S](CodeGenFunction &CGF) {
return CGF.Builder.CreateIsNotNull(
CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
});
}
// Emit final copy of the lastprivate variables if IsLastIter != 0.
if (HasLastprivateClause) {
EmitOMPLastprivateClauseFinal(
S, /*NoFinals=*/false,
Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getBeginLoc())));
}
}
// We're now done with the loop, so jump to the continuation block.
if (ContBlock) {
EmitBranch(ContBlock);
EmitBlock(ContBlock, true);
}
}
}
void CodeGenFunction::EmitOMPDistributeDirective(
const OMPDistributeDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
};
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen);
}
static llvm::Function *emitOutlinedOrderedFunction(CodeGenModule &CGM,
const CapturedStmt *S) {
CodeGenFunction CGF(CGM, /*suppressNewContext=*/true);
CodeGenFunction::CGCapturedStmtInfo CapStmtInfo;
CGF.CapturedStmtInfo = &CapStmtInfo;
llvm::Function *Fn = CGF.GenerateOpenMPCapturedStmtFunction(*S);
Fn->setDoesNotRecurse();
return Fn;
}
void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) {
if (S.hasClausesOfKind<OMPDependClause>()) {
assert(!S.getAssociatedStmt() &&
"No associated statement must be in ordered depend construct.");
for (const auto *DC : S.getClausesOfKind<OMPDependClause>())
CGM.getOpenMPRuntime().emitDoacrossOrdered(*this, DC);
return;
}
const auto *C = S.getSingleClause<OMPSIMDClause>();
auto &&CodeGen = [&S, C, this](CodeGenFunction &CGF,
PrePostActionTy &Action) {
const CapturedStmt *CS = S.getInnermostCapturedStmt();
if (C) {
llvm::SmallVector<llvm::Value *, 16> CapturedVars;
CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
llvm::Function *OutlinedFn = emitOutlinedOrderedFunction(CGM, CS);
CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, S.getBeginLoc(),
OutlinedFn, CapturedVars);
} else {
Action.Enter(CGF);
CGF.EmitStmt(CS->getCapturedStmt());
}
};
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitOrderedRegion(*this, CodeGen, S.getBeginLoc(), !C);
}
static llvm::Value *convertToScalarValue(CodeGenFunction &CGF, RValue Val,
QualType SrcType, QualType DestType,
SourceLocation Loc) {
assert(CGF.hasScalarEvaluationKind(DestType) &&
"DestType must have scalar evaluation kind.");
assert(!Val.isAggregate() && "Must be a scalar or complex.");
return Val.isScalar() ? CGF.EmitScalarConversion(Val.getScalarVal(), SrcType,
DestType, Loc)
: CGF.EmitComplexToScalarConversion(
Val.getComplexVal(), SrcType, DestType, Loc);
}
static CodeGenFunction::ComplexPairTy
convertToComplexValue(CodeGenFunction &CGF, RValue Val, QualType SrcType,
QualType DestType, SourceLocation Loc) {
assert(CGF.getEvaluationKind(DestType) == TEK_Complex &&
"DestType must have complex evaluation kind.");
CodeGenFunction::ComplexPairTy ComplexVal;
if (Val.isScalar()) {
// Convert the input element to the element type of the complex.
QualType DestElementType =
DestType->castAs<ComplexType>()->getElementType();
llvm::Value *ScalarVal = CGF.EmitScalarConversion(
Val.getScalarVal(), SrcType, DestElementType, Loc);
ComplexVal = CodeGenFunction::ComplexPairTy(
ScalarVal, llvm::Constant::getNullValue(ScalarVal->getType()));
} else {
assert(Val.isComplex() && "Must be a scalar or complex.");
QualType SrcElementType = SrcType->castAs<ComplexType>()->getElementType();
QualType DestElementType =
DestType->castAs<ComplexType>()->getElementType();
ComplexVal.first = CGF.EmitScalarConversion(
Val.getComplexVal().first, SrcElementType, DestElementType, Loc);
ComplexVal.second = CGF.EmitScalarConversion(
Val.getComplexVal().second, SrcElementType, DestElementType, Loc);
}
return ComplexVal;
}
static void emitSimpleAtomicStore(CodeGenFunction &CGF, bool IsSeqCst,
LValue LVal, RValue RVal) {
if (LVal.isGlobalReg()) {
CGF.EmitStoreThroughGlobalRegLValue(RVal, LVal);
} else {
CGF.EmitAtomicStore(RVal, LVal,
IsSeqCst ? llvm::AtomicOrdering::SequentiallyConsistent
: llvm::AtomicOrdering::Monotonic,
LVal.isVolatile(), /*IsInit=*/false);
}
}
void CodeGenFunction::emitOMPSimpleStore(LValue LVal, RValue RVal,
QualType RValTy, SourceLocation Loc) {
switch (getEvaluationKind(LVal.getType())) {
case TEK_Scalar:
EmitStoreThroughLValue(RValue::get(convertToScalarValue(
*this, RVal, RValTy, LVal.getType(), Loc)),
LVal);
break;
case TEK_Complex:
EmitStoreOfComplex(
convertToComplexValue(*this, RVal, RValTy, LVal.getType(), Loc), LVal,
/*isInit=*/false);
break;
case TEK_Aggregate:
llvm_unreachable("Must be a scalar or complex.");
}
}
static void emitOMPAtomicReadExpr(CodeGenFunction &CGF, bool IsSeqCst,
const Expr *X, const Expr *V,
SourceLocation Loc) {
// v = x;
assert(V->isLValue() && "V of 'omp atomic read' is not lvalue");
assert(X->isLValue() && "X of 'omp atomic read' is not lvalue");
LValue XLValue = CGF.EmitLValue(X);
LValue VLValue = CGF.EmitLValue(V);
RValue Res = XLValue.isGlobalReg()
? CGF.EmitLoadOfLValue(XLValue, Loc)
: CGF.EmitAtomicLoad(
XLValue, Loc,
IsSeqCst ? llvm::AtomicOrdering::SequentiallyConsistent
: llvm::AtomicOrdering::Monotonic,
XLValue.isVolatile());
// OpenMP, 2.12.6, atomic Construct
// Any atomic construct with a seq_cst clause forces the atomically
// performed operation to include an implicit flush operation without a
// list.
if (IsSeqCst)
CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc);
CGF.emitOMPSimpleStore(VLValue, Res, X->getType().getNonReferenceType(), Loc);
}
static void emitOMPAtomicWriteExpr(CodeGenFunction &CGF, bool IsSeqCst,
const Expr *X, const Expr *E,
SourceLocation Loc) {
// x = expr;
assert(X->isLValue() && "X of 'omp atomic write' is not lvalue");
emitSimpleAtomicStore(CGF, IsSeqCst, CGF.EmitLValue(X), CGF.EmitAnyExpr(E));
// OpenMP, 2.12.6, atomic Construct
// Any atomic construct with a seq_cst clause forces the atomically
// performed operation to include an implicit flush operation without a
// list.
if (IsSeqCst)
CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc);
}
static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X,
RValue Update,
BinaryOperatorKind BO,
llvm::AtomicOrdering AO,
bool IsXLHSInRHSPart) {
ASTContext &Context = CGF.getContext();
// Allow atomicrmw only if 'x' and 'update' are integer values, lvalue for 'x'
// expression is simple and atomic is allowed for the given type for the
// target platform.
if (BO == BO_Comma || !Update.isScalar() ||
!Update.getScalarVal()->getType()->isIntegerTy() ||
!X.isSimple() || (!isa<llvm::ConstantInt>(Update.getScalarVal()) &&
(Update.getScalarVal()->getType() !=
X.getAddress().getElementType())) ||
!X.getAddress().getElementType()->isIntegerTy() ||
!Context.getTargetInfo().hasBuiltinAtomic(
Context.getTypeSize(X.getType()), Context.toBits(X.getAlignment())))
return std::make_pair(false, RValue::get(nullptr));
llvm::AtomicRMWInst::BinOp RMWOp;
switch (BO) {
case BO_Add:
RMWOp = llvm::AtomicRMWInst::Add;
break;
case BO_Sub:
if (!IsXLHSInRHSPart)
return std::make_pair(false, RValue::get(nullptr));
RMWOp = llvm::AtomicRMWInst::Sub;
break;
case BO_And:
RMWOp = llvm::AtomicRMWInst::And;
break;
case BO_Or:
RMWOp = llvm::AtomicRMWInst::Or;
break;
case BO_Xor:
RMWOp = llvm::AtomicRMWInst::Xor;
break;
case BO_LT:
RMWOp = X.getType()->hasSignedIntegerRepresentation()
? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Min
: llvm::AtomicRMWInst::Max)
: (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMin
: llvm::AtomicRMWInst::UMax);
break;
case BO_GT:
RMWOp = X.getType()->hasSignedIntegerRepresentation()
? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Max
: llvm::AtomicRMWInst::Min)
: (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMax
: llvm::AtomicRMWInst::UMin);
break;
case BO_Assign:
RMWOp = llvm::AtomicRMWInst::Xchg;
break;
case BO_Mul:
case BO_Div:
case BO_Rem:
case BO_Shl:
case BO_Shr:
case BO_LAnd:
case BO_LOr:
return std::make_pair(false, RValue::get(nullptr));
case BO_PtrMemD:
case BO_PtrMemI:
case BO_LE:
case BO_GE:
case BO_EQ:
case BO_NE:
case BO_Cmp:
case BO_AddAssign:
case BO_SubAssign:
case BO_AndAssign:
case BO_OrAssign:
case BO_XorAssign:
case BO_MulAssign:
case BO_DivAssign:
case BO_RemAssign:
case BO_ShlAssign:
case BO_ShrAssign:
case BO_Comma:
llvm_unreachable("Unsupported atomic update operation");
}
llvm::Value *UpdateVal = Update.getScalarVal();
if (auto *IC = dyn_cast<llvm::ConstantInt>(UpdateVal)) {
UpdateVal = CGF.Builder.CreateIntCast(
IC, X.getAddress().getElementType(),
X.getType()->hasSignedIntegerRepresentation());
}
llvm::Value *Res =
CGF.Builder.CreateAtomicRMW(RMWOp, X.getPointer(), UpdateVal, AO);
return std::make_pair(true, RValue::get(Res));
}
std::pair<bool, RValue> CodeGenFunction::EmitOMPAtomicSimpleUpdateExpr(
LValue X, RValue E, BinaryOperatorKind BO, bool IsXLHSInRHSPart,
llvm::AtomicOrdering AO, SourceLocation Loc,
const llvm::function_ref<RValue(RValue)> CommonGen) {
// Update expressions are allowed to have the following forms:
// x binop= expr; -> xrval + expr;
// x++, ++x -> xrval + 1;
// x--, --x -> xrval - 1;
// x = x binop expr; -> xrval binop expr
// x = expr Op x; - > expr binop xrval;
auto Res = emitOMPAtomicRMW(*this, X, E, BO, AO, IsXLHSInRHSPart);
if (!Res.first) {
if (X.isGlobalReg()) {
// Emit an update expression: 'xrval' binop 'expr' or 'expr' binop
// 'xrval'.
EmitStoreThroughLValue(CommonGen(EmitLoadOfLValue(X, Loc)), X);
} else {
// Perform compare-and-swap procedure.
EmitAtomicUpdate(X, AO, CommonGen, X.getType().isVolatileQualified());
}
}
return Res;
}
static void emitOMPAtomicUpdateExpr(CodeGenFunction &CGF, bool IsSeqCst,
const Expr *X, const Expr *E,
const Expr *UE, bool IsXLHSInRHSPart,
SourceLocation Loc) {
assert(isa<BinaryOperator>(UE->IgnoreImpCasts()) &&
"Update expr in 'atomic update' must be a binary operator.");
const auto *BOUE = cast<BinaryOperator>(UE->IgnoreImpCasts());
// Update expressions are allowed to have the following forms:
// x binop= expr; -> xrval + expr;
// x++, ++x -> xrval + 1;
// x--, --x -> xrval - 1;
// x = x binop expr; -> xrval binop expr
// x = expr Op x; - > expr binop xrval;
assert(X->isLValue() && "X of 'omp atomic update' is not lvalue");
LValue XLValue = CGF.EmitLValue(X);
RValue ExprRValue = CGF.EmitAnyExpr(E);
llvm::AtomicOrdering AO = IsSeqCst
? llvm::AtomicOrdering::SequentiallyConsistent
: llvm::AtomicOrdering::Monotonic;
const auto *LHS = cast<OpaqueValueExpr>(BOUE->getLHS()->IgnoreImpCasts());
const auto *RHS = cast<OpaqueValueExpr>(BOUE->getRHS()->IgnoreImpCasts());
const OpaqueValueExpr *XRValExpr = IsXLHSInRHSPart ? LHS : RHS;
const OpaqueValueExpr *ERValExpr = IsXLHSInRHSPart ? RHS : LHS;
auto &&Gen = [&CGF, UE, ExprRValue, XRValExpr, ERValExpr](RValue XRValue) {
CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue);
return CGF.EmitAnyExpr(UE);
};
(void)CGF.EmitOMPAtomicSimpleUpdateExpr(
XLValue, ExprRValue, BOUE->getOpcode(), IsXLHSInRHSPart, AO, Loc, Gen);
// OpenMP, 2.12.6, atomic Construct
// Any atomic construct with a seq_cst clause forces the atomically
// performed operation to include an implicit flush operation without a
// list.
if (IsSeqCst)
CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc);
}
static RValue convertToType(CodeGenFunction &CGF, RValue Value,
QualType SourceType, QualType ResType,
SourceLocation Loc) {
switch (CGF.getEvaluationKind(ResType)) {
case TEK_Scalar:
return RValue::get(
convertToScalarValue(CGF, Value, SourceType, ResType, Loc));
case TEK_Complex: {
auto Res = convertToComplexValue(CGF, Value, SourceType, ResType, Loc);
return RValue::getComplex(Res.first, Res.second);
}
case TEK_Aggregate:
break;
}
llvm_unreachable("Must be a scalar or complex.");
}
static void emitOMPAtomicCaptureExpr(CodeGenFunction &CGF, bool IsSeqCst,
bool IsPostfixUpdate, const Expr *V,
const Expr *X, const Expr *E,
const Expr *UE, bool IsXLHSInRHSPart,
SourceLocation Loc) {
assert(X->isLValue() && "X of 'omp atomic capture' is not lvalue");
assert(V->isLValue() && "V of 'omp atomic capture' is not lvalue");
RValue NewVVal;
LValue VLValue = CGF.EmitLValue(V);
LValue XLValue = CGF.EmitLValue(X);
RValue ExprRValue = CGF.EmitAnyExpr(E);
llvm::AtomicOrdering AO = IsSeqCst
? llvm::AtomicOrdering::SequentiallyConsistent
: llvm::AtomicOrdering::Monotonic;
QualType NewVValType;
if (UE) {
// 'x' is updated with some additional value.
assert(isa<BinaryOperator>(UE->IgnoreImpCasts()) &&
"Update expr in 'atomic capture' must be a binary operator.");
const auto *BOUE = cast<BinaryOperator>(UE->IgnoreImpCasts());
// Update expressions are allowed to have the following forms:
// x binop= expr; -> xrval + expr;
// x++, ++x -> xrval + 1;
// x--, --x -> xrval - 1;
// x = x binop expr; -> xrval binop expr
// x = expr Op x; - > expr binop xrval;
const auto *LHS = cast<OpaqueValueExpr>(BOUE->getLHS()->IgnoreImpCasts());
const auto *RHS = cast<OpaqueValueExpr>(BOUE->getRHS()->IgnoreImpCasts());
const OpaqueValueExpr *XRValExpr = IsXLHSInRHSPart ? LHS : RHS;
NewVValType = XRValExpr->getType();
const OpaqueValueExpr *ERValExpr = IsXLHSInRHSPart ? RHS : LHS;
auto &&Gen = [&CGF, &NewVVal, UE, ExprRValue, XRValExpr, ERValExpr,
IsPostfixUpdate](RValue XRValue) {
CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue);
RValue Res = CGF.EmitAnyExpr(UE);
NewVVal = IsPostfixUpdate ? XRValue : Res;
return Res;
};
auto Res = CGF.EmitOMPAtomicSimpleUpdateExpr(
XLValue, ExprRValue, BOUE->getOpcode(), IsXLHSInRHSPart, AO, Loc, Gen);
if (Res.first) {
// 'atomicrmw' instruction was generated.
if (IsPostfixUpdate) {
// Use old value from 'atomicrmw'.
NewVVal = Res.second;
} else {
// 'atomicrmw' does not provide new value, so evaluate it using old
// value of 'x'.
CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, Res.second);
NewVVal = CGF.EmitAnyExpr(UE);
}
}
} else {
// 'x' is simply rewritten with some 'expr'.
NewVValType = X->getType().getNonReferenceType();
ExprRValue = convertToType(CGF, ExprRValue, E->getType(),
X->getType().getNonReferenceType(), Loc);
auto &&Gen = [&NewVVal, ExprRValue](RValue XRValue) {
NewVVal = XRValue;
return ExprRValue;
};
// Try to perform atomicrmw xchg, otherwise simple exchange.
auto Res = CGF.EmitOMPAtomicSimpleUpdateExpr(
XLValue, ExprRValue, /*BO=*/BO_Assign, /*IsXLHSInRHSPart=*/false, AO,
Loc, Gen);
if (Res.first) {
// 'atomicrmw' instruction was generated.
NewVVal = IsPostfixUpdate ? Res.second : ExprRValue;
}
}
// Emit post-update store to 'v' of old/new 'x' value.
CGF.emitOMPSimpleStore(VLValue, NewVVal, NewVValType, Loc);
// OpenMP, 2.12.6, atomic Construct
// Any atomic construct with a seq_cst clause forces the atomically
// performed operation to include an implicit flush operation without a
// list.
if (IsSeqCst)
CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc);
}
static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
bool IsSeqCst, bool IsPostfixUpdate,
const Expr *X, const Expr *V, const Expr *E,
const Expr *UE, bool IsXLHSInRHSPart,
SourceLocation Loc) {
switch (Kind) {
case OMPC_read:
emitOMPAtomicReadExpr(CGF, IsSeqCst, X, V, Loc);
break;
case OMPC_write:
emitOMPAtomicWriteExpr(CGF, IsSeqCst, X, E, Loc);
break;
case OMPC_unknown:
case OMPC_update:
emitOMPAtomicUpdateExpr(CGF, IsSeqCst, X, E, UE, IsXLHSInRHSPart, Loc);
break;
case OMPC_capture:
emitOMPAtomicCaptureExpr(CGF, IsSeqCst, IsPostfixUpdate, V, X, E, UE,
IsXLHSInRHSPart, Loc);
break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_reduction:
case OMPC_task_reduction:
case OMPC_in_reduction:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_collapse:
case OMPC_default:
case OMPC_seq_cst:
case OMPC_shared:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_flush:
case OMPC_proc_bind:
case OMPC_schedule:
case OMPC_ordered:
case OMPC_nowait:
case OMPC_untied:
case OMPC_threadprivate:
case OMPC_depend:
case OMPC_mergeable:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
case OMPC_num_teams:
case OMPC_thread_limit:
case OMPC_priority:
case OMPC_grainsize:
case OMPC_nogroup:
case OMPC_num_tasks:
case OMPC_hint:
case OMPC_dist_schedule:
case OMPC_defaultmap:
case OMPC_uniform:
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
llvm_unreachable("Clause is not allowed in 'omp atomic'.");
}
}
void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) {
bool IsSeqCst = S.getSingleClause<OMPSeqCstClause>();
OpenMPClauseKind Kind = OMPC_unknown;
for (const OMPClause *C : S.clauses()) {
// Find first clause (skip seq_cst clause, if it is first).
if (C->getClauseKind() != OMPC_seq_cst) {
Kind = C->getClauseKind();
break;
}
}
const Stmt *CS = S.getInnermostCapturedStmt()->IgnoreContainers();
if (const auto *FE = dyn_cast<FullExpr>(CS))
enterFullExpression(FE);
// Processing for statements under 'atomic capture'.
if (const auto *Compound = dyn_cast<CompoundStmt>(CS)) {
for (const Stmt *C : Compound->body()) {
if (const auto *FE = dyn_cast<FullExpr>(C))
enterFullExpression(FE);
}
}
auto &&CodeGen = [&S, Kind, IsSeqCst, CS](CodeGenFunction &CGF,
PrePostActionTy &) {
CGF.EmitStopPoint(CS);
emitOMPAtomicExpr(CGF, Kind, IsSeqCst, S.isPostfixUpdate(), S.getX(),
S.getV(), S.getExpr(), S.getUpdateExpr(),
S.isXLHSInRHSPart(), S.getBeginLoc());
};
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_atomic, CodeGen);
}
static void emitCommonOMPTargetDirective(CodeGenFunction &CGF,
const OMPExecutableDirective &S,
const RegionCodeGenTy &CodeGen) {
assert(isOpenMPTargetExecutionDirective(S.getDirectiveKind()));
CodeGenModule &CGM = CGF.CGM;
// On device emit this construct as inlined code.
if (CGM.getLangOpts().OpenMPIsDevice) {
OMPLexicalScope Scope(CGF, S, OMPD_target);
CGM.getOpenMPRuntime().emitInlinedDirective(
CGF, OMPD_target, [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
});
return;
}
llvm::Function *Fn = nullptr;
llvm::Constant *FnID = nullptr;
const Expr *IfCond = nullptr;
// Check for the at most one if clause associated with the target region.
for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
if (C->getNameModifier() == OMPD_unknown ||
C->getNameModifier() == OMPD_target) {
IfCond = C->getCondition();
break;
}
}
// Check if we have any device clause associated with the directive.
const Expr *Device = nullptr;
if (auto *C = S.getSingleClause<OMPDeviceClause>())
Device = C->getDevice();
// Check if we have an if clause whose conditional always evaluates to false
// or if we do not have any targets specified. If so the target region is not
// an offload entry point.
bool IsOffloadEntry = true;
if (IfCond) {
bool Val;
if (CGF.ConstantFoldsToSimpleInteger(IfCond, Val) && !Val)
IsOffloadEntry = false;
}
if (CGM.getLangOpts().OMPTargetTriples.empty())
IsOffloadEntry = false;
assert(CGF.CurFuncDecl && "No parent declaration for target region!");
StringRef ParentName;
// In case we have Ctors/Dtors we use the complete type variant to produce
// the mangling of the device outlined kernel.
if (const auto *D = dyn_cast<CXXConstructorDecl>(CGF.CurFuncDecl))
ParentName = CGM.getMangledName(GlobalDecl(D, Ctor_Complete));
else if (const auto *D = dyn_cast<CXXDestructorDecl>(CGF.CurFuncDecl))
ParentName = CGM.getMangledName(GlobalDecl(D, Dtor_Complete));
else
ParentName =
CGM.getMangledName(GlobalDecl(cast<FunctionDecl>(CGF.CurFuncDecl)));
// Emit target region as a standalone region.
CGM.getOpenMPRuntime().emitTargetOutlinedFunction(S, ParentName, Fn, FnID,
IsOffloadEntry, CodeGen);
OMPLexicalScope Scope(CGF, S, OMPD_task);
auto &&SizeEmitter = [](CodeGenFunction &CGF, const OMPLoopDirective &D) {
OMPLoopScope(CGF, D);
// Emit calculation of the iterations count.
llvm::Value *NumIterations = CGF.EmitScalarExpr(D.getNumIterations());
NumIterations = CGF.Builder.CreateIntCast(NumIterations, CGF.Int64Ty,
/*IsSigned=*/false);
return NumIterations;
};
CGM.getOpenMPRuntime().emitTargetNumIterationsCall(CGF, S, Device,
SizeEmitter);
CGM.getOpenMPRuntime().emitTargetCall(CGF, S, Fn, FnID, IfCond, Device);
}
static void emitTargetRegion(CodeGenFunction &CGF, const OMPTargetDirective &S,
PrePostActionTy &Action) {
Action.Enter(CGF);
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
(void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
CGF.EmitOMPPrivateClause(S, PrivateScope);
(void)PrivateScope.Privatize();
if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
CGF.EmitStmt(S.getCapturedStmt(OMPD_target)->getCapturedStmt());
}
void CodeGenFunction::EmitOMPTargetDeviceFunction(CodeGenModule &CGM,
StringRef ParentName,
const OMPTargetDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetRegion(CGF, S, Action);
};
llvm::Function *Fn;
llvm::Constant *Addr;
// Emit target region as a standalone region.
CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
assert(Fn && Addr && "Target device function emission failed.");
}
void CodeGenFunction::EmitOMPTargetDirective(const OMPTargetDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetRegion(CGF, S, Action);
};
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
static void emitCommonOMPTeamsDirective(CodeGenFunction &CGF,
const OMPExecutableDirective &S,
OpenMPDirectiveKind InnermostKind,
const RegionCodeGenTy &CodeGen) {
const CapturedStmt *CS = S.getCapturedStmt(OMPD_teams);
llvm::Value *OutlinedFn =
CGF.CGM.getOpenMPRuntime().emitTeamsOutlinedFunction(
S, *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen);
const auto *NT = S.getSingleClause<OMPNumTeamsClause>();
const auto *TL = S.getSingleClause<OMPThreadLimitClause>();
if (NT || TL) {
const Expr *NumTeams = NT ? NT->getNumTeams() : nullptr;
const Expr *ThreadLimit = TL ? TL->getThreadLimit() : nullptr;
CGF.CGM.getOpenMPRuntime().emitNumTeamsClause(CGF, NumTeams, ThreadLimit,
S.getBeginLoc());
}
OMPTeamsScope Scope(CGF, S);
llvm::SmallVector<llvm::Value *, 16> CapturedVars;
CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
CGF.CGM.getOpenMPRuntime().emitTeamsCall(CGF, S, S.getBeginLoc(), OutlinedFn,
CapturedVars);
}
void CodeGenFunction::EmitOMPTeamsDirective(const OMPTeamsDirective &S) {
// Emit teams region as a standalone region.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
OMPPrivateScope PrivateScope(CGF);
(void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
CGF.EmitOMPPrivateClause(S, PrivateScope);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.EmitStmt(S.getCapturedStmt(OMPD_teams)->getCapturedStmt());
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen);
emitPostUpdateForReductionClause(*this, S,
[](CodeGenFunction &) { return nullptr; });
}
static void emitTargetTeamsRegion(CodeGenFunction &CGF, PrePostActionTy &Action,
const OMPTargetTeamsDirective &S) {
auto *CS = S.getCapturedStmt(OMPD_teams);
Action.Enter(CGF);
// Emit teams region as a standalone region.
auto &&CodeGen = [&S, CS](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
(void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
CGF.EmitOMPPrivateClause(S, PrivateScope);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
CGF.EmitStmt(CS->getCapturedStmt());
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
emitCommonOMPTeamsDirective(CGF, S, OMPD_teams, CodeGen);
emitPostUpdateForReductionClause(CGF, S,
[](CodeGenFunction &) { return nullptr; });
}
void CodeGenFunction::EmitOMPTargetTeamsDeviceFunction(
CodeGenModule &CGM, StringRef ParentName,
const OMPTargetTeamsDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetTeamsRegion(CGF, Action, S);
};
llvm::Function *Fn;
llvm::Constant *Addr;
// Emit target region as a standalone region.
CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
assert(Fn && Addr && "Target device function emission failed.");
}
void CodeGenFunction::EmitOMPTargetTeamsDirective(
const OMPTargetTeamsDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetTeamsRegion(CGF, Action, S);
};
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
static void
emitTargetTeamsDistributeRegion(CodeGenFunction &CGF, PrePostActionTy &Action,
const OMPTargetTeamsDistributeDirective &S) {
Action.Enter(CGF);
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
};
// Emit teams region as a standalone region.
auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
PrePostActionTy &Action) {
Action.Enter(CGF);
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
CodeGenDistribute);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute, CodeGen);
emitPostUpdateForReductionClause(CGF, S,
[](CodeGenFunction &) { return nullptr; });
}
void CodeGenFunction::EmitOMPTargetTeamsDistributeDeviceFunction(
CodeGenModule &CGM, StringRef ParentName,
const OMPTargetTeamsDistributeDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetTeamsDistributeRegion(CGF, Action, S);
};
llvm::Function *Fn;
llvm::Constant *Addr;
// Emit target region as a standalone region.
CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
assert(Fn && Addr && "Target device function emission failed.");
}
void CodeGenFunction::EmitOMPTargetTeamsDistributeDirective(
const OMPTargetTeamsDistributeDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetTeamsDistributeRegion(CGF, Action, S);
};
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
static void emitTargetTeamsDistributeSimdRegion(
CodeGenFunction &CGF, PrePostActionTy &Action,
const OMPTargetTeamsDistributeSimdDirective &S) {
Action.Enter(CGF);
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
};
// Emit teams region as a standalone region.
auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
PrePostActionTy &Action) {
Action.Enter(CGF);
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
CodeGenDistribute);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_simd, CodeGen);
emitPostUpdateForReductionClause(CGF, S,
[](CodeGenFunction &) { return nullptr; });
}
void CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDeviceFunction(
CodeGenModule &CGM, StringRef ParentName,
const OMPTargetTeamsDistributeSimdDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetTeamsDistributeSimdRegion(CGF, Action, S);
};
llvm::Function *Fn;
llvm::Constant *Addr;
// Emit target region as a standalone region.
CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
assert(Fn && Addr && "Target device function emission failed.");
}
void CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDirective(
const OMPTargetTeamsDistributeSimdDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetTeamsDistributeSimdRegion(CGF, Action, S);
};
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
void CodeGenFunction::EmitOMPTeamsDistributeDirective(
const OMPTeamsDistributeDirective &S) {
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
};
// Emit teams region as a standalone region.
auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
PrePostActionTy &Action) {
Action.Enter(CGF);
OMPPrivateScope PrivateScope(CGF);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
CodeGenDistribute);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen);
emitPostUpdateForReductionClause(*this, S,
[](CodeGenFunction &) { return nullptr; });
}
void CodeGenFunction::EmitOMPTeamsDistributeSimdDirective(
const OMPTeamsDistributeSimdDirective &S) {
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
};
// Emit teams region as a standalone region.
auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
PrePostActionTy &Action) {
Action.Enter(CGF);
OMPPrivateScope PrivateScope(CGF);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_simd,
CodeGenDistribute);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_simd, CodeGen);
emitPostUpdateForReductionClause(*this, S,
[](CodeGenFunction &) { return nullptr; });
}
void CodeGenFunction::EmitOMPTeamsDistributeParallelForDirective(
const OMPTeamsDistributeParallelForDirective &S) {
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
S.getDistInc());
};
// Emit teams region as a standalone region.
auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
PrePostActionTy &Action) {
Action.Enter(CGF);
OMPPrivateScope PrivateScope(CGF);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
CodeGenDistribute);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen);
emitPostUpdateForReductionClause(*this, S,
[](CodeGenFunction &) { return nullptr; });
}
void CodeGenFunction::EmitOMPTeamsDistributeParallelForSimdDirective(
const OMPTeamsDistributeParallelForSimdDirective &S) {
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
S.getDistInc());
};
// Emit teams region as a standalone region.
auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
PrePostActionTy &Action) {
Action.Enter(CGF);
OMPPrivateScope PrivateScope(CGF);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(
CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen);
emitPostUpdateForReductionClause(*this, S,
[](CodeGenFunction &) { return nullptr; });
}
static void emitTargetTeamsDistributeParallelForRegion(
CodeGenFunction &CGF, const OMPTargetTeamsDistributeParallelForDirective &S,
PrePostActionTy &Action) {
Action.Enter(CGF);
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
S.getDistInc());
};
// Emit teams region as a standalone region.
auto &&CodeGenTeams = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
PrePostActionTy &Action) {
Action.Enter(CGF);
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(
CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for,
CodeGenTeams);
emitPostUpdateForReductionClause(CGF, S,
[](CodeGenFunction &) { return nullptr; });
}
void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForDeviceFunction(
CodeGenModule &CGM, StringRef ParentName,
const OMPTargetTeamsDistributeParallelForDirective &S) {
// Emit SPMD target teams distribute parallel for region as a standalone
// region.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetTeamsDistributeParallelForRegion(CGF, S, Action);
};
llvm::Function *Fn;
llvm::Constant *Addr;
// Emit target region as a standalone region.
CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
assert(Fn && Addr && "Target device function emission failed.");
}
void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForDirective(
const OMPTargetTeamsDistributeParallelForDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetTeamsDistributeParallelForRegion(CGF, S, Action);
};
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
static void emitTargetTeamsDistributeParallelForSimdRegion(
CodeGenFunction &CGF,
const OMPTargetTeamsDistributeParallelForSimdDirective &S,
PrePostActionTy &Action) {
Action.Enter(CGF);
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
S.getDistInc());
};
// Emit teams region as a standalone region.
auto &&CodeGenTeams = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
PrePostActionTy &Action) {
Action.Enter(CGF);
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(
CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for_simd,
CodeGenTeams);
emitPostUpdateForReductionClause(CGF, S,
[](CodeGenFunction &) { return nullptr; });
}
void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForSimdDeviceFunction(
CodeGenModule &CGM, StringRef ParentName,
const OMPTargetTeamsDistributeParallelForSimdDirective &S) {
// Emit SPMD target teams distribute parallel for simd region as a standalone
// region.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetTeamsDistributeParallelForSimdRegion(CGF, S, Action);
};
llvm::Function *Fn;
llvm::Constant *Addr;
// Emit target region as a standalone region.
CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
assert(Fn && Addr && "Target device function emission failed.");
}
void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForSimdDirective(
const OMPTargetTeamsDistributeParallelForSimdDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetTeamsDistributeParallelForSimdRegion(CGF, S, Action);
};
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
void CodeGenFunction::EmitOMPCancellationPointDirective(
const OMPCancellationPointDirective &S) {
CGM.getOpenMPRuntime().emitCancellationPointCall(*this, S.getBeginLoc(),
S.getCancelRegion());
}
void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) {
const Expr *IfCond = nullptr;
for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
if (C->getNameModifier() == OMPD_unknown ||
C->getNameModifier() == OMPD_cancel) {
IfCond = C->getCondition();
break;
}
}
CGM.getOpenMPRuntime().emitCancelCall(*this, S.getBeginLoc(), IfCond,
S.getCancelRegion());
}
CodeGenFunction::JumpDest
CodeGenFunction::getOMPCancelDestination(OpenMPDirectiveKind Kind) {
if (Kind == OMPD_parallel || Kind == OMPD_task ||
Kind == OMPD_target_parallel)
return ReturnBlock;
assert(Kind == OMPD_for || Kind == OMPD_section || Kind == OMPD_sections ||
Kind == OMPD_parallel_sections || Kind == OMPD_parallel_for ||
Kind == OMPD_distribute_parallel_for ||
Kind == OMPD_target_parallel_for ||
Kind == OMPD_teams_distribute_parallel_for ||
Kind == OMPD_target_teams_distribute_parallel_for);
return OMPCancelStack.getExitBlock();
}
void CodeGenFunction::EmitOMPUseDevicePtrClause(
const OMPClause &NC, OMPPrivateScope &PrivateScope,
const llvm::DenseMap<const ValueDecl *, Address> &CaptureDeviceAddrMap) {
const auto &C = cast<OMPUseDevicePtrClause>(NC);
auto OrigVarIt = C.varlist_begin();
auto InitIt = C.inits().begin();
for (const Expr *PvtVarIt : C.private_copies()) {
const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*OrigVarIt)->getDecl());
const auto *InitVD = cast<VarDecl>(cast<DeclRefExpr>(*InitIt)->getDecl());
const auto *PvtVD = cast<VarDecl>(cast<DeclRefExpr>(PvtVarIt)->getDecl());
// In order to identify the right initializer we need to match the
// declaration used by the mapping logic. In some cases we may get
// OMPCapturedExprDecl that refers to the original declaration.
const ValueDecl *MatchingVD = OrigVD;
if (const auto *OED = dyn_cast<OMPCapturedExprDecl>(MatchingVD)) {
// OMPCapturedExprDecl are used to privative fields of the current
// structure.
const auto *ME = cast<MemberExpr>(OED->getInit());
assert(isa<CXXThisExpr>(ME->getBase()) &&
"Base should be the current struct!");
MatchingVD = ME->getMemberDecl();
}
// If we don't have information about the current list item, move on to
// the next one.
auto InitAddrIt = CaptureDeviceAddrMap.find(MatchingVD);
if (InitAddrIt == CaptureDeviceAddrMap.end())
continue;
bool IsRegistered = PrivateScope.addPrivate(OrigVD, [this, OrigVD,
InitAddrIt, InitVD,
PvtVD]() {
// Initialize the temporary initialization variable with the address we
// get from the runtime library. We have to cast the source address
// because it is always a void *. References are materialized in the
// privatization scope, so the initialization here disregards the fact
// the original variable is a reference.
QualType AddrQTy =
getContext().getPointerType(OrigVD->getType().getNonReferenceType());
llvm::Type *AddrTy = ConvertTypeForMem(AddrQTy);
Address InitAddr = Builder.CreateBitCast(InitAddrIt->second, AddrTy);
setAddrOfLocalVar(InitVD, InitAddr);
// Emit private declaration, it will be initialized by the value we
// declaration we just added to the local declarations map.
EmitDecl(*PvtVD);
// The initialization variables reached its purpose in the emission
// of the previous declaration, so we don't need it anymore.
LocalDeclMap.erase(InitVD);
// Return the address of the private variable.
return GetAddrOfLocalVar(PvtVD);
});
assert(IsRegistered && "firstprivate var already registered as private");
// Silence the warning about unused variable.
(void)IsRegistered;
++OrigVarIt;
++InitIt;
}
}
// Generate the instructions for '#pragma omp target data' directive.
void CodeGenFunction::EmitOMPTargetDataDirective(
const OMPTargetDataDirective &S) {
CGOpenMPRuntime::TargetDataInfo Info(/*RequiresDevicePointerInfo=*/true);
// Create a pre/post action to signal the privatization of the device pointer.
// This action can be replaced by the OpenMP runtime code generation to
// deactivate privatization.
bool PrivatizeDevicePointers = false;
class DevicePointerPrivActionTy : public PrePostActionTy {
bool &PrivatizeDevicePointers;
public:
explicit DevicePointerPrivActionTy(bool &PrivatizeDevicePointers)
: PrePostActionTy(), PrivatizeDevicePointers(PrivatizeDevicePointers) {}
void Enter(CodeGenFunction &CGF) override {
PrivatizeDevicePointers = true;
}
};
DevicePointerPrivActionTy PrivAction(PrivatizeDevicePointers);
auto &&CodeGen = [&S, &Info, &PrivatizeDevicePointers](
CodeGenFunction &CGF, PrePostActionTy &Action) {
auto &&InnermostCodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
};
// Codegen that selects whether to generate the privatization code or not.
auto &&PrivCodeGen = [&S, &Info, &PrivatizeDevicePointers,
&InnermostCodeGen](CodeGenFunction &CGF,
PrePostActionTy &Action) {
RegionCodeGenTy RCG(InnermostCodeGen);
PrivatizeDevicePointers = false;
// Call the pre-action to change the status of PrivatizeDevicePointers if
// needed.
Action.Enter(CGF);
if (PrivatizeDevicePointers) {
OMPPrivateScope PrivateScope(CGF);
// Emit all instances of the use_device_ptr clause.
for (const auto *C : S.getClausesOfKind<OMPUseDevicePtrClause>())
CGF.EmitOMPUseDevicePtrClause(*C, PrivateScope,
Info.CaptureDeviceAddrMap);
(void)PrivateScope.Privatize();
RCG(CGF);
} else {
RCG(CGF);
}
};
// Forward the provided action to the privatization codegen.
RegionCodeGenTy PrivRCG(PrivCodeGen);
PrivRCG.setAction(Action);
// Notwithstanding the body of the region is emitted as inlined directive,
// we don't use an inline scope as changes in the references inside the
// region are expected to be visible outside, so we do not privative them.
OMPLexicalScope Scope(CGF, S);
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_target_data,
PrivRCG);
};
RegionCodeGenTy RCG(CodeGen);
// If we don't have target devices, don't bother emitting the data mapping
// code.
if (CGM.getLangOpts().OMPTargetTriples.empty()) {
RCG(*this);
return;
}
// Check if we have any if clause associated with the directive.
const Expr *IfCond = nullptr;
if (const auto *C = S.getSingleClause<OMPIfClause>())
IfCond = C->getCondition();
// Check if we have any device clause associated with the directive.
const Expr *Device = nullptr;
if (const auto *C = S.getSingleClause<OMPDeviceClause>())
Device = C->getDevice();
// Set the action to signal privatization of device pointers.
RCG.setAction(PrivAction);
// Emit region code.
CGM.getOpenMPRuntime().emitTargetDataCalls(*this, S, IfCond, Device, RCG,
Info);
}
void CodeGenFunction::EmitOMPTargetEnterDataDirective(
const OMPTargetEnterDataDirective &S) {
// If we don't have target devices, don't bother emitting the data mapping
// code.
if (CGM.getLangOpts().OMPTargetTriples.empty())
return;
// Check if we have any if clause associated with the directive.
const Expr *IfCond = nullptr;
if (const auto *C = S.getSingleClause<OMPIfClause>())
IfCond = C->getCondition();
// Check if we have any device clause associated with the directive.
const Expr *Device = nullptr;
if (const auto *C = S.getSingleClause<OMPDeviceClause>())
Device = C->getDevice();
OMPLexicalScope Scope(*this, S, OMPD_task);
CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
}
void CodeGenFunction::EmitOMPTargetExitDataDirective(
const OMPTargetExitDataDirective &S) {
// If we don't have target devices, don't bother emitting the data mapping
// code.
if (CGM.getLangOpts().OMPTargetTriples.empty())
return;
// Check if we have any if clause associated with the directive.
const Expr *IfCond = nullptr;
if (const auto *C = S.getSingleClause<OMPIfClause>())
IfCond = C->getCondition();
// Check if we have any device clause associated with the directive.
const Expr *Device = nullptr;
if (const auto *C = S.getSingleClause<OMPDeviceClause>())
Device = C->getDevice();
OMPLexicalScope Scope(*this, S, OMPD_task);
CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
}
static void emitTargetParallelRegion(CodeGenFunction &CGF,
const OMPTargetParallelDirective &S,
PrePostActionTy &Action) {
// Get the captured statement associated with the 'parallel' region.
const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel);
Action.Enter(CGF);
auto &&CodeGen = [&S, CS](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
(void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
CGF.EmitOMPPrivateClause(S, PrivateScope);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
if (isOpenMPTargetExecutionDirective(S.getDirectiveKind()))
CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S);
// TODO: Add support for clauses.
CGF.EmitStmt(CS->getCapturedStmt());
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
};
emitCommonOMPParallelDirective(CGF, S, OMPD_parallel, CodeGen,
emitEmptyBoundParameters);
emitPostUpdateForReductionClause(CGF, S,
[](CodeGenFunction &) { return nullptr; });
}
void CodeGenFunction::EmitOMPTargetParallelDeviceFunction(
CodeGenModule &CGM, StringRef ParentName,
const OMPTargetParallelDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetParallelRegion(CGF, S, Action);
};
llvm::Function *Fn;
llvm::Constant *Addr;
// Emit target region as a standalone region.
CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
assert(Fn && Addr && "Target device function emission failed.");
}
void CodeGenFunction::EmitOMPTargetParallelDirective(
const OMPTargetParallelDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetParallelRegion(CGF, S, Action);
};
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
static void emitTargetParallelForRegion(CodeGenFunction &CGF,
const OMPTargetParallelForDirective &S,
PrePostActionTy &Action) {
Action.Enter(CGF);
// Emit directive as a combined directive that consists of two implicit
// directives: 'parallel' with 'for' directive.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
CodeGenFunction::OMPCancelStackRAII CancelRegion(
CGF, OMPD_target_parallel_for, S.hasCancel());
CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
emitDispatchForLoopBounds);
};
emitCommonOMPParallelDirective(CGF, S, OMPD_for, CodeGen,
emitEmptyBoundParameters);
}
void CodeGenFunction::EmitOMPTargetParallelForDeviceFunction(
CodeGenModule &CGM, StringRef ParentName,
const OMPTargetParallelForDirective &S) {
// Emit SPMD target parallel for region as a standalone region.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetParallelForRegion(CGF, S, Action);
};
llvm::Function *Fn;
llvm::Constant *Addr;
// Emit target region as a standalone region.
CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
assert(Fn && Addr && "Target device function emission failed.");
}
void CodeGenFunction::EmitOMPTargetParallelForDirective(
const OMPTargetParallelForDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetParallelForRegion(CGF, S, Action);
};
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
static void
emitTargetParallelForSimdRegion(CodeGenFunction &CGF,
const OMPTargetParallelForSimdDirective &S,
PrePostActionTy &Action) {
Action.Enter(CGF);
// Emit directive as a combined directive that consists of two implicit
// directives: 'parallel' with 'for' directive.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
emitDispatchForLoopBounds);
};
emitCommonOMPParallelDirective(CGF, S, OMPD_simd, CodeGen,
emitEmptyBoundParameters);
}
void CodeGenFunction::EmitOMPTargetParallelForSimdDeviceFunction(
CodeGenModule &CGM, StringRef ParentName,
const OMPTargetParallelForSimdDirective &S) {
// Emit SPMD target parallel for region as a standalone region.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetParallelForSimdRegion(CGF, S, Action);
};
llvm::Function *Fn;
llvm::Constant *Addr;
// Emit target region as a standalone region.
CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
assert(Fn && Addr && "Target device function emission failed.");
}
void CodeGenFunction::EmitOMPTargetParallelForSimdDirective(
const OMPTargetParallelForSimdDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
emitTargetParallelForSimdRegion(CGF, S, Action);
};
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
/// Emit a helper variable and return corresponding lvalue.
static void mapParam(CodeGenFunction &CGF, const DeclRefExpr *Helper,
const ImplicitParamDecl *PVD,
CodeGenFunction::OMPPrivateScope &Privates) {
const auto *VDecl = cast<VarDecl>(Helper->getDecl());
Privates.addPrivate(VDecl,
[&CGF, PVD]() { return CGF.GetAddrOfLocalVar(PVD); });
}
void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) {
assert(isOpenMPTaskLoopDirective(S.getDirectiveKind()));
// Emit outlined function for task construct.
const CapturedStmt *CS = S.getCapturedStmt(OMPD_taskloop);
Address CapturedStruct = GenerateCapturedStmtArgument(*CS);
QualType SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl());
const Expr *IfCond = nullptr;
for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
if (C->getNameModifier() == OMPD_unknown ||
C->getNameModifier() == OMPD_taskloop) {
IfCond = C->getCondition();
break;
}
}
OMPTaskDataTy Data;
// Check if taskloop must be emitted without taskgroup.
Data.Nogroup = S.getSingleClause<OMPNogroupClause>();
// TODO: Check if we should emit tied or untied task.
Data.Tied = true;
// Set scheduling for taskloop
if (const auto* Clause = S.getSingleClause<OMPGrainsizeClause>()) {
// grainsize clause
Data.Schedule.setInt(/*IntVal=*/false);
Data.Schedule.setPointer(EmitScalarExpr(Clause->getGrainsize()));
} else if (const auto* Clause = S.getSingleClause<OMPNumTasksClause>()) {
// num_tasks clause
Data.Schedule.setInt(/*IntVal=*/true);
Data.Schedule.setPointer(EmitScalarExpr(Clause->getNumTasks()));
}
auto &&BodyGen = [CS, &S](CodeGenFunction &CGF, PrePostActionTy &) {
// if (PreCond) {
// for (IV in 0..LastIteration) BODY;
// <Final counter/linear vars updates>;
// }
//
// Emit: if (PreCond) - begin.
// If the condition constant folds and can be elided, avoid emitting the
// whole loop.
bool CondConstant;
llvm::BasicBlock *ContBlock = nullptr;
OMPLoopScope PreInitScope(CGF, S);
if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) {
if (!CondConstant)
return;
} else {
llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("taskloop.if.then");
ContBlock = CGF.createBasicBlock("taskloop.if.end");
emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock,
CGF.getProfileCount(&S));
CGF.EmitBlock(ThenBlock);
CGF.incrementProfileCounter(&S);
}
if (isOpenMPSimdDirective(S.getDirectiveKind()))
CGF.EmitOMPSimdInit(S);
OMPPrivateScope LoopScope(CGF);
// Emit helper vars inits.
enum { LowerBound = 5, UpperBound, Stride, LastIter };
auto *I = CS->getCapturedDecl()->param_begin();
auto *LBP = std::next(I, LowerBound);
auto *UBP = std::next(I, UpperBound);
auto *STP = std::next(I, Stride);
auto *LIP = std::next(I, LastIter);
mapParam(CGF, cast<DeclRefExpr>(S.getLowerBoundVariable()), *LBP,
LoopScope);
mapParam(CGF, cast<DeclRefExpr>(S.getUpperBoundVariable()), *UBP,
LoopScope);
mapParam(CGF, cast<DeclRefExpr>(S.getStrideVariable()), *STP, LoopScope);
mapParam(CGF, cast<DeclRefExpr>(S.getIsLastIterVariable()), *LIP,
LoopScope);
CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
(void)LoopScope.Privatize();
// Emit the loop iteration variable.
const Expr *IVExpr = S.getIterationVariable();
const auto *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl());
CGF.EmitVarDecl(*IVDecl);
CGF.EmitIgnoredExpr(S.getInit());
// Emit the iterations count variable.
// If it is not a variable, Sema decided to calculate iterations count on
// each iteration (e.g., it is foldable into a constant).
if (const auto *LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) {
CGF.EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl()));
// Emit calculation of the iterations count.
CGF.EmitIgnoredExpr(S.getCalcLastIteration());
}
CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(),
S.getInc(),
[&S](CodeGenFunction &CGF) {
CGF.EmitOMPLoopBody(S, JumpDest());
CGF.EmitStopPoint(&S);
},
[](CodeGenFunction &) {});
// Emit: if (PreCond) - end.
if (ContBlock) {
CGF.EmitBranch(ContBlock);
CGF.EmitBlock(ContBlock, true);
}
// Emit final copy of the lastprivate variables if IsLastIter != 0.
if (HasLastprivateClause) {
CGF.EmitOMPLastprivateClauseFinal(
S, isOpenMPSimdDirective(S.getDirectiveKind()),
CGF.Builder.CreateIsNotNull(CGF.EmitLoadOfScalar(
CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false,
(*LIP)->getType(), S.getBeginLoc())));
}
};
auto &&TaskGen = [&S, SharedsTy, CapturedStruct,
IfCond](CodeGenFunction &CGF, llvm::Value *OutlinedFn,
const OMPTaskDataTy &Data) {
auto &&CodeGen = [&S, OutlinedFn, SharedsTy, CapturedStruct, IfCond,
&Data](CodeGenFunction &CGF, PrePostActionTy &) {
OMPLoopScope PreInitScope(CGF, S);
CGF.CGM.getOpenMPRuntime().emitTaskLoopCall(CGF, S.getBeginLoc(), S,
OutlinedFn, SharedsTy,
CapturedStruct, IfCond, Data);
};
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_taskloop,
CodeGen);
};
if (Data.Nogroup) {
EmitOMPTaskBasedDirective(S, OMPD_taskloop, BodyGen, TaskGen, Data);
} else {
CGM.getOpenMPRuntime().emitTaskgroupRegion(
*this,
[&S, &BodyGen, &TaskGen, &Data](CodeGenFunction &CGF,
PrePostActionTy &Action) {
Action.Enter(CGF);
CGF.EmitOMPTaskBasedDirective(S, OMPD_taskloop, BodyGen, TaskGen,
Data);
},
S.getBeginLoc());
}
}
void CodeGenFunction::EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S) {
EmitOMPTaskLoopBasedDirective(S);
}
void CodeGenFunction::EmitOMPTaskLoopSimdDirective(
const OMPTaskLoopSimdDirective &S) {
EmitOMPTaskLoopBasedDirective(S);
}
// Generate the instructions for '#pragma omp target update' directive.
void CodeGenFunction::EmitOMPTargetUpdateDirective(
const OMPTargetUpdateDirective &S) {
// If we don't have target devices, don't bother emitting the data mapping
// code.
if (CGM.getLangOpts().OMPTargetTriples.empty())
return;
// Check if we have any if clause associated with the directive.
const Expr *IfCond = nullptr;
if (const auto *C = S.getSingleClause<OMPIfClause>())
IfCond = C->getCondition();
// Check if we have any device clause associated with the directive.
const Expr *Device = nullptr;
if (const auto *C = S.getSingleClause<OMPDeviceClause>())
Device = C->getDevice();
OMPLexicalScope Scope(*this, S, OMPD_task);
CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
}
void CodeGenFunction::EmitSimpleOMPExecutableDirective(
const OMPExecutableDirective &D) {
if (!D.hasAssociatedStmt() || !D.getAssociatedStmt())
return;
auto &&CodeGen = [&D](CodeGenFunction &CGF, PrePostActionTy &Action) {
if (isOpenMPSimdDirective(D.getDirectiveKind())) {
emitOMPSimdRegion(CGF, cast<OMPLoopDirective>(D), Action);
} else {
OMPPrivateScope LoopGlobals(CGF);
if (const auto *LD = dyn_cast<OMPLoopDirective>(&D)) {
for (const Expr *E : LD->counters()) {
const auto *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
if (!VD->hasLocalStorage() && !CGF.LocalDeclMap.count(VD)) {
LValue GlobLVal = CGF.EmitLValue(E);
LoopGlobals.addPrivate(
VD, [&GlobLVal]() { return GlobLVal.getAddress(); });
}
if (isa<OMPCapturedExprDecl>(VD)) {
// Emit only those that were not explicitly referenced in clauses.
if (!CGF.LocalDeclMap.count(VD))
CGF.EmitVarDecl(*VD);
}
}
for (const auto *C : D.getClausesOfKind<OMPOrderedClause>()) {
if (!C->getNumForLoops())
continue;
for (unsigned I = LD->getCollapsedNumber(),
E = C->getLoopNumIterations().size();
I < E; ++I) {
if (const auto *VD = dyn_cast<OMPCapturedExprDecl>(
cast<DeclRefExpr>(C->getLoopCounter(I))->getDecl())) {
// Emit only those that were not explicitly referenced in clauses.
if (!CGF.LocalDeclMap.count(VD))
CGF.EmitVarDecl(*VD);
}
}
}
}
LoopGlobals.Privatize();
CGF.EmitStmt(D.getInnermostCapturedStmt()->getCapturedStmt());
}
};
OMPSimdLexicalScope Scope(*this, D);
CGM.getOpenMPRuntime().emitInlinedDirective(
*this,
isOpenMPSimdDirective(D.getDirectiveKind()) ? OMPD_simd
: D.getDirectiveKind(),
CodeGen);
}
Index: stable/11/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp
===================================================================
--- stable/11/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp (revision 350259)
@@ -1,157 +1,158 @@
//===--- PPC.cpp - PPC Helpers for Tools ------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "PPC.h"
#include "ToolChains/CommonArgs.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
/// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting.
std::string ppc::getPPCTargetCPU(const ArgList &Args) {
if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
StringRef CPUName = A->getValue();
if (CPUName == "native") {
std::string CPU = llvm::sys::getHostCPUName();
if (!CPU.empty() && CPU != "generic")
return CPU;
else
return "";
}
return llvm::StringSwitch<const char *>(CPUName)
.Case("common", "generic")
.Case("440", "440")
.Case("440fp", "440")
.Case("450", "450")
.Case("601", "601")
.Case("602", "602")
.Case("603", "603")
.Case("603e", "603e")
.Case("603ev", "603ev")
.Case("604", "604")
.Case("604e", "604e")
.Case("620", "620")
.Case("630", "pwr3")
.Case("G3", "g3")
.Case("7400", "7400")
.Case("G4", "g4")
.Case("7450", "7450")
.Case("G4+", "g4+")
.Case("750", "750")
.Case("970", "970")
.Case("G5", "g5")
.Case("a2", "a2")
.Case("a2q", "a2q")
.Case("e500mc", "e500mc")
.Case("e5500", "e5500")
.Case("power3", "pwr3")
.Case("power4", "pwr4")
.Case("power5", "pwr5")
.Case("power5x", "pwr5x")
.Case("power6", "pwr6")
.Case("power6x", "pwr6x")
.Case("power7", "pwr7")
.Case("power8", "pwr8")
.Case("power9", "pwr9")
.Case("pwr3", "pwr3")
.Case("pwr4", "pwr4")
.Case("pwr5", "pwr5")
.Case("pwr5x", "pwr5x")
.Case("pwr6", "pwr6")
.Case("pwr6x", "pwr6x")
.Case("pwr7", "pwr7")
.Case("pwr8", "pwr8")
.Case("pwr9", "pwr9")
.Case("powerpc", "ppc")
.Case("powerpc64", "ppc64")
.Case("powerpc64le", "ppc64le")
.Default("");
}
return "";
}
const char *ppc::getPPCAsmModeForCPU(StringRef Name) {
return llvm::StringSwitch<const char *>(Name)
.Case("pwr7", "-mpower7")
.Case("power7", "-mpower7")
.Case("pwr8", "-mpower8")
.Case("power8", "-mpower8")
.Case("ppc64le", "-mpower8")
.Case("pwr9", "-mpower9")
.Case("power9", "-mpower9")
.Default("-many");
}
void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group);
ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args);
if (FloatABI == ppc::FloatABI::Soft)
Features.push_back("-hard-float");
ppc::ReadGOTPtrMode ReadGOT = ppc::getPPCReadGOTPtrMode(D, Triple, Args);
if (ReadGOT == ppc::ReadGOTPtrMode::SecurePlt)
Features.push_back("+secure-plt");
}
ppc::ReadGOTPtrMode ppc::getPPCReadGOTPtrMode(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args) {
if (Args.getLastArg(options::OPT_msecure_plt))
return ppc::ReadGOTPtrMode::SecurePlt;
- if (Triple.isOSOpenBSD())
+ if ((Triple.isOSFreeBSD() && Triple.getOSMajorVersion() >= 13) ||
+ Triple.isOSNetBSD() || Triple.isOSOpenBSD())
return ppc::ReadGOTPtrMode::SecurePlt;
else
return ppc::ReadGOTPtrMode::Bss;
}
ppc::FloatABI ppc::getPPCFloatABI(const Driver &D, const ArgList &Args) {
ppc::FloatABI ABI = ppc::FloatABI::Invalid;
if (Arg *A =
Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
options::OPT_mfloat_abi_EQ)) {
if (A->getOption().matches(options::OPT_msoft_float))
ABI = ppc::FloatABI::Soft;
else if (A->getOption().matches(options::OPT_mhard_float))
ABI = ppc::FloatABI::Hard;
else {
ABI = llvm::StringSwitch<ppc::FloatABI>(A->getValue())
.Case("soft", ppc::FloatABI::Soft)
.Case("hard", ppc::FloatABI::Hard)
.Default(ppc::FloatABI::Invalid);
if (ABI == ppc::FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
D.Diag(clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
ABI = ppc::FloatABI::Hard;
}
}
}
// If unspecified, choose the default based on the platform.
if (ABI == ppc::FloatABI::Invalid) {
ABI = ppc::FloatABI::Hard;
}
return ABI;
}
bool ppc::hasPPCAbiArg(const ArgList &Args, const char *Value) {
Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
return A && (A->getValue() == StringRef(Value));
}
Index: stable/11/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- stable/11/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp (revision 350259)
@@ -1,6208 +1,6214 @@
//===--- LLVM.cpp - Clang+LLVM ToolChain Implementations --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Clang.h"
#include "Arch/AArch64.h"
#include "Arch/ARM.h"
#include "Arch/Mips.h"
#include "Arch/PPC.h"
#include "Arch/RISCV.h"
#include "Arch/Sparc.h"
#include "Arch/SystemZ.h"
#include "Arch/X86.h"
#include "AMDGPU.h"
#include "CommonArgs.h"
#include "Hexagon.h"
#include "MSP430.h"
#include "InputInfo.h"
#include "PS4CPU.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Distro.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "clang/Driver/XRayArgs.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/TargetParser.h"
#include "llvm/Support/YAMLParser.h"
#ifdef LLVM_ON_UNIX
#include <unistd.h> // For getuid().
#endif
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
if (Arg *A =
Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC)) {
if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) &&
!Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) {
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
<< A->getBaseArg().getAsString(Args)
<< (D.IsCLMode() ? "/E, /P or /EP" : "-E");
}
}
}
static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) {
// In gcc, only ARM checks this, but it seems reasonable to check universally.
if (Args.hasArg(options::OPT_static))
if (const Arg *A =
Args.getLastArg(options::OPT_dynamic, options::OPT_mdynamic_no_pic))
D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args)
<< "-static";
}
// Add backslashes to escape spaces and other backslashes.
// This is used for the space-separated argument list specified with
// the -dwarf-debug-flags option.
static void EscapeSpacesAndBackslashes(const char *Arg,
SmallVectorImpl<char> &Res) {
for (; *Arg; ++Arg) {
switch (*Arg) {
default:
break;
case ' ':
case '\\':
Res.push_back('\\');
break;
}
Res.push_back(*Arg);
}
}
// Quote target names for inclusion in GNU Make dependency files.
// Only the characters '$', '#', ' ', '\t' are quoted.
static void QuoteTarget(StringRef Target, SmallVectorImpl<char> &Res) {
for (unsigned i = 0, e = Target.size(); i != e; ++i) {
switch (Target[i]) {
case ' ':
case '\t':
// Escape the preceding backslashes
for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j)
Res.push_back('\\');
// Escape the space/tab
Res.push_back('\\');
break;
case '$':
Res.push_back('$');
break;
case '#':
Res.push_back('\\');
break;
default:
break;
}
Res.push_back(Target[i]);
}
}
/// Apply \a Work on the current tool chain \a RegularToolChain and any other
/// offloading tool chain that is associated with the current action \a JA.
static void
forAllAssociatedToolChains(Compilation &C, const JobAction &JA,
const ToolChain &RegularToolChain,
llvm::function_ref<void(const ToolChain &)> Work) {
// Apply Work on the current/regular tool chain.
Work(RegularToolChain);
// Apply Work on all the offloading tool chains associated with the current
// action.
if (JA.isHostOffloading(Action::OFK_Cuda))
Work(*C.getSingleOffloadToolChain<Action::OFK_Cuda>());
else if (JA.isDeviceOffloading(Action::OFK_Cuda))
Work(*C.getSingleOffloadToolChain<Action::OFK_Host>());
else if (JA.isHostOffloading(Action::OFK_HIP))
Work(*C.getSingleOffloadToolChain<Action::OFK_HIP>());
else if (JA.isDeviceOffloading(Action::OFK_HIP))
Work(*C.getSingleOffloadToolChain<Action::OFK_Host>());
if (JA.isHostOffloading(Action::OFK_OpenMP)) {
auto TCs = C.getOffloadToolChains<Action::OFK_OpenMP>();
for (auto II = TCs.first, IE = TCs.second; II != IE; ++II)
Work(*II->second);
} else if (JA.isDeviceOffloading(Action::OFK_OpenMP))
Work(*C.getSingleOffloadToolChain<Action::OFK_Host>());
//
// TODO: Add support for other offloading programming models here.
//
}
/// This is a helper function for validating the optional refinement step
/// parameter in reciprocal argument strings. Return false if there is an error
/// parsing the refinement step. Otherwise, return true and set the Position
/// of the refinement step in the input string.
static bool getRefinementStep(StringRef In, const Driver &D,
const Arg &A, size_t &Position) {
const char RefinementStepToken = ':';
Position = In.find(RefinementStepToken);
if (Position != StringRef::npos) {
StringRef Option = A.getOption().getName();
StringRef RefStep = In.substr(Position + 1);
// Allow exactly one numeric character for the additional refinement
// step parameter. This is reasonable for all currently-supported
// operations and architectures because we would expect that a larger value
// of refinement steps would cause the estimate "optimization" to
// under-perform the native operation. Also, if the estimate does not
// converge quickly, it probably will not ever converge, so further
// refinement steps will not produce a better answer.
if (RefStep.size() != 1) {
D.Diag(diag::err_drv_invalid_value) << Option << RefStep;
return false;
}
char RefStepChar = RefStep[0];
if (RefStepChar < '0' || RefStepChar > '9') {
D.Diag(diag::err_drv_invalid_value) << Option << RefStep;
return false;
}
}
return true;
}
/// The -mrecip flag requires processing of many optional parameters.
static void ParseMRecip(const Driver &D, const ArgList &Args,
ArgStringList &OutStrings) {
StringRef DisabledPrefixIn = "!";
StringRef DisabledPrefixOut = "!";
StringRef EnabledPrefixOut = "";
StringRef Out = "-mrecip=";
Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ);
if (!A)
return;
unsigned NumOptions = A->getNumValues();
if (NumOptions == 0) {
// No option is the same as "all".
OutStrings.push_back(Args.MakeArgString(Out + "all"));
return;
}
// Pass through "all", "none", or "default" with an optional refinement step.
if (NumOptions == 1) {
StringRef Val = A->getValue(0);
size_t RefStepLoc;
if (!getRefinementStep(Val, D, *A, RefStepLoc))
return;
StringRef ValBase = Val.slice(0, RefStepLoc);
if (ValBase == "all" || ValBase == "none" || ValBase == "default") {
OutStrings.push_back(Args.MakeArgString(Out + Val));
return;
}
}
// Each reciprocal type may be enabled or disabled individually.
// Check each input value for validity, concatenate them all back together,
// and pass through.
llvm::StringMap<bool> OptionStrings;
OptionStrings.insert(std::make_pair("divd", false));
OptionStrings.insert(std::make_pair("divf", false));
OptionStrings.insert(std::make_pair("vec-divd", false));
OptionStrings.insert(std::make_pair("vec-divf", false));
OptionStrings.insert(std::make_pair("sqrtd", false));
OptionStrings.insert(std::make_pair("sqrtf", false));
OptionStrings.insert(std::make_pair("vec-sqrtd", false));
OptionStrings.insert(std::make_pair("vec-sqrtf", false));
for (unsigned i = 0; i != NumOptions; ++i) {
StringRef Val = A->getValue(i);
bool IsDisabled = Val.startswith(DisabledPrefixIn);
// Ignore the disablement token for string matching.
if (IsDisabled)
Val = Val.substr(1);
size_t RefStep;
if (!getRefinementStep(Val, D, *A, RefStep))
return;
StringRef ValBase = Val.slice(0, RefStep);
llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase);
if (OptionIter == OptionStrings.end()) {
// Try again specifying float suffix.
OptionIter = OptionStrings.find(ValBase.str() + 'f');
if (OptionIter == OptionStrings.end()) {
// The input name did not match any known option string.
D.Diag(diag::err_drv_unknown_argument) << Val;
return;
}
// The option was specified without a float or double suffix.
// Make sure that the double entry was not already specified.
// The float entry will be checked below.
if (OptionStrings[ValBase.str() + 'd']) {
D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val;
return;
}
}
if (OptionIter->second == true) {
// Duplicate option specified.
D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val;
return;
}
// Mark the matched option as found. Do not allow duplicate specifiers.
OptionIter->second = true;
// If the precision was not specified, also mark the double entry as found.
if (ValBase.back() != 'f' && ValBase.back() != 'd')
OptionStrings[ValBase.str() + 'd'] = true;
// Build the output string.
StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut;
Out = Args.MakeArgString(Out + Prefix + Val);
if (i != NumOptions - 1)
Out = Args.MakeArgString(Out + ",");
}
OutStrings.push_back(Args.MakeArgString(Out));
}
/// The -mprefer-vector-width option accepts either a positive integer
/// or the string "none".
static void ParseMPreferVectorWidth(const Driver &D, const ArgList &Args,
ArgStringList &CmdArgs) {
Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ);
if (!A)
return;
StringRef Value = A->getValue();
if (Value == "none") {
CmdArgs.push_back("-mprefer-vector-width=none");
} else {
unsigned Width;
if (Value.getAsInteger(10, Width)) {
D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Value;
return;
}
CmdArgs.push_back(Args.MakeArgString("-mprefer-vector-width=" + Value));
}
}
static void getWebAssemblyTargetFeatures(const ArgList &Args,
std::vector<StringRef> &Features) {
handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group);
}
static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
const ArgList &Args, ArgStringList &CmdArgs,
bool ForAS) {
const Driver &D = TC.getDriver();
std::vector<StringRef> Features;
switch (Triple.getArch()) {
default:
break;
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
mips::getMIPSTargetFeatures(D, Triple, Args, Features);
break;
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS);
break;
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
ppc::getPPCTargetFeatures(D, Triple, Args, Features);
break;
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
riscv::getRISCVTargetFeatures(D, Args, Features);
break;
case llvm::Triple::systemz:
systemz::getSystemZTargetFeatures(Args, Features);
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
aarch64::getAArch64TargetFeatures(D, Triple, Args, Features);
break;
case llvm::Triple::x86:
case llvm::Triple::x86_64:
x86::getX86TargetFeatures(D, Triple, Args, Features);
break;
case llvm::Triple::hexagon:
hexagon::getHexagonTargetFeatures(D, Args, Features);
break;
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
getWebAssemblyTargetFeatures(Args, Features);
break;
case llvm::Triple::sparc:
case llvm::Triple::sparcel:
case llvm::Triple::sparcv9:
sparc::getSparcTargetFeatures(D, Args, Features);
break;
case llvm::Triple::r600:
case llvm::Triple::amdgcn:
amdgpu::getAMDGPUTargetFeatures(D, Args, Features);
break;
case llvm::Triple::msp430:
msp430::getMSP430TargetFeatures(D, Args, Features);
}
// Find the last of each feature.
llvm::StringMap<unsigned> LastOpt;
for (unsigned I = 0, N = Features.size(); I < N; ++I) {
StringRef Name = Features[I];
assert(Name[0] == '-' || Name[0] == '+');
LastOpt[Name.drop_front(1)] = I;
}
for (unsigned I = 0, N = Features.size(); I < N; ++I) {
// If this feature was overridden, ignore it.
StringRef Name = Features[I];
llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1));
assert(LastI != LastOpt.end());
unsigned Last = LastI->second;
if (Last != I)
continue;
CmdArgs.push_back("-target-feature");
CmdArgs.push_back(Name.data());
}
}
static bool
shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
const llvm::Triple &Triple) {
// We use the zero-cost exception tables for Objective-C if the non-fragile
// ABI is enabled or when compiling for x86_64 and ARM on Snow Leopard and
// later.
if (runtime.isNonFragile())
return true;
if (!Triple.isMacOSX())
return false;
return (!Triple.isMacOSXVersionLT(10, 5) &&
(Triple.getArch() == llvm::Triple::x86_64 ||
Triple.getArch() == llvm::Triple::arm));
}
/// Adds exception related arguments to the driver command arguments. There's a
/// master flag, -fexceptions and also language specific flags to enable/disable
/// C++ and Objective-C exceptions. This makes it possible to for example
/// disable C++ exceptions but enable Objective-C exceptions.
static void addExceptionArgs(const ArgList &Args, types::ID InputType,
const ToolChain &TC, bool KernelOrKext,
const ObjCRuntime &objcRuntime,
ArgStringList &CmdArgs) {
const llvm::Triple &Triple = TC.getTriple();
if (KernelOrKext) {
// -mkernel and -fapple-kext imply no exceptions, so claim exception related
// arguments now to avoid warnings about unused arguments.
Args.ClaimAllArgs(options::OPT_fexceptions);
Args.ClaimAllArgs(options::OPT_fno_exceptions);
Args.ClaimAllArgs(options::OPT_fobjc_exceptions);
Args.ClaimAllArgs(options::OPT_fno_objc_exceptions);
Args.ClaimAllArgs(options::OPT_fcxx_exceptions);
Args.ClaimAllArgs(options::OPT_fno_cxx_exceptions);
return;
}
// See if the user explicitly enabled exceptions.
bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
false);
// Obj-C exceptions are enabled by default, regardless of -fexceptions. This
// is not necessarily sensible, but follows GCC.
if (types::isObjC(InputType) &&
Args.hasFlag(options::OPT_fobjc_exceptions,
options::OPT_fno_objc_exceptions, true)) {
CmdArgs.push_back("-fobjc-exceptions");
EH |= shouldUseExceptionTablesForObjCExceptions(objcRuntime, Triple);
}
if (types::isCXX(InputType)) {
// Disable C++ EH by default on XCore and PS4.
bool CXXExceptionsEnabled =
Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU();
Arg *ExceptionArg = Args.getLastArg(
options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions,
options::OPT_fexceptions, options::OPT_fno_exceptions);
if (ExceptionArg)
CXXExceptionsEnabled =
ExceptionArg->getOption().matches(options::OPT_fcxx_exceptions) ||
ExceptionArg->getOption().matches(options::OPT_fexceptions);
if (CXXExceptionsEnabled) {
CmdArgs.push_back("-fcxx-exceptions");
EH = true;
}
}
if (EH)
CmdArgs.push_back("-fexceptions");
}
static bool ShouldDisableAutolink(const ArgList &Args, const ToolChain &TC) {
bool Default = true;
if (TC.getTriple().isOSDarwin()) {
// The native darwin assembler doesn't support the linker_option directives,
// so we disable them if we think the .s file will be passed to it.
Default = TC.useIntegratedAs();
}
return !Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink,
Default);
}
static bool ShouldDisableDwarfDirectory(const ArgList &Args,
const ToolChain &TC) {
bool UseDwarfDirectory =
Args.hasFlag(options::OPT_fdwarf_directory_asm,
options::OPT_fno_dwarf_directory_asm, TC.useIntegratedAs());
return !UseDwarfDirectory;
}
// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases
// to the corresponding DebugInfoKind.
static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) {
assert(A.getOption().matches(options::OPT_gN_Group) &&
"Not a -g option that specifies a debug-info level");
if (A.getOption().matches(options::OPT_g0) ||
A.getOption().matches(options::OPT_ggdb0))
return codegenoptions::NoDebugInfo;
if (A.getOption().matches(options::OPT_gline_tables_only) ||
A.getOption().matches(options::OPT_ggdb1))
return codegenoptions::DebugLineTablesOnly;
if (A.getOption().matches(options::OPT_gline_directives_only))
return codegenoptions::DebugDirectivesOnly;
return codegenoptions::LimitedDebugInfo;
}
static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
switch (Triple.getArch()){
default:
return false;
case llvm::Triple::arm:
case llvm::Triple::thumb:
// ARM Darwin targets require a frame pointer to be always present to aid
// offline debugging via backtraces.
return Triple.isOSDarwin();
}
}
static bool useFramePointerForTargetByDefault(const ArgList &Args,
const llvm::Triple &Triple) {
switch (Triple.getArch()) {
case llvm::Triple::xcore:
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
// XCore never wants frame pointers, regardless of OS.
// WebAssembly never wants frame pointers.
return false;
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
return !areOptimizationsEnabled(Args);
default:
break;
}
if (Triple.isOSNetBSD()) {
return !areOptimizationsEnabled(Args);
}
if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI ||
Triple.isOSHurd()) {
switch (Triple.getArch()) {
// Don't use a frame pointer on linux if optimizing for certain targets.
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
case llvm::Triple::systemz:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
return !areOptimizationsEnabled(Args);
default:
return true;
}
}
if (Triple.isOSWindows()) {
switch (Triple.getArch()) {
case llvm::Triple::x86:
return !areOptimizationsEnabled(Args);
case llvm::Triple::x86_64:
return Triple.isOSBinFormatMachO();
case llvm::Triple::arm:
case llvm::Triple::thumb:
// Windows on ARM builds with FPO disabled to aid fast stack walking
return true;
default:
// All other supported Windows ISAs use xdata unwind information, so frame
// pointers are not generally useful.
return false;
}
}
return true;
}
static bool shouldUseFramePointer(const ArgList &Args,
const llvm::Triple &Triple) {
if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer,
options::OPT_fomit_frame_pointer))
return A->getOption().matches(options::OPT_fno_omit_frame_pointer) ||
mustUseNonLeafFramePointerForTarget(Triple);
if (Args.hasArg(options::OPT_pg))
return true;
return useFramePointerForTargetByDefault(Args, Triple);
}
static bool shouldUseLeafFramePointer(const ArgList &Args,
const llvm::Triple &Triple) {
if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer,
options::OPT_momit_leaf_frame_pointer))
return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer);
if (Args.hasArg(options::OPT_pg))
return true;
if (Triple.isPS4CPU())
return false;
return useFramePointerForTargetByDefault(Args, Triple);
}
/// Add a CC1 option to specify the debug compilation directory.
static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) {
SmallString<128> cwd;
if (!llvm::sys::fs::current_path(cwd)) {
CmdArgs.push_back("-fdebug-compilation-dir");
CmdArgs.push_back(Args.MakeArgString(cwd));
}
}
/// Add a CC1 and CC1AS option to specify the debug file path prefix map.
static void addDebugPrefixMapArg(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) {
for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) {
StringRef Map = A->getValue();
if (Map.find('=') == StringRef::npos)
D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map;
else
CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map));
A->claim();
}
}
/// Vectorize at all optimization levels greater than 1 except for -Oz.
/// For -Oz the loop vectorizer is disable, while the slp vectorizer is enabled.
static bool shouldEnableVectorizerAtOLevel(const ArgList &Args, bool isSlpVec) {
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
if (A->getOption().matches(options::OPT_O4) ||
A->getOption().matches(options::OPT_Ofast))
return true;
if (A->getOption().matches(options::OPT_O0))
return false;
assert(A->getOption().matches(options::OPT_O) && "Must have a -O flag");
// Vectorize -Os.
StringRef S(A->getValue());
if (S == "s")
return true;
// Don't vectorize -Oz, unless it's the slp vectorizer.
if (S == "z")
return isSlpVec;
unsigned OptLevel = 0;
if (S.getAsInteger(10, OptLevel))
return false;
return OptLevel > 1;
}
return false;
}
/// Add -x lang to \p CmdArgs for \p Input.
static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
ArgStringList &CmdArgs) {
// When using -verify-pch, we don't want to provide the type
// 'precompiled-header' if it was inferred from the file extension
if (Args.hasArg(options::OPT_verify_pch) && Input.getType() == types::TY_PCH)
return;
CmdArgs.push_back("-x");
if (Args.hasArg(options::OPT_rewrite_objc))
CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX));
else {
// Map the driver type to the frontend type. This is mostly an identity
// mapping, except that the distinction between module interface units
// and other source files does not exist at the frontend layer.
const char *ClangType;
switch (Input.getType()) {
case types::TY_CXXModule:
ClangType = "c++";
break;
case types::TY_PP_CXXModule:
ClangType = "c++-cpp-output";
break;
default:
ClangType = types::getTypeName(Input.getType());
break;
}
CmdArgs.push_back(ClangType);
}
}
static void appendUserToPath(SmallVectorImpl<char> &Result) {
#ifdef LLVM_ON_UNIX
const char *Username = getenv("LOGNAME");
#else
const char *Username = getenv("USERNAME");
#endif
if (Username) {
// Validate that LoginName can be used in a path, and get its length.
size_t Len = 0;
for (const char *P = Username; *P; ++P, ++Len) {
if (!clang::isAlphanumeric(*P) && *P != '_') {
Username = nullptr;
break;
}
}
if (Username && Len > 0) {
Result.append(Username, Username + Len);
return;
}
}
// Fallback to user id.
#ifdef LLVM_ON_UNIX
std::string UID = llvm::utostr(getuid());
#else
// FIXME: Windows seems to have an 'SID' that might work.
std::string UID = "9999";
#endif
Result.append(UID.begin(), UID.end());
}
-static void addPGOAndCoverageFlags(Compilation &C, const Driver &D,
- const InputInfo &Output, const ArgList &Args,
+static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
+ const Driver &D, const InputInfo &Output,
+ const ArgList &Args,
ArgStringList &CmdArgs) {
auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate,
options::OPT_fprofile_generate_EQ,
options::OPT_fno_profile_generate);
if (PGOGenerateArg &&
PGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate))
PGOGenerateArg = nullptr;
auto *ProfileGenerateArg = Args.getLastArg(
options::OPT_fprofile_instr_generate,
options::OPT_fprofile_instr_generate_EQ,
options::OPT_fno_profile_instr_generate);
if (ProfileGenerateArg &&
ProfileGenerateArg->getOption().matches(
options::OPT_fno_profile_instr_generate))
ProfileGenerateArg = nullptr;
if (PGOGenerateArg && ProfileGenerateArg)
D.Diag(diag::err_drv_argument_not_allowed_with)
<< PGOGenerateArg->getSpelling() << ProfileGenerateArg->getSpelling();
auto *ProfileUseArg = getLastProfileUseArg(Args);
if (PGOGenerateArg && ProfileUseArg)
D.Diag(diag::err_drv_argument_not_allowed_with)
<< ProfileUseArg->getSpelling() << PGOGenerateArg->getSpelling();
if (ProfileGenerateArg && ProfileUseArg)
D.Diag(diag::err_drv_argument_not_allowed_with)
<< ProfileGenerateArg->getSpelling() << ProfileUseArg->getSpelling();
if (ProfileGenerateArg) {
if (ProfileGenerateArg->getOption().matches(
options::OPT_fprofile_instr_generate_EQ))
CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-instrument-path=") +
ProfileGenerateArg->getValue()));
// The default is to use Clang Instrumentation.
CmdArgs.push_back("-fprofile-instrument=clang");
+ if (TC.getTriple().isWindowsMSVCEnvironment()) {
+ // Add dependent lib for clang_rt.profile
+ CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
+ TC.getCompilerRT(Args, "profile")));
+ }
}
if (PGOGenerateArg) {
CmdArgs.push_back("-fprofile-instrument=llvm");
if (PGOGenerateArg->getOption().matches(
options::OPT_fprofile_generate_EQ)) {
SmallString<128> Path(PGOGenerateArg->getValue());
llvm::sys::path::append(Path, "default_%m.profraw");
CmdArgs.push_back(
Args.MakeArgString(Twine("-fprofile-instrument-path=") + Path));
}
}
if (ProfileUseArg) {
if (ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ))
CmdArgs.push_back(Args.MakeArgString(
Twine("-fprofile-instrument-use-path=") + ProfileUseArg->getValue()));
else if ((ProfileUseArg->getOption().matches(
options::OPT_fprofile_use_EQ) ||
ProfileUseArg->getOption().matches(
options::OPT_fprofile_instr_use))) {
SmallString<128> Path(
ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue());
if (Path.empty() || llvm::sys::fs::is_directory(Path))
llvm::sys::path::append(Path, "default.profdata");
CmdArgs.push_back(
Args.MakeArgString(Twine("-fprofile-instrument-use-path=") + Path));
}
}
if (Args.hasArg(options::OPT_ftest_coverage) ||
Args.hasArg(options::OPT_coverage))
CmdArgs.push_back("-femit-coverage-notes");
if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
false) ||
Args.hasArg(options::OPT_coverage))
CmdArgs.push_back("-femit-coverage-data");
if (Args.hasFlag(options::OPT_fcoverage_mapping,
options::OPT_fno_coverage_mapping, false)) {
if (!ProfileGenerateArg)
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
<< "-fcoverage-mapping"
<< "-fprofile-instr-generate";
CmdArgs.push_back("-fcoverage-mapping");
}
if (Args.hasArg(options::OPT_fprofile_exclude_files_EQ)) {
auto *Arg = Args.getLastArg(options::OPT_fprofile_exclude_files_EQ);
if (!Args.hasArg(options::OPT_coverage))
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
<< "-fprofile-exclude-files="
<< "--coverage";
StringRef v = Arg->getValue();
CmdArgs.push_back(
Args.MakeArgString(Twine("-fprofile-exclude-files=" + v)));
}
if (Args.hasArg(options::OPT_fprofile_filter_files_EQ)) {
auto *Arg = Args.getLastArg(options::OPT_fprofile_filter_files_EQ);
if (!Args.hasArg(options::OPT_coverage))
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
<< "-fprofile-filter-files="
<< "--coverage";
StringRef v = Arg->getValue();
CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-filter-files=" + v)));
}
if (C.getArgs().hasArg(options::OPT_c) ||
C.getArgs().hasArg(options::OPT_S)) {
if (Output.isFilename()) {
CmdArgs.push_back("-coverage-notes-file");
SmallString<128> OutputFilename;
if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
OutputFilename = FinalOutput->getValue();
else
OutputFilename = llvm::sys::path::filename(Output.getBaseInput());
SmallString<128> CoverageFilename = OutputFilename;
if (llvm::sys::path::is_relative(CoverageFilename)) {
SmallString<128> Pwd;
if (!llvm::sys::fs::current_path(Pwd)) {
llvm::sys::path::append(Pwd, CoverageFilename);
CoverageFilename.swap(Pwd);
}
}
llvm::sys::path::replace_extension(CoverageFilename, "gcno");
CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
// Leave -fprofile-dir= an unused argument unless .gcda emission is
// enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider
// the flag used. There is no -fno-profile-dir, so the user has no
// targeted way to suppress the warning.
if (Args.hasArg(options::OPT_fprofile_arcs) ||
Args.hasArg(options::OPT_coverage)) {
CmdArgs.push_back("-coverage-data-file");
if (Arg *FProfileDir = Args.getLastArg(options::OPT_fprofile_dir)) {
CoverageFilename = FProfileDir->getValue();
llvm::sys::path::append(CoverageFilename, OutputFilename);
}
llvm::sys::path::replace_extension(CoverageFilename, "gcda");
CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
}
}
}
}
/// Check whether the given input tree contains any compilation actions.
static bool ContainsCompileAction(const Action *A) {
if (isa<CompileJobAction>(A) || isa<BackendJobAction>(A))
return true;
for (const auto &AI : A->inputs())
if (ContainsCompileAction(AI))
return true;
return false;
}
/// Check if -relax-all should be passed to the internal assembler.
/// This is done by default when compiling non-assembler source with -O0.
static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
bool RelaxDefault = true;
if (Arg *A = Args.getLastArg(options::OPT_O_Group))
RelaxDefault = A->getOption().matches(options::OPT_O0);
if (RelaxDefault) {
RelaxDefault = false;
for (const auto &Act : C.getActions()) {
if (ContainsCompileAction(Act)) {
RelaxDefault = true;
break;
}
}
}
return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all,
RelaxDefault);
}
// Extract the integer N from a string spelled "-dwarf-N", returning 0
// on mismatch. The StringRef input (rather than an Arg) allows
// for use by the "-Xassembler" option parser.
static unsigned DwarfVersionNum(StringRef ArgValue) {
return llvm::StringSwitch<unsigned>(ArgValue)
.Case("-gdwarf-2", 2)
.Case("-gdwarf-3", 3)
.Case("-gdwarf-4", 4)
.Case("-gdwarf-5", 5)
.Default(0);
}
static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs,
codegenoptions::DebugInfoKind DebugInfoKind,
unsigned DwarfVersion,
llvm::DebuggerKind DebuggerTuning) {
switch (DebugInfoKind) {
case codegenoptions::DebugDirectivesOnly:
CmdArgs.push_back("-debug-info-kind=line-directives-only");
break;
case codegenoptions::DebugLineTablesOnly:
CmdArgs.push_back("-debug-info-kind=line-tables-only");
break;
case codegenoptions::LimitedDebugInfo:
CmdArgs.push_back("-debug-info-kind=limited");
break;
case codegenoptions::FullDebugInfo:
CmdArgs.push_back("-debug-info-kind=standalone");
break;
default:
break;
}
if (DwarfVersion > 0)
CmdArgs.push_back(
Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion)));
switch (DebuggerTuning) {
case llvm::DebuggerKind::GDB:
CmdArgs.push_back("-debugger-tuning=gdb");
break;
case llvm::DebuggerKind::LLDB:
CmdArgs.push_back("-debugger-tuning=lldb");
break;
case llvm::DebuggerKind::SCE:
CmdArgs.push_back("-debugger-tuning=sce");
break;
default:
break;
}
}
static bool checkDebugInfoOption(const Arg *A, const ArgList &Args,
const Driver &D, const ToolChain &TC) {
assert(A && "Expected non-nullptr argument.");
if (TC.supportsDebugInfoOption(A))
return true;
D.Diag(diag::warn_drv_unsupported_debug_info_opt_for_target)
<< A->getAsString(Args) << TC.getTripleString();
return false;
}
static void RenderDebugInfoCompressionArgs(const ArgList &Args,
ArgStringList &CmdArgs,
const Driver &D,
const ToolChain &TC) {
const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ);
if (!A)
return;
if (checkDebugInfoOption(A, Args, D, TC)) {
if (A->getOption().getID() == options::OPT_gz) {
if (llvm::zlib::isAvailable())
CmdArgs.push_back("-compress-debug-sections");
else
D.Diag(diag::warn_debug_compression_unavailable);
return;
}
StringRef Value = A->getValue();
if (Value == "none") {
CmdArgs.push_back("-compress-debug-sections=none");
} else if (Value == "zlib" || Value == "zlib-gnu") {
if (llvm::zlib::isAvailable()) {
CmdArgs.push_back(
Args.MakeArgString("-compress-debug-sections=" + Twine(Value)));
} else {
D.Diag(diag::warn_debug_compression_unavailable);
}
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
}
}
}
static const char *RelocationModelName(llvm::Reloc::Model Model) {
switch (Model) {
case llvm::Reloc::Static:
return "static";
case llvm::Reloc::PIC_:
return "pic";
case llvm::Reloc::DynamicNoPIC:
return "dynamic-no-pic";
case llvm::Reloc::ROPI:
return "ropi";
case llvm::Reloc::RWPI:
return "rwpi";
case llvm::Reloc::ROPI_RWPI:
return "ropi-rwpi";
}
llvm_unreachable("Unknown Reloc::Model kind");
}
void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
const Driver &D, const ArgList &Args,
ArgStringList &CmdArgs,
const InputInfo &Output,
const InputInfoList &Inputs) const {
Arg *A;
const bool IsIAMCU = getToolChain().getTriple().isOSIAMCU();
CheckPreprocessingOptions(D, Args);
Args.AddLastArg(CmdArgs, options::OPT_C);
Args.AddLastArg(CmdArgs, options::OPT_CC);
// Handle dependency file generation.
if ((A = Args.getLastArg(options::OPT_M, options::OPT_MM)) ||
(A = Args.getLastArg(options::OPT_MD)) ||
(A = Args.getLastArg(options::OPT_MMD))) {
// Determine the output location.
const char *DepFile;
if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
DepFile = MF->getValue();
C.addFailureResultFile(DepFile, &JA);
} else if (Output.getType() == types::TY_Dependencies) {
DepFile = Output.getFilename();
} else if (A->getOption().matches(options::OPT_M) ||
A->getOption().matches(options::OPT_MM)) {
DepFile = "-";
} else {
DepFile = getDependencyFileName(Args, Inputs);
C.addFailureResultFile(DepFile, &JA);
}
CmdArgs.push_back("-dependency-file");
CmdArgs.push_back(DepFile);
// Add a default target if one wasn't specified.
if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) {
const char *DepTarget;
// If user provided -o, that is the dependency target, except
// when we are only generating a dependency file.
Arg *OutputOpt = Args.getLastArg(options::OPT_o);
if (OutputOpt && Output.getType() != types::TY_Dependencies) {
DepTarget = OutputOpt->getValue();
} else {
// Otherwise derive from the base input.
//
// FIXME: This should use the computed output file location.
SmallString<128> P(Inputs[0].getBaseInput());
llvm::sys::path::replace_extension(P, "o");
DepTarget = Args.MakeArgString(llvm::sys::path::filename(P));
}
if (!A->getOption().matches(options::OPT_MD) && !A->getOption().matches(options::OPT_MMD)) {
CmdArgs.push_back("-w");
}
CmdArgs.push_back("-MT");
SmallString<128> Quoted;
QuoteTarget(DepTarget, Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
}
if (A->getOption().matches(options::OPT_M) ||
A->getOption().matches(options::OPT_MD))
CmdArgs.push_back("-sys-header-deps");
if ((isa<PrecompileJobAction>(JA) &&
!Args.hasArg(options::OPT_fno_module_file_deps)) ||
Args.hasArg(options::OPT_fmodule_file_deps))
CmdArgs.push_back("-module-file-deps");
}
if (Args.hasArg(options::OPT_MG)) {
if (!A || A->getOption().matches(options::OPT_MD) ||
A->getOption().matches(options::OPT_MMD))
D.Diag(diag::err_drv_mg_requires_m_or_mm);
CmdArgs.push_back("-MG");
}
Args.AddLastArg(CmdArgs, options::OPT_MP);
Args.AddLastArg(CmdArgs, options::OPT_MV);
// Convert all -MQ <target> args to -MT <quoted target>
for (const Arg *A : Args.filtered(options::OPT_MT, options::OPT_MQ)) {
A->claim();
if (A->getOption().matches(options::OPT_MQ)) {
CmdArgs.push_back("-MT");
SmallString<128> Quoted;
QuoteTarget(A->getValue(), Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
// -MT flag - no change
} else {
A->render(Args, CmdArgs);
}
}
// Add offload include arguments specific for CUDA. This must happen before
// we -I or -include anything else, because we must pick up the CUDA headers
// from the particular CUDA installation, rather than from e.g.
// /usr/local/include.
if (JA.isOffloading(Action::OFK_Cuda))
getToolChain().AddCudaIncludeArgs(Args, CmdArgs);
// Add -i* options, and automatically translate to
// -include-pch/-include-pth for transparent PCH support. It's
// wonky, but we include looking for .gch so we can support seamless
// replacement into a build system already set up to be generating
// .gch files.
if (getToolChain().getDriver().IsCLMode()) {
const Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc);
const Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu);
if (YcArg && JA.getKind() >= Action::PrecompileJobClass &&
JA.getKind() <= Action::AssembleJobClass) {
CmdArgs.push_back(Args.MakeArgString("-building-pch-with-obj"));
}
if (YcArg || YuArg) {
StringRef ThroughHeader = YcArg ? YcArg->getValue() : YuArg->getValue();
if (!isa<PrecompileJobAction>(JA)) {
CmdArgs.push_back("-include-pch");
CmdArgs.push_back(Args.MakeArgString(D.GetClPchPath(
C, !ThroughHeader.empty()
? ThroughHeader
: llvm::sys::path::filename(Inputs[0].getBaseInput()))));
}
if (ThroughHeader.empty()) {
CmdArgs.push_back(Args.MakeArgString(
Twine("-pch-through-hdrstop-") + (YcArg ? "create" : "use")));
} else {
CmdArgs.push_back(
Args.MakeArgString(Twine("-pch-through-header=") + ThroughHeader));
}
}
}
bool RenderedImplicitInclude = false;
for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) {
if (A->getOption().matches(options::OPT_include)) {
// Handling of gcc-style gch precompiled headers.
bool IsFirstImplicitInclude = !RenderedImplicitInclude;
RenderedImplicitInclude = true;
bool FoundPCH = false;
SmallString<128> P(A->getValue());
// We want the files to have a name like foo.h.pch. Add a dummy extension
// so that replace_extension does the right thing.
P += ".dummy";
llvm::sys::path::replace_extension(P, "pch");
if (llvm::sys::fs::exists(P))
FoundPCH = true;
if (!FoundPCH) {
llvm::sys::path::replace_extension(P, "gch");
if (llvm::sys::fs::exists(P)) {
FoundPCH = true;
}
}
if (FoundPCH) {
if (IsFirstImplicitInclude) {
A->claim();
CmdArgs.push_back("-include-pch");
CmdArgs.push_back(Args.MakeArgString(P));
continue;
} else {
// Ignore the PCH if not first on command line and emit warning.
D.Diag(diag::warn_drv_pch_not_first_include) << P
<< A->getAsString(Args);
}
}
} else if (A->getOption().matches(options::OPT_isystem_after)) {
// Handling of paths which must come late. These entries are handled by
// the toolchain itself after the resource dir is inserted in the right
// search order.
// Do not claim the argument so that the use of the argument does not
// silently go unnoticed on toolchains which do not honour the option.
continue;
}
// Not translated, render as usual.
A->claim();
A->render(Args, CmdArgs);
}
Args.AddAllArgs(CmdArgs,
{options::OPT_D, options::OPT_U, options::OPT_I_Group,
options::OPT_F, options::OPT_index_header_map});
// Add -Wp, and -Xpreprocessor if using the preprocessor.
// FIXME: There is a very unfortunate problem here, some troubled
// souls abuse -Wp, to pass preprocessor options in gcc syntax. To
// really support that we would have to parse and then translate
// those options. :(
Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA,
options::OPT_Xpreprocessor);
// -I- is a deprecated GCC feature, reject it.
if (Arg *A = Args.getLastArg(options::OPT_I_))
D.Diag(diag::err_drv_I_dash_not_supported) << A->getAsString(Args);
// If we have a --sysroot, and don't have an explicit -isysroot flag, add an
// -isysroot to the CC1 invocation.
StringRef sysroot = C.getSysRoot();
if (sysroot != "") {
if (!Args.hasArg(options::OPT_isysroot)) {
CmdArgs.push_back("-isysroot");
CmdArgs.push_back(C.getArgs().MakeArgString(sysroot));
}
}
// Parse additional include paths from environment variables.
// FIXME: We should probably sink the logic for handling these from the
// frontend into the driver. It will allow deleting 4 otherwise unused flags.
// CPATH - included following the user specified includes (but prior to
// builtin and standard includes).
addDirectoryList(Args, CmdArgs, "-I", "CPATH");
// C_INCLUDE_PATH - system includes enabled when compiling C.
addDirectoryList(Args, CmdArgs, "-c-isystem", "C_INCLUDE_PATH");
// CPLUS_INCLUDE_PATH - system includes enabled when compiling C++.
addDirectoryList(Args, CmdArgs, "-cxx-isystem", "CPLUS_INCLUDE_PATH");
// OBJC_INCLUDE_PATH - system includes enabled when compiling ObjC.
addDirectoryList(Args, CmdArgs, "-objc-isystem", "OBJC_INCLUDE_PATH");
// OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++.
addDirectoryList(Args, CmdArgs, "-objcxx-isystem", "OBJCPLUS_INCLUDE_PATH");
// While adding the include arguments, we also attempt to retrieve the
// arguments of related offloading toolchains or arguments that are specific
// of an offloading programming model.
// Add C++ include arguments, if needed.
if (types::isCXX(Inputs[0].getType()))
forAllAssociatedToolChains(C, JA, getToolChain(),
[&Args, &CmdArgs](const ToolChain &TC) {
TC.AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
});
// Add system include arguments for all targets but IAMCU.
if (!IsIAMCU)
forAllAssociatedToolChains(C, JA, getToolChain(),
[&Args, &CmdArgs](const ToolChain &TC) {
TC.AddClangSystemIncludeArgs(Args, CmdArgs);
});
else {
// For IAMCU add special include arguments.
getToolChain().AddIAMCUIncludeArgs(Args, CmdArgs);
}
}
// FIXME: Move to target hook.
static bool isSignedCharDefault(const llvm::Triple &Triple) {
switch (Triple.getArch()) {
default:
return true;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
if (Triple.isOSDarwin() || Triple.isOSWindows())
return true;
return false;
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
if (Triple.isOSDarwin())
return true;
return false;
case llvm::Triple::hexagon:
case llvm::Triple::ppc64le:
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
case llvm::Triple::systemz:
case llvm::Triple::xcore:
return false;
}
}
static bool isNoCommonDefault(const llvm::Triple &Triple) {
switch (Triple.getArch()) {
default:
if (Triple.isOSFuchsia())
return true;
return false;
case llvm::Triple::xcore:
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
return true;
}
}
namespace {
void RenderARMABI(const llvm::Triple &Triple, const ArgList &Args,
ArgStringList &CmdArgs) {
// Select the ABI to use.
// FIXME: Support -meabi.
// FIXME: Parts of this are duplicated in the backend, unify this somehow.
const char *ABIName = nullptr;
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
ABIName = A->getValue();
} else {
std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false);
ABIName = llvm::ARM::computeDefaultTargetABI(Triple, CPU).data();
}
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName);
}
}
void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
ArgStringList &CmdArgs, bool KernelOrKext) const {
RenderARMABI(Triple, Args, CmdArgs);
// Determine floating point ABI from the options & target defaults.
arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args);
if (ABI == arm::FloatABI::Soft) {
// Floating point operations and argument passing are soft.
// FIXME: This changes CPP defines, we need -target-soft-float.
CmdArgs.push_back("-msoft-float");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("soft");
} else if (ABI == arm::FloatABI::SoftFP) {
// Floating point operations are hard, but argument passing is soft.
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("soft");
} else {
// Floating point operations and argument passing are hard.
assert(ABI == arm::FloatABI::Hard && "Invalid float abi!");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("hard");
}
// Forward the -mglobal-merge option for explicit control over the pass.
if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
options::OPT_mno_global_merge)) {
CmdArgs.push_back("-mllvm");
if (A->getOption().matches(options::OPT_mno_global_merge))
CmdArgs.push_back("-arm-global-merge=false");
else
CmdArgs.push_back("-arm-global-merge=true");
}
if (!Args.hasFlag(options::OPT_mimplicit_float,
options::OPT_mno_implicit_float, true))
CmdArgs.push_back("-no-implicit-float");
}
void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple,
const ArgList &Args, bool KernelOrKext,
ArgStringList &CmdArgs) const {
const ToolChain &TC = getToolChain();
// Add the target features
getTargetFeatures(TC, EffectiveTriple, Args, CmdArgs, false);
// Add target specific flags.
switch (TC.getArch()) {
default:
break;
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
// Use the effective triple, which takes into account the deployment target.
AddARMTargetArgs(EffectiveTriple, Args, CmdArgs, KernelOrKext);
CmdArgs.push_back("-fallow-half-arguments-and-returns");
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
AddAArch64TargetArgs(Args, CmdArgs);
CmdArgs.push_back("-fallow-half-arguments-and-returns");
break;
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
AddMIPSTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
AddPPCTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
AddRISCVTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::sparc:
case llvm::Triple::sparcel:
case llvm::Triple::sparcv9:
AddSparcTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::systemz:
AddSystemZTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::x86:
case llvm::Triple::x86_64:
AddX86TargetArgs(Args, CmdArgs);
break;
case llvm::Triple::lanai:
AddLanaiTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::hexagon:
AddHexagonTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
AddWebAssemblyTargetArgs(Args, CmdArgs);
break;
}
}
// Parse -mbranch-protection=<protection>[+<protection>]* where
// <protection> ::= standard | none | [bti,pac-ret[+b-key,+leaf]*]
// Returns a triple of (return address signing Scope, signing key, require
// landing pads)
static std::tuple<StringRef, StringRef, bool>
ParseAArch64BranchProtection(const Driver &D, const ArgList &Args,
const Arg *A) {
StringRef Scope = "none";
StringRef Key = "a_key";
bool IndirectBranches = false;
StringRef Value = A->getValue();
// This maps onto -mbranch-protection=<scope>+<key>
if (Value.equals("standard")) {
Scope = "non-leaf";
Key = "a_key";
IndirectBranches = true;
} else if (!Value.equals("none")) {
SmallVector<StringRef, 4> BranchProtection;
StringRef(A->getValue()).split(BranchProtection, '+');
auto Protection = BranchProtection.begin();
while (Protection != BranchProtection.end()) {
if (Protection->equals("bti"))
IndirectBranches = true;
else if (Protection->equals("pac-ret")) {
Scope = "non-leaf";
while (++Protection != BranchProtection.end()) {
// Inner loop as "leaf" and "b-key" options must only appear attached
// to pac-ret.
if (Protection->equals("leaf"))
Scope = "all";
else if (Protection->equals("b-key"))
Key = "b_key";
else
break;
}
Protection--;
} else
D.Diag(diag::err_invalid_branch_protection)
<< *Protection << A->getAsString(Args);
Protection++;
}
}
return std::make_tuple(Scope, Key, IndirectBranches);
}
namespace {
void RenderAArch64ABI(const llvm::Triple &Triple, const ArgList &Args,
ArgStringList &CmdArgs) {
const char *ABIName = nullptr;
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
ABIName = A->getValue();
else if (Triple.isOSDarwin())
ABIName = "darwinpcs";
else
ABIName = "aapcs";
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName);
}
}
void Clang::AddAArch64TargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) ||
Args.hasArg(options::OPT_mkernel) ||
Args.hasArg(options::OPT_fapple_kext))
CmdArgs.push_back("-disable-red-zone");
if (!Args.hasFlag(options::OPT_mimplicit_float,
options::OPT_mno_implicit_float, true))
CmdArgs.push_back("-no-implicit-float");
RenderAArch64ABI(Triple, Args, CmdArgs);
if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769,
options::OPT_mno_fix_cortex_a53_835769)) {
CmdArgs.push_back("-mllvm");
if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769))
CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1");
else
CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=0");
} else if (Triple.isAndroid()) {
// Enabled A53 errata (835769) workaround by default on android
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1");
}
// Forward the -mglobal-merge option for explicit control over the pass.
if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
options::OPT_mno_global_merge)) {
CmdArgs.push_back("-mllvm");
if (A->getOption().matches(options::OPT_mno_global_merge))
CmdArgs.push_back("-aarch64-enable-global-merge=false");
else
CmdArgs.push_back("-aarch64-enable-global-merge=true");
}
// Enable/disable return address signing and indirect branch targets.
if (Arg *A = Args.getLastArg(options::OPT_msign_return_address_EQ,
options::OPT_mbranch_protection_EQ)) {
const Driver &D = getToolChain().getDriver();
StringRef Scope, Key;
bool IndirectBranches;
if (A->getOption().matches(options::OPT_msign_return_address_EQ)) {
Scope = A->getValue();
if (!Scope.equals("none") && !Scope.equals("non-leaf") &&
!Scope.equals("all"))
D.Diag(diag::err_invalid_branch_protection)
<< Scope << A->getAsString(Args);
Key = "a_key";
IndirectBranches = false;
} else
std::tie(Scope, Key, IndirectBranches) =
ParseAArch64BranchProtection(D, Args, A);
CmdArgs.push_back(
Args.MakeArgString(Twine("-msign-return-address=") + Scope));
CmdArgs.push_back(
Args.MakeArgString(Twine("-msign-return-address-key=") + Key));
if (IndirectBranches)
CmdArgs.push_back("-mbranch-target-enforce");
}
}
void Clang::AddMIPSTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getDriver();
StringRef CPUName;
StringRef ABIName;
const llvm::Triple &Triple = getToolChain().getTriple();
mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName.data());
mips::FloatABI ABI = mips::getMipsFloatABI(D, Args);
if (ABI == mips::FloatABI::Soft) {
// Floating point operations and argument passing are soft.
CmdArgs.push_back("-msoft-float");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("soft");
} else {
// Floating point operations and argument passing are hard.
assert(ABI == mips::FloatABI::Hard && "Invalid float abi!");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("hard");
}
if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) {
if (A->getOption().matches(options::OPT_mxgot)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-mxgot");
}
}
if (Arg *A = Args.getLastArg(options::OPT_mldc1_sdc1,
options::OPT_mno_ldc1_sdc1)) {
if (A->getOption().matches(options::OPT_mno_ldc1_sdc1)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-mno-ldc1-sdc1");
}
}
if (Arg *A = Args.getLastArg(options::OPT_mcheck_zero_division,
options::OPT_mno_check_zero_division)) {
if (A->getOption().matches(options::OPT_mno_check_zero_division)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-mno-check-zero-division");
}
}
if (Arg *A = Args.getLastArg(options::OPT_G)) {
StringRef v = A->getValue();
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString("-mips-ssection-threshold=" + v));
A->claim();
}
Arg *GPOpt = Args.getLastArg(options::OPT_mgpopt, options::OPT_mno_gpopt);
Arg *ABICalls =
Args.getLastArg(options::OPT_mabicalls, options::OPT_mno_abicalls);
// -mabicalls is the default for many MIPS environments, even with -fno-pic.
// -mgpopt is the default for static, -fno-pic environments but these two
// options conflict. We want to be certain that -mno-abicalls -mgpopt is
// the only case where -mllvm -mgpopt is passed.
// NOTE: We need a warning here or in the backend to warn when -mgpopt is
// passed explicitly when compiling something with -mabicalls
// (implictly) in affect. Currently the warning is in the backend.
//
// When the ABI in use is N64, we also need to determine the PIC mode that
// is in use, as -fno-pic for N64 implies -mno-abicalls.
bool NoABICalls =
ABICalls && ABICalls->getOption().matches(options::OPT_mno_abicalls);
llvm::Reloc::Model RelocationModel;
unsigned PICLevel;
bool IsPIE;
std::tie(RelocationModel, PICLevel, IsPIE) =
ParsePICArgs(getToolChain(), Args);
NoABICalls = NoABICalls ||
(RelocationModel == llvm::Reloc::Static && ABIName == "n64");
bool WantGPOpt = GPOpt && GPOpt->getOption().matches(options::OPT_mgpopt);
// We quietly ignore -mno-gpopt as the backend defaults to -mno-gpopt.
if (NoABICalls && (!GPOpt || WantGPOpt)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-mgpopt");
Arg *LocalSData = Args.getLastArg(options::OPT_mlocal_sdata,
options::OPT_mno_local_sdata);
Arg *ExternSData = Args.getLastArg(options::OPT_mextern_sdata,
options::OPT_mno_extern_sdata);
Arg *EmbeddedData = Args.getLastArg(options::OPT_membedded_data,
options::OPT_mno_embedded_data);
if (LocalSData) {
CmdArgs.push_back("-mllvm");
if (LocalSData->getOption().matches(options::OPT_mlocal_sdata)) {
CmdArgs.push_back("-mlocal-sdata=1");
} else {
CmdArgs.push_back("-mlocal-sdata=0");
}
LocalSData->claim();
}
if (ExternSData) {
CmdArgs.push_back("-mllvm");
if (ExternSData->getOption().matches(options::OPT_mextern_sdata)) {
CmdArgs.push_back("-mextern-sdata=1");
} else {
CmdArgs.push_back("-mextern-sdata=0");
}
ExternSData->claim();
}
if (EmbeddedData) {
CmdArgs.push_back("-mllvm");
if (EmbeddedData->getOption().matches(options::OPT_membedded_data)) {
CmdArgs.push_back("-membedded-data=1");
} else {
CmdArgs.push_back("-membedded-data=0");
}
EmbeddedData->claim();
}
} else if ((!ABICalls || (!NoABICalls && ABICalls)) && WantGPOpt)
D.Diag(diag::warn_drv_unsupported_gpopt) << (ABICalls ? 0 : 1);
if (GPOpt)
GPOpt->claim();
if (Arg *A = Args.getLastArg(options::OPT_mcompact_branches_EQ)) {
StringRef Val = StringRef(A->getValue());
if (mips::hasCompactBranches(CPUName)) {
if (Val == "never" || Val == "always" || Val == "optimal") {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString("-mips-compact-branches=" + Val));
} else
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Val;
} else
D.Diag(diag::warn_target_unsupported_compact_branches) << CPUName;
}
if (Arg *A = Args.getLastArg(options::OPT_mrelax_pic_calls,
options::OPT_mno_relax_pic_calls)) {
if (A->getOption().matches(options::OPT_mno_relax_pic_calls)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-mips-jalr-reloc=0");
}
}
}
void Clang::AddPPCTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// Select the ABI to use.
const char *ABIName = nullptr;
if (getToolChain().getTriple().isOSLinux())
switch (getToolChain().getArch()) {
case llvm::Triple::ppc64: {
// When targeting a processor that supports QPX, or if QPX is
// specifically enabled, default to using the ABI that supports QPX (so
// long as it is not specifically disabled).
bool HasQPX = false;
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
HasQPX = A->getValue() == StringRef("a2q");
HasQPX = Args.hasFlag(options::OPT_mqpx, options::OPT_mno_qpx, HasQPX);
if (HasQPX) {
ABIName = "elfv1-qpx";
break;
}
ABIName = "elfv1";
break;
}
case llvm::Triple::ppc64le:
ABIName = "elfv2";
break;
default:
break;
}
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
// The ppc64 linux abis are all "altivec" abis by default. Accept and ignore
// the option if given as we don't have backend support for any targets
// that don't use the altivec abi.
if (StringRef(A->getValue()) != "altivec")
ABIName = A->getValue();
ppc::FloatABI FloatABI =
ppc::getPPCFloatABI(getToolChain().getDriver(), Args);
if (FloatABI == ppc::FloatABI::Soft) {
// Floating point operations and argument passing are soft.
CmdArgs.push_back("-msoft-float");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("soft");
} else {
// Floating point operations and argument passing are hard.
assert(FloatABI == ppc::FloatABI::Hard && "Invalid float abi!");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("hard");
}
if (ABIName) {
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName);
}
}
void Clang::AddRISCVTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// FIXME: currently defaults to the soft-float ABIs. Will need to be
// expanded to select ilp32f, ilp32d, lp64f, lp64d when appropriate.
const char *ABIName = nullptr;
const llvm::Triple &Triple = getToolChain().getTriple();
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
ABIName = A->getValue();
else if (Triple.getArch() == llvm::Triple::riscv32)
ABIName = "ilp32";
else if (Triple.getArch() == llvm::Triple::riscv64)
ABIName = "lp64";
else
llvm_unreachable("Unexpected triple!");
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName);
}
void Clang::AddSparcTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
sparc::FloatABI FloatABI =
sparc::getSparcFloatABI(getToolChain().getDriver(), Args);
if (FloatABI == sparc::FloatABI::Soft) {
// Floating point operations and argument passing are soft.
CmdArgs.push_back("-msoft-float");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("soft");
} else {
// Floating point operations and argument passing are hard.
assert(FloatABI == sparc::FloatABI::Hard && "Invalid float abi!");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("hard");
}
}
void Clang::AddSystemZTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
if (Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false))
CmdArgs.push_back("-mbackchain");
}
void Clang::AddX86TargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) ||
Args.hasArg(options::OPT_mkernel) ||
Args.hasArg(options::OPT_fapple_kext))
CmdArgs.push_back("-disable-red-zone");
if (!Args.hasFlag(options::OPT_mtls_direct_seg_refs,
options::OPT_mno_tls_direct_seg_refs, true))
CmdArgs.push_back("-mno-tls-direct-seg-refs");
// Default to avoid implicit floating-point for kernel/kext code, but allow
// that to be overridden with -mno-soft-float.
bool NoImplicitFloat = (Args.hasArg(options::OPT_mkernel) ||
Args.hasArg(options::OPT_fapple_kext));
if (Arg *A = Args.getLastArg(
options::OPT_msoft_float, options::OPT_mno_soft_float,
options::OPT_mimplicit_float, options::OPT_mno_implicit_float)) {
const Option &O = A->getOption();
NoImplicitFloat = (O.matches(options::OPT_mno_implicit_float) ||
O.matches(options::OPT_msoft_float));
}
if (NoImplicitFloat)
CmdArgs.push_back("-no-implicit-float");
if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) {
StringRef Value = A->getValue();
if (Value == "intel" || Value == "att") {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
} else {
getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
}
} else if (getToolChain().getDriver().IsCLMode()) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-x86-asm-syntax=intel");
}
// Set flags to support MCU ABI.
if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) {
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("soft");
CmdArgs.push_back("-mstack-alignment=4");
}
}
void Clang::AddHexagonTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
CmdArgs.push_back("-mqdsp6-compat");
CmdArgs.push_back("-Wreturn-type");
if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString("-hexagon-small-data-threshold=" +
Twine(G.getValue())));
}
if (!Args.hasArg(options::OPT_fno_short_enums))
CmdArgs.push_back("-fshort-enums");
if (Args.getLastArg(options::OPT_mieee_rnd_near)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-enable-hexagon-ieee-rnd-near");
}
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-machine-sink-split=0");
}
void Clang::AddLanaiTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
StringRef CPUName = A->getValue();
CmdArgs.push_back("-target-cpu");
CmdArgs.push_back(Args.MakeArgString(CPUName));
}
if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
StringRef Value = A->getValue();
// Only support mregparm=4 to support old usage. Report error for all other
// cases.
int Mregparm;
if (Value.getAsInteger(10, Mregparm)) {
if (Mregparm != 4) {
getToolChain().getDriver().Diag(
diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
}
}
}
}
void Clang::AddWebAssemblyTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// Default to "hidden" visibility.
if (!Args.hasArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat)) {
CmdArgs.push_back("-fvisibility");
CmdArgs.push_back("hidden");
}
}
void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
StringRef Target, const InputInfo &Output,
const InputInfo &Input, const ArgList &Args) const {
// If this is a dry run, do not create the compilation database file.
if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH))
return;
using llvm::yaml::escape;
const Driver &D = getToolChain().getDriver();
if (!CompilationDatabase) {
std::error_code EC;
auto File = llvm::make_unique<llvm::raw_fd_ostream>(Filename, EC, llvm::sys::fs::F_Text);
if (EC) {
D.Diag(clang::diag::err_drv_compilationdatabase) << Filename
<< EC.message();
return;
}
CompilationDatabase = std::move(File);
}
auto &CDB = *CompilationDatabase;
SmallString<128> Buf;
if (llvm::sys::fs::current_path(Buf))
Buf = ".";
CDB << "{ \"directory\": \"" << escape(Buf) << "\"";
CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\"";
CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\"";
CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\"";
Buf = "-x";
Buf += types::getTypeName(Input.getType());
CDB << ", \"" << escape(Buf) << "\"";
if (!D.SysRoot.empty() && !Args.hasArg(options::OPT__sysroot_EQ)) {
Buf = "--sysroot=";
Buf += D.SysRoot;
CDB << ", \"" << escape(Buf) << "\"";
}
CDB << ", \"" << escape(Input.getFilename()) << "\"";
for (auto &A: Args) {
auto &O = A->getOption();
// Skip language selection, which is positional.
if (O.getID() == options::OPT_x)
continue;
// Skip writing dependency output and the compilation database itself.
if (O.getGroup().isValid() && O.getGroup().getID() == options::OPT_M_Group)
continue;
// Skip inputs.
if (O.getKind() == Option::InputClass)
continue;
// All other arguments are quoted and appended.
ArgStringList ASL;
A->render(Args, ASL);
for (auto &it: ASL)
CDB << ", \"" << escape(it) << "\"";
}
Buf = "--target=";
Buf += Target;
CDB << ", \"" << escape(Buf) << "\"]},\n";
}
static void CollectArgsForIntegratedAssembler(Compilation &C,
const ArgList &Args,
ArgStringList &CmdArgs,
const Driver &D) {
if (UseRelaxAll(C, Args))
CmdArgs.push_back("-mrelax-all");
// Only default to -mincremental-linker-compatible if we think we are
// targeting the MSVC linker.
bool DefaultIncrementalLinkerCompatible =
C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();
if (Args.hasFlag(options::OPT_mincremental_linker_compatible,
options::OPT_mno_incremental_linker_compatible,
DefaultIncrementalLinkerCompatible))
CmdArgs.push_back("-mincremental-linker-compatible");
switch (C.getDefaultToolChain().getArch()) {
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
if (Arg *A = Args.getLastArg(options::OPT_mimplicit_it_EQ)) {
StringRef Value = A->getValue();
if (Value == "always" || Value == "never" || Value == "arm" ||
Value == "thumb") {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString("-arm-implicit-it=" + Value));
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
}
}
break;
default:
break;
}
// When passing -I arguments to the assembler we sometimes need to
// unconditionally take the next argument. For example, when parsing
// '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the
// -Wa,-I arg and when parsing '-Wa,-I,foo' we need to accept the 'foo'
// arg after parsing the '-I' arg.
bool TakeNextArg = false;
bool UseRelaxRelocations = C.getDefaultToolChain().useRelaxRelocations();
const char *MipsTargetFeature = nullptr;
for (const Arg *A :
Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
A->claim();
for (StringRef Value : A->getValues()) {
if (TakeNextArg) {
CmdArgs.push_back(Value.data());
TakeNextArg = false;
continue;
}
if (C.getDefaultToolChain().getTriple().isOSBinFormatCOFF() &&
Value == "-mbig-obj")
continue; // LLVM handles bigobj automatically
switch (C.getDefaultToolChain().getArch()) {
default:
break;
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
case llvm::Triple::arm:
case llvm::Triple::armeb:
if (Value == "-mthumb")
// -mthumb has already been processed in ComputeLLVMTriple()
// recognize but skip over here.
continue;
break;
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
if (Value == "--trap") {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+use-tcc-in-div");
continue;
}
if (Value == "--break") {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("-use-tcc-in-div");
continue;
}
if (Value.startswith("-msoft-float")) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+soft-float");
continue;
}
if (Value.startswith("-mhard-float")) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("-soft-float");
continue;
}
MipsTargetFeature = llvm::StringSwitch<const char *>(Value)
.Case("-mips1", "+mips1")
.Case("-mips2", "+mips2")
.Case("-mips3", "+mips3")
.Case("-mips4", "+mips4")
.Case("-mips5", "+mips5")
.Case("-mips32", "+mips32")
.Case("-mips32r2", "+mips32r2")
.Case("-mips32r3", "+mips32r3")
.Case("-mips32r5", "+mips32r5")
.Case("-mips32r6", "+mips32r6")
.Case("-mips64", "+mips64")
.Case("-mips64r2", "+mips64r2")
.Case("-mips64r3", "+mips64r3")
.Case("-mips64r5", "+mips64r5")
.Case("-mips64r6", "+mips64r6")
.Default(nullptr);
if (MipsTargetFeature)
continue;
}
if (Value == "-force_cpusubtype_ALL") {
// Do nothing, this is the default and we don't support anything else.
} else if (Value == "-L") {
CmdArgs.push_back("-msave-temp-labels");
} else if (Value == "--fatal-warnings") {
CmdArgs.push_back("-massembler-fatal-warnings");
} else if (Value == "--noexecstack") {
CmdArgs.push_back("-mnoexecstack");
} else if (Value.startswith("-compress-debug-sections") ||
Value.startswith("--compress-debug-sections") ||
Value == "-nocompress-debug-sections" ||
Value == "--nocompress-debug-sections") {
CmdArgs.push_back(Value.data());
} else if (Value == "-mrelax-relocations=yes" ||
Value == "--mrelax-relocations=yes") {
UseRelaxRelocations = true;
} else if (Value == "-mrelax-relocations=no" ||
Value == "--mrelax-relocations=no") {
UseRelaxRelocations = false;
} else if (Value.startswith("-I")) {
CmdArgs.push_back(Value.data());
// We need to consume the next argument if the current arg is a plain
// -I. The next arg will be the include directory.
if (Value == "-I")
TakeNextArg = true;
} else if (Value.startswith("-gdwarf-")) {
// "-gdwarf-N" options are not cc1as options.
unsigned DwarfVersion = DwarfVersionNum(Value);
if (DwarfVersion == 0) { // Send it onward, and let cc1as complain.
CmdArgs.push_back(Value.data());
} else {
RenderDebugEnablingArgs(Args, CmdArgs,
codegenoptions::LimitedDebugInfo,
DwarfVersion, llvm::DebuggerKind::Default);
}
} else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") ||
Value.startswith("-mhwdiv") || Value.startswith("-march")) {
// Do nothing, we'll validate it later.
} else if (Value == "-defsym") {
if (A->getNumValues() != 2) {
D.Diag(diag::err_drv_defsym_invalid_format) << Value;
break;
}
const char *S = A->getValue(1);
auto Pair = StringRef(S).split('=');
auto Sym = Pair.first;
auto SVal = Pair.second;
if (Sym.empty() || SVal.empty()) {
D.Diag(diag::err_drv_defsym_invalid_format) << S;
break;
}
int64_t IVal;
if (SVal.getAsInteger(0, IVal)) {
D.Diag(diag::err_drv_defsym_invalid_symval) << SVal;
break;
}
CmdArgs.push_back(Value.data());
TakeNextArg = true;
} else if (Value == "-fdebug-compilation-dir") {
CmdArgs.push_back("-fdebug-compilation-dir");
TakeNextArg = true;
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
}
}
}
if (UseRelaxRelocations)
CmdArgs.push_back("--mrelax-relocations");
if (MipsTargetFeature != nullptr) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back(MipsTargetFeature);
}
// forward -fembed-bitcode to assmebler
if (C.getDriver().embedBitcodeEnabled() ||
C.getDriver().embedBitcodeMarkerOnly())
Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ);
}
static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
bool OFastEnabled, const ArgList &Args,
ArgStringList &CmdArgs) {
// Handle various floating point optimization flags, mapping them to the
// appropriate LLVM code generation flags. This is complicated by several
// "umbrella" flags, so we do this by stepping through the flags incrementally
// adjusting what we think is enabled/disabled, then at the end setting the
// LLVM flags based on the final state.
bool HonorINFs = true;
bool HonorNaNs = true;
// -fmath-errno is the default on some platforms, e.g. BSD-derived OSes.
bool MathErrno = TC.IsMathErrnoDefault();
bool AssociativeMath = false;
bool ReciprocalMath = false;
bool SignedZeros = true;
bool TrappingMath = true;
StringRef DenormalFPMath = "";
StringRef FPContract = "";
if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
CmdArgs.push_back("-mlimit-float-precision");
CmdArgs.push_back(A->getValue());
}
for (const Arg *A : Args) {
switch (A->getOption().getID()) {
// If this isn't an FP option skip the claim below
default: continue;
// Options controlling individual features
case options::OPT_fhonor_infinities: HonorINFs = true; break;
case options::OPT_fno_honor_infinities: HonorINFs = false; break;
case options::OPT_fhonor_nans: HonorNaNs = true; break;
case options::OPT_fno_honor_nans: HonorNaNs = false; break;
case options::OPT_fmath_errno: MathErrno = true; break;
case options::OPT_fno_math_errno: MathErrno = false; break;
case options::OPT_fassociative_math: AssociativeMath = true; break;
case options::OPT_fno_associative_math: AssociativeMath = false; break;
case options::OPT_freciprocal_math: ReciprocalMath = true; break;
case options::OPT_fno_reciprocal_math: ReciprocalMath = false; break;
case options::OPT_fsigned_zeros: SignedZeros = true; break;
case options::OPT_fno_signed_zeros: SignedZeros = false; break;
case options::OPT_ftrapping_math: TrappingMath = true; break;
case options::OPT_fno_trapping_math: TrappingMath = false; break;
case options::OPT_fdenormal_fp_math_EQ:
DenormalFPMath = A->getValue();
break;
// Validate and pass through -fp-contract option.
case options::OPT_ffp_contract: {
StringRef Val = A->getValue();
if (Val == "fast" || Val == "on" || Val == "off")
FPContract = Val;
else
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Val;
break;
}
case options::OPT_ffinite_math_only:
HonorINFs = false;
HonorNaNs = false;
break;
case options::OPT_fno_finite_math_only:
HonorINFs = true;
HonorNaNs = true;
break;
case options::OPT_funsafe_math_optimizations:
AssociativeMath = true;
ReciprocalMath = true;
SignedZeros = false;
TrappingMath = false;
break;
case options::OPT_fno_unsafe_math_optimizations:
AssociativeMath = false;
ReciprocalMath = false;
SignedZeros = true;
TrappingMath = true;
// -fno_unsafe_math_optimizations restores default denormal handling
DenormalFPMath = "";
break;
case options::OPT_Ofast:
// If -Ofast is the optimization level, then -ffast-math should be enabled
if (!OFastEnabled)
continue;
LLVM_FALLTHROUGH;
case options::OPT_ffast_math:
HonorINFs = false;
HonorNaNs = false;
MathErrno = false;
AssociativeMath = true;
ReciprocalMath = true;
SignedZeros = false;
TrappingMath = false;
// If fast-math is set then set the fp-contract mode to fast.
FPContract = "fast";
break;
case options::OPT_fno_fast_math:
HonorINFs = true;
HonorNaNs = true;
// Turning on -ffast-math (with either flag) removes the need for
// MathErrno. However, turning *off* -ffast-math merely restores the
// toolchain default (which may be false).
MathErrno = TC.IsMathErrnoDefault();
AssociativeMath = false;
ReciprocalMath = false;
SignedZeros = true;
TrappingMath = true;
// -fno_fast_math restores default denormal and fpcontract handling
DenormalFPMath = "";
FPContract = "";
break;
}
// If we handled this option claim it
A->claim();
}
if (!HonorINFs)
CmdArgs.push_back("-menable-no-infs");
if (!HonorNaNs)
CmdArgs.push_back("-menable-no-nans");
if (MathErrno)
CmdArgs.push_back("-fmath-errno");
if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros &&
!TrappingMath)
CmdArgs.push_back("-menable-unsafe-fp-math");
if (!SignedZeros)
CmdArgs.push_back("-fno-signed-zeros");
if (AssociativeMath && !SignedZeros && !TrappingMath)
CmdArgs.push_back("-mreassociate");
if (ReciprocalMath)
CmdArgs.push_back("-freciprocal-math");
if (!TrappingMath)
CmdArgs.push_back("-fno-trapping-math");
if (!DenormalFPMath.empty())
CmdArgs.push_back(
Args.MakeArgString("-fdenormal-fp-math=" + DenormalFPMath));
if (!FPContract.empty())
CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract));
ParseMRecip(D, Args, CmdArgs);
// -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the
// individual features enabled by -ffast-math instead of the option itself as
// that's consistent with gcc's behaviour.
if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath &&
ReciprocalMath && !SignedZeros && !TrappingMath)
CmdArgs.push_back("-ffast-math");
// Handle __FINITE_MATH_ONLY__ similarly.
if (!HonorINFs && !HonorNaNs)
CmdArgs.push_back("-ffinite-math-only");
if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) {
CmdArgs.push_back("-mfpmath");
CmdArgs.push_back(A->getValue());
}
// Disable a codegen optimization for floating-point casts.
if (Args.hasFlag(options::OPT_fno_strict_float_cast_overflow,
options::OPT_fstrict_float_cast_overflow, false))
CmdArgs.push_back("-fno-strict-float-cast-overflow");
}
static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
const llvm::Triple &Triple,
const InputInfo &Input) {
// Enable region store model by default.
CmdArgs.push_back("-analyzer-store=region");
// Treat blocks as analysis entry points.
CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks");
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
CmdArgs.push_back("-analyzer-checker=core");
CmdArgs.push_back("-analyzer-checker=apiModeling");
if (!Triple.isWindowsMSVCEnvironment()) {
CmdArgs.push_back("-analyzer-checker=unix");
} else {
// Enable "unix" checkers that also work on Windows.
CmdArgs.push_back("-analyzer-checker=unix.API");
CmdArgs.push_back("-analyzer-checker=unix.Malloc");
CmdArgs.push_back("-analyzer-checker=unix.MallocSizeof");
CmdArgs.push_back("-analyzer-checker=unix.MismatchedDeallocator");
CmdArgs.push_back("-analyzer-checker=unix.cstring.BadSizeArg");
CmdArgs.push_back("-analyzer-checker=unix.cstring.NullArg");
}
// Disable some unix checkers for PS4.
if (Triple.isPS4CPU()) {
CmdArgs.push_back("-analyzer-disable-checker=unix.API");
CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork");
}
if (Triple.isOSDarwin())
CmdArgs.push_back("-analyzer-checker=osx");
CmdArgs.push_back("-analyzer-checker=deadcode");
if (types::isCXX(Input.getType()))
CmdArgs.push_back("-analyzer-checker=cplusplus");
if (!Triple.isPS4CPU()) {
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.UncheckedReturn");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork");
}
// Default nullability checks.
CmdArgs.push_back("-analyzer-checker=nullability.NullPassedToNonnull");
CmdArgs.push_back("-analyzer-checker=nullability.NullReturnedFromNonnull");
}
// Set the output format. The default is plist, for (lame) historical reasons.
CmdArgs.push_back("-analyzer-output");
if (Arg *A = Args.getLastArg(options::OPT__analyzer_output))
CmdArgs.push_back(A->getValue());
else
CmdArgs.push_back("plist");
// Disable the presentation of standard compiler warnings when using
// --analyze. We only want to show static analyzer diagnostics or frontend
// errors.
CmdArgs.push_back("-w");
// Add -Xanalyzer arguments when running as analyzer.
Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer);
}
static void RenderSSPOptions(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs, bool KernelOrKext) {
const llvm::Triple &EffectiveTriple = TC.getEffectiveTriple();
// NVPTX doesn't support stack protectors; from the compiler's perspective, it
// doesn't even have a stack!
if (EffectiveTriple.isNVPTX())
return;
// -stack-protector=0 is default.
unsigned StackProtectorLevel = 0;
unsigned DefaultStackProtectorLevel =
TC.GetDefaultStackProtectorLevel(KernelOrKext);
if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector,
options::OPT_fstack_protector_all,
options::OPT_fstack_protector_strong,
options::OPT_fstack_protector)) {
if (A->getOption().matches(options::OPT_fstack_protector))
StackProtectorLevel =
std::max<unsigned>(LangOptions::SSPOn, DefaultStackProtectorLevel);
else if (A->getOption().matches(options::OPT_fstack_protector_strong))
StackProtectorLevel = LangOptions::SSPStrong;
else if (A->getOption().matches(options::OPT_fstack_protector_all))
StackProtectorLevel = LangOptions::SSPReq;
} else {
StackProtectorLevel = DefaultStackProtectorLevel;
}
if (StackProtectorLevel) {
CmdArgs.push_back("-stack-protector");
CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel)));
}
// --param ssp-buffer-size=
for (const Arg *A : Args.filtered(options::OPT__param)) {
StringRef Str(A->getValue());
if (Str.startswith("ssp-buffer-size=")) {
if (StackProtectorLevel) {
CmdArgs.push_back("-stack-protector-buffer-size");
// FIXME: Verify the argument is a valid integer.
CmdArgs.push_back(Args.MakeArgString(Str.drop_front(16)));
}
A->claim();
}
}
}
static void RenderTrivialAutoVarInitOptions(const Driver &D,
const ToolChain &TC,
const ArgList &Args,
ArgStringList &CmdArgs) {
auto DefaultTrivialAutoVarInit = TC.GetDefaultTrivialAutoVarInit();
StringRef TrivialAutoVarInit = "";
for (const Arg *A : Args) {
switch (A->getOption().getID()) {
default:
continue;
case options::OPT_ftrivial_auto_var_init: {
A->claim();
StringRef Val = A->getValue();
if (Val == "uninitialized" || Val == "zero" || Val == "pattern")
TrivialAutoVarInit = Val;
else
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Val;
break;
}
}
}
if (TrivialAutoVarInit.empty())
switch (DefaultTrivialAutoVarInit) {
case LangOptions::TrivialAutoVarInitKind::Uninitialized:
break;
case LangOptions::TrivialAutoVarInitKind::Pattern:
TrivialAutoVarInit = "pattern";
break;
case LangOptions::TrivialAutoVarInitKind::Zero:
TrivialAutoVarInit = "zero";
break;
}
if (!TrivialAutoVarInit.empty()) {
if (TrivialAutoVarInit == "zero" && !Args.hasArg(options::OPT_enable_trivial_var_init_zero))
D.Diag(diag::err_drv_trivial_auto_var_init_zero_disabled);
CmdArgs.push_back(
Args.MakeArgString("-ftrivial-auto-var-init=" + TrivialAutoVarInit));
}
}
static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs) {
const unsigned ForwardedArguments[] = {
options::OPT_cl_opt_disable,
options::OPT_cl_strict_aliasing,
options::OPT_cl_single_precision_constant,
options::OPT_cl_finite_math_only,
options::OPT_cl_kernel_arg_info,
options::OPT_cl_unsafe_math_optimizations,
options::OPT_cl_fast_relaxed_math,
options::OPT_cl_mad_enable,
options::OPT_cl_no_signed_zeros,
options::OPT_cl_denorms_are_zero,
options::OPT_cl_fp32_correctly_rounded_divide_sqrt,
options::OPT_cl_uniform_work_group_size
};
if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) {
std::string CLStdStr = std::string("-cl-std=") + A->getValue();
CmdArgs.push_back(Args.MakeArgString(CLStdStr));
}
for (const auto &Arg : ForwardedArguments)
if (const auto *A = Args.getLastArg(Arg))
CmdArgs.push_back(Args.MakeArgString(A->getOption().getPrefixedName()));
}
static void RenderARCMigrateToolOptions(const Driver &D, const ArgList &Args,
ArgStringList &CmdArgs) {
bool ARCMTEnabled = false;
if (!Args.hasArg(options::OPT_fno_objc_arc, options::OPT_fobjc_arc)) {
if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check,
options::OPT_ccc_arcmt_modify,
options::OPT_ccc_arcmt_migrate)) {
ARCMTEnabled = true;
switch (A->getOption().getID()) {
default: llvm_unreachable("missed a case");
case options::OPT_ccc_arcmt_check:
CmdArgs.push_back("-arcmt-check");
break;
case options::OPT_ccc_arcmt_modify:
CmdArgs.push_back("-arcmt-modify");
break;
case options::OPT_ccc_arcmt_migrate:
CmdArgs.push_back("-arcmt-migrate");
CmdArgs.push_back("-mt-migrate-directory");
CmdArgs.push_back(A->getValue());
Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output);
Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors);
break;
}
}
} else {
Args.ClaimAllArgs(options::OPT_ccc_arcmt_check);
Args.ClaimAllArgs(options::OPT_ccc_arcmt_modify);
Args.ClaimAllArgs(options::OPT_ccc_arcmt_migrate);
}
if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) {
if (ARCMTEnabled)
D.Diag(diag::err_drv_argument_not_allowed_with)
<< A->getAsString(Args) << "-ccc-arcmt-migrate";
CmdArgs.push_back("-mt-migrate-directory");
CmdArgs.push_back(A->getValue());
if (!Args.hasArg(options::OPT_objcmt_migrate_literals,
options::OPT_objcmt_migrate_subscripting,
options::OPT_objcmt_migrate_property)) {
// None specified, means enable them all.
CmdArgs.push_back("-objcmt-migrate-literals");
CmdArgs.push_back("-objcmt-migrate-subscripting");
CmdArgs.push_back("-objcmt-migrate-property");
} else {
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property);
}
} else {
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_all);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readonly_property);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readwrite_property);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property_dot_syntax);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_annotation);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_instancetype);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_nsmacros);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_protocol_conformance);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_atomic_property);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_designated_init);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path);
}
}
static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T,
const ArgList &Args, ArgStringList &CmdArgs) {
// -fbuiltin is default unless -mkernel is used.
bool UseBuiltins =
Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin,
!Args.hasArg(options::OPT_mkernel));
if (!UseBuiltins)
CmdArgs.push_back("-fno-builtin");
// -ffreestanding implies -fno-builtin.
if (Args.hasArg(options::OPT_ffreestanding))
UseBuiltins = false;
// Process the -fno-builtin-* options.
for (const auto &Arg : Args) {
const Option &O = Arg->getOption();
if (!O.matches(options::OPT_fno_builtin_))
continue;
Arg->claim();
// If -fno-builtin is specified, then there's no need to pass the option to
// the frontend.
if (!UseBuiltins)
continue;
StringRef FuncName = Arg->getValue();
CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName));
}
// le32-specific flags:
// -fno-math-builtin: clang should not convert math builtins to intrinsics
// by default.
if (TC.getArch() == llvm::Triple::le32)
CmdArgs.push_back("-fno-math-builtin");
}
void Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) {
llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Result);
llvm::sys::path::append(Result, "org.llvm.clang.");
appendUserToPath(Result);
llvm::sys::path::append(Result, "ModuleCache");
}
static void RenderModulesOptions(Compilation &C, const Driver &D,
const ArgList &Args, const InputInfo &Input,
const InputInfo &Output,
ArgStringList &CmdArgs, bool &HaveModules) {
// -fmodules enables the use of precompiled modules (off by default).
// Users can pass -fno-cxx-modules to turn off modules support for
// C++/Objective-C++ programs.
bool HaveClangModules = false;
if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
options::OPT_fno_cxx_modules, true);
if (AllowedInCXX || !types::isCXX(Input.getType())) {
CmdArgs.push_back("-fmodules");
HaveClangModules = true;
}
}
HaveModules = HaveClangModules;
if (Args.hasArg(options::OPT_fmodules_ts)) {
CmdArgs.push_back("-fmodules-ts");
HaveModules = true;
}
// -fmodule-maps enables implicit reading of module map files. By default,
// this is enabled if we are using Clang's flavor of precompiled modules.
if (Args.hasFlag(options::OPT_fimplicit_module_maps,
options::OPT_fno_implicit_module_maps, HaveClangModules))
CmdArgs.push_back("-fimplicit-module-maps");
// -fmodules-decluse checks that modules used are declared so (off by default)
if (Args.hasFlag(options::OPT_fmodules_decluse,
options::OPT_fno_modules_decluse, false))
CmdArgs.push_back("-fmodules-decluse");
// -fmodules-strict-decluse is like -fmodule-decluse, but also checks that
// all #included headers are part of modules.
if (Args.hasFlag(options::OPT_fmodules_strict_decluse,
options::OPT_fno_modules_strict_decluse, false))
CmdArgs.push_back("-fmodules-strict-decluse");
// -fno-implicit-modules turns off implicitly compiling modules on demand.
bool ImplicitModules = false;
if (!Args.hasFlag(options::OPT_fimplicit_modules,
options::OPT_fno_implicit_modules, HaveClangModules)) {
if (HaveModules)
CmdArgs.push_back("-fno-implicit-modules");
} else if (HaveModules) {
ImplicitModules = true;
// -fmodule-cache-path specifies where our implicitly-built module files
// should be written.
SmallString<128> Path;
if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path))
Path = A->getValue();
if (C.isForDiagnostics()) {
// When generating crash reports, we want to emit the modules along with
// the reproduction sources, so we ignore any provided module path.
Path = Output.getFilename();
llvm::sys::path::replace_extension(Path, ".cache");
llvm::sys::path::append(Path, "modules");
} else if (Path.empty()) {
// No module path was provided: use the default.
Driver::getDefaultModuleCachePath(Path);
}
const char Arg[] = "-fmodules-cache-path=";
Path.insert(Path.begin(), Arg, Arg + strlen(Arg));
CmdArgs.push_back(Args.MakeArgString(Path));
}
if (HaveModules) {
// -fprebuilt-module-path specifies where to load the prebuilt module files.
for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) {
CmdArgs.push_back(Args.MakeArgString(
std::string("-fprebuilt-module-path=") + A->getValue()));
A->claim();
}
}
// -fmodule-name specifies the module that is currently being built (or
// used for header checking by -fmodule-maps).
Args.AddLastArg(CmdArgs, options::OPT_fmodule_name_EQ);
// -fmodule-map-file can be used to specify files containing module
// definitions.
Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file);
// -fbuiltin-module-map can be used to load the clang
// builtin headers modulemap file.
if (Args.hasArg(options::OPT_fbuiltin_module_map)) {
SmallString<128> BuiltinModuleMap(D.ResourceDir);
llvm::sys::path::append(BuiltinModuleMap, "include");
llvm::sys::path::append(BuiltinModuleMap, "module.modulemap");
if (llvm::sys::fs::exists(BuiltinModuleMap))
CmdArgs.push_back(
Args.MakeArgString("-fmodule-map-file=" + BuiltinModuleMap));
}
// The -fmodule-file=<name>=<file> form specifies the mapping of module
// names to precompiled module files (the module is loaded only if used).
// The -fmodule-file=<file> form can be used to unconditionally load
// precompiled module files (whether used or not).
if (HaveModules)
Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file);
else
Args.ClaimAllArgs(options::OPT_fmodule_file);
// When building modules and generating crashdumps, we need to dump a module
// dependency VFS alongside the output.
if (HaveClangModules && C.isForDiagnostics()) {
SmallString<128> VFSDir(Output.getFilename());
llvm::sys::path::replace_extension(VFSDir, ".cache");
// Add the cache directory as a temp so the crash diagnostics pick it up.
C.addTempFile(Args.MakeArgString(VFSDir));
llvm::sys::path::append(VFSDir, "vfs");
CmdArgs.push_back("-module-dependency-dir");
CmdArgs.push_back(Args.MakeArgString(VFSDir));
}
if (HaveClangModules)
Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path);
// Pass through all -fmodules-ignore-macro arguments.
Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro);
Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval);
Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after);
Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp);
if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) {
if (Args.hasArg(options::OPT_fbuild_session_timestamp))
D.Diag(diag::err_drv_argument_not_allowed_with)
<< A->getAsString(Args) << "-fbuild-session-timestamp";
llvm::sys::fs::file_status Status;
if (llvm::sys::fs::status(A->getValue(), Status))
D.Diag(diag::err_drv_no_such_file) << A->getValue();
CmdArgs.push_back(
Args.MakeArgString("-fbuild-session-timestamp=" +
Twine((uint64_t)Status.getLastModificationTime()
.time_since_epoch()
.count())));
}
if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) {
if (!Args.getLastArg(options::OPT_fbuild_session_timestamp,
options::OPT_fbuild_session_file))
D.Diag(diag::err_drv_modules_validate_once_requires_timestamp);
Args.AddLastArg(CmdArgs,
options::OPT_fmodules_validate_once_per_build_session);
}
if (Args.hasFlag(options::OPT_fmodules_validate_system_headers,
options::OPT_fno_modules_validate_system_headers,
ImplicitModules))
CmdArgs.push_back("-fmodules-validate-system-headers");
Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation);
}
static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T,
ArgStringList &CmdArgs) {
// -fsigned-char is default.
if (const Arg *A = Args.getLastArg(options::OPT_fsigned_char,
options::OPT_fno_signed_char,
options::OPT_funsigned_char,
options::OPT_fno_unsigned_char)) {
if (A->getOption().matches(options::OPT_funsigned_char) ||
A->getOption().matches(options::OPT_fno_signed_char)) {
CmdArgs.push_back("-fno-signed-char");
}
} else if (!isSignedCharDefault(T)) {
CmdArgs.push_back("-fno-signed-char");
}
// The default depends on the language standard.
if (const Arg *A =
Args.getLastArg(options::OPT_fchar8__t, options::OPT_fno_char8__t))
A->render(Args, CmdArgs);
if (const Arg *A = Args.getLastArg(options::OPT_fshort_wchar,
options::OPT_fno_short_wchar)) {
if (A->getOption().matches(options::OPT_fshort_wchar)) {
CmdArgs.push_back("-fwchar-type=short");
CmdArgs.push_back("-fno-signed-wchar");
} else {
bool IsARM = T.isARM() || T.isThumb() || T.isAArch64();
CmdArgs.push_back("-fwchar-type=int");
if (IsARM && !(T.isOSWindows() || T.isOSNetBSD() ||
T.isOSOpenBSD()))
CmdArgs.push_back("-fno-signed-wchar");
else
CmdArgs.push_back("-fsigned-wchar");
}
}
}
static void RenderObjCOptions(const ToolChain &TC, const Driver &D,
const llvm::Triple &T, const ArgList &Args,
ObjCRuntime &Runtime, bool InferCovariantReturns,
const InputInfo &Input, ArgStringList &CmdArgs) {
const llvm::Triple::ArchType Arch = TC.getArch();
// -fobjc-dispatch-method is only relevant with the nonfragile-abi, and legacy
// is the default. Except for deployment target of 10.5, next runtime is
// always legacy dispatch and -fno-objc-legacy-dispatch gets ignored silently.
if (Runtime.isNonFragile()) {
if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
options::OPT_fno_objc_legacy_dispatch,
Runtime.isLegacyDispatchDefaultForArch(Arch))) {
if (TC.UseObjCMixedDispatch())
CmdArgs.push_back("-fobjc-dispatch-method=mixed");
else
CmdArgs.push_back("-fobjc-dispatch-method=non-legacy");
}
}
// When ObjectiveC legacy runtime is in effect on MacOSX, turn on the option
// to do Array/Dictionary subscripting by default.
if (Arch == llvm::Triple::x86 && T.isMacOSX() &&
Runtime.getKind() == ObjCRuntime::FragileMacOSX && Runtime.isNeXTFamily())
CmdArgs.push_back("-fobjc-subscripting-legacy-runtime");
// Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
// NOTE: This logic is duplicated in ToolChains.cpp.
if (isObjCAutoRefCount(Args)) {
TC.CheckObjCARC();
CmdArgs.push_back("-fobjc-arc");
// FIXME: It seems like this entire block, and several around it should be
// wrapped in isObjC, but for now we just use it here as this is where it
// was being used previously.
if (types::isCXX(Input.getType()) && types::isObjC(Input.getType())) {
if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
CmdArgs.push_back("-fobjc-arc-cxxlib=libc++");
else
CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++");
}
// Allow the user to enable full exceptions code emission.
// We default off for Objective-C, on for Objective-C++.
if (Args.hasFlag(options::OPT_fobjc_arc_exceptions,
options::OPT_fno_objc_arc_exceptions,
/*default=*/types::isCXX(Input.getType())))
CmdArgs.push_back("-fobjc-arc-exceptions");
}
// Silence warning for full exception code emission options when explicitly
// set to use no ARC.
if (Args.hasArg(options::OPT_fno_objc_arc)) {
Args.ClaimAllArgs(options::OPT_fobjc_arc_exceptions);
Args.ClaimAllArgs(options::OPT_fno_objc_arc_exceptions);
}
// Allow the user to control whether messages can be converted to runtime
// functions.
if (types::isObjC(Input.getType())) {
auto *Arg = Args.getLastArg(
options::OPT_fobjc_convert_messages_to_runtime_calls,
options::OPT_fno_objc_convert_messages_to_runtime_calls);
if (Arg &&
Arg->getOption().matches(
options::OPT_fno_objc_convert_messages_to_runtime_calls))
CmdArgs.push_back("-fno-objc-convert-messages-to-runtime-calls");
}
// -fobjc-infer-related-result-type is the default, except in the Objective-C
// rewriter.
if (InferCovariantReturns)
CmdArgs.push_back("-fno-objc-infer-related-result-type");
// Pass down -fobjc-weak or -fno-objc-weak if present.
if (types::isObjC(Input.getType())) {
auto WeakArg =
Args.getLastArg(options::OPT_fobjc_weak, options::OPT_fno_objc_weak);
if (!WeakArg) {
// nothing to do
} else if (!Runtime.allowsWeak()) {
if (WeakArg->getOption().matches(options::OPT_fobjc_weak))
D.Diag(diag::err_objc_weak_unsupported);
} else {
WeakArg->render(Args, CmdArgs);
}
}
}
static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,
ArgStringList &CmdArgs) {
bool CaretDefault = true;
bool ColumnDefault = true;
if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diagnostics_classic,
options::OPT__SLASH_diagnostics_column,
options::OPT__SLASH_diagnostics_caret)) {
switch (A->getOption().getID()) {
case options::OPT__SLASH_diagnostics_caret:
CaretDefault = true;
ColumnDefault = true;
break;
case options::OPT__SLASH_diagnostics_column:
CaretDefault = false;
ColumnDefault = true;
break;
case options::OPT__SLASH_diagnostics_classic:
CaretDefault = false;
ColumnDefault = false;
break;
}
}
// -fcaret-diagnostics is default.
if (!Args.hasFlag(options::OPT_fcaret_diagnostics,
options::OPT_fno_caret_diagnostics, CaretDefault))
CmdArgs.push_back("-fno-caret-diagnostics");
// -fdiagnostics-fixit-info is default, only pass non-default.
if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info,
options::OPT_fno_diagnostics_fixit_info))
CmdArgs.push_back("-fno-diagnostics-fixit-info");
// Enable -fdiagnostics-show-option by default.
if (Args.hasFlag(options::OPT_fdiagnostics_show_option,
options::OPT_fno_diagnostics_show_option))
CmdArgs.push_back("-fdiagnostics-show-option");
if (const Arg *A =
Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) {
CmdArgs.push_back("-fdiagnostics-show-category");
CmdArgs.push_back(A->getValue());
}
if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness,
options::OPT_fno_diagnostics_show_hotness, false))
CmdArgs.push_back("-fdiagnostics-show-hotness");
if (const Arg *A =
Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) {
std::string Opt =
std::string("-fdiagnostics-hotness-threshold=") + A->getValue();
CmdArgs.push_back(Args.MakeArgString(Opt));
}
if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
CmdArgs.push_back("-fdiagnostics-format");
CmdArgs.push_back(A->getValue());
}
if (const Arg *A = Args.getLastArg(
options::OPT_fdiagnostics_show_note_include_stack,
options::OPT_fno_diagnostics_show_note_include_stack)) {
const Option &O = A->getOption();
if (O.matches(options::OPT_fdiagnostics_show_note_include_stack))
CmdArgs.push_back("-fdiagnostics-show-note-include-stack");
else
CmdArgs.push_back("-fno-diagnostics-show-note-include-stack");
}
// Color diagnostics are parsed by the driver directly from argv and later
// re-parsed to construct this job; claim any possible color diagnostic here
// to avoid warn_drv_unused_argument and diagnose bad
// OPT_fdiagnostics_color_EQ values.
for (const Arg *A : Args) {
const Option &O = A->getOption();
if (!O.matches(options::OPT_fcolor_diagnostics) &&
!O.matches(options::OPT_fdiagnostics_color) &&
!O.matches(options::OPT_fno_color_diagnostics) &&
!O.matches(options::OPT_fno_diagnostics_color) &&
!O.matches(options::OPT_fdiagnostics_color_EQ))
continue;
if (O.matches(options::OPT_fdiagnostics_color_EQ)) {
StringRef Value(A->getValue());
if (Value != "always" && Value != "never" && Value != "auto")
D.Diag(diag::err_drv_clang_unsupported)
<< ("-fdiagnostics-color=" + Value).str();
}
A->claim();
}
if (D.getDiags().getDiagnosticOptions().ShowColors)
CmdArgs.push_back("-fcolor-diagnostics");
if (Args.hasArg(options::OPT_fansi_escape_codes))
CmdArgs.push_back("-fansi-escape-codes");
if (!Args.hasFlag(options::OPT_fshow_source_location,
options::OPT_fno_show_source_location))
CmdArgs.push_back("-fno-show-source-location");
if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths))
CmdArgs.push_back("-fdiagnostics-absolute-paths");
if (!Args.hasFlag(options::OPT_fshow_column, options::OPT_fno_show_column,
ColumnDefault))
CmdArgs.push_back("-fno-show-column");
if (!Args.hasFlag(options::OPT_fspell_checking,
options::OPT_fno_spell_checking))
CmdArgs.push_back("-fno-spell-checking");
}
enum class DwarfFissionKind { None, Split, Single };
static DwarfFissionKind getDebugFissionKind(const Driver &D,
const ArgList &Args, Arg *&Arg) {
Arg =
Args.getLastArg(options::OPT_gsplit_dwarf, options::OPT_gsplit_dwarf_EQ);
if (!Arg)
return DwarfFissionKind::None;
if (Arg->getOption().matches(options::OPT_gsplit_dwarf))
return DwarfFissionKind::Split;
StringRef Value = Arg->getValue();
if (Value == "split")
return DwarfFissionKind::Split;
if (Value == "single")
return DwarfFissionKind::Single;
D.Diag(diag::err_drv_unsupported_option_argument)
<< Arg->getOption().getName() << Arg->getValue();
return DwarfFissionKind::None;
}
static void RenderDebugOptions(const ToolChain &TC, const Driver &D,
const llvm::Triple &T, const ArgList &Args,
bool EmitCodeView, bool IsWindowsMSVC,
ArgStringList &CmdArgs,
codegenoptions::DebugInfoKind &DebugInfoKind,
DwarfFissionKind &DwarfFission) {
if (Args.hasFlag(options::OPT_fdebug_info_for_profiling,
options::OPT_fno_debug_info_for_profiling, false) &&
checkDebugInfoOption(
Args.getLastArg(options::OPT_fdebug_info_for_profiling), Args, D, TC))
CmdArgs.push_back("-fdebug-info-for-profiling");
// The 'g' groups options involve a somewhat intricate sequence of decisions
// about what to pass from the driver to the frontend, but by the time they
// reach cc1 they've been factored into three well-defined orthogonal choices:
// * what level of debug info to generate
// * what dwarf version to write
// * what debugger tuning to use
// This avoids having to monkey around further in cc1 other than to disable
// codeview if not running in a Windows environment. Perhaps even that
// decision should be made in the driver as well though.
unsigned DWARFVersion = 0;
llvm::DebuggerKind DebuggerTuning = TC.getDefaultDebuggerTuning();
bool SplitDWARFInlining =
Args.hasFlag(options::OPT_fsplit_dwarf_inlining,
options::OPT_fno_split_dwarf_inlining, true);
Args.ClaimAllArgs(options::OPT_g_Group);
Arg* SplitDWARFArg;
DwarfFission = getDebugFissionKind(D, Args, SplitDWARFArg);
if (DwarfFission != DwarfFissionKind::None &&
!checkDebugInfoOption(SplitDWARFArg, Args, D, TC)) {
DwarfFission = DwarfFissionKind::None;
SplitDWARFInlining = false;
}
if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) {
if (checkDebugInfoOption(A, Args, D, TC)) {
// If the last option explicitly specified a debug-info level, use it.
if (A->getOption().matches(options::OPT_gN_Group)) {
DebugInfoKind = DebugLevelToInfoKind(*A);
// If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses.
// But -gsplit-dwarf is not a g_group option, hence we have to check the
// order explicitly. If -gsplit-dwarf wins, we fix DebugInfoKind later.
// This gets a bit more complicated if you've disabled inline info in
// the skeleton CUs (SplitDWARFInlining) - then there's value in
// composing split-dwarf and line-tables-only, so let those compose
// naturally in that case. And if you just turned off debug info,
// (-gsplit-dwarf -g0) - do that.
if (DwarfFission != DwarfFissionKind::None) {
if (A->getIndex() > SplitDWARFArg->getIndex()) {
if (DebugInfoKind == codegenoptions::NoDebugInfo ||
DebugInfoKind == codegenoptions::DebugDirectivesOnly ||
(DebugInfoKind == codegenoptions::DebugLineTablesOnly &&
SplitDWARFInlining))
DwarfFission = DwarfFissionKind::None;
} else if (SplitDWARFInlining)
DebugInfoKind = codegenoptions::NoDebugInfo;
}
} else {
// For any other 'g' option, use Limited.
DebugInfoKind = codegenoptions::LimitedDebugInfo;
}
} else {
DebugInfoKind = codegenoptions::LimitedDebugInfo;
}
}
// If a debugger tuning argument appeared, remember it.
if (const Arg *A =
Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) {
if (checkDebugInfoOption(A, Args, D, TC)) {
if (A->getOption().matches(options::OPT_glldb))
DebuggerTuning = llvm::DebuggerKind::LLDB;
else if (A->getOption().matches(options::OPT_gsce))
DebuggerTuning = llvm::DebuggerKind::SCE;
else
DebuggerTuning = llvm::DebuggerKind::GDB;
}
}
// If a -gdwarf argument appeared, remember it.
if (const Arg *A =
Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3,
options::OPT_gdwarf_4, options::OPT_gdwarf_5))
if (checkDebugInfoOption(A, Args, D, TC))
DWARFVersion = DwarfVersionNum(A->getSpelling());
if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) {
if (checkDebugInfoOption(A, Args, D, TC))
EmitCodeView = true;
}
// If the user asked for debug info but did not explicitly specify -gcodeview
// or -gdwarf, ask the toolchain for the default format.
if (!EmitCodeView && DWARFVersion == 0 &&
DebugInfoKind != codegenoptions::NoDebugInfo) {
switch (TC.getDefaultDebugFormat()) {
case codegenoptions::DIF_CodeView:
EmitCodeView = true;
break;
case codegenoptions::DIF_DWARF:
DWARFVersion = TC.GetDefaultDwarfVersion();
break;
}
}
// -gline-directives-only supported only for the DWARF debug info.
if (DWARFVersion == 0 && DebugInfoKind == codegenoptions::DebugDirectivesOnly)
DebugInfoKind = codegenoptions::NoDebugInfo;
// We ignore flag -gstrict-dwarf for now.
// And we handle flag -grecord-gcc-switches later with DWARFDebugFlags.
Args.ClaimAllArgs(options::OPT_g_flags_Group);
// Column info is included by default for everything except SCE and
// CodeView. Clang doesn't track end columns, just starting columns, which,
// in theory, is fine for CodeView (and PDB). In practice, however, the
// Microsoft debuggers don't handle missing end columns well, so it's better
// not to include any column info.
if (const Arg *A = Args.getLastArg(options::OPT_gcolumn_info))
(void)checkDebugInfoOption(A, Args, D, TC);
if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info,
/*Default=*/!EmitCodeView &&
DebuggerTuning != llvm::DebuggerKind::SCE))
CmdArgs.push_back("-dwarf-column-info");
// FIXME: Move backend command line options to the module.
// If -gline-tables-only or -gline-directives-only is the last option it wins.
if (const Arg *A = Args.getLastArg(options::OPT_gmodules))
if (checkDebugInfoOption(A, Args, D, TC)) {
if (DebugInfoKind != codegenoptions::DebugLineTablesOnly &&
DebugInfoKind != codegenoptions::DebugDirectivesOnly) {
DebugInfoKind = codegenoptions::LimitedDebugInfo;
CmdArgs.push_back("-dwarf-ext-refs");
CmdArgs.push_back("-fmodule-format=obj");
}
}
// -gsplit-dwarf should turn on -g and enable the backend dwarf
// splitting and extraction.
// FIXME: Currently only works on Linux and Fuchsia.
if (T.isOSLinux() || T.isOSFuchsia()) {
if (!SplitDWARFInlining)
CmdArgs.push_back("-fno-split-dwarf-inlining");
if (DwarfFission != DwarfFissionKind::None) {
if (DebugInfoKind == codegenoptions::NoDebugInfo)
DebugInfoKind = codegenoptions::LimitedDebugInfo;
if (DwarfFission == DwarfFissionKind::Single)
CmdArgs.push_back("-enable-split-dwarf=single");
else
CmdArgs.push_back("-enable-split-dwarf");
}
}
// After we've dealt with all combinations of things that could
// make DebugInfoKind be other than None or DebugLineTablesOnly,
// figure out if we need to "upgrade" it to standalone debug info.
// We parse these two '-f' options whether or not they will be used,
// to claim them even if you wrote "-fstandalone-debug -gline-tables-only"
bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug,
options::OPT_fno_standalone_debug,
TC.GetDefaultStandaloneDebug());
if (const Arg *A = Args.getLastArg(options::OPT_fstandalone_debug))
(void)checkDebugInfoOption(A, Args, D, TC);
if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug)
DebugInfoKind = codegenoptions::FullDebugInfo;
if (Args.hasFlag(options::OPT_gembed_source, options::OPT_gno_embed_source,
false)) {
// Source embedding is a vendor extension to DWARF v5. By now we have
// checked if a DWARF version was stated explicitly, and have otherwise
// fallen back to the target default, so if this is still not at least 5
// we emit an error.
const Arg *A = Args.getLastArg(options::OPT_gembed_source);
if (DWARFVersion < 5)
D.Diag(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-gdwarf-5";
else if (checkDebugInfoOption(A, Args, D, TC))
CmdArgs.push_back("-gembed-source");
}
if (EmitCodeView) {
CmdArgs.push_back("-gcodeview");
// Emit codeview type hashes if requested.
if (Args.hasFlag(options::OPT_gcodeview_ghash,
options::OPT_gno_codeview_ghash, false)) {
CmdArgs.push_back("-gcodeview-ghash");
}
}
// Adjust the debug info kind for the given toolchain.
TC.adjustDebugInfoKind(DebugInfoKind, Args);
RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DWARFVersion,
DebuggerTuning);
// -fdebug-macro turns on macro debug info generation.
if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro,
false))
if (checkDebugInfoOption(Args.getLastArg(options::OPT_fdebug_macro), Args,
D, TC))
CmdArgs.push_back("-debug-info-macro");
// -ggnu-pubnames turns on gnu style pubnames in the backend.
const auto *PubnamesArg =
Args.getLastArg(options::OPT_ggnu_pubnames, options::OPT_gno_gnu_pubnames,
options::OPT_gpubnames, options::OPT_gno_pubnames);
if (DwarfFission != DwarfFissionKind::None ||
DebuggerTuning == llvm::DebuggerKind::LLDB ||
(PubnamesArg && checkDebugInfoOption(PubnamesArg, Args, D, TC)))
if (!PubnamesArg ||
(!PubnamesArg->getOption().matches(options::OPT_gno_gnu_pubnames) &&
!PubnamesArg->getOption().matches(options::OPT_gno_pubnames)))
CmdArgs.push_back(PubnamesArg && PubnamesArg->getOption().matches(
options::OPT_gpubnames)
? "-gpubnames"
: "-ggnu-pubnames");
if (Args.hasFlag(options::OPT_fdebug_ranges_base_address,
options::OPT_fno_debug_ranges_base_address, false)) {
CmdArgs.push_back("-fdebug-ranges-base-address");
}
// -gdwarf-aranges turns on the emission of the aranges section in the
// backend.
// Always enabled for SCE tuning.
bool NeedAranges = DebuggerTuning == llvm::DebuggerKind::SCE;
if (const Arg *A = Args.getLastArg(options::OPT_gdwarf_aranges))
NeedAranges = checkDebugInfoOption(A, Args, D, TC) || NeedAranges;
if (NeedAranges) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-generate-arange-section");
}
if (Args.hasFlag(options::OPT_fdebug_types_section,
options::OPT_fno_debug_types_section, false)) {
if (!T.isOSBinFormatELF()) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< Args.getLastArg(options::OPT_fdebug_types_section)
->getAsString(Args)
<< T.getTriple();
} else if (checkDebugInfoOption(
Args.getLastArg(options::OPT_fdebug_types_section), Args, D,
TC)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-generate-type-units");
}
}
// Decide how to render forward declarations of template instantiations.
// SCE wants full descriptions, others just get them in the name.
if (DebuggerTuning == llvm::DebuggerKind::SCE)
CmdArgs.push_back("-debug-forward-template-params");
// Do we need to explicitly import anonymous namespaces into the parent
// scope?
if (DebuggerTuning == llvm::DebuggerKind::SCE)
CmdArgs.push_back("-dwarf-explicit-import");
RenderDebugInfoCompressionArgs(Args, CmdArgs, D, TC);
}
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
const ArgList &Args, const char *LinkingOutput) const {
const auto &TC = getToolChain();
const llvm::Triple &RawTriple = TC.getTriple();
const llvm::Triple &Triple = TC.getEffectiveTriple();
const std::string &TripleStr = Triple.getTriple();
bool KernelOrKext =
Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
const Driver &D = TC.getDriver();
ArgStringList CmdArgs;
// Check number of inputs for sanity. We need at least one input.
assert(Inputs.size() >= 1 && "Must have at least one input.");
// CUDA/HIP compilation may have multiple inputs (source file + results of
// device-side compilations). OpenMP device jobs also take the host IR as a
// second input. Module precompilation accepts a list of header files to
// include as part of the module. All other jobs are expected to have exactly
// one input.
bool IsCuda = JA.isOffloading(Action::OFK_Cuda);
bool IsHIP = JA.isOffloading(Action::OFK_HIP);
bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);
bool IsHeaderModulePrecompile = isa<HeaderModulePrecompileJobAction>(JA);
// A header module compilation doesn't have a main input file, so invent a
// fake one as a placeholder.
const char *ModuleName = [&]{
auto *ModuleNameArg = Args.getLastArg(options::OPT_fmodule_name_EQ);
return ModuleNameArg ? ModuleNameArg->getValue() : "";
}();
InputInfo HeaderModuleInput(Inputs[0].getType(), ModuleName, ModuleName);
const InputInfo &Input =
IsHeaderModulePrecompile ? HeaderModuleInput : Inputs[0];
InputInfoList ModuleHeaderInputs;
const InputInfo *CudaDeviceInput = nullptr;
const InputInfo *OpenMPDeviceInput = nullptr;
for (const InputInfo &I : Inputs) {
if (&I == &Input) {
// This is the primary input.
} else if (IsHeaderModulePrecompile &&
types::getPrecompiledType(I.getType()) == types::TY_PCH) {
types::ID Expected = HeaderModuleInput.getType();
if (I.getType() != Expected) {
D.Diag(diag::err_drv_module_header_wrong_kind)
<< I.getFilename() << types::getTypeName(I.getType())
<< types::getTypeName(Expected);
}
ModuleHeaderInputs.push_back(I);
} else if ((IsCuda || IsHIP) && !CudaDeviceInput) {
CudaDeviceInput = &I;
} else if (IsOpenMPDevice && !OpenMPDeviceInput) {
OpenMPDeviceInput = &I;
} else {
llvm_unreachable("unexpectedly given multiple inputs");
}
}
const llvm::Triple *AuxTriple = IsCuda ? TC.getAuxTriple() : nullptr;
bool IsWindowsGNU = RawTriple.isWindowsGNUEnvironment();
bool IsWindowsCygnus = RawTriple.isWindowsCygwinEnvironment();
bool IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment();
bool IsIAMCU = RawTriple.isOSIAMCU();
// Adjust IsWindowsXYZ for CUDA/HIP compilations. Even when compiling in
// device mode (i.e., getToolchain().getTriple() is NVPTX/AMDGCN, not
// Windows), we need to pass Windows-specific flags to cc1.
if (IsCuda || IsHIP) {
IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment();
IsWindowsGNU |= AuxTriple && AuxTriple->isWindowsGNUEnvironment();
IsWindowsCygnus |= AuxTriple && AuxTriple->isWindowsCygwinEnvironment();
}
// C++ is not supported for IAMCU.
if (IsIAMCU && types::isCXX(Input.getType()))
D.Diag(diag::err_drv_clang_unsupported) << "C++ for IAMCU";
// Invoke ourselves in -cc1 mode.
//
// FIXME: Implement custom jobs for internal actions.
CmdArgs.push_back("-cc1");
// Add the "effective" target triple.
CmdArgs.push_back("-triple");
CmdArgs.push_back(Args.MakeArgString(TripleStr));
if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) {
DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args);
Args.ClaimAllArgs(options::OPT_MJ);
}
if (IsCuda || IsHIP) {
// We have to pass the triple of the host if compiling for a CUDA/HIP device
// and vice-versa.
std::string NormalizedTriple;
if (JA.isDeviceOffloading(Action::OFK_Cuda) ||
JA.isDeviceOffloading(Action::OFK_HIP))
NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Host>()
->getTriple()
.normalize();
else
NormalizedTriple =
(IsCuda ? C.getSingleOffloadToolChain<Action::OFK_Cuda>()
: C.getSingleOffloadToolChain<Action::OFK_HIP>())
->getTriple()
.normalize();
CmdArgs.push_back("-aux-triple");
CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
}
if (IsOpenMPDevice) {
// We have to pass the triple of the host if compiling for an OpenMP device.
std::string NormalizedTriple =
C.getSingleOffloadToolChain<Action::OFK_Host>()
->getTriple()
.normalize();
CmdArgs.push_back("-aux-triple");
CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
}
if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm ||
Triple.getArch() == llvm::Triple::thumb)) {
unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6;
unsigned Version;
Triple.getArchName().substr(Offset).getAsInteger(10, Version);
if (Version < 7)
D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName()
<< TripleStr;
}
// Push all default warning arguments that are specific to
// the given target. These come before user provided warning options
// are provided.
TC.addClangWarningOptions(CmdArgs);
// Select the appropriate action.
RewriteKind rewriteKind = RK_None;
if (isa<AnalyzeJobAction>(JA)) {
assert(JA.getType() == types::TY_Plist && "Invalid output type.");
CmdArgs.push_back("-analyze");
} else if (isa<MigrateJobAction>(JA)) {
CmdArgs.push_back("-migrate");
} else if (isa<PreprocessJobAction>(JA)) {
if (Output.getType() == types::TY_Dependencies)
CmdArgs.push_back("-Eonly");
else {
CmdArgs.push_back("-E");
if (Args.hasArg(options::OPT_rewrite_objc) &&
!Args.hasArg(options::OPT_g_Group))
CmdArgs.push_back("-P");
}
} else if (isa<AssembleJobAction>(JA)) {
CmdArgs.push_back("-emit-obj");
CollectArgsForIntegratedAssembler(C, Args, CmdArgs, D);
// Also ignore explicit -force_cpusubtype_ALL option.
(void)Args.hasArg(options::OPT_force__cpusubtype__ALL);
} else if (isa<PrecompileJobAction>(JA)) {
if (JA.getType() == types::TY_Nothing)
CmdArgs.push_back("-fsyntax-only");
else if (JA.getType() == types::TY_ModuleFile)
CmdArgs.push_back(IsHeaderModulePrecompile
? "-emit-header-module"
: "-emit-module-interface");
else
CmdArgs.push_back("-emit-pch");
} else if (isa<VerifyPCHJobAction>(JA)) {
CmdArgs.push_back("-verify-pch");
} else {
assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
"Invalid action for clang tool.");
if (JA.getType() == types::TY_Nothing) {
CmdArgs.push_back("-fsyntax-only");
} else if (JA.getType() == types::TY_LLVM_IR ||
JA.getType() == types::TY_LTO_IR) {
CmdArgs.push_back("-emit-llvm");
} else if (JA.getType() == types::TY_LLVM_BC ||
JA.getType() == types::TY_LTO_BC) {
CmdArgs.push_back("-emit-llvm-bc");
} else if (JA.getType() == types::TY_PP_Asm) {
CmdArgs.push_back("-S");
} else if (JA.getType() == types::TY_AST) {
CmdArgs.push_back("-emit-pch");
} else if (JA.getType() == types::TY_ModuleFile) {
CmdArgs.push_back("-module-file-info");
} else if (JA.getType() == types::TY_RewrittenObjC) {
CmdArgs.push_back("-rewrite-objc");
rewriteKind = RK_NonFragile;
} else if (JA.getType() == types::TY_RewrittenLegacyObjC) {
CmdArgs.push_back("-rewrite-objc");
rewriteKind = RK_Fragile;
} else {
assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!");
}
// Preserve use-list order by default when emitting bitcode, so that
// loading the bitcode up in 'opt' or 'llc' and running passes gives the
// same result as running passes here. For LTO, we don't need to preserve
// the use-list order, since serialization to bitcode is part of the flow.
if (JA.getType() == types::TY_LLVM_BC)
CmdArgs.push_back("-emit-llvm-uselists");
// Device-side jobs do not support LTO.
bool isDeviceOffloadAction = !(JA.isDeviceOffloading(Action::OFK_None) ||
JA.isDeviceOffloading(Action::OFK_Host));
if (D.isUsingLTO() && !isDeviceOffloadAction) {
Args.AddLastArg(CmdArgs, options::OPT_flto, options::OPT_flto_EQ);
// The Darwin and PS4 linkers currently use the legacy LTO API, which
// does not support LTO unit features (CFI, whole program vtable opt)
// under ThinLTO.
if (!(RawTriple.isOSDarwin() || RawTriple.isPS4()) ||
D.getLTOMode() == LTOK_Full)
CmdArgs.push_back("-flto-unit");
}
}
if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) {
if (!types::isLLVMIR(Input.getType()))
D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args)
<< "-x ir";
Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ);
}
if (Args.getLastArg(options::OPT_save_temps_EQ))
Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);
// Embed-bitcode option.
// Only white-listed flags below are allowed to be embedded.
if (C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO() &&
(isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) {
// Add flags implied by -fembed-bitcode.
Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ);
// Disable all llvm IR level optimizations.
CmdArgs.push_back("-disable-llvm-passes");
// reject options that shouldn't be supported in bitcode
// also reject kernel/kext
static const constexpr unsigned kBitcodeOptionBlacklist[] = {
options::OPT_mkernel,
options::OPT_fapple_kext,
options::OPT_ffunction_sections,
options::OPT_fno_function_sections,
options::OPT_fdata_sections,
options::OPT_fno_data_sections,
options::OPT_funique_section_names,
options::OPT_fno_unique_section_names,
options::OPT_mrestrict_it,
options::OPT_mno_restrict_it,
options::OPT_mstackrealign,
options::OPT_mno_stackrealign,
options::OPT_mstack_alignment,
options::OPT_mcmodel_EQ,
options::OPT_mlong_calls,
options::OPT_mno_long_calls,
options::OPT_ggnu_pubnames,
options::OPT_gdwarf_aranges,
options::OPT_fdebug_types_section,
options::OPT_fno_debug_types_section,
options::OPT_fdwarf_directory_asm,
options::OPT_fno_dwarf_directory_asm,
options::OPT_mrelax_all,
options::OPT_mno_relax_all,
options::OPT_ftrap_function_EQ,
options::OPT_ffixed_r9,
options::OPT_mfix_cortex_a53_835769,
options::OPT_mno_fix_cortex_a53_835769,
options::OPT_ffixed_x18,
options::OPT_mglobal_merge,
options::OPT_mno_global_merge,
options::OPT_mred_zone,
options::OPT_mno_red_zone,
options::OPT_Wa_COMMA,
options::OPT_Xassembler,
options::OPT_mllvm,
};
for (const auto &A : Args)
if (std::find(std::begin(kBitcodeOptionBlacklist),
std::end(kBitcodeOptionBlacklist),
A->getOption().getID()) !=
std::end(kBitcodeOptionBlacklist))
D.Diag(diag::err_drv_unsupported_embed_bitcode) << A->getSpelling();
// Render the CodeGen options that need to be passed.
if (!Args.hasFlag(options::OPT_foptimize_sibling_calls,
options::OPT_fno_optimize_sibling_calls))
CmdArgs.push_back("-mdisable-tail-calls");
RenderFloatingPointOptions(TC, D, isOptimizationLevelFast(Args), Args,
CmdArgs);
// Render ABI arguments
switch (TC.getArch()) {
default: break;
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
RenderARMABI(Triple, Args, CmdArgs);
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
RenderAArch64ABI(Triple, Args, CmdArgs);
break;
}
// Optimization level for CodeGen.
if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) {
if (A->getOption().matches(options::OPT_O4)) {
CmdArgs.push_back("-O3");
D.Diag(diag::warn_O4_is_O3);
} else {
A->render(Args, CmdArgs);
}
}
// Input/Output file.
if (Output.getType() == types::TY_Dependencies) {
// Handled with other dependency code.
} else if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
} else {
assert(Output.isNothing() && "Input output.");
}
for (const auto &II : Inputs) {
addDashXForInput(Args, II, CmdArgs);
if (II.isFilename())
CmdArgs.push_back(II.getFilename());
else
II.getInputArg().renderAsInput(Args, CmdArgs);
}
C.addCommand(llvm::make_unique<Command>(JA, *this, D.getClangProgramPath(),
CmdArgs, Inputs));
return;
}
if (C.getDriver().embedBitcodeMarkerOnly() && !C.getDriver().isUsingLTO())
CmdArgs.push_back("-fembed-bitcode=marker");
// We normally speed up the clang process a bit by skipping destructors at
// exit, but when we're generating diagnostics we can rely on some of the
// cleanup.
if (!C.isForDiagnostics())
CmdArgs.push_back("-disable-free");
#ifdef NDEBUG
const bool IsAssertBuild = false;
#else
const bool IsAssertBuild = true;
#endif
// Disable the verification pass in -asserts builds.
if (!IsAssertBuild)
CmdArgs.push_back("-disable-llvm-verifier");
// Discard value names in assert builds unless otherwise specified.
if (Args.hasFlag(options::OPT_fdiscard_value_names,
options::OPT_fno_discard_value_names, !IsAssertBuild))
CmdArgs.push_back("-discard-value-names");
// Set the main file name, so that debug info works even with
// -save-temps.
CmdArgs.push_back("-main-file-name");
CmdArgs.push_back(getBaseInputName(Args, Input));
// Some flags which affect the language (via preprocessor
// defines).
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("-static-define");
if (Args.hasArg(options::OPT_municode))
CmdArgs.push_back("-DUNICODE");
if (isa<AnalyzeJobAction>(JA))
RenderAnalyzerOptions(Args, CmdArgs, Triple, Input);
// Enable compatilibily mode to avoid analyzer-config related errors.
// Since we can't access frontend flags through hasArg, let's manually iterate
// through them.
bool FoundAnalyzerConfig = false;
for (auto Arg : Args.filtered(options::OPT_Xclang))
if (StringRef(Arg->getValue()) == "-analyzer-config") {
FoundAnalyzerConfig = true;
break;
}
if (!FoundAnalyzerConfig)
for (auto Arg : Args.filtered(options::OPT_Xanalyzer))
if (StringRef(Arg->getValue()) == "-analyzer-config") {
FoundAnalyzerConfig = true;
break;
}
if (FoundAnalyzerConfig)
CmdArgs.push_back("-analyzer-config-compatibility-mode=true");
CheckCodeGenerationOptions(D, Args);
unsigned FunctionAlignment = ParseFunctionAlignment(TC, Args);
assert(FunctionAlignment <= 31 && "function alignment will be truncated!");
if (FunctionAlignment) {
CmdArgs.push_back("-function-alignment");
CmdArgs.push_back(Args.MakeArgString(std::to_string(FunctionAlignment)));
}
llvm::Reloc::Model RelocationModel;
unsigned PICLevel;
bool IsPIE;
std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(TC, Args);
const char *RMName = RelocationModelName(RelocationModel);
if ((RelocationModel == llvm::Reloc::ROPI ||
RelocationModel == llvm::Reloc::ROPI_RWPI) &&
types::isCXX(Input.getType()) &&
!Args.hasArg(options::OPT_fallow_unsupported))
D.Diag(diag::err_drv_ropi_incompatible_with_cxx);
if (RMName) {
CmdArgs.push_back("-mrelocation-model");
CmdArgs.push_back(RMName);
}
if (PICLevel > 0) {
CmdArgs.push_back("-pic-level");
CmdArgs.push_back(PICLevel == 1 ? "1" : "2");
if (IsPIE)
CmdArgs.push_back("-pic-is-pie");
}
if (Arg *A = Args.getLastArg(options::OPT_meabi)) {
CmdArgs.push_back("-meabi");
CmdArgs.push_back(A->getValue());
}
CmdArgs.push_back("-mthread-model");
if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) {
if (!TC.isThreadModelSupported(A->getValue()))
D.Diag(diag::err_drv_invalid_thread_model_for_target)
<< A->getValue() << A->getAsString(Args);
CmdArgs.push_back(A->getValue());
}
else
CmdArgs.push_back(Args.MakeArgString(TC.getThreadModel()));
Args.AddLastArg(CmdArgs, options::OPT_fveclib);
if (Args.hasFlag(options::OPT_fmerge_all_constants,
options::OPT_fno_merge_all_constants, false))
CmdArgs.push_back("-fmerge-all-constants");
if (Args.hasFlag(options::OPT_fno_delete_null_pointer_checks,
options::OPT_fdelete_null_pointer_checks, false))
CmdArgs.push_back("-fno-delete-null-pointer-checks");
// LLVM Code Generator Options.
if (Args.hasArg(options::OPT_frewrite_map_file) ||
Args.hasArg(options::OPT_frewrite_map_file_EQ)) {
for (const Arg *A : Args.filtered(options::OPT_frewrite_map_file,
options::OPT_frewrite_map_file_EQ)) {
StringRef Map = A->getValue();
if (!llvm::sys::fs::exists(Map)) {
D.Diag(diag::err_drv_no_such_file) << Map;
} else {
CmdArgs.push_back("-frewrite-map-file");
CmdArgs.push_back(A->getValue());
A->claim();
}
}
}
if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) {
StringRef v = A->getValue();
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString("-warn-stack-size=" + v));
A->claim();
}
if (!Args.hasFlag(options::OPT_fjump_tables, options::OPT_fno_jump_tables,
true))
CmdArgs.push_back("-fno-jump-tables");
if (Args.hasFlag(options::OPT_fprofile_sample_accurate,
options::OPT_fno_profile_sample_accurate, false))
CmdArgs.push_back("-fprofile-sample-accurate");
if (!Args.hasFlag(options::OPT_fpreserve_as_comments,
options::OPT_fno_preserve_as_comments, true))
CmdArgs.push_back("-fno-preserve-as-comments");
if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
CmdArgs.push_back("-mregparm");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return,
options::OPT_freg_struct_return)) {
if (TC.getArch() != llvm::Triple::x86) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getSpelling() << RawTriple.str();
} else if (A->getOption().matches(options::OPT_fpcc_struct_return)) {
CmdArgs.push_back("-fpcc-struct-return");
} else {
assert(A->getOption().matches(options::OPT_freg_struct_return));
CmdArgs.push_back("-freg-struct-return");
}
}
if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
CmdArgs.push_back("-fdefault-calling-conv=stdcall");
if (shouldUseFramePointer(Args, RawTriple))
CmdArgs.push_back("-mdisable-fp-elim");
if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
options::OPT_fno_zero_initialized_in_bss))
CmdArgs.push_back("-mno-zero-initialized-in-bss");
bool OFastEnabled = isOptimizationLevelFast(Args);
// If -Ofast is the optimization level, then -fstrict-aliasing should be
// enabled. This alias option is being used to simplify the hasFlag logic.
OptSpecifier StrictAliasingAliasOption =
OFastEnabled ? options::OPT_Ofast : options::OPT_fstrict_aliasing;
// We turn strict aliasing off by default if we're in CL mode, since MSVC
// doesn't do any TBAA.
bool TBAAOnByDefault = !D.IsCLMode();
if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption,
options::OPT_fno_strict_aliasing, TBAAOnByDefault))
CmdArgs.push_back("-relaxed-aliasing");
if (!Args.hasFlag(options::OPT_fstruct_path_tbaa,
options::OPT_fno_struct_path_tbaa))
CmdArgs.push_back("-no-struct-path-tbaa");
if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums,
false))
CmdArgs.push_back("-fstrict-enums");
if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return,
true))
CmdArgs.push_back("-fno-strict-return");
if (Args.hasFlag(options::OPT_fallow_editor_placeholders,
options::OPT_fno_allow_editor_placeholders, false))
CmdArgs.push_back("-fallow-editor-placeholders");
if (Args.hasFlag(options::OPT_fstrict_vtable_pointers,
options::OPT_fno_strict_vtable_pointers,
false))
CmdArgs.push_back("-fstrict-vtable-pointers");
if (Args.hasFlag(options::OPT_fforce_emit_vtables,
options::OPT_fno_force_emit_vtables,
false))
CmdArgs.push_back("-fforce-emit-vtables");
if (!Args.hasFlag(options::OPT_foptimize_sibling_calls,
options::OPT_fno_optimize_sibling_calls))
CmdArgs.push_back("-mdisable-tail-calls");
if (Args.hasFlag(options::OPT_fno_escaping_block_tail_calls,
options::OPT_fescaping_block_tail_calls, false))
CmdArgs.push_back("-fno-escaping-block-tail-calls");
Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses,
options::OPT_fno_fine_grained_bitfield_accesses);
// Handle segmented stacks.
if (Args.hasArg(options::OPT_fsplit_stack))
CmdArgs.push_back("-split-stacks");
RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs);
// Decide whether to use verbose asm. Verbose assembly is the default on
// toolchains which have the integrated assembler on by default.
bool IsIntegratedAssemblerDefault = TC.IsIntegratedAssemblerDefault();
if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm,
IsIntegratedAssemblerDefault) ||
Args.hasArg(options::OPT_dA))
CmdArgs.push_back("-masm-verbose");
if (!TC.useIntegratedAs())
CmdArgs.push_back("-no-integrated-as");
if (Args.hasArg(options::OPT_fdebug_pass_structure)) {
CmdArgs.push_back("-mdebug-pass");
CmdArgs.push_back("Structure");
}
if (Args.hasArg(options::OPT_fdebug_pass_arguments)) {
CmdArgs.push_back("-mdebug-pass");
CmdArgs.push_back("Arguments");
}
// Enable -mconstructor-aliases except on darwin, where we have to work around
// a linker bug (see <rdar://problem/7651567>), and CUDA device code, where
// aliases aren't supported.
if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX())
CmdArgs.push_back("-mconstructor-aliases");
// Darwin's kernel doesn't support guard variables; just die if we
// try to use them.
if (KernelOrKext && RawTriple.isOSDarwin())
CmdArgs.push_back("-fforbid-guard-variables");
if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields,
false)) {
CmdArgs.push_back("-mms-bitfields");
}
if (Args.hasFlag(options::OPT_mpie_copy_relocations,
options::OPT_mno_pie_copy_relocations,
false)) {
CmdArgs.push_back("-mpie-copy-relocations");
}
if (Args.hasFlag(options::OPT_fno_plt, options::OPT_fplt, false)) {
CmdArgs.push_back("-fno-plt");
}
// -fhosted is default.
// TODO: Audit uses of KernelOrKext and see where it'd be more appropriate to
// use Freestanding.
bool Freestanding =
Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) ||
KernelOrKext;
if (Freestanding)
CmdArgs.push_back("-ffreestanding");
// This is a coarse approximation of what llvm-gcc actually does, both
// -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
// complicated ways.
bool AsynchronousUnwindTables =
Args.hasFlag(options::OPT_fasynchronous_unwind_tables,
options::OPT_fno_asynchronous_unwind_tables,
(TC.IsUnwindTablesDefault(Args) ||
TC.getSanitizerArgs().needsUnwindTables()) &&
!Freestanding);
if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
AsynchronousUnwindTables))
CmdArgs.push_back("-munwind-tables");
TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind());
// FIXME: Handle -mtune=.
(void)Args.hasArg(options::OPT_mtune_EQ);
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
CmdArgs.push_back("-mcode-model");
CmdArgs.push_back(A->getValue());
}
// Add the target cpu
std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false);
if (!CPU.empty()) {
CmdArgs.push_back("-target-cpu");
CmdArgs.push_back(Args.MakeArgString(CPU));
}
RenderTargetOptions(Triple, Args, KernelOrKext, CmdArgs);
// These two are potentially updated by AddClangCLArgs.
codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo;
bool EmitCodeView = false;
// Add clang-cl arguments.
types::ID InputType = Input.getType();
if (D.IsCLMode())
AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView);
DwarfFissionKind DwarfFission;
RenderDebugOptions(TC, D, RawTriple, Args, EmitCodeView, IsWindowsMSVC,
CmdArgs, DebugInfoKind, DwarfFission);
// Add the split debug info name to the command lines here so we
// can propagate it to the backend.
bool SplitDWARF = (DwarfFission != DwarfFissionKind::None) &&
(RawTriple.isOSLinux() || RawTriple.isOSFuchsia()) &&
(isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) ||
isa<BackendJobAction>(JA));
const char *SplitDWARFOut;
if (SplitDWARF) {
CmdArgs.push_back("-split-dwarf-file");
SplitDWARFOut = SplitDebugName(Args, Output);
CmdArgs.push_back(SplitDWARFOut);
}
// Pass the linker version in use.
if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
CmdArgs.push_back("-target-linker-version");
CmdArgs.push_back(A->getValue());
}
if (!shouldUseLeafFramePointer(Args, RawTriple))
CmdArgs.push_back("-momit-leaf-frame-pointer");
// Explicitly error on some things we know we don't support and can't just
// ignore.
if (!Args.hasArg(options::OPT_fallow_unsupported)) {
Arg *Unsupported;
if (types::isCXX(InputType) && RawTriple.isOSDarwin() &&
TC.getArch() == llvm::Triple::x86) {
if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) ||
(Unsupported = Args.getLastArg(options::OPT_mkernel)))
D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386)
<< Unsupported->getOption().getName();
}
// The faltivec option has been superseded by the maltivec option.
if ((Unsupported = Args.getLastArg(options::OPT_faltivec)))
D.Diag(diag::err_drv_clang_unsupported_opt_faltivec)
<< Unsupported->getOption().getName()
<< "please use -maltivec and include altivec.h explicitly";
if ((Unsupported = Args.getLastArg(options::OPT_fno_altivec)))
D.Diag(diag::err_drv_clang_unsupported_opt_faltivec)
<< Unsupported->getOption().getName() << "please use -mno-altivec";
}
Args.AddAllArgs(CmdArgs, options::OPT_v);
Args.AddLastArg(CmdArgs, options::OPT_H);
if (D.CCPrintHeaders && !D.CCGenDiagnostics) {
CmdArgs.push_back("-header-include-file");
CmdArgs.push_back(D.CCPrintHeadersFilename ? D.CCPrintHeadersFilename
: "-");
}
Args.AddLastArg(CmdArgs, options::OPT_P);
Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
if (D.CCLogDiagnostics && !D.CCGenDiagnostics) {
CmdArgs.push_back("-diagnostic-log-file");
CmdArgs.push_back(D.CCLogDiagnosticsFilename ? D.CCLogDiagnosticsFilename
: "-");
}
bool UseSeparateSections = isUseSeparateSections(Triple);
if (Args.hasFlag(options::OPT_ffunction_sections,
options::OPT_fno_function_sections, UseSeparateSections)) {
CmdArgs.push_back("-ffunction-sections");
}
if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections,
UseSeparateSections)) {
CmdArgs.push_back("-fdata-sections");
}
if (!Args.hasFlag(options::OPT_funique_section_names,
options::OPT_fno_unique_section_names, true))
CmdArgs.push_back("-fno-unique-section-names");
if (auto *A = Args.getLastArg(
options::OPT_finstrument_functions,
options::OPT_finstrument_functions_after_inlining,
options::OPT_finstrument_function_entry_bare))
A->render(Args, CmdArgs);
// NVPTX doesn't support PGO or coverage. There's no runtime support for
// sampling, overhead of call arc collection is way too high and there's no
// way to collect the output.
if (!Triple.isNVPTX())
- addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs);
+ addPGOAndCoverageFlags(TC, C, D, Output, Args, CmdArgs);
if (auto *ABICompatArg = Args.getLastArg(options::OPT_fclang_abi_compat_EQ))
ABICompatArg->render(Args, CmdArgs);
// Add runtime flag for PS4 when PGO, coverage, or sanitizers are enabled.
if (RawTriple.isPS4CPU() &&
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
PS4cpu::addProfileRTArgs(TC, Args, CmdArgs);
PS4cpu::addSanitizerArgs(TC, CmdArgs);
}
// Pass options for controlling the default header search paths.
if (Args.hasArg(options::OPT_nostdinc)) {
CmdArgs.push_back("-nostdsysteminc");
CmdArgs.push_back("-nobuiltininc");
} else {
if (Args.hasArg(options::OPT_nostdlibinc))
CmdArgs.push_back("-nostdsysteminc");
Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
}
// Pass the path to compiler resource files.
CmdArgs.push_back("-resource-dir");
CmdArgs.push_back(D.ResourceDir.c_str());
Args.AddLastArg(CmdArgs, options::OPT_working_directory);
RenderARCMigrateToolOptions(D, Args, CmdArgs);
// Add preprocessing options like -I, -D, etc. if we are using the
// preprocessor.
//
// FIXME: Support -fpreprocessed
if (types::getPreprocessedType(InputType) != types::TY_INVALID)
AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs);
// Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes
// that "The compiler can only warn and ignore the option if not recognized".
// When building with ccache, it will pass -D options to clang even on
// preprocessed inputs and configure concludes that -fPIC is not supported.
Args.ClaimAllArgs(options::OPT_D);
// Manually translate -O4 to -O3; let clang reject others.
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
if (A->getOption().matches(options::OPT_O4)) {
CmdArgs.push_back("-O3");
D.Diag(diag::warn_O4_is_O3);
} else {
A->render(Args, CmdArgs);
}
}
// Warn about ignored options to clang.
for (const Arg *A :
Args.filtered(options::OPT_clang_ignored_gcc_optimization_f_Group)) {
D.Diag(diag::warn_ignored_gcc_optimization) << A->getAsString(Args);
A->claim();
}
for (const Arg *A :
Args.filtered(options::OPT_clang_ignored_legacy_options_Group)) {
D.Diag(diag::warn_ignored_clang_option) << A->getAsString(Args);
A->claim();
}
claimNoWarnArgs(Args);
Args.AddAllArgs(CmdArgs, options::OPT_R_Group);
Args.AddAllArgs(CmdArgs, options::OPT_W_Group);
if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false))
CmdArgs.push_back("-pedantic");
Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors);
Args.AddLastArg(CmdArgs, options::OPT_w);
// Fixed point flags
if (Args.hasFlag(options::OPT_ffixed_point, options::OPT_fno_fixed_point,
/*Default=*/false))
Args.AddLastArg(CmdArgs, options::OPT_ffixed_point);
// Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi}
// (-ansi is equivalent to -std=c89 or -std=c++98).
//
// If a std is supplied, only add -trigraphs if it follows the
// option.
bool ImplyVCPPCXXVer = false;
if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
if (Std->getOption().matches(options::OPT_ansi))
if (types::isCXX(InputType))
CmdArgs.push_back("-std=c++98");
else
CmdArgs.push_back("-std=c89");
else
Std->render(Args, CmdArgs);
// If -f(no-)trigraphs appears after the language standard flag, honor it.
if (Arg *A = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi,
options::OPT_ftrigraphs,
options::OPT_fno_trigraphs))
if (A != Std)
A->render(Args, CmdArgs);
} else {
// Honor -std-default.
//
// FIXME: Clang doesn't correctly handle -std= when the input language
// doesn't match. For the time being just ignore this for C++ inputs;
// eventually we want to do all the standard defaulting here instead of
// splitting it between the driver and clang -cc1.
if (!types::isCXX(InputType))
Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, "-std=",
/*Joined=*/true);
else if (IsWindowsMSVC)
ImplyVCPPCXXVer = true;
Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs,
options::OPT_fno_trigraphs);
}
// GCC's behavior for -Wwrite-strings is a bit strange:
// * In C, this "warning flag" changes the types of string literals from
// 'char[N]' to 'const char[N]', and thus triggers an unrelated warning
// for the discarded qualifier.
// * In C++, this is just a normal warning flag.
//
// Implementing this warning correctly in C is hard, so we follow GCC's
// behavior for now. FIXME: Directly diagnose uses of a string literal as
// a non-const char* in C, rather than using this crude hack.
if (!types::isCXX(InputType)) {
// FIXME: This should behave just like a warning flag, and thus should also
// respect -Weverything, -Wno-everything, -Werror=write-strings, and so on.
Arg *WriteStrings =
Args.getLastArg(options::OPT_Wwrite_strings,
options::OPT_Wno_write_strings, options::OPT_w);
if (WriteStrings &&
WriteStrings->getOption().matches(options::OPT_Wwrite_strings))
CmdArgs.push_back("-fconst-strings");
}
// GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active
// during C++ compilation, which it is by default. GCC keeps this define even
// in the presence of '-w', match this behavior bug-for-bug.
if (types::isCXX(InputType) &&
Args.hasFlag(options::OPT_Wdeprecated, options::OPT_Wno_deprecated,
true)) {
CmdArgs.push_back("-fdeprecated-macro");
}
// Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'.
if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) {
if (Asm->getOption().matches(options::OPT_fasm))
CmdArgs.push_back("-fgnu-keywords");
else
CmdArgs.push_back("-fno-gnu-keywords");
}
if (ShouldDisableDwarfDirectory(Args, TC))
CmdArgs.push_back("-fno-dwarf-directory-asm");
if (ShouldDisableAutolink(Args, TC))
CmdArgs.push_back("-fno-autolink");
// Add in -fdebug-compilation-dir if necessary.
addDebugCompDirArg(Args, CmdArgs);
addDebugPrefixMapArg(D, Args, CmdArgs);
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_,
options::OPT_ftemplate_depth_EQ)) {
CmdArgs.push_back("-ftemplate-depth");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) {
CmdArgs.push_back("-foperator-arrow-depth");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) {
CmdArgs.push_back("-fconstexpr-depth");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) {
CmdArgs.push_back("-fconstexpr-steps");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) {
CmdArgs.push_back("-fbracket-depth");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ,
options::OPT_Wlarge_by_value_copy_def)) {
if (A->getNumValues()) {
StringRef bytes = A->getValue();
CmdArgs.push_back(Args.MakeArgString("-Wlarge-by-value-copy=" + bytes));
} else
CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value
}
if (Args.hasArg(options::OPT_relocatable_pch))
CmdArgs.push_back("-relocatable-pch");
if (const Arg *A = Args.getLastArg(options::OPT_fcf_runtime_abi_EQ)) {
static const char *kCFABIs[] = {
"standalone", "objc", "swift", "swift-5.0", "swift-4.2", "swift-4.1",
};
if (find(kCFABIs, StringRef(A->getValue())) == std::end(kCFABIs))
D.Diag(diag::err_drv_invalid_cf_runtime_abi) << A->getValue();
else
A->render(Args, CmdArgs);
}
if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) {
CmdArgs.push_back("-fconstant-string-class");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) {
CmdArgs.push_back("-ftabstop");
CmdArgs.push_back(A->getValue());
}
if (Args.hasFlag(options::OPT_fstack_size_section,
options::OPT_fno_stack_size_section, RawTriple.isPS4()))
CmdArgs.push_back("-fstack-size-section");
CmdArgs.push_back("-ferror-limit");
if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ))
CmdArgs.push_back(A->getValue());
else
CmdArgs.push_back("19");
if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) {
CmdArgs.push_back("-fmacro-backtrace-limit");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) {
CmdArgs.push_back("-ftemplate-backtrace-limit");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) {
CmdArgs.push_back("-fconstexpr-backtrace-limit");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) {
CmdArgs.push_back("-fspell-checking-limit");
CmdArgs.push_back(A->getValue());
}
// Pass -fmessage-length=.
CmdArgs.push_back("-fmessage-length");
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
CmdArgs.push_back(A->getValue());
} else {
// If -fmessage-length=N was not specified, determine whether this is a
// terminal and, if so, implicitly define -fmessage-length appropriately.
unsigned N = llvm::sys::Process::StandardErrColumns();
CmdArgs.push_back(Args.MakeArgString(Twine(N)));
}
// -fvisibility= and -fvisibility-ms-compat are of a piece.
if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat)) {
if (A->getOption().matches(options::OPT_fvisibility_EQ)) {
CmdArgs.push_back("-fvisibility");
CmdArgs.push_back(A->getValue());
} else {
assert(A->getOption().matches(options::OPT_fvisibility_ms_compat));
CmdArgs.push_back("-fvisibility");
CmdArgs.push_back("hidden");
CmdArgs.push_back("-ftype-visibility");
CmdArgs.push_back("default");
}
}
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden);
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden);
Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ);
// Forward -f (flag) options which we can pass directly.
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
Args.AddLastArg(CmdArgs, options::OPT_fdigraphs, options::OPT_fno_digraphs);
Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names);
Args.AddLastArg(CmdArgs, options::OPT_femulated_tls,
options::OPT_fno_emulated_tls);
Args.AddLastArg(CmdArgs, options::OPT_fkeep_static_consts);
// AltiVec-like language extensions aren't relevant for assembling.
if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm)
Args.AddLastArg(CmdArgs, options::OPT_fzvector);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type);
// Forward flags for OpenMP. We don't do this if the current action is an
// device offloading action other than OpenMP.
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
options::OPT_fno_openmp, false) &&
(JA.isDeviceOffloading(Action::OFK_None) ||
JA.isDeviceOffloading(Action::OFK_OpenMP))) {
switch (D.getOpenMPRuntime(Args)) {
case Driver::OMPRT_OMP:
case Driver::OMPRT_IOMP5:
// Clang can generate useful OpenMP code for these two runtime libraries.
CmdArgs.push_back("-fopenmp");
// If no option regarding the use of TLS in OpenMP codegeneration is
// given, decide a default based on the target. Otherwise rely on the
// options and pass the right information to the frontend.
if (!Args.hasFlag(options::OPT_fopenmp_use_tls,
options::OPT_fnoopenmp_use_tls, /*Default=*/true))
CmdArgs.push_back("-fnoopenmp-use-tls");
Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd,
options::OPT_fno_openmp_simd);
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ);
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_number_of_sm_EQ);
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_blocks_per_sm_EQ);
if (Args.hasFlag(options::OPT_fopenmp_optimistic_collapse,
options::OPT_fno_openmp_optimistic_collapse,
/*Default=*/false))
CmdArgs.push_back("-fopenmp-optimistic-collapse");
// When in OpenMP offloading mode with NVPTX target, forward
// cuda-mode flag
if (Args.hasFlag(options::OPT_fopenmp_cuda_mode,
options::OPT_fno_openmp_cuda_mode, /*Default=*/false))
CmdArgs.push_back("-fopenmp-cuda-mode");
// When in OpenMP offloading mode with NVPTX target, check if full runtime
// is required.
if (Args.hasFlag(options::OPT_fopenmp_cuda_force_full_runtime,
options::OPT_fno_openmp_cuda_force_full_runtime,
/*Default=*/false))
CmdArgs.push_back("-fopenmp-cuda-force-full-runtime");
break;
default:
// By default, if Clang doesn't know how to generate useful OpenMP code
// for a specific runtime library, we just don't pass the '-fopenmp' flag
// down to the actual compilation.
// FIXME: It would be better to have a mode which *only* omits IR
// generation based on the OpenMP support so that we get consistent
// semantic analysis, etc.
break;
}
} else {
Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd,
options::OPT_fno_openmp_simd);
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ);
}
const SanitizerArgs &Sanitize = TC.getSanitizerArgs();
Sanitize.addArgs(TC, Args, CmdArgs, InputType);
const XRayArgs &XRay = TC.getXRayArgs();
XRay.addArgs(TC, Args, CmdArgs, InputType);
if (TC.SupportsProfiling())
Args.AddLastArg(CmdArgs, options::OPT_pg);
if (TC.SupportsProfiling())
Args.AddLastArg(CmdArgs, options::OPT_mfentry);
// -flax-vector-conversions is default.
if (!Args.hasFlag(options::OPT_flax_vector_conversions,
options::OPT_fno_lax_vector_conversions))
CmdArgs.push_back("-fno-lax-vector-conversions");
if (Args.getLastArg(options::OPT_fapple_kext) ||
(Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType)))
CmdArgs.push_back("-fapple-kext");
Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
CmdArgs.push_back("-ftrapv-handler");
CmdArgs.push_back(A->getValue());
}
Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ);
// -fno-strict-overflow implies -fwrapv if it isn't disabled, but
// -fstrict-overflow won't turn off an explicitly enabled -fwrapv.
if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) {
if (A->getOption().matches(options::OPT_fwrapv))
CmdArgs.push_back("-fwrapv");
} else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow,
options::OPT_fno_strict_overflow)) {
if (A->getOption().matches(options::OPT_fno_strict_overflow))
CmdArgs.push_back("-fwrapv");
}
if (Arg *A = Args.getLastArg(options::OPT_freroll_loops,
options::OPT_fno_reroll_loops))
if (A->getOption().matches(options::OPT_freroll_loops))
CmdArgs.push_back("-freroll-loops");
Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
Args.AddLastArg(CmdArgs, options::OPT_funroll_loops,
options::OPT_fno_unroll_loops);
Args.AddLastArg(CmdArgs, options::OPT_pthread);
if (Args.hasFlag(options::OPT_mspeculative_load_hardening, options::OPT_mno_speculative_load_hardening,
false))
CmdArgs.push_back(Args.MakeArgString("-mspeculative-load-hardening"));
RenderSSPOptions(TC, Args, CmdArgs, KernelOrKext);
RenderTrivialAutoVarInitOptions(D, TC, Args, CmdArgs);
// Translate -mstackrealign
if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
false))
CmdArgs.push_back(Args.MakeArgString("-mstackrealign"));
if (Args.hasArg(options::OPT_mstack_alignment)) {
StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment));
}
if (Args.hasArg(options::OPT_mstack_probe_size)) {
StringRef Size = Args.getLastArgValue(options::OPT_mstack_probe_size);
if (!Size.empty())
CmdArgs.push_back(Args.MakeArgString("-mstack-probe-size=" + Size));
else
CmdArgs.push_back("-mstack-probe-size=0");
}
if (!Args.hasFlag(options::OPT_mstack_arg_probe,
options::OPT_mno_stack_arg_probe, true))
CmdArgs.push_back(Args.MakeArgString("-mno-stack-arg-probe"));
if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it,
options::OPT_mno_restrict_it)) {
if (A->getOption().matches(options::OPT_mrestrict_it)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-arm-restrict-it");
} else {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-arm-no-restrict-it");
}
} else if (Triple.isOSWindows() &&
(Triple.getArch() == llvm::Triple::arm ||
Triple.getArch() == llvm::Triple::thumb)) {
// Windows on ARM expects restricted IT blocks
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-arm-restrict-it");
}
// Forward -cl options to -cc1
RenderOpenCLOptions(Args, CmdArgs);
if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) {
CmdArgs.push_back(
Args.MakeArgString(Twine("-fcf-protection=") + A->getValue()));
}
// Forward -f options with positive and negative forms; we translate
// these by hand.
if (Arg *A = getLastProfileSampleUseArg(Args)) {
StringRef fname = A->getValue();
if (!llvm::sys::fs::exists(fname))
D.Diag(diag::err_drv_no_such_file) << fname;
else
A->render(Args, CmdArgs);
}
Args.AddLastArg(CmdArgs, options::OPT_fprofile_remapping_file_EQ);
RenderBuiltinOptions(TC, RawTriple, Args, CmdArgs);
if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
options::OPT_fno_assume_sane_operator_new))
CmdArgs.push_back("-fno-assume-sane-operator-new");
// -fblocks=0 is default.
if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
TC.IsBlocksDefault()) ||
(Args.hasArg(options::OPT_fgnu_runtime) &&
Args.hasArg(options::OPT_fobjc_nonfragile_abi) &&
!Args.hasArg(options::OPT_fno_blocks))) {
CmdArgs.push_back("-fblocks");
if (!Args.hasArg(options::OPT_fgnu_runtime) && !TC.hasBlocksRuntime())
CmdArgs.push_back("-fblocks-runtime-optional");
}
// -fencode-extended-block-signature=1 is default.
if (TC.IsEncodeExtendedBlockSignatureDefault())
CmdArgs.push_back("-fencode-extended-block-signature");
if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts,
false) &&
types::isCXX(InputType)) {
CmdArgs.push_back("-fcoroutines-ts");
}
Args.AddLastArg(CmdArgs, options::OPT_fdouble_square_bracket_attributes,
options::OPT_fno_double_square_bracket_attributes);
bool HaveModules = false;
RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules);
// -faccess-control is default.
if (Args.hasFlag(options::OPT_fno_access_control,
options::OPT_faccess_control, false))
CmdArgs.push_back("-fno-access-control");
// -felide-constructors is the default.
if (Args.hasFlag(options::OPT_fno_elide_constructors,
options::OPT_felide_constructors, false))
CmdArgs.push_back("-fno-elide-constructors");
ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
if (KernelOrKext || (types::isCXX(InputType) &&
(RTTIMode == ToolChain::RM_Disabled)))
CmdArgs.push_back("-fno-rtti");
// -fshort-enums=0 is default for all architectures except Hexagon.
if (Args.hasFlag(options::OPT_fshort_enums, options::OPT_fno_short_enums,
TC.getArch() == llvm::Triple::hexagon))
CmdArgs.push_back("-fshort-enums");
RenderCharacterOptions(Args, AuxTriple ? *AuxTriple : RawTriple, CmdArgs);
// -fuse-cxa-atexit is default.
if (!Args.hasFlag(
options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit,
!RawTriple.isOSWindows() &&
RawTriple.getOS() != llvm::Triple::Solaris &&
TC.getArch() != llvm::Triple::xcore &&
((RawTriple.getVendor() != llvm::Triple::MipsTechnologies) ||
RawTriple.hasEnvironment())) ||
KernelOrKext)
CmdArgs.push_back("-fno-use-cxa-atexit");
if (Args.hasFlag(options::OPT_fregister_global_dtors_with_atexit,
options::OPT_fno_register_global_dtors_with_atexit,
RawTriple.isOSDarwin() && !KernelOrKext))
CmdArgs.push_back("-fregister-global-dtors-with-atexit");
// -fms-extensions=0 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
IsWindowsMSVC))
CmdArgs.push_back("-fms-extensions");
// -fno-use-line-directives is default.
if (Args.hasFlag(options::OPT_fuse_line_directives,
options::OPT_fno_use_line_directives, false))
CmdArgs.push_back("-fuse-line-directives");
// -fms-compatibility=0 is default.
if (Args.hasFlag(options::OPT_fms_compatibility,
options::OPT_fno_ms_compatibility,
(IsWindowsMSVC &&
Args.hasFlag(options::OPT_fms_extensions,
options::OPT_fno_ms_extensions, true))))
CmdArgs.push_back("-fms-compatibility");
VersionTuple MSVT = TC.computeMSVCVersion(&D, Args);
if (!MSVT.empty())
CmdArgs.push_back(
Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString()));
bool IsMSVC2015Compatible = MSVT.getMajor() >= 19;
if (ImplyVCPPCXXVer) {
StringRef LanguageStandard;
if (const Arg *StdArg = Args.getLastArg(options::OPT__SLASH_std)) {
LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue())
.Case("c++14", "-std=c++14")
.Case("c++17", "-std=c++17")
.Case("c++latest", "-std=c++2a")
.Default("");
if (LanguageStandard.empty())
D.Diag(clang::diag::warn_drv_unused_argument)
<< StdArg->getAsString(Args);
}
if (LanguageStandard.empty()) {
if (IsMSVC2015Compatible)
LanguageStandard = "-std=c++14";
else
LanguageStandard = "-std=c++11";
}
CmdArgs.push_back(LanguageStandard.data());
}
// -fno-borland-extensions is default.
if (Args.hasFlag(options::OPT_fborland_extensions,
options::OPT_fno_borland_extensions, false))
CmdArgs.push_back("-fborland-extensions");
// -fno-declspec is default, except for PS4.
if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec,
RawTriple.isPS4()))
CmdArgs.push_back("-fdeclspec");
else if (Args.hasArg(options::OPT_fno_declspec))
CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec.
// -fthreadsafe-static is default, except for MSVC compatibility versions less
// than 19.
if (!Args.hasFlag(options::OPT_fthreadsafe_statics,
options::OPT_fno_threadsafe_statics,
!IsWindowsMSVC || IsMSVC2015Compatible))
CmdArgs.push_back("-fno-threadsafe-statics");
// -fno-delayed-template-parsing is default, except when targeting MSVC.
// Many old Windows SDK versions require this to parse.
// FIXME: MSVC introduced /Zc:twoPhase- to disable this behavior in their
// compiler. We should be able to disable this by default at some point.
if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
options::OPT_fno_delayed_template_parsing, IsWindowsMSVC))
CmdArgs.push_back("-fdelayed-template-parsing");
// -fgnu-keywords default varies depending on language; only pass if
// specified.
if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords,
options::OPT_fno_gnu_keywords))
A->render(Args, CmdArgs);
if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline,
false))
CmdArgs.push_back("-fgnu89-inline");
if (Args.hasArg(options::OPT_fno_inline))
CmdArgs.push_back("-fno-inline");
if (Arg* InlineArg = Args.getLastArg(options::OPT_finline_functions,
options::OPT_finline_hint_functions,
options::OPT_fno_inline_functions))
InlineArg->render(Args, CmdArgs);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager,
options::OPT_fno_experimental_new_pass_manager);
ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind);
RenderObjCOptions(TC, D, RawTriple, Args, Runtime, rewriteKind != RK_None,
Input, CmdArgs);
if (Args.hasFlag(options::OPT_fapplication_extension,
options::OPT_fno_application_extension, false))
CmdArgs.push_back("-fapplication-extension");
// Handle GCC-style exception args.
if (!C.getDriver().IsCLMode())
addExceptionArgs(Args, InputType, TC, KernelOrKext, Runtime, CmdArgs);
// Handle exception personalities
Arg *A = Args.getLastArg(options::OPT_fsjlj_exceptions,
options::OPT_fseh_exceptions,
options::OPT_fdwarf_exceptions);
if (A) {
const Option &Opt = A->getOption();
if (Opt.matches(options::OPT_fsjlj_exceptions))
CmdArgs.push_back("-fsjlj-exceptions");
if (Opt.matches(options::OPT_fseh_exceptions))
CmdArgs.push_back("-fseh-exceptions");
if (Opt.matches(options::OPT_fdwarf_exceptions))
CmdArgs.push_back("-fdwarf-exceptions");
} else {
switch (TC.GetExceptionModel(Args)) {
default:
break;
case llvm::ExceptionHandling::DwarfCFI:
CmdArgs.push_back("-fdwarf-exceptions");
break;
case llvm::ExceptionHandling::SjLj:
CmdArgs.push_back("-fsjlj-exceptions");
break;
case llvm::ExceptionHandling::WinEH:
CmdArgs.push_back("-fseh-exceptions");
break;
}
}
// C++ "sane" operator new.
if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
options::OPT_fno_assume_sane_operator_new))
CmdArgs.push_back("-fno-assume-sane-operator-new");
// -frelaxed-template-template-args is off by default, as it is a severe
// breaking change until a corresponding change to template partial ordering
// is provided.
if (Args.hasFlag(options::OPT_frelaxed_template_template_args,
options::OPT_fno_relaxed_template_template_args, false))
CmdArgs.push_back("-frelaxed-template-template-args");
// -fsized-deallocation is off by default, as it is an ABI-breaking change for
// most platforms.
if (Args.hasFlag(options::OPT_fsized_deallocation,
options::OPT_fno_sized_deallocation, false))
CmdArgs.push_back("-fsized-deallocation");
// -faligned-allocation is on by default in C++17 onwards and otherwise off
// by default.
if (Arg *A = Args.getLastArg(options::OPT_faligned_allocation,
options::OPT_fno_aligned_allocation,
options::OPT_faligned_new_EQ)) {
if (A->getOption().matches(options::OPT_fno_aligned_allocation))
CmdArgs.push_back("-fno-aligned-allocation");
else
CmdArgs.push_back("-faligned-allocation");
}
// The default new alignment can be specified using a dedicated option or via
// a GCC-compatible option that also turns on aligned allocation.
if (Arg *A = Args.getLastArg(options::OPT_fnew_alignment_EQ,
options::OPT_faligned_new_EQ))
CmdArgs.push_back(
Args.MakeArgString(Twine("-fnew-alignment=") + A->getValue()));
// -fconstant-cfstrings is default, and may be subject to argument translation
// on Darwin.
if (!Args.hasFlag(options::OPT_fconstant_cfstrings,
options::OPT_fno_constant_cfstrings) ||
!Args.hasFlag(options::OPT_mconstant_cfstrings,
options::OPT_mno_constant_cfstrings))
CmdArgs.push_back("-fno-constant-cfstrings");
// -fno-pascal-strings is default, only pass non-default.
if (Args.hasFlag(options::OPT_fpascal_strings,
options::OPT_fno_pascal_strings, false))
CmdArgs.push_back("-fpascal-strings");
// Honor -fpack-struct= and -fpack-struct, if given. Note that
// -fno-pack-struct doesn't apply to -fpack-struct=.
if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) {
std::string PackStructStr = "-fpack-struct=";
PackStructStr += A->getValue();
CmdArgs.push_back(Args.MakeArgString(PackStructStr));
} else if (Args.hasFlag(options::OPT_fpack_struct,
options::OPT_fno_pack_struct, false)) {
CmdArgs.push_back("-fpack-struct=1");
}
// Handle -fmax-type-align=N and -fno-type-align
bool SkipMaxTypeAlign = Args.hasArg(options::OPT_fno_max_type_align);
if (Arg *A = Args.getLastArg(options::OPT_fmax_type_align_EQ)) {
if (!SkipMaxTypeAlign) {
std::string MaxTypeAlignStr = "-fmax-type-align=";
MaxTypeAlignStr += A->getValue();
CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
}
} else if (RawTriple.isOSDarwin()) {
if (!SkipMaxTypeAlign) {
std::string MaxTypeAlignStr = "-fmax-type-align=16";
CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
}
}
if (!Args.hasFlag(options::OPT_Qy, options::OPT_Qn, true))
CmdArgs.push_back("-Qn");
// -fcommon is the default unless compiling kernel code or the target says so
bool NoCommonDefault = KernelOrKext || isNoCommonDefault(RawTriple);
if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common,
!NoCommonDefault))
CmdArgs.push_back("-fno-common");
// -fsigned-bitfields is default, and clang doesn't yet support
// -funsigned-bitfields.
if (!Args.hasFlag(options::OPT_fsigned_bitfields,
options::OPT_funsigned_bitfields))
D.Diag(diag::warn_drv_clang_unsupported)
<< Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args);
// -fsigned-bitfields is default, and clang doesn't support -fno-for-scope.
if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope))
D.Diag(diag::err_drv_clang_unsupported)
<< Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args);
// -finput_charset=UTF-8 is default. Reject others
if (Arg *inputCharset = Args.getLastArg(options::OPT_finput_charset_EQ)) {
StringRef value = inputCharset->getValue();
if (!value.equals_lower("utf-8"))
D.Diag(diag::err_drv_invalid_value) << inputCharset->getAsString(Args)
<< value;
}
// -fexec_charset=UTF-8 is default. Reject others
if (Arg *execCharset = Args.getLastArg(options::OPT_fexec_charset_EQ)) {
StringRef value = execCharset->getValue();
if (!value.equals_lower("utf-8"))
D.Diag(diag::err_drv_invalid_value) << execCharset->getAsString(Args)
<< value;
}
RenderDiagnosticsOptions(D, Args, CmdArgs);
// -fno-asm-blocks is default.
if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks,
false))
CmdArgs.push_back("-fasm-blocks");
// -fgnu-inline-asm is default.
if (!Args.hasFlag(options::OPT_fgnu_inline_asm,
options::OPT_fno_gnu_inline_asm, true))
CmdArgs.push_back("-fno-gnu-inline-asm");
// Enable vectorization per default according to the optimization level
// selected. For optimization levels that want vectorization we use the alias
// option to simplify the hasFlag logic.
bool EnableVec = shouldEnableVectorizerAtOLevel(Args, false);
OptSpecifier VectorizeAliasOption =
EnableVec ? options::OPT_O_Group : options::OPT_fvectorize;
if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption,
options::OPT_fno_vectorize, EnableVec))
CmdArgs.push_back("-vectorize-loops");
// -fslp-vectorize is enabled based on the optimization level selected.
bool EnableSLPVec = shouldEnableVectorizerAtOLevel(Args, true);
OptSpecifier SLPVectAliasOption =
EnableSLPVec ? options::OPT_O_Group : options::OPT_fslp_vectorize;
if (Args.hasFlag(options::OPT_fslp_vectorize, SLPVectAliasOption,
options::OPT_fno_slp_vectorize, EnableSLPVec))
CmdArgs.push_back("-vectorize-slp");
ParseMPreferVectorWidth(D, Args, CmdArgs);
if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ))
A->render(Args, CmdArgs);
if (Arg *A = Args.getLastArg(
options::OPT_fsanitize_undefined_strip_path_components_EQ))
A->render(Args, CmdArgs);
// -fdollars-in-identifiers default varies depending on platform and
// language; only pass if specified.
if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers,
options::OPT_fno_dollars_in_identifiers)) {
if (A->getOption().matches(options::OPT_fdollars_in_identifiers))
CmdArgs.push_back("-fdollars-in-identifiers");
else
CmdArgs.push_back("-fno-dollars-in-identifiers");
}
// -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for
// practical purposes.
if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time,
options::OPT_fno_unit_at_a_time)) {
if (A->getOption().matches(options::OPT_fno_unit_at_a_time))
D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);
}
if (Args.hasFlag(options::OPT_fapple_pragma_pack,
options::OPT_fno_apple_pragma_pack, false))
CmdArgs.push_back("-fapple-pragma-pack");
if (Args.hasFlag(options::OPT_fsave_optimization_record,
options::OPT_foptimization_record_file_EQ,
options::OPT_fno_save_optimization_record, false)) {
CmdArgs.push_back("-opt-record-file");
const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ);
if (A) {
CmdArgs.push_back(A->getValue());
} else {
SmallString<128> F;
if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) {
if (Arg *FinalOutput = Args.getLastArg(options::OPT_o))
F = FinalOutput->getValue();
}
if (F.empty()) {
// Use the input filename.
F = llvm::sys::path::stem(Input.getBaseInput());
// If we're compiling for an offload architecture (i.e. a CUDA device),
// we need to make the file name for the device compilation different
// from the host compilation.
if (!JA.isDeviceOffloading(Action::OFK_None) &&
!JA.isDeviceOffloading(Action::OFK_Host)) {
llvm::sys::path::replace_extension(F, "");
F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(),
Triple.normalize());
F += "-";
F += JA.getOffloadingArch();
}
}
llvm::sys::path::replace_extension(F, "opt.yaml");
CmdArgs.push_back(Args.MakeArgString(F));
}
}
bool RewriteImports = Args.hasFlag(options::OPT_frewrite_imports,
options::OPT_fno_rewrite_imports, false);
if (RewriteImports)
CmdArgs.push_back("-frewrite-imports");
// Enable rewrite includes if the user's asked for it or if we're generating
// diagnostics.
// TODO: Once -module-dependency-dir works with -frewrite-includes it'd be
// nice to enable this when doing a crashdump for modules as well.
if (Args.hasFlag(options::OPT_frewrite_includes,
options::OPT_fno_rewrite_includes, false) ||
(C.isForDiagnostics() && !HaveModules))
CmdArgs.push_back("-frewrite-includes");
// Only allow -traditional or -traditional-cpp outside in preprocessing modes.
if (Arg *A = Args.getLastArg(options::OPT_traditional,
options::OPT_traditional_cpp)) {
if (isa<PreprocessJobAction>(JA))
CmdArgs.push_back("-traditional-cpp");
else
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
Args.AddLastArg(CmdArgs, options::OPT_dM);
Args.AddLastArg(CmdArgs, options::OPT_dD);
// Handle serialized diagnostics.
if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) {
CmdArgs.push_back("-serialize-diagnostic-file");
CmdArgs.push_back(Args.MakeArgString(A->getValue()));
}
if (Args.hasArg(options::OPT_fretain_comments_from_system_headers))
CmdArgs.push_back("-fretain-comments-from-system-headers");
// Forward -fcomment-block-commands to -cc1.
Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands);
// Forward -fparse-all-comments to -cc1.
Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments);
// Turn -fplugin=name.so into -load name.so
for (const Arg *A : Args.filtered(options::OPT_fplugin_EQ)) {
CmdArgs.push_back("-load");
CmdArgs.push_back(A->getValue());
A->claim();
}
// Setup statistics file output.
SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);
if (!StatsFile.empty())
CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + StatsFile));
// Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
// parser.
// -finclude-default-header flag is for preprocessor,
// do not pass it to other cc1 commands when save-temps is enabled
if (C.getDriver().isSaveTempsEnabled() &&
!isa<PreprocessJobAction>(JA)) {
for (auto Arg : Args.filtered(options::OPT_Xclang)) {
Arg->claim();
if (StringRef(Arg->getValue()) != "-finclude-default-header")
CmdArgs.push_back(Arg->getValue());
}
}
else {
Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
}
for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
A->claim();
// We translate this by hand to the -cc1 argument, since nightly test uses
// it and developers have been trained to spell it with -mllvm. Both
// spellings are now deprecated and should be removed.
if (StringRef(A->getValue(0)) == "-disable-llvm-optzns") {
CmdArgs.push_back("-disable-llvm-optzns");
} else {
A->render(Args, CmdArgs);
}
}
// With -save-temps, we want to save the unoptimized bitcode output from the
// CompileJobAction, use -disable-llvm-passes to get pristine IR generated
// by the frontend.
// When -fembed-bitcode is enabled, optimized bitcode is emitted because it
// has slightly different breakdown between stages.
// FIXME: -fembed-bitcode -save-temps will save optimized bitcode instead of
// pristine IR generated by the frontend. Ideally, a new compile action should
// be added so both IR can be captured.
if (C.getDriver().isSaveTempsEnabled() &&
!(C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO()) &&
isa<CompileJobAction>(JA))
CmdArgs.push_back("-disable-llvm-passes");
if (Output.getType() == types::TY_Dependencies) {
// Handled with other dependency code.
} else if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
} else {
assert(Output.isNothing() && "Invalid output.");
}
addDashXForInput(Args, Input, CmdArgs);
ArrayRef<InputInfo> FrontendInputs = Input;
if (IsHeaderModulePrecompile)
FrontendInputs = ModuleHeaderInputs;
else if (Input.isNothing())
FrontendInputs = {};
for (const InputInfo &Input : FrontendInputs) {
if (Input.isFilename())
CmdArgs.push_back(Input.getFilename());
else
Input.getInputArg().renderAsInput(Args, CmdArgs);
}
Args.AddAllArgs(CmdArgs, options::OPT_undef);
const char *Exec = D.getClangProgramPath();
// Optionally embed the -cc1 level arguments into the debug info or a
// section, for build analysis.
// Also record command line arguments into the debug info if
// -grecord-gcc-switches options is set on.
// By default, -gno-record-gcc-switches is set on and no recording.
auto GRecordSwitches =
Args.hasFlag(options::OPT_grecord_command_line,
options::OPT_gno_record_command_line, false);
auto FRecordSwitches =
Args.hasFlag(options::OPT_frecord_command_line,
options::OPT_fno_record_command_line, false);
if (FRecordSwitches && !Triple.isOSBinFormatELF())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< Args.getLastArg(options::OPT_frecord_command_line)->getAsString(Args)
<< TripleStr;
if (TC.UseDwarfDebugFlags() || GRecordSwitches || FRecordSwitches) {
ArgStringList OriginalArgs;
for (const auto &Arg : Args)
Arg->render(Args, OriginalArgs);
SmallString<256> Flags;
Flags += Exec;
for (const char *OriginalArg : OriginalArgs) {
SmallString<128> EscapedArg;
EscapeSpacesAndBackslashes(OriginalArg, EscapedArg);
Flags += " ";
Flags += EscapedArg;
}
auto FlagsArgString = Args.MakeArgString(Flags);
if (TC.UseDwarfDebugFlags() || GRecordSwitches) {
CmdArgs.push_back("-dwarf-debug-flags");
CmdArgs.push_back(FlagsArgString);
}
if (FRecordSwitches) {
CmdArgs.push_back("-record-command-line");
CmdArgs.push_back(FlagsArgString);
}
}
// Host-side cuda compilation receives all device-side outputs in a single
// fatbin as Inputs[1]. Include the binary with -fcuda-include-gpubinary.
if ((IsCuda || IsHIP) && CudaDeviceInput) {
CmdArgs.push_back("-fcuda-include-gpubinary");
CmdArgs.push_back(CudaDeviceInput->getFilename());
if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
CmdArgs.push_back("-fgpu-rdc");
}
if (IsCuda) {
if (Args.hasFlag(options::OPT_fcuda_short_ptr,
options::OPT_fno_cuda_short_ptr, false))
CmdArgs.push_back("-fcuda-short-ptr");
}
// OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path
// to specify the result of the compile phase on the host, so the meaningful
// device declarations can be identified. Also, -fopenmp-is-device is passed
// along to tell the frontend that it is generating code for a device, so that
// only the relevant declarations are emitted.
if (IsOpenMPDevice) {
CmdArgs.push_back("-fopenmp-is-device");
if (OpenMPDeviceInput) {
CmdArgs.push_back("-fopenmp-host-ir-file-path");
CmdArgs.push_back(Args.MakeArgString(OpenMPDeviceInput->getFilename()));
}
}
// For all the host OpenMP offloading compile jobs we need to pass the targets
// information using -fopenmp-targets= option.
if (JA.isHostOffloading(Action::OFK_OpenMP)) {
SmallString<128> TargetInfo("-fopenmp-targets=");
Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ);
assert(Tgts && Tgts->getNumValues() &&
"OpenMP offloading has to have targets specified.");
for (unsigned i = 0; i < Tgts->getNumValues(); ++i) {
if (i)
TargetInfo += ',';
// We need to get the string from the triple because it may be not exactly
// the same as the one we get directly from the arguments.
llvm::Triple T(Tgts->getValue(i));
TargetInfo += T.getTriple();
}
CmdArgs.push_back(Args.MakeArgString(TargetInfo.str()));
}
bool WholeProgramVTables =
Args.hasFlag(options::OPT_fwhole_program_vtables,
options::OPT_fno_whole_program_vtables, false);
if (WholeProgramVTables) {
if (!D.isUsingLTO())
D.Diag(diag::err_drv_argument_only_allowed_with)
<< "-fwhole-program-vtables"
<< "-flto";
CmdArgs.push_back("-fwhole-program-vtables");
}
bool RequiresSplitLTOUnit = WholeProgramVTables || Sanitize.needsLTO();
bool SplitLTOUnit =
Args.hasFlag(options::OPT_fsplit_lto_unit,
options::OPT_fno_split_lto_unit, RequiresSplitLTOUnit);
if (RequiresSplitLTOUnit && !SplitLTOUnit)
D.Diag(diag::err_drv_argument_not_allowed_with)
<< "-fno-split-lto-unit"
<< (WholeProgramVTables ? "-fwhole-program-vtables" : "-fsanitize=cfi");
if (SplitLTOUnit)
CmdArgs.push_back("-fsplit-lto-unit");
if (Arg *A = Args.getLastArg(options::OPT_fexperimental_isel,
options::OPT_fno_experimental_isel)) {
CmdArgs.push_back("-mllvm");
if (A->getOption().matches(options::OPT_fexperimental_isel)) {
CmdArgs.push_back("-global-isel=1");
// GISel is on by default on AArch64 -O0, so don't bother adding
// the fallback remarks for it. Other combinations will add a warning of
// some kind.
bool IsArchSupported = Triple.getArch() == llvm::Triple::aarch64;
bool IsOptLevelSupported = false;
Arg *A = Args.getLastArg(options::OPT_O_Group);
if (Triple.getArch() == llvm::Triple::aarch64) {
if (!A || A->getOption().matches(options::OPT_O0))
IsOptLevelSupported = true;
}
if (!IsArchSupported || !IsOptLevelSupported) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-global-isel-abort=2");
if (!IsArchSupported)
D.Diag(diag::warn_drv_experimental_isel_incomplete) << Triple.getArchName();
else
D.Diag(diag::warn_drv_experimental_isel_incomplete_opt);
}
} else {
CmdArgs.push_back("-global-isel=0");
}
}
if (Arg *A = Args.getLastArg(options::OPT_fforce_enable_int128,
options::OPT_fno_force_enable_int128)) {
if (A->getOption().matches(options::OPT_fforce_enable_int128))
CmdArgs.push_back("-fforce-enable-int128");
}
if (Args.hasFlag(options::OPT_fcomplete_member_pointers,
options::OPT_fno_complete_member_pointers, false))
CmdArgs.push_back("-fcomplete-member-pointers");
if (!Args.hasFlag(options::OPT_fcxx_static_destructors,
options::OPT_fno_cxx_static_destructors, true))
CmdArgs.push_back("-fno-c++-static-destructors");
if (Arg *A = Args.getLastArg(options::OPT_moutline,
options::OPT_mno_outline)) {
if (A->getOption().matches(options::OPT_moutline)) {
// We only support -moutline in AArch64 right now. If we're not compiling
// for AArch64, emit a warning and ignore the flag. Otherwise, add the
// proper mllvm flags.
if (Triple.getArch() != llvm::Triple::aarch64) {
D.Diag(diag::warn_drv_moutline_unsupported_opt) << Triple.getArchName();
} else {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-enable-machine-outliner");
}
} else {
// Disable all outlining behaviour.
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-enable-machine-outliner=never");
}
}
if (Args.hasFlag(options::OPT_faddrsig, options::OPT_fno_addrsig,
(TC.getTriple().isOSBinFormatELF() ||
TC.getTriple().isOSBinFormatCOFF()) &&
!TC.getTriple().isPS4() &&
!TC.getTriple().isOSNetBSD() &&
!Distro(D.getVFS()).IsGentoo() &&
!TC.getTriple().isAndroid() &&
TC.useIntegratedAs()))
CmdArgs.push_back("-faddrsig");
// Finally add the compile command to the compilation.
if (Args.hasArg(options::OPT__SLASH_fallback) &&
Output.getType() == types::TY_Object &&
(InputType == types::TY_C || InputType == types::TY_CXX)) {
auto CLCommand =
getCLFallback()->GetCommand(C, JA, Output, Inputs, Args, LinkingOutput);
C.addCommand(llvm::make_unique<FallbackCommand>(
JA, *this, Exec, CmdArgs, Inputs, std::move(CLCommand)));
} else if (Args.hasArg(options::OPT__SLASH_fallback) &&
isa<PrecompileJobAction>(JA)) {
// In /fallback builds, run the main compilation even if the pch generation
// fails, so that the main compilation's fallback to cl.exe runs.
C.addCommand(llvm::make_unique<ForceSuccessCommand>(JA, *this, Exec,
CmdArgs, Inputs));
} else {
C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
// Make the compile command echo its inputs for /showFilenames.
if (Output.getType() == types::TY_Object &&
Args.hasFlag(options::OPT__SLASH_showFilenames,
options::OPT__SLASH_showFilenames_, false)) {
C.getJobs().getJobs().back()->setPrintInputFilenames(true);
}
if (Arg *A = Args.getLastArg(options::OPT_pg))
if (!shouldUseFramePointer(Args, Triple))
D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer"
<< A->getAsString(Args);
// Claim some arguments which clang supports automatically.
// -fpch-preprocess is used with gcc to add a special marker in the output to
// include the PCH file.
Args.ClaimAllArgs(options::OPT_fpch_preprocess);
// Claim some arguments which clang doesn't support, but we don't
// care to warn the user about.
Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group);
Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group);
// Disable warnings for clang -E -emit-llvm foo.c
Args.ClaimAllArgs(options::OPT_emit_llvm);
}
Clang::Clang(const ToolChain &TC)
// CAUTION! The first constructor argument ("clang") is not arbitrary,
// as it is for other tools. Some operations on a Tool actually test
// whether that tool is Clang based on the Tool's Name as a string.
: Tool("clang", "clang frontend", TC, RF_Full) {}
Clang::~Clang() {}
/// Add options related to the Objective-C runtime/ABI.
///
/// Returns true if the runtime is non-fragile.
ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
ArgStringList &cmdArgs,
RewriteKind rewriteKind) const {
// Look for the controlling runtime option.
Arg *runtimeArg =
args.getLastArg(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
options::OPT_fobjc_runtime_EQ);
// Just forward -fobjc-runtime= to the frontend. This supercedes
// options about fragility.
if (runtimeArg &&
runtimeArg->getOption().matches(options::OPT_fobjc_runtime_EQ)) {
ObjCRuntime runtime;
StringRef value = runtimeArg->getValue();
if (runtime.tryParse(value)) {
getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime)
<< value;
}
if ((runtime.getKind() == ObjCRuntime::GNUstep) &&
(runtime.getVersion() >= VersionTuple(2, 0)))
if (!getToolChain().getTriple().isOSBinFormatELF() &&
!getToolChain().getTriple().isOSBinFormatCOFF()) {
getToolChain().getDriver().Diag(
diag::err_drv_gnustep_objc_runtime_incompatible_binary)
<< runtime.getVersion().getMajor();
}
runtimeArg->render(args, cmdArgs);
return runtime;
}
// Otherwise, we'll need the ABI "version". Version numbers are
// slightly confusing for historical reasons:
// 1 - Traditional "fragile" ABI
// 2 - Non-fragile ABI, version 1
// 3 - Non-fragile ABI, version 2
unsigned objcABIVersion = 1;
// If -fobjc-abi-version= is present, use that to set the version.
if (Arg *abiArg = args.getLastArg(options::OPT_fobjc_abi_version_EQ)) {
StringRef value = abiArg->getValue();
if (value == "1")
objcABIVersion = 1;
else if (value == "2")
objcABIVersion = 2;
else if (value == "3")
objcABIVersion = 3;
else
getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) << value;
} else {
// Otherwise, determine if we are using the non-fragile ABI.
bool nonFragileABIIsDefault =
(rewriteKind == RK_NonFragile ||
(rewriteKind == RK_None &&
getToolChain().IsObjCNonFragileABIDefault()));
if (args.hasFlag(options::OPT_fobjc_nonfragile_abi,
options::OPT_fno_objc_nonfragile_abi,
nonFragileABIIsDefault)) {
// Determine the non-fragile ABI version to use.
#ifdef DISABLE_DEFAULT_NONFRAGILEABI_TWO
unsigned nonFragileABIVersion = 1;
#else
unsigned nonFragileABIVersion = 2;
#endif
if (Arg *abiArg =
args.getLastArg(options::OPT_fobjc_nonfragile_abi_version_EQ)) {
StringRef value = abiArg->getValue();
if (value == "1")
nonFragileABIVersion = 1;
else if (value == "2")
nonFragileABIVersion = 2;
else
getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported)
<< value;
}
objcABIVersion = 1 + nonFragileABIVersion;
} else {
objcABIVersion = 1;
}
}
// We don't actually care about the ABI version other than whether
// it's non-fragile.
bool isNonFragile = objcABIVersion != 1;
// If we have no runtime argument, ask the toolchain for its default runtime.
// However, the rewriter only really supports the Mac runtime, so assume that.
ObjCRuntime runtime;
if (!runtimeArg) {
switch (rewriteKind) {
case RK_None:
runtime = getToolChain().getDefaultObjCRuntime(isNonFragile);
break;
case RK_Fragile:
runtime = ObjCRuntime(ObjCRuntime::FragileMacOSX, VersionTuple());
break;
case RK_NonFragile:
runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple());
break;
}
// -fnext-runtime
} else if (runtimeArg->getOption().matches(options::OPT_fnext_runtime)) {
// On Darwin, make this use the default behavior for the toolchain.
if (getToolChain().getTriple().isOSDarwin()) {
runtime = getToolChain().getDefaultObjCRuntime(isNonFragile);
// Otherwise, build for a generic macosx port.
} else {
runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple());
}
// -fgnu-runtime
} else {
assert(runtimeArg->getOption().matches(options::OPT_fgnu_runtime));
// Legacy behaviour is to target the gnustep runtime if we are in
// non-fragile mode or the GCC runtime in fragile mode.
if (isNonFragile)
runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(2, 0));
else
runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple());
}
cmdArgs.push_back(
args.MakeArgString("-fobjc-runtime=" + runtime.getAsString()));
return runtime;
}
static bool maybeConsumeDash(const std::string &EH, size_t &I) {
bool HaveDash = (I + 1 < EH.size() && EH[I + 1] == '-');
I += HaveDash;
return !HaveDash;
}
namespace {
struct EHFlags {
bool Synch = false;
bool Asynch = false;
bool NoUnwindC = false;
};
} // end anonymous namespace
/// /EH controls whether to run destructor cleanups when exceptions are
/// thrown. There are three modifiers:
/// - s: Cleanup after "synchronous" exceptions, aka C++ exceptions.
/// - a: Cleanup after "asynchronous" exceptions, aka structured exceptions.
/// The 'a' modifier is unimplemented and fundamentally hard in LLVM IR.
/// - c: Assume that extern "C" functions are implicitly nounwind.
/// The default is /EHs-c-, meaning cleanups are disabled.
static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) {
EHFlags EH;
std::vector<std::string> EHArgs =
Args.getAllArgValues(options::OPT__SLASH_EH);
for (auto EHVal : EHArgs) {
for (size_t I = 0, E = EHVal.size(); I != E; ++I) {
switch (EHVal[I]) {
case 'a':
EH.Asynch = maybeConsumeDash(EHVal, I);
if (EH.Asynch)
EH.Synch = false;
continue;
case 'c':
EH.NoUnwindC = maybeConsumeDash(EHVal, I);
continue;
case 's':
EH.Synch = maybeConsumeDash(EHVal, I);
if (EH.Synch)
EH.Asynch = false;
continue;
default:
break;
}
D.Diag(clang::diag::err_drv_invalid_value) << "/EH" << EHVal;
break;
}
}
// The /GX, /GX- flags are only processed if there are not /EH flags.
// The default is that /GX is not specified.
if (EHArgs.empty() &&
Args.hasFlag(options::OPT__SLASH_GX, options::OPT__SLASH_GX_,
/*default=*/false)) {
EH.Synch = true;
EH.NoUnwindC = true;
}
return EH;
}
void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
ArgStringList &CmdArgs,
codegenoptions::DebugInfoKind *DebugInfoKind,
bool *EmitCodeView) const {
unsigned RTOptionID = options::OPT__SLASH_MT;
if (Args.hasArg(options::OPT__SLASH_LDd))
// The /LDd option implies /MTd. The dependent lib part can be overridden,
// but defining _DEBUG is sticky.
RTOptionID = options::OPT__SLASH_MTd;
if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group))
RTOptionID = A->getOption().getID();
StringRef FlagForCRT;
switch (RTOptionID) {
case options::OPT__SLASH_MD:
if (Args.hasArg(options::OPT__SLASH_LDd))
CmdArgs.push_back("-D_DEBUG");
CmdArgs.push_back("-D_MT");
CmdArgs.push_back("-D_DLL");
FlagForCRT = "--dependent-lib=msvcrt";
break;
case options::OPT__SLASH_MDd:
CmdArgs.push_back("-D_DEBUG");
CmdArgs.push_back("-D_MT");
CmdArgs.push_back("-D_DLL");
FlagForCRT = "--dependent-lib=msvcrtd";
break;
case options::OPT__SLASH_MT:
if (Args.hasArg(options::OPT__SLASH_LDd))
CmdArgs.push_back("-D_DEBUG");
CmdArgs.push_back("-D_MT");
CmdArgs.push_back("-flto-visibility-public-std");
FlagForCRT = "--dependent-lib=libcmt";
break;
case options::OPT__SLASH_MTd:
CmdArgs.push_back("-D_DEBUG");
CmdArgs.push_back("-D_MT");
CmdArgs.push_back("-flto-visibility-public-std");
FlagForCRT = "--dependent-lib=libcmtd";
break;
default:
llvm_unreachable("Unexpected option ID.");
}
if (Args.hasArg(options::OPT__SLASH_Zl)) {
CmdArgs.push_back("-D_VC_NODEFAULTLIB");
} else {
CmdArgs.push_back(FlagForCRT.data());
// This provides POSIX compatibility (maps 'open' to '_open'), which most
// users want. The /Za flag to cl.exe turns this off, but it's not
// implemented in clang.
CmdArgs.push_back("--dependent-lib=oldnames");
}
if (Arg *A = Args.getLastArg(options::OPT_show_includes))
A->render(Args, CmdArgs);
// This controls whether or not we emit RTTI data for polymorphic types.
if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR,
/*default=*/false))
CmdArgs.push_back("-fno-rtti-data");
// This controls whether or not we emit stack-protector instrumentation.
// In MSVC, Buffer Security Check (/GS) is on by default.
if (Args.hasFlag(options::OPT__SLASH_GS, options::OPT__SLASH_GS_,
/*default=*/true)) {
CmdArgs.push_back("-stack-protector");
CmdArgs.push_back(Args.MakeArgString(Twine(LangOptions::SSPStrong)));
}
// Emit CodeView if -Z7, -Zd, or -gline-tables-only are present.
if (Arg *DebugInfoArg =
Args.getLastArg(options::OPT__SLASH_Z7, options::OPT__SLASH_Zd,
options::OPT_gline_tables_only)) {
*EmitCodeView = true;
if (DebugInfoArg->getOption().matches(options::OPT__SLASH_Z7))
*DebugInfoKind = codegenoptions::LimitedDebugInfo;
else
*DebugInfoKind = codegenoptions::DebugLineTablesOnly;
} else {
*EmitCodeView = false;
}
const Driver &D = getToolChain().getDriver();
EHFlags EH = parseClangCLEHFlags(D, Args);
if (EH.Synch || EH.Asynch) {
if (types::isCXX(InputType))
CmdArgs.push_back("-fcxx-exceptions");
CmdArgs.push_back("-fexceptions");
}
if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC)
CmdArgs.push_back("-fexternc-nounwind");
// /EP should expand to -E -P.
if (Args.hasArg(options::OPT__SLASH_EP)) {
CmdArgs.push_back("-E");
CmdArgs.push_back("-P");
}
unsigned VolatileOptionID;
if (getToolChain().getArch() == llvm::Triple::x86_64 ||
getToolChain().getArch() == llvm::Triple::x86)
VolatileOptionID = options::OPT__SLASH_volatile_ms;
else
VolatileOptionID = options::OPT__SLASH_volatile_iso;
if (Arg *A = Args.getLastArg(options::OPT__SLASH_volatile_Group))
VolatileOptionID = A->getOption().getID();
if (VolatileOptionID == options::OPT__SLASH_volatile_ms)
CmdArgs.push_back("-fms-volatile");
if (Args.hasFlag(options::OPT__SLASH_Zc_dllexportInlines_,
options::OPT__SLASH_Zc_dllexportInlines,
false)) {
if (Args.hasArg(options::OPT__SLASH_fallback)) {
D.Diag(clang::diag::err_drv_dllexport_inlines_and_fallback);
} else {
CmdArgs.push_back("-fno-dllexport-inlines");
}
}
Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg);
Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb);
if (MostGeneralArg && BestCaseArg)
D.Diag(clang::diag::err_drv_argument_not_allowed_with)
<< MostGeneralArg->getAsString(Args) << BestCaseArg->getAsString(Args);
if (MostGeneralArg) {
Arg *SingleArg = Args.getLastArg(options::OPT__SLASH_vms);
Arg *MultipleArg = Args.getLastArg(options::OPT__SLASH_vmm);
Arg *VirtualArg = Args.getLastArg(options::OPT__SLASH_vmv);
Arg *FirstConflict = SingleArg ? SingleArg : MultipleArg;
Arg *SecondConflict = VirtualArg ? VirtualArg : MultipleArg;
if (FirstConflict && SecondConflict && FirstConflict != SecondConflict)
D.Diag(clang::diag::err_drv_argument_not_allowed_with)
<< FirstConflict->getAsString(Args)
<< SecondConflict->getAsString(Args);
if (SingleArg)
CmdArgs.push_back("-fms-memptr-rep=single");
else if (MultipleArg)
CmdArgs.push_back("-fms-memptr-rep=multiple");
else
CmdArgs.push_back("-fms-memptr-rep=virtual");
}
// Parse the default calling convention options.
if (Arg *CCArg =
Args.getLastArg(options::OPT__SLASH_Gd, options::OPT__SLASH_Gr,
options::OPT__SLASH_Gz, options::OPT__SLASH_Gv,
options::OPT__SLASH_Gregcall)) {
unsigned DCCOptId = CCArg->getOption().getID();
const char *DCCFlag = nullptr;
bool ArchSupported = true;
llvm::Triple::ArchType Arch = getToolChain().getArch();
switch (DCCOptId) {
case options::OPT__SLASH_Gd:
DCCFlag = "-fdefault-calling-conv=cdecl";
break;
case options::OPT__SLASH_Gr:
ArchSupported = Arch == llvm::Triple::x86;
DCCFlag = "-fdefault-calling-conv=fastcall";
break;
case options::OPT__SLASH_Gz:
ArchSupported = Arch == llvm::Triple::x86;
DCCFlag = "-fdefault-calling-conv=stdcall";
break;
case options::OPT__SLASH_Gv:
ArchSupported = Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64;
DCCFlag = "-fdefault-calling-conv=vectorcall";
break;
case options::OPT__SLASH_Gregcall:
ArchSupported = Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64;
DCCFlag = "-fdefault-calling-conv=regcall";
break;
}
// MSVC doesn't warn if /Gr or /Gz is used on x64, so we don't either.
if (ArchSupported && DCCFlag)
CmdArgs.push_back(DCCFlag);
}
if (Arg *A = Args.getLastArg(options::OPT_vtordisp_mode_EQ))
A->render(Args, CmdArgs);
if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) {
CmdArgs.push_back("-fdiagnostics-format");
if (Args.hasArg(options::OPT__SLASH_fallback))
CmdArgs.push_back("msvc-fallback");
else
CmdArgs.push_back("msvc");
}
if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) {
SmallVector<StringRef, 1> SplitArgs;
StringRef(A->getValue()).split(SplitArgs, ",");
bool Instrument = false;
bool NoChecks = false;
for (StringRef Arg : SplitArgs) {
if (Arg.equals_lower("cf"))
Instrument = true;
else if (Arg.equals_lower("cf-"))
Instrument = false;
else if (Arg.equals_lower("nochecks"))
NoChecks = true;
else if (Arg.equals_lower("nochecks-"))
NoChecks = false;
else
D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << Arg;
}
// Currently there's no support emitting CFG instrumentation; the flag only
// emits the table of address-taken functions.
if (Instrument || NoChecks)
CmdArgs.push_back("-cfguard");
}
}
visualstudio::Compiler *Clang::getCLFallback() const {
if (!CLFallback)
CLFallback.reset(new visualstudio::Compiler(getToolChain()));
return CLFallback.get();
}
const char *Clang::getBaseInputName(const ArgList &Args,
const InputInfo &Input) {
return Args.MakeArgString(llvm::sys::path::filename(Input.getBaseInput()));
}
const char *Clang::getBaseInputStem(const ArgList &Args,
const InputInfoList &Inputs) {
const char *Str = getBaseInputName(Args, Inputs[0]);
if (const char *End = strrchr(Str, '.'))
return Args.MakeArgString(std::string(Str, End));
return Str;
}
const char *Clang::getDependencyFileName(const ArgList &Args,
const InputInfoList &Inputs) {
// FIXME: Think about this more.
std::string Res;
if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
std::string Str(OutputOpt->getValue());
Res = Str.substr(0, Str.rfind('.'));
} else {
Res = getBaseInputStem(Args, Inputs);
}
return Args.MakeArgString(Res + ".d");
}
// Begin ClangAs
void ClangAs::AddMIPSTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
StringRef CPUName;
StringRef ABIName;
const llvm::Triple &Triple = getToolChain().getTriple();
mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName.data());
}
void ClangAs::AddX86TargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) {
StringRef Value = A->getValue();
if (Value == "intel" || Value == "att") {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
} else {
getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
}
}
}
void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
assert(Inputs.size() == 1 && "Unexpected number of inputs.");
const InputInfo &Input = Inputs[0];
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
const std::string &TripleStr = Triple.getTriple();
const auto &D = getToolChain().getDriver();
// Don't warn about "clang -w -c foo.s"
Args.ClaimAllArgs(options::OPT_w);
// and "clang -emit-llvm -c foo.s"
Args.ClaimAllArgs(options::OPT_emit_llvm);
claimNoWarnArgs(Args);
// Invoke ourselves in -cc1as mode.
//
// FIXME: Implement custom jobs for internal actions.
CmdArgs.push_back("-cc1as");
// Add the "effective" target triple.
CmdArgs.push_back("-triple");
CmdArgs.push_back(Args.MakeArgString(TripleStr));
// Set the output mode, we currently only expect to be used as a real
// assembler.
CmdArgs.push_back("-filetype");
CmdArgs.push_back("obj");
// Set the main file name, so that debug info works even with
// -save-temps or preprocessed assembly.
CmdArgs.push_back("-main-file-name");
CmdArgs.push_back(Clang::getBaseInputName(Args, Input));
// Add the target cpu
std::string CPU = getCPUName(Args, Triple, /*FromAs*/ true);
if (!CPU.empty()) {
CmdArgs.push_back("-target-cpu");
CmdArgs.push_back(Args.MakeArgString(CPU));
}
// Add the target features
getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, true);
// Ignore explicit -force_cpusubtype_ALL option.
(void)Args.hasArg(options::OPT_force__cpusubtype__ALL);
// Pass along any -I options so we get proper .include search paths.
Args.AddAllArgs(CmdArgs, options::OPT_I_Group);
// Determine the original source input.
const Action *SourceAction = &JA;
while (SourceAction->getKind() != Action::InputClass) {
assert(!SourceAction->getInputs().empty() && "unexpected root action!");
SourceAction = SourceAction->getInputs()[0];
}
// Forward -g and handle debug info related flags, assuming we are dealing
// with an actual assembly file.
bool WantDebug = false;
unsigned DwarfVersion = 0;
Args.ClaimAllArgs(options::OPT_g_Group);
if (Arg *A = Args.getLastArg(options::OPT_g_Group)) {
WantDebug = !A->getOption().matches(options::OPT_g0) &&
!A->getOption().matches(options::OPT_ggdb0);
if (WantDebug)
DwarfVersion = DwarfVersionNum(A->getSpelling());
}
if (DwarfVersion == 0)
DwarfVersion = getToolChain().GetDefaultDwarfVersion();
codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo;
if (SourceAction->getType() == types::TY_Asm ||
SourceAction->getType() == types::TY_PP_Asm) {
// You might think that it would be ok to set DebugInfoKind outside of
// the guard for source type, however there is a test which asserts
// that some assembler invocation receives no -debug-info-kind,
// and it's not clear whether that test is just overly restrictive.
DebugInfoKind = (WantDebug ? codegenoptions::LimitedDebugInfo
: codegenoptions::NoDebugInfo);
// Add the -fdebug-compilation-dir flag if needed.
addDebugCompDirArg(Args, CmdArgs);
addDebugPrefixMapArg(getToolChain().getDriver(), Args, CmdArgs);
// Set the AT_producer to the clang version when using the integrated
// assembler on assembly source files.
CmdArgs.push_back("-dwarf-debug-producer");
CmdArgs.push_back(Args.MakeArgString(getClangFullVersion()));
// And pass along -I options
Args.AddAllArgs(CmdArgs, options::OPT_I);
}
RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion,
llvm::DebuggerKind::Default);
RenderDebugInfoCompressionArgs(Args, CmdArgs, D, getToolChain());
// Handle -fPIC et al -- the relocation-model affects the assembler
// for some targets.
llvm::Reloc::Model RelocationModel;
unsigned PICLevel;
bool IsPIE;
std::tie(RelocationModel, PICLevel, IsPIE) =
ParsePICArgs(getToolChain(), Args);
const char *RMName = RelocationModelName(RelocationModel);
if (RMName) {
CmdArgs.push_back("-mrelocation-model");
CmdArgs.push_back(RMName);
}
// Optionally embed the -cc1as level arguments into the debug info, for build
// analysis.
if (getToolChain().UseDwarfDebugFlags()) {
ArgStringList OriginalArgs;
for (const auto &Arg : Args)
Arg->render(Args, OriginalArgs);
SmallString<256> Flags;
const char *Exec = getToolChain().getDriver().getClangProgramPath();
Flags += Exec;
for (const char *OriginalArg : OriginalArgs) {
SmallString<128> EscapedArg;
EscapeSpacesAndBackslashes(OriginalArg, EscapedArg);
Flags += " ";
Flags += EscapedArg;
}
CmdArgs.push_back("-dwarf-debug-flags");
CmdArgs.push_back(Args.MakeArgString(Flags));
}
// FIXME: Add -static support, once we have it.
// Add target specific flags.
switch (getToolChain().getArch()) {
default:
break;
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
AddMIPSTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::x86:
case llvm::Triple::x86_64:
AddX86TargetArgs(Args, CmdArgs);
break;
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
// This isn't in AddARMTargetArgs because we want to do this for assembly
// only, not C/C++.
if (Args.hasFlag(options::OPT_mdefault_build_attributes,
options::OPT_mno_default_build_attributes, true)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-arm-add-build-attributes");
}
break;
}
// Consume all the warning flags. Usually this would be handled more
// gracefully by -cc1 (warning about unknown warning flags, etc) but -cc1as
// doesn't handle that so rather than warning about unused flags that are
// actually used, we'll lie by omission instead.
// FIXME: Stop lying and consume only the appropriate driver flags
Args.ClaimAllArgs(options::OPT_W_Group);
CollectArgsForIntegratedAssembler(C, Args, CmdArgs,
getToolChain().getDriver());
Args.AddAllArgs(CmdArgs, options::OPT_mllvm);
assert(Output.isFilename() && "Unexpected lipo output.");
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
const llvm::Triple &T = getToolChain().getTriple();
Arg *A;
if ((getDebugFissionKind(D, Args, A) == DwarfFissionKind::Split) &&
(T.isOSLinux() || T.isOSFuchsia())) {
CmdArgs.push_back("-split-dwarf-file");
CmdArgs.push_back(SplitDebugName(Args, Output));
}
assert(Input.isFilename() && "Invalid input.");
CmdArgs.push_back(Input.getFilename());
const char *Exec = getToolChain().getDriver().getClangProgramPath();
C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
// Begin OffloadBundler
void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const {
// The version with only one output is expected to refer to a bundling job.
assert(isa<OffloadBundlingJobAction>(JA) && "Expecting bundling job!");
// The bundling command looks like this:
// clang-offload-bundler -type=bc
// -targets=host-triple,openmp-triple1,openmp-triple2
// -outputs=input_file
// -inputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2"
ArgStringList CmdArgs;
// Get the type.
CmdArgs.push_back(TCArgs.MakeArgString(
Twine("-type=") + types::getTypeTempSuffix(Output.getType())));
assert(JA.getInputs().size() == Inputs.size() &&
"Not have inputs for all dependence actions??");
// Get the targets.
SmallString<128> Triples;
Triples += "-targets=";
for (unsigned I = 0; I < Inputs.size(); ++I) {
if (I)
Triples += ',';
// Find ToolChain for this input.
Action::OffloadKind CurKind = Action::OFK_Host;
const ToolChain *CurTC = &getToolChain();
const Action *CurDep = JA.getInputs()[I];
if (const auto *OA = dyn_cast<OffloadAction>(CurDep)) {
CurTC = nullptr;
OA->doOnEachDependence([&](Action *A, const ToolChain *TC, const char *) {
assert(CurTC == nullptr && "Expected one dependence!");
CurKind = A->getOffloadingDeviceKind();
CurTC = TC;
});
}
Triples += Action::GetOffloadKindName(CurKind);
Triples += '-';
Triples += CurTC->getTriple().normalize();
if (CurKind == Action::OFK_HIP && CurDep->getOffloadingArch()) {
Triples += '-';
Triples += CurDep->getOffloadingArch();
}
}
CmdArgs.push_back(TCArgs.MakeArgString(Triples));
// Get bundled file command.
CmdArgs.push_back(
TCArgs.MakeArgString(Twine("-outputs=") + Output.getFilename()));
// Get unbundled files command.
SmallString<128> UB;
UB += "-inputs=";
for (unsigned I = 0; I < Inputs.size(); ++I) {
if (I)
UB += ',';
// Find ToolChain for this input.
const ToolChain *CurTC = &getToolChain();
if (const auto *OA = dyn_cast<OffloadAction>(JA.getInputs()[I])) {
CurTC = nullptr;
OA->doOnEachDependence([&](Action *, const ToolChain *TC, const char *) {
assert(CurTC == nullptr && "Expected one dependence!");
CurTC = TC;
});
}
UB += CurTC->getInputFilename(Inputs[I]);
}
CmdArgs.push_back(TCArgs.MakeArgString(UB));
// All the inputs are encoded as commands.
C.addCommand(llvm::make_unique<Command>(
JA, *this,
TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
CmdArgs, None));
}
void OffloadBundler::ConstructJobMultipleOutputs(
Compilation &C, const JobAction &JA, const InputInfoList &Outputs,
const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const {
// The version with multiple outputs is expected to refer to a unbundling job.
auto &UA = cast<OffloadUnbundlingJobAction>(JA);
// The unbundling command looks like this:
// clang-offload-bundler -type=bc
// -targets=host-triple,openmp-triple1,openmp-triple2
// -inputs=input_file
// -outputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2"
// -unbundle
ArgStringList CmdArgs;
assert(Inputs.size() == 1 && "Expecting to unbundle a single file!");
InputInfo Input = Inputs.front();
// Get the type.
CmdArgs.push_back(TCArgs.MakeArgString(
Twine("-type=") + types::getTypeTempSuffix(Input.getType())));
// Get the targets.
SmallString<128> Triples;
Triples += "-targets=";
auto DepInfo = UA.getDependentActionsInfo();
for (unsigned I = 0; I < DepInfo.size(); ++I) {
if (I)
Triples += ',';
auto &Dep = DepInfo[I];
Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind);
Triples += '-';
Triples += Dep.DependentToolChain->getTriple().normalize();
if (Dep.DependentOffloadKind == Action::OFK_HIP &&
!Dep.DependentBoundArch.empty()) {
Triples += '-';
Triples += Dep.DependentBoundArch;
}
}
CmdArgs.push_back(TCArgs.MakeArgString(Triples));
// Get bundled file command.
CmdArgs.push_back(
TCArgs.MakeArgString(Twine("-inputs=") + Input.getFilename()));
// Get unbundled files command.
SmallString<128> UB;
UB += "-outputs=";
for (unsigned I = 0; I < Outputs.size(); ++I) {
if (I)
UB += ',';
UB += DepInfo[I].DependentToolChain->getInputFilename(Outputs[I]);
}
CmdArgs.push_back(TCArgs.MakeArgString(UB));
CmdArgs.push_back("-unbundle");
// All the inputs are encoded as commands.
C.addCommand(llvm::make_unique<Command>(
JA, *this,
TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
CmdArgs, None));
}
Index: stable/11/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.cpp
===================================================================
--- stable/11/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.cpp (revision 350259)
@@ -1,1034 +1,1039 @@
//===--- Linux.h - Linux ToolChain Implementations --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Linux.h"
#include "Arch/ARM.h"
#include "Arch/Mips.h"
#include "Arch/PPC.h"
#include "Arch/RISCV.h"
#include "CommonArgs.h"
#include "clang/Config/config.h"
#include "clang/Driver/Distro.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Option/ArgList.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <system_error>
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;
using tools::addPathIfExists;
/// Get our best guess at the multiarch triple for a target.
///
/// Debian-based systems are starting to use a multiarch setup where they use
/// a target-triple directory in the library and header search paths.
/// Unfortunately, this triple does not align with the vanilla target triple,
/// so we provide a rough mapping here.
static std::string getMultiarchTriple(const Driver &D,
const llvm::Triple &TargetTriple,
StringRef SysRoot) {
llvm::Triple::EnvironmentType TargetEnvironment =
TargetTriple.getEnvironment();
bool IsAndroid = TargetTriple.isAndroid();
bool IsMipsR6 = TargetTriple.getSubArch() == llvm::Triple::MipsSubArch_r6;
+ bool IsMipsN32Abi = TargetTriple.getEnvironment() == llvm::Triple::GNUABIN32;
// For most architectures, just use whatever we have rather than trying to be
// clever.
switch (TargetTriple.getArch()) {
default:
break;
// We use the existence of '/lib/<triple>' as a directory to detect some
// common linux triples that don't quite match the Clang triple for both
// 32-bit and 64-bit targets. Multiarch fixes its install triples to these
// regardless of what the actual target triple is.
case llvm::Triple::arm:
case llvm::Triple::thumb:
if (IsAndroid) {
return "arm-linux-androideabi";
} else if (TargetEnvironment == llvm::Triple::GNUEABIHF) {
if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabihf"))
return "arm-linux-gnueabihf";
} else {
if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabi"))
return "arm-linux-gnueabi";
}
break;
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
if (TargetEnvironment == llvm::Triple::GNUEABIHF) {
if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabihf"))
return "armeb-linux-gnueabihf";
} else {
if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabi"))
return "armeb-linux-gnueabi";
}
break;
case llvm::Triple::x86:
if (IsAndroid)
return "i686-linux-android";
if (D.getVFS().exists(SysRoot + "/lib/i386-linux-gnu"))
return "i386-linux-gnu";
break;
case llvm::Triple::x86_64:
if (IsAndroid)
return "x86_64-linux-android";
// We don't want this for x32, otherwise it will match x86_64 libs
if (TargetEnvironment != llvm::Triple::GNUX32 &&
D.getVFS().exists(SysRoot + "/lib/x86_64-linux-gnu"))
return "x86_64-linux-gnu";
break;
case llvm::Triple::aarch64:
if (IsAndroid)
return "aarch64-linux-android";
if (D.getVFS().exists(SysRoot + "/lib/aarch64-linux-gnu"))
return "aarch64-linux-gnu";
break;
case llvm::Triple::aarch64_be:
if (D.getVFS().exists(SysRoot + "/lib/aarch64_be-linux-gnu"))
return "aarch64_be-linux-gnu";
break;
case llvm::Triple::mips: {
- std::string Arch = IsMipsR6 ? "mipsisa32r6" : "mips";
- if (D.getVFS().exists(SysRoot + "/lib/" + Arch + "-linux-gnu"))
- return Arch + "-linux-gnu";
+ std::string MT = IsMipsR6 ? "mipsisa32r6-linux-gnu" : "mips-linux-gnu";
+ if (D.getVFS().exists(SysRoot + "/lib/" + MT))
+ return MT;
break;
}
case llvm::Triple::mipsel: {
if (IsAndroid)
return "mipsel-linux-android";
- std::string Arch = IsMipsR6 ? "mipsisa32r6el" : "mipsel";
- if (D.getVFS().exists(SysRoot + "/lib/" + Arch + "-linux-gnu"))
- return Arch + "-linux-gnu";
+ std::string MT = IsMipsR6 ? "mipsisa32r6el-linux-gnu" : "mipsel-linux-gnu";
+ if (D.getVFS().exists(SysRoot + "/lib/" + MT))
+ return MT;
break;
}
case llvm::Triple::mips64: {
- std::string Arch = IsMipsR6 ? "mipsisa64r6" : "mips64";
- std::string ABI = llvm::Triple::getEnvironmentTypeName(TargetEnvironment);
- if (D.getVFS().exists(SysRoot + "/lib/" + Arch + "-linux-" + ABI))
- return Arch + "-linux-" + ABI;
+ std::string MT = std::string(IsMipsR6 ? "mipsisa64r6" : "mips64") +
+ "-linux-" + (IsMipsN32Abi ? "gnuabin32" : "gnuabi64");
+ if (D.getVFS().exists(SysRoot + "/lib/" + MT))
+ return MT;
+ if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu"))
+ return "mips64-linux-gnu";
break;
}
case llvm::Triple::mips64el: {
if (IsAndroid)
return "mips64el-linux-android";
- std::string Arch = IsMipsR6 ? "mipsisa64r6el" : "mips64el";
- std::string ABI = llvm::Triple::getEnvironmentTypeName(TargetEnvironment);
- if (D.getVFS().exists(SysRoot + "/lib/" + Arch + "-linux-" + ABI))
- return Arch + "-linux-" + ABI;
+ std::string MT = std::string(IsMipsR6 ? "mipsisa64r6el" : "mips64el") +
+ "-linux-" + (IsMipsN32Abi ? "gnuabin32" : "gnuabi64");
+ if (D.getVFS().exists(SysRoot + "/lib/" + MT))
+ return MT;
+ if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu"))
+ return "mips64el-linux-gnu";
break;
}
case llvm::Triple::ppc:
if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe"))
return "powerpc-linux-gnuspe";
if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnu"))
return "powerpc-linux-gnu";
break;
case llvm::Triple::ppc64:
if (D.getVFS().exists(SysRoot + "/lib/powerpc64-linux-gnu"))
return "powerpc64-linux-gnu";
break;
case llvm::Triple::ppc64le:
if (D.getVFS().exists(SysRoot + "/lib/powerpc64le-linux-gnu"))
return "powerpc64le-linux-gnu";
break;
case llvm::Triple::sparc:
if (D.getVFS().exists(SysRoot + "/lib/sparc-linux-gnu"))
return "sparc-linux-gnu";
break;
case llvm::Triple::sparcv9:
if (D.getVFS().exists(SysRoot + "/lib/sparc64-linux-gnu"))
return "sparc64-linux-gnu";
break;
case llvm::Triple::systemz:
if (D.getVFS().exists(SysRoot + "/lib/s390x-linux-gnu"))
return "s390x-linux-gnu";
break;
}
return TargetTriple.str();
}
static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) {
if (Triple.isMIPS()) {
if (Triple.isAndroid()) {
StringRef CPUName;
StringRef ABIName;
tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
if (CPUName == "mips32r6")
return "libr6";
if (CPUName == "mips32r2")
return "libr2";
}
// lib32 directory has a special meaning on MIPS targets.
// It contains N32 ABI binaries. Use this folder if produce
// code for N32 ABI only.
if (tools::mips::hasMipsAbiArg(Args, "n32"))
return "lib32";
return Triple.isArch32Bit() ? "lib" : "lib64";
}
// It happens that only x86 and PPC use the 'lib32' variant of oslibdir, and
// using that variant while targeting other architectures causes problems
// because the libraries are laid out in shared system roots that can't cope
// with a 'lib32' library search path being considered. So we only enable
// them when we know we may need it.
//
// FIXME: This is a bit of a hack. We should really unify this code for
// reasoning about oslibdir spellings with the lib dir spellings in the
// GCCInstallationDetector, but that is a more significant refactoring.
if (Triple.getArch() == llvm::Triple::x86 ||
Triple.getArch() == llvm::Triple::ppc)
return "lib32";
if (Triple.getArch() == llvm::Triple::x86_64 &&
Triple.getEnvironment() == llvm::Triple::GNUX32)
return "libx32";
if (Triple.getArch() == llvm::Triple::riscv32)
return "lib32";
return Triple.isArch32Bit() ? "lib" : "lib64";
}
static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,
const Multilib &Multilib,
StringRef InstallPath,
ToolChain::path_list &Paths) {
if (const auto &PathsCallback = Multilibs.filePathsCallback())
for (const auto &Path : PathsCallback(Multilib))
addPathIfExists(D, InstallPath + Path, Paths);
}
Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
GCCInstallation.init(Triple, Args);
Multilibs = GCCInstallation.getMultilibs();
SelectedMultilib = GCCInstallation.getMultilib();
llvm::Triple::ArchType Arch = Triple.getArch();
std::string SysRoot = computeSysRoot();
// Cross-compiling binutils and GCC installations (vanilla and openSUSE at
// least) put various tools in a triple-prefixed directory off of the parent
// of the GCC installation. We use the GCC triple here to ensure that we end
// up with tools that support the same amount of cross compiling as the
// detected GCC installation. For example, if we find a GCC installation
// targeting x86_64, but it is a bi-arch GCC installation, it can also be
// used to target i386.
// FIXME: This seems unlikely to be Linux-specific.
ToolChain::path_list &PPaths = getProgramPaths();
PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
GCCInstallation.getTriple().str() + "/bin")
.str());
Distro Distro(D.getVFS());
if (Distro.IsAlpineLinux() || Triple.isAndroid()) {
ExtraOpts.push_back("-z");
ExtraOpts.push_back("now");
}
if (Distro.IsOpenSUSE() || Distro.IsUbuntu() || Distro.IsAlpineLinux() ||
Triple.isAndroid()) {
ExtraOpts.push_back("-z");
ExtraOpts.push_back("relro");
}
// The lld default page size is too large for Aarch64, which produces much
// larger .so files and images for arm64 device targets. Use 4KB page size
// for Android arm64 targets instead.
if (Triple.isAArch64() && Triple.isAndroid()) {
ExtraOpts.push_back("-z");
ExtraOpts.push_back("max-page-size=4096");
}
if (GCCInstallation.getParentLibPath().find("opt/rh/devtoolset") !=
StringRef::npos)
// With devtoolset on RHEL, we want to add a bin directory that is relative
// to the detected gcc install, because if we are using devtoolset gcc then
// we want to use other tools from devtoolset (e.g. ld) instead of the
// standard system tools.
PPaths.push_back(Twine(GCCInstallation.getParentLibPath() +
"/../bin").str());
if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
ExtraOpts.push_back("-X");
const bool IsAndroid = Triple.isAndroid();
const bool IsMips = Triple.isMIPS();
const bool IsHexagon = Arch == llvm::Triple::hexagon;
const bool IsRISCV =
Arch == llvm::Triple::riscv32 || Arch == llvm::Triple::riscv64;
if (IsMips && !SysRoot.empty())
ExtraOpts.push_back("--sysroot=" + SysRoot);
// Do not use 'gnu' hash style for Mips targets because .gnu.hash
// and the MIPS ABI require .dynsym to be sorted in different ways.
// .gnu.hash needs symbols to be grouped by hash code whereas the MIPS
// ABI requires a mapping between the GOT and the symbol table.
// Android loader does not support .gnu.hash until API 23.
// Hexagon linker/loader does not support .gnu.hash
if (!IsMips && !IsHexagon) {
if (Distro.IsRedhat() || Distro.IsOpenSUSE() || Distro.IsAlpineLinux() ||
(Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick) ||
(IsAndroid && !Triple.isAndroidVersionLT(23)))
ExtraOpts.push_back("--hash-style=gnu");
if (Distro.IsDebian() || Distro.IsOpenSUSE() ||
Distro == Distro::UbuntuLucid || Distro == Distro::UbuntuJaunty ||
Distro == Distro::UbuntuKarmic ||
(IsAndroid && Triple.isAndroidVersionLT(23)))
ExtraOpts.push_back("--hash-style=both");
}
if (Distro.IsRedhat() && Distro != Distro::RHEL5 && Distro != Distro::RHEL6)
ExtraOpts.push_back("--no-add-needed");
#ifdef ENABLE_LINKER_BUILD_ID
ExtraOpts.push_back("--build-id");
#endif
if (IsAndroid || Distro.IsOpenSUSE())
ExtraOpts.push_back("--enable-new-dtags");
// The selection of paths to try here is designed to match the patterns which
// the GCC driver itself uses, as this is part of the GCC-compatible driver.
// This was determined by running GCC in a fake filesystem, creating all
// possible permutations of these directories, and seeing which ones it added
// to the link paths.
path_list &Paths = getFilePaths();
const std::string OSLibDir = getOSLibDir(Triple, Args);
const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot);
// Add the multilib suffixed paths where they are available.
if (GCCInstallation.isValid()) {
const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
const std::string &LibPath = GCCInstallation.getParentLibPath();
// Add toolchain / multilib specific file paths.
addMultilibsFilePaths(D, Multilibs, SelectedMultilib,
GCCInstallation.getInstallPath(), Paths);
// Sourcery CodeBench MIPS toolchain holds some libraries under
// a biarch-like suffix of the GCC installation.
addPathIfExists(D, GCCInstallation.getInstallPath() + SelectedMultilib.gccSuffix(),
Paths);
// GCC cross compiling toolchains will install target libraries which ship
// as part of the toolchain under <prefix>/<triple>/<libdir> rather than as
// any part of the GCC installation in
// <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat
// debatable, but is the reality today. We need to search this tree even
// when we have a sysroot somewhere else. It is the responsibility of
// whomever is doing the cross build targeting a sysroot using a GCC
// installation that is *not* within the system root to ensure two things:
//
// 1) Any DSOs that are linked in from this tree or from the install path
// above must be present on the system root and found via an
// appropriate rpath.
// 2) There must not be libraries installed into
// <prefix>/<triple>/<libdir> unless they should be preferred over
// those within the system root.
//
// Note that this matches the GCC behavior. See the below comment for where
// Clang diverges from GCC's behavior.
addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" +
OSLibDir + SelectedMultilib.osSuffix(),
Paths);
// If the GCC installation we found is inside of the sysroot, we want to
// prefer libraries installed in the parent prefix of the GCC installation.
// It is important to *not* use these paths when the GCC installation is
// outside of the system root as that can pick up unintended libraries.
// This usually happens when there is an external cross compiler on the
// host system, and a more minimal sysroot available that is the target of
// the cross. Note that GCC does include some of these directories in some
// configurations but this seems somewhere between questionable and simply
// a bug.
if (StringRef(LibPath).startswith(SysRoot)) {
addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths);
addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths);
}
}
// Similar to the logic for GCC above, if we currently running Clang inside
// of the requested system root, add its parent library paths to
// those searched.
// FIXME: It's not clear whether we should use the driver's installed
// directory ('Dir' below) or the ResourceDir.
if (StringRef(D.Dir).startswith(SysRoot)) {
addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths);
addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths);
}
addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths);
addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths);
if (IsAndroid) {
// Android sysroots contain a library directory for each supported OS
// version as well as some unversioned libraries in the usual multiarch
// directory.
unsigned Major;
unsigned Minor;
unsigned Micro;
Triple.getEnvironmentVersion(Major, Minor, Micro);
addPathIfExists(D,
SysRoot + "/usr/lib/" + MultiarchTriple + "/" +
llvm::to_string(Major),
Paths);
}
addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths);
// 64-bit OpenEmbedded sysroots may not have a /usr/lib dir. So they cannot
// find /usr/lib64 as it is referenced as /usr/lib/../lib64. So we handle
// this here.
if (Triple.getVendor() == llvm::Triple::OpenEmbedded &&
Triple.isArch64Bit())
addPathIfExists(D, SysRoot + "/usr/" + OSLibDir, Paths);
else
addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths);
if (IsRISCV) {
StringRef ABIName = tools::riscv::getRISCVABI(Args, Triple);
addPathIfExists(D, SysRoot + "/" + OSLibDir + "/" + ABIName, Paths);
addPathIfExists(D, SysRoot + "/usr/" + OSLibDir + "/" + ABIName, Paths);
}
// Try walking via the GCC triple path in case of biarch or multiarch GCC
// installations with strange symlinks.
if (GCCInstallation.isValid()) {
addPathIfExists(D,
SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() +
"/../../" + OSLibDir,
Paths);
// Add the 'other' biarch variant path
Multilib BiarchSibling;
if (GCCInstallation.getBiarchSibling(BiarchSibling)) {
addPathIfExists(D, GCCInstallation.getInstallPath() +
BiarchSibling.gccSuffix(),
Paths);
}
// See comments above on the multilib variant for details of why this is
// included even from outside the sysroot.
const std::string &LibPath = GCCInstallation.getParentLibPath();
const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
const Multilib &Multilib = GCCInstallation.getMultilib();
addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" +
Multilib.osSuffix(),
Paths);
// See comments above on the multilib variant for details of why this is
// only included from within the sysroot.
if (StringRef(LibPath).startswith(SysRoot))
addPathIfExists(D, LibPath, Paths);
}
// Similar to the logic for GCC above, if we are currently running Clang
// inside of the requested system root, add its parent library path to those
// searched.
// FIXME: It's not clear whether we should use the driver's installed
// directory ('Dir' below) or the ResourceDir.
if (StringRef(D.Dir).startswith(SysRoot))
addPathIfExists(D, D.Dir + "/../lib", Paths);
addPathIfExists(D, SysRoot + "/lib", Paths);
addPathIfExists(D, SysRoot + "/usr/lib", Paths);
}
ToolChain::CXXStdlibType Linux::GetDefaultCXXStdlibType() const {
if (getTriple().isAndroid())
return ToolChain::CST_Libcxx;
return ToolChain::CST_Libstdcxx;
}
bool Linux::HasNativeLLVMSupport() const { return true; }
Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); }
Tool *Linux::buildAssembler() const {
return new tools::gnutools::Assembler(*this);
}
std::string Linux::computeSysRoot() const {
if (!getDriver().SysRoot.empty())
return getDriver().SysRoot;
if (getTriple().isAndroid()) {
// Android toolchains typically include a sysroot at ../sysroot relative to
// the clang binary.
const StringRef ClangDir = getDriver().getInstalledDir();
std::string AndroidSysRootPath = (ClangDir + "/../sysroot").str();
if (getVFS().exists(AndroidSysRootPath))
return AndroidSysRootPath;
}
if (!GCCInstallation.isValid() || !getTriple().isMIPS())
return std::string();
// Standalone MIPS toolchains use different names for sysroot folder
// and put it into different places. Here we try to check some known
// variants.
const StringRef InstallDir = GCCInstallation.getInstallPath();
const StringRef TripleStr = GCCInstallation.getTriple().str();
const Multilib &Multilib = GCCInstallation.getMultilib();
std::string Path =
(InstallDir + "/../../../../" + TripleStr + "/libc" + Multilib.osSuffix())
.str();
if (getVFS().exists(Path))
return Path;
Path = (InstallDir + "/../../../../sysroot" + Multilib.osSuffix()).str();
if (getVFS().exists(Path))
return Path;
return std::string();
}
std::string Linux::getDynamicLinker(const ArgList &Args) const {
const llvm::Triple::ArchType Arch = getArch();
const llvm::Triple &Triple = getTriple();
const Distro Distro(getDriver().getVFS());
if (Triple.isAndroid())
return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker";
if (Triple.isMusl()) {
std::string ArchName;
bool IsArm = false;
switch (Arch) {
case llvm::Triple::arm:
case llvm::Triple::thumb:
ArchName = "arm";
IsArm = true;
break;
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
ArchName = "armeb";
IsArm = true;
break;
default:
ArchName = Triple.getArchName().str();
}
if (IsArm &&
(Triple.getEnvironment() == llvm::Triple::MuslEABIHF ||
tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard))
ArchName += "hf";
return "/lib/ld-musl-" + ArchName + ".so.1";
}
std::string LibDir;
std::string Loader;
switch (Arch) {
default:
llvm_unreachable("unsupported architecture");
case llvm::Triple::aarch64:
LibDir = "lib";
Loader = "ld-linux-aarch64.so.1";
break;
case llvm::Triple::aarch64_be:
LibDir = "lib";
Loader = "ld-linux-aarch64_be.so.1";
break;
case llvm::Triple::arm:
case llvm::Triple::thumb:
case llvm::Triple::armeb:
case llvm::Triple::thumbeb: {
const bool HF =
Triple.getEnvironment() == llvm::Triple::GNUEABIHF ||
tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard;
LibDir = "lib";
Loader = HF ? "ld-linux-armhf.so.3" : "ld-linux.so.3";
break;
}
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
case llvm::Triple::mips64el: {
bool IsNaN2008 = tools::mips::isNaN2008(Args, Triple);
LibDir = "lib" + tools::mips::getMipsABILibSuffix(Args, Triple);
if (tools::mips::isUCLibc(Args))
Loader = IsNaN2008 ? "ld-uClibc-mipsn8.so.0" : "ld-uClibc.so.0";
else if (!Triple.hasEnvironment() &&
Triple.getVendor() == llvm::Triple::VendorType::MipsTechnologies)
Loader =
Triple.isLittleEndian() ? "ld-musl-mipsel.so.1" : "ld-musl-mips.so.1";
else
Loader = IsNaN2008 ? "ld-linux-mipsn8.so.1" : "ld.so.1";
break;
}
case llvm::Triple::ppc:
LibDir = "lib";
Loader = "ld.so.1";
break;
case llvm::Triple::ppc64:
LibDir = "lib64";
Loader =
(tools::ppc::hasPPCAbiArg(Args, "elfv2")) ? "ld64.so.2" : "ld64.so.1";
break;
case llvm::Triple::ppc64le:
LibDir = "lib64";
Loader =
(tools::ppc::hasPPCAbiArg(Args, "elfv1")) ? "ld64.so.1" : "ld64.so.2";
break;
case llvm::Triple::riscv32: {
StringRef ABIName = tools::riscv::getRISCVABI(Args, Triple);
LibDir = "lib";
Loader = ("ld-linux-riscv32-" + ABIName + ".so.1").str();
break;
}
case llvm::Triple::riscv64: {
StringRef ABIName = tools::riscv::getRISCVABI(Args, Triple);
LibDir = "lib";
Loader = ("ld-linux-riscv64-" + ABIName + ".so.1").str();
break;
}
case llvm::Triple::sparc:
case llvm::Triple::sparcel:
LibDir = "lib";
Loader = "ld-linux.so.2";
break;
case llvm::Triple::sparcv9:
LibDir = "lib64";
Loader = "ld-linux.so.2";
break;
case llvm::Triple::systemz:
LibDir = "lib";
Loader = "ld64.so.1";
break;
case llvm::Triple::x86:
LibDir = "lib";
Loader = "ld-linux.so.2";
break;
case llvm::Triple::x86_64: {
bool X32 = Triple.getEnvironment() == llvm::Triple::GNUX32;
LibDir = X32 ? "libx32" : "lib64";
Loader = X32 ? "ld-linux-x32.so.2" : "ld-linux-x86-64.so.2";
break;
}
}
if (Distro == Distro::Exherbo && (Triple.getVendor() == llvm::Triple::UnknownVendor ||
Triple.getVendor() == llvm::Triple::PC))
return "/usr/" + Triple.str() + "/lib/" + Loader;
return "/" + LibDir + "/" + Loader;
}
void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
const Driver &D = getDriver();
std::string SysRoot = computeSysRoot();
if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
return;
if (!DriverArgs.hasArg(options::OPT_nostdlibinc))
addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
SmallString<128> P(D.ResourceDir);
llvm::sys::path::append(P, "include");
addSystemInclude(DriverArgs, CC1Args, P);
}
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
// Check for configure-time C include directories.
StringRef CIncludeDirs(C_INCLUDE_DIRS);
if (CIncludeDirs != "") {
SmallVector<StringRef, 5> dirs;
CIncludeDirs.split(dirs, ":");
for (StringRef dir : dirs) {
StringRef Prefix =
llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : "";
addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
}
return;
}
// Lacking those, try to detect the correct set of system includes for the
// target triple.
// Add include directories specific to the selected multilib set and multilib.
if (GCCInstallation.isValid()) {
const auto &Callback = Multilibs.includeDirsCallback();
if (Callback) {
for (const auto &Path : Callback(GCCInstallation.getMultilib()))
addExternCSystemIncludeIfExists(
DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path);
}
}
// Implement generic Debian multiarch support.
const StringRef X86_64MultiarchIncludeDirs[] = {
"/usr/include/x86_64-linux-gnu",
// FIXME: These are older forms of multiarch. It's not clear that they're
// in use in any released version of Debian, so we should consider
// removing them.
"/usr/include/i686-linux-gnu/64", "/usr/include/i486-linux-gnu/64"};
const StringRef X86MultiarchIncludeDirs[] = {
"/usr/include/i386-linux-gnu",
// FIXME: These are older forms of multiarch. It's not clear that they're
// in use in any released version of Debian, so we should consider
// removing them.
"/usr/include/x86_64-linux-gnu/32", "/usr/include/i686-linux-gnu",
"/usr/include/i486-linux-gnu"};
const StringRef AArch64MultiarchIncludeDirs[] = {
"/usr/include/aarch64-linux-gnu"};
const StringRef ARMMultiarchIncludeDirs[] = {
"/usr/include/arm-linux-gnueabi"};
const StringRef ARMHFMultiarchIncludeDirs[] = {
"/usr/include/arm-linux-gnueabihf"};
const StringRef ARMEBMultiarchIncludeDirs[] = {
"/usr/include/armeb-linux-gnueabi"};
const StringRef ARMEBHFMultiarchIncludeDirs[] = {
"/usr/include/armeb-linux-gnueabihf"};
const StringRef MIPSMultiarchIncludeDirs[] = {"/usr/include/mips-linux-gnu"};
const StringRef MIPSELMultiarchIncludeDirs[] = {
"/usr/include/mipsel-linux-gnu"};
const StringRef MIPS64MultiarchIncludeDirs[] = {
"/usr/include/mips64-linux-gnuabi64"};
const StringRef MIPS64ELMultiarchIncludeDirs[] = {
"/usr/include/mips64el-linux-gnuabi64"};
const StringRef MIPSN32MultiarchIncludeDirs[] = {
"/usr/include/mips64-linux-gnuabin32"};
const StringRef MIPSN32ELMultiarchIncludeDirs[] = {
"/usr/include/mips64el-linux-gnuabin32"};
const StringRef MIPSR6MultiarchIncludeDirs[] = {
"/usr/include/mipsisa32-linux-gnu"};
const StringRef MIPSR6ELMultiarchIncludeDirs[] = {
"/usr/include/mipsisa32r6el-linux-gnu"};
const StringRef MIPS64R6MultiarchIncludeDirs[] = {
"/usr/include/mipsisa64r6-linux-gnuabi64"};
const StringRef MIPS64R6ELMultiarchIncludeDirs[] = {
"/usr/include/mipsisa64r6el-linux-gnuabi64"};
const StringRef MIPSN32R6MultiarchIncludeDirs[] = {
"/usr/include/mipsisa64r6-linux-gnuabin32"};
const StringRef MIPSN32R6ELMultiarchIncludeDirs[] = {
"/usr/include/mipsisa64r6el-linux-gnuabin32"};
const StringRef PPCMultiarchIncludeDirs[] = {
"/usr/include/powerpc-linux-gnu",
"/usr/include/powerpc-linux-gnuspe"};
const StringRef PPC64MultiarchIncludeDirs[] = {
"/usr/include/powerpc64-linux-gnu"};
const StringRef PPC64LEMultiarchIncludeDirs[] = {
"/usr/include/powerpc64le-linux-gnu"};
const StringRef SparcMultiarchIncludeDirs[] = {
"/usr/include/sparc-linux-gnu"};
const StringRef Sparc64MultiarchIncludeDirs[] = {
"/usr/include/sparc64-linux-gnu"};
const StringRef SYSTEMZMultiarchIncludeDirs[] = {
"/usr/include/s390x-linux-gnu"};
ArrayRef<StringRef> MultiarchIncludeDirs;
switch (getTriple().getArch()) {
case llvm::Triple::x86_64:
MultiarchIncludeDirs = X86_64MultiarchIncludeDirs;
break;
case llvm::Triple::x86:
MultiarchIncludeDirs = X86MultiarchIncludeDirs;
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
MultiarchIncludeDirs = AArch64MultiarchIncludeDirs;
break;
case llvm::Triple::arm:
case llvm::Triple::thumb:
if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs;
else
MultiarchIncludeDirs = ARMMultiarchIncludeDirs;
break;
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
MultiarchIncludeDirs = ARMEBHFMultiarchIncludeDirs;
else
MultiarchIncludeDirs = ARMEBMultiarchIncludeDirs;
break;
case llvm::Triple::mips:
if (getTriple().getSubArch() == llvm::Triple::MipsSubArch_r6)
MultiarchIncludeDirs = MIPSR6MultiarchIncludeDirs;
else
MultiarchIncludeDirs = MIPSMultiarchIncludeDirs;
break;
case llvm::Triple::mipsel:
if (getTriple().getSubArch() == llvm::Triple::MipsSubArch_r6)
MultiarchIncludeDirs = MIPSR6ELMultiarchIncludeDirs;
else
MultiarchIncludeDirs = MIPSELMultiarchIncludeDirs;
break;
case llvm::Triple::mips64:
if (getTriple().getSubArch() == llvm::Triple::MipsSubArch_r6)
if (getTriple().getEnvironment() == llvm::Triple::GNUABIN32)
MultiarchIncludeDirs = MIPSN32R6MultiarchIncludeDirs;
else
MultiarchIncludeDirs = MIPS64R6MultiarchIncludeDirs;
else if (getTriple().getEnvironment() == llvm::Triple::GNUABIN32)
MultiarchIncludeDirs = MIPSN32MultiarchIncludeDirs;
else
MultiarchIncludeDirs = MIPS64MultiarchIncludeDirs;
break;
case llvm::Triple::mips64el:
if (getTriple().getSubArch() == llvm::Triple::MipsSubArch_r6)
if (getTriple().getEnvironment() == llvm::Triple::GNUABIN32)
MultiarchIncludeDirs = MIPSN32R6ELMultiarchIncludeDirs;
else
MultiarchIncludeDirs = MIPS64R6ELMultiarchIncludeDirs;
else if (getTriple().getEnvironment() == llvm::Triple::GNUABIN32)
MultiarchIncludeDirs = MIPSN32ELMultiarchIncludeDirs;
else
MultiarchIncludeDirs = MIPS64ELMultiarchIncludeDirs;
break;
case llvm::Triple::ppc:
MultiarchIncludeDirs = PPCMultiarchIncludeDirs;
break;
case llvm::Triple::ppc64:
MultiarchIncludeDirs = PPC64MultiarchIncludeDirs;
break;
case llvm::Triple::ppc64le:
MultiarchIncludeDirs = PPC64LEMultiarchIncludeDirs;
break;
case llvm::Triple::sparc:
MultiarchIncludeDirs = SparcMultiarchIncludeDirs;
break;
case llvm::Triple::sparcv9:
MultiarchIncludeDirs = Sparc64MultiarchIncludeDirs;
break;
case llvm::Triple::systemz:
MultiarchIncludeDirs = SYSTEMZMultiarchIncludeDirs;
break;
default:
break;
}
const std::string AndroidMultiarchIncludeDir =
std::string("/usr/include/") +
getMultiarchTriple(D, getTriple(), SysRoot);
const StringRef AndroidMultiarchIncludeDirs[] = {AndroidMultiarchIncludeDir};
if (getTriple().isAndroid())
MultiarchIncludeDirs = AndroidMultiarchIncludeDirs;
for (StringRef Dir : MultiarchIncludeDirs) {
if (D.getVFS().exists(SysRoot + Dir)) {
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + Dir);
break;
}
}
if (getTriple().getOS() == llvm::Triple::RTEMS)
return;
// Add an include of '/include' directly. This isn't provided by default by
// system GCCs, but is often used with cross-compiling GCCs, and harmless to
// add even when Clang is acting as-if it were a system compiler.
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
}
static std::string DetectLibcxxIncludePath(StringRef base) {
std::error_code EC;
int MaxVersion = 0;
std::string MaxVersionString = "";
for (llvm::sys::fs::directory_iterator LI(base, EC), LE; !EC && LI != LE;
LI = LI.increment(EC)) {
StringRef VersionText = llvm::sys::path::filename(LI->path());
int Version;
if (VersionText[0] == 'v' &&
!VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) {
if (Version > MaxVersion) {
MaxVersion = Version;
MaxVersionString = VersionText;
}
}
}
return MaxVersion ? (base + "/" + MaxVersionString).str() : "";
}
void Linux::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
const std::string& SysRoot = computeSysRoot();
const std::string LibCXXIncludePathCandidates[] = {
DetectLibcxxIncludePath(getDriver().ResourceDir + "/include/c++"),
DetectLibcxxIncludePath(getDriver().Dir + "/../include/c++"),
// If this is a development, non-installed, clang, libcxx will
// not be found at ../include/c++ but it likely to be found at
// one of the following two locations:
DetectLibcxxIncludePath(SysRoot + "/usr/local/include/c++"),
DetectLibcxxIncludePath(SysRoot + "/usr/include/c++") };
for (const auto &IncludePath : LibCXXIncludePathCandidates) {
if (IncludePath.empty() || !getVFS().exists(IncludePath))
continue;
// Use the first candidate that exists.
addSystemInclude(DriverArgs, CC1Args, IncludePath);
return;
}
}
void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
// We need a detected GCC installation on Linux to provide libstdc++'s
// headers.
if (!GCCInstallation.isValid())
return;
// By default, look for the C++ headers in an include directory adjacent to
// the lib directory of the GCC installation. Note that this is expect to be
// equivalent to '/usr/include/c++/X.Y' in almost all cases.
StringRef LibDir = GCCInstallation.getParentLibPath();
StringRef InstallDir = GCCInstallation.getInstallPath();
StringRef TripleStr = GCCInstallation.getTriple().str();
const Multilib &Multilib = GCCInstallation.getMultilib();
const std::string GCCMultiarchTriple = getMultiarchTriple(
getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot);
const std::string TargetMultiarchTriple =
getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot);
const GCCVersion &Version = GCCInstallation.getVersion();
// The primary search for libstdc++ supports multiarch variants.
if (addLibStdCXXIncludePaths(LibDir.str() + "/../include",
"/c++/" + Version.Text, TripleStr,
GCCMultiarchTriple, TargetMultiarchTriple,
Multilib.includeSuffix(), DriverArgs, CC1Args))
return;
// Otherwise, fall back on a bunch of options which don't use multiarch
// layouts for simplicity.
const std::string LibStdCXXIncludePathCandidates[] = {
// Gentoo is weird and places its headers inside the GCC install,
// so if the first attempt to find the headers fails, try these patterns.
InstallDir.str() + "/include/g++-v" + Version.Text,
InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." +
Version.MinorStr,
InstallDir.str() + "/include/g++-v" + Version.MajorStr,
// Android standalone toolchain has C++ headers in yet another place.
LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
// Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++,
// without a subdirectory corresponding to the gcc version.
LibDir.str() + "/../include/c++",
// Cray's gcc installation puts headers under "g++" without a
// version suffix.
LibDir.str() + "/../include/g++",
};
for (const auto &IncludePath : LibStdCXXIncludePathCandidates) {
if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr,
/*GCCMultiarchTriple*/ "",
/*TargetMultiarchTriple*/ "",
Multilib.includeSuffix(), DriverArgs, CC1Args))
break;
}
}
void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
}
void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (GCCInstallation.isValid()) {
CC1Args.push_back("-isystem");
CC1Args.push_back(DriverArgs.MakeArgString(
GCCInstallation.getParentLibPath() + "/../" +
GCCInstallation.getTriple().str() + "/include"));
}
}
bool Linux::isPIEDefault() const {
return (getTriple().isAndroid() && !getTriple().isAndroidVersionLT(16)) ||
getTriple().isMusl() || getSanitizerArgs().requiresPIE();
}
bool Linux::IsMathErrnoDefault() const {
if (getTriple().isAndroid())
return false;
return Generic_ELF::IsMathErrnoDefault();
}
SanitizerMask Linux::getSupportedSanitizers() const {
const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
const bool IsMIPS = getTriple().isMIPS32();
const bool IsMIPS64 = getTriple().isMIPS64();
const bool IsPowerPC64 = getTriple().getArch() == llvm::Triple::ppc64 ||
getTriple().getArch() == llvm::Triple::ppc64le;
const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 ||
getTriple().getArch() == llvm::Triple::aarch64_be;
const bool IsArmArch = getTriple().getArch() == llvm::Triple::arm ||
getTriple().getArch() == llvm::Triple::thumb ||
getTriple().getArch() == llvm::Triple::armeb ||
getTriple().getArch() == llvm::Triple::thumbeb;
SanitizerMask Res = ToolChain::getSupportedSanitizers();
Res |= SanitizerKind::Address;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
Res |= SanitizerKind::KernelAddress;
Res |= SanitizerKind::Memory;
Res |= SanitizerKind::Vptr;
Res |= SanitizerKind::SafeStack;
if (IsX86_64 || IsMIPS64 || IsAArch64)
Res |= SanitizerKind::DataFlow;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64)
Res |= SanitizerKind::Leak;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64)
Res |= SanitizerKind::Thread;
if (IsX86_64)
Res |= SanitizerKind::KernelMemory;
if (IsX86_64 || IsMIPS64)
Res |= SanitizerKind::Efficiency;
if (IsX86 || IsX86_64)
Res |= SanitizerKind::Function;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch ||
IsPowerPC64)
Res |= SanitizerKind::Scudo;
if (IsX86_64 || IsAArch64) {
Res |= SanitizerKind::HWAddress;
Res |= SanitizerKind::KernelHWAddress;
}
return Res;
}
void Linux::addProfileRTLibs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const {
if (!needsProfileRT(Args)) return;
// Add linker option -u__llvm_runtime_variable to cause runtime
// initialization module to be linked in.
if ((!Args.hasArg(options::OPT_coverage)) && (!Args.hasArg(options::OPT_ftest_coverage)))
CmdArgs.push_back(Args.MakeArgString(
Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
ToolChain::addProfileRTLibs(Args, CmdArgs);
}
Index: stable/11/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp
===================================================================
--- stable/11/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp (revision 350259)
@@ -1,13932 +1,13931 @@
//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements semantic analysis for OpenMP directives and
/// clauses.
///
//===----------------------------------------------------------------------===//
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/PointerEmbeddedInt.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// Stack of data-sharing attributes for variables
//===----------------------------------------------------------------------===//
static const Expr *checkMapClauseExpressionBase(
Sema &SemaRef, Expr *E,
OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents,
OpenMPClauseKind CKind, bool NoDiagnose);
namespace {
/// Default data sharing attributes, which can be applied to directive.
enum DefaultDataSharingAttributes {
DSA_unspecified = 0, /// Data sharing attribute not specified.
DSA_none = 1 << 0, /// Default data sharing attribute 'none'.
DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'.
};
/// Attributes of the defaultmap clause.
enum DefaultMapAttributes {
DMA_unspecified, /// Default mapping is not specified.
DMA_tofrom_scalar, /// Default mapping is 'tofrom:scalar'.
};
/// Stack for tracking declarations used in OpenMP directives and
/// clauses and their data-sharing attributes.
class DSAStackTy {
public:
struct DSAVarData {
OpenMPDirectiveKind DKind = OMPD_unknown;
OpenMPClauseKind CKind = OMPC_unknown;
const Expr *RefExpr = nullptr;
DeclRefExpr *PrivateCopy = nullptr;
SourceLocation ImplicitDSALoc;
DSAVarData() = default;
DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind,
const Expr *RefExpr, DeclRefExpr *PrivateCopy,
SourceLocation ImplicitDSALoc)
: DKind(DKind), CKind(CKind), RefExpr(RefExpr),
PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc) {}
};
using OperatorOffsetTy =
llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>;
using DoacrossDependMapTy =
llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>;
private:
struct DSAInfo {
OpenMPClauseKind Attributes = OMPC_unknown;
/// Pointer to a reference expression and a flag which shows that the
/// variable is marked as lastprivate(true) or not (false).
llvm::PointerIntPair<const Expr *, 1, bool> RefExpr;
DeclRefExpr *PrivateCopy = nullptr;
};
using DeclSAMapTy = llvm::SmallDenseMap<const ValueDecl *, DSAInfo, 8>;
using AlignedMapTy = llvm::SmallDenseMap<const ValueDecl *, const Expr *, 8>;
using LCDeclInfo = std::pair<unsigned, VarDecl *>;
using LoopControlVariablesMapTy =
llvm::SmallDenseMap<const ValueDecl *, LCDeclInfo, 8>;
/// Struct that associates a component with the clause kind where they are
/// found.
struct MappedExprComponentTy {
OMPClauseMappableExprCommon::MappableExprComponentLists Components;
OpenMPClauseKind Kind = OMPC_unknown;
};
using MappedExprComponentsTy =
llvm::DenseMap<const ValueDecl *, MappedExprComponentTy>;
using CriticalsWithHintsTy =
llvm::StringMap<std::pair<const OMPCriticalDirective *, llvm::APSInt>>;
struct ReductionData {
using BOKPtrType = llvm::PointerEmbeddedInt<BinaryOperatorKind, 16>;
SourceRange ReductionRange;
llvm::PointerUnion<const Expr *, BOKPtrType> ReductionOp;
ReductionData() = default;
void set(BinaryOperatorKind BO, SourceRange RR) {
ReductionRange = RR;
ReductionOp = BO;
}
void set(const Expr *RefExpr, SourceRange RR) {
ReductionRange = RR;
ReductionOp = RefExpr;
}
};
using DeclReductionMapTy =
llvm::SmallDenseMap<const ValueDecl *, ReductionData, 4>;
struct SharingMapTy {
DeclSAMapTy SharingMap;
DeclReductionMapTy ReductionMap;
AlignedMapTy AlignedMap;
MappedExprComponentsTy MappedExprComponents;
LoopControlVariablesMapTy LCVMap;
DefaultDataSharingAttributes DefaultAttr = DSA_unspecified;
SourceLocation DefaultAttrLoc;
DefaultMapAttributes DefaultMapAttr = DMA_unspecified;
SourceLocation DefaultMapAttrLoc;
OpenMPDirectiveKind Directive = OMPD_unknown;
DeclarationNameInfo DirectiveName;
Scope *CurScope = nullptr;
SourceLocation ConstructLoc;
/// Set of 'depend' clauses with 'sink|source' dependence kind. Required to
/// get the data (loop counters etc.) about enclosing loop-based construct.
/// This data is required during codegen.
DoacrossDependMapTy DoacrossDepends;
/// first argument (Expr *) contains optional argument of the
/// 'ordered' clause, the second one is true if the regions has 'ordered'
/// clause, false otherwise.
llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion;
unsigned AssociatedLoops = 1;
const Decl *PossiblyLoopCounter = nullptr;
bool NowaitRegion = false;
bool CancelRegion = false;
bool LoopStart = false;
SourceLocation InnerTeamsRegionLoc;
/// Reference to the taskgroup task_reduction reference expression.
Expr *TaskgroupReductionRef = nullptr;
llvm::DenseSet<QualType> MappedClassesQualTypes;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
: Directive(DKind), DirectiveName(Name), CurScope(CurScope),
ConstructLoc(Loc) {}
SharingMapTy() = default;
};
using StackTy = SmallVector<SharingMapTy, 4>;
/// Stack of used declaration and their data-sharing attributes.
DeclSAMapTy Threadprivates;
const FunctionScopeInfo *CurrentNonCapturingFunctionScope = nullptr;
SmallVector<std::pair<StackTy, const FunctionScopeInfo *>, 4> Stack;
/// true, if check for DSA must be from parent directive, false, if
/// from current directive.
OpenMPClauseKind ClauseKindMode = OMPC_unknown;
Sema &SemaRef;
bool ForceCapturing = false;
/// true if all the vaiables in the target executable directives must be
/// captured by reference.
bool ForceCaptureByReferenceInTargetExecutable = false;
CriticalsWithHintsTy Criticals;
using iterator = StackTy::const_reverse_iterator;
DSAVarData getDSA(iterator &Iter, ValueDecl *D) const;
/// Checks if the variable is a local for OpenMP region.
bool isOpenMPLocal(VarDecl *D, iterator Iter) const;
bool isStackEmpty() const {
return Stack.empty() ||
Stack.back().second != CurrentNonCapturingFunctionScope ||
Stack.back().first.empty();
}
/// Vector of previously declared requires directives
SmallVector<const OMPRequiresDecl *, 2> RequiresDecls;
public:
explicit DSAStackTy(Sema &S) : SemaRef(S) {}
bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; }
OpenMPClauseKind getClauseParsingMode() const {
assert(isClauseParsingMode() && "Must be in clause parsing mode.");
return ClauseKindMode;
}
void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; }
bool isForceVarCapturing() const { return ForceCapturing; }
void setForceVarCapturing(bool V) { ForceCapturing = V; }
void setForceCaptureByReferenceInTargetExecutable(bool V) {
ForceCaptureByReferenceInTargetExecutable = V;
}
bool isForceCaptureByReferenceInTargetExecutable() const {
return ForceCaptureByReferenceInTargetExecutable;
}
void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName,
Scope *CurScope, SourceLocation Loc) {
if (Stack.empty() ||
Stack.back().second != CurrentNonCapturingFunctionScope)
Stack.emplace_back(StackTy(), CurrentNonCapturingFunctionScope);
Stack.back().first.emplace_back(DKind, DirName, CurScope, Loc);
Stack.back().first.back().DefaultAttrLoc = Loc;
}
void pop() {
assert(!Stack.back().first.empty() &&
"Data-sharing attributes stack is empty!");
Stack.back().first.pop_back();
}
/// Marks that we're started loop parsing.
void loopInit() {
assert(isOpenMPLoopDirective(getCurrentDirective()) &&
"Expected loop-based directive.");
Stack.back().first.back().LoopStart = true;
}
/// Start capturing of the variables in the loop context.
void loopStart() {
assert(isOpenMPLoopDirective(getCurrentDirective()) &&
"Expected loop-based directive.");
Stack.back().first.back().LoopStart = false;
}
/// true, if variables are captured, false otherwise.
bool isLoopStarted() const {
assert(isOpenMPLoopDirective(getCurrentDirective()) &&
"Expected loop-based directive.");
return !Stack.back().first.back().LoopStart;
}
/// Marks (or clears) declaration as possibly loop counter.
void resetPossibleLoopCounter(const Decl *D = nullptr) {
Stack.back().first.back().PossiblyLoopCounter =
D ? D->getCanonicalDecl() : D;
}
/// Gets the possible loop counter decl.
const Decl *getPossiblyLoopCunter() const {
return Stack.back().first.back().PossiblyLoopCounter;
}
/// Start new OpenMP region stack in new non-capturing function.
void pushFunction() {
const FunctionScopeInfo *CurFnScope = SemaRef.getCurFunction();
assert(!isa<CapturingScopeInfo>(CurFnScope));
CurrentNonCapturingFunctionScope = CurFnScope;
}
/// Pop region stack for non-capturing function.
void popFunction(const FunctionScopeInfo *OldFSI) {
if (!Stack.empty() && Stack.back().second == OldFSI) {
assert(Stack.back().first.empty());
Stack.pop_back();
}
CurrentNonCapturingFunctionScope = nullptr;
for (const FunctionScopeInfo *FSI : llvm::reverse(SemaRef.FunctionScopes)) {
if (!isa<CapturingScopeInfo>(FSI)) {
CurrentNonCapturingFunctionScope = FSI;
break;
}
}
}
void addCriticalWithHint(const OMPCriticalDirective *D, llvm::APSInt Hint) {
Criticals.try_emplace(D->getDirectiveName().getAsString(), D, Hint);
}
const std::pair<const OMPCriticalDirective *, llvm::APSInt>
getCriticalWithHint(const DeclarationNameInfo &Name) const {
auto I = Criticals.find(Name.getAsString());
if (I != Criticals.end())
return I->second;
return std::make_pair(nullptr, llvm::APSInt());
}
/// If 'aligned' declaration for given variable \a D was not seen yet,
/// add it and return NULL; otherwise return previous occurrence's expression
/// for diagnostics.
const Expr *addUniqueAligned(const ValueDecl *D, const Expr *NewDE);
/// Register specified variable as loop control variable.
void addLoopControlVariable(const ValueDecl *D, VarDecl *Capture);
/// Check if the specified variable is a loop control variable for
/// current region.
/// \return The index of the loop control variable in the list of associated
/// for-loops (from outer to inner).
const LCDeclInfo isLoopControlVariable(const ValueDecl *D) const;
/// Check if the specified variable is a loop control variable for
/// parent region.
/// \return The index of the loop control variable in the list of associated
/// for-loops (from outer to inner).
const LCDeclInfo isParentLoopControlVariable(const ValueDecl *D) const;
/// Get the loop control variable for the I-th loop (or nullptr) in
/// parent directive.
const ValueDecl *getParentLoopControlVariable(unsigned I) const;
/// Adds explicit data sharing attribute to the specified declaration.
void addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
DeclRefExpr *PrivateCopy = nullptr);
/// Adds additional information for the reduction items with the reduction id
/// represented as an operator.
void addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
BinaryOperatorKind BOK);
/// Adds additional information for the reduction items with the reduction id
/// represented as reduction identifier.
void addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
const Expr *ReductionRef);
/// Returns the location and reduction operation from the innermost parent
/// region for the given \p D.
const DSAVarData
getTopMostTaskgroupReductionData(const ValueDecl *D, SourceRange &SR,
BinaryOperatorKind &BOK,
Expr *&TaskgroupDescriptor) const;
/// Returns the location and reduction operation from the innermost parent
/// region for the given \p D.
const DSAVarData
getTopMostTaskgroupReductionData(const ValueDecl *D, SourceRange &SR,
const Expr *&ReductionRef,
Expr *&TaskgroupDescriptor) const;
/// Return reduction reference expression for the current taskgroup.
Expr *getTaskgroupReductionRef() const {
assert(Stack.back().first.back().Directive == OMPD_taskgroup &&
"taskgroup reference expression requested for non taskgroup "
"directive.");
return Stack.back().first.back().TaskgroupReductionRef;
}
/// Checks if the given \p VD declaration is actually a taskgroup reduction
/// descriptor variable at the \p Level of OpenMP regions.
bool isTaskgroupReductionRef(const ValueDecl *VD, unsigned Level) const {
return Stack.back().first[Level].TaskgroupReductionRef &&
cast<DeclRefExpr>(Stack.back().first[Level].TaskgroupReductionRef)
->getDecl() == VD;
}
/// Returns data sharing attributes from top of the stack for the
/// specified declaration.
const DSAVarData getTopDSA(ValueDecl *D, bool FromParent);
/// Returns data-sharing attributes for the specified declaration.
const DSAVarData getImplicitDSA(ValueDecl *D, bool FromParent) const;
/// Checks if the specified variables has data-sharing attributes which
/// match specified \a CPred predicate in any directive which matches \a DPred
/// predicate.
const DSAVarData
hasDSA(ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> CPred,
const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
bool FromParent) const;
/// Checks if the specified variables has data-sharing attributes which
/// match specified \a CPred predicate in any innermost directive which
/// matches \a DPred predicate.
const DSAVarData
hasInnermostDSA(ValueDecl *D,
const llvm::function_ref<bool(OpenMPClauseKind)> CPred,
const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
bool FromParent) const;
/// Checks if the specified variables has explicit data-sharing
/// attributes which match specified \a CPred predicate at the specified
/// OpenMP region.
bool hasExplicitDSA(const ValueDecl *D,
const llvm::function_ref<bool(OpenMPClauseKind)> CPred,
unsigned Level, bool NotLastprivate = false) const;
/// Returns true if the directive at level \Level matches in the
/// specified \a DPred predicate.
bool hasExplicitDirective(
const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
unsigned Level) const;
/// Finds a directive which matches specified \a DPred predicate.
bool hasDirective(
const llvm::function_ref<bool(
OpenMPDirectiveKind, const DeclarationNameInfo &, SourceLocation)>
DPred,
bool FromParent) const;
/// Returns currently analyzed directive.
OpenMPDirectiveKind getCurrentDirective() const {
return isStackEmpty() ? OMPD_unknown : Stack.back().first.back().Directive;
}
/// Returns directive kind at specified level.
OpenMPDirectiveKind getDirective(unsigned Level) const {
assert(!isStackEmpty() && "No directive at specified level.");
return Stack.back().first[Level].Directive;
}
/// Returns parent directive.
OpenMPDirectiveKind getParentDirective() const {
if (isStackEmpty() || Stack.back().first.size() == 1)
return OMPD_unknown;
return std::next(Stack.back().first.rbegin())->Directive;
}
/// Add requires decl to internal vector
void addRequiresDecl(OMPRequiresDecl *RD) {
RequiresDecls.push_back(RD);
}
/// Checks for a duplicate clause amongst previously declared requires
/// directives
bool hasDuplicateRequiresClause(ArrayRef<OMPClause *> ClauseList) const {
bool IsDuplicate = false;
for (OMPClause *CNew : ClauseList) {
for (const OMPRequiresDecl *D : RequiresDecls) {
for (const OMPClause *CPrev : D->clauselists()) {
if (CNew->getClauseKind() == CPrev->getClauseKind()) {
SemaRef.Diag(CNew->getBeginLoc(),
diag::err_omp_requires_clause_redeclaration)
<< getOpenMPClauseName(CNew->getClauseKind());
SemaRef.Diag(CPrev->getBeginLoc(),
diag::note_omp_requires_previous_clause)
<< getOpenMPClauseName(CPrev->getClauseKind());
IsDuplicate = true;
}
}
}
}
return IsDuplicate;
}
/// Set default data sharing attribute to none.
void setDefaultDSANone(SourceLocation Loc) {
assert(!isStackEmpty());
Stack.back().first.back().DefaultAttr = DSA_none;
Stack.back().first.back().DefaultAttrLoc = Loc;
}
/// Set default data sharing attribute to shared.
void setDefaultDSAShared(SourceLocation Loc) {
assert(!isStackEmpty());
Stack.back().first.back().DefaultAttr = DSA_shared;
Stack.back().first.back().DefaultAttrLoc = Loc;
}
/// Set default data mapping attribute to 'tofrom:scalar'.
void setDefaultDMAToFromScalar(SourceLocation Loc) {
assert(!isStackEmpty());
Stack.back().first.back().DefaultMapAttr = DMA_tofrom_scalar;
Stack.back().first.back().DefaultMapAttrLoc = Loc;
}
DefaultDataSharingAttributes getDefaultDSA() const {
return isStackEmpty() ? DSA_unspecified
: Stack.back().first.back().DefaultAttr;
}
SourceLocation getDefaultDSALocation() const {
return isStackEmpty() ? SourceLocation()
: Stack.back().first.back().DefaultAttrLoc;
}
DefaultMapAttributes getDefaultDMA() const {
return isStackEmpty() ? DMA_unspecified
: Stack.back().first.back().DefaultMapAttr;
}
DefaultMapAttributes getDefaultDMAAtLevel(unsigned Level) const {
return Stack.back().first[Level].DefaultMapAttr;
}
SourceLocation getDefaultDMALocation() const {
return isStackEmpty() ? SourceLocation()
: Stack.back().first.back().DefaultMapAttrLoc;
}
/// Checks if the specified variable is a threadprivate.
bool isThreadPrivate(VarDecl *D) {
const DSAVarData DVar = getTopDSA(D, false);
return isOpenMPThreadPrivate(DVar.CKind);
}
/// Marks current region as ordered (it has an 'ordered' clause).
void setOrderedRegion(bool IsOrdered, const Expr *Param,
OMPOrderedClause *Clause) {
assert(!isStackEmpty());
if (IsOrdered)
Stack.back().first.back().OrderedRegion.emplace(Param, Clause);
else
Stack.back().first.back().OrderedRegion.reset();
}
/// Returns true, if region is ordered (has associated 'ordered' clause),
/// false - otherwise.
bool isOrderedRegion() const {
if (isStackEmpty())
return false;
return Stack.back().first.rbegin()->OrderedRegion.hasValue();
}
/// Returns optional parameter for the ordered region.
std::pair<const Expr *, OMPOrderedClause *> getOrderedRegionParam() const {
if (isStackEmpty() ||
!Stack.back().first.rbegin()->OrderedRegion.hasValue())
return std::make_pair(nullptr, nullptr);
return Stack.back().first.rbegin()->OrderedRegion.getValue();
}
/// Returns true, if parent region is ordered (has associated
/// 'ordered' clause), false - otherwise.
bool isParentOrderedRegion() const {
if (isStackEmpty() || Stack.back().first.size() == 1)
return false;
return std::next(Stack.back().first.rbegin())->OrderedRegion.hasValue();
}
/// Returns optional parameter for the ordered region.
std::pair<const Expr *, OMPOrderedClause *>
getParentOrderedRegionParam() const {
if (isStackEmpty() || Stack.back().first.size() == 1 ||
!std::next(Stack.back().first.rbegin())->OrderedRegion.hasValue())
return std::make_pair(nullptr, nullptr);
return std::next(Stack.back().first.rbegin())->OrderedRegion.getValue();
}
/// Marks current region as nowait (it has a 'nowait' clause).
void setNowaitRegion(bool IsNowait = true) {
assert(!isStackEmpty());
Stack.back().first.back().NowaitRegion = IsNowait;
}
/// Returns true, if parent region is nowait (has associated
/// 'nowait' clause), false - otherwise.
bool isParentNowaitRegion() const {
if (isStackEmpty() || Stack.back().first.size() == 1)
return false;
return std::next(Stack.back().first.rbegin())->NowaitRegion;
}
/// Marks parent region as cancel region.
void setParentCancelRegion(bool Cancel = true) {
if (!isStackEmpty() && Stack.back().first.size() > 1) {
auto &StackElemRef = *std::next(Stack.back().first.rbegin());
StackElemRef.CancelRegion |= StackElemRef.CancelRegion || Cancel;
}
}
/// Return true if current region has inner cancel construct.
bool isCancelRegion() const {
return isStackEmpty() ? false : Stack.back().first.back().CancelRegion;
}
/// Set collapse value for the region.
void setAssociatedLoops(unsigned Val) {
assert(!isStackEmpty());
Stack.back().first.back().AssociatedLoops = Val;
}
/// Return collapse value for region.
unsigned getAssociatedLoops() const {
return isStackEmpty() ? 0 : Stack.back().first.back().AssociatedLoops;
}
/// Marks current target region as one with closely nested teams
/// region.
void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) {
if (!isStackEmpty() && Stack.back().first.size() > 1) {
std::next(Stack.back().first.rbegin())->InnerTeamsRegionLoc =
TeamsRegionLoc;
}
}
/// Returns true, if current region has closely nested teams region.
bool hasInnerTeamsRegion() const {
return getInnerTeamsRegionLoc().isValid();
}
/// Returns location of the nested teams region (if any).
SourceLocation getInnerTeamsRegionLoc() const {
return isStackEmpty() ? SourceLocation()
: Stack.back().first.back().InnerTeamsRegionLoc;
}
Scope *getCurScope() const {
return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope;
}
SourceLocation getConstructLoc() const {
return isStackEmpty() ? SourceLocation()
: Stack.back().first.back().ConstructLoc;
}
/// Do the check specified in \a Check to all component lists and return true
/// if any issue is found.
bool checkMappableExprComponentListsForDecl(
const ValueDecl *VD, bool CurrentRegionOnly,
const llvm::function_ref<
bool(OMPClauseMappableExprCommon::MappableExprComponentListRef,
OpenMPClauseKind)>
Check) const {
if (isStackEmpty())
return false;
auto SI = Stack.back().first.rbegin();
auto SE = Stack.back().first.rend();
if (SI == SE)
return false;
if (CurrentRegionOnly)
SE = std::next(SI);
else
std::advance(SI, 1);
for (; SI != SE; ++SI) {
auto MI = SI->MappedExprComponents.find(VD);
if (MI != SI->MappedExprComponents.end())
for (OMPClauseMappableExprCommon::MappableExprComponentListRef L :
MI->second.Components)
if (Check(L, MI->second.Kind))
return true;
}
return false;
}
/// Do the check specified in \a Check to all component lists at a given level
/// and return true if any issue is found.
bool checkMappableExprComponentListsForDeclAtLevel(
const ValueDecl *VD, unsigned Level,
const llvm::function_ref<
bool(OMPClauseMappableExprCommon::MappableExprComponentListRef,
OpenMPClauseKind)>
Check) const {
if (isStackEmpty())
return false;
auto StartI = Stack.back().first.begin();
auto EndI = Stack.back().first.end();
if (std::distance(StartI, EndI) <= (int)Level)
return false;
std::advance(StartI, Level);
auto MI = StartI->MappedExprComponents.find(VD);
if (MI != StartI->MappedExprComponents.end())
for (OMPClauseMappableExprCommon::MappableExprComponentListRef L :
MI->second.Components)
if (Check(L, MI->second.Kind))
return true;
return false;
}
/// Create a new mappable expression component list associated with a given
/// declaration and initialize it with the provided list of components.
void addMappableExpressionComponents(
const ValueDecl *VD,
OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
OpenMPClauseKind WhereFoundClauseKind) {
assert(!isStackEmpty() &&
"Not expecting to retrieve components from a empty stack!");
MappedExprComponentTy &MEC =
Stack.back().first.back().MappedExprComponents[VD];
// Create new entry and append the new components there.
MEC.Components.resize(MEC.Components.size() + 1);
MEC.Components.back().append(Components.begin(), Components.end());
MEC.Kind = WhereFoundClauseKind;
}
unsigned getNestingLevel() const {
assert(!isStackEmpty());
return Stack.back().first.size() - 1;
}
void addDoacrossDependClause(OMPDependClause *C,
const OperatorOffsetTy &OpsOffs) {
assert(!isStackEmpty() && Stack.back().first.size() > 1);
SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin());
assert(isOpenMPWorksharingDirective(StackElem.Directive));
StackElem.DoacrossDepends.try_emplace(C, OpsOffs);
}
llvm::iterator_range<DoacrossDependMapTy::const_iterator>
getDoacrossDependClauses() const {
assert(!isStackEmpty());
const SharingMapTy &StackElem = Stack.back().first.back();
if (isOpenMPWorksharingDirective(StackElem.Directive)) {
const DoacrossDependMapTy &Ref = StackElem.DoacrossDepends;
return llvm::make_range(Ref.begin(), Ref.end());
}
return llvm::make_range(StackElem.DoacrossDepends.end(),
StackElem.DoacrossDepends.end());
}
// Store types of classes which have been explicitly mapped
void addMappedClassesQualTypes(QualType QT) {
SharingMapTy &StackElem = Stack.back().first.back();
StackElem.MappedClassesQualTypes.insert(QT);
}
// Return set of mapped classes types
bool isClassPreviouslyMapped(QualType QT) const {
const SharingMapTy &StackElem = Stack.back().first.back();
return StackElem.MappedClassesQualTypes.count(QT) != 0;
}
};
bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) {
return isOpenMPParallelDirective(DKind) || isOpenMPTeamsDirective(DKind);
}
bool isImplicitOrExplicitTaskingRegion(OpenMPDirectiveKind DKind) {
return isImplicitTaskingRegion(DKind) || isOpenMPTaskingDirective(DKind) || DKind == OMPD_unknown;
}
} // namespace
static const Expr *getExprAsWritten(const Expr *E) {
if (const auto *FE = dyn_cast<FullExpr>(E))
E = FE->getSubExpr();
if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
E = MTE->GetTemporaryExpr();
while (const auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
E = Binder->getSubExpr();
if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E))
E = ICE->getSubExprAsWritten();
return E->IgnoreParens();
}
static Expr *getExprAsWritten(Expr *E) {
return const_cast<Expr *>(getExprAsWritten(const_cast<const Expr *>(E)));
}
static const ValueDecl *getCanonicalDecl(const ValueDecl *D) {
if (const auto *CED = dyn_cast<OMPCapturedExprDecl>(D))
if (const auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
D = ME->getMemberDecl();
const auto *VD = dyn_cast<VarDecl>(D);
const auto *FD = dyn_cast<FieldDecl>(D);
if (VD != nullptr) {
VD = VD->getCanonicalDecl();
D = VD;
} else {
assert(FD);
FD = FD->getCanonicalDecl();
D = FD;
}
return D;
}
static ValueDecl *getCanonicalDecl(ValueDecl *D) {
return const_cast<ValueDecl *>(
getCanonicalDecl(const_cast<const ValueDecl *>(D)));
}
DSAStackTy::DSAVarData DSAStackTy::getDSA(iterator &Iter,
ValueDecl *D) const {
D = getCanonicalDecl(D);
auto *VD = dyn_cast<VarDecl>(D);
const auto *FD = dyn_cast<FieldDecl>(D);
DSAVarData DVar;
if (isStackEmpty() || Iter == Stack.back().first.rend()) {
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a region but not in construct]
// File-scope or namespace-scope variables referenced in called routines
// in the region are shared unless they appear in a threadprivate
// directive.
if (VD && !VD->isFunctionOrMethodVarDecl() && !isa<ParmVarDecl>(VD))
DVar.CKind = OMPC_shared;
// OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced
// in a region but not in construct]
// Variables with static storage duration that are declared in called
// routines in the region are shared.
if (VD && VD->hasGlobalStorage())
DVar.CKind = OMPC_shared;
// Non-static data members are shared by default.
if (FD)
DVar.CKind = OMPC_shared;
return DVar;
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.1]
// Variables with automatic storage duration that are declared in a scope
// inside the construct are private.
if (VD && isOpenMPLocal(VD, Iter) && VD->isLocalVarDecl() &&
(VD->getStorageClass() == SC_Auto || VD->getStorageClass() == SC_None)) {
DVar.CKind = OMPC_private;
return DVar;
}
DVar.DKind = Iter->Directive;
// Explicitly specified attributes and local variables with predetermined
// attributes.
if (Iter->SharingMap.count(D)) {
const DSAInfo &Data = Iter->SharingMap.lookup(D);
DVar.RefExpr = Data.RefExpr.getPointer();
DVar.PrivateCopy = Data.PrivateCopy;
DVar.CKind = Data.Attributes;
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
return DVar;
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, implicitly determined, p.1]
// In a parallel or task construct, the data-sharing attributes of these
// variables are determined by the default clause, if present.
switch (Iter->DefaultAttr) {
case DSA_shared:
DVar.CKind = OMPC_shared;
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
return DVar;
case DSA_none:
return DVar;
case DSA_unspecified:
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, implicitly determined, p.2]
// In a parallel construct, if no default clause is present, these
// variables are shared.
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
if (isOpenMPParallelDirective(DVar.DKind) ||
isOpenMPTeamsDirective(DVar.DKind)) {
DVar.CKind = OMPC_shared;
return DVar;
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, implicitly determined, p.4]
// In a task construct, if no default clause is present, a variable that in
// the enclosing context is determined to be shared by all implicit tasks
// bound to the current team is shared.
if (isOpenMPTaskingDirective(DVar.DKind)) {
DSAVarData DVarTemp;
iterator I = Iter, E = Stack.back().first.rend();
do {
++I;
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables
// Referenced in a Construct, implicitly determined, p.6]
// In a task construct, if no default clause is present, a variable
// whose data-sharing attribute is not determined by the rules above is
// firstprivate.
DVarTemp = getDSA(I, D);
if (DVarTemp.CKind != OMPC_shared) {
DVar.RefExpr = nullptr;
DVar.CKind = OMPC_firstprivate;
return DVar;
}
} while (I != E && !isImplicitTaskingRegion(I->Directive));
DVar.CKind =
(DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared;
return DVar;
}
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, implicitly determined, p.3]
// For constructs other than task, if no default clause is present, these
// variables inherit their data-sharing attributes from the enclosing
// context.
return getDSA(++Iter, D);
}
const Expr *DSAStackTy::addUniqueAligned(const ValueDecl *D,
const Expr *NewDE) {
assert(!isStackEmpty() && "Data sharing attributes stack is empty");
D = getCanonicalDecl(D);
SharingMapTy &StackElem = Stack.back().first.back();
auto It = StackElem.AlignedMap.find(D);
if (It == StackElem.AlignedMap.end()) {
assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
StackElem.AlignedMap[D] = NewDE;
return nullptr;
}
assert(It->second && "Unexpected nullptr expr in the aligned map");
return It->second;
}
void DSAStackTy::addLoopControlVariable(const ValueDecl *D, VarDecl *Capture) {
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
SharingMapTy &StackElem = Stack.back().first.back();
StackElem.LCVMap.try_emplace(
D, LCDeclInfo(StackElem.LCVMap.size() + 1, Capture));
}
const DSAStackTy::LCDeclInfo
DSAStackTy::isLoopControlVariable(const ValueDecl *D) const {
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
const SharingMapTy &StackElem = Stack.back().first.back();
auto It = StackElem.LCVMap.find(D);
if (It != StackElem.LCVMap.end())
return It->second;
return {0, nullptr};
}
const DSAStackTy::LCDeclInfo
DSAStackTy::isParentLoopControlVariable(const ValueDecl *D) const {
assert(!isStackEmpty() && Stack.back().first.size() > 1 &&
"Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
const SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin());
auto It = StackElem.LCVMap.find(D);
if (It != StackElem.LCVMap.end())
return It->second;
return {0, nullptr};
}
const ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) const {
assert(!isStackEmpty() && Stack.back().first.size() > 1 &&
"Data-sharing attributes stack is empty");
const SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin());
if (StackElem.LCVMap.size() < I)
return nullptr;
for (const auto &Pair : StackElem.LCVMap)
if (Pair.second.first == I)
return Pair.first;
return nullptr;
}
void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
DeclRefExpr *PrivateCopy) {
D = getCanonicalDecl(D);
if (A == OMPC_threadprivate) {
DSAInfo &Data = Threadprivates[D];
Data.Attributes = A;
Data.RefExpr.setPointer(E);
Data.PrivateCopy = nullptr;
} else {
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
DSAInfo &Data = Stack.back().first.back().SharingMap[D];
assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) ||
(A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) ||
(A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) ||
(isLoopControlVariable(D).first && A == OMPC_private));
if (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) {
Data.RefExpr.setInt(/*IntVal=*/true);
return;
}
const bool IsLastprivate =
A == OMPC_lastprivate || Data.Attributes == OMPC_lastprivate;
Data.Attributes = A;
Data.RefExpr.setPointerAndInt(E, IsLastprivate);
Data.PrivateCopy = PrivateCopy;
if (PrivateCopy) {
DSAInfo &Data =
Stack.back().first.back().SharingMap[PrivateCopy->getDecl()];
Data.Attributes = A;
Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate);
Data.PrivateCopy = nullptr;
}
}
}
/// Build a variable declaration for OpenMP loop iteration variable.
static VarDecl *buildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type,
StringRef Name, const AttrVec *Attrs = nullptr,
DeclRefExpr *OrigRef = nullptr) {
DeclContext *DC = SemaRef.CurContext;
IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name);
TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc);
auto *Decl =
VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, TInfo, SC_None);
if (Attrs) {
for (specific_attr_iterator<AlignedAttr> I(Attrs->begin()), E(Attrs->end());
I != E; ++I)
Decl->addAttr(*I);
}
Decl->setImplicit();
if (OrigRef) {
Decl->addAttr(
OMPReferencedVarAttr::CreateImplicit(SemaRef.Context, OrigRef));
}
return Decl;
}
static DeclRefExpr *buildDeclRefExpr(Sema &S, VarDecl *D, QualType Ty,
SourceLocation Loc,
bool RefersToCapture = false) {
D->setReferenced();
D->markUsed(S.Context);
return DeclRefExpr::Create(S.getASTContext(), NestedNameSpecifierLoc(),
SourceLocation(), D, RefersToCapture, Loc, Ty,
VK_LValue);
}
void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
BinaryOperatorKind BOK) {
D = getCanonicalDecl(D);
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
assert(
Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction &&
"Additional reduction info may be specified only for reduction items.");
ReductionData &ReductionData = Stack.back().first.back().ReductionMap[D];
assert(ReductionData.ReductionRange.isInvalid() &&
Stack.back().first.back().Directive == OMPD_taskgroup &&
"Additional reduction info may be specified only once for reduction "
"items.");
ReductionData.set(BOK, SR);
Expr *&TaskgroupReductionRef =
Stack.back().first.back().TaskgroupReductionRef;
if (!TaskgroupReductionRef) {
VarDecl *VD = buildVarDecl(SemaRef, SR.getBegin(),
SemaRef.Context.VoidPtrTy, ".task_red.");
TaskgroupReductionRef =
buildDeclRefExpr(SemaRef, VD, SemaRef.Context.VoidPtrTy, SR.getBegin());
}
}
void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
const Expr *ReductionRef) {
D = getCanonicalDecl(D);
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
assert(
Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction &&
"Additional reduction info may be specified only for reduction items.");
ReductionData &ReductionData = Stack.back().first.back().ReductionMap[D];
assert(ReductionData.ReductionRange.isInvalid() &&
Stack.back().first.back().Directive == OMPD_taskgroup &&
"Additional reduction info may be specified only once for reduction "
"items.");
ReductionData.set(ReductionRef, SR);
Expr *&TaskgroupReductionRef =
Stack.back().first.back().TaskgroupReductionRef;
if (!TaskgroupReductionRef) {
VarDecl *VD = buildVarDecl(SemaRef, SR.getBegin(),
SemaRef.Context.VoidPtrTy, ".task_red.");
TaskgroupReductionRef =
buildDeclRefExpr(SemaRef, VD, SemaRef.Context.VoidPtrTy, SR.getBegin());
}
}
const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
const ValueDecl *D, SourceRange &SR, BinaryOperatorKind &BOK,
Expr *&TaskgroupDescriptor) const {
D = getCanonicalDecl(D);
assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
if (Stack.back().first.empty())
return DSAVarData();
for (iterator I = std::next(Stack.back().first.rbegin(), 1),
E = Stack.back().first.rend();
I != E; std::advance(I, 1)) {
const DSAInfo &Data = I->SharingMap.lookup(D);
if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup)
continue;
const ReductionData &ReductionData = I->ReductionMap.lookup(D);
if (!ReductionData.ReductionOp ||
ReductionData.ReductionOp.is<const Expr *>())
return DSAVarData();
SR = ReductionData.ReductionRange;
BOK = ReductionData.ReductionOp.get<ReductionData::BOKPtrType>();
assert(I->TaskgroupReductionRef && "taskgroup reduction reference "
"expression for the descriptor is not "
"set.");
TaskgroupDescriptor = I->TaskgroupReductionRef;
return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(),
Data.PrivateCopy, I->DefaultAttrLoc);
}
return DSAVarData();
}
const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
const ValueDecl *D, SourceRange &SR, const Expr *&ReductionRef,
Expr *&TaskgroupDescriptor) const {
D = getCanonicalDecl(D);
assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
if (Stack.back().first.empty())
return DSAVarData();
for (iterator I = std::next(Stack.back().first.rbegin(), 1),
E = Stack.back().first.rend();
I != E; std::advance(I, 1)) {
const DSAInfo &Data = I->SharingMap.lookup(D);
if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup)
continue;
const ReductionData &ReductionData = I->ReductionMap.lookup(D);
if (!ReductionData.ReductionOp ||
!ReductionData.ReductionOp.is<const Expr *>())
return DSAVarData();
SR = ReductionData.ReductionRange;
ReductionRef = ReductionData.ReductionOp.get<const Expr *>();
assert(I->TaskgroupReductionRef && "taskgroup reduction reference "
"expression for the descriptor is not "
"set.");
TaskgroupDescriptor = I->TaskgroupReductionRef;
return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(),
Data.PrivateCopy, I->DefaultAttrLoc);
}
return DSAVarData();
}
bool DSAStackTy::isOpenMPLocal(VarDecl *D, iterator Iter) const {
D = D->getCanonicalDecl();
if (!isStackEmpty()) {
iterator I = Iter, E = Stack.back().first.rend();
Scope *TopScope = nullptr;
while (I != E && !isImplicitOrExplicitTaskingRegion(I->Directive) &&
!isOpenMPTargetExecutionDirective(I->Directive))
++I;
if (I == E)
return false;
TopScope = I->CurScope ? I->CurScope->getParent() : nullptr;
Scope *CurScope = getCurScope();
while (CurScope != TopScope && !CurScope->isDeclScope(D))
CurScope = CurScope->getParent();
return CurScope != TopScope;
}
return false;
}
static bool isConstNotMutableType(Sema &SemaRef, QualType Type,
bool AcceptIfMutable = true,
bool *IsClassType = nullptr) {
ASTContext &Context = SemaRef.getASTContext();
Type = Type.getNonReferenceType().getCanonicalType();
bool IsConstant = Type.isConstant(Context);
Type = Context.getBaseElementType(Type);
const CXXRecordDecl *RD = AcceptIfMutable && SemaRef.getLangOpts().CPlusPlus
? Type->getAsCXXRecordDecl()
: nullptr;
if (const auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(RD))
if (const ClassTemplateDecl *CTD = CTSD->getSpecializedTemplate())
RD = CTD->getTemplatedDecl();
if (IsClassType)
*IsClassType = RD;
return IsConstant && !(SemaRef.getLangOpts().CPlusPlus && RD &&
RD->hasDefinition() && RD->hasMutableFields());
}
static bool rejectConstNotMutableType(Sema &SemaRef, const ValueDecl *D,
QualType Type, OpenMPClauseKind CKind,
SourceLocation ELoc,
bool AcceptIfMutable = true,
bool ListItemNotVar = false) {
ASTContext &Context = SemaRef.getASTContext();
bool IsClassType;
if (isConstNotMutableType(SemaRef, Type, AcceptIfMutable, &IsClassType)) {
unsigned Diag = ListItemNotVar
? diag::err_omp_const_list_item
: IsClassType ? diag::err_omp_const_not_mutable_variable
: diag::err_omp_const_variable;
SemaRef.Diag(ELoc, Diag) << getOpenMPClauseName(CKind);
if (!ListItemNotVar && D) {
const VarDecl *VD = dyn_cast<VarDecl>(D);
bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
SemaRef.Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
}
return true;
}
return false;
}
const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
bool FromParent) {
D = getCanonicalDecl(D);
DSAVarData DVar;
auto *VD = dyn_cast<VarDecl>(D);
auto TI = Threadprivates.find(D);
if (TI != Threadprivates.end()) {
DVar.RefExpr = TI->getSecond().RefExpr.getPointer();
DVar.CKind = OMPC_threadprivate;
return DVar;
}
if (VD && VD->hasAttr<OMPThreadPrivateDeclAttr>()) {
DVar.RefExpr = buildDeclRefExpr(
SemaRef, VD, D->getType().getNonReferenceType(),
VD->getAttr<OMPThreadPrivateDeclAttr>()->getLocation());
DVar.CKind = OMPC_threadprivate;
addDSA(D, DVar.RefExpr, OMPC_threadprivate);
return DVar;
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.1]
// Variables appearing in threadprivate directives are threadprivate.
if ((VD && VD->getTLSKind() != VarDecl::TLS_None &&
!(VD->hasAttr<OMPThreadPrivateDeclAttr>() &&
SemaRef.getLangOpts().OpenMPUseTLS &&
SemaRef.getASTContext().getTargetInfo().isTLSSupported())) ||
(VD && VD->getStorageClass() == SC_Register &&
VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())) {
DVar.RefExpr = buildDeclRefExpr(
SemaRef, VD, D->getType().getNonReferenceType(), D->getLocation());
DVar.CKind = OMPC_threadprivate;
addDSA(D, DVar.RefExpr, OMPC_threadprivate);
return DVar;
}
if (SemaRef.getLangOpts().OpenMPCUDAMode && VD &&
VD->isLocalVarDeclOrParm() && !isStackEmpty() &&
!isLoopControlVariable(D).first) {
iterator IterTarget =
std::find_if(Stack.back().first.rbegin(), Stack.back().first.rend(),
[](const SharingMapTy &Data) {
return isOpenMPTargetExecutionDirective(Data.Directive);
});
if (IterTarget != Stack.back().first.rend()) {
iterator ParentIterTarget = std::next(IterTarget, 1);
for (iterator Iter = Stack.back().first.rbegin();
Iter != ParentIterTarget; std::advance(Iter, 1)) {
if (isOpenMPLocal(VD, Iter)) {
DVar.RefExpr =
buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(),
D->getLocation());
DVar.CKind = OMPC_threadprivate;
return DVar;
}
}
if (!isClauseParsingMode() || IterTarget != Stack.back().first.rbegin()) {
auto DSAIter = IterTarget->SharingMap.find(D);
if (DSAIter != IterTarget->SharingMap.end() &&
isOpenMPPrivate(DSAIter->getSecond().Attributes)) {
DVar.RefExpr = DSAIter->getSecond().RefExpr.getPointer();
DVar.CKind = OMPC_threadprivate;
return DVar;
}
iterator End = Stack.back().first.rend();
if (!SemaRef.isOpenMPCapturedByRef(
D, std::distance(ParentIterTarget, End))) {
DVar.RefExpr =
buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(),
IterTarget->ConstructLoc);
DVar.CKind = OMPC_threadprivate;
return DVar;
}
}
}
}
if (isStackEmpty())
// Not in OpenMP execution region and top scope was already checked.
return DVar;
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.4]
// Static data members are shared.
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.7]
// Variables with static storage duration that are declared in a scope
// inside the construct are shared.
auto &&MatchesAlways = [](OpenMPDirectiveKind) { return true; };
if (VD && VD->isStaticDataMember()) {
DSAVarData DVarTemp = hasDSA(D, isOpenMPPrivate, MatchesAlways, FromParent);
if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr)
return DVar;
DVar.CKind = OMPC_shared;
return DVar;
}
// The predetermined shared attribute for const-qualified types having no
// mutable members was removed after OpenMP 3.1.
if (SemaRef.LangOpts.OpenMP <= 31) {
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.6]
// Variables with const qualified type having no mutable member are
// shared.
if (isConstNotMutableType(SemaRef, D->getType())) {
// Variables with const-qualified type having no mutable member may be
// listed in a firstprivate clause, even if they are static data members.
DSAVarData DVarTemp = hasInnermostDSA(
D,
[](OpenMPClauseKind C) {
return C == OMPC_firstprivate || C == OMPC_shared;
},
MatchesAlways, FromParent);
if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr)
return DVarTemp;
DVar.CKind = OMPC_shared;
return DVar;
}
}
// Explicitly specified attributes and local variables with predetermined
// attributes.
iterator I = Stack.back().first.rbegin();
iterator EndI = Stack.back().first.rend();
if (FromParent && I != EndI)
std::advance(I, 1);
auto It = I->SharingMap.find(D);
if (It != I->SharingMap.end()) {
const DSAInfo &Data = It->getSecond();
DVar.RefExpr = Data.RefExpr.getPointer();
DVar.PrivateCopy = Data.PrivateCopy;
DVar.CKind = Data.Attributes;
DVar.ImplicitDSALoc = I->DefaultAttrLoc;
DVar.DKind = I->Directive;
}
return DVar;
}
const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
bool FromParent) const {
if (isStackEmpty()) {
iterator I;
return getDSA(I, D);
}
D = getCanonicalDecl(D);
iterator StartI = Stack.back().first.rbegin();
iterator EndI = Stack.back().first.rend();
if (FromParent && StartI != EndI)
std::advance(StartI, 1);
return getDSA(StartI, D);
}
const DSAStackTy::DSAVarData
DSAStackTy::hasDSA(ValueDecl *D,
const llvm::function_ref<bool(OpenMPClauseKind)> CPred,
const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
bool FromParent) const {
if (isStackEmpty())
return {};
D = getCanonicalDecl(D);
iterator I = Stack.back().first.rbegin();
iterator EndI = Stack.back().first.rend();
if (FromParent && I != EndI)
std::advance(I, 1);
for (; I != EndI; std::advance(I, 1)) {
if (!DPred(I->Directive) && !isImplicitOrExplicitTaskingRegion(I->Directive))
continue;
iterator NewI = I;
DSAVarData DVar = getDSA(NewI, D);
if (I == NewI && CPred(DVar.CKind))
return DVar;
}
return {};
}
const DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(
ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> CPred,
const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
bool FromParent) const {
if (isStackEmpty())
return {};
D = getCanonicalDecl(D);
iterator StartI = Stack.back().first.rbegin();
iterator EndI = Stack.back().first.rend();
if (FromParent && StartI != EndI)
std::advance(StartI, 1);
if (StartI == EndI || !DPred(StartI->Directive))
return {};
iterator NewI = StartI;
DSAVarData DVar = getDSA(NewI, D);
return (NewI == StartI && CPred(DVar.CKind)) ? DVar : DSAVarData();
}
bool DSAStackTy::hasExplicitDSA(
const ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> CPred,
unsigned Level, bool NotLastprivate) const {
if (isStackEmpty())
return false;
D = getCanonicalDecl(D);
auto StartI = Stack.back().first.begin();
auto EndI = Stack.back().first.end();
if (std::distance(StartI, EndI) <= (int)Level)
return false;
std::advance(StartI, Level);
auto I = StartI->SharingMap.find(D);
if ((I != StartI->SharingMap.end()) &&
I->getSecond().RefExpr.getPointer() &&
CPred(I->getSecond().Attributes) &&
(!NotLastprivate || !I->getSecond().RefExpr.getInt()))
return true;
// Check predetermined rules for the loop control variables.
auto LI = StartI->LCVMap.find(D);
if (LI != StartI->LCVMap.end())
return CPred(OMPC_private);
return false;
}
bool DSAStackTy::hasExplicitDirective(
const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
unsigned Level) const {
if (isStackEmpty())
return false;
auto StartI = Stack.back().first.begin();
auto EndI = Stack.back().first.end();
if (std::distance(StartI, EndI) <= (int)Level)
return false;
std::advance(StartI, Level);
return DPred(StartI->Directive);
}
bool DSAStackTy::hasDirective(
const llvm::function_ref<bool(OpenMPDirectiveKind,
const DeclarationNameInfo &, SourceLocation)>
DPred,
bool FromParent) const {
// We look only in the enclosing region.
if (isStackEmpty())
return false;
auto StartI = std::next(Stack.back().first.rbegin());
auto EndI = Stack.back().first.rend();
if (FromParent && StartI != EndI)
StartI = std::next(StartI);
for (auto I = StartI, EE = EndI; I != EE; ++I) {
if (DPred(I->Directive, I->DirectiveName, I->ConstructLoc))
return true;
}
return false;
}
void Sema::InitDataSharingAttributesStack() {
VarDataSharingAttributesStack = new DSAStackTy(*this);
}
#define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack)
void Sema::pushOpenMPFunctionRegion() {
DSAStack->pushFunction();
}
void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) {
DSAStack->popFunction(OldFSI);
}
bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
ASTContext &Ctx = getASTContext();
bool IsByRef = true;
// Find the directive that is associated with the provided scope.
D = cast<ValueDecl>(D->getCanonicalDecl());
QualType Ty = D->getType();
if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) {
// This table summarizes how a given variable should be passed to the device
// given its type and the clauses where it appears. This table is based on
// the description in OpenMP 4.5 [2.10.4, target Construct] and
// OpenMP 4.5 [2.15.5, Data-mapping Attribute Rules and Clauses].
//
// =========================================================================
// | type | defaultmap | pvt | first | is_device_ptr | map | res. |
// | |(tofrom:scalar)| | pvt | | | |
// =========================================================================
// | scl | | | | - | | bycopy|
// | scl | | - | x | - | - | bycopy|
// | scl | | x | - | - | - | null |
// | scl | x | | | - | | byref |
// | scl | x | - | x | - | - | bycopy|
// | scl | x | x | - | - | - | null |
// | scl | | - | - | - | x | byref |
// | scl | x | - | - | - | x | byref |
//
// | agg | n.a. | | | - | | byref |
// | agg | n.a. | - | x | - | - | byref |
// | agg | n.a. | x | - | - | - | null |
// | agg | n.a. | - | - | - | x | byref |
// | agg | n.a. | - | - | - | x[] | byref |
//
// | ptr | n.a. | | | - | | bycopy|
// | ptr | n.a. | - | x | - | - | bycopy|
// | ptr | n.a. | x | - | - | - | null |
// | ptr | n.a. | - | - | - | x | byref |
// | ptr | n.a. | - | - | - | x[] | bycopy|
// | ptr | n.a. | - | - | x | | bycopy|
// | ptr | n.a. | - | - | x | x | bycopy|
// | ptr | n.a. | - | - | x | x[] | bycopy|
// =========================================================================
// Legend:
// scl - scalar
// ptr - pointer
// agg - aggregate
// x - applies
// - - invalid in this combination
// [] - mapped with an array section
// byref - should be mapped by reference
// byval - should be mapped by value
// null - initialize a local variable to null on the device
//
// Observations:
// - All scalar declarations that show up in a map clause have to be passed
// by reference, because they may have been mapped in the enclosing data
// environment.
// - If the scalar value does not fit the size of uintptr, it has to be
// passed by reference, regardless the result in the table above.
// - For pointers mapped by value that have either an implicit map or an
// array section, the runtime library may pass the NULL value to the
// device instead of the value passed to it by the compiler.
if (Ty->isReferenceType())
Ty = Ty->castAs<ReferenceType>()->getPointeeType();
// Locate map clauses and see if the variable being captured is referred to
// in any of those clauses. Here we only care about variables, not fields,
// because fields are part of aggregates.
bool IsVariableUsedInMapClause = false;
bool IsVariableAssociatedWithSection = false;
DSAStack->checkMappableExprComponentListsForDeclAtLevel(
D, Level,
[&IsVariableUsedInMapClause, &IsVariableAssociatedWithSection, D](
OMPClauseMappableExprCommon::MappableExprComponentListRef
MapExprComponents,
OpenMPClauseKind WhereFoundClauseKind) {
// Only the map clause information influences how a variable is
// captured. E.g. is_device_ptr does not require changing the default
// behavior.
if (WhereFoundClauseKind != OMPC_map)
return false;
auto EI = MapExprComponents.rbegin();
auto EE = MapExprComponents.rend();
assert(EI != EE && "Invalid map expression!");
if (isa<DeclRefExpr>(EI->getAssociatedExpression()))
IsVariableUsedInMapClause |= EI->getAssociatedDeclaration() == D;
++EI;
if (EI == EE)
return false;
if (isa<ArraySubscriptExpr>(EI->getAssociatedExpression()) ||
isa<OMPArraySectionExpr>(EI->getAssociatedExpression()) ||
isa<MemberExpr>(EI->getAssociatedExpression())) {
IsVariableAssociatedWithSection = true;
// There is nothing more we need to know about this variable.
return true;
}
// Keep looking for more map info.
return false;
});
if (IsVariableUsedInMapClause) {
// If variable is identified in a map clause it is always captured by
// reference except if it is a pointer that is dereferenced somehow.
IsByRef = !(Ty->isPointerType() && IsVariableAssociatedWithSection);
} else {
// By default, all the data that has a scalar type is mapped by copy
// (except for reduction variables).
IsByRef =
(DSAStack->isForceCaptureByReferenceInTargetExecutable() &&
!Ty->isAnyPointerType()) ||
!Ty->isScalarType() ||
DSAStack->getDefaultDMAAtLevel(Level) == DMA_tofrom_scalar ||
DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K) { return K == OMPC_reduction; }, Level);
}
}
if (IsByRef && Ty.getNonReferenceType()->isScalarType()) {
IsByRef =
((DSAStack->isForceCaptureByReferenceInTargetExecutable() &&
!Ty->isAnyPointerType()) ||
!DSAStack->hasExplicitDSA(
D,
[](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; },
Level, /*NotLastprivate=*/true)) &&
// If the variable is artificial and must be captured by value - try to
// capture by value.
!(isa<OMPCapturedExprDecl>(D) && !D->hasAttr<OMPCaptureNoInitAttr>() &&
!cast<OMPCapturedExprDecl>(D)->getInit()->isGLValue());
}
// When passing data by copy, we need to make sure it fits the uintptr size
// and alignment, because the runtime library only deals with uintptr types.
// If it does not fit the uintptr size, we need to pass the data by reference
// instead.
if (!IsByRef &&
(Ctx.getTypeSizeInChars(Ty) >
Ctx.getTypeSizeInChars(Ctx.getUIntPtrType()) ||
Ctx.getDeclAlign(D) > Ctx.getTypeAlignInChars(Ctx.getUIntPtrType()))) {
IsByRef = true;
}
return IsByRef;
}
unsigned Sema::getOpenMPNestingLevel() const {
assert(getLangOpts().OpenMP);
return DSAStack->getNestingLevel();
}
bool Sema::isInOpenMPTargetExecutionDirective() const {
return (isOpenMPTargetExecutionDirective(DSAStack->getCurrentDirective()) &&
!DSAStack->isClauseParsingMode()) ||
DSAStack->hasDirective(
[](OpenMPDirectiveKind K, const DeclarationNameInfo &,
SourceLocation) -> bool {
return isOpenMPTargetExecutionDirective(K);
},
false);
}
VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
D = getCanonicalDecl(D);
// If we are attempting to capture a global variable in a directive with
// 'target' we return true so that this global is also mapped to the device.
//
auto *VD = dyn_cast<VarDecl>(D);
if (VD && !VD->hasLocalStorage()) {
if (isInOpenMPDeclareTargetContext() &&
(getCurCapturedRegion() || getCurBlock() || getCurLambda())) {
// Try to mark variable as declare target if it is used in capturing
// regions.
if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
checkDeclIsAllowedInOpenMPTarget(nullptr, VD);
return nullptr;
} else if (isInOpenMPTargetExecutionDirective()) {
// If the declaration is enclosed in a 'declare target' directive,
// then it should not be captured.
//
if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
return nullptr;
return VD;
}
}
// Capture variables captured by reference in lambdas for target-based
// directives.
if (VD && !DSAStack->isClauseParsingMode()) {
if (const auto *RD = VD->getType()
.getCanonicalType()
.getNonReferenceType()
->getAsCXXRecordDecl()) {
bool SavedForceCaptureByReferenceInTargetExecutable =
DSAStack->isForceCaptureByReferenceInTargetExecutable();
DSAStack->setForceCaptureByReferenceInTargetExecutable(/*V=*/true);
if (RD->isLambda()) {
llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
FieldDecl *ThisCapture;
RD->getCaptureFields(Captures, ThisCapture);
for (const LambdaCapture &LC : RD->captures()) {
if (LC.getCaptureKind() == LCK_ByRef) {
VarDecl *VD = LC.getCapturedVar();
DeclContext *VDC = VD->getDeclContext();
if (!VDC->Encloses(CurContext))
continue;
DSAStackTy::DSAVarData DVarPrivate =
DSAStack->getTopDSA(VD, /*FromParent=*/false);
// Do not capture already captured variables.
if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) &&
DVarPrivate.CKind == OMPC_unknown &&
!DSAStack->checkMappableExprComponentListsForDecl(
D, /*CurrentRegionOnly=*/true,
[](OMPClauseMappableExprCommon::
MappableExprComponentListRef,
OpenMPClauseKind) { return true; }))
MarkVariableReferenced(LC.getLocation(), LC.getCapturedVar());
} else if (LC.getCaptureKind() == LCK_This) {
QualType ThisTy = getCurrentThisType();
if (!ThisTy.isNull() &&
Context.typesAreCompatible(ThisTy, ThisCapture->getType()))
CheckCXXThisCapture(LC.getLocation());
}
}
}
DSAStack->setForceCaptureByReferenceInTargetExecutable(
SavedForceCaptureByReferenceInTargetExecutable);
}
}
if (DSAStack->getCurrentDirective() != OMPD_unknown &&
(!DSAStack->isClauseParsingMode() ||
DSAStack->getParentDirective() != OMPD_unknown)) {
auto &&Info = DSAStack->isLoopControlVariable(D);
if (Info.first ||
(VD && VD->hasLocalStorage() &&
isImplicitOrExplicitTaskingRegion(DSAStack->getCurrentDirective())) ||
(VD && DSAStack->isForceVarCapturing()))
return VD ? VD : Info.second;
DSAStackTy::DSAVarData DVarPrivate =
DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode());
if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind))
return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
DVarPrivate = DSAStack->hasDSA(D, isOpenMPPrivate,
[](OpenMPDirectiveKind) { return true; },
DSAStack->isClauseParsingMode());
if (DVarPrivate.CKind != OMPC_unknown)
return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
}
return nullptr;
}
void Sema::adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex,
unsigned Level) const {
SmallVector<OpenMPDirectiveKind, 4> Regions;
getOpenMPCaptureRegions(Regions, DSAStack->getDirective(Level));
FunctionScopesIndex -= Regions.size();
}
void Sema::startOpenMPLoop() {
assert(LangOpts.OpenMP && "OpenMP must be enabled.");
if (isOpenMPLoopDirective(DSAStack->getCurrentDirective()))
DSAStack->loopInit();
}
bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
if (DSAStack->getAssociatedLoops() > 0 &&
!DSAStack->isLoopStarted()) {
DSAStack->resetPossibleLoopCounter(D);
DSAStack->loopStart();
return true;
}
if ((DSAStack->getPossiblyLoopCunter() == D->getCanonicalDecl() ||
DSAStack->isLoopControlVariable(D).first) &&
!DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K) { return K != OMPC_private; }, Level) &&
!isOpenMPSimdDirective(DSAStack->getCurrentDirective()))
return true;
}
return DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) ||
(DSAStack->isClauseParsingMode() &&
DSAStack->getClauseParsingMode() == OMPC_private) ||
// Consider taskgroup reduction descriptor variable a private to avoid
// possible capture in the region.
(DSAStack->hasExplicitDirective(
[](OpenMPDirectiveKind K) { return K == OMPD_taskgroup; },
Level) &&
DSAStack->isTaskgroupReductionRef(D, Level));
}
void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D,
unsigned Level) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
D = getCanonicalDecl(D);
OpenMPClauseKind OMPC = OMPC_unknown;
for (unsigned I = DSAStack->getNestingLevel() + 1; I > Level; --I) {
const unsigned NewLevel = I - 1;
if (DSAStack->hasExplicitDSA(D,
[&OMPC](const OpenMPClauseKind K) {
if (isOpenMPPrivate(K)) {
OMPC = K;
return true;
}
return false;
},
NewLevel))
break;
if (DSAStack->checkMappableExprComponentListsForDeclAtLevel(
D, NewLevel,
[](OMPClauseMappableExprCommon::MappableExprComponentListRef,
OpenMPClauseKind) { return true; })) {
OMPC = OMPC_map;
break;
}
if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective,
NewLevel)) {
OMPC = OMPC_map;
if (D->getType()->isScalarType() &&
DSAStack->getDefaultDMAAtLevel(NewLevel) !=
DefaultMapAttributes::DMA_tofrom_scalar)
OMPC = OMPC_firstprivate;
break;
}
}
if (OMPC != OMPC_unknown)
FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, OMPC));
}
bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D,
unsigned Level) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
// Return true if the current level is no longer enclosed in a target region.
const auto *VD = dyn_cast<VarDecl>(D);
return VD && !VD->hasLocalStorage() &&
DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective,
Level);
}
void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; }
void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
const DeclarationNameInfo &DirName,
Scope *CurScope, SourceLocation Loc) {
DSAStack->push(DKind, DirName, CurScope, Loc);
PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated);
}
void Sema::StartOpenMPClause(OpenMPClauseKind K) {
DSAStack->setClauseParsingMode(K);
}
void Sema::EndOpenMPClause() {
DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown);
}
void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
// OpenMP [2.14.3.5, Restrictions, C/C++, p.1]
// A variable of class type (or array thereof) that appears in a lastprivate
// clause requires an accessible, unambiguous default constructor for the
// class type, unless the list item is also specified in a firstprivate
// clause.
if (const auto *D = dyn_cast_or_null<OMPExecutableDirective>(CurDirective)) {
for (OMPClause *C : D->clauses()) {
if (auto *Clause = dyn_cast<OMPLastprivateClause>(C)) {
SmallVector<Expr *, 8> PrivateCopies;
for (Expr *DE : Clause->varlists()) {
if (DE->isValueDependent() || DE->isTypeDependent()) {
PrivateCopies.push_back(nullptr);
continue;
}
auto *DRE = cast<DeclRefExpr>(DE->IgnoreParens());
auto *VD = cast<VarDecl>(DRE->getDecl());
QualType Type = VD->getType().getNonReferenceType();
const DSAStackTy::DSAVarData DVar =
DSAStack->getTopDSA(VD, /*FromParent=*/false);
if (DVar.CKind == OMPC_lastprivate) {
// Generate helper private variable and initialize it with the
// default value. The address of the original variable is replaced
// by the address of the new private variable in CodeGen. This new
// variable is not added to IdResolver, so the code in the OpenMP
// region uses original variable for proper diagnostics.
VarDecl *VDPrivate = buildVarDecl(
*this, DE->getExprLoc(), Type.getUnqualifiedType(),
VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr, DRE);
ActOnUninitializedDecl(VDPrivate);
if (VDPrivate->isInvalidDecl())
continue;
PrivateCopies.push_back(buildDeclRefExpr(
*this, VDPrivate, DE->getType(), DE->getExprLoc()));
} else {
// The variable is also a firstprivate, so initialization sequence
// for private copy is generated already.
PrivateCopies.push_back(nullptr);
}
}
// Set initializers to private copies if no errors were found.
if (PrivateCopies.size() == Clause->varlist_size())
Clause->setPrivateCopies(PrivateCopies);
}
}
}
DSAStack->pop();
DiscardCleanupsInEvaluationContext();
PopExpressionEvaluationContext();
}
static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
Expr *NumIterations, Sema &SemaRef,
Scope *S, DSAStackTy *Stack);
namespace {
class VarDeclFilterCCC final : public CorrectionCandidateCallback {
private:
Sema &SemaRef;
public:
explicit VarDeclFilterCCC(Sema &S) : SemaRef(S) {}
bool ValidateCandidate(const TypoCorrection &Candidate) override {
NamedDecl *ND = Candidate.getCorrectionDecl();
if (const auto *VD = dyn_cast_or_null<VarDecl>(ND)) {
return VD->hasGlobalStorage() &&
SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(),
SemaRef.getCurScope());
}
return false;
}
};
class VarOrFuncDeclFilterCCC final : public CorrectionCandidateCallback {
private:
Sema &SemaRef;
public:
explicit VarOrFuncDeclFilterCCC(Sema &S) : SemaRef(S) {}
bool ValidateCandidate(const TypoCorrection &Candidate) override {
NamedDecl *ND = Candidate.getCorrectionDecl();
if (ND && (isa<VarDecl>(ND) || isa<FunctionDecl>(ND))) {
return SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(),
SemaRef.getCurScope());
}
return false;
}
};
} // namespace
ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
CXXScopeSpec &ScopeSpec,
const DeclarationNameInfo &Id) {
LookupResult Lookup(*this, Id, LookupOrdinaryName);
LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
if (Lookup.isAmbiguous())
return ExprError();
VarDecl *VD;
if (!Lookup.isSingleResult()) {
if (TypoCorrection Corrected = CorrectTypo(
Id, LookupOrdinaryName, CurScope, nullptr,
llvm::make_unique<VarDeclFilterCCC>(*this), CTK_ErrorRecovery)) {
diagnoseTypo(Corrected,
PDiag(Lookup.empty()
? diag::err_undeclared_var_use_suggest
: diag::err_omp_expected_var_arg_suggest)
<< Id.getName());
VD = Corrected.getCorrectionDeclAs<VarDecl>();
} else {
Diag(Id.getLoc(), Lookup.empty() ? diag::err_undeclared_var_use
: diag::err_omp_expected_var_arg)
<< Id.getName();
return ExprError();
}
} else if (!(VD = Lookup.getAsSingle<VarDecl>())) {
Diag(Id.getLoc(), diag::err_omp_expected_var_arg) << Id.getName();
Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);
return ExprError();
}
Lookup.suppressDiagnostics();
// OpenMP [2.9.2, Syntax, C/C++]
// Variables must be file-scope, namespace-scope, or static block-scope.
if (!VD->hasGlobalStorage()) {
Diag(Id.getLoc(), diag::err_omp_global_var_arg)
<< getOpenMPDirectiveName(OMPD_threadprivate) << !VD->isStaticLocal();
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< VD;
return ExprError();
}
VarDecl *CanonicalVD = VD->getCanonicalDecl();
NamedDecl *ND = CanonicalVD;
// OpenMP [2.9.2, Restrictions, C/C++, p.2]
// A threadprivate directive for file-scope variables must appear outside
// any definition or declaration.
if (CanonicalVD->getDeclContext()->isTranslationUnit() &&
!getCurLexicalContext()->isTranslationUnit()) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< VD;
return ExprError();
}
// OpenMP [2.9.2, Restrictions, C/C++, p.3]
// A threadprivate directive for static class member variables must appear
// in the class definition, in the same scope in which the member
// variables are declared.
if (CanonicalVD->isStaticDataMember() &&
!CanonicalVD->getDeclContext()->Equals(getCurLexicalContext())) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< VD;
return ExprError();
}
// OpenMP [2.9.2, Restrictions, C/C++, p.4]
// A threadprivate directive for namespace-scope variables must appear
// outside any definition or declaration other than the namespace
// definition itself.
if (CanonicalVD->getDeclContext()->isNamespace() &&
(!getCurLexicalContext()->isFileContext() ||
!getCurLexicalContext()->Encloses(CanonicalVD->getDeclContext()))) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< VD;
return ExprError();
}
// OpenMP [2.9.2, Restrictions, C/C++, p.6]
// A threadprivate directive for static block-scope variables must appear
// in the scope of the variable and not in a nested scope.
if (CanonicalVD->isStaticLocal() && CurScope &&
!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< VD;
return ExprError();
}
// OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
// A threadprivate directive must lexically precede all references to any
// of the variables in its list.
if (VD->isUsed() && !DSAStack->isThreadPrivate(VD)) {
Diag(Id.getLoc(), diag::err_omp_var_used)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
return ExprError();
}
QualType ExprType = VD->getType().getNonReferenceType();
return DeclRefExpr::Create(Context, NestedNameSpecifierLoc(),
SourceLocation(), VD,
/*RefersToEnclosingVariableOrCapture=*/false,
Id.getLoc(), ExprType, VK_LValue);
}
Sema::DeclGroupPtrTy
Sema::ActOnOpenMPThreadprivateDirective(SourceLocation Loc,
ArrayRef<Expr *> VarList) {
if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) {
CurContext->addDecl(D);
return DeclGroupPtrTy::make(DeclGroupRef(D));
}
return nullptr;
}
namespace {
class LocalVarRefChecker final
: public ConstStmtVisitor<LocalVarRefChecker, bool> {
Sema &SemaRef;
public:
bool VisitDeclRefExpr(const DeclRefExpr *E) {
if (const auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
if (VD->hasLocalStorage()) {
SemaRef.Diag(E->getBeginLoc(),
diag::err_omp_local_var_in_threadprivate_init)
<< E->getSourceRange();
SemaRef.Diag(VD->getLocation(), diag::note_defined_here)
<< VD << VD->getSourceRange();
return true;
}
}
return false;
}
bool VisitStmt(const Stmt *S) {
for (const Stmt *Child : S->children()) {
if (Child && Visit(Child))
return true;
}
return false;
}
explicit LocalVarRefChecker(Sema &SemaRef) : SemaRef(SemaRef) {}
};
} // namespace
OMPThreadPrivateDecl *
Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {
SmallVector<Expr *, 8> Vars;
for (Expr *RefExpr : VarList) {
auto *DE = cast<DeclRefExpr>(RefExpr);
auto *VD = cast<VarDecl>(DE->getDecl());
SourceLocation ILoc = DE->getExprLoc();
// Mark variable as used.
VD->setReferenced();
VD->markUsed(Context);
QualType QType = VD->getType();
if (QType->isDependentType() || QType->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
continue;
}
// OpenMP [2.9.2, Restrictions, C/C++, p.10]
// A threadprivate variable must not have an incomplete type.
if (RequireCompleteType(ILoc, VD->getType(),
diag::err_omp_threadprivate_incomplete_type)) {
continue;
}
// OpenMP [2.9.2, Restrictions, C/C++, p.10]
// A threadprivate variable must not have a reference type.
if (VD->getType()->isReferenceType()) {
Diag(ILoc, diag::err_omp_ref_type_arg)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType();
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< VD;
continue;
}
// Check if this is a TLS variable. If TLS is not being supported, produce
// the corresponding diagnostic.
if ((VD->getTLSKind() != VarDecl::TLS_None &&
!(VD->hasAttr<OMPThreadPrivateDeclAttr>() &&
getLangOpts().OpenMPUseTLS &&
getASTContext().getTargetInfo().isTLSSupported())) ||
(VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() &&
!VD->isLocalVarDecl())) {
Diag(ILoc, diag::err_omp_var_thread_local)
<< VD << ((VD->getTLSKind() != VarDecl::TLS_None) ? 0 : 1);
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< VD;
continue;
}
// Check if initial value of threadprivate variable reference variable with
// local storage (it is not supported by runtime).
if (const Expr *Init = VD->getAnyInitializer()) {
LocalVarRefChecker Checker(*this);
if (Checker.Visit(Init))
continue;
}
Vars.push_back(RefExpr);
DSAStack->addDSA(VD, DE, OMPC_threadprivate);
VD->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(
Context, SourceRange(Loc, Loc)));
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPThreadPrivate(VD);
}
OMPThreadPrivateDecl *D = nullptr;
if (!Vars.empty()) {
D = OMPThreadPrivateDecl::Create(Context, getCurLexicalContext(), Loc,
Vars);
D->setAccess(AS_public);
}
return D;
}
Sema::DeclGroupPtrTy
Sema::ActOnOpenMPRequiresDirective(SourceLocation Loc,
ArrayRef<OMPClause *> ClauseList) {
OMPRequiresDecl *D = nullptr;
if (!CurContext->isFileContext()) {
Diag(Loc, diag::err_omp_invalid_scope) << "requires";
} else {
D = CheckOMPRequiresDecl(Loc, ClauseList);
if (D) {
CurContext->addDecl(D);
DSAStack->addRequiresDecl(D);
}
}
return DeclGroupPtrTy::make(DeclGroupRef(D));
}
OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc,
ArrayRef<OMPClause *> ClauseList) {
if (!DSAStack->hasDuplicateRequiresClause(ClauseList))
return OMPRequiresDecl::Create(Context, getCurLexicalContext(), Loc,
ClauseList);
return nullptr;
}
static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack,
const ValueDecl *D,
const DSAStackTy::DSAVarData &DVar,
bool IsLoopIterVar = false) {
if (DVar.RefExpr) {
SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(DVar.CKind);
return;
}
enum {
PDSA_StaticMemberShared,
PDSA_StaticLocalVarShared,
PDSA_LoopIterVarPrivate,
PDSA_LoopIterVarLinear,
PDSA_LoopIterVarLastprivate,
PDSA_ConstVarShared,
PDSA_GlobalVarShared,
PDSA_TaskVarFirstprivate,
PDSA_LocalVarPrivate,
PDSA_Implicit
} Reason = PDSA_Implicit;
bool ReportHint = false;
auto ReportLoc = D->getLocation();
auto *VD = dyn_cast<VarDecl>(D);
if (IsLoopIterVar) {
if (DVar.CKind == OMPC_private)
Reason = PDSA_LoopIterVarPrivate;
else if (DVar.CKind == OMPC_lastprivate)
Reason = PDSA_LoopIterVarLastprivate;
else
Reason = PDSA_LoopIterVarLinear;
} else if (isOpenMPTaskingDirective(DVar.DKind) &&
DVar.CKind == OMPC_firstprivate) {
Reason = PDSA_TaskVarFirstprivate;
ReportLoc = DVar.ImplicitDSALoc;
} else if (VD && VD->isStaticLocal())
Reason = PDSA_StaticLocalVarShared;
else if (VD && VD->isStaticDataMember())
Reason = PDSA_StaticMemberShared;
else if (VD && VD->isFileVarDecl())
Reason = PDSA_GlobalVarShared;
else if (D->getType().isConstant(SemaRef.getASTContext()))
Reason = PDSA_ConstVarShared;
else if (VD && VD->isLocalVarDecl() && DVar.CKind == OMPC_private) {
ReportHint = true;
Reason = PDSA_LocalVarPrivate;
}
if (Reason != PDSA_Implicit) {
SemaRef.Diag(ReportLoc, diag::note_omp_predetermined_dsa)
<< Reason << ReportHint
<< getOpenMPDirectiveName(Stack->getCurrentDirective());
} else if (DVar.ImplicitDSALoc.isValid()) {
SemaRef.Diag(DVar.ImplicitDSALoc, diag::note_omp_implicit_dsa)
<< getOpenMPClauseName(DVar.CKind);
}
}
namespace {
class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
DSAStackTy *Stack;
Sema &SemaRef;
bool ErrorFound = false;
CapturedStmt *CS = nullptr;
llvm::SmallVector<Expr *, 4> ImplicitFirstprivate;
llvm::SmallVector<Expr *, 4> ImplicitMap;
Sema::VarsWithInheritedDSAType VarsWithInheritedDSA;
llvm::SmallDenseSet<const ValueDecl *, 4> ImplicitDeclarations;
void VisitSubCaptures(OMPExecutableDirective *S) {
// Check implicitly captured variables.
if (!S->hasAssociatedStmt() || !S->getAssociatedStmt())
return;
for (const CapturedStmt::Capture &Cap :
S->getInnermostCapturedStmt()->captures()) {
if (!Cap.capturesVariable())
continue;
VarDecl *VD = Cap.getCapturedVar();
// Do not try to map the variable if it or its sub-component was mapped
// already.
if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) &&
Stack->checkMappableExprComponentListsForDecl(
VD, /*CurrentRegionOnly=*/true,
[](OMPClauseMappableExprCommon::MappableExprComponentListRef,
OpenMPClauseKind) { return true; }))
continue;
DeclRefExpr *DRE = buildDeclRefExpr(
SemaRef, VD, VD->getType().getNonLValueExprType(SemaRef.Context),
Cap.getLocation(), /*RefersToCapture=*/true);
Visit(DRE);
}
}
public:
void VisitDeclRefExpr(DeclRefExpr *E) {
if (E->isTypeDependent() || E->isValueDependent() ||
E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
return;
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
VD = VD->getCanonicalDecl();
// Skip internally declared variables.
if (VD->hasLocalStorage() && !CS->capturesVariable(VD))
return;
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false);
// Check if the variable has explicit DSA set and stop analysis if it so.
if (DVar.RefExpr || !ImplicitDeclarations.insert(VD).second)
return;
// Skip internally declared static variables.
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (VD->hasGlobalStorage() && !CS->capturesVariable(VD) &&
(!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link))
return;
SourceLocation ELoc = E->getExprLoc();
OpenMPDirectiveKind DKind = Stack->getCurrentDirective();
// The default(none) clause requires that each variable that is referenced
// in the construct, and does not have a predetermined data-sharing
// attribute, must have its data-sharing attribute explicitly determined
// by being listed in a data-sharing attribute clause.
if (DVar.CKind == OMPC_unknown && Stack->getDefaultDSA() == DSA_none &&
isImplicitOrExplicitTaskingRegion(DKind) &&
VarsWithInheritedDSA.count(VD) == 0) {
VarsWithInheritedDSA[VD] = E;
return;
}
if (isOpenMPTargetExecutionDirective(DKind) &&
!Stack->isLoopControlVariable(VD).first) {
if (!Stack->checkMappableExprComponentListsForDecl(
VD, /*CurrentRegionOnly=*/true,
[](OMPClauseMappableExprCommon::MappableExprComponentListRef
StackComponents,
OpenMPClauseKind) {
// Variable is used if it has been marked as an array, array
// section or the variable iself.
return StackComponents.size() == 1 ||
std::all_of(
std::next(StackComponents.rbegin()),
StackComponents.rend(),
[](const OMPClauseMappableExprCommon::
MappableComponent &MC) {
return MC.getAssociatedDeclaration() ==
nullptr &&
(isa<OMPArraySectionExpr>(
MC.getAssociatedExpression()) ||
isa<ArraySubscriptExpr>(
MC.getAssociatedExpression()));
});
})) {
bool IsFirstprivate = false;
// By default lambdas are captured as firstprivates.
if (const auto *RD =
VD->getType().getNonReferenceType()->getAsCXXRecordDecl())
IsFirstprivate = RD->isLambda();
IsFirstprivate =
IsFirstprivate ||
(VD->getType().getNonReferenceType()->isScalarType() &&
Stack->getDefaultDMA() != DMA_tofrom_scalar && !Res);
if (IsFirstprivate)
ImplicitFirstprivate.emplace_back(E);
else
ImplicitMap.emplace_back(E);
return;
}
}
// OpenMP [2.9.3.6, Restrictions, p.2]
// A list item that appears in a reduction clause of the innermost
// enclosing worksharing or parallel construct may not be accessed in an
// explicit task.
DVar = Stack->hasInnermostDSA(
VD, [](OpenMPClauseKind C) { return C == OMPC_reduction; },
[](OpenMPDirectiveKind K) {
return isOpenMPParallelDirective(K) ||
isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K);
},
/*FromParent=*/true);
if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) {
ErrorFound = true;
SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task);
reportOriginalDsa(SemaRef, Stack, VD, DVar);
return;
}
// Define implicit data-sharing attributes for task.
DVar = Stack->getImplicitDSA(VD, /*FromParent=*/false);
if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared &&
!Stack->isLoopControlVariable(VD).first)
ImplicitFirstprivate.push_back(E);
}
}
void VisitMemberExpr(MemberExpr *E) {
if (E->isTypeDependent() || E->isValueDependent() ||
E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
return;
auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
OpenMPDirectiveKind DKind = Stack->getCurrentDirective();
if (auto *TE = dyn_cast<CXXThisExpr>(E->getBase()->IgnoreParens())) {
if (!FD)
return;
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(FD, /*FromParent=*/false);
// Check if the variable has explicit DSA set and stop analysis if it
// so.
if (DVar.RefExpr || !ImplicitDeclarations.insert(FD).second)
return;
if (isOpenMPTargetExecutionDirective(DKind) &&
!Stack->isLoopControlVariable(FD).first &&
!Stack->checkMappableExprComponentListsForDecl(
FD, /*CurrentRegionOnly=*/true,
[](OMPClauseMappableExprCommon::MappableExprComponentListRef
StackComponents,
OpenMPClauseKind) {
return isa<CXXThisExpr>(
cast<MemberExpr>(
StackComponents.back().getAssociatedExpression())
->getBase()
->IgnoreParens());
})) {
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3]
// A bit-field cannot appear in a map clause.
//
if (FD->isBitField())
return;
// Check to see if the member expression is referencing a class that
// has already been explicitly mapped
if (Stack->isClassPreviouslyMapped(TE->getType()))
return;
ImplicitMap.emplace_back(E);
return;
}
SourceLocation ELoc = E->getExprLoc();
// OpenMP [2.9.3.6, Restrictions, p.2]
// A list item that appears in a reduction clause of the innermost
// enclosing worksharing or parallel construct may not be accessed in
// an explicit task.
DVar = Stack->hasInnermostDSA(
FD, [](OpenMPClauseKind C) { return C == OMPC_reduction; },
[](OpenMPDirectiveKind K) {
return isOpenMPParallelDirective(K) ||
isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K);
},
/*FromParent=*/true);
if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) {
ErrorFound = true;
SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task);
reportOriginalDsa(SemaRef, Stack, FD, DVar);
return;
}
// Define implicit data-sharing attributes for task.
DVar = Stack->getImplicitDSA(FD, /*FromParent=*/false);
if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared &&
!Stack->isLoopControlVariable(FD).first) {
// Check if there is a captured expression for the current field in the
// region. Do not mark it as firstprivate unless there is no captured
// expression.
// TODO: try to make it firstprivate.
if (DVar.CKind != OMPC_unknown)
ImplicitFirstprivate.push_back(E);
}
return;
}
if (isOpenMPTargetExecutionDirective(DKind)) {
OMPClauseMappableExprCommon::MappableExprComponentList CurComponents;
if (!checkMapClauseExpressionBase(SemaRef, E, CurComponents, OMPC_map,
/*NoDiagnose=*/true))
return;
const auto *VD = cast<ValueDecl>(
CurComponents.back().getAssociatedDeclaration()->getCanonicalDecl());
if (!Stack->checkMappableExprComponentListsForDecl(
VD, /*CurrentRegionOnly=*/true,
[&CurComponents](
OMPClauseMappableExprCommon::MappableExprComponentListRef
StackComponents,
OpenMPClauseKind) {
auto CCI = CurComponents.rbegin();
auto CCE = CurComponents.rend();
for (const auto &SC : llvm::reverse(StackComponents)) {
// Do both expressions have the same kind?
if (CCI->getAssociatedExpression()->getStmtClass() !=
SC.getAssociatedExpression()->getStmtClass())
if (!(isa<OMPArraySectionExpr>(
SC.getAssociatedExpression()) &&
isa<ArraySubscriptExpr>(
CCI->getAssociatedExpression())))
return false;
const Decl *CCD = CCI->getAssociatedDeclaration();
const Decl *SCD = SC.getAssociatedDeclaration();
CCD = CCD ? CCD->getCanonicalDecl() : nullptr;
SCD = SCD ? SCD->getCanonicalDecl() : nullptr;
if (SCD != CCD)
return false;
std::advance(CCI, 1);
if (CCI == CCE)
break;
}
return true;
})) {
Visit(E->getBase());
}
} else {
Visit(E->getBase());
}
}
void VisitOMPExecutableDirective(OMPExecutableDirective *S) {
for (OMPClause *C : S->clauses()) {
// Skip analysis of arguments of implicitly defined firstprivate clause
// for task|target directives.
// Skip analysis of arguments of implicitly defined map clause for target
// directives.
if (C && !((isa<OMPFirstprivateClause>(C) || isa<OMPMapClause>(C)) &&
C->isImplicit())) {
for (Stmt *CC : C->children()) {
if (CC)
Visit(CC);
}
}
}
// Check implicitly captured variables.
VisitSubCaptures(S);
}
void VisitStmt(Stmt *S) {
for (Stmt *C : S->children()) {
if (C) {
// Check implicitly captured variables in the task-based directives to
// check if they must be firstprivatized.
Visit(C);
}
}
}
bool isErrorFound() const { return ErrorFound; }
ArrayRef<Expr *> getImplicitFirstprivate() const {
return ImplicitFirstprivate;
}
ArrayRef<Expr *> getImplicitMap() const { return ImplicitMap; }
const Sema::VarsWithInheritedDSAType &getVarsWithInheritedDSA() const {
return VarsWithInheritedDSA;
}
DSAAttrChecker(DSAStackTy *S, Sema &SemaRef, CapturedStmt *CS)
: Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) {}
};
} // namespace
void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
switch (DKind) {
case OMPD_parallel:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_parallel_sections:
case OMPD_teams:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst();
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
Sema::CapturedParamNameType Params[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
std::make_pair(".bound_tid.", KmpInt32PtrTy),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
break;
}
case OMPD_target_teams:
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst();
QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict();
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
QualType Args[] = {VoidPtrTy};
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = true;
QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI);
Sema::CapturedParamNameType Params[] = {
std::make_pair(".global_tid.", KmpInt32Ty),
std::make_pair(".part_id.", KmpInt32PtrTy),
std::make_pair(".privates.", VoidPtrTy),
std::make_pair(
".copy_fn.",
Context.getPointerType(CopyFnType).withConst().withRestrict()),
std::make_pair(".task_t.", Context.VoidPtrTy.withConst()),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
Context, AlwaysInlineAttr::Keyword_forceinline));
Sema::CapturedParamNameType ParamsTarget[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
ParamsTarget);
Sema::CapturedParamNameType ParamsTeamsOrParallel[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
std::make_pair(".bound_tid.", KmpInt32PtrTy),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'teams' or 'parallel'. Both regions have
// the same implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
ParamsTeamsOrParallel);
break;
}
case OMPD_target:
case OMPD_target_simd: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst();
QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict();
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
QualType Args[] = {VoidPtrTy};
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = true;
QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI);
Sema::CapturedParamNameType Params[] = {
std::make_pair(".global_tid.", KmpInt32Ty),
std::make_pair(".part_id.", KmpInt32PtrTy),
std::make_pair(".privates.", VoidPtrTy),
std::make_pair(
".copy_fn.",
Context.getPointerType(CopyFnType).withConst().withRestrict()),
std::make_pair(".task_t.", Context.VoidPtrTy.withConst()),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
Context, AlwaysInlineAttr::Keyword_forceinline));
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
std::make_pair(StringRef(), QualType()));
break;
}
case OMPD_simd:
case OMPD_for:
case OMPD_for_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
case OMPD_master:
case OMPD_critical:
case OMPD_taskgroup:
case OMPD_distribute:
case OMPD_distribute_simd:
case OMPD_ordered:
case OMPD_atomic:
case OMPD_target_data: {
Sema::CapturedParamNameType Params[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
break;
}
case OMPD_task: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst();
QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict();
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
QualType Args[] = {VoidPtrTy};
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = true;
QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI);
Sema::CapturedParamNameType Params[] = {
std::make_pair(".global_tid.", KmpInt32Ty),
std::make_pair(".part_id.", KmpInt32PtrTy),
std::make_pair(".privates.", VoidPtrTy),
std::make_pair(
".copy_fn.",
Context.getPointerType(CopyFnType).withConst().withRestrict()),
std::make_pair(".task_t.", Context.VoidPtrTy.withConst()),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
Context, AlwaysInlineAttr::Keyword_forceinline));
break;
}
case OMPD_taskloop:
case OMPD_taskloop_simd: {
QualType KmpInt32Ty =
Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1)
.withConst();
QualType KmpUInt64Ty =
Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0)
.withConst();
QualType KmpInt64Ty =
Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1)
.withConst();
QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict();
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
QualType Args[] = {VoidPtrTy};
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = true;
QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI);
Sema::CapturedParamNameType Params[] = {
std::make_pair(".global_tid.", KmpInt32Ty),
std::make_pair(".part_id.", KmpInt32PtrTy),
std::make_pair(".privates.", VoidPtrTy),
std::make_pair(
".copy_fn.",
Context.getPointerType(CopyFnType).withConst().withRestrict()),
std::make_pair(".task_t.", Context.VoidPtrTy.withConst()),
std::make_pair(".lb.", KmpUInt64Ty),
std::make_pair(".ub.", KmpUInt64Ty),
std::make_pair(".st.", KmpInt64Ty),
std::make_pair(".liter.", KmpInt32Ty),
std::make_pair(".reductions.", VoidPtrTy),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
Context, AlwaysInlineAttr::Keyword_forceinline));
break;
}
case OMPD_distribute_parallel_for_simd:
case OMPD_distribute_parallel_for: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst();
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
Sema::CapturedParamNameType Params[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
std::make_pair(".bound_tid.", KmpInt32PtrTy),
std::make_pair(".previous.lb.", Context.getSizeType().withConst()),
std::make_pair(".previous.ub.", Context.getSizeType().withConst()),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
break;
}
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst();
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict();
QualType Args[] = {VoidPtrTy};
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = true;
QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI);
Sema::CapturedParamNameType Params[] = {
std::make_pair(".global_tid.", KmpInt32Ty),
std::make_pair(".part_id.", KmpInt32PtrTy),
std::make_pair(".privates.", VoidPtrTy),
std::make_pair(
".copy_fn.",
Context.getPointerType(CopyFnType).withConst().withRestrict()),
std::make_pair(".task_t.", Context.VoidPtrTy.withConst()),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
Context, AlwaysInlineAttr::Keyword_forceinline));
Sema::CapturedParamNameType ParamsTarget[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
ParamsTarget);
Sema::CapturedParamNameType ParamsTeams[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
std::make_pair(".bound_tid.", KmpInt32PtrTy),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
ParamsTeams);
Sema::CapturedParamNameType ParamsParallel[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
std::make_pair(".bound_tid.", KmpInt32PtrTy),
std::make_pair(".previous.lb.", Context.getSizeType().withConst()),
std::make_pair(".previous.ub.", Context.getSizeType().withConst()),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'teams' or 'parallel'. Both regions have
// the same implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
ParamsParallel);
break;
}
case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst();
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
Sema::CapturedParamNameType ParamsTeams[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
std::make_pair(".bound_tid.", KmpInt32PtrTy),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
ParamsTeams);
Sema::CapturedParamNameType ParamsParallel[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
std::make_pair(".bound_tid.", KmpInt32PtrTy),
std::make_pair(".previous.lb.", Context.getSizeType().withConst()),
std::make_pair(".previous.ub.", Context.getSizeType().withConst()),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'teams' or 'parallel'. Both regions have
// the same implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
ParamsParallel);
break;
}
case OMPD_target_update:
case OMPD_target_enter_data:
case OMPD_target_exit_data: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst();
QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict();
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
QualType Args[] = {VoidPtrTy};
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = true;
QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI);
Sema::CapturedParamNameType Params[] = {
std::make_pair(".global_tid.", KmpInt32Ty),
std::make_pair(".part_id.", KmpInt32PtrTy),
std::make_pair(".privates.", VoidPtrTy),
std::make_pair(
".copy_fn.",
Context.getPointerType(CopyFnType).withConst().withRestrict()),
std::make_pair(".task_t.", Context.VoidPtrTy.withConst()),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
Context, AlwaysInlineAttr::Keyword_forceinline));
break;
}
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_cancel:
case OMPD_flush:
case OMPD_declare_reduction:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_requires:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
}
int Sema::getOpenMPCaptureLevels(OpenMPDirectiveKind DKind) {
SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
getOpenMPCaptureRegions(CaptureRegions, DKind);
return CaptureRegions.size();
}
static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
Expr *CaptureExpr, bool WithInit,
bool AsExpression) {
assert(CaptureExpr);
ASTContext &C = S.getASTContext();
Expr *Init = AsExpression ? CaptureExpr : CaptureExpr->IgnoreImpCasts();
QualType Ty = Init->getType();
if (CaptureExpr->getObjectKind() == OK_Ordinary && CaptureExpr->isGLValue()) {
if (S.getLangOpts().CPlusPlus) {
Ty = C.getLValueReferenceType(Ty);
} else {
Ty = C.getPointerType(Ty);
ExprResult Res =
S.CreateBuiltinUnaryOp(CaptureExpr->getExprLoc(), UO_AddrOf, Init);
if (!Res.isUsable())
return nullptr;
Init = Res.get();
}
WithInit = true;
}
auto *CED = OMPCapturedExprDecl::Create(C, S.CurContext, Id, Ty,
CaptureExpr->getBeginLoc());
if (!WithInit)
CED->addAttr(OMPCaptureNoInitAttr::CreateImplicit(C));
S.CurContext->addHiddenDecl(CED);
S.AddInitializerToDecl(CED, Init, /*DirectInit=*/false);
return CED;
}
static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr,
bool WithInit) {
OMPCapturedExprDecl *CD;
if (VarDecl *VD = S.isOpenMPCapturedDecl(D))
CD = cast<OMPCapturedExprDecl>(VD);
else
CD = buildCaptureDecl(S, D->getIdentifier(), CaptureExpr, WithInit,
/*AsExpression=*/false);
return buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(),
CaptureExpr->getExprLoc());
}
static ExprResult buildCapture(Sema &S, Expr *CaptureExpr, DeclRefExpr *&Ref) {
CaptureExpr = S.DefaultLvalueConversion(CaptureExpr).get();
if (!Ref) {
OMPCapturedExprDecl *CD = buildCaptureDecl(
S, &S.getASTContext().Idents.get(".capture_expr."), CaptureExpr,
/*WithInit=*/true, /*AsExpression=*/true);
Ref = buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(),
CaptureExpr->getExprLoc());
}
ExprResult Res = Ref;
if (!S.getLangOpts().CPlusPlus &&
CaptureExpr->getObjectKind() == OK_Ordinary && CaptureExpr->isGLValue() &&
Ref->getType()->isPointerType()) {
Res = S.CreateBuiltinUnaryOp(CaptureExpr->getExprLoc(), UO_Deref, Ref);
if (!Res.isUsable())
return ExprError();
}
return S.DefaultLvalueConversion(Res.get());
}
namespace {
// OpenMP directives parsed in this section are represented as a
// CapturedStatement with an associated statement. If a syntax error
// is detected during the parsing of the associated statement, the
// compiler must abort processing and close the CapturedStatement.
//
// Combined directives such as 'target parallel' have more than one
// nested CapturedStatements. This RAII ensures that we unwind out
// of all the nested CapturedStatements when an error is found.
class CaptureRegionUnwinderRAII {
private:
Sema &S;
bool &ErrorFound;
OpenMPDirectiveKind DKind = OMPD_unknown;
public:
CaptureRegionUnwinderRAII(Sema &S, bool &ErrorFound,
OpenMPDirectiveKind DKind)
: S(S), ErrorFound(ErrorFound), DKind(DKind) {}
~CaptureRegionUnwinderRAII() {
if (ErrorFound) {
int ThisCaptureLevel = S.getOpenMPCaptureLevels(DKind);
while (--ThisCaptureLevel >= 0)
S.ActOnCapturedRegionError();
}
}
};
} // namespace
StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
ArrayRef<OMPClause *> Clauses) {
bool ErrorFound = false;
CaptureRegionUnwinderRAII CaptureRegionUnwinder(
*this, ErrorFound, DSAStack->getCurrentDirective());
if (!S.isUsable()) {
ErrorFound = true;
return StmtError();
}
SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
getOpenMPCaptureRegions(CaptureRegions, DSAStack->getCurrentDirective());
OMPOrderedClause *OC = nullptr;
OMPScheduleClause *SC = nullptr;
SmallVector<const OMPLinearClause *, 4> LCs;
SmallVector<const OMPClauseWithPreInit *, 4> PICs;
// This is required for proper codegen.
for (OMPClause *Clause : Clauses) {
if (isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) &&
Clause->getClauseKind() == OMPC_in_reduction) {
// Capture taskgroup task_reduction descriptors inside the tasking regions
// with the corresponding in_reduction items.
auto *IRC = cast<OMPInReductionClause>(Clause);
for (Expr *E : IRC->taskgroup_descriptors())
if (E)
MarkDeclarationsReferencedInExpr(E);
}
if (isOpenMPPrivate(Clause->getClauseKind()) ||
Clause->getClauseKind() == OMPC_copyprivate ||
(getLangOpts().OpenMPUseTLS &&
getASTContext().getTargetInfo().isTLSSupported() &&
Clause->getClauseKind() == OMPC_copyin)) {
DSAStack->setForceVarCapturing(Clause->getClauseKind() == OMPC_copyin);
// Mark all variables in private list clauses as used in inner region.
for (Stmt *VarRef : Clause->children()) {
if (auto *E = cast_or_null<Expr>(VarRef)) {
MarkDeclarationsReferencedInExpr(E);
}
}
DSAStack->setForceVarCapturing(/*V=*/false);
} else if (CaptureRegions.size() > 1 ||
CaptureRegions.back() != OMPD_unknown) {
if (auto *C = OMPClauseWithPreInit::get(Clause))
PICs.push_back(C);
if (auto *C = OMPClauseWithPostUpdate::get(Clause)) {
if (Expr *E = C->getPostUpdateExpr())
MarkDeclarationsReferencedInExpr(E);
}
}
if (Clause->getClauseKind() == OMPC_schedule)
SC = cast<OMPScheduleClause>(Clause);
else if (Clause->getClauseKind() == OMPC_ordered)
OC = cast<OMPOrderedClause>(Clause);
else if (Clause->getClauseKind() == OMPC_linear)
LCs.push_back(cast<OMPLinearClause>(Clause));
}
// OpenMP, 2.7.1 Loop Construct, Restrictions
// The nonmonotonic modifier cannot be specified if an ordered clause is
// specified.
if (SC &&
(SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic ||
SC->getSecondScheduleModifier() ==
OMPC_SCHEDULE_MODIFIER_nonmonotonic) &&
OC) {
Diag(SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic
? SC->getFirstScheduleModifierLoc()
: SC->getSecondScheduleModifierLoc(),
diag::err_omp_schedule_nonmonotonic_ordered)
<< SourceRange(OC->getBeginLoc(), OC->getEndLoc());
ErrorFound = true;
}
if (!LCs.empty() && OC && OC->getNumForLoops()) {
for (const OMPLinearClause *C : LCs) {
Diag(C->getBeginLoc(), diag::err_omp_linear_ordered)
<< SourceRange(OC->getBeginLoc(), OC->getEndLoc());
}
ErrorFound = true;
}
if (isOpenMPWorksharingDirective(DSAStack->getCurrentDirective()) &&
isOpenMPSimdDirective(DSAStack->getCurrentDirective()) && OC &&
OC->getNumForLoops()) {
Diag(OC->getBeginLoc(), diag::err_omp_ordered_simd)
<< getOpenMPDirectiveName(DSAStack->getCurrentDirective());
ErrorFound = true;
}
if (ErrorFound) {
return StmtError();
}
StmtResult SR = S;
for (OpenMPDirectiveKind ThisCaptureRegion : llvm::reverse(CaptureRegions)) {
// Mark all variables in private list clauses as used in inner region.
// Required for proper codegen of combined directives.
// TODO: add processing for other clauses.
if (ThisCaptureRegion != OMPD_unknown) {
for (const clang::OMPClauseWithPreInit *C : PICs) {
OpenMPDirectiveKind CaptureRegion = C->getCaptureRegion();
// Find the particular capture region for the clause if the
// directive is a combined one with multiple capture regions.
// If the directive is not a combined one, the capture region
// associated with the clause is OMPD_unknown and is generated
// only once.
if (CaptureRegion == ThisCaptureRegion ||
CaptureRegion == OMPD_unknown) {
if (auto *DS = cast_or_null<DeclStmt>(C->getPreInitStmt())) {
for (Decl *D : DS->decls())
MarkVariableReferenced(D->getLocation(), cast<VarDecl>(D));
}
}
}
}
SR = ActOnCapturedRegionEnd(SR.get());
}
return SR;
}
static bool checkCancelRegion(Sema &SemaRef, OpenMPDirectiveKind CurrentRegion,
OpenMPDirectiveKind CancelRegion,
SourceLocation StartLoc) {
// CancelRegion is only needed for cancel and cancellation_point.
if (CurrentRegion != OMPD_cancel && CurrentRegion != OMPD_cancellation_point)
return false;
if (CancelRegion == OMPD_parallel || CancelRegion == OMPD_for ||
CancelRegion == OMPD_sections || CancelRegion == OMPD_taskgroup)
return false;
SemaRef.Diag(StartLoc, diag::err_omp_wrong_cancel_region)
<< getOpenMPDirectiveName(CancelRegion);
return true;
}
static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
OpenMPDirectiveKind CurrentRegion,
const DeclarationNameInfo &CurrentName,
OpenMPDirectiveKind CancelRegion,
SourceLocation StartLoc) {
if (Stack->getCurScope()) {
OpenMPDirectiveKind ParentRegion = Stack->getParentDirective();
OpenMPDirectiveKind OffendingRegion = ParentRegion;
bool NestingProhibited = false;
bool CloseNesting = true;
bool OrphanSeen = false;
enum {
NoRecommend,
ShouldBeInParallelRegion,
ShouldBeInOrderedRegion,
ShouldBeInTargetRegion,
ShouldBeInTeamsRegion
} Recommend = NoRecommend;
if (isOpenMPSimdDirective(ParentRegion) && CurrentRegion != OMPD_ordered) {
// OpenMP [2.16, Nesting of Regions]
// OpenMP constructs may not be nested inside a simd region.
// OpenMP [2.8.1,simd Construct, Restrictions]
// An ordered construct with the simd clause is the only OpenMP
// construct that can appear in the simd region.
// Allowing a SIMD construct nested in another SIMD construct is an
// extension. The OpenMP 4.5 spec does not allow it. Issue a warning
// message.
SemaRef.Diag(StartLoc, (CurrentRegion != OMPD_simd)
? diag::err_omp_prohibited_region_simd
: diag::warn_omp_nesting_simd);
return CurrentRegion != OMPD_simd;
}
if (ParentRegion == OMPD_atomic) {
// OpenMP [2.16, Nesting of Regions]
// OpenMP constructs may not be nested inside an atomic region.
SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_atomic);
return true;
}
if (CurrentRegion == OMPD_section) {
// OpenMP [2.7.2, sections Construct, Restrictions]
// Orphaned section directives are prohibited. That is, the section
// directives must appear within the sections construct and must not be
// encountered elsewhere in the sections region.
if (ParentRegion != OMPD_sections &&
ParentRegion != OMPD_parallel_sections) {
SemaRef.Diag(StartLoc, diag::err_omp_orphaned_section_directive)
<< (ParentRegion != OMPD_unknown)
<< getOpenMPDirectiveName(ParentRegion);
return true;
}
return false;
}
// Allow some constructs (except teams and cancellation constructs) to be
// orphaned (they could be used in functions, called from OpenMP regions
// with the required preconditions).
if (ParentRegion == OMPD_unknown &&
!isOpenMPNestingTeamsDirective(CurrentRegion) &&
CurrentRegion != OMPD_cancellation_point &&
CurrentRegion != OMPD_cancel)
return false;
if (CurrentRegion == OMPD_cancellation_point ||
CurrentRegion == OMPD_cancel) {
// OpenMP [2.16, Nesting of Regions]
// A cancellation point construct for which construct-type-clause is
// taskgroup must be nested inside a task construct. A cancellation
// point construct for which construct-type-clause is not taskgroup must
// be closely nested inside an OpenMP construct that matches the type
// specified in construct-type-clause.
// A cancel construct for which construct-type-clause is taskgroup must be
// nested inside a task construct. A cancel construct for which
// construct-type-clause is not taskgroup must be closely nested inside an
// OpenMP construct that matches the type specified in
// construct-type-clause.
NestingProhibited =
!((CancelRegion == OMPD_parallel &&
(ParentRegion == OMPD_parallel ||
ParentRegion == OMPD_target_parallel)) ||
(CancelRegion == OMPD_for &&
(ParentRegion == OMPD_for || ParentRegion == OMPD_parallel_for ||
ParentRegion == OMPD_target_parallel_for ||
ParentRegion == OMPD_distribute_parallel_for ||
ParentRegion == OMPD_teams_distribute_parallel_for ||
ParentRegion == OMPD_target_teams_distribute_parallel_for)) ||
(CancelRegion == OMPD_taskgroup && ParentRegion == OMPD_task) ||
(CancelRegion == OMPD_sections &&
(ParentRegion == OMPD_section || ParentRegion == OMPD_sections ||
ParentRegion == OMPD_parallel_sections)));
OrphanSeen = ParentRegion == OMPD_unknown;
} else if (CurrentRegion == OMPD_master) {
// OpenMP [2.16, Nesting of Regions]
// A master region may not be closely nested inside a worksharing,
// atomic, or explicit task region.
NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
isOpenMPTaskingDirective(ParentRegion);
} else if (CurrentRegion == OMPD_critical && CurrentName.getName()) {
// OpenMP [2.16, Nesting of Regions]
// A critical region may not be nested (closely or otherwise) inside a
// critical region with the same name. Note that this restriction is not
// sufficient to prevent deadlock.
SourceLocation PreviousCriticalLoc;
bool DeadLock = Stack->hasDirective(
[CurrentName, &PreviousCriticalLoc](OpenMPDirectiveKind K,
const DeclarationNameInfo &DNI,
SourceLocation Loc) {
if (K == OMPD_critical && DNI.getName() == CurrentName.getName()) {
PreviousCriticalLoc = Loc;
return true;
}
return false;
},
false /* skip top directive */);
if (DeadLock) {
SemaRef.Diag(StartLoc,
diag::err_omp_prohibited_region_critical_same_name)
<< CurrentName.getName();
if (PreviousCriticalLoc.isValid())
SemaRef.Diag(PreviousCriticalLoc,
diag::note_omp_previous_critical_region);
return true;
}
} else if (CurrentRegion == OMPD_barrier) {
// OpenMP [2.16, Nesting of Regions]
// A barrier region may not be closely nested inside a worksharing,
// explicit task, critical, ordered, atomic, or master region.
NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
isOpenMPTaskingDirective(ParentRegion) ||
ParentRegion == OMPD_master ||
ParentRegion == OMPD_critical ||
ParentRegion == OMPD_ordered;
} else if (isOpenMPWorksharingDirective(CurrentRegion) &&
!isOpenMPParallelDirective(CurrentRegion) &&
!isOpenMPTeamsDirective(CurrentRegion)) {
// OpenMP [2.16, Nesting of Regions]
// A worksharing region may not be closely nested inside a worksharing,
// explicit task, critical, ordered, atomic, or master region.
NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
isOpenMPTaskingDirective(ParentRegion) ||
ParentRegion == OMPD_master ||
ParentRegion == OMPD_critical ||
ParentRegion == OMPD_ordered;
Recommend = ShouldBeInParallelRegion;
} else if (CurrentRegion == OMPD_ordered) {
// OpenMP [2.16, Nesting of Regions]
// An ordered region may not be closely nested inside a critical,
// atomic, or explicit task region.
// An ordered region must be closely nested inside a loop region (or
// parallel loop region) with an ordered clause.
// OpenMP [2.8.1,simd Construct, Restrictions]
// An ordered construct with the simd clause is the only OpenMP construct
// that can appear in the simd region.
NestingProhibited = ParentRegion == OMPD_critical ||
isOpenMPTaskingDirective(ParentRegion) ||
!(isOpenMPSimdDirective(ParentRegion) ||
Stack->isParentOrderedRegion());
Recommend = ShouldBeInOrderedRegion;
} else if (isOpenMPNestingTeamsDirective(CurrentRegion)) {
// OpenMP [2.16, Nesting of Regions]
// If specified, a teams construct must be contained within a target
// construct.
NestingProhibited = ParentRegion != OMPD_target;
OrphanSeen = ParentRegion == OMPD_unknown;
Recommend = ShouldBeInTargetRegion;
}
if (!NestingProhibited &&
!isOpenMPTargetExecutionDirective(CurrentRegion) &&
!isOpenMPTargetDataManagementDirective(CurrentRegion) &&
(ParentRegion == OMPD_teams || ParentRegion == OMPD_target_teams)) {
// OpenMP [2.16, Nesting of Regions]
// distribute, parallel, parallel sections, parallel workshare, and the
// parallel loop and parallel loop SIMD constructs are the only OpenMP
// constructs that can be closely nested in the teams region.
NestingProhibited = !isOpenMPParallelDirective(CurrentRegion) &&
!isOpenMPDistributeDirective(CurrentRegion);
Recommend = ShouldBeInParallelRegion;
}
if (!NestingProhibited &&
isOpenMPNestingDistributeDirective(CurrentRegion)) {
// OpenMP 4.5 [2.17 Nesting of Regions]
// The region associated with the distribute construct must be strictly
// nested inside a teams region
NestingProhibited =
(ParentRegion != OMPD_teams && ParentRegion != OMPD_target_teams);
Recommend = ShouldBeInTeamsRegion;
}
if (!NestingProhibited &&
(isOpenMPTargetExecutionDirective(CurrentRegion) ||
isOpenMPTargetDataManagementDirective(CurrentRegion))) {
// OpenMP 4.5 [2.17 Nesting of Regions]
// If a target, target update, target data, target enter data, or
// target exit data construct is encountered during execution of a
// target region, the behavior is unspecified.
NestingProhibited = Stack->hasDirective(
[&OffendingRegion](OpenMPDirectiveKind K, const DeclarationNameInfo &,
SourceLocation) {
if (isOpenMPTargetExecutionDirective(K)) {
OffendingRegion = K;
return true;
}
return false;
},
false /* don't skip top directive */);
CloseNesting = false;
}
if (NestingProhibited) {
if (OrphanSeen) {
SemaRef.Diag(StartLoc, diag::err_omp_orphaned_device_directive)
<< getOpenMPDirectiveName(CurrentRegion) << Recommend;
} else {
SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region)
<< CloseNesting << getOpenMPDirectiveName(OffendingRegion)
<< Recommend << getOpenMPDirectiveName(CurrentRegion);
}
return true;
}
}
return false;
}
static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
ArrayRef<OMPClause *> Clauses,
ArrayRef<OpenMPDirectiveKind> AllowedNameModifiers) {
bool ErrorFound = false;
unsigned NamedModifiersNumber = 0;
SmallVector<const OMPIfClause *, OMPC_unknown + 1> FoundNameModifiers(
OMPD_unknown + 1);
SmallVector<SourceLocation, 4> NameModifierLoc;
for (const OMPClause *C : Clauses) {
if (const auto *IC = dyn_cast_or_null<OMPIfClause>(C)) {
// At most one if clause without a directive-name-modifier can appear on
// the directive.
OpenMPDirectiveKind CurNM = IC->getNameModifier();
if (FoundNameModifiers[CurNM]) {
S.Diag(C->getBeginLoc(), diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(Kind) << getOpenMPClauseName(OMPC_if)
<< (CurNM != OMPD_unknown) << getOpenMPDirectiveName(CurNM);
ErrorFound = true;
} else if (CurNM != OMPD_unknown) {
NameModifierLoc.push_back(IC->getNameModifierLoc());
++NamedModifiersNumber;
}
FoundNameModifiers[CurNM] = IC;
if (CurNM == OMPD_unknown)
continue;
// Check if the specified name modifier is allowed for the current
// directive.
// At most one if clause with the particular directive-name-modifier can
// appear on the directive.
bool MatchFound = false;
for (auto NM : AllowedNameModifiers) {
if (CurNM == NM) {
MatchFound = true;
break;
}
}
if (!MatchFound) {
S.Diag(IC->getNameModifierLoc(),
diag::err_omp_wrong_if_directive_name_modifier)
<< getOpenMPDirectiveName(CurNM) << getOpenMPDirectiveName(Kind);
ErrorFound = true;
}
}
}
// If any if clause on the directive includes a directive-name-modifier then
// all if clauses on the directive must include a directive-name-modifier.
if (FoundNameModifiers[OMPD_unknown] && NamedModifiersNumber > 0) {
if (NamedModifiersNumber == AllowedNameModifiers.size()) {
S.Diag(FoundNameModifiers[OMPD_unknown]->getBeginLoc(),
diag::err_omp_no_more_if_clause);
} else {
std::string Values;
std::string Sep(", ");
unsigned AllowedCnt = 0;
unsigned TotalAllowedNum =
AllowedNameModifiers.size() - NamedModifiersNumber;
for (unsigned Cnt = 0, End = AllowedNameModifiers.size(); Cnt < End;
++Cnt) {
OpenMPDirectiveKind NM = AllowedNameModifiers[Cnt];
if (!FoundNameModifiers[NM]) {
Values += "'";
Values += getOpenMPDirectiveName(NM);
Values += "'";
if (AllowedCnt + 2 == TotalAllowedNum)
Values += " or ";
else if (AllowedCnt + 1 != TotalAllowedNum)
Values += Sep;
++AllowedCnt;
}
}
S.Diag(FoundNameModifiers[OMPD_unknown]->getCondition()->getBeginLoc(),
diag::err_omp_unnamed_if_clause)
<< (TotalAllowedNum > 1) << Values;
}
for (SourceLocation Loc : NameModifierLoc) {
S.Diag(Loc, diag::note_omp_previous_named_if_clause);
}
ErrorFound = true;
}
return ErrorFound;
}
StmtResult Sema::ActOnOpenMPExecutableDirective(
OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) {
StmtResult Res = StmtError();
// First check CancelRegion which is then used in checkNestingOfRegions.
if (checkCancelRegion(*this, Kind, CancelRegion, StartLoc) ||
checkNestingOfRegions(*this, DSAStack, Kind, DirName, CancelRegion,
StartLoc))
return StmtError();
llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit;
VarsWithInheritedDSAType VarsWithInheritedDSA;
bool ErrorFound = false;
ClausesWithImplicit.append(Clauses.begin(), Clauses.end());
if (AStmt && !CurContext->isDependentContext()) {
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
// Check default data sharing attributes for referenced variables.
DSAAttrChecker DSAChecker(DSAStack, *this, cast<CapturedStmt>(AStmt));
int ThisCaptureLevel = getOpenMPCaptureLevels(Kind);
Stmt *S = AStmt;
while (--ThisCaptureLevel >= 0)
S = cast<CapturedStmt>(S)->getCapturedStmt();
DSAChecker.Visit(S);
if (DSAChecker.isErrorFound())
return StmtError();
// Generate list of implicitly defined firstprivate variables.
VarsWithInheritedDSA = DSAChecker.getVarsWithInheritedDSA();
SmallVector<Expr *, 4> ImplicitFirstprivates(
DSAChecker.getImplicitFirstprivate().begin(),
DSAChecker.getImplicitFirstprivate().end());
SmallVector<Expr *, 4> ImplicitMaps(DSAChecker.getImplicitMap().begin(),
DSAChecker.getImplicitMap().end());
// Mark taskgroup task_reduction descriptors as implicitly firstprivate.
for (OMPClause *C : Clauses) {
if (auto *IRC = dyn_cast<OMPInReductionClause>(C)) {
for (Expr *E : IRC->taskgroup_descriptors())
if (E)
ImplicitFirstprivates.emplace_back(E);
}
}
if (!ImplicitFirstprivates.empty()) {
if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause(
ImplicitFirstprivates, SourceLocation(), SourceLocation(),
SourceLocation())) {
ClausesWithImplicit.push_back(Implicit);
ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() !=
ImplicitFirstprivates.size();
} else {
ErrorFound = true;
}
}
if (!ImplicitMaps.empty()) {
if (OMPClause *Implicit = ActOnOpenMPMapClause(
llvm::None, llvm::None, OMPC_MAP_tofrom,
/*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(),
ImplicitMaps, SourceLocation(), SourceLocation(),
SourceLocation())) {
ClausesWithImplicit.emplace_back(Implicit);
ErrorFound |=
cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMaps.size();
} else {
ErrorFound = true;
}
}
}
llvm::SmallVector<OpenMPDirectiveKind, 4> AllowedNameModifiers;
switch (Kind) {
case OMPD_parallel:
Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_simd:
Res = ActOnOpenMPSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc,
VarsWithInheritedDSA);
break;
case OMPD_for:
Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc,
VarsWithInheritedDSA);
break;
case OMPD_for_simd:
Res = ActOnOpenMPForSimdDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
break;
case OMPD_sections:
Res = ActOnOpenMPSectionsDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
break;
case OMPD_section:
assert(ClausesWithImplicit.empty() &&
"No clauses are allowed for 'omp section' directive");
Res = ActOnOpenMPSectionDirective(AStmt, StartLoc, EndLoc);
break;
case OMPD_single:
Res = ActOnOpenMPSingleDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
break;
case OMPD_master:
assert(ClausesWithImplicit.empty() &&
"No clauses are allowed for 'omp master' directive");
Res = ActOnOpenMPMasterDirective(AStmt, StartLoc, EndLoc);
break;
case OMPD_critical:
Res = ActOnOpenMPCriticalDirective(DirName, ClausesWithImplicit, AStmt,
StartLoc, EndLoc);
break;
case OMPD_parallel_for:
Res = ActOnOpenMPParallelForDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_parallel_for_simd:
Res = ActOnOpenMPParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_parallel_sections:
Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt,
StartLoc, EndLoc);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_task:
Res =
ActOnOpenMPTaskDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc);
AllowedNameModifiers.push_back(OMPD_task);
break;
case OMPD_taskyield:
assert(ClausesWithImplicit.empty() &&
"No clauses are allowed for 'omp taskyield' directive");
assert(AStmt == nullptr &&
"No associated statement allowed for 'omp taskyield' directive");
Res = ActOnOpenMPTaskyieldDirective(StartLoc, EndLoc);
break;
case OMPD_barrier:
assert(ClausesWithImplicit.empty() &&
"No clauses are allowed for 'omp barrier' directive");
assert(AStmt == nullptr &&
"No associated statement allowed for 'omp barrier' directive");
Res = ActOnOpenMPBarrierDirective(StartLoc, EndLoc);
break;
case OMPD_taskwait:
assert(ClausesWithImplicit.empty() &&
"No clauses are allowed for 'omp taskwait' directive");
assert(AStmt == nullptr &&
"No associated statement allowed for 'omp taskwait' directive");
Res = ActOnOpenMPTaskwaitDirective(StartLoc, EndLoc);
break;
case OMPD_taskgroup:
Res = ActOnOpenMPTaskgroupDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
break;
case OMPD_flush:
assert(AStmt == nullptr &&
"No associated statement allowed for 'omp flush' directive");
Res = ActOnOpenMPFlushDirective(ClausesWithImplicit, StartLoc, EndLoc);
break;
case OMPD_ordered:
Res = ActOnOpenMPOrderedDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
break;
case OMPD_atomic:
Res = ActOnOpenMPAtomicDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
break;
case OMPD_teams:
Res =
ActOnOpenMPTeamsDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc);
break;
case OMPD_target:
Res = ActOnOpenMPTargetDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
AllowedNameModifiers.push_back(OMPD_target);
break;
case OMPD_target_parallel:
Res = ActOnOpenMPTargetParallelDirective(ClausesWithImplicit, AStmt,
StartLoc, EndLoc);
AllowedNameModifiers.push_back(OMPD_target);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_target_parallel_for:
Res = ActOnOpenMPTargetParallelForDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_cancellation_point:
assert(ClausesWithImplicit.empty() &&
"No clauses are allowed for 'omp cancellation point' directive");
assert(AStmt == nullptr && "No associated statement allowed for 'omp "
"cancellation point' directive");
Res = ActOnOpenMPCancellationPointDirective(StartLoc, EndLoc, CancelRegion);
break;
case OMPD_cancel:
assert(AStmt == nullptr &&
"No associated statement allowed for 'omp cancel' directive");
Res = ActOnOpenMPCancelDirective(ClausesWithImplicit, StartLoc, EndLoc,
CancelRegion);
AllowedNameModifiers.push_back(OMPD_cancel);
break;
case OMPD_target_data:
Res = ActOnOpenMPTargetDataDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
AllowedNameModifiers.push_back(OMPD_target_data);
break;
case OMPD_target_enter_data:
Res = ActOnOpenMPTargetEnterDataDirective(ClausesWithImplicit, StartLoc,
EndLoc, AStmt);
AllowedNameModifiers.push_back(OMPD_target_enter_data);
break;
case OMPD_target_exit_data:
Res = ActOnOpenMPTargetExitDataDirective(ClausesWithImplicit, StartLoc,
EndLoc, AStmt);
AllowedNameModifiers.push_back(OMPD_target_exit_data);
break;
case OMPD_taskloop:
Res = ActOnOpenMPTaskLoopDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_taskloop);
break;
case OMPD_taskloop_simd:
Res = ActOnOpenMPTaskLoopSimdDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_taskloop);
break;
case OMPD_distribute:
Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
break;
case OMPD_target_update:
Res = ActOnOpenMPTargetUpdateDirective(ClausesWithImplicit, StartLoc,
EndLoc, AStmt);
AllowedNameModifiers.push_back(OMPD_target_update);
break;
case OMPD_distribute_parallel_for:
Res = ActOnOpenMPDistributeParallelForDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_distribute_parallel_for_simd:
Res = ActOnOpenMPDistributeParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_distribute_simd:
Res = ActOnOpenMPDistributeSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
break;
case OMPD_target_parallel_for_simd:
Res = ActOnOpenMPTargetParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_target_simd:
Res = ActOnOpenMPTargetSimdDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
break;
case OMPD_teams_distribute:
Res = ActOnOpenMPTeamsDistributeDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
break;
case OMPD_teams_distribute_simd:
Res = ActOnOpenMPTeamsDistributeSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
break;
case OMPD_teams_distribute_parallel_for_simd:
Res = ActOnOpenMPTeamsDistributeParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_teams_distribute_parallel_for:
Res = ActOnOpenMPTeamsDistributeParallelForDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_target_teams:
Res = ActOnOpenMPTargetTeamsDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
AllowedNameModifiers.push_back(OMPD_target);
break;
case OMPD_target_teams_distribute:
Res = ActOnOpenMPTargetTeamsDistributeDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
break;
case OMPD_target_teams_distribute_parallel_for:
Res = ActOnOpenMPTargetTeamsDistributeParallelForDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_target_teams_distribute_parallel_for_simd:
Res = ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_target_teams_distribute_simd:
Res = ActOnOpenMPTargetTeamsDistributeSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
break;
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_threadprivate:
case OMPD_declare_reduction:
case OMPD_declare_simd:
case OMPD_requires:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
for (const auto &P : VarsWithInheritedDSA) {
Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable)
<< P.first << P.second->getSourceRange();
}
ErrorFound = !VarsWithInheritedDSA.empty() || ErrorFound;
if (!AllowedNameModifiers.empty())
ErrorFound = checkIfClauses(*this, Kind, Clauses, AllowedNameModifiers) ||
ErrorFound;
if (ErrorFound)
return StmtError();
return Res;
}
Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen,
ArrayRef<Expr *> Uniforms, ArrayRef<Expr *> Aligneds,
ArrayRef<Expr *> Alignments, ArrayRef<Expr *> Linears,
ArrayRef<unsigned> LinModifiers, ArrayRef<Expr *> Steps, SourceRange SR) {
assert(Aligneds.size() == Alignments.size());
assert(Linears.size() == LinModifiers.size());
assert(Linears.size() == Steps.size());
if (!DG || DG.get().isNull())
return DeclGroupPtrTy();
if (!DG.get().isSingleDecl()) {
Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd);
return DG;
}
Decl *ADecl = DG.get().getSingleDecl();
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl))
ADecl = FTD->getTemplatedDecl();
auto *FD = dyn_cast<FunctionDecl>(ADecl);
if (!FD) {
Diag(ADecl->getLocation(), diag::err_omp_function_expected);
return DeclGroupPtrTy();
}
// OpenMP [2.8.2, declare simd construct, Description]
// The parameter of the simdlen clause must be a constant positive integer
// expression.
ExprResult SL;
if (Simdlen)
SL = VerifyPositiveIntegerConstantInClause(Simdlen, OMPC_simdlen);
// OpenMP [2.8.2, declare simd construct, Description]
// The special this pointer can be used as if was one of the arguments to the
// function in any of the linear, aligned, or uniform clauses.
// The uniform clause declares one or more arguments to have an invariant
// value for all concurrent invocations of the function in the execution of a
// single SIMD loop.
llvm::DenseMap<const Decl *, const Expr *> UniformedArgs;
const Expr *UniformedLinearThis = nullptr;
for (const Expr *E : Uniforms) {
E = E->IgnoreParenImpCasts();
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
FD->getParamDecl(PVD->getFunctionScopeIndex())
->getCanonicalDecl() == PVD->getCanonicalDecl()) {
UniformedArgs.try_emplace(PVD->getCanonicalDecl(), E);
continue;
}
if (isa<CXXThisExpr>(E)) {
UniformedLinearThis = E;
continue;
}
Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
<< FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0);
}
// OpenMP [2.8.2, declare simd construct, Description]
// The aligned clause declares that the object to which each list item points
// is aligned to the number of bytes expressed in the optional parameter of
// the aligned clause.
// The special this pointer can be used as if was one of the arguments to the
// function in any of the linear, aligned, or uniform clauses.
// The type of list items appearing in the aligned clause must be array,
// pointer, reference to array, or reference to pointer.
llvm::DenseMap<const Decl *, const Expr *> AlignedArgs;
const Expr *AlignedThis = nullptr;
for (const Expr *E : Aligneds) {
E = E->IgnoreParenImpCasts();
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
const VarDecl *CanonPVD = PVD->getCanonicalDecl();
if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
FD->getParamDecl(PVD->getFunctionScopeIndex())
->getCanonicalDecl() == CanonPVD) {
// OpenMP [2.8.1, simd construct, Restrictions]
// A list-item cannot appear in more than one aligned clause.
if (AlignedArgs.count(CanonPVD) > 0) {
Diag(E->getExprLoc(), diag::err_omp_aligned_twice)
<< 1 << E->getSourceRange();
Diag(AlignedArgs[CanonPVD]->getExprLoc(),
diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_aligned);
continue;
}
AlignedArgs[CanonPVD] = E;
QualType QTy = PVD->getType()
.getNonReferenceType()
.getUnqualifiedType()
.getCanonicalType();
const Type *Ty = QTy.getTypePtrOrNull();
if (!Ty || (!Ty->isArrayType() && !Ty->isPointerType())) {
Diag(E->getExprLoc(), diag::err_omp_aligned_expected_array_or_ptr)
<< QTy << getLangOpts().CPlusPlus << E->getSourceRange();
Diag(PVD->getLocation(), diag::note_previous_decl) << PVD;
}
continue;
}
}
if (isa<CXXThisExpr>(E)) {
if (AlignedThis) {
Diag(E->getExprLoc(), diag::err_omp_aligned_twice)
<< 2 << E->getSourceRange();
Diag(AlignedThis->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_aligned);
}
AlignedThis = E;
continue;
}
Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
<< FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0);
}
// The optional parameter of the aligned clause, alignment, must be a constant
// positive integer expression. If no optional parameter is specified,
// implementation-defined default alignments for SIMD instructions on the
// target platforms are assumed.
SmallVector<const Expr *, 4> NewAligns;
for (Expr *E : Alignments) {
ExprResult Align;
if (E)
Align = VerifyPositiveIntegerConstantInClause(E, OMPC_aligned);
NewAligns.push_back(Align.get());
}
// OpenMP [2.8.2, declare simd construct, Description]
// The linear clause declares one or more list items to be private to a SIMD
// lane and to have a linear relationship with respect to the iteration space
// of a loop.
// The special this pointer can be used as if was one of the arguments to the
// function in any of the linear, aligned, or uniform clauses.
// When a linear-step expression is specified in a linear clause it must be
// either a constant integer expression or an integer-typed parameter that is
// specified in a uniform clause on the directive.
llvm::DenseMap<const Decl *, const Expr *> LinearArgs;
const bool IsUniformedThis = UniformedLinearThis != nullptr;
auto MI = LinModifiers.begin();
for (const Expr *E : Linears) {
auto LinKind = static_cast<OpenMPLinearClauseKind>(*MI);
++MI;
E = E->IgnoreParenImpCasts();
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
const VarDecl *CanonPVD = PVD->getCanonicalDecl();
if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
FD->getParamDecl(PVD->getFunctionScopeIndex())
->getCanonicalDecl() == CanonPVD) {
// OpenMP [2.15.3.7, linear Clause, Restrictions]
// A list-item cannot appear in more than one linear clause.
if (LinearArgs.count(CanonPVD) > 0) {
Diag(E->getExprLoc(), diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(OMPC_linear)
<< getOpenMPClauseName(OMPC_linear) << E->getSourceRange();
Diag(LinearArgs[CanonPVD]->getExprLoc(),
diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_linear);
continue;
}
// Each argument can appear in at most one uniform or linear clause.
if (UniformedArgs.count(CanonPVD) > 0) {
Diag(E->getExprLoc(), diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(OMPC_linear)
<< getOpenMPClauseName(OMPC_uniform) << E->getSourceRange();
Diag(UniformedArgs[CanonPVD]->getExprLoc(),
diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_uniform);
continue;
}
LinearArgs[CanonPVD] = E;
if (E->isValueDependent() || E->isTypeDependent() ||
E->isInstantiationDependent() ||
E->containsUnexpandedParameterPack())
continue;
(void)CheckOpenMPLinearDecl(CanonPVD, E->getExprLoc(), LinKind,
PVD->getOriginalType());
continue;
}
}
if (isa<CXXThisExpr>(E)) {
if (UniformedLinearThis) {
Diag(E->getExprLoc(), diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(OMPC_linear)
<< getOpenMPClauseName(IsUniformedThis ? OMPC_uniform : OMPC_linear)
<< E->getSourceRange();
Diag(UniformedLinearThis->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(IsUniformedThis ? OMPC_uniform
: OMPC_linear);
continue;
}
UniformedLinearThis = E;
if (E->isValueDependent() || E->isTypeDependent() ||
E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
continue;
(void)CheckOpenMPLinearDecl(/*D=*/nullptr, E->getExprLoc(), LinKind,
E->getType());
continue;
}
Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
<< FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0);
}
Expr *Step = nullptr;
Expr *NewStep = nullptr;
SmallVector<Expr *, 4> NewSteps;
for (Expr *E : Steps) {
// Skip the same step expression, it was checked already.
if (Step == E || !E) {
NewSteps.push_back(E ? NewStep : nullptr);
continue;
}
Step = E;
if (const auto *DRE = dyn_cast<DeclRefExpr>(Step))
if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
const VarDecl *CanonPVD = PVD->getCanonicalDecl();
if (UniformedArgs.count(CanonPVD) == 0) {
Diag(Step->getExprLoc(), diag::err_omp_expected_uniform_param)
<< Step->getSourceRange();
} else if (E->isValueDependent() || E->isTypeDependent() ||
E->isInstantiationDependent() ||
E->containsUnexpandedParameterPack() ||
CanonPVD->getType()->hasIntegerRepresentation()) {
NewSteps.push_back(Step);
} else {
Diag(Step->getExprLoc(), diag::err_omp_expected_int_param)
<< Step->getSourceRange();
}
continue;
}
NewStep = Step;
if (Step && !Step->isValueDependent() && !Step->isTypeDependent() &&
!Step->isInstantiationDependent() &&
!Step->containsUnexpandedParameterPack()) {
NewStep = PerformOpenMPImplicitIntegerConversion(Step->getExprLoc(), Step)
.get();
if (NewStep)
NewStep = VerifyIntegerConstantExpression(NewStep).get();
}
NewSteps.push_back(NewStep);
}
auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit(
Context, BS, SL.get(), const_cast<Expr **>(Uniforms.data()),
Uniforms.size(), const_cast<Expr **>(Aligneds.data()), Aligneds.size(),
const_cast<Expr **>(NewAligns.data()), NewAligns.size(),
const_cast<Expr **>(Linears.data()), Linears.size(),
const_cast<unsigned *>(LinModifiers.data()), LinModifiers.size(),
NewSteps.data(), NewSteps.size(), SR);
ADecl->addAttr(NewAttr);
return ConvertDeclToDeclGroup(ADecl);
}
StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
setFunctionHasBranchProtectedScope();
return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
DSAStack->isCancelRegion());
}
namespace {
/// Helper class for checking canonical form of the OpenMP loops and
/// extracting iteration space of each loop in the loop nest, that will be used
/// for IR generation.
class OpenMPIterationSpaceChecker {
/// Reference to Sema.
Sema &SemaRef;
/// A location for diagnostics (when there is no some better location).
SourceLocation DefaultLoc;
/// A location for diagnostics (when increment is not compatible).
SourceLocation ConditionLoc;
/// A source location for referring to loop init later.
SourceRange InitSrcRange;
/// A source location for referring to condition later.
SourceRange ConditionSrcRange;
/// A source location for referring to increment later.
SourceRange IncrementSrcRange;
/// Loop variable.
ValueDecl *LCDecl = nullptr;
/// Reference to loop variable.
Expr *LCRef = nullptr;
/// Lower bound (initializer for the var).
Expr *LB = nullptr;
/// Upper bound.
Expr *UB = nullptr;
/// Loop step (increment).
Expr *Step = nullptr;
/// This flag is true when condition is one of:
/// Var < UB
/// Var <= UB
/// UB > Var
/// UB >= Var
/// This will have no value when the condition is !=
llvm::Optional<bool> TestIsLessOp;
/// This flag is true when condition is strict ( < or > ).
bool TestIsStrictOp = false;
/// This flag is true when step is subtracted on each iteration.
bool SubtractStep = false;
public:
OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc)
: SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc) {}
/// Check init-expr for canonical loop form and save loop counter
/// variable - #Var and its initialization value - #LB.
bool checkAndSetInit(Stmt *S, bool EmitDiags = true);
/// Check test-expr for canonical form, save upper-bound (#UB), flags
/// for less/greater and for strict/non-strict comparison.
bool checkAndSetCond(Expr *S);
/// Check incr-expr for canonical loop form and return true if it
/// does not conform, otherwise save loop step (#Step).
bool checkAndSetInc(Expr *S);
/// Return the loop counter variable.
ValueDecl *getLoopDecl() const { return LCDecl; }
/// Return the reference expression to loop counter variable.
Expr *getLoopDeclRefExpr() const { return LCRef; }
/// Source range of the loop init.
SourceRange getInitSrcRange() const { return InitSrcRange; }
/// Source range of the loop condition.
SourceRange getConditionSrcRange() const { return ConditionSrcRange; }
/// Source range of the loop increment.
SourceRange getIncrementSrcRange() const { return IncrementSrcRange; }
/// True if the step should be subtracted.
bool shouldSubtractStep() const { return SubtractStep; }
/// Build the expression to calculate the number of iterations.
Expr *buildNumIterations(
Scope *S, const bool LimitedType,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const;
/// Build the precondition expression for the loops.
Expr *
buildPreCond(Scope *S, Expr *Cond,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const;
/// Build reference expression to the counter be used for codegen.
DeclRefExpr *
buildCounterVar(llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
DSAStackTy &DSA) const;
/// Build reference expression to the private counter be used for
/// codegen.
Expr *buildPrivateCounterVar() const;
/// Build initialization of the counter be used for codegen.
Expr *buildCounterInit() const;
/// Build step of the counter be used for codegen.
Expr *buildCounterStep() const;
/// Build loop data with counter value for depend clauses in ordered
/// directives.
Expr *
buildOrderedLoopData(Scope *S, Expr *Counter,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
SourceLocation Loc, Expr *Inc = nullptr,
OverloadedOperatorKind OOK = OO_Amp);
/// Return true if any expression is dependent.
bool dependent() const;
private:
/// Check the right-hand side of an assignment in the increment
/// expression.
bool checkAndSetIncRHS(Expr *RHS);
/// Helper to set loop counter variable and its initializer.
bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB);
/// Helper to set upper bound.
bool setUB(Expr *NewUB, llvm::Optional<bool> LessOp, bool StrictOp,
SourceRange SR, SourceLocation SL);
/// Helper to set loop increment.
bool setStep(Expr *NewStep, bool Subtract);
};
bool OpenMPIterationSpaceChecker::dependent() const {
if (!LCDecl) {
assert(!LB && !UB && !Step);
return false;
}
return LCDecl->getType()->isDependentType() ||
(LB && LB->isValueDependent()) || (UB && UB->isValueDependent()) ||
(Step && Step->isValueDependent());
}
bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl,
Expr *NewLCRefExpr,
Expr *NewLB) {
// State consistency checking to ensure correct usage.
assert(LCDecl == nullptr && LB == nullptr && LCRef == nullptr &&
UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp);
if (!NewLCDecl || !NewLB)
return true;
LCDecl = getCanonicalDecl(NewLCDecl);
LCRef = NewLCRefExpr;
if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(NewLB))
if (const CXXConstructorDecl *Ctor = CE->getConstructor())
if ((Ctor->isCopyOrMoveConstructor() ||
Ctor->isConvertingConstructor(/*AllowExplicit=*/false)) &&
CE->getNumArgs() > 0 && CE->getArg(0) != nullptr)
NewLB = CE->getArg(0)->IgnoreParenImpCasts();
LB = NewLB;
return false;
}
bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, llvm::Optional<bool> LessOp,
bool StrictOp, SourceRange SR,
SourceLocation SL) {
// State consistency checking to ensure correct usage.
assert(LCDecl != nullptr && LB != nullptr && UB == nullptr &&
Step == nullptr && !TestIsLessOp && !TestIsStrictOp);
if (!NewUB)
return true;
UB = NewUB;
if (LessOp)
TestIsLessOp = LessOp;
TestIsStrictOp = StrictOp;
ConditionSrcRange = SR;
ConditionLoc = SL;
return false;
}
bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
// State consistency checking to ensure correct usage.
assert(LCDecl != nullptr && LB != nullptr && Step == nullptr);
if (!NewStep)
return true;
if (!NewStep->isValueDependent()) {
// Check that the step is integer expression.
SourceLocation StepLoc = NewStep->getBeginLoc();
ExprResult Val = SemaRef.PerformOpenMPImplicitIntegerConversion(
StepLoc, getExprAsWritten(NewStep));
if (Val.isInvalid())
return true;
NewStep = Val.get();
// OpenMP [2.6, Canonical Loop Form, Restrictions]
// If test-expr is of form var relational-op b and relational-op is < or
// <= then incr-expr must cause var to increase on each iteration of the
// loop. If test-expr is of form var relational-op b and relational-op is
// > or >= then incr-expr must cause var to decrease on each iteration of
// the loop.
// If test-expr is of form b relational-op var and relational-op is < or
// <= then incr-expr must cause var to decrease on each iteration of the
// loop. If test-expr is of form b relational-op var and relational-op is
// > or >= then incr-expr must cause var to increase on each iteration of
// the loop.
llvm::APSInt Result;
bool IsConstant = NewStep->isIntegerConstantExpr(Result, SemaRef.Context);
bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation();
bool IsConstNeg =
IsConstant && Result.isSigned() && (Subtract != Result.isNegative());
bool IsConstPos =
IsConstant && Result.isSigned() && (Subtract == Result.isNegative());
bool IsConstZero = IsConstant && !Result.getBoolValue();
// != with increment is treated as <; != with decrement is treated as >
if (!TestIsLessOp.hasValue())
TestIsLessOp = IsConstPos || (IsUnsigned && !Subtract);
if (UB && (IsConstZero ||
(TestIsLessOp.getValue() ?
(IsConstNeg || (IsUnsigned && Subtract)) :
(IsConstPos || (IsUnsigned && !Subtract))))) {
SemaRef.Diag(NewStep->getExprLoc(),
diag::err_omp_loop_incr_not_compatible)
<< LCDecl << TestIsLessOp.getValue() << NewStep->getSourceRange();
SemaRef.Diag(ConditionLoc,
diag::note_omp_loop_cond_requres_compatible_incr)
<< TestIsLessOp.getValue() << ConditionSrcRange;
return true;
}
if (TestIsLessOp.getValue() == Subtract) {
NewStep =
SemaRef.CreateBuiltinUnaryOp(NewStep->getExprLoc(), UO_Minus, NewStep)
.get();
Subtract = !Subtract;
}
}
Step = NewStep;
SubtractStep = Subtract;
return false;
}
bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
// Check init-expr for canonical loop form and save loop counter
// variable - #Var and its initialization value - #LB.
// OpenMP [2.6] Canonical loop form. init-expr may be one of the following:
// var = lb
// integer-type var = lb
// random-access-iterator-type var = lb
// pointer-type var = lb
//
if (!S) {
if (EmitDiags) {
SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init);
}
return true;
}
if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(S))
if (!ExprTemp->cleanupsHaveSideEffects())
S = ExprTemp->getSubExpr();
InitSrcRange = S->getSourceRange();
if (Expr *E = dyn_cast<Expr>(S))
S = E->IgnoreParens();
if (auto *BO = dyn_cast<BinaryOperator>(S)) {
if (BO->getOpcode() == BO_Assign) {
Expr *LHS = BO->getLHS()->IgnoreParens();
if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) {
if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl()))
if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS());
}
if (auto *ME = dyn_cast<MemberExpr>(LHS)) {
if (ME->isArrow() &&
isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
}
}
} else if (auto *DS = dyn_cast<DeclStmt>(S)) {
if (DS->isSingleDecl()) {
if (auto *Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) {
if (Var->hasInit() && !Var->getType()->isReferenceType()) {
// Accept non-canonical init form here but emit ext. warning.
if (Var->getInitStyle() != VarDecl::CInit && EmitDiags)
SemaRef.Diag(S->getBeginLoc(),
diag::ext_omp_loop_not_canonical_init)
<< S->getSourceRange();
return setLCDeclAndLB(
Var,
buildDeclRefExpr(SemaRef, Var,
Var->getType().getNonReferenceType(),
DS->getBeginLoc()),
Var->getInit());
}
}
}
} else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) {
if (CE->getOperator() == OO_Equal) {
Expr *LHS = CE->getArg(0);
if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) {
if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl()))
if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1));
}
if (auto *ME = dyn_cast<MemberExpr>(LHS)) {
if (ME->isArrow() &&
isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
}
}
}
if (dependent() || SemaRef.CurContext->isDependentContext())
return false;
if (EmitDiags) {
SemaRef.Diag(S->getBeginLoc(), diag::err_omp_loop_not_canonical_init)
<< S->getSourceRange();
}
return true;
}
/// Ignore parenthesizes, implicit casts, copy constructor and return the
/// variable (which may be the loop variable) if possible.
static const ValueDecl *getInitLCDecl(const Expr *E) {
if (!E)
return nullptr;
E = getExprAsWritten(E);
if (const auto *CE = dyn_cast_or_null<CXXConstructExpr>(E))
if (const CXXConstructorDecl *Ctor = CE->getConstructor())
if ((Ctor->isCopyOrMoveConstructor() ||
Ctor->isConvertingConstructor(/*AllowExplicit=*/false)) &&
CE->getNumArgs() > 0 && CE->getArg(0) != nullptr)
E = CE->getArg(0)->IgnoreParenImpCasts();
if (const auto *DRE = dyn_cast_or_null<DeclRefExpr>(E)) {
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
return getCanonicalDecl(VD);
}
if (const auto *ME = dyn_cast_or_null<MemberExpr>(E))
if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
return getCanonicalDecl(ME->getMemberDecl());
return nullptr;
}
bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
// Check test-expr for canonical form, save upper-bound UB, flags for
// less/greater and for strict/non-strict comparison.
// OpenMP [2.6] Canonical loop form. Test-expr may be one of the following:
// var relational-op b
// b relational-op var
//
if (!S) {
SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << LCDecl;
return true;
}
S = getExprAsWritten(S);
SourceLocation CondLoc = S->getBeginLoc();
if (auto *BO = dyn_cast<BinaryOperator>(S)) {
if (BO->isRelationalOp()) {
if (getInitLCDecl(BO->getLHS()) == LCDecl)
return setUB(BO->getRHS(),
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE),
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
BO->getSourceRange(), BO->getOperatorLoc());
if (getInitLCDecl(BO->getRHS()) == LCDecl)
return setUB(BO->getLHS(),
(BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE),
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
BO->getSourceRange(), BO->getOperatorLoc());
} else if (BO->getOpcode() == BO_NE)
return setUB(getInitLCDecl(BO->getLHS()) == LCDecl ?
BO->getRHS() : BO->getLHS(),
/*LessOp=*/llvm::None,
/*StrictOp=*/true,
BO->getSourceRange(), BO->getOperatorLoc());
} else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) {
if (CE->getNumArgs() == 2) {
auto Op = CE->getOperator();
switch (Op) {
case OO_Greater:
case OO_GreaterEqual:
case OO_Less:
case OO_LessEqual:
if (getInitLCDecl(CE->getArg(0)) == LCDecl)
return setUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual,
Op == OO_Less || Op == OO_Greater, CE->getSourceRange(),
CE->getOperatorLoc());
if (getInitLCDecl(CE->getArg(1)) == LCDecl)
return setUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual,
Op == OO_Less || Op == OO_Greater, CE->getSourceRange(),
CE->getOperatorLoc());
break;
case OO_ExclaimEqual:
return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ?
CE->getArg(1) : CE->getArg(0),
/*LessOp=*/llvm::None,
/*StrictOp=*/true,
CE->getSourceRange(),
CE->getOperatorLoc());
break;
default:
break;
}
}
}
if (dependent() || SemaRef.CurContext->isDependentContext())
return false;
SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond)
<< S->getSourceRange() << LCDecl;
return true;
}
bool OpenMPIterationSpaceChecker::checkAndSetIncRHS(Expr *RHS) {
// RHS of canonical loop form increment can be:
// var + incr
// incr + var
// var - incr
//
RHS = RHS->IgnoreParenImpCasts();
if (auto *BO = dyn_cast<BinaryOperator>(RHS)) {
if (BO->isAdditiveOp()) {
bool IsAdd = BO->getOpcode() == BO_Add;
if (getInitLCDecl(BO->getLHS()) == LCDecl)
return setStep(BO->getRHS(), !IsAdd);
if (IsAdd && getInitLCDecl(BO->getRHS()) == LCDecl)
return setStep(BO->getLHS(), /*Subtract=*/false);
}
} else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(RHS)) {
bool IsAdd = CE->getOperator() == OO_Plus;
if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) {
if (getInitLCDecl(CE->getArg(0)) == LCDecl)
return setStep(CE->getArg(1), !IsAdd);
if (IsAdd && getInitLCDecl(CE->getArg(1)) == LCDecl)
return setStep(CE->getArg(0), /*Subtract=*/false);
}
}
if (dependent() || SemaRef.CurContext->isDependentContext())
return false;
SemaRef.Diag(RHS->getBeginLoc(), diag::err_omp_loop_not_canonical_incr)
<< RHS->getSourceRange() << LCDecl;
return true;
}
bool OpenMPIterationSpaceChecker::checkAndSetInc(Expr *S) {
// Check incr-expr for canonical loop form and return true if it
// does not conform.
// OpenMP [2.6] Canonical loop form. Test-expr may be one of the following:
// ++var
// var++
// --var
// var--
// var += incr
// var -= incr
// var = var + incr
// var = incr + var
// var = var - incr
//
if (!S) {
SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << LCDecl;
return true;
}
if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(S))
if (!ExprTemp->cleanupsHaveSideEffects())
S = ExprTemp->getSubExpr();
IncrementSrcRange = S->getSourceRange();
S = S->IgnoreParens();
if (auto *UO = dyn_cast<UnaryOperator>(S)) {
if (UO->isIncrementDecrementOp() &&
getInitLCDecl(UO->getSubExpr()) == LCDecl)
return setStep(SemaRef
.ActOnIntegerConstant(UO->getBeginLoc(),
(UO->isDecrementOp() ? -1 : 1))
.get(),
/*Subtract=*/false);
} else if (auto *BO = dyn_cast<BinaryOperator>(S)) {
switch (BO->getOpcode()) {
case BO_AddAssign:
case BO_SubAssign:
if (getInitLCDecl(BO->getLHS()) == LCDecl)
return setStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign);
break;
case BO_Assign:
if (getInitLCDecl(BO->getLHS()) == LCDecl)
return checkAndSetIncRHS(BO->getRHS());
break;
default:
break;
}
} else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) {
switch (CE->getOperator()) {
case OO_PlusPlus:
case OO_MinusMinus:
if (getInitLCDecl(CE->getArg(0)) == LCDecl)
return setStep(SemaRef
.ActOnIntegerConstant(
CE->getBeginLoc(),
((CE->getOperator() == OO_MinusMinus) ? -1 : 1))
.get(),
/*Subtract=*/false);
break;
case OO_PlusEqual:
case OO_MinusEqual:
if (getInitLCDecl(CE->getArg(0)) == LCDecl)
return setStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual);
break;
case OO_Equal:
if (getInitLCDecl(CE->getArg(0)) == LCDecl)
return checkAndSetIncRHS(CE->getArg(1));
break;
default:
break;
}
}
if (dependent() || SemaRef.CurContext->isDependentContext())
return false;
SemaRef.Diag(S->getBeginLoc(), diag::err_omp_loop_not_canonical_incr)
<< S->getSourceRange() << LCDecl;
return true;
}
static ExprResult
tryBuildCapture(Sema &SemaRef, Expr *Capture,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
if (SemaRef.CurContext->isDependentContext())
return ExprResult(Capture);
if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects))
return SemaRef.PerformImplicitConversion(
Capture->IgnoreImpCasts(), Capture->getType(), Sema::AA_Converting,
/*AllowExplicit=*/true);
auto I = Captures.find(Capture);
if (I != Captures.end())
return buildCapture(SemaRef, Capture, I->second);
DeclRefExpr *Ref = nullptr;
ExprResult Res = buildCapture(SemaRef, Capture, Ref);
Captures[Capture] = Ref;
return Res;
}
/// Build the expression to calculate the number of iterations.
Expr *OpenMPIterationSpaceChecker::buildNumIterations(
Scope *S, const bool LimitedType,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
ExprResult Diff;
QualType VarType = LCDecl->getType().getNonReferenceType();
if (VarType->isIntegerType() || VarType->isPointerType() ||
SemaRef.getLangOpts().CPlusPlus) {
// Upper - Lower
Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB;
Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB;
Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
if (!Upper || !Lower)
return nullptr;
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
if (!Diff.isUsable() && VarType->getAsCXXRecordDecl()) {
// BuildBinOp already emitted error, this one is to point user to upper
// and lower bound, and to tell what is passed to 'operator-'.
SemaRef.Diag(Upper->getBeginLoc(), diag::err_omp_loop_diff_cxx)
<< Upper->getSourceRange() << Lower->getSourceRange();
return nullptr;
}
}
if (!Diff.isUsable())
return nullptr;
// Upper - Lower [- 1]
if (TestIsStrictOp)
Diff = SemaRef.BuildBinOp(
S, DefaultLoc, BO_Sub, Diff.get(),
SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
if (!Diff.isUsable())
return nullptr;
// Upper - Lower [- 1] + Step
ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
if (!NewStep.isUsable())
return nullptr;
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get());
if (!Diff.isUsable())
return nullptr;
// Parentheses (for dumping/debugging purposes only).
Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
if (!Diff.isUsable())
return nullptr;
// (Upper - Lower [- 1] + Step) / Step
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
if (!Diff.isUsable())
return nullptr;
// OpenMP runtime requires 32-bit or 64-bit loop variables.
QualType Type = Diff.get()->getType();
ASTContext &C = SemaRef.Context;
bool UseVarType = VarType->hasIntegerRepresentation() &&
C.getTypeSize(Type) > C.getTypeSize(VarType);
if (!Type->isIntegerType() || UseVarType) {
unsigned NewSize =
UseVarType ? C.getTypeSize(VarType) : C.getTypeSize(Type);
bool IsSigned = UseVarType ? VarType->hasSignedIntegerRepresentation()
: Type->hasSignedIntegerRepresentation();
Type = C.getIntTypeForBitwidth(NewSize, IsSigned);
if (!SemaRef.Context.hasSameType(Diff.get()->getType(), Type)) {
Diff = SemaRef.PerformImplicitConversion(
Diff.get(), Type, Sema::AA_Converting, /*AllowExplicit=*/true);
if (!Diff.isUsable())
return nullptr;
}
}
if (LimitedType) {
unsigned NewSize = (C.getTypeSize(Type) > 32) ? 64 : 32;
if (NewSize != C.getTypeSize(Type)) {
if (NewSize < C.getTypeSize(Type)) {
assert(NewSize == 64 && "incorrect loop var size");
SemaRef.Diag(DefaultLoc, diag::warn_omp_loop_64_bit_var)
<< InitSrcRange << ConditionSrcRange;
}
QualType NewType = C.getIntTypeForBitwidth(
NewSize, Type->hasSignedIntegerRepresentation() ||
C.getTypeSize(Type) < NewSize);
if (!SemaRef.Context.hasSameType(Diff.get()->getType(), NewType)) {
Diff = SemaRef.PerformImplicitConversion(Diff.get(), NewType,
Sema::AA_Converting, true);
if (!Diff.isUsable())
return nullptr;
}
}
}
return Diff.get();
}
Expr *OpenMPIterationSpaceChecker::buildPreCond(
Scope *S, Expr *Cond,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
// Try to build LB <op> UB, where <op> is <, >, <=, or >=.
bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics();
SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
ExprResult NewLB = tryBuildCapture(SemaRef, LB, Captures);
ExprResult NewUB = tryBuildCapture(SemaRef, UB, Captures);
if (!NewLB.isUsable() || !NewUB.isUsable())
return nullptr;
ExprResult CondExpr =
SemaRef.BuildBinOp(S, DefaultLoc,
TestIsLessOp.getValue() ?
(TestIsStrictOp ? BO_LT : BO_LE) :
(TestIsStrictOp ? BO_GT : BO_GE),
NewLB.get(), NewUB.get());
if (CondExpr.isUsable()) {
if (!SemaRef.Context.hasSameUnqualifiedType(CondExpr.get()->getType(),
SemaRef.Context.BoolTy))
CondExpr = SemaRef.PerformImplicitConversion(
CondExpr.get(), SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting,
/*AllowExplicit=*/true);
}
SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress);
// Otherwise use original loop conditon and evaluate it in runtime.
return CondExpr.isUsable() ? CondExpr.get() : Cond;
}
/// Build reference expression to the counter be used for codegen.
DeclRefExpr *OpenMPIterationSpaceChecker::buildCounterVar(
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
DSAStackTy &DSA) const {
auto *VD = dyn_cast<VarDecl>(LCDecl);
if (!VD) {
VD = SemaRef.isOpenMPCapturedDecl(LCDecl);
DeclRefExpr *Ref = buildDeclRefExpr(
SemaRef, VD, VD->getType().getNonReferenceType(), DefaultLoc);
const DSAStackTy::DSAVarData Data =
DSA.getTopDSA(LCDecl, /*FromParent=*/false);
// If the loop control decl is explicitly marked as private, do not mark it
// as captured again.
if (!isOpenMPPrivate(Data.CKind) || !Data.RefExpr)
Captures.insert(std::make_pair(LCRef, Ref));
return Ref;
}
- return buildDeclRefExpr(SemaRef, VD, VD->getType().getNonReferenceType(),
- DefaultLoc);
+ return cast<DeclRefExpr>(LCRef);
}
Expr *OpenMPIterationSpaceChecker::buildPrivateCounterVar() const {
if (LCDecl && !LCDecl->isInvalidDecl()) {
QualType Type = LCDecl->getType().getNonReferenceType();
VarDecl *PrivateVar = buildVarDecl(
SemaRef, DefaultLoc, Type, LCDecl->getName(),
LCDecl->hasAttrs() ? &LCDecl->getAttrs() : nullptr,
isa<VarDecl>(LCDecl)
? buildDeclRefExpr(SemaRef, cast<VarDecl>(LCDecl), Type, DefaultLoc)
: nullptr);
if (PrivateVar->isInvalidDecl())
return nullptr;
return buildDeclRefExpr(SemaRef, PrivateVar, Type, DefaultLoc);
}
return nullptr;
}
/// Build initialization of the counter to be used for codegen.
Expr *OpenMPIterationSpaceChecker::buildCounterInit() const { return LB; }
/// Build step of the counter be used for codegen.
Expr *OpenMPIterationSpaceChecker::buildCounterStep() const { return Step; }
Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
Scope *S, Expr *Counter,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, SourceLocation Loc,
Expr *Inc, OverloadedOperatorKind OOK) {
Expr *Cnt = SemaRef.DefaultLvalueConversion(Counter).get();
if (!Cnt)
return nullptr;
if (Inc) {
assert((OOK == OO_Plus || OOK == OO_Minus) &&
"Expected only + or - operations for depend clauses.");
BinaryOperatorKind BOK = (OOK == OO_Plus) ? BO_Add : BO_Sub;
Cnt = SemaRef.BuildBinOp(S, Loc, BOK, Cnt, Inc).get();
if (!Cnt)
return nullptr;
}
ExprResult Diff;
QualType VarType = LCDecl->getType().getNonReferenceType();
if (VarType->isIntegerType() || VarType->isPointerType() ||
SemaRef.getLangOpts().CPlusPlus) {
// Upper - Lower
Expr *Upper =
TestIsLessOp.getValue() ? Cnt : tryBuildCapture(SemaRef, UB, Captures).get();
Expr *Lower =
TestIsLessOp.getValue() ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt;
if (!Upper || !Lower)
return nullptr;
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
if (!Diff.isUsable() && VarType->getAsCXXRecordDecl()) {
// BuildBinOp already emitted error, this one is to point user to upper
// and lower bound, and to tell what is passed to 'operator-'.
SemaRef.Diag(Upper->getBeginLoc(), diag::err_omp_loop_diff_cxx)
<< Upper->getSourceRange() << Lower->getSourceRange();
return nullptr;
}
}
if (!Diff.isUsable())
return nullptr;
// Parentheses (for dumping/debugging purposes only).
Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
if (!Diff.isUsable())
return nullptr;
ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
if (!NewStep.isUsable())
return nullptr;
// (Upper - Lower) / Step
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
if (!Diff.isUsable())
return nullptr;
return Diff.get();
}
/// Iteration space of a single for loop.
struct LoopIterationSpace final {
/// Condition of the loop.
Expr *PreCond = nullptr;
/// This expression calculates the number of iterations in the loop.
/// It is always possible to calculate it before starting the loop.
Expr *NumIterations = nullptr;
/// The loop counter variable.
Expr *CounterVar = nullptr;
/// Private loop counter variable.
Expr *PrivateCounterVar = nullptr;
/// This is initializer for the initial value of #CounterVar.
Expr *CounterInit = nullptr;
/// This is step for the #CounterVar used to generate its update:
/// #CounterVar = #CounterInit + #CounterStep * CurrentIteration.
Expr *CounterStep = nullptr;
/// Should step be subtracted?
bool Subtract = false;
/// Source range of the loop init.
SourceRange InitSrcRange;
/// Source range of the loop condition.
SourceRange CondSrcRange;
/// Source range of the loop increment.
SourceRange IncSrcRange;
};
} // namespace
void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
assert(getLangOpts().OpenMP && "OpenMP is not active.");
assert(Init && "Expected loop in canonical form.");
unsigned AssociatedLoops = DSAStack->getAssociatedLoops();
if (AssociatedLoops > 0 &&
isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
DSAStack->loopStart();
OpenMPIterationSpaceChecker ISC(*this, ForLoc);
if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) {
if (ValueDecl *D = ISC.getLoopDecl()) {
auto *VD = dyn_cast<VarDecl>(D);
if (!VD) {
if (VarDecl *Private = isOpenMPCapturedDecl(D)) {
VD = Private;
} else {
DeclRefExpr *Ref = buildCapture(*this, D, ISC.getLoopDeclRefExpr(),
/*WithInit=*/false);
VD = cast<VarDecl>(Ref->getDecl());
}
}
DSAStack->addLoopControlVariable(D, VD);
const Decl *LD = DSAStack->getPossiblyLoopCunter();
if (LD != D->getCanonicalDecl()) {
DSAStack->resetPossibleLoopCounter();
if (auto *Var = dyn_cast_or_null<VarDecl>(LD))
MarkDeclarationsReferencedInExpr(
buildDeclRefExpr(*this, const_cast<VarDecl *>(Var),
Var->getType().getNonLValueExprType(Context),
ForLoc, /*RefersToCapture=*/true));
}
}
}
DSAStack->setAssociatedLoops(AssociatedLoops - 1);
}
}
/// Called on a for stmt to check and extract its iteration space
/// for further processing (such as collapsing).
static bool checkOpenMPIterationSpace(
OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA,
unsigned CurrentNestedLoopCount, unsigned NestedLoopCount,
unsigned TotalNestedLoopCount, Expr *CollapseLoopCountExpr,
Expr *OrderedLoopCountExpr,
Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA,
LoopIterationSpace &ResultIterSpace,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
// OpenMP [2.6, Canonical Loop Form]
// for (init-expr; test-expr; incr-expr) structured-block
auto *For = dyn_cast_or_null<ForStmt>(S);
if (!For) {
SemaRef.Diag(S->getBeginLoc(), diag::err_omp_not_for)
<< (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr)
<< getOpenMPDirectiveName(DKind) << TotalNestedLoopCount
<< (CurrentNestedLoopCount > 0) << CurrentNestedLoopCount;
if (TotalNestedLoopCount > 1) {
if (CollapseLoopCountExpr && OrderedLoopCountExpr)
SemaRef.Diag(DSA.getConstructLoc(),
diag::note_omp_collapse_ordered_expr)
<< 2 << CollapseLoopCountExpr->getSourceRange()
<< OrderedLoopCountExpr->getSourceRange();
else if (CollapseLoopCountExpr)
SemaRef.Diag(CollapseLoopCountExpr->getExprLoc(),
diag::note_omp_collapse_ordered_expr)
<< 0 << CollapseLoopCountExpr->getSourceRange();
else
SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(),
diag::note_omp_collapse_ordered_expr)
<< 1 << OrderedLoopCountExpr->getSourceRange();
}
return true;
}
assert(For->getBody());
OpenMPIterationSpaceChecker ISC(SemaRef, For->getForLoc());
// Check init.
Stmt *Init = For->getInit();
if (ISC.checkAndSetInit(Init))
return true;
bool HasErrors = false;
// Check loop variable's type.
if (ValueDecl *LCDecl = ISC.getLoopDecl()) {
Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr();
// OpenMP [2.6, Canonical Loop Form]
// Var is one of the following:
// A variable of signed or unsigned integer type.
// For C++, a variable of a random access iterator type.
// For C, a variable of a pointer type.
QualType VarType = LCDecl->getType().getNonReferenceType();
if (!VarType->isDependentType() && !VarType->isIntegerType() &&
!VarType->isPointerType() &&
!(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) {
SemaRef.Diag(Init->getBeginLoc(), diag::err_omp_loop_variable_type)
<< SemaRef.getLangOpts().CPlusPlus;
HasErrors = true;
}
// OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in
// a Construct
// The loop iteration variable(s) in the associated for-loop(s) of a for or
// parallel for construct is (are) private.
// The loop iteration variable in the associated for-loop of a simd
// construct with just one associated for-loop is linear with a
// constant-linear-step that is the increment of the associated for-loop.
// Exclude loop var from the list of variables with implicitly defined data
// sharing attributes.
VarsWithImplicitDSA.erase(LCDecl);
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++].
// The loop iteration variable in the associated for-loop of a simd
// construct with just one associated for-loop may be listed in a linear
// clause with a constant-linear-step that is the increment of the
// associated for-loop.
// The loop iteration variable(s) in the associated for-loop(s) of a for or
// parallel for construct may be listed in a private or lastprivate clause.
DSAStackTy::DSAVarData DVar = DSA.getTopDSA(LCDecl, false);
// If LoopVarRefExpr is nullptr it means the corresponding loop variable is
// declared in the loop and it is predetermined as a private.
OpenMPClauseKind PredeterminedCKind =
isOpenMPSimdDirective(DKind)
? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate)
: OMPC_private;
if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
DVar.CKind != PredeterminedCKind) ||
((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop ||
isOpenMPDistributeDirective(DKind)) &&
!isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
(DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
SemaRef.Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa)
<< getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(PredeterminedCKind);
if (DVar.RefExpr == nullptr)
DVar.CKind = PredeterminedCKind;
reportOriginalDsa(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true);
HasErrors = true;
} else if (LoopDeclRefExpr != nullptr) {
// Make the loop iteration variable private (for worksharing constructs),
// linear (for simd directives with the only one associated loop) or
// lastprivate (for simd directives with several collapsed or ordered
// loops).
if (DVar.CKind == OMPC_unknown)
DVar = DSA.hasDSA(LCDecl, isOpenMPPrivate,
[](OpenMPDirectiveKind) -> bool { return true; },
/*FromParent=*/false);
DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind);
}
assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars");
// Check test-expr.
HasErrors |= ISC.checkAndSetCond(For->getCond());
// Check incr-expr.
HasErrors |= ISC.checkAndSetInc(For->getInc());
}
if (ISC.dependent() || SemaRef.CurContext->isDependentContext() || HasErrors)
return HasErrors;
// Build the loop's iteration space representation.
ResultIterSpace.PreCond =
ISC.buildPreCond(DSA.getCurScope(), For->getCond(), Captures);
ResultIterSpace.NumIterations = ISC.buildNumIterations(
DSA.getCurScope(),
(isOpenMPWorksharingDirective(DKind) ||
isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)),
Captures);
ResultIterSpace.CounterVar = ISC.buildCounterVar(Captures, DSA);
ResultIterSpace.PrivateCounterVar = ISC.buildPrivateCounterVar();
ResultIterSpace.CounterInit = ISC.buildCounterInit();
ResultIterSpace.CounterStep = ISC.buildCounterStep();
ResultIterSpace.InitSrcRange = ISC.getInitSrcRange();
ResultIterSpace.CondSrcRange = ISC.getConditionSrcRange();
ResultIterSpace.IncSrcRange = ISC.getIncrementSrcRange();
ResultIterSpace.Subtract = ISC.shouldSubtractStep();
HasErrors |= (ResultIterSpace.PreCond == nullptr ||
ResultIterSpace.NumIterations == nullptr ||
ResultIterSpace.CounterVar == nullptr ||
ResultIterSpace.PrivateCounterVar == nullptr ||
ResultIterSpace.CounterInit == nullptr ||
ResultIterSpace.CounterStep == nullptr);
if (!HasErrors && DSA.isOrderedRegion()) {
if (DSA.getOrderedRegionParam().second->getNumForLoops()) {
if (CurrentNestedLoopCount <
DSA.getOrderedRegionParam().second->getLoopNumIterations().size()) {
DSA.getOrderedRegionParam().second->setLoopNumIterations(
CurrentNestedLoopCount, ResultIterSpace.NumIterations);
DSA.getOrderedRegionParam().second->setLoopCounter(
CurrentNestedLoopCount, ResultIterSpace.CounterVar);
}
}
for (auto &Pair : DSA.getDoacrossDependClauses()) {
if (CurrentNestedLoopCount >= Pair.first->getNumLoops()) {
// Erroneous case - clause has some problems.
continue;
}
if (Pair.first->getDependencyKind() == OMPC_DEPEND_sink &&
Pair.second.size() <= CurrentNestedLoopCount) {
// Erroneous case - clause has some problems.
Pair.first->setLoopData(CurrentNestedLoopCount, nullptr);
continue;
}
Expr *CntValue;
if (Pair.first->getDependencyKind() == OMPC_DEPEND_source)
CntValue = ISC.buildOrderedLoopData(
DSA.getCurScope(), ResultIterSpace.CounterVar, Captures,
Pair.first->getDependencyLoc());
else
CntValue = ISC.buildOrderedLoopData(
DSA.getCurScope(), ResultIterSpace.CounterVar, Captures,
Pair.first->getDependencyLoc(),
Pair.second[CurrentNestedLoopCount].first,
Pair.second[CurrentNestedLoopCount].second);
Pair.first->setLoopData(CurrentNestedLoopCount, CntValue);
}
}
return HasErrors;
}
/// Build 'VarRef = Start.
static ExprResult
buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
ExprResult Start,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
// Build 'VarRef = Start.
ExprResult NewStart = tryBuildCapture(SemaRef, Start.get(), Captures);
if (!NewStart.isUsable())
return ExprError();
if (!SemaRef.Context.hasSameType(NewStart.get()->getType(),
VarRef.get()->getType())) {
NewStart = SemaRef.PerformImplicitConversion(
NewStart.get(), VarRef.get()->getType(), Sema::AA_Converting,
/*AllowExplicit=*/true);
if (!NewStart.isUsable())
return ExprError();
}
ExprResult Init =
SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), NewStart.get());
return Init;
}
/// Build 'VarRef = Start + Iter * Step'.
static ExprResult buildCounterUpdate(
Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
ExprResult Start, ExprResult Iter, ExprResult Step, bool Subtract,
llvm::MapVector<const Expr *, DeclRefExpr *> *Captures = nullptr) {
// Add parentheses (for debugging purposes only).
Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get());
if (!VarRef.isUsable() || !Start.isUsable() || !Iter.isUsable() ||
!Step.isUsable())
return ExprError();
ExprResult NewStep = Step;
if (Captures)
NewStep = tryBuildCapture(SemaRef, Step.get(), *Captures);
if (NewStep.isInvalid())
return ExprError();
ExprResult Update =
SemaRef.BuildBinOp(S, Loc, BO_Mul, Iter.get(), NewStep.get());
if (!Update.isUsable())
return ExprError();
// Try to build 'VarRef = Start, VarRef (+|-)= Iter * Step' or
// 'VarRef = Start (+|-) Iter * Step'.
ExprResult NewStart = Start;
if (Captures)
NewStart = tryBuildCapture(SemaRef, Start.get(), *Captures);
if (NewStart.isInvalid())
return ExprError();
// First attempt: try to build 'VarRef = Start, VarRef += Iter * Step'.
ExprResult SavedUpdate = Update;
ExprResult UpdateVal;
if (VarRef.get()->getType()->isOverloadableType() ||
NewStart.get()->getType()->isOverloadableType() ||
Update.get()->getType()->isOverloadableType()) {
bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics();
SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
Update =
SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), NewStart.get());
if (Update.isUsable()) {
UpdateVal =
SemaRef.BuildBinOp(S, Loc, Subtract ? BO_SubAssign : BO_AddAssign,
VarRef.get(), SavedUpdate.get());
if (UpdateVal.isUsable()) {
Update = SemaRef.CreateBuiltinBinOp(Loc, BO_Comma, Update.get(),
UpdateVal.get());
}
}
SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress);
}
// Second attempt: try to build 'VarRef = Start (+|-) Iter * Step'.
if (!Update.isUsable() || !UpdateVal.isUsable()) {
Update = SemaRef.BuildBinOp(S, Loc, Subtract ? BO_Sub : BO_Add,
NewStart.get(), SavedUpdate.get());
if (!Update.isUsable())
return ExprError();
if (!SemaRef.Context.hasSameType(Update.get()->getType(),
VarRef.get()->getType())) {
Update = SemaRef.PerformImplicitConversion(
Update.get(), VarRef.get()->getType(), Sema::AA_Converting, true);
if (!Update.isUsable())
return ExprError();
}
Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), Update.get());
}
return Update;
}
/// Convert integer expression \a E to make it have at least \a Bits
/// bits.
static ExprResult widenIterationCount(unsigned Bits, Expr *E, Sema &SemaRef) {
if (E == nullptr)
return ExprError();
ASTContext &C = SemaRef.Context;
QualType OldType = E->getType();
unsigned HasBits = C.getTypeSize(OldType);
if (HasBits >= Bits)
return ExprResult(E);
// OK to convert to signed, because new type has more bits than old.
QualType NewType = C.getIntTypeForBitwidth(Bits, /* Signed */ true);
return SemaRef.PerformImplicitConversion(E, NewType, Sema::AA_Converting,
true);
}
/// Check if the given expression \a E is a constant integer that fits
/// into \a Bits bits.
static bool fitsInto(unsigned Bits, bool Signed, const Expr *E, Sema &SemaRef) {
if (E == nullptr)
return false;
llvm::APSInt Result;
if (E->isIntegerConstantExpr(Result, SemaRef.Context))
return Signed ? Result.isSignedIntN(Bits) : Result.isIntN(Bits);
return false;
}
/// Build preinits statement for the given declarations.
static Stmt *buildPreInits(ASTContext &Context,
MutableArrayRef<Decl *> PreInits) {
if (!PreInits.empty()) {
return new (Context) DeclStmt(
DeclGroupRef::Create(Context, PreInits.begin(), PreInits.size()),
SourceLocation(), SourceLocation());
}
return nullptr;
}
/// Build preinits statement for the given declarations.
static Stmt *
buildPreInits(ASTContext &Context,
const llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
if (!Captures.empty()) {
SmallVector<Decl *, 16> PreInits;
for (const auto &Pair : Captures)
PreInits.push_back(Pair.second->getDecl());
return buildPreInits(Context, PreInits);
}
return nullptr;
}
/// Build postupdate expression for the given list of postupdates expressions.
static Expr *buildPostUpdate(Sema &S, ArrayRef<Expr *> PostUpdates) {
Expr *PostUpdate = nullptr;
if (!PostUpdates.empty()) {
for (Expr *E : PostUpdates) {
Expr *ConvE = S.BuildCStyleCastExpr(
E->getExprLoc(),
S.Context.getTrivialTypeSourceInfo(S.Context.VoidTy),
E->getExprLoc(), E)
.get();
PostUpdate = PostUpdate
? S.CreateBuiltinBinOp(ConvE->getExprLoc(), BO_Comma,
PostUpdate, ConvE)
.get()
: ConvE;
}
}
return PostUpdate;
}
/// Called on a for stmt to check itself and nested loops (if any).
/// \return Returns 0 if one of the collapsed stmts is not canonical for loop,
/// number of collapsed loops otherwise.
static unsigned
checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Expr *OrderedLoopCountExpr, Stmt *AStmt, Sema &SemaRef,
DSAStackTy &DSA,
Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA,
OMPLoopDirective::HelperExprs &Built) {
unsigned NestedLoopCount = 1;
if (CollapseLoopCountExpr) {
// Found 'collapse' clause - calculate collapse number.
Expr::EvalResult Result;
if (CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
NestedLoopCount = Result.Val.getInt().getLimitedValue();
}
unsigned OrderedLoopCount = 1;
if (OrderedLoopCountExpr) {
// Found 'ordered' clause - calculate collapse number.
Expr::EvalResult EVResult;
if (OrderedLoopCountExpr->EvaluateAsInt(EVResult, SemaRef.getASTContext())) {
llvm::APSInt Result = EVResult.Val.getInt();
if (Result.getLimitedValue() < NestedLoopCount) {
SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(),
diag::err_omp_wrong_ordered_loop_count)
<< OrderedLoopCountExpr->getSourceRange();
SemaRef.Diag(CollapseLoopCountExpr->getExprLoc(),
diag::note_collapse_loop_count)
<< CollapseLoopCountExpr->getSourceRange();
}
OrderedLoopCount = Result.getLimitedValue();
}
}
// This is helper routine for loop directives (e.g., 'for', 'simd',
// 'for simd', etc.).
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
SmallVector<LoopIterationSpace, 4> IterSpaces;
IterSpaces.resize(std::max(OrderedLoopCount, NestedLoopCount));
Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true);
for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
if (checkOpenMPIterationSpace(
DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount,
std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr,
OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt],
Captures))
return 0;
// Move on to the next nested for loop, or to the loop body.
// OpenMP [2.8.1, simd construct, Restrictions]
// All loops associated with the construct must be perfectly nested; that
// is, there must be no intervening code nor any OpenMP directive between
// any two loops.
CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
}
for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) {
if (checkOpenMPIterationSpace(
DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount,
std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr,
OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt],
Captures))
return 0;
if (Cnt > 0 && IterSpaces[Cnt].CounterVar) {
// Handle initialization of captured loop iterator variables.
auto *DRE = cast<DeclRefExpr>(IterSpaces[Cnt].CounterVar);
if (isa<OMPCapturedExprDecl>(DRE->getDecl())) {
Captures[DRE] = DRE;
}
}
// Move on to the next nested for loop, or to the loop body.
// OpenMP [2.8.1, simd construct, Restrictions]
// All loops associated with the construct must be perfectly nested; that
// is, there must be no intervening code nor any OpenMP directive between
// any two loops.
CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
}
Built.clear(/* size */ NestedLoopCount);
if (SemaRef.CurContext->isDependentContext())
return NestedLoopCount;
// An example of what is generated for the following code:
//
// #pragma omp simd collapse(2) ordered(2)
// for (i = 0; i < NI; ++i)
// for (k = 0; k < NK; ++k)
// for (j = J0; j < NJ; j+=2) {
// <loop body>
// }
//
// We generate the code below.
// Note: the loop body may be outlined in CodeGen.
// Note: some counters may be C++ classes, operator- is used to find number of
// iterations and operator+= to calculate counter value.
// Note: decltype(NumIterations) must be integer type (in 'omp for', only i32
// or i64 is currently supported).
//
// #define NumIterations (NI * ((NJ - J0 - 1 + 2) / 2))
// for (int[32|64]_t IV = 0; IV < NumIterations; ++IV ) {
// .local.i = IV / ((NJ - J0 - 1 + 2) / 2);
// .local.j = J0 + (IV % ((NJ - J0 - 1 + 2) / 2)) * 2;
// // similar updates for vars in clauses (e.g. 'linear')
// <loop body (using local i and j)>
// }
// i = NI; // assign final values of counters
// j = NJ;
//
// Last iteration number is (I1 * I2 * ... In) - 1, where I1, I2 ... In are
// the iteration counts of the collapsed for loops.
// Precondition tests if there is at least one iteration (all conditions are
// true).
auto PreCond = ExprResult(IterSpaces[0].PreCond);
Expr *N0 = IterSpaces[0].NumIterations;
ExprResult LastIteration32 =
widenIterationCount(/*Bits=*/32,
SemaRef
.PerformImplicitConversion(
N0->IgnoreImpCasts(), N0->getType(),
Sema::AA_Converting, /*AllowExplicit=*/true)
.get(),
SemaRef);
ExprResult LastIteration64 = widenIterationCount(
/*Bits=*/64,
SemaRef
.PerformImplicitConversion(N0->IgnoreImpCasts(), N0->getType(),
Sema::AA_Converting,
/*AllowExplicit=*/true)
.get(),
SemaRef);
if (!LastIteration32.isUsable() || !LastIteration64.isUsable())
return NestedLoopCount;
ASTContext &C = SemaRef.Context;
bool AllCountsNeedLessThan32Bits = C.getTypeSize(N0->getType()) < 32;
Scope *CurScope = DSA.getCurScope();
for (unsigned Cnt = 1; Cnt < NestedLoopCount; ++Cnt) {
if (PreCond.isUsable()) {
PreCond =
SemaRef.BuildBinOp(CurScope, PreCond.get()->getExprLoc(), BO_LAnd,
PreCond.get(), IterSpaces[Cnt].PreCond);
}
Expr *N = IterSpaces[Cnt].NumIterations;
SourceLocation Loc = N->getExprLoc();
AllCountsNeedLessThan32Bits &= C.getTypeSize(N->getType()) < 32;
if (LastIteration32.isUsable())
LastIteration32 = SemaRef.BuildBinOp(
CurScope, Loc, BO_Mul, LastIteration32.get(),
SemaRef
.PerformImplicitConversion(N->IgnoreImpCasts(), N->getType(),
Sema::AA_Converting,
/*AllowExplicit=*/true)
.get());
if (LastIteration64.isUsable())
LastIteration64 = SemaRef.BuildBinOp(
CurScope, Loc, BO_Mul, LastIteration64.get(),
SemaRef
.PerformImplicitConversion(N->IgnoreImpCasts(), N->getType(),
Sema::AA_Converting,
/*AllowExplicit=*/true)
.get());
}
// Choose either the 32-bit or 64-bit version.
ExprResult LastIteration = LastIteration64;
if (SemaRef.getLangOpts().OpenMPOptimisticCollapse ||
(LastIteration32.isUsable() &&
C.getTypeSize(LastIteration32.get()->getType()) == 32 &&
(AllCountsNeedLessThan32Bits || NestedLoopCount == 1 ||
fitsInto(
/*Bits=*/32,
LastIteration32.get()->getType()->hasSignedIntegerRepresentation(),
LastIteration64.get(), SemaRef))))
LastIteration = LastIteration32;
QualType VType = LastIteration.get()->getType();
QualType RealVType = VType;
QualType StrideVType = VType;
if (isOpenMPTaskLoopDirective(DKind)) {
VType =
SemaRef.Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0);
StrideVType =
SemaRef.Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
}
if (!LastIteration.isUsable())
return 0;
// Save the number of iterations.
ExprResult NumIterations = LastIteration;
{
LastIteration = SemaRef.BuildBinOp(
CurScope, LastIteration.get()->getExprLoc(), BO_Sub,
LastIteration.get(),
SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
if (!LastIteration.isUsable())
return 0;
}
// Calculate the last iteration number beforehand instead of doing this on
// each iteration. Do not do this if the number of iterations may be kfold-ed.
llvm::APSInt Result;
bool IsConstant =
LastIteration.get()->isIntegerConstantExpr(Result, SemaRef.Context);
ExprResult CalcLastIteration;
if (!IsConstant) {
ExprResult SaveRef =
tryBuildCapture(SemaRef, LastIteration.get(), Captures);
LastIteration = SaveRef;
// Prepare SaveRef + 1.
NumIterations = SemaRef.BuildBinOp(
CurScope, SaveRef.get()->getExprLoc(), BO_Add, SaveRef.get(),
SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
if (!NumIterations.isUsable())
return 0;
}
SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin();
// Build variables passed into runtime, necessary for worksharing directives.
ExprResult LB, UB, IL, ST, EUB, CombLB, CombUB, PrevLB, PrevUB, CombEUB;
if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
isOpenMPDistributeDirective(DKind)) {
// Lower bound variable, initialized with zero.
VarDecl *LBDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.lb");
LB = buildDeclRefExpr(SemaRef, LBDecl, VType, InitLoc);
SemaRef.AddInitializerToDecl(LBDecl,
SemaRef.ActOnIntegerConstant(InitLoc, 0).get(),
/*DirectInit*/ false);
// Upper bound variable, initialized with last iteration number.
VarDecl *UBDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.ub");
UB = buildDeclRefExpr(SemaRef, UBDecl, VType, InitLoc);
SemaRef.AddInitializerToDecl(UBDecl, LastIteration.get(),
/*DirectInit*/ false);
// A 32-bit variable-flag where runtime returns 1 for the last iteration.
// This will be used to implement clause 'lastprivate'.
QualType Int32Ty = SemaRef.Context.getIntTypeForBitwidth(32, true);
VarDecl *ILDecl = buildVarDecl(SemaRef, InitLoc, Int32Ty, ".omp.is_last");
IL = buildDeclRefExpr(SemaRef, ILDecl, Int32Ty, InitLoc);
SemaRef.AddInitializerToDecl(ILDecl,
SemaRef.ActOnIntegerConstant(InitLoc, 0).get(),
/*DirectInit*/ false);
// Stride variable returned by runtime (we initialize it to 1 by default).
VarDecl *STDecl =
buildVarDecl(SemaRef, InitLoc, StrideVType, ".omp.stride");
ST = buildDeclRefExpr(SemaRef, STDecl, StrideVType, InitLoc);
SemaRef.AddInitializerToDecl(STDecl,
SemaRef.ActOnIntegerConstant(InitLoc, 1).get(),
/*DirectInit*/ false);
// Build expression: UB = min(UB, LastIteration)
// It is necessary for CodeGen of directives with static scheduling.
ExprResult IsUBGreater = SemaRef.BuildBinOp(CurScope, InitLoc, BO_GT,
UB.get(), LastIteration.get());
ExprResult CondOp = SemaRef.ActOnConditionalOp(
LastIteration.get()->getExprLoc(), InitLoc, IsUBGreater.get(),
LastIteration.get(), UB.get());
EUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, UB.get(),
CondOp.get());
EUB = SemaRef.ActOnFinishFullExpr(EUB.get());
// If we have a combined directive that combines 'distribute', 'for' or
// 'simd' we need to be able to access the bounds of the schedule of the
// enclosing region. E.g. in 'distribute parallel for' the bounds obtained
// by scheduling 'distribute' have to be passed to the schedule of 'for'.
if (isOpenMPLoopBoundSharingDirective(DKind)) {
// Lower bound variable, initialized with zero.
VarDecl *CombLBDecl =
buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.lb");
CombLB = buildDeclRefExpr(SemaRef, CombLBDecl, VType, InitLoc);
SemaRef.AddInitializerToDecl(
CombLBDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(),
/*DirectInit*/ false);
// Upper bound variable, initialized with last iteration number.
VarDecl *CombUBDecl =
buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.ub");
CombUB = buildDeclRefExpr(SemaRef, CombUBDecl, VType, InitLoc);
SemaRef.AddInitializerToDecl(CombUBDecl, LastIteration.get(),
/*DirectInit*/ false);
ExprResult CombIsUBGreater = SemaRef.BuildBinOp(
CurScope, InitLoc, BO_GT, CombUB.get(), LastIteration.get());
ExprResult CombCondOp =
SemaRef.ActOnConditionalOp(InitLoc, InitLoc, CombIsUBGreater.get(),
LastIteration.get(), CombUB.get());
CombEUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, CombUB.get(),
CombCondOp.get());
CombEUB = SemaRef.ActOnFinishFullExpr(CombEUB.get());
const CapturedDecl *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl();
// We expect to have at least 2 more parameters than the 'parallel'
// directive does - the lower and upper bounds of the previous schedule.
assert(CD->getNumParams() >= 4 &&
"Unexpected number of parameters in loop combined directive");
// Set the proper type for the bounds given what we learned from the
// enclosed loops.
ImplicitParamDecl *PrevLBDecl = CD->getParam(/*PrevLB=*/2);
ImplicitParamDecl *PrevUBDecl = CD->getParam(/*PrevUB=*/3);
// Previous lower and upper bounds are obtained from the region
// parameters.
PrevLB =
buildDeclRefExpr(SemaRef, PrevLBDecl, PrevLBDecl->getType(), InitLoc);
PrevUB =
buildDeclRefExpr(SemaRef, PrevUBDecl, PrevUBDecl->getType(), InitLoc);
}
}
// Build the iteration variable and its initialization before loop.
ExprResult IV;
ExprResult Init, CombInit;
{
VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv");
IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc);
Expr *RHS =
(isOpenMPWorksharingDirective(DKind) ||
isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind))
? LB.get()
: SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get();
Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS);
Init = SemaRef.ActOnFinishFullExpr(Init.get());
if (isOpenMPLoopBoundSharingDirective(DKind)) {
Expr *CombRHS =
(isOpenMPWorksharingDirective(DKind) ||
isOpenMPTaskLoopDirective(DKind) ||
isOpenMPDistributeDirective(DKind))
? CombLB.get()
: SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get();
CombInit =
SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), CombRHS);
CombInit = SemaRef.ActOnFinishFullExpr(CombInit.get());
}
}
// Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops.
SourceLocation CondLoc = AStmt->getBeginLoc();
ExprResult Cond =
(isOpenMPWorksharingDirective(DKind) ||
isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind))
? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get())
: SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(),
NumIterations.get());
ExprResult CombDistCond;
if (isOpenMPLoopBoundSharingDirective(DKind)) {
CombDistCond =
SemaRef.BuildBinOp(
CurScope, CondLoc, BO_LT, IV.get(), NumIterations.get());
}
ExprResult CombCond;
if (isOpenMPLoopBoundSharingDirective(DKind)) {
CombCond =
SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), CombUB.get());
}
// Loop increment (IV = IV + 1)
SourceLocation IncLoc = AStmt->getBeginLoc();
ExprResult Inc =
SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, IV.get(),
SemaRef.ActOnIntegerConstant(IncLoc, 1).get());
if (!Inc.isUsable())
return 0;
Inc = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, IV.get(), Inc.get());
Inc = SemaRef.ActOnFinishFullExpr(Inc.get());
if (!Inc.isUsable())
return 0;
// Increments for worksharing loops (LB = LB + ST; UB = UB + ST).
// Used for directives with static scheduling.
// In combined construct, add combined version that use CombLB and CombUB
// base variables for the update
ExprResult NextLB, NextUB, CombNextLB, CombNextUB;
if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
isOpenMPDistributeDirective(DKind)) {
// LB + ST
NextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, LB.get(), ST.get());
if (!NextLB.isUsable())
return 0;
// LB = LB + ST
NextLB =
SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, LB.get(), NextLB.get());
NextLB = SemaRef.ActOnFinishFullExpr(NextLB.get());
if (!NextLB.isUsable())
return 0;
// UB + ST
NextUB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, UB.get(), ST.get());
if (!NextUB.isUsable())
return 0;
// UB = UB + ST
NextUB =
SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, UB.get(), NextUB.get());
NextUB = SemaRef.ActOnFinishFullExpr(NextUB.get());
if (!NextUB.isUsable())
return 0;
if (isOpenMPLoopBoundSharingDirective(DKind)) {
CombNextLB =
SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, CombLB.get(), ST.get());
if (!NextLB.isUsable())
return 0;
// LB = LB + ST
CombNextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, CombLB.get(),
CombNextLB.get());
CombNextLB = SemaRef.ActOnFinishFullExpr(CombNextLB.get());
if (!CombNextLB.isUsable())
return 0;
// UB + ST
CombNextUB =
SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, CombUB.get(), ST.get());
if (!CombNextUB.isUsable())
return 0;
// UB = UB + ST
CombNextUB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, CombUB.get(),
CombNextUB.get());
CombNextUB = SemaRef.ActOnFinishFullExpr(CombNextUB.get());
if (!CombNextUB.isUsable())
return 0;
}
}
// Create increment expression for distribute loop when combined in a same
// directive with for as IV = IV + ST; ensure upper bound expression based
// on PrevUB instead of NumIterations - used to implement 'for' when found
// in combination with 'distribute', like in 'distribute parallel for'
SourceLocation DistIncLoc = AStmt->getBeginLoc();
ExprResult DistCond, DistInc, PrevEUB, ParForInDistCond;
if (isOpenMPLoopBoundSharingDirective(DKind)) {
DistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get());
assert(DistCond.isUsable() && "distribute cond expr was not built");
DistInc =
SemaRef.BuildBinOp(CurScope, DistIncLoc, BO_Add, IV.get(), ST.get());
assert(DistInc.isUsable() && "distribute inc expr was not built");
DistInc = SemaRef.BuildBinOp(CurScope, DistIncLoc, BO_Assign, IV.get(),
DistInc.get());
DistInc = SemaRef.ActOnFinishFullExpr(DistInc.get());
assert(DistInc.isUsable() && "distribute inc expr was not built");
// Build expression: UB = min(UB, prevUB) for #for in composite or combined
// construct
SourceLocation DistEUBLoc = AStmt->getBeginLoc();
ExprResult IsUBGreater =
SemaRef.BuildBinOp(CurScope, DistEUBLoc, BO_GT, UB.get(), PrevUB.get());
ExprResult CondOp = SemaRef.ActOnConditionalOp(
DistEUBLoc, DistEUBLoc, IsUBGreater.get(), PrevUB.get(), UB.get());
PrevEUB = SemaRef.BuildBinOp(CurScope, DistIncLoc, BO_Assign, UB.get(),
CondOp.get());
PrevEUB = SemaRef.ActOnFinishFullExpr(PrevEUB.get());
// Build IV <= PrevUB to be used in parallel for is in combination with
// a distribute directive with schedule(static, 1)
ParForInDistCond =
SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), PrevUB.get());
}
// Build updates and final values of the loop counters.
bool HasErrors = false;
Built.Counters.resize(NestedLoopCount);
Built.Inits.resize(NestedLoopCount);
Built.Updates.resize(NestedLoopCount);
Built.Finals.resize(NestedLoopCount);
{
// We implement the following algorithm for obtaining the
// original loop iteration variable values based on the
// value of the collapsed loop iteration variable IV.
//
// Let n+1 be the number of collapsed loops in the nest.
// Iteration variables (I0, I1, .... In)
// Iteration counts (N0, N1, ... Nn)
//
// Acc = IV;
//
// To compute Ik for loop k, 0 <= k <= n, generate:
// Prod = N(k+1) * N(k+2) * ... * Nn;
// Ik = Acc / Prod;
// Acc -= Ik * Prod;
//
ExprResult Acc = IV;
for (unsigned int Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
LoopIterationSpace &IS = IterSpaces[Cnt];
SourceLocation UpdLoc = IS.IncSrcRange.getBegin();
ExprResult Iter;
// Compute prod
ExprResult Prod =
SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get();
for (unsigned int K = Cnt+1; K < NestedLoopCount; ++K)
Prod = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Mul, Prod.get(),
IterSpaces[K].NumIterations);
// Iter = Acc / Prod
// If there is at least one more inner loop to avoid
// multiplication by 1.
if (Cnt + 1 < NestedLoopCount)
Iter = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Div,
Acc.get(), Prod.get());
else
Iter = Acc;
if (!Iter.isUsable()) {
HasErrors = true;
break;
}
// Update Acc:
// Acc -= Iter * Prod
// Check if there is at least one more inner loop to avoid
// multiplication by 1.
if (Cnt + 1 < NestedLoopCount)
Prod = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Mul,
Iter.get(), Prod.get());
else
Prod = Iter;
Acc = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Sub,
Acc.get(), Prod.get());
// Build update: IS.CounterVar(Private) = IS.Start + Iter * IS.Step
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IS.CounterVar)->getDecl());
DeclRefExpr *CounterVar = buildDeclRefExpr(
SemaRef, VD, IS.CounterVar->getType(), IS.CounterVar->getExprLoc(),
/*RefersToCapture=*/true);
ExprResult Init = buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar,
IS.CounterInit, Captures);
if (!Init.isUsable()) {
HasErrors = true;
break;
}
ExprResult Update = buildCounterUpdate(
SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter,
IS.CounterStep, IS.Subtract, &Captures);
if (!Update.isUsable()) {
HasErrors = true;
break;
}
// Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step
ExprResult Final = buildCounterUpdate(
SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit,
IS.NumIterations, IS.CounterStep, IS.Subtract, &Captures);
if (!Final.isUsable()) {
HasErrors = true;
break;
}
if (!Update.isUsable() || !Final.isUsable()) {
HasErrors = true;
break;
}
// Save results
Built.Counters[Cnt] = IS.CounterVar;
Built.PrivateCounters[Cnt] = IS.PrivateCounterVar;
Built.Inits[Cnt] = Init.get();
Built.Updates[Cnt] = Update.get();
Built.Finals[Cnt] = Final.get();
}
}
if (HasErrors)
return 0;
// Save results
Built.IterationVarRef = IV.get();
Built.LastIteration = LastIteration.get();
Built.NumIterations = NumIterations.get();
Built.CalcLastIteration =
SemaRef.ActOnFinishFullExpr(CalcLastIteration.get()).get();
Built.PreCond = PreCond.get();
Built.PreInits = buildPreInits(C, Captures);
Built.Cond = Cond.get();
Built.Init = Init.get();
Built.Inc = Inc.get();
Built.LB = LB.get();
Built.UB = UB.get();
Built.IL = IL.get();
Built.ST = ST.get();
Built.EUB = EUB.get();
Built.NLB = NextLB.get();
Built.NUB = NextUB.get();
Built.PrevLB = PrevLB.get();
Built.PrevUB = PrevUB.get();
Built.DistInc = DistInc.get();
Built.PrevEUB = PrevEUB.get();
Built.DistCombinedFields.LB = CombLB.get();
Built.DistCombinedFields.UB = CombUB.get();
Built.DistCombinedFields.EUB = CombEUB.get();
Built.DistCombinedFields.Init = CombInit.get();
Built.DistCombinedFields.Cond = CombCond.get();
Built.DistCombinedFields.NLB = CombNextLB.get();
Built.DistCombinedFields.NUB = CombNextUB.get();
Built.DistCombinedFields.DistCond = CombDistCond.get();
Built.DistCombinedFields.ParForInDistCond = ParForInDistCond.get();
return NestedLoopCount;
}
static Expr *getCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) {
auto CollapseClauses =
OMPExecutableDirective::getClausesOfKind<OMPCollapseClause>(Clauses);
if (CollapseClauses.begin() != CollapseClauses.end())
return (*CollapseClauses.begin())->getNumForLoops();
return nullptr;
}
static Expr *getOrderedNumberExpr(ArrayRef<OMPClause *> Clauses) {
auto OrderedClauses =
OMPExecutableDirective::getClausesOfKind<OMPOrderedClause>(Clauses);
if (OrderedClauses.begin() != OrderedClauses.end())
return (*OrderedClauses.begin())->getNumForLoops();
return nullptr;
}
static bool checkSimdlenSafelenSpecified(Sema &S,
const ArrayRef<OMPClause *> Clauses) {
const OMPSafelenClause *Safelen = nullptr;
const OMPSimdlenClause *Simdlen = nullptr;
for (const OMPClause *Clause : Clauses) {
if (Clause->getClauseKind() == OMPC_safelen)
Safelen = cast<OMPSafelenClause>(Clause);
else if (Clause->getClauseKind() == OMPC_simdlen)
Simdlen = cast<OMPSimdlenClause>(Clause);
if (Safelen && Simdlen)
break;
}
if (Simdlen && Safelen) {
const Expr *SimdlenLength = Simdlen->getSimdlen();
const Expr *SafelenLength = Safelen->getSafelen();
if (SimdlenLength->isValueDependent() || SimdlenLength->isTypeDependent() ||
SimdlenLength->isInstantiationDependent() ||
SimdlenLength->containsUnexpandedParameterPack())
return false;
if (SafelenLength->isValueDependent() || SafelenLength->isTypeDependent() ||
SafelenLength->isInstantiationDependent() ||
SafelenLength->containsUnexpandedParameterPack())
return false;
Expr::EvalResult SimdlenResult, SafelenResult;
SimdlenLength->EvaluateAsInt(SimdlenResult, S.Context);
SafelenLength->EvaluateAsInt(SafelenResult, S.Context);
llvm::APSInt SimdlenRes = SimdlenResult.Val.getInt();
llvm::APSInt SafelenRes = SafelenResult.Val.getInt();
// OpenMP 4.5 [2.8.1, simd Construct, Restrictions]
// If both simdlen and safelen clauses are specified, the value of the
// simdlen parameter must be less than or equal to the value of the safelen
// parameter.
if (SimdlenRes > SafelenRes) {
S.Diag(SimdlenLength->getExprLoc(),
diag::err_omp_wrong_simdlen_safelen_values)
<< SimdlenLength->getSourceRange() << SafelenLength->getSourceRange();
return true;
}
}
return false;
}
StmtResult
Sema::ActOnOpenMPSimdDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt,
SourceLocation StartLoc, SourceLocation EndLoc,
VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses),
AStmt, *this, *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp simd loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
Clauses, AStmt, B);
}
StmtResult
Sema::ActOnOpenMPForDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt,
SourceLocation StartLoc, SourceLocation EndLoc,
VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_for, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses),
AStmt, *this, *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
setFunctionHasBranchProtectedScope();
return OMPForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
Clauses, AStmt, B, DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPForSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_for_simd, getCollapseNumberExpr(Clauses),
getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for simd loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
return OMPForSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
auto BaseStmt = AStmt;
while (auto *CS = dyn_cast_or_null<CapturedStmt>(BaseStmt))
BaseStmt = CS->getCapturedStmt();
if (auto *C = dyn_cast_or_null<CompoundStmt>(BaseStmt)) {
auto S = C->children();
if (S.begin() == S.end())
return StmtError();
// All associated statements must be '#pragma omp section' except for
// the first one.
for (Stmt *SectionStmt : llvm::make_range(std::next(S.begin()), S.end())) {
if (!SectionStmt || !isa<OMPSectionDirective>(SectionStmt)) {
if (SectionStmt)
Diag(SectionStmt->getBeginLoc(),
diag::err_omp_sections_substmt_not_section);
return StmtError();
}
cast<OMPSectionDirective>(SectionStmt)
->setHasCancel(DSAStack->isCancelRegion());
}
} else {
Diag(AStmt->getBeginLoc(), diag::err_omp_sections_not_compound_stmt);
return StmtError();
}
setFunctionHasBranchProtectedScope();
return OMPSectionsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPSectionDirective(Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
setFunctionHasBranchProtectedScope();
DSAStack->setParentCancelRegion(DSAStack->isCancelRegion());
return OMPSectionDirective::Create(Context, StartLoc, EndLoc, AStmt,
DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
setFunctionHasBranchProtectedScope();
// OpenMP [2.7.3, single Construct, Restrictions]
// The copyprivate clause must not be used with the nowait clause.
const OMPClause *Nowait = nullptr;
const OMPClause *Copyprivate = nullptr;
for (const OMPClause *Clause : Clauses) {
if (Clause->getClauseKind() == OMPC_nowait)
Nowait = Clause;
else if (Clause->getClauseKind() == OMPC_copyprivate)
Copyprivate = Clause;
if (Copyprivate && Nowait) {
Diag(Copyprivate->getBeginLoc(),
diag::err_omp_single_copyprivate_with_nowait);
Diag(Nowait->getBeginLoc(), diag::note_omp_nowait_clause_here);
return StmtError();
}
}
return OMPSingleDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
}
StmtResult Sema::ActOnOpenMPMasterDirective(Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
setFunctionHasBranchProtectedScope();
return OMPMasterDirective::Create(Context, StartLoc, EndLoc, AStmt);
}
StmtResult Sema::ActOnOpenMPCriticalDirective(
const DeclarationNameInfo &DirName, ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
bool ErrorFound = false;
llvm::APSInt Hint;
SourceLocation HintLoc;
bool DependentHint = false;
for (const OMPClause *C : Clauses) {
if (C->getClauseKind() == OMPC_hint) {
if (!DirName.getName()) {
Diag(C->getBeginLoc(), diag::err_omp_hint_clause_no_name);
ErrorFound = true;
}
Expr *E = cast<OMPHintClause>(C)->getHint();
if (E->isTypeDependent() || E->isValueDependent() ||
E->isInstantiationDependent()) {
DependentHint = true;
} else {
Hint = E->EvaluateKnownConstInt(Context);
HintLoc = C->getBeginLoc();
}
}
}
if (ErrorFound)
return StmtError();
const auto Pair = DSAStack->getCriticalWithHint(DirName);
if (Pair.first && DirName.getName() && !DependentHint) {
if (llvm::APSInt::compareValues(Hint, Pair.second) != 0) {
Diag(StartLoc, diag::err_omp_critical_with_hint);
if (HintLoc.isValid())
Diag(HintLoc, diag::note_omp_critical_hint_here)
<< 0 << Hint.toString(/*Radix=*/10, /*Signed=*/false);
else
Diag(StartLoc, diag::note_omp_critical_no_hint) << 0;
if (const auto *C = Pair.first->getSingleClause<OMPHintClause>()) {
Diag(C->getBeginLoc(), diag::note_omp_critical_hint_here)
<< 1
<< C->getHint()->EvaluateKnownConstInt(Context).toString(
/*Radix=*/10, /*Signed=*/false);
} else {
Diag(Pair.first->getBeginLoc(), diag::note_omp_critical_no_hint) << 1;
}
}
}
setFunctionHasBranchProtectedScope();
auto *Dir = OMPCriticalDirective::Create(Context, DirName, StartLoc, EndLoc,
Clauses, AStmt);
if (!Pair.first && DirName.getName() && !DependentHint)
DSAStack->addCriticalWithHint(Dir, Hint);
return Dir;
}
StmtResult Sema::ActOnOpenMPParallelForDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_parallel_for, getCollapseNumberExpr(Clauses),
getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp parallel for loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
setFunctionHasBranchProtectedScope();
return OMPParallelForDirective::Create(Context, StartLoc, EndLoc,
NestedLoopCount, Clauses, AStmt, B,
DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPParallelForSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_parallel_for_simd, getCollapseNumberExpr(Clauses),
getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
return OMPParallelForSimdDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
StmtResult
Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
auto BaseStmt = AStmt;
while (auto *CS = dyn_cast_or_null<CapturedStmt>(BaseStmt))
BaseStmt = CS->getCapturedStmt();
if (auto *C = dyn_cast_or_null<CompoundStmt>(BaseStmt)) {
auto S = C->children();
if (S.begin() == S.end())
return StmtError();
// All associated statements must be '#pragma omp section' except for
// the first one.
for (Stmt *SectionStmt : llvm::make_range(std::next(S.begin()), S.end())) {
if (!SectionStmt || !isa<OMPSectionDirective>(SectionStmt)) {
if (SectionStmt)
Diag(SectionStmt->getBeginLoc(),
diag::err_omp_parallel_sections_substmt_not_section);
return StmtError();
}
cast<OMPSectionDirective>(SectionStmt)
->setHasCancel(DSAStack->isCancelRegion());
}
} else {
Diag(AStmt->getBeginLoc(),
diag::err_omp_parallel_sections_not_compound_stmt);
return StmtError();
}
setFunctionHasBranchProtectedScope();
return OMPParallelSectionsDirective::Create(
Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
setFunctionHasBranchProtectedScope();
return OMPTaskDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc,
SourceLocation EndLoc) {
return OMPTaskyieldDirective::Create(Context, StartLoc, EndLoc);
}
StmtResult Sema::ActOnOpenMPBarrierDirective(SourceLocation StartLoc,
SourceLocation EndLoc) {
return OMPBarrierDirective::Create(Context, StartLoc, EndLoc);
}
StmtResult Sema::ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc,
SourceLocation EndLoc) {
return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc);
}
StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
setFunctionHasBranchProtectedScope();
return OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, Clauses,
AStmt,
DSAStack->getTaskgroupReductionRef());
}
StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc) {
assert(Clauses.size() <= 1 && "Extra clauses in flush directive");
return OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses);
}
StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
const OMPClause *DependFound = nullptr;
const OMPClause *DependSourceClause = nullptr;
const OMPClause *DependSinkClause = nullptr;
bool ErrorFound = false;
const OMPThreadsClause *TC = nullptr;
const OMPSIMDClause *SC = nullptr;
for (const OMPClause *C : Clauses) {
if (auto *DC = dyn_cast<OMPDependClause>(C)) {
DependFound = C;
if (DC->getDependencyKind() == OMPC_DEPEND_source) {
if (DependSourceClause) {
Diag(C->getBeginLoc(), diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(OMPD_ordered)
<< getOpenMPClauseName(OMPC_depend) << 2;
ErrorFound = true;
} else {
DependSourceClause = C;
}
if (DependSinkClause) {
Diag(C->getBeginLoc(), diag::err_omp_depend_sink_source_not_allowed)
<< 0;
ErrorFound = true;
}
} else if (DC->getDependencyKind() == OMPC_DEPEND_sink) {
if (DependSourceClause) {
Diag(C->getBeginLoc(), diag::err_omp_depend_sink_source_not_allowed)
<< 1;
ErrorFound = true;
}
DependSinkClause = C;
}
} else if (C->getClauseKind() == OMPC_threads) {
TC = cast<OMPThreadsClause>(C);
} else if (C->getClauseKind() == OMPC_simd) {
SC = cast<OMPSIMDClause>(C);
}
}
if (!ErrorFound && !SC &&
isOpenMPSimdDirective(DSAStack->getParentDirective())) {
// OpenMP [2.8.1,simd Construct, Restrictions]
// An ordered construct with the simd clause is the only OpenMP construct
// that can appear in the simd region.
Diag(StartLoc, diag::err_omp_prohibited_region_simd);
ErrorFound = true;
} else if (DependFound && (TC || SC)) {
Diag(DependFound->getBeginLoc(), diag::err_omp_depend_clause_thread_simd)
<< getOpenMPClauseName(TC ? TC->getClauseKind() : SC->getClauseKind());
ErrorFound = true;
} else if (DependFound && !DSAStack->getParentOrderedRegionParam().first) {
Diag(DependFound->getBeginLoc(),
diag::err_omp_ordered_directive_without_param);
ErrorFound = true;
} else if (TC || Clauses.empty()) {
if (const Expr *Param = DSAStack->getParentOrderedRegionParam().first) {
SourceLocation ErrLoc = TC ? TC->getBeginLoc() : StartLoc;
Diag(ErrLoc, diag::err_omp_ordered_directive_with_param)
<< (TC != nullptr);
Diag(Param->getBeginLoc(), diag::note_omp_ordered_param);
ErrorFound = true;
}
}
if ((!AStmt && !DependFound) || ErrorFound)
return StmtError();
if (AStmt) {
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
setFunctionHasBranchProtectedScope();
}
return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
}
namespace {
/// Helper class for checking expression in 'omp atomic [update]'
/// construct.
class OpenMPAtomicUpdateChecker {
/// Error results for atomic update expressions.
enum ExprAnalysisErrorCode {
/// A statement is not an expression statement.
NotAnExpression,
/// Expression is not builtin binary or unary operation.
NotABinaryOrUnaryExpression,
/// Unary operation is not post-/pre- increment/decrement operation.
NotAnUnaryIncDecExpression,
/// An expression is not of scalar type.
NotAScalarType,
/// A binary operation is not an assignment operation.
NotAnAssignmentOp,
/// RHS part of the binary operation is not a binary expression.
NotABinaryExpression,
/// RHS part is not additive/multiplicative/shift/biwise binary
/// expression.
NotABinaryOperator,
/// RHS binary operation does not have reference to the updated LHS
/// part.
NotAnUpdateExpression,
/// No errors is found.
NoError
};
/// Reference to Sema.
Sema &SemaRef;
/// A location for note diagnostics (when error is found).
SourceLocation NoteLoc;
/// 'x' lvalue part of the source atomic expression.
Expr *X;
/// 'expr' rvalue part of the source atomic expression.
Expr *E;
/// Helper expression of the form
/// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
/// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
Expr *UpdateExpr;
/// Is 'x' a LHS in a RHS part of full update expression. It is
/// important for non-associative operations.
bool IsXLHSInRHSPart;
BinaryOperatorKind Op;
SourceLocation OpLoc;
/// true if the source expression is a postfix unary operation, false
/// if it is a prefix unary operation.
bool IsPostfixUpdate;
public:
OpenMPAtomicUpdateChecker(Sema &SemaRef)
: SemaRef(SemaRef), X(nullptr), E(nullptr), UpdateExpr(nullptr),
IsXLHSInRHSPart(false), Op(BO_PtrMemD), IsPostfixUpdate(false) {}
/// Check specified statement that it is suitable for 'atomic update'
/// constructs and extract 'x', 'expr' and Operation from the original
/// expression. If DiagId and NoteId == 0, then only check is performed
/// without error notification.
/// \param DiagId Diagnostic which should be emitted if error is found.
/// \param NoteId Diagnostic note for the main error message.
/// \return true if statement is not an update expression, false otherwise.
bool checkStatement(Stmt *S, unsigned DiagId = 0, unsigned NoteId = 0);
/// Return the 'x' lvalue part of the source atomic expression.
Expr *getX() const { return X; }
/// Return the 'expr' rvalue part of the source atomic expression.
Expr *getExpr() const { return E; }
/// Return the update expression used in calculation of the updated
/// value. Always has form 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
/// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
Expr *getUpdateExpr() const { return UpdateExpr; }
/// Return true if 'x' is LHS in RHS part of full update expression,
/// false otherwise.
bool isXLHSInRHSPart() const { return IsXLHSInRHSPart; }
/// true if the source expression is a postfix unary operation, false
/// if it is a prefix unary operation.
bool isPostfixUpdate() const { return IsPostfixUpdate; }
private:
bool checkBinaryOperation(BinaryOperator *AtomicBinOp, unsigned DiagId = 0,
unsigned NoteId = 0);
};
} // namespace
bool OpenMPAtomicUpdateChecker::checkBinaryOperation(
BinaryOperator *AtomicBinOp, unsigned DiagId, unsigned NoteId) {
ExprAnalysisErrorCode ErrorFound = NoError;
SourceLocation ErrorLoc, NoteLoc;
SourceRange ErrorRange, NoteRange;
// Allowed constructs are:
// x = x binop expr;
// x = expr binop x;
if (AtomicBinOp->getOpcode() == BO_Assign) {
X = AtomicBinOp->getLHS();
if (const auto *AtomicInnerBinOp = dyn_cast<BinaryOperator>(
AtomicBinOp->getRHS()->IgnoreParenImpCasts())) {
if (AtomicInnerBinOp->isMultiplicativeOp() ||
AtomicInnerBinOp->isAdditiveOp() || AtomicInnerBinOp->isShiftOp() ||
AtomicInnerBinOp->isBitwiseOp()) {
Op = AtomicInnerBinOp->getOpcode();
OpLoc = AtomicInnerBinOp->getOperatorLoc();
Expr *LHS = AtomicInnerBinOp->getLHS();
Expr *RHS = AtomicInnerBinOp->getRHS();
llvm::FoldingSetNodeID XId, LHSId, RHSId;
X->IgnoreParenImpCasts()->Profile(XId, SemaRef.getASTContext(),
/*Canonical=*/true);
LHS->IgnoreParenImpCasts()->Profile(LHSId, SemaRef.getASTContext(),
/*Canonical=*/true);
RHS->IgnoreParenImpCasts()->Profile(RHSId, SemaRef.getASTContext(),
/*Canonical=*/true);
if (XId == LHSId) {
E = RHS;
IsXLHSInRHSPart = true;
} else if (XId == RHSId) {
E = LHS;
IsXLHSInRHSPart = false;
} else {
ErrorLoc = AtomicInnerBinOp->getExprLoc();
ErrorRange = AtomicInnerBinOp->getSourceRange();
NoteLoc = X->getExprLoc();
NoteRange = X->getSourceRange();
ErrorFound = NotAnUpdateExpression;
}
} else {
ErrorLoc = AtomicInnerBinOp->getExprLoc();
ErrorRange = AtomicInnerBinOp->getSourceRange();
NoteLoc = AtomicInnerBinOp->getOperatorLoc();
NoteRange = SourceRange(NoteLoc, NoteLoc);
ErrorFound = NotABinaryOperator;
}
} else {
NoteLoc = ErrorLoc = AtomicBinOp->getRHS()->getExprLoc();
NoteRange = ErrorRange = AtomicBinOp->getRHS()->getSourceRange();
ErrorFound = NotABinaryExpression;
}
} else {
ErrorLoc = AtomicBinOp->getExprLoc();
ErrorRange = AtomicBinOp->getSourceRange();
NoteLoc = AtomicBinOp->getOperatorLoc();
NoteRange = SourceRange(NoteLoc, NoteLoc);
ErrorFound = NotAnAssignmentOp;
}
if (ErrorFound != NoError && DiagId != 0 && NoteId != 0) {
SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange;
SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange;
return true;
}
if (SemaRef.CurContext->isDependentContext())
E = X = UpdateExpr = nullptr;
return ErrorFound != NoError;
}
bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId,
unsigned NoteId) {
ExprAnalysisErrorCode ErrorFound = NoError;
SourceLocation ErrorLoc, NoteLoc;
SourceRange ErrorRange, NoteRange;
// Allowed constructs are:
// x++;
// x--;
// ++x;
// --x;
// x binop= expr;
// x = x binop expr;
// x = expr binop x;
if (auto *AtomicBody = dyn_cast<Expr>(S)) {
AtomicBody = AtomicBody->IgnoreParenImpCasts();
if (AtomicBody->getType()->isScalarType() ||
AtomicBody->isInstantiationDependent()) {
if (const auto *AtomicCompAssignOp = dyn_cast<CompoundAssignOperator>(
AtomicBody->IgnoreParenImpCasts())) {
// Check for Compound Assignment Operation
Op = BinaryOperator::getOpForCompoundAssignment(
AtomicCompAssignOp->getOpcode());
OpLoc = AtomicCompAssignOp->getOperatorLoc();
E = AtomicCompAssignOp->getRHS();
X = AtomicCompAssignOp->getLHS()->IgnoreParens();
IsXLHSInRHSPart = true;
} else if (auto *AtomicBinOp = dyn_cast<BinaryOperator>(
AtomicBody->IgnoreParenImpCasts())) {
// Check for Binary Operation
if (checkBinaryOperation(AtomicBinOp, DiagId, NoteId))
return true;
} else if (const auto *AtomicUnaryOp = dyn_cast<UnaryOperator>(
AtomicBody->IgnoreParenImpCasts())) {
// Check for Unary Operation
if (AtomicUnaryOp->isIncrementDecrementOp()) {
IsPostfixUpdate = AtomicUnaryOp->isPostfix();
Op = AtomicUnaryOp->isIncrementOp() ? BO_Add : BO_Sub;
OpLoc = AtomicUnaryOp->getOperatorLoc();
X = AtomicUnaryOp->getSubExpr()->IgnoreParens();
E = SemaRef.ActOnIntegerConstant(OpLoc, /*uint64_t Val=*/1).get();
IsXLHSInRHSPart = true;
} else {
ErrorFound = NotAnUnaryIncDecExpression;
ErrorLoc = AtomicUnaryOp->getExprLoc();
ErrorRange = AtomicUnaryOp->getSourceRange();
NoteLoc = AtomicUnaryOp->getOperatorLoc();
NoteRange = SourceRange(NoteLoc, NoteLoc);
}
} else if (!AtomicBody->isInstantiationDependent()) {
ErrorFound = NotABinaryOrUnaryExpression;
NoteLoc = ErrorLoc = AtomicBody->getExprLoc();
NoteRange = ErrorRange = AtomicBody->getSourceRange();
}
} else {
ErrorFound = NotAScalarType;
NoteLoc = ErrorLoc = AtomicBody->getBeginLoc();
NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
}
} else {
ErrorFound = NotAnExpression;
NoteLoc = ErrorLoc = S->getBeginLoc();
NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
}
if (ErrorFound != NoError && DiagId != 0 && NoteId != 0) {
SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange;
SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange;
return true;
}
if (SemaRef.CurContext->isDependentContext())
E = X = UpdateExpr = nullptr;
if (ErrorFound == NoError && E && X) {
// Build an update expression of form 'OpaqueValueExpr(x) binop
// OpaqueValueExpr(expr)' or 'OpaqueValueExpr(expr) binop
// OpaqueValueExpr(x)' and then cast it to the type of the 'x' expression.
auto *OVEX = new (SemaRef.getASTContext())
OpaqueValueExpr(X->getExprLoc(), X->getType(), VK_RValue);
auto *OVEExpr = new (SemaRef.getASTContext())
OpaqueValueExpr(E->getExprLoc(), E->getType(), VK_RValue);
ExprResult Update =
SemaRef.CreateBuiltinBinOp(OpLoc, Op, IsXLHSInRHSPart ? OVEX : OVEExpr,
IsXLHSInRHSPart ? OVEExpr : OVEX);
if (Update.isInvalid())
return true;
Update = SemaRef.PerformImplicitConversion(Update.get(), X->getType(),
Sema::AA_Casting);
if (Update.isInvalid())
return true;
UpdateExpr = Update.get();
}
return ErrorFound != NoError;
}
StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
OpenMPClauseKind AtomicKind = OMPC_unknown;
SourceLocation AtomicKindLoc;
for (const OMPClause *C : Clauses) {
if (C->getClauseKind() == OMPC_read || C->getClauseKind() == OMPC_write ||
C->getClauseKind() == OMPC_update ||
C->getClauseKind() == OMPC_capture) {
if (AtomicKind != OMPC_unknown) {
Diag(C->getBeginLoc(), diag::err_omp_atomic_several_clauses)
<< SourceRange(C->getBeginLoc(), C->getEndLoc());
Diag(AtomicKindLoc, diag::note_omp_atomic_previous_clause)
<< getOpenMPClauseName(AtomicKind);
} else {
AtomicKind = C->getClauseKind();
AtomicKindLoc = C->getBeginLoc();
}
}
}
Stmt *Body = CS->getCapturedStmt();
if (auto *EWC = dyn_cast<ExprWithCleanups>(Body))
Body = EWC->getSubExpr();
Expr *X = nullptr;
Expr *V = nullptr;
Expr *E = nullptr;
Expr *UE = nullptr;
bool IsXLHSInRHSPart = false;
bool IsPostfixUpdate = false;
// OpenMP [2.12.6, atomic Construct]
// In the next expressions:
// * x and v (as applicable) are both l-value expressions with scalar type.
// * During the execution of an atomic region, multiple syntactic
// occurrences of x must designate the same storage location.
// * Neither of v and expr (as applicable) may access the storage location
// designated by x.
// * Neither of x and expr (as applicable) may access the storage location
// designated by v.
// * expr is an expression with scalar type.
// * binop is one of +, *, -, /, &, ^, |, <<, or >>.
// * binop, binop=, ++, and -- are not overloaded operators.
// * The expression x binop expr must be numerically equivalent to x binop
// (expr). This requirement is satisfied if the operators in expr have
// precedence greater than binop, or by using parentheses around expr or
// subexpressions of expr.
// * The expression expr binop x must be numerically equivalent to (expr)
// binop x. This requirement is satisfied if the operators in expr have
// precedence equal to or greater than binop, or by using parentheses around
// expr or subexpressions of expr.
// * For forms that allow multiple occurrences of x, the number of times
// that x is evaluated is unspecified.
if (AtomicKind == OMPC_read) {
enum {
NotAnExpression,
NotAnAssignmentOp,
NotAScalarType,
NotAnLValue,
NoError
} ErrorFound = NoError;
SourceLocation ErrorLoc, NoteLoc;
SourceRange ErrorRange, NoteRange;
// If clause is read:
// v = x;
if (const auto *AtomicBody = dyn_cast<Expr>(Body)) {
const auto *AtomicBinOp =
dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts());
if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) {
X = AtomicBinOp->getRHS()->IgnoreParenImpCasts();
V = AtomicBinOp->getLHS()->IgnoreParenImpCasts();
if ((X->isInstantiationDependent() || X->getType()->isScalarType()) &&
(V->isInstantiationDependent() || V->getType()->isScalarType())) {
if (!X->isLValue() || !V->isLValue()) {
const Expr *NotLValueExpr = X->isLValue() ? V : X;
ErrorFound = NotAnLValue;
ErrorLoc = AtomicBinOp->getExprLoc();
ErrorRange = AtomicBinOp->getSourceRange();
NoteLoc = NotLValueExpr->getExprLoc();
NoteRange = NotLValueExpr->getSourceRange();
}
} else if (!X->isInstantiationDependent() ||
!V->isInstantiationDependent()) {
const Expr *NotScalarExpr =
(X->isInstantiationDependent() || X->getType()->isScalarType())
? V
: X;
ErrorFound = NotAScalarType;
ErrorLoc = AtomicBinOp->getExprLoc();
ErrorRange = AtomicBinOp->getSourceRange();
NoteLoc = NotScalarExpr->getExprLoc();
NoteRange = NotScalarExpr->getSourceRange();
}
} else if (!AtomicBody->isInstantiationDependent()) {
ErrorFound = NotAnAssignmentOp;
ErrorLoc = AtomicBody->getExprLoc();
ErrorRange = AtomicBody->getSourceRange();
NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc()
: AtomicBody->getExprLoc();
NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange()
: AtomicBody->getSourceRange();
}
} else {
ErrorFound = NotAnExpression;
NoteLoc = ErrorLoc = Body->getBeginLoc();
NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
}
if (ErrorFound != NoError) {
Diag(ErrorLoc, diag::err_omp_atomic_read_not_expression_statement)
<< ErrorRange;
Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound
<< NoteRange;
return StmtError();
}
if (CurContext->isDependentContext())
V = X = nullptr;
} else if (AtomicKind == OMPC_write) {
enum {
NotAnExpression,
NotAnAssignmentOp,
NotAScalarType,
NotAnLValue,
NoError
} ErrorFound = NoError;
SourceLocation ErrorLoc, NoteLoc;
SourceRange ErrorRange, NoteRange;
// If clause is write:
// x = expr;
if (const auto *AtomicBody = dyn_cast<Expr>(Body)) {
const auto *AtomicBinOp =
dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts());
if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) {
X = AtomicBinOp->getLHS();
E = AtomicBinOp->getRHS();
if ((X->isInstantiationDependent() || X->getType()->isScalarType()) &&
(E->isInstantiationDependent() || E->getType()->isScalarType())) {
if (!X->isLValue()) {
ErrorFound = NotAnLValue;
ErrorLoc = AtomicBinOp->getExprLoc();
ErrorRange = AtomicBinOp->getSourceRange();
NoteLoc = X->getExprLoc();
NoteRange = X->getSourceRange();
}
} else if (!X->isInstantiationDependent() ||
!E->isInstantiationDependent()) {
const Expr *NotScalarExpr =
(X->isInstantiationDependent() || X->getType()->isScalarType())
? E
: X;
ErrorFound = NotAScalarType;
ErrorLoc = AtomicBinOp->getExprLoc();
ErrorRange = AtomicBinOp->getSourceRange();
NoteLoc = NotScalarExpr->getExprLoc();
NoteRange = NotScalarExpr->getSourceRange();
}
} else if (!AtomicBody->isInstantiationDependent()) {
ErrorFound = NotAnAssignmentOp;
ErrorLoc = AtomicBody->getExprLoc();
ErrorRange = AtomicBody->getSourceRange();
NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc()
: AtomicBody->getExprLoc();
NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange()
: AtomicBody->getSourceRange();
}
} else {
ErrorFound = NotAnExpression;
NoteLoc = ErrorLoc = Body->getBeginLoc();
NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
}
if (ErrorFound != NoError) {
Diag(ErrorLoc, diag::err_omp_atomic_write_not_expression_statement)
<< ErrorRange;
Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound
<< NoteRange;
return StmtError();
}
if (CurContext->isDependentContext())
E = X = nullptr;
} else if (AtomicKind == OMPC_update || AtomicKind == OMPC_unknown) {
// If clause is update:
// x++;
// x--;
// ++x;
// --x;
// x binop= expr;
// x = x binop expr;
// x = expr binop x;
OpenMPAtomicUpdateChecker Checker(*this);
if (Checker.checkStatement(
Body, (AtomicKind == OMPC_update)
? diag::err_omp_atomic_update_not_expression_statement
: diag::err_omp_atomic_not_expression_statement,
diag::note_omp_atomic_update))
return StmtError();
if (!CurContext->isDependentContext()) {
E = Checker.getExpr();
X = Checker.getX();
UE = Checker.getUpdateExpr();
IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
}
} else if (AtomicKind == OMPC_capture) {
enum {
NotAnAssignmentOp,
NotACompoundStatement,
NotTwoSubstatements,
NotASpecificExpression,
NoError
} ErrorFound = NoError;
SourceLocation ErrorLoc, NoteLoc;
SourceRange ErrorRange, NoteRange;
if (const auto *AtomicBody = dyn_cast<Expr>(Body)) {
// If clause is a capture:
// v = x++;
// v = x--;
// v = ++x;
// v = --x;
// v = x binop= expr;
// v = x = x binop expr;
// v = x = expr binop x;
const auto *AtomicBinOp =
dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts());
if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) {
V = AtomicBinOp->getLHS();
Body = AtomicBinOp->getRHS()->IgnoreParenImpCasts();
OpenMPAtomicUpdateChecker Checker(*this);
if (Checker.checkStatement(
Body, diag::err_omp_atomic_capture_not_expression_statement,
diag::note_omp_atomic_update))
return StmtError();
E = Checker.getExpr();
X = Checker.getX();
UE = Checker.getUpdateExpr();
IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
IsPostfixUpdate = Checker.isPostfixUpdate();
} else if (!AtomicBody->isInstantiationDependent()) {
ErrorLoc = AtomicBody->getExprLoc();
ErrorRange = AtomicBody->getSourceRange();
NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc()
: AtomicBody->getExprLoc();
NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange()
: AtomicBody->getSourceRange();
ErrorFound = NotAnAssignmentOp;
}
if (ErrorFound != NoError) {
Diag(ErrorLoc, diag::err_omp_atomic_capture_not_expression_statement)
<< ErrorRange;
Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange;
return StmtError();
}
if (CurContext->isDependentContext())
UE = V = E = X = nullptr;
} else {
// If clause is a capture:
// { v = x; x = expr; }
// { v = x; x++; }
// { v = x; x--; }
// { v = x; ++x; }
// { v = x; --x; }
// { v = x; x binop= expr; }
// { v = x; x = x binop expr; }
// { v = x; x = expr binop x; }
// { x++; v = x; }
// { x--; v = x; }
// { ++x; v = x; }
// { --x; v = x; }
// { x binop= expr; v = x; }
// { x = x binop expr; v = x; }
// { x = expr binop x; v = x; }
if (auto *CS = dyn_cast<CompoundStmt>(Body)) {
// Check that this is { expr1; expr2; }
if (CS->size() == 2) {
Stmt *First = CS->body_front();
Stmt *Second = CS->body_back();
if (auto *EWC = dyn_cast<ExprWithCleanups>(First))
First = EWC->getSubExpr()->IgnoreParenImpCasts();
if (auto *EWC = dyn_cast<ExprWithCleanups>(Second))
Second = EWC->getSubExpr()->IgnoreParenImpCasts();
// Need to find what subexpression is 'v' and what is 'x'.
OpenMPAtomicUpdateChecker Checker(*this);
bool IsUpdateExprFound = !Checker.checkStatement(Second);
BinaryOperator *BinOp = nullptr;
if (IsUpdateExprFound) {
BinOp = dyn_cast<BinaryOperator>(First);
IsUpdateExprFound = BinOp && BinOp->getOpcode() == BO_Assign;
}
if (IsUpdateExprFound && !CurContext->isDependentContext()) {
// { v = x; x++; }
// { v = x; x--; }
// { v = x; ++x; }
// { v = x; --x; }
// { v = x; x binop= expr; }
// { v = x; x = x binop expr; }
// { v = x; x = expr binop x; }
// Check that the first expression has form v = x.
Expr *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts();
llvm::FoldingSetNodeID XId, PossibleXId;
Checker.getX()->Profile(XId, Context, /*Canonical=*/true);
PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true);
IsUpdateExprFound = XId == PossibleXId;
if (IsUpdateExprFound) {
V = BinOp->getLHS();
X = Checker.getX();
E = Checker.getExpr();
UE = Checker.getUpdateExpr();
IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
IsPostfixUpdate = true;
}
}
if (!IsUpdateExprFound) {
IsUpdateExprFound = !Checker.checkStatement(First);
BinOp = nullptr;
if (IsUpdateExprFound) {
BinOp = dyn_cast<BinaryOperator>(Second);
IsUpdateExprFound = BinOp && BinOp->getOpcode() == BO_Assign;
}
if (IsUpdateExprFound && !CurContext->isDependentContext()) {
// { x++; v = x; }
// { x--; v = x; }
// { ++x; v = x; }
// { --x; v = x; }
// { x binop= expr; v = x; }
// { x = x binop expr; v = x; }
// { x = expr binop x; v = x; }
// Check that the second expression has form v = x.
Expr *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts();
llvm::FoldingSetNodeID XId, PossibleXId;
Checker.getX()->Profile(XId, Context, /*Canonical=*/true);
PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true);
IsUpdateExprFound = XId == PossibleXId;
if (IsUpdateExprFound) {
V = BinOp->getLHS();
X = Checker.getX();
E = Checker.getExpr();
UE = Checker.getUpdateExpr();
IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
IsPostfixUpdate = false;
}
}
}
if (!IsUpdateExprFound) {
// { v = x; x = expr; }
auto *FirstExpr = dyn_cast<Expr>(First);
auto *SecondExpr = dyn_cast<Expr>(Second);
if (!FirstExpr || !SecondExpr ||
!(FirstExpr->isInstantiationDependent() ||
SecondExpr->isInstantiationDependent())) {
auto *FirstBinOp = dyn_cast<BinaryOperator>(First);
if (!FirstBinOp || FirstBinOp->getOpcode() != BO_Assign) {
ErrorFound = NotAnAssignmentOp;
NoteLoc = ErrorLoc = FirstBinOp ? FirstBinOp->getOperatorLoc()
: First->getBeginLoc();
NoteRange = ErrorRange = FirstBinOp
? FirstBinOp->getSourceRange()
: SourceRange(ErrorLoc, ErrorLoc);
} else {
auto *SecondBinOp = dyn_cast<BinaryOperator>(Second);
if (!SecondBinOp || SecondBinOp->getOpcode() != BO_Assign) {
ErrorFound = NotAnAssignmentOp;
NoteLoc = ErrorLoc = SecondBinOp
? SecondBinOp->getOperatorLoc()
: Second->getBeginLoc();
NoteRange = ErrorRange =
SecondBinOp ? SecondBinOp->getSourceRange()
: SourceRange(ErrorLoc, ErrorLoc);
} else {
Expr *PossibleXRHSInFirst =
FirstBinOp->getRHS()->IgnoreParenImpCasts();
Expr *PossibleXLHSInSecond =
SecondBinOp->getLHS()->IgnoreParenImpCasts();
llvm::FoldingSetNodeID X1Id, X2Id;
PossibleXRHSInFirst->Profile(X1Id, Context,
/*Canonical=*/true);
PossibleXLHSInSecond->Profile(X2Id, Context,
/*Canonical=*/true);
IsUpdateExprFound = X1Id == X2Id;
if (IsUpdateExprFound) {
V = FirstBinOp->getLHS();
X = SecondBinOp->getLHS();
E = SecondBinOp->getRHS();
UE = nullptr;
IsXLHSInRHSPart = false;
IsPostfixUpdate = true;
} else {
ErrorFound = NotASpecificExpression;
ErrorLoc = FirstBinOp->getExprLoc();
ErrorRange = FirstBinOp->getSourceRange();
NoteLoc = SecondBinOp->getLHS()->getExprLoc();
NoteRange = SecondBinOp->getRHS()->getSourceRange();
}
}
}
}
}
} else {
NoteLoc = ErrorLoc = Body->getBeginLoc();
NoteRange = ErrorRange =
SourceRange(Body->getBeginLoc(), Body->getBeginLoc());
ErrorFound = NotTwoSubstatements;
}
} else {
NoteLoc = ErrorLoc = Body->getBeginLoc();
NoteRange = ErrorRange =
SourceRange(Body->getBeginLoc(), Body->getBeginLoc());
ErrorFound = NotACompoundStatement;
}
if (ErrorFound != NoError) {
Diag(ErrorLoc, diag::err_omp_atomic_capture_not_compound_statement)
<< ErrorRange;
Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange;
return StmtError();
}
if (CurContext->isDependentContext())
UE = V = E = X = nullptr;
}
}
setFunctionHasBranchProtectedScope();
return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
X, V, E, UE, IsXLHSInRHSPart,
IsPostfixUpdate);
}
StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
// OpenMP [2.16, Nesting of Regions]
// If specified, a teams construct must be contained within a target
// construct. That target construct must contain no statements or directives
// outside of the teams construct.
if (DSAStack->hasInnerTeamsRegion()) {
const Stmt *S = CS->IgnoreContainers(/*IgnoreCaptured=*/true);
bool OMPTeamsFound = true;
if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
auto I = CS->body_begin();
while (I != CS->body_end()) {
const auto *OED = dyn_cast<OMPExecutableDirective>(*I);
if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind())) {
OMPTeamsFound = false;
break;
}
++I;
}
assert(I != CS->body_end() && "Not found statement");
S = *I;
} else {
const auto *OED = dyn_cast<OMPExecutableDirective>(S);
OMPTeamsFound = OED && isOpenMPTeamsDirective(OED->getDirectiveKind());
}
if (!OMPTeamsFound) {
Diag(StartLoc, diag::err_omp_target_contains_not_only_teams);
Diag(DSAStack->getInnerTeamsRegionLoc(),
diag::note_omp_nested_teams_construct_here);
Diag(S->getBeginLoc(), diag::note_omp_nested_statement_here)
<< isa<OMPExecutableDirective>(S);
return StmtError();
}
}
setFunctionHasBranchProtectedScope();
return OMPTargetDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
}
StmtResult
Sema::ActOnOpenMPTargetParallelDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
setFunctionHasBranchProtectedScope();
return OMPTargetParallelDirective::Create(Context, StartLoc, EndLoc, Clauses,
AStmt);
}
StmtResult Sema::ActOnOpenMPTargetParallelForDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel_for);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_target_parallel_for, getCollapseNumberExpr(Clauses),
getOrderedNumberExpr(Clauses), CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp target parallel for loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
setFunctionHasBranchProtectedScope();
return OMPTargetParallelForDirective::Create(Context, StartLoc, EndLoc,
NestedLoopCount, Clauses, AStmt,
B, DSAStack->isCancelRegion());
}
/// Check for existence of a map clause in the list of clauses.
static bool hasClauses(ArrayRef<OMPClause *> Clauses,
const OpenMPClauseKind K) {
return llvm::any_of(
Clauses, [K](const OMPClause *C) { return C->getClauseKind() == K; });
}
template <typename... Params>
static bool hasClauses(ArrayRef<OMPClause *> Clauses, const OpenMPClauseKind K,
const Params... ClauseTypes) {
return hasClauses(Clauses, K) || hasClauses(Clauses, ClauseTypes...);
}
StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
// OpenMP [2.10.1, Restrictions, p. 97]
// At least one map clause must appear on the directive.
if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr)) {
Diag(StartLoc, diag::err_omp_no_clause_for_directive)
<< "'map' or 'use_device_ptr'"
<< getOpenMPDirectiveName(OMPD_target_data);
return StmtError();
}
setFunctionHasBranchProtectedScope();
return OMPTargetDataDirective::Create(Context, StartLoc, EndLoc, Clauses,
AStmt);
}
StmtResult
Sema::ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc, Stmt *AStmt) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_enter_data);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
// OpenMP [2.10.2, Restrictions, p. 99]
// At least one map clause must appear on the directive.
if (!hasClauses(Clauses, OMPC_map)) {
Diag(StartLoc, diag::err_omp_no_clause_for_directive)
<< "'map'" << getOpenMPDirectiveName(OMPD_target_enter_data);
return StmtError();
}
return OMPTargetEnterDataDirective::Create(Context, StartLoc, EndLoc, Clauses,
AStmt);
}
StmtResult
Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc, Stmt *AStmt) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_exit_data);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
// OpenMP [2.10.3, Restrictions, p. 102]
// At least one map clause must appear on the directive.
if (!hasClauses(Clauses, OMPC_map)) {
Diag(StartLoc, diag::err_omp_no_clause_for_directive)
<< "'map'" << getOpenMPDirectiveName(OMPD_target_exit_data);
return StmtError();
}
return OMPTargetExitDataDirective::Create(Context, StartLoc, EndLoc, Clauses,
AStmt);
}
StmtResult Sema::ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc,
Stmt *AStmt) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_update);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
if (!hasClauses(Clauses, OMPC_to, OMPC_from)) {
Diag(StartLoc, diag::err_omp_at_least_one_motion_clause_required);
return StmtError();
}
return OMPTargetUpdateDirective::Create(Context, StartLoc, EndLoc, Clauses,
AStmt);
}
StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
setFunctionHasBranchProtectedScope();
DSAStack->setParentTeamsRegionLoc(StartLoc);
return OMPTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
}
StmtResult
Sema::ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc,
SourceLocation EndLoc,
OpenMPDirectiveKind CancelRegion) {
if (DSAStack->isParentNowaitRegion()) {
Diag(StartLoc, diag::err_omp_parent_cancel_region_nowait) << 0;
return StmtError();
}
if (DSAStack->isParentOrderedRegion()) {
Diag(StartLoc, diag::err_omp_parent_cancel_region_ordered) << 0;
return StmtError();
}
return OMPCancellationPointDirective::Create(Context, StartLoc, EndLoc,
CancelRegion);
}
StmtResult Sema::ActOnOpenMPCancelDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc,
OpenMPDirectiveKind CancelRegion) {
if (DSAStack->isParentNowaitRegion()) {
Diag(StartLoc, diag::err_omp_parent_cancel_region_nowait) << 1;
return StmtError();
}
if (DSAStack->isParentOrderedRegion()) {
Diag(StartLoc, diag::err_omp_parent_cancel_region_ordered) << 1;
return StmtError();
}
DSAStack->setParentCancelRegion(/*Cancel=*/true);
return OMPCancelDirective::Create(Context, StartLoc, EndLoc, Clauses,
CancelRegion);
}
static bool checkGrainsizeNumTasksClauses(Sema &S,
ArrayRef<OMPClause *> Clauses) {
const OMPClause *PrevClause = nullptr;
bool ErrorFound = false;
for (const OMPClause *C : Clauses) {
if (C->getClauseKind() == OMPC_grainsize ||
C->getClauseKind() == OMPC_num_tasks) {
if (!PrevClause)
PrevClause = C;
else if (PrevClause->getClauseKind() != C->getClauseKind()) {
S.Diag(C->getBeginLoc(),
diag::err_omp_grainsize_num_tasks_mutually_exclusive)
<< getOpenMPClauseName(C->getClauseKind())
<< getOpenMPClauseName(PrevClause->getClauseKind());
S.Diag(PrevClause->getBeginLoc(),
diag::note_omp_previous_grainsize_num_tasks)
<< getOpenMPClauseName(PrevClause->getClauseKind());
ErrorFound = true;
}
}
}
return ErrorFound;
}
static bool checkReductionClauseWithNogroup(Sema &S,
ArrayRef<OMPClause *> Clauses) {
const OMPClause *ReductionClause = nullptr;
const OMPClause *NogroupClause = nullptr;
for (const OMPClause *C : Clauses) {
if (C->getClauseKind() == OMPC_reduction) {
ReductionClause = C;
if (NogroupClause)
break;
continue;
}
if (C->getClauseKind() == OMPC_nogroup) {
NogroupClause = C;
if (ReductionClause)
break;
continue;
}
}
if (ReductionClause && NogroupClause) {
S.Diag(ReductionClause->getBeginLoc(), diag::err_omp_reduction_with_nogroup)
<< SourceRange(NogroupClause->getBeginLoc(),
NogroupClause->getEndLoc());
return true;
}
return false;
}
StmtResult Sema::ActOnOpenMPTaskLoopDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_taskloop, getCollapseNumberExpr(Clauses),
/*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
// OpenMP, [2.9.2 taskloop Construct, Restrictions]
// The grainsize clause and num_tasks clause are mutually exclusive and may
// not appear on the same taskloop directive.
if (checkGrainsizeNumTasksClauses(*this, Clauses))
return StmtError();
// OpenMP, [2.9.2 taskloop Construct, Restrictions]
// If a reduction clause is present on the taskloop directive, the nogroup
// clause must not be specified.
if (checkReductionClauseWithNogroup(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc,
NestedLoopCount, Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_taskloop_simd, getCollapseNumberExpr(Clauses),
/*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
// OpenMP, [2.9.2 taskloop Construct, Restrictions]
// The grainsize clause and num_tasks clause are mutually exclusive and may
// not appear on the same taskloop directive.
if (checkGrainsizeNumTasksClauses(*this, Clauses))
return StmtError();
// OpenMP, [2.9.2 taskloop Construct, Restrictions]
// If a reduction clause is present on the taskloop directive, the nogroup
// clause must not be specified.
if (checkReductionClauseWithNogroup(*this, Clauses))
return StmtError();
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
return OMPTaskLoopSimdDirective::Create(Context, StartLoc, EndLoc,
NestedLoopCount, Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPDistributeDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_distribute, getCollapseNumberExpr(Clauses),
nullptr /*ordered not a clause on distribute*/, AStmt,
*this, *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
setFunctionHasBranchProtectedScope();
return OMPDistributeDirective::Create(Context, StartLoc, EndLoc,
NestedLoopCount, Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPDistributeParallelForDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel =
getOpenMPCaptureLevels(OMPD_distribute_parallel_for);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_distribute_parallel_for, getCollapseNumberExpr(Clauses),
nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
setFunctionHasBranchProtectedScope();
return OMPDistributeParallelForDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel =
getOpenMPCaptureLevels(OMPD_distribute_parallel_for_simd);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses),
nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
return OMPDistributeParallelForSimdDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPDistributeSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_distribute_simd);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_distribute_simd, getCollapseNumberExpr(Clauses),
nullptr /*ordered not a clause on distribute*/, CS, *this,
*DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
return OMPDistributeSimdDirective::Create(Context, StartLoc, EndLoc,
NestedLoopCount, Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel_for);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_target_parallel_for_simd, getCollapseNumberExpr(Clauses),
getOrderedNumberExpr(Clauses), CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp target parallel for simd loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
return OMPTargetParallelForSimdDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPTargetSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_simd);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will define the
// nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_target_simd, getCollapseNumberExpr(Clauses),
getOrderedNumberExpr(Clauses), CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp target simd loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
return OMPTargetSimdDirective::Create(Context, StartLoc, EndLoc,
NestedLoopCount, Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPTeamsDistributeDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_teams_distribute);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_teams_distribute, getCollapseNumberExpr(Clauses),
nullptr /*ordered not a clause on distribute*/, CS, *this,
*DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp teams distribute loop exprs were not built");
setFunctionHasBranchProtectedScope();
DSAStack->setParentTeamsRegionLoc(StartLoc);
return OMPTeamsDistributeDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel =
getOpenMPCaptureLevels(OMPD_teams_distribute_simd);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_teams_distribute_simd, getCollapseNumberExpr(Clauses),
nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp teams distribute simd loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
DSAStack->setParentTeamsRegionLoc(StartLoc);
return OMPTeamsDistributeSimdDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel =
getOpenMPCaptureLevels(OMPD_teams_distribute_parallel_for_simd);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_teams_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses),
nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
DSAStack->setParentTeamsRegionLoc(StartLoc);
return OMPTeamsDistributeParallelForSimdDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel =
getOpenMPCaptureLevels(OMPD_teams_distribute_parallel_for);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_teams_distribute_parallel_for, getCollapseNumberExpr(Clauses),
nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
setFunctionHasBranchProtectedScope();
DSAStack->setParentTeamsRegionLoc(StartLoc);
return OMPTeamsDistributeParallelForDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_teams);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
setFunctionHasBranchProtectedScope();
return OMPTargetTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses,
AStmt);
}
StmtResult Sema::ActOnOpenMPTargetTeamsDistributeDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel =
getOpenMPCaptureLevels(OMPD_target_teams_distribute);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_target_teams_distribute, getCollapseNumberExpr(Clauses),
nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp target teams distribute loop exprs were not built");
setFunctionHasBranchProtectedScope();
return OMPTargetTeamsDistributeDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel =
getOpenMPCaptureLevels(OMPD_target_teams_distribute_parallel_for);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_target_teams_distribute_parallel_for, getCollapseNumberExpr(Clauses),
nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp target teams distribute parallel for loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
setFunctionHasBranchProtectedScope();
return OMPTargetTeamsDistributeParallelForDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(
OMPD_target_teams_distribute_parallel_for_simd);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_target_teams_distribute_parallel_for_simd,
getCollapseNumberExpr(Clauses),
nullptr /*ordered not a clause on distribute*/, CS, *this,
*DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp target teams distribute parallel for simd loop exprs were not "
"built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
return OMPTargetTeamsDistributeParallelForSimdDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
StmtResult Sema::ActOnOpenMPTargetTeamsDistributeSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel =
getOpenMPCaptureLevels(OMPD_target_teams_distribute_simd);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
// top and a single exit at the bottom.
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
}
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_target_teams_distribute_simd, getCollapseNumberExpr(Clauses),
nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp target teams distribute simd loop exprs were not built");
if (!CurContext->isDependentContext()) {
// Finalize the clauses that need pre-built expressions for CodeGen.
for (OMPClause *C : Clauses) {
if (auto *LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
B.NumIterations, *this, CurScope,
DSAStack))
return StmtError();
}
}
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
setFunctionHasBranchProtectedScope();
return OMPTargetTeamsDistributeSimdDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_final:
Res = ActOnOpenMPFinalClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_num_threads:
Res = ActOnOpenMPNumThreadsClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_safelen:
Res = ActOnOpenMPSafelenClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_simdlen:
Res = ActOnOpenMPSimdlenClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_collapse:
Res = ActOnOpenMPCollapseClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_ordered:
Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Expr);
break;
case OMPC_device:
Res = ActOnOpenMPDeviceClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_num_teams:
Res = ActOnOpenMPNumTeamsClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_thread_limit:
Res = ActOnOpenMPThreadLimitClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_priority:
Res = ActOnOpenMPPriorityClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_grainsize:
Res = ActOnOpenMPGrainsizeClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_num_tasks:
Res = ActOnOpenMPNumTasksClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_hint:
Res = ActOnOpenMPHintClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_if:
case OMPC_default:
case OMPC_proc_bind:
case OMPC_schedule:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
case OMPC_task_reduction:
case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_nowait:
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
case OMPC_nogroup:
case OMPC_dist_schedule:
case OMPC_defaultmap:
case OMPC_unknown:
case OMPC_uniform:
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
llvm_unreachable("Clause is not allowed.");
}
return Res;
}
// An OpenMP directive such as 'target parallel' has two captured regions:
// for the 'target' and 'parallel' respectively. This function returns
// the region in which to capture expressions associated with a clause.
// A return value of OMPD_unknown signifies that the expression should not
// be captured.
static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
OpenMPDirectiveKind DKind, OpenMPClauseKind CKind,
OpenMPDirectiveKind NameModifier = OMPD_unknown) {
OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
switch (CKind) {
case OMPC_if:
switch (DKind) {
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
// If this clause applies to the nested 'parallel' region, capture within
// the 'target' region, otherwise do not capture.
if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel)
CaptureRegion = OMPD_target;
break;
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
// If this clause applies to the nested 'parallel' region, capture within
// the 'teams' region, otherwise do not capture.
if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel)
CaptureRegion = OMPD_teams;
break;
case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd:
CaptureRegion = OMPD_teams;
break;
case OMPD_target_update:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
CaptureRegion = OMPD_task;
break;
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_target:
case OMPD_target_simd:
case OMPD_target_teams:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_target_data:
// Do not capture if-clause expressions.
break;
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
case OMPD_simd:
case OMPD_for:
case OMPD_for_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
case OMPD_master:
case OMPD_critical:
case OMPD_taskgroup:
case OMPD_distribute:
case OMPD_ordered:
case OMPD_atomic:
case OMPD_distribute_simd:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd:
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with if-clause");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
break;
case OMPC_num_threads:
switch (DKind) {
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
CaptureRegion = OMPD_target;
break;
case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
CaptureRegion = OMPD_teams;
break;
case OMPD_parallel:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
// Do not capture num_threads-clause expressions.
break;
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
case OMPD_target:
case OMPD_target_simd:
case OMPD_target_teams:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd:
case OMPD_cancel:
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
case OMPD_simd:
case OMPD_for:
case OMPD_for_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
case OMPD_master:
case OMPD_critical:
case OMPD_taskgroup:
case OMPD_distribute:
case OMPD_ordered:
case OMPD_atomic:
case OMPD_distribute_simd:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd:
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with num_threads-clause");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
break;
case OMPC_num_teams:
switch (DKind) {
case OMPD_target_teams:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
CaptureRegion = OMPD_target;
break;
case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_teams:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd:
// Do not capture num_teams-clause expressions.
break;
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_target:
case OMPD_target_simd:
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
case OMPD_for:
case OMPD_for_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
case OMPD_master:
case OMPD_critical:
case OMPD_taskgroup:
case OMPD_distribute:
case OMPD_ordered:
case OMPD_atomic:
case OMPD_distribute_simd:
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with num_teams-clause");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
break;
case OMPC_thread_limit:
switch (DKind) {
case OMPD_target_teams:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
CaptureRegion = OMPD_target;
break;
case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_teams:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd:
// Do not capture thread_limit-clause expressions.
break;
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_target:
case OMPD_target_simd:
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
case OMPD_for:
case OMPD_for_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
case OMPD_master:
case OMPD_critical:
case OMPD_taskgroup:
case OMPD_distribute:
case OMPD_ordered:
case OMPD_atomic:
case OMPD_distribute_simd:
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
break;
case OMPC_schedule:
switch (DKind) {
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
CaptureRegion = OMPD_parallel;
break;
case OMPD_for:
case OMPD_for_simd:
// Do not capture schedule-clause expressions.
break;
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
case OMPD_teams:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd:
case OMPD_target:
case OMPD_target_simd:
case OMPD_target_parallel:
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
case OMPD_master:
case OMPD_critical:
case OMPD_taskgroup:
case OMPD_distribute:
case OMPD_ordered:
case OMPD_atomic:
case OMPD_distribute_simd:
case OMPD_target_teams:
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with schedule clause");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
break;
case OMPC_dist_schedule:
switch (DKind) {
case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd:
CaptureRegion = OMPD_teams;
break;
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_distribute:
case OMPD_distribute_simd:
// Do not capture thread_limit-clause expressions.
break;
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_target_parallel_for_simd:
case OMPD_target_parallel_for:
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
case OMPD_teams:
case OMPD_target:
case OMPD_target_simd:
case OMPD_target_parallel:
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
case OMPD_for:
case OMPD_for_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
case OMPD_master:
case OMPD_critical:
case OMPD_taskgroup:
case OMPD_ordered:
case OMPD_atomic:
case OMPD_target_teams:
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with schedule clause");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
break;
case OMPC_device:
switch (DKind) {
case OMPD_target_update:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target:
case OMPD_target_simd:
case OMPD_target_teams:
case OMPD_target_parallel:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
CaptureRegion = OMPD_task;
break;
case OMPD_target_data:
// Do not capture device-clause expressions.
break;
case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_teams:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
case OMPD_for:
case OMPD_for_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
case OMPD_master:
case OMPD_critical:
case OMPD_taskgroup:
case OMPD_distribute:
case OMPD_ordered:
case OMPD_atomic:
case OMPD_distribute_simd:
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with num_teams-clause");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
break;
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_reduction:
case OMPC_task_reduction:
case OMPC_in_reduction:
case OMPC_linear:
case OMPC_default:
case OMPC_proc_bind:
case OMPC_final:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_collapse:
case OMPC_private:
case OMPC_shared:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_ordered:
case OMPC_nowait:
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
case OMPC_priority:
case OMPC_grainsize:
case OMPC_nogroup:
case OMPC_num_tasks:
case OMPC_hint:
case OMPC_defaultmap:
case OMPC_unknown:
case OMPC_uniform:
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
llvm_unreachable("Unexpected OpenMP clause.");
}
return CaptureRegion;
}
OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier,
Expr *Condition, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation NameModifierLoc,
SourceLocation ColonLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Condition;
Stmt *HelperValStmt = nullptr;
OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
!Condition->isInstantiationDependent() &&
!Condition->containsUnexpandedParameterPack()) {
ExprResult Val = CheckBooleanCondition(StartLoc, Condition);
if (Val.isInvalid())
return nullptr;
ValExpr = Val.get();
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
CaptureRegion =
getOpenMPCaptureRegionForClause(DKind, OMPC_if, NameModifier);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
HelperValStmt = buildPreInits(Context, Captures);
}
}
return new (Context)
OMPIfClause(NameModifier, ValExpr, HelperValStmt, CaptureRegion, StartLoc,
LParenLoc, NameModifierLoc, ColonLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Condition;
if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
!Condition->isInstantiationDependent() &&
!Condition->containsUnexpandedParameterPack()) {
ExprResult Val = CheckBooleanCondition(StartLoc, Condition);
if (Val.isInvalid())
return nullptr;
ValExpr = MakeFullExpr(Val.get()).get();
}
return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc);
}
ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc,
Expr *Op) {
if (!Op)
return ExprError();
class IntConvertDiagnoser : public ICEConvertDiagnoser {
public:
IntConvertDiagnoser()
: ICEConvertDiagnoser(/*AllowScopedEnumerations*/ false, false, true) {}
SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
QualType T) override {
return S.Diag(Loc, diag::err_omp_not_integral) << T;
}
SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
QualType T) override {
return S.Diag(Loc, diag::err_omp_incomplete_type) << T;
}
SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc,
QualType T,
QualType ConvTy) override {
return S.Diag(Loc, diag::err_omp_explicit_conversion) << T << ConvTy;
}
SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv,
QualType ConvTy) override {
return S.Diag(Conv->getLocation(), diag::note_omp_conversion_here)
<< ConvTy->isEnumeralType() << ConvTy;
}
SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
QualType T) override {
return S.Diag(Loc, diag::err_omp_ambiguous_conversion) << T;
}
SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
QualType ConvTy) override {
return S.Diag(Conv->getLocation(), diag::note_omp_conversion_here)
<< ConvTy->isEnumeralType() << ConvTy;
}
SemaDiagnosticBuilder diagnoseConversion(Sema &, SourceLocation, QualType,
QualType) override {
llvm_unreachable("conversion functions are permitted");
}
} ConvertDiagnoser;
return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser);
}
static bool isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef,
OpenMPClauseKind CKind,
bool StrictlyPositive) {
if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() &&
!ValExpr->isInstantiationDependent()) {
SourceLocation Loc = ValExpr->getExprLoc();
ExprResult Value =
SemaRef.PerformOpenMPImplicitIntegerConversion(Loc, ValExpr);
if (Value.isInvalid())
return false;
ValExpr = Value.get();
// The expression must evaluate to a non-negative integer value.
llvm::APSInt Result;
if (ValExpr->isIntegerConstantExpr(Result, SemaRef.Context) &&
Result.isSigned() &&
!((!StrictlyPositive && Result.isNonNegative()) ||
(StrictlyPositive && Result.isStrictlyPositive()))) {
SemaRef.Diag(Loc, diag::err_omp_negative_expression_in_clause)
<< getOpenMPClauseName(CKind) << (StrictlyPositive ? 1 : 0)
<< ValExpr->getSourceRange();
return false;
}
}
return true;
}
OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = NumThreads;
Stmt *HelperValStmt = nullptr;
// OpenMP [2.5, Restrictions]
// The num_threads expression must evaluate to a positive integer value.
if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_num_threads,
/*StrictlyPositive=*/true))
return nullptr;
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
HelperValStmt = buildPreInits(Context, Captures);
}
return new (Context) OMPNumThreadsClause(
ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
}
ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E,
OpenMPClauseKind CKind,
bool StrictlyPositive) {
if (!E)
return ExprError();
if (E->isValueDependent() || E->isTypeDependent() ||
E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
return E;
llvm::APSInt Result;
ExprResult ICE = VerifyIntegerConstantExpression(E, &Result);
if (ICE.isInvalid())
return ExprError();
if ((StrictlyPositive && !Result.isStrictlyPositive()) ||
(!StrictlyPositive && !Result.isNonNegative())) {
Diag(E->getExprLoc(), diag::err_omp_negative_expression_in_clause)
<< getOpenMPClauseName(CKind) << (StrictlyPositive ? 1 : 0)
<< E->getSourceRange();
return ExprError();
}
if (CKind == OMPC_aligned && !Result.isPowerOf2()) {
Diag(E->getExprLoc(), diag::warn_omp_alignment_not_power_of_two)
<< E->getSourceRange();
return ExprError();
}
if (CKind == OMPC_collapse && DSAStack->getAssociatedLoops() == 1)
DSAStack->setAssociatedLoops(Result.getExtValue());
else if (CKind == OMPC_ordered)
DSAStack->setAssociatedLoops(Result.getExtValue());
return ICE;
}
OMPClause *Sema::ActOnOpenMPSafelenClause(Expr *Len, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
// OpenMP [2.8.1, simd construct, Description]
// The parameter of the safelen clause must be a constant
// positive integer expression.
ExprResult Safelen = VerifyPositiveIntegerConstantInClause(Len, OMPC_safelen);
if (Safelen.isInvalid())
return nullptr;
return new (Context)
OMPSafelenClause(Safelen.get(), StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPSimdlenClause(Expr *Len, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
// OpenMP [2.8.1, simd construct, Description]
// The parameter of the simdlen clause must be a constant
// positive integer expression.
ExprResult Simdlen = VerifyPositiveIntegerConstantInClause(Len, OMPC_simdlen);
if (Simdlen.isInvalid())
return nullptr;
return new (Context)
OMPSimdlenClause(Simdlen.get(), StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumForLoops,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
// OpenMP [2.7.1, loop construct, Description]
// OpenMP [2.8.1, simd construct, Description]
// OpenMP [2.9.6, distribute construct, Description]
// The parameter of the collapse clause must be a constant
// positive integer expression.
ExprResult NumForLoopsResult =
VerifyPositiveIntegerConstantInClause(NumForLoops, OMPC_collapse);
if (NumForLoopsResult.isInvalid())
return nullptr;
return new (Context)
OMPCollapseClause(NumForLoopsResult.get(), StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc,
SourceLocation EndLoc,
SourceLocation LParenLoc,
Expr *NumForLoops) {
// OpenMP [2.7.1, loop construct, Description]
// OpenMP [2.8.1, simd construct, Description]
// OpenMP [2.9.6, distribute construct, Description]
// The parameter of the ordered clause must be a constant
// positive integer expression if any.
if (NumForLoops && LParenLoc.isValid()) {
ExprResult NumForLoopsResult =
VerifyPositiveIntegerConstantInClause(NumForLoops, OMPC_ordered);
if (NumForLoopsResult.isInvalid())
return nullptr;
NumForLoops = NumForLoopsResult.get();
} else {
NumForLoops = nullptr;
}
auto *Clause = OMPOrderedClause::Create(
Context, NumForLoops, NumForLoops ? DSAStack->getAssociatedLoops() : 0,
StartLoc, LParenLoc, EndLoc);
DSAStack->setOrderedRegion(/*IsOrdered=*/true, NumForLoops, Clause);
return Clause;
}
OMPClause *Sema::ActOnOpenMPSimpleClause(
OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc,
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_default:
Res =
ActOnOpenMPDefaultClause(static_cast<OpenMPDefaultClauseKind>(Argument),
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_proc_bind:
Res = ActOnOpenMPProcBindClause(
static_cast<OpenMPProcBindClauseKind>(Argument), ArgumentLoc, StartLoc,
LParenLoc, EndLoc);
break;
case OMPC_atomic_default_mem_order:
Res = ActOnOpenMPAtomicDefaultMemOrderClause(
static_cast<OpenMPAtomicDefaultMemOrderClauseKind>(Argument),
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_collapse:
case OMPC_schedule:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
case OMPC_task_reduction:
case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_ordered:
case OMPC_nowait:
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
case OMPC_depend:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
case OMPC_num_teams:
case OMPC_thread_limit:
case OMPC_priority:
case OMPC_grainsize:
case OMPC_nogroup:
case OMPC_num_tasks:
case OMPC_hint:
case OMPC_dist_schedule:
case OMPC_defaultmap:
case OMPC_unknown:
case OMPC_uniform:
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
llvm_unreachable("Clause is not allowed.");
}
return Res;
}
static std::string
getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last,
ArrayRef<unsigned> Exclude = llvm::None) {
SmallString<256> Buffer;
llvm::raw_svector_ostream Out(Buffer);
unsigned Bound = Last >= 2 ? Last - 2 : 0;
unsigned Skipped = Exclude.size();
auto S = Exclude.begin(), E = Exclude.end();
for (unsigned I = First; I < Last; ++I) {
if (std::find(S, E, I) != E) {
--Skipped;
continue;
}
Out << "'" << getOpenMPSimpleClauseTypeName(K, I) << "'";
if (I == Bound - Skipped)
Out << " or ";
else if (I != Bound + 1 - Skipped)
Out << ", ";
}
return Out.str();
}
OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
SourceLocation KindKwLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
if (Kind == OMPC_DEFAULT_unknown) {
static_assert(OMPC_DEFAULT_unknown > 0,
"OMPC_DEFAULT_unknown not greater than 0");
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
<< getListOfPossibleValues(OMPC_default, /*First=*/0,
/*Last=*/OMPC_DEFAULT_unknown)
<< getOpenMPClauseName(OMPC_default);
return nullptr;
}
switch (Kind) {
case OMPC_DEFAULT_none:
DSAStack->setDefaultDSANone(KindKwLoc);
break;
case OMPC_DEFAULT_shared:
DSAStack->setDefaultDSAShared(KindKwLoc);
break;
case OMPC_DEFAULT_unknown:
llvm_unreachable("Clause kind is not allowed.");
break;
}
return new (Context)
OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind,
SourceLocation KindKwLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
if (Kind == OMPC_PROC_BIND_unknown) {
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
<< getListOfPossibleValues(OMPC_proc_bind, /*First=*/0,
/*Last=*/OMPC_PROC_BIND_unknown)
<< getOpenMPClauseName(OMPC_proc_bind);
return nullptr;
}
return new (Context)
OMPProcBindClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPAtomicDefaultMemOrderClause(
OpenMPAtomicDefaultMemOrderClauseKind Kind, SourceLocation KindKwLoc,
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
if (Kind == OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown) {
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
<< getListOfPossibleValues(
OMPC_atomic_default_mem_order, /*First=*/0,
/*Last=*/OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown)
<< getOpenMPClauseName(OMPC_atomic_default_mem_order);
return nullptr;
}
return new (Context) OMPAtomicDefaultMemOrderClause(Kind, KindKwLoc, StartLoc,
LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
OpenMPClauseKind Kind, ArrayRef<unsigned> Argument, Expr *Expr,
SourceLocation StartLoc, SourceLocation LParenLoc,
ArrayRef<SourceLocation> ArgumentLoc, SourceLocation DelimLoc,
SourceLocation EndLoc) {
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_schedule:
enum { Modifier1, Modifier2, ScheduleKind, NumberOfElements };
assert(Argument.size() == NumberOfElements &&
ArgumentLoc.size() == NumberOfElements);
Res = ActOnOpenMPScheduleClause(
static_cast<OpenMPScheduleClauseModifier>(Argument[Modifier1]),
static_cast<OpenMPScheduleClauseModifier>(Argument[Modifier2]),
static_cast<OpenMPScheduleClauseKind>(Argument[ScheduleKind]), Expr,
StartLoc, LParenLoc, ArgumentLoc[Modifier1], ArgumentLoc[Modifier2],
ArgumentLoc[ScheduleKind], DelimLoc, EndLoc);
break;
case OMPC_if:
assert(Argument.size() == 1 && ArgumentLoc.size() == 1);
Res = ActOnOpenMPIfClause(static_cast<OpenMPDirectiveKind>(Argument.back()),
Expr, StartLoc, LParenLoc, ArgumentLoc.back(),
DelimLoc, EndLoc);
break;
case OMPC_dist_schedule:
Res = ActOnOpenMPDistScheduleClause(
static_cast<OpenMPDistScheduleClauseKind>(Argument.back()), Expr,
StartLoc, LParenLoc, ArgumentLoc.back(), DelimLoc, EndLoc);
break;
case OMPC_defaultmap:
enum { Modifier, DefaultmapKind };
Res = ActOnOpenMPDefaultmapClause(
static_cast<OpenMPDefaultmapClauseModifier>(Argument[Modifier]),
static_cast<OpenMPDefaultmapClauseKind>(Argument[DefaultmapKind]),
StartLoc, LParenLoc, ArgumentLoc[Modifier], ArgumentLoc[DefaultmapKind],
EndLoc);
break;
case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_collapse:
case OMPC_default:
case OMPC_proc_bind:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
case OMPC_task_reduction:
case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_ordered:
case OMPC_nowait:
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
case OMPC_depend:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
case OMPC_num_teams:
case OMPC_thread_limit:
case OMPC_priority:
case OMPC_grainsize:
case OMPC_nogroup:
case OMPC_num_tasks:
case OMPC_hint:
case OMPC_unknown:
case OMPC_uniform:
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
llvm_unreachable("Clause is not allowed.");
}
return Res;
}
static bool checkScheduleModifiers(Sema &S, OpenMPScheduleClauseModifier M1,
OpenMPScheduleClauseModifier M2,
SourceLocation M1Loc, SourceLocation M2Loc) {
if (M1 == OMPC_SCHEDULE_MODIFIER_unknown && M1Loc.isValid()) {
SmallVector<unsigned, 2> Excluded;
if (M2 != OMPC_SCHEDULE_MODIFIER_unknown)
Excluded.push_back(M2);
if (M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic)
Excluded.push_back(OMPC_SCHEDULE_MODIFIER_monotonic);
if (M2 == OMPC_SCHEDULE_MODIFIER_monotonic)
Excluded.push_back(OMPC_SCHEDULE_MODIFIER_nonmonotonic);
S.Diag(M1Loc, diag::err_omp_unexpected_clause_value)
<< getListOfPossibleValues(OMPC_schedule,
/*First=*/OMPC_SCHEDULE_MODIFIER_unknown + 1,
/*Last=*/OMPC_SCHEDULE_MODIFIER_last,
Excluded)
<< getOpenMPClauseName(OMPC_schedule);
return true;
}
return false;
}
OMPClause *Sema::ActOnOpenMPScheduleClause(
OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2,
OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc,
SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc) {
if (checkScheduleModifiers(*this, M1, M2, M1Loc, M2Loc) ||
checkScheduleModifiers(*this, M2, M1, M2Loc, M1Loc))
return nullptr;
// OpenMP, 2.7.1, Loop Construct, Restrictions
// Either the monotonic modifier or the nonmonotonic modifier can be specified
// but not both.
if ((M1 == M2 && M1 != OMPC_SCHEDULE_MODIFIER_unknown) ||
(M1 == OMPC_SCHEDULE_MODIFIER_monotonic &&
M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) ||
(M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic &&
M2 == OMPC_SCHEDULE_MODIFIER_monotonic)) {
Diag(M2Loc, diag::err_omp_unexpected_schedule_modifier)
<< getOpenMPSimpleClauseTypeName(OMPC_schedule, M2)
<< getOpenMPSimpleClauseTypeName(OMPC_schedule, M1);
return nullptr;
}
if (Kind == OMPC_SCHEDULE_unknown) {
std::string Values;
if (M1Loc.isInvalid() && M2Loc.isInvalid()) {
unsigned Exclude[] = {OMPC_SCHEDULE_unknown};
Values = getListOfPossibleValues(OMPC_schedule, /*First=*/0,
/*Last=*/OMPC_SCHEDULE_MODIFIER_last,
Exclude);
} else {
Values = getListOfPossibleValues(OMPC_schedule, /*First=*/0,
/*Last=*/OMPC_SCHEDULE_unknown);
}
Diag(KindLoc, diag::err_omp_unexpected_clause_value)
<< Values << getOpenMPClauseName(OMPC_schedule);
return nullptr;
}
// OpenMP, 2.7.1, Loop Construct, Restrictions
// The nonmonotonic modifier can only be specified with schedule(dynamic) or
// schedule(guided).
if ((M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ||
M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) &&
Kind != OMPC_SCHEDULE_dynamic && Kind != OMPC_SCHEDULE_guided) {
Diag(M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ? M1Loc : M2Loc,
diag::err_omp_schedule_nonmonotonic_static);
return nullptr;
}
Expr *ValExpr = ChunkSize;
Stmt *HelperValStmt = nullptr;
if (ChunkSize) {
if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() &&
!ChunkSize->isInstantiationDependent() &&
!ChunkSize->containsUnexpandedParameterPack()) {
SourceLocation ChunkSizeLoc = ChunkSize->getBeginLoc();
ExprResult Val =
PerformOpenMPImplicitIntegerConversion(ChunkSizeLoc, ChunkSize);
if (Val.isInvalid())
return nullptr;
ValExpr = Val.get();
// OpenMP [2.7.1, Restrictions]
// chunk_size must be a loop invariant integer expression with a positive
// value.
llvm::APSInt Result;
if (ValExpr->isIntegerConstantExpr(Result, Context)) {
if (Result.isSigned() && !Result.isStrictlyPositive()) {
Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause)
<< "schedule" << 1 << ChunkSize->getSourceRange();
return nullptr;
}
} else if (getOpenMPCaptureRegionForClause(
DSAStack->getCurrentDirective(), OMPC_schedule) !=
OMPD_unknown &&
!CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
HelperValStmt = buildPreInits(Context, Captures);
}
}
}
return new (Context)
OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc, Kind,
ValExpr, HelperValStmt, M1, M1Loc, M2, M2Loc);
}
OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
SourceLocation StartLoc,
SourceLocation EndLoc) {
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_ordered:
Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc);
break;
case OMPC_nowait:
Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc);
break;
case OMPC_untied:
Res = ActOnOpenMPUntiedClause(StartLoc, EndLoc);
break;
case OMPC_mergeable:
Res = ActOnOpenMPMergeableClause(StartLoc, EndLoc);
break;
case OMPC_read:
Res = ActOnOpenMPReadClause(StartLoc, EndLoc);
break;
case OMPC_write:
Res = ActOnOpenMPWriteClause(StartLoc, EndLoc);
break;
case OMPC_update:
Res = ActOnOpenMPUpdateClause(StartLoc, EndLoc);
break;
case OMPC_capture:
Res = ActOnOpenMPCaptureClause(StartLoc, EndLoc);
break;
case OMPC_seq_cst:
Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc);
break;
case OMPC_threads:
Res = ActOnOpenMPThreadsClause(StartLoc, EndLoc);
break;
case OMPC_simd:
Res = ActOnOpenMPSIMDClause(StartLoc, EndLoc);
break;
case OMPC_nogroup:
Res = ActOnOpenMPNogroupClause(StartLoc, EndLoc);
break;
case OMPC_unified_address:
Res = ActOnOpenMPUnifiedAddressClause(StartLoc, EndLoc);
break;
case OMPC_unified_shared_memory:
Res = ActOnOpenMPUnifiedSharedMemoryClause(StartLoc, EndLoc);
break;
case OMPC_reverse_offload:
Res = ActOnOpenMPReverseOffloadClause(StartLoc, EndLoc);
break;
case OMPC_dynamic_allocators:
Res = ActOnOpenMPDynamicAllocatorsClause(StartLoc, EndLoc);
break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_collapse:
case OMPC_schedule:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
case OMPC_task_reduction:
case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
case OMPC_default:
case OMPC_proc_bind:
case OMPC_threadprivate:
case OMPC_flush:
case OMPC_depend:
case OMPC_device:
case OMPC_map:
case OMPC_num_teams:
case OMPC_thread_limit:
case OMPC_priority:
case OMPC_grainsize:
case OMPC_num_tasks:
case OMPC_hint:
case OMPC_dist_schedule:
case OMPC_defaultmap:
case OMPC_unknown:
case OMPC_uniform:
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
case OMPC_is_device_ptr:
case OMPC_atomic_default_mem_order:
llvm_unreachable("Clause is not allowed.");
}
return Res;
}
OMPClause *Sema::ActOnOpenMPNowaitClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
DSAStack->setNowaitRegion();
return new (Context) OMPNowaitClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPUntiedClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPUntiedClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPMergeableClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPMergeableClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPReadClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPReadClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPWriteClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPWriteClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPUpdateClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPUpdateClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPCaptureClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPCaptureClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPSeqCstClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPSeqCstClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPThreadsClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPThreadsClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPSIMDClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPSIMDClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPNogroupClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPNogroupClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPUnifiedAddressClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPUnifiedAddressClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPUnifiedSharedMemoryClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPUnifiedSharedMemoryClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPReverseOffloadClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPReverseOffloadClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPDynamicAllocatorsClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPVarListClause(
OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec,
const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind,
OpenMPLinearClauseKind LinKind,
ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
ArrayRef<SourceLocation> MapTypeModifiersLoc,
OpenMPMapClauseKind MapType, bool IsMapTypeImplicit,
SourceLocation DepLinMapLoc) {
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_private:
Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_firstprivate:
Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_lastprivate:
Res = ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_shared:
Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_reduction:
Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
EndLoc, ReductionIdScopeSpec, ReductionId);
break;
case OMPC_task_reduction:
Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
EndLoc, ReductionIdScopeSpec,
ReductionId);
break;
case OMPC_in_reduction:
Res =
ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
EndLoc, ReductionIdScopeSpec, ReductionId);
break;
case OMPC_linear:
Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
LinKind, DepLinMapLoc, ColonLoc, EndLoc);
break;
case OMPC_aligned:
Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc,
ColonLoc, EndLoc);
break;
case OMPC_copyin:
Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_copyprivate:
Res = ActOnOpenMPCopyprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_flush:
Res = ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_depend:
Res = ActOnOpenMPDependClause(DepKind, DepLinMapLoc, ColonLoc, VarList,
StartLoc, LParenLoc, EndLoc);
break;
case OMPC_map:
Res = ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc, MapType,
IsMapTypeImplicit, DepLinMapLoc, ColonLoc,
VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_to:
Res = ActOnOpenMPToClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_from:
Res = ActOnOpenMPFromClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_use_device_ptr:
Res = ActOnOpenMPUseDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_is_device_ptr:
Res = ActOnOpenMPIsDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_collapse:
case OMPC_default:
case OMPC_proc_bind:
case OMPC_schedule:
case OMPC_ordered:
case OMPC_nowait:
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_read:
case OMPC_write:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
case OMPC_num_teams:
case OMPC_thread_limit:
case OMPC_priority:
case OMPC_grainsize:
case OMPC_nogroup:
case OMPC_num_tasks:
case OMPC_hint:
case OMPC_dist_schedule:
case OMPC_defaultmap:
case OMPC_unknown:
case OMPC_uniform:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
llvm_unreachable("Clause is not allowed.");
}
return Res;
}
ExprResult Sema::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK,
ExprObjectKind OK, SourceLocation Loc) {
ExprResult Res = BuildDeclRefExpr(
Capture, Capture->getType().getNonReferenceType(), VK_LValue, Loc);
if (!Res.isUsable())
return ExprError();
if (OK == OK_Ordinary && !getLangOpts().CPlusPlus) {
Res = CreateBuiltinUnaryOp(Loc, UO_Deref, Res.get());
if (!Res.isUsable())
return ExprError();
}
if (VK != VK_LValue && Res.get()->isGLValue()) {
Res = DefaultLvalueConversion(Res.get());
if (!Res.isUsable())
return ExprError();
}
return Res;
}
static std::pair<ValueDecl *, bool>
getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
SourceRange &ERange, bool AllowArraySection = false) {
if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
RefExpr->containsUnexpandedParameterPack())
return std::make_pair(nullptr, true);
// OpenMP [3.1, C/C++]
// A list item is a variable name.
// OpenMP [2.9.3.3, Restrictions, p.1]
// A variable that is part of another variable (as an array or
// structure element) cannot appear in a private clause.
RefExpr = RefExpr->IgnoreParens();
enum {
NoArrayExpr = -1,
ArraySubscript = 0,
OMPArraySection = 1
} IsArrayExpr = NoArrayExpr;
if (AllowArraySection) {
if (auto *ASE = dyn_cast_or_null<ArraySubscriptExpr>(RefExpr)) {
Expr *Base = ASE->getBase()->IgnoreParenImpCasts();
while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
Base = TempASE->getBase()->IgnoreParenImpCasts();
RefExpr = Base;
IsArrayExpr = ArraySubscript;
} else if (auto *OASE = dyn_cast_or_null<OMPArraySectionExpr>(RefExpr)) {
Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
Base = TempOASE->getBase()->IgnoreParenImpCasts();
while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
Base = TempASE->getBase()->IgnoreParenImpCasts();
RefExpr = Base;
IsArrayExpr = OMPArraySection;
}
}
ELoc = RefExpr->getExprLoc();
ERange = RefExpr->getSourceRange();
RefExpr = RefExpr->IgnoreParenImpCasts();
auto *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);
auto *ME = dyn_cast_or_null<MemberExpr>(RefExpr);
if ((!DE || !isa<VarDecl>(DE->getDecl())) &&
(S.getCurrentThisType().isNull() || !ME ||
!isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()) ||
!isa<FieldDecl>(ME->getMemberDecl()))) {
if (IsArrayExpr != NoArrayExpr) {
S.Diag(ELoc, diag::err_omp_expected_base_var_name) << IsArrayExpr
<< ERange;
} else {
S.Diag(ELoc,
AllowArraySection
? diag::err_omp_expected_var_name_member_expr_or_array_item
: diag::err_omp_expected_var_name_member_expr)
<< (S.getCurrentThisType().isNull() ? 0 : 1) << ERange;
}
return std::make_pair(nullptr, false);
}
return std::make_pair(
getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false);
}
OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> PrivateCopies;
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP private clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
PrivateCopies.push_back(nullptr);
}
ValueDecl *D = Res.first;
if (!D)
continue;
QualType Type = D->getType();
auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
// A variable that appears in a private clause must not have an incomplete
// type or a reference type.
if (RequireCompleteType(ELoc, Type, diag::err_omp_private_incomplete_type))
continue;
Type = Type.getNonReferenceType();
// OpenMP 5.0 [2.19.3, List Item Privatization, Restrictions]
// A variable that is privatized must not have a const-qualified type
// unless it is of class type with a mutable member. This restriction does
// not apply to the firstprivate clause.
//
// OpenMP 3.1 [2.9.3.3, private clause, Restrictions]
// A variable that appears in a private clause must not have a
// const-qualified type unless it is of class type with a mutable member.
if (rejectConstNotMutableType(*this, D, Type, OMPC_private, ELoc))
continue;
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
// Variables with the predetermined data-sharing attributes may not be
// listed in data-sharing attributes clauses, except for the cases
// listed below. For these exceptions only, listing a predetermined
// variable in a data-sharing attribute clause is allowed and overrides
// the variable's predetermined data-sharing attributes.
DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false);
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) {
Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_private);
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
// Variably modified types are not supported for tasks.
if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() &&
isOpenMPTaskingDirective(CurrDir)) {
Diag(ELoc, diag::err_omp_variably_modified_type_not_supported)
<< getOpenMPClauseName(OMPC_private) << Type
<< getOpenMPDirectiveName(CurrDir);
bool IsDecl =
!VD ||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
continue;
}
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
if (isOpenMPTargetExecutionDirective(CurrDir)) {
OpenMPClauseKind ConflictKind;
if (DSAStack->checkMappableExprComponentListsForDecl(
VD, /*CurrentRegionOnly=*/true,
[&](OMPClauseMappableExprCommon::MappableExprComponentListRef,
OpenMPClauseKind WhereFoundClauseKind) -> bool {
ConflictKind = WhereFoundClauseKind;
return true;
})) {
Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa)
<< getOpenMPClauseName(OMPC_private)
<< getOpenMPClauseName(ConflictKind)
<< getOpenMPDirectiveName(CurrDir);
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
}
// OpenMP [2.9.3.3, Restrictions, C/C++, p.1]
// A variable of class type (or array thereof) that appears in a private
// clause requires an accessible, unambiguous default constructor for the
// class type.
// Generate helper private variable and initialize it with the default
// value. The address of the original variable is replaced by the address of
// the new private variable in CodeGen. This new variable is not added to
// IdResolver, so the code in the OpenMP region uses original variable for
// proper diagnostics.
Type = Type.getUnqualifiedType();
VarDecl *VDPrivate =
buildVarDecl(*this, ELoc, Type, D->getName(),
D->hasAttrs() ? &D->getAttrs() : nullptr,
VD ? cast<DeclRefExpr>(SimpleRefExpr) : nullptr);
ActOnUninitializedDecl(VDPrivate);
if (VDPrivate->isInvalidDecl())
continue;
DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr(
*this, VDPrivate, RefExpr->getType().getUnqualifiedType(), ELoc);
DeclRefExpr *Ref = nullptr;
if (!VD && !CurContext->isDependentContext())
Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref);
Vars.push_back((VD || CurContext->isDependentContext())
? RefExpr->IgnoreParens()
: Ref);
PrivateCopies.push_back(VDPrivateRefExpr);
}
if (Vars.empty())
return nullptr;
return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars,
PrivateCopies);
}
namespace {
class DiagsUninitializedSeveretyRAII {
private:
DiagnosticsEngine &Diags;
SourceLocation SavedLoc;
bool IsIgnored = false;
public:
DiagsUninitializedSeveretyRAII(DiagnosticsEngine &Diags, SourceLocation Loc,
bool IsIgnored)
: Diags(Diags), SavedLoc(Loc), IsIgnored(IsIgnored) {
if (!IsIgnored) {
Diags.setSeverity(/*Diag*/ diag::warn_uninit_self_reference_in_init,
/*Map*/ diag::Severity::Ignored, Loc);
}
}
~DiagsUninitializedSeveretyRAII() {
if (!IsIgnored)
Diags.popMappings(SavedLoc);
}
};
}
OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> PrivateCopies;
SmallVector<Expr *, 8> Inits;
SmallVector<Decl *, 4> ExprCaptures;
bool IsImplicitClause =
StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid();
SourceLocation ImplicitClauseLoc = DSAStack->getConstructLoc();
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP firstprivate clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
PrivateCopies.push_back(nullptr);
Inits.push_back(nullptr);
}
ValueDecl *D = Res.first;
if (!D)
continue;
ELoc = IsImplicitClause ? ImplicitClauseLoc : ELoc;
QualType Type = D->getType();
auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
// A variable that appears in a private clause must not have an incomplete
// type or a reference type.
if (RequireCompleteType(ELoc, Type,
diag::err_omp_firstprivate_incomplete_type))
continue;
Type = Type.getNonReferenceType();
// OpenMP [2.9.3.4, Restrictions, C/C++, p.1]
// A variable of class type (or array thereof) that appears in a private
// clause requires an accessible, unambiguous copy constructor for the
// class type.
QualType ElemType = Context.getBaseElementType(Type).getNonReferenceType();
// If an implicit firstprivate variable found it was checked already.
DSAStackTy::DSAVarData TopDVar;
if (!IsImplicitClause) {
DSAStackTy::DSAVarData DVar =
DSAStack->getTopDSA(D, /*FromParent=*/false);
TopDVar = DVar;
OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
bool IsConstant = ElemType.isConstant(Context);
// OpenMP [2.4.13, Data-sharing Attribute Clauses]
// A list item that specifies a given variable may not appear in more
// than one clause on the same directive, except that a variable may be
// specified in both firstprivate and lastprivate clauses.
// OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
// A list item may appear in a firstprivate or lastprivate clause but not
// both.
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate &&
(isOpenMPDistributeDirective(CurrDir) ||
DVar.CKind != OMPC_lastprivate) &&
DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_firstprivate);
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
// Variables with the predetermined data-sharing attributes may not be
// listed in data-sharing attributes clauses, except for the cases
// listed below. For these exceptions only, listing a predetermined
// variable in a data-sharing attribute clause is allowed and overrides
// the variable's predetermined data-sharing attributes.
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, p.2]
// Variables with const-qualified type having no mutable member may be
// listed in a firstprivate clause, even if they are static data members.
if (!(IsConstant || (VD && VD->isStaticDataMember())) && !DVar.RefExpr &&
DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_firstprivate);
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
// OpenMP [2.9.3.4, Restrictions, p.2]
// A list item that is private within a parallel region must not appear
// in a firstprivate clause on a worksharing construct if any of the
// worksharing regions arising from the worksharing construct ever bind
// to any of the parallel regions arising from the parallel construct.
// OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
// A list item that is private within a teams region must not appear in a
// firstprivate clause on a distribute construct if any of the distribute
// regions arising from the distribute construct ever bind to any of the
// teams regions arising from the teams construct.
// OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
// A list item that appears in a reduction clause of a teams construct
// must not appear in a firstprivate clause on a distribute construct if
// any of the distribute regions arising from the distribute construct
// ever bind to any of the teams regions arising from the teams construct.
if ((isOpenMPWorksharingDirective(CurrDir) ||
isOpenMPDistributeDirective(CurrDir)) &&
!isOpenMPParallelDirective(CurrDir) &&
!isOpenMPTeamsDirective(CurrDir)) {
DVar = DSAStack->getImplicitDSA(D, true);
if (DVar.CKind != OMPC_shared &&
(isOpenMPParallelDirective(DVar.DKind) ||
isOpenMPTeamsDirective(DVar.DKind) ||
DVar.DKind == OMPD_unknown)) {
Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_firstprivate)
<< getOpenMPClauseName(OMPC_shared);
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
}
// OpenMP [2.9.3.4, Restrictions, p.3]
// A list item that appears in a reduction clause of a parallel construct
// must not appear in a firstprivate clause on a worksharing or task
// construct if any of the worksharing or task regions arising from the
// worksharing or task construct ever bind to any of the parallel regions
// arising from the parallel construct.
// OpenMP [2.9.3.4, Restrictions, p.4]
// A list item that appears in a reduction clause in worksharing
// construct must not appear in a firstprivate clause in a task construct
// encountered during execution of any of the worksharing regions arising
// from the worksharing construct.
if (isOpenMPTaskingDirective(CurrDir)) {
DVar = DSAStack->hasInnermostDSA(
D, [](OpenMPClauseKind C) { return C == OMPC_reduction; },
[](OpenMPDirectiveKind K) {
return isOpenMPParallelDirective(K) ||
isOpenMPWorksharingDirective(K) ||
isOpenMPTeamsDirective(K);
},
/*FromParent=*/true);
if (DVar.CKind == OMPC_reduction &&
(isOpenMPParallelDirective(DVar.DKind) ||
isOpenMPWorksharingDirective(DVar.DKind) ||
isOpenMPTeamsDirective(DVar.DKind))) {
Diag(ELoc, diag::err_omp_parallel_reduction_in_task_firstprivate)
<< getOpenMPDirectiveName(DVar.DKind);
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
}
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
if (isOpenMPTargetExecutionDirective(CurrDir)) {
OpenMPClauseKind ConflictKind;
if (DSAStack->checkMappableExprComponentListsForDecl(
VD, /*CurrentRegionOnly=*/true,
[&ConflictKind](
OMPClauseMappableExprCommon::MappableExprComponentListRef,
OpenMPClauseKind WhereFoundClauseKind) {
ConflictKind = WhereFoundClauseKind;
return true;
})) {
Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa)
<< getOpenMPClauseName(OMPC_firstprivate)
<< getOpenMPClauseName(ConflictKind)
<< getOpenMPDirectiveName(DSAStack->getCurrentDirective());
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
}
}
// Variably modified types are not supported for tasks.
if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() &&
isOpenMPTaskingDirective(DSAStack->getCurrentDirective())) {
Diag(ELoc, diag::err_omp_variably_modified_type_not_supported)
<< getOpenMPClauseName(OMPC_firstprivate) << Type
<< getOpenMPDirectiveName(DSAStack->getCurrentDirective());
bool IsDecl =
!VD ||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
continue;
}
Type = Type.getUnqualifiedType();
VarDecl *VDPrivate =
buildVarDecl(*this, ELoc, Type, D->getName(),
D->hasAttrs() ? &D->getAttrs() : nullptr,
VD ? cast<DeclRefExpr>(SimpleRefExpr) : nullptr);
// Generate helper private variable and initialize it with the value of the
// original variable. The address of the original variable is replaced by
// the address of the new private variable in the CodeGen. This new variable
// is not added to IdResolver, so the code in the OpenMP region uses
// original variable for proper diagnostics and variable capturing.
Expr *VDInitRefExpr = nullptr;
// For arrays generate initializer for single element and replace it by the
// original array element in CodeGen.
if (Type->isArrayType()) {
VarDecl *VDInit =
buildVarDecl(*this, RefExpr->getExprLoc(), ElemType, D->getName());
VDInitRefExpr = buildDeclRefExpr(*this, VDInit, ElemType, ELoc);
Expr *Init = DefaultLvalueConversion(VDInitRefExpr).get();
ElemType = ElemType.getUnqualifiedType();
VarDecl *VDInitTemp = buildVarDecl(*this, RefExpr->getExprLoc(), ElemType,
".firstprivate.temp");
InitializedEntity Entity =
InitializedEntity::InitializeVariable(VDInitTemp);
InitializationKind Kind = InitializationKind::CreateCopy(ELoc, ELoc);
InitializationSequence InitSeq(*this, Entity, Kind, Init);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Init);
if (Result.isInvalid())
VDPrivate->setInvalidDecl();
else
VDPrivate->setInit(Result.getAs<Expr>());
// Remove temp variable declaration.
Context.Deallocate(VDInitTemp);
} else {
VarDecl *VDInit = buildVarDecl(*this, RefExpr->getExprLoc(), Type,
".firstprivate.temp");
VDInitRefExpr = buildDeclRefExpr(*this, VDInit, RefExpr->getType(),
RefExpr->getExprLoc());
AddInitializerToDecl(VDPrivate,
DefaultLvalueConversion(VDInitRefExpr).get(),
/*DirectInit=*/false);
}
if (VDPrivate->isInvalidDecl()) {
if (IsImplicitClause) {
Diag(RefExpr->getExprLoc(),
diag::note_omp_task_predetermined_firstprivate_here);
}
continue;
}
CurContext->addDecl(VDPrivate);
DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr(
*this, VDPrivate, RefExpr->getType().getUnqualifiedType(),
RefExpr->getExprLoc());
DeclRefExpr *Ref = nullptr;
if (!VD && !CurContext->isDependentContext()) {
if (TopDVar.CKind == OMPC_lastprivate) {
Ref = TopDVar.PrivateCopy;
} else {
Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
if (!isOpenMPCapturedDecl(D))
ExprCaptures.push_back(Ref->getDecl());
}
}
DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref);
Vars.push_back((VD || CurContext->isDependentContext())
? RefExpr->IgnoreParens()
: Ref);
PrivateCopies.push_back(VDPrivateRefExpr);
Inits.push_back(VDInitRefExpr);
}
if (Vars.empty())
return nullptr;
return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
Vars, PrivateCopies, Inits,
buildPreInits(Context, ExprCaptures));
}
OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> SrcExprs;
SmallVector<Expr *, 8> DstExprs;
SmallVector<Expr *, 8> AssignmentOps;
SmallVector<Decl *, 4> ExprCaptures;
SmallVector<Expr *, 4> ExprPostUpdates;
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP lastprivate clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
SrcExprs.push_back(nullptr);
DstExprs.push_back(nullptr);
AssignmentOps.push_back(nullptr);
}
ValueDecl *D = Res.first;
if (!D)
continue;
QualType Type = D->getType();
auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.14.3.5, Restrictions, C/C++, p.2]
// A variable that appears in a lastprivate clause must not have an
// incomplete type or a reference type.
if (RequireCompleteType(ELoc, Type,
diag::err_omp_lastprivate_incomplete_type))
continue;
Type = Type.getNonReferenceType();
// OpenMP 5.0 [2.19.3, List Item Privatization, Restrictions]
// A variable that is privatized must not have a const-qualified type
// unless it is of class type with a mutable member. This restriction does
// not apply to the firstprivate clause.
//
// OpenMP 3.1 [2.9.3.5, lastprivate clause, Restrictions]
// A variable that appears in a lastprivate clause must not have a
// const-qualified type unless it is of class type with a mutable member.
if (rejectConstNotMutableType(*this, D, Type, OMPC_lastprivate, ELoc))
continue;
OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
// Variables with the predetermined data-sharing attributes may not be
// listed in data-sharing attributes clauses, except for the cases
// listed below.
// OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
// A list item may appear in a firstprivate or lastprivate clause but not
// both.
DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false);
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate &&
(isOpenMPDistributeDirective(CurrDir) ||
DVar.CKind != OMPC_firstprivate) &&
(DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_lastprivate);
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
// OpenMP [2.14.3.5, Restrictions, p.2]
// A list item that is private within a parallel region, or that appears in
// the reduction clause of a parallel construct, must not appear in a
// lastprivate clause on a worksharing construct if any of the corresponding
// worksharing regions ever binds to any of the corresponding parallel
// regions.
DSAStackTy::DSAVarData TopDVar = DVar;
if (isOpenMPWorksharingDirective(CurrDir) &&
!isOpenMPParallelDirective(CurrDir) &&
!isOpenMPTeamsDirective(CurrDir)) {
DVar = DSAStack->getImplicitDSA(D, true);
if (DVar.CKind != OMPC_shared) {
Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_lastprivate)
<< getOpenMPClauseName(OMPC_shared);
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
}
// OpenMP [2.14.3.5, Restrictions, C++, p.1,2]
// A variable of class type (or array thereof) that appears in a
// lastprivate clause requires an accessible, unambiguous default
// constructor for the class type, unless the list item is also specified
// in a firstprivate clause.
// A variable of class type (or array thereof) that appears in a
// lastprivate clause requires an accessible, unambiguous copy assignment
// operator for the class type.
Type = Context.getBaseElementType(Type).getNonReferenceType();
VarDecl *SrcVD = buildVarDecl(*this, ERange.getBegin(),
Type.getUnqualifiedType(), ".lastprivate.src",
D->hasAttrs() ? &D->getAttrs() : nullptr);
DeclRefExpr *PseudoSrcExpr =
buildDeclRefExpr(*this, SrcVD, Type.getUnqualifiedType(), ELoc);
VarDecl *DstVD =
buildVarDecl(*this, ERange.getBegin(), Type, ".lastprivate.dst",
D->hasAttrs() ? &D->getAttrs() : nullptr);
DeclRefExpr *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc);
// For arrays generate assignment operation for single element and replace
// it by the original array element in CodeGen.
ExprResult AssignmentOp = BuildBinOp(/*S=*/nullptr, ELoc, BO_Assign,
PseudoDstExpr, PseudoSrcExpr);
if (AssignmentOp.isInvalid())
continue;
AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), ELoc,
/*DiscardedValue=*/true);
if (AssignmentOp.isInvalid())
continue;
DeclRefExpr *Ref = nullptr;
if (!VD && !CurContext->isDependentContext()) {
if (TopDVar.CKind == OMPC_firstprivate) {
Ref = TopDVar.PrivateCopy;
} else {
Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
if (!isOpenMPCapturedDecl(D))
ExprCaptures.push_back(Ref->getDecl());
}
if (TopDVar.CKind == OMPC_firstprivate ||
(!isOpenMPCapturedDecl(D) &&
Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>())) {
ExprResult RefRes = DefaultLvalueConversion(Ref);
if (!RefRes.isUsable())
continue;
ExprResult PostUpdateRes =
BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, SimpleRefExpr,
RefRes.get());
if (!PostUpdateRes.isUsable())
continue;
ExprPostUpdates.push_back(
IgnoredValueConversions(PostUpdateRes.get()).get());
}
}
DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_lastprivate, Ref);
Vars.push_back((VD || CurContext->isDependentContext())
? RefExpr->IgnoreParens()
: Ref);
SrcExprs.push_back(PseudoSrcExpr);
DstExprs.push_back(PseudoDstExpr);
AssignmentOps.push_back(AssignmentOp.get());
}
if (Vars.empty())
return nullptr;
return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
Vars, SrcExprs, DstExprs, AssignmentOps,
buildPreInits(Context, ExprCaptures),
buildPostUpdate(*this, ExprPostUpdates));
}
OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP lastprivate clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
}
ValueDecl *D = Res.first;
if (!D)
continue;
auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
// Variables with the predetermined data-sharing attributes may not be
// listed in data-sharing attributes clauses, except for the cases
// listed below. For these exceptions only, listing a predetermined
// variable in a data-sharing attribute clause is allowed and overrides
// the variable's predetermined data-sharing attributes.
DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false);
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared &&
DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_shared);
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
DeclRefExpr *Ref = nullptr;
if (!VD && isOpenMPCapturedDecl(D) && !CurContext->isDependentContext())
Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_shared, Ref);
Vars.push_back((VD || !Ref || CurContext->isDependentContext())
? RefExpr->IgnoreParens()
: Ref);
}
if (Vars.empty())
return nullptr;
return OMPSharedClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
}
namespace {
class DSARefChecker : public StmtVisitor<DSARefChecker, bool> {
DSAStackTy *Stack;
public:
bool VisitDeclRefExpr(DeclRefExpr *E) {
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false);
if (DVar.CKind == OMPC_shared && !DVar.RefExpr)
return false;
if (DVar.CKind != OMPC_unknown)
return true;
DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA(
VD, isOpenMPPrivate, [](OpenMPDirectiveKind) { return true; },
/*FromParent=*/true);
return DVarPrivate.CKind != OMPC_unknown;
}
return false;
}
bool VisitStmt(Stmt *S) {
for (Stmt *Child : S->children()) {
if (Child && Visit(Child))
return true;
}
return false;
}
explicit DSARefChecker(DSAStackTy *S) : Stack(S) {}
};
} // namespace
namespace {
// Transform MemberExpression for specified FieldDecl of current class to
// DeclRefExpr to specified OMPCapturedExprDecl.
class TransformExprToCaptures : public TreeTransform<TransformExprToCaptures> {
typedef TreeTransform<TransformExprToCaptures> BaseTransform;
ValueDecl *Field = nullptr;
DeclRefExpr *CapturedExpr = nullptr;
public:
TransformExprToCaptures(Sema &SemaRef, ValueDecl *FieldDecl)
: BaseTransform(SemaRef), Field(FieldDecl), CapturedExpr(nullptr) {}
ExprResult TransformMemberExpr(MemberExpr *E) {
if (isa<CXXThisExpr>(E->getBase()->IgnoreParenImpCasts()) &&
E->getMemberDecl() == Field) {
CapturedExpr = buildCapture(SemaRef, Field, E, /*WithInit=*/false);
return CapturedExpr;
}
return BaseTransform::TransformMemberExpr(E);
}
DeclRefExpr *getCapturedExpr() { return CapturedExpr; }
};
} // namespace
template <typename T, typename U>
static T filterLookupForUDR(SmallVectorImpl<U> &Lookups,
const llvm::function_ref<T(ValueDecl *)> Gen) {
for (U &Set : Lookups) {
for (auto *D : Set) {
if (T Res = Gen(cast<ValueDecl>(D)))
return Res;
}
}
return T();
}
static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case");
for (auto RD : D->redecls()) {
// Don't bother with extra checks if we already know this one isn't visible.
if (RD == D)
continue;
auto ND = cast<NamedDecl>(RD);
if (LookupResult::isVisible(SemaRef, ND))
return ND;
}
return nullptr;
}
static void
argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &ReductionId,
SourceLocation Loc, QualType Ty,
SmallVectorImpl<UnresolvedSet<8>> &Lookups) {
// Find all of the associated namespaces and classes based on the
// arguments we have.
Sema::AssociatedNamespaceSet AssociatedNamespaces;
Sema::AssociatedClassSet AssociatedClasses;
OpaqueValueExpr OVE(Loc, Ty, VK_LValue);
SemaRef.FindAssociatedClassesAndNamespaces(Loc, &OVE, AssociatedNamespaces,
AssociatedClasses);
// C++ [basic.lookup.argdep]p3:
// Let X be the lookup set produced by unqualified lookup (3.4.1)
// and let Y be the lookup set produced by argument dependent
// lookup (defined as follows). If X contains [...] then Y is
// empty. Otherwise Y is the set of declarations found in the
// namespaces associated with the argument types as described
// below. The set of declarations found by the lookup of the name
// is the union of X and Y.
//
// Here, we compute Y and add its members to the overloaded
// candidate set.
for (auto *NS : AssociatedNamespaces) {
// When considering an associated namespace, the lookup is the
// same as the lookup performed when the associated namespace is
// used as a qualifier (3.4.3.2) except that:
//
// -- Any using-directives in the associated namespace are
// ignored.
//
// -- Any namespace-scope friend functions declared in
// associated classes are visible within their respective
// namespaces even if they are not visible during an ordinary
// lookup (11.4).
DeclContext::lookup_result R = NS->lookup(ReductionId.getName());
for (auto *D : R) {
auto *Underlying = D;
if (auto *USD = dyn_cast<UsingShadowDecl>(D))
Underlying = USD->getTargetDecl();
if (!isa<OMPDeclareReductionDecl>(Underlying))
continue;
if (!SemaRef.isVisible(D)) {
D = findAcceptableDecl(SemaRef, D);
if (!D)
continue;
if (auto *USD = dyn_cast<UsingShadowDecl>(D))
Underlying = USD->getTargetDecl();
}
Lookups.emplace_back();
Lookups.back().addDecl(Underlying);
}
}
}
static ExprResult
buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
Scope *S, CXXScopeSpec &ReductionIdScopeSpec,
const DeclarationNameInfo &ReductionId, QualType Ty,
CXXCastPath &BasePath, Expr *UnresolvedReduction) {
if (ReductionIdScopeSpec.isInvalid())
return ExprError();
SmallVector<UnresolvedSet<8>, 4> Lookups;
if (S) {
LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName);
Lookup.suppressDiagnostics();
while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec)) {
NamedDecl *D = Lookup.getRepresentativeDecl();
do {
S = S->getParent();
} while (S && !S->isDeclScope(D));
if (S)
S = S->getParent();
Lookups.emplace_back();
Lookups.back().append(Lookup.begin(), Lookup.end());
Lookup.clear();
}
} else if (auto *ULE =
cast_or_null<UnresolvedLookupExpr>(UnresolvedReduction)) {
Lookups.push_back(UnresolvedSet<8>());
Decl *PrevD = nullptr;
for (NamedDecl *D : ULE->decls()) {
if (D == PrevD)
Lookups.push_back(UnresolvedSet<8>());
else if (auto *DRD = cast<OMPDeclareReductionDecl>(D))
Lookups.back().addDecl(DRD);
PrevD = D;
}
}
if (SemaRef.CurContext->isDependentContext() || Ty->isDependentType() ||
Ty->isInstantiationDependentType() ||
Ty->containsUnexpandedParameterPack() ||
filterLookupForUDR<bool>(Lookups, [](ValueDecl *D) {
return !D->isInvalidDecl() &&
(D->getType()->isDependentType() ||
D->getType()->isInstantiationDependentType() ||
D->getType()->containsUnexpandedParameterPack());
})) {
UnresolvedSet<8> ResSet;
for (const UnresolvedSet<8> &Set : Lookups) {
if (Set.empty())
continue;
ResSet.append(Set.begin(), Set.end());
// The last item marks the end of all declarations at the specified scope.
ResSet.addDecl(Set[Set.size() - 1]);
}
return UnresolvedLookupExpr::Create(
SemaRef.Context, /*NamingClass=*/nullptr,
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), ReductionId,
/*ADL=*/true, /*Overloaded=*/true, ResSet.begin(), ResSet.end());
}
// Lookup inside the classes.
// C++ [over.match.oper]p3:
// For a unary operator @ with an operand of a type whose
// cv-unqualified version is T1, and for a binary operator @ with
// a left operand of a type whose cv-unqualified version is T1 and
// a right operand of a type whose cv-unqualified version is T2,
// three sets of candidate functions, designated member
// candidates, non-member candidates and built-in candidates, are
// constructed as follows:
// -- If T1 is a complete class type or a class currently being
// defined, the set of member candidates is the result of the
// qualified lookup of T1::operator@ (13.3.1.1.1); otherwise,
// the set of member candidates is empty.
LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName);
Lookup.suppressDiagnostics();
if (const auto *TyRec = Ty->getAs<RecordType>()) {
// Complete the type if it can be completed.
// If the type is neither complete nor being defined, bail out now.
if (SemaRef.isCompleteType(Loc, Ty) || TyRec->isBeingDefined() ||
TyRec->getDecl()->getDefinition()) {
Lookup.clear();
SemaRef.LookupQualifiedName(Lookup, TyRec->getDecl());
if (Lookup.empty()) {
Lookups.emplace_back();
Lookups.back().append(Lookup.begin(), Lookup.end());
}
}
}
// Perform ADL.
argumentDependentLookup(SemaRef, ReductionId, Loc, Ty, Lookups);
if (auto *VD = filterLookupForUDR<ValueDecl *>(
Lookups, [&SemaRef, Ty](ValueDecl *D) -> ValueDecl * {
if (!D->isInvalidDecl() &&
SemaRef.Context.hasSameType(D->getType(), Ty))
return D;
return nullptr;
}))
return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc);
if (auto *VD = filterLookupForUDR<ValueDecl *>(
Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * {
if (!D->isInvalidDecl() &&
SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) &&
!Ty.isMoreQualifiedThan(D->getType()))
return D;
return nullptr;
})) {
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/false);
if (SemaRef.IsDerivedFrom(Loc, Ty, VD->getType(), Paths)) {
if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType(
VD->getType().getUnqualifiedType()))) {
if (SemaRef.CheckBaseClassAccess(Loc, VD->getType(), Ty, Paths.front(),
/*DiagID=*/0) !=
Sema::AR_inaccessible) {
SemaRef.BuildBasePathArray(Paths, BasePath);
return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc);
}
}
}
}
if (ReductionIdScopeSpec.isSet()) {
SemaRef.Diag(Loc, diag::err_omp_not_resolved_reduction_identifier) << Range;
return ExprError();
}
return ExprEmpty();
}
namespace {
/// Data for the reduction-based clauses.
struct ReductionData {
/// List of original reduction items.
SmallVector<Expr *, 8> Vars;
/// List of private copies of the reduction items.
SmallVector<Expr *, 8> Privates;
/// LHS expressions for the reduction_op expressions.
SmallVector<Expr *, 8> LHSs;
/// RHS expressions for the reduction_op expressions.
SmallVector<Expr *, 8> RHSs;
/// Reduction operation expression.
SmallVector<Expr *, 8> ReductionOps;
/// Taskgroup descriptors for the corresponding reduction items in
/// in_reduction clauses.
SmallVector<Expr *, 8> TaskgroupDescriptors;
/// List of captures for clause.
SmallVector<Decl *, 4> ExprCaptures;
/// List of postupdate expressions.
SmallVector<Expr *, 4> ExprPostUpdates;
ReductionData() = delete;
/// Reserves required memory for the reduction data.
ReductionData(unsigned Size) {
Vars.reserve(Size);
Privates.reserve(Size);
LHSs.reserve(Size);
RHSs.reserve(Size);
ReductionOps.reserve(Size);
TaskgroupDescriptors.reserve(Size);
ExprCaptures.reserve(Size);
ExprPostUpdates.reserve(Size);
}
/// Stores reduction item and reduction operation only (required for dependent
/// reduction item).
void push(Expr *Item, Expr *ReductionOp) {
Vars.emplace_back(Item);
Privates.emplace_back(nullptr);
LHSs.emplace_back(nullptr);
RHSs.emplace_back(nullptr);
ReductionOps.emplace_back(ReductionOp);
TaskgroupDescriptors.emplace_back(nullptr);
}
/// Stores reduction data.
void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS, Expr *ReductionOp,
Expr *TaskgroupDescriptor) {
Vars.emplace_back(Item);
Privates.emplace_back(Private);
LHSs.emplace_back(LHS);
RHSs.emplace_back(RHS);
ReductionOps.emplace_back(ReductionOp);
TaskgroupDescriptors.emplace_back(TaskgroupDescriptor);
}
};
} // namespace
static bool checkOMPArraySectionConstantForReduction(
ASTContext &Context, const OMPArraySectionExpr *OASE, bool &SingleElement,
SmallVectorImpl<llvm::APSInt> &ArraySizes) {
const Expr *Length = OASE->getLength();
if (Length == nullptr) {
// For array sections of the form [1:] or [:], we would need to analyze
// the lower bound...
if (OASE->getColonLoc().isValid())
return false;
// This is an array subscript which has implicit length 1!
SingleElement = true;
ArraySizes.push_back(llvm::APSInt::get(1));
} else {
Expr::EvalResult Result;
if (!Length->EvaluateAsInt(Result, Context))
return false;
llvm::APSInt ConstantLengthValue = Result.Val.getInt();
SingleElement = (ConstantLengthValue.getSExtValue() == 1);
ArraySizes.push_back(ConstantLengthValue);
}
// Get the base of this array section and walk up from there.
const Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
// We require length = 1 for all array sections except the right-most to
// guarantee that the memory region is contiguous and has no holes in it.
while (const auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base)) {
Length = TempOASE->getLength();
if (Length == nullptr) {
// For array sections of the form [1:] or [:], we would need to analyze
// the lower bound...
if (OASE->getColonLoc().isValid())
return false;
// This is an array subscript which has implicit length 1!
ArraySizes.push_back(llvm::APSInt::get(1));
} else {
Expr::EvalResult Result;
if (!Length->EvaluateAsInt(Result, Context))
return false;
llvm::APSInt ConstantLengthValue = Result.Val.getInt();
if (ConstantLengthValue.getSExtValue() != 1)
return false;
ArraySizes.push_back(ConstantLengthValue);
}
Base = TempOASE->getBase()->IgnoreParenImpCasts();
}
// If we have a single element, we don't need to add the implicit lengths.
if (!SingleElement) {
while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) {
// Has implicit length 1!
ArraySizes.push_back(llvm::APSInt::get(1));
Base = TempASE->getBase()->IgnoreParenImpCasts();
}
}
// This array section can be privatized as a single value or as a constant
// sized array.
return true;
}
static bool actOnOMPReductionKindClause(
Sema &S, DSAStackTy *Stack, OpenMPClauseKind ClauseKind,
ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation ColonLoc, SourceLocation EndLoc,
CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
ArrayRef<Expr *> UnresolvedReductions, ReductionData &RD) {
DeclarationName DN = ReductionId.getName();
OverloadedOperatorKind OOK = DN.getCXXOverloadedOperator();
BinaryOperatorKind BOK = BO_Comma;
ASTContext &Context = S.Context;
// OpenMP [2.14.3.6, reduction clause]
// C
// reduction-identifier is either an identifier or one of the following
// operators: +, -, *, &, |, ^, && and ||
// C++
// reduction-identifier is either an id-expression or one of the following
// operators: +, -, *, &, |, ^, && and ||
switch (OOK) {
case OO_Plus:
case OO_Minus:
BOK = BO_Add;
break;
case OO_Star:
BOK = BO_Mul;
break;
case OO_Amp:
BOK = BO_And;
break;
case OO_Pipe:
BOK = BO_Or;
break;
case OO_Caret:
BOK = BO_Xor;
break;
case OO_AmpAmp:
BOK = BO_LAnd;
break;
case OO_PipePipe:
BOK = BO_LOr;
break;
case OO_New:
case OO_Delete:
case OO_Array_New:
case OO_Array_Delete:
case OO_Slash:
case OO_Percent:
case OO_Tilde:
case OO_Exclaim:
case OO_Equal:
case OO_Less:
case OO_Greater:
case OO_LessEqual:
case OO_GreaterEqual:
case OO_PlusEqual:
case OO_MinusEqual:
case OO_StarEqual:
case OO_SlashEqual:
case OO_PercentEqual:
case OO_CaretEqual:
case OO_AmpEqual:
case OO_PipeEqual:
case OO_LessLess:
case OO_GreaterGreater:
case OO_LessLessEqual:
case OO_GreaterGreaterEqual:
case OO_EqualEqual:
case OO_ExclaimEqual:
case OO_Spaceship:
case OO_PlusPlus:
case OO_MinusMinus:
case OO_Comma:
case OO_ArrowStar:
case OO_Arrow:
case OO_Call:
case OO_Subscript:
case OO_Conditional:
case OO_Coawait:
case NUM_OVERLOADED_OPERATORS:
llvm_unreachable("Unexpected reduction identifier");
case OO_None:
if (IdentifierInfo *II = DN.getAsIdentifierInfo()) {
if (II->isStr("max"))
BOK = BO_GT;
else if (II->isStr("min"))
BOK = BO_LT;
}
break;
}
SourceRange ReductionIdRange;
if (ReductionIdScopeSpec.isValid())
ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc());
else
ReductionIdRange.setBegin(ReductionId.getBeginLoc());
ReductionIdRange.setEnd(ReductionId.getEndLoc());
auto IR = UnresolvedReductions.begin(), ER = UnresolvedReductions.end();
bool FirstIter = true;
for (Expr *RefExpr : VarList) {
assert(RefExpr && "nullptr expr in OpenMP reduction clause.");
// OpenMP [2.1, C/C++]
// A list item is a variable or array section, subject to the restrictions
// specified in Section 2.4 on page 42 and in each of the sections
// describing clauses and directives for which a list appears.
// OpenMP [2.14.3.3, Restrictions, p.1]
// A variable that is part of another variable (as an array or
// structure element) cannot appear in a private clause.
if (!FirstIter && IR != ER)
++IR;
FirstIter = false;
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange,
/*AllowArraySection=*/true);
if (Res.second) {
// Try to find 'declare reduction' corresponding construct before using
// builtin/overloaded operators.
QualType Type = Context.DependentTy;
CXXCastPath BasePath;
ExprResult DeclareReductionRef = buildDeclareReductionRef(
S, ELoc, ERange, Stack->getCurScope(), ReductionIdScopeSpec,
ReductionId, Type, BasePath, IR == ER ? nullptr : *IR);
Expr *ReductionOp = nullptr;
if (S.CurContext->isDependentContext() &&
(DeclareReductionRef.isUnset() ||
isa<UnresolvedLookupExpr>(DeclareReductionRef.get())))
ReductionOp = DeclareReductionRef.get();
// It will be analyzed later.
RD.push(RefExpr, ReductionOp);
}
ValueDecl *D = Res.first;
if (!D)
continue;
Expr *TaskgroupDescriptor = nullptr;
QualType Type;
auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr->IgnoreParens());
auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr->IgnoreParens());
if (ASE) {
Type = ASE->getType().getNonReferenceType();
} else if (OASE) {
QualType BaseType =
OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
Type = ATy->getElementType();
else
Type = BaseType->getPointeeType();
Type = Type.getNonReferenceType();
} else {
Type = Context.getBaseElementType(D->getType().getNonReferenceType());
}
auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
// A variable that appears in a private clause must not have an incomplete
// type or a reference type.
if (S.RequireCompleteType(ELoc, D->getType(),
diag::err_omp_reduction_incomplete_type))
continue;
// OpenMP [2.14.3.6, reduction clause, Restrictions]
// A list item that appears in a reduction clause must not be
// const-qualified.
if (rejectConstNotMutableType(S, D, Type, ClauseKind, ELoc,
/*AcceptIfMutable*/ false, ASE || OASE))
continue;
OpenMPDirectiveKind CurrDir = Stack->getCurrentDirective();
// OpenMP [2.9.3.6, Restrictions, C/C++, p.4]
// If a list-item is a reference type then it must bind to the same object
// for all threads of the team.
if (!ASE && !OASE) {
if (VD) {
VarDecl *VDDef = VD->getDefinition();
if (VD->getType()->isReferenceType() && VDDef && VDDef->hasInit()) {
DSARefChecker Check(Stack);
if (Check.Visit(VDDef->getInit())) {
S.Diag(ELoc, diag::err_omp_reduction_ref_type_arg)
<< getOpenMPClauseName(ClauseKind) << ERange;
S.Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef;
continue;
}
}
}
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
// Variables with the predetermined data-sharing attributes may not be
// listed in data-sharing attributes clauses, except for the cases
// listed below. For these exceptions only, listing a predetermined
// variable in a data-sharing attribute clause is allowed and overrides
// the variable's predetermined data-sharing attributes.
// OpenMP [2.14.3.6, Restrictions, p.3]
// Any number of reduction clauses can be specified on the directive,
// but a list item can appear only once in the reduction clauses for that
// directive.
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(D, /*FromParent=*/false);
if (DVar.CKind == OMPC_reduction) {
S.Diag(ELoc, diag::err_omp_once_referenced)
<< getOpenMPClauseName(ClauseKind);
if (DVar.RefExpr)
S.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
continue;
}
if (DVar.CKind != OMPC_unknown) {
S.Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_reduction);
reportOriginalDsa(S, Stack, D, DVar);
continue;
}
// OpenMP [2.14.3.6, Restrictions, p.1]
// A list item that appears in a reduction clause of a worksharing
// construct must be shared in the parallel regions to which any of the
// worksharing regions arising from the worksharing construct bind.
if (isOpenMPWorksharingDirective(CurrDir) &&
!isOpenMPParallelDirective(CurrDir) &&
!isOpenMPTeamsDirective(CurrDir)) {
DVar = Stack->getImplicitDSA(D, true);
if (DVar.CKind != OMPC_shared) {
S.Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_reduction)
<< getOpenMPClauseName(OMPC_shared);
reportOriginalDsa(S, Stack, D, DVar);
continue;
}
}
}
// Try to find 'declare reduction' corresponding construct before using
// builtin/overloaded operators.
CXXCastPath BasePath;
ExprResult DeclareReductionRef = buildDeclareReductionRef(
S, ELoc, ERange, Stack->getCurScope(), ReductionIdScopeSpec,
ReductionId, Type, BasePath, IR == ER ? nullptr : *IR);
if (DeclareReductionRef.isInvalid())
continue;
if (S.CurContext->isDependentContext() &&
(DeclareReductionRef.isUnset() ||
isa<UnresolvedLookupExpr>(DeclareReductionRef.get()))) {
RD.push(RefExpr, DeclareReductionRef.get());
continue;
}
if (BOK == BO_Comma && DeclareReductionRef.isUnset()) {
// Not allowed reduction identifier is found.
S.Diag(ReductionId.getBeginLoc(),
diag::err_omp_unknown_reduction_identifier)
<< Type << ReductionIdRange;
continue;
}
// OpenMP [2.14.3.6, reduction clause, Restrictions]
// The type of a list item that appears in a reduction clause must be valid
// for the reduction-identifier. For a max or min reduction in C, the type
// of the list item must be an allowed arithmetic data type: char, int,
// float, double, or _Bool, possibly modified with long, short, signed, or
// unsigned. For a max or min reduction in C++, the type of the list item
// must be an allowed arithmetic data type: char, wchar_t, int, float,
// double, or bool, possibly modified with long, short, signed, or unsigned.
if (DeclareReductionRef.isUnset()) {
if ((BOK == BO_GT || BOK == BO_LT) &&
!(Type->isScalarType() ||
(S.getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
S.Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
<< getOpenMPClauseName(ClauseKind) << S.getLangOpts().CPlusPlus;
if (!ASE && !OASE) {
bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
S.Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
}
continue;
}
if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
!S.getLangOpts().CPlusPlus && Type->isFloatingType()) {
S.Diag(ELoc, diag::err_omp_clause_floating_type_arg)
<< getOpenMPClauseName(ClauseKind);
if (!ASE && !OASE) {
bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
S.Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
}
continue;
}
}
Type = Type.getNonLValueExprType(Context).getUnqualifiedType();
VarDecl *LHSVD = buildVarDecl(S, ELoc, Type, ".reduction.lhs",
D->hasAttrs() ? &D->getAttrs() : nullptr);
VarDecl *RHSVD = buildVarDecl(S, ELoc, Type, D->getName(),
D->hasAttrs() ? &D->getAttrs() : nullptr);
QualType PrivateTy = Type;
// Try if we can determine constant lengths for all array sections and avoid
// the VLA.
bool ConstantLengthOASE = false;
if (OASE) {
bool SingleElement;
llvm::SmallVector<llvm::APSInt, 4> ArraySizes;
ConstantLengthOASE = checkOMPArraySectionConstantForReduction(
Context, OASE, SingleElement, ArraySizes);
// If we don't have a single element, we must emit a constant array type.
if (ConstantLengthOASE && !SingleElement) {
for (llvm::APSInt &Size : ArraySizes)
PrivateTy = Context.getConstantArrayType(
PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0);
}
}
if ((OASE && !ConstantLengthOASE) ||
(!OASE && !ASE &&
D->getType().getNonReferenceType()->isVariablyModifiedType())) {
if (!Context.getTargetInfo().isVLASupported() &&
S.shouldDiagnoseTargetSupportFromOpenMP()) {
S.Diag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE;
S.Diag(ELoc, diag::note_vla_unsupported);
continue;
}
// For arrays/array sections only:
// Create pseudo array type for private copy. The size for this array will
// be generated during codegen.
// For array subscripts or single variables Private Ty is the same as Type
// (type of the variable or single array element).
PrivateTy = Context.getVariableArrayType(
Type,
new (Context) OpaqueValueExpr(ELoc, Context.getSizeType(), VK_RValue),
ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange());
} else if (!ASE && !OASE &&
Context.getAsArrayType(D->getType().getNonReferenceType())) {
PrivateTy = D->getType().getNonReferenceType();
}
// Private copy.
VarDecl *PrivateVD =
buildVarDecl(S, ELoc, PrivateTy, D->getName(),
D->hasAttrs() ? &D->getAttrs() : nullptr,
VD ? cast<DeclRefExpr>(SimpleRefExpr) : nullptr);
// Add initializer for private variable.
Expr *Init = nullptr;
DeclRefExpr *LHSDRE = buildDeclRefExpr(S, LHSVD, Type, ELoc);
DeclRefExpr *RHSDRE = buildDeclRefExpr(S, RHSVD, Type, ELoc);
if (DeclareReductionRef.isUsable()) {
auto *DRDRef = DeclareReductionRef.getAs<DeclRefExpr>();
auto *DRD = cast<OMPDeclareReductionDecl>(DRDRef->getDecl());
if (DRD->getInitializer()) {
Init = DRDRef;
RHSVD->setInit(DRDRef);
RHSVD->setInitStyle(VarDecl::CallInit);
}
} else {
switch (BOK) {
case BO_Add:
case BO_Xor:
case BO_Or:
case BO_LOr:
// '+', '-', '^', '|', '||' reduction ops - initializer is '0'.
if (Type->isScalarType() || Type->isAnyComplexType())
Init = S.ActOnIntegerConstant(ELoc, /*Val=*/0).get();
break;
case BO_Mul:
case BO_LAnd:
if (Type->isScalarType() || Type->isAnyComplexType()) {
// '*' and '&&' reduction ops - initializer is '1'.
Init = S.ActOnIntegerConstant(ELoc, /*Val=*/1).get();
}
break;
case BO_And: {
// '&' reduction op - initializer is '~0'.
QualType OrigType = Type;
if (auto *ComplexTy = OrigType->getAs<ComplexType>())
Type = ComplexTy->getElementType();
if (Type->isRealFloatingType()) {
llvm::APFloat InitValue =
llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type),
/*isIEEE=*/true);
Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
Type, ELoc);
} else if (Type->isScalarType()) {
uint64_t Size = Context.getTypeSize(Type);
QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0);
llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size);
Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
}
if (Init && OrigType->isAnyComplexType()) {
// Init = 0xFFFF + 0xFFFFi;
auto *Im = new (Context) ImaginaryLiteral(Init, OrigType);
Init = S.CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get();
}
Type = OrigType;
break;
}
case BO_LT:
case BO_GT: {
// 'min' reduction op - initializer is 'Largest representable number in
// the reduction list item type'.
// 'max' reduction op - initializer is 'Least representable number in
// the reduction list item type'.
if (Type->isIntegerType() || Type->isPointerType()) {
bool IsSigned = Type->hasSignedIntegerRepresentation();
uint64_t Size = Context.getTypeSize(Type);
QualType IntTy =
Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned);
llvm::APInt InitValue =
(BOK != BO_LT) ? IsSigned ? llvm::APInt::getSignedMinValue(Size)
: llvm::APInt::getMinValue(Size)
: IsSigned ? llvm::APInt::getSignedMaxValue(Size)
: llvm::APInt::getMaxValue(Size);
Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
if (Type->isPointerType()) {
// Cast to pointer type.
ExprResult CastExpr = S.BuildCStyleCastExpr(
ELoc, Context.getTrivialTypeSourceInfo(Type, ELoc), ELoc, Init);
if (CastExpr.isInvalid())
continue;
Init = CastExpr.get();
}
} else if (Type->isRealFloatingType()) {
llvm::APFloat InitValue = llvm::APFloat::getLargest(
Context.getFloatTypeSemantics(Type), BOK != BO_LT);
Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
Type, ELoc);
}
break;
}
case BO_PtrMemD:
case BO_PtrMemI:
case BO_MulAssign:
case BO_Div:
case BO_Rem:
case BO_Sub:
case BO_Shl:
case BO_Shr:
case BO_LE:
case BO_GE:
case BO_EQ:
case BO_NE:
case BO_Cmp:
case BO_AndAssign:
case BO_XorAssign:
case BO_OrAssign:
case BO_Assign:
case BO_AddAssign:
case BO_SubAssign:
case BO_DivAssign:
case BO_RemAssign:
case BO_ShlAssign:
case BO_ShrAssign:
case BO_Comma:
llvm_unreachable("Unexpected reduction operation");
}
}
if (Init && DeclareReductionRef.isUnset())
S.AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false);
else if (!Init)
S.ActOnUninitializedDecl(RHSVD);
if (RHSVD->isInvalidDecl())
continue;
if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) {
S.Diag(ELoc, diag::err_omp_reduction_id_not_compatible)
<< Type << ReductionIdRange;
bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
S.Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
continue;
}
// Store initializer for single element in private copy. Will be used during
// codegen.
PrivateVD->setInit(RHSVD->getInit());
PrivateVD->setInitStyle(RHSVD->getInitStyle());
DeclRefExpr *PrivateDRE = buildDeclRefExpr(S, PrivateVD, PrivateTy, ELoc);
ExprResult ReductionOp;
if (DeclareReductionRef.isUsable()) {
QualType RedTy = DeclareReductionRef.get()->getType();
QualType PtrRedTy = Context.getPointerType(RedTy);
ExprResult LHS = S.CreateBuiltinUnaryOp(ELoc, UO_AddrOf, LHSDRE);
ExprResult RHS = S.CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RHSDRE);
if (!BasePath.empty()) {
LHS = S.DefaultLvalueConversion(LHS.get());
RHS = S.DefaultLvalueConversion(RHS.get());
LHS = ImplicitCastExpr::Create(Context, PtrRedTy,
CK_UncheckedDerivedToBase, LHS.get(),
&BasePath, LHS.get()->getValueKind());
RHS = ImplicitCastExpr::Create(Context, PtrRedTy,
CK_UncheckedDerivedToBase, RHS.get(),
&BasePath, RHS.get()->getValueKind());
}
FunctionProtoType::ExtProtoInfo EPI;
QualType Params[] = {PtrRedTy, PtrRedTy};
QualType FnTy = Context.getFunctionType(Context.VoidTy, Params, EPI);
auto *OVE = new (Context) OpaqueValueExpr(
ELoc, Context.getPointerType(FnTy), VK_RValue, OK_Ordinary,
S.DefaultLvalueConversion(DeclareReductionRef.get()).get());
Expr *Args[] = {LHS.get(), RHS.get()};
ReductionOp =
CallExpr::Create(Context, OVE, Args, Context.VoidTy, VK_RValue, ELoc);
} else {
ReductionOp = S.BuildBinOp(
Stack->getCurScope(), ReductionId.getBeginLoc(), BOK, LHSDRE, RHSDRE);
if (ReductionOp.isUsable()) {
if (BOK != BO_LT && BOK != BO_GT) {
ReductionOp =
S.BuildBinOp(Stack->getCurScope(), ReductionId.getBeginLoc(),
BO_Assign, LHSDRE, ReductionOp.get());
} else {
auto *ConditionalOp = new (Context)
ConditionalOperator(ReductionOp.get(), ELoc, LHSDRE, ELoc, RHSDRE,
Type, VK_LValue, OK_Ordinary);
ReductionOp =
S.BuildBinOp(Stack->getCurScope(), ReductionId.getBeginLoc(),
BO_Assign, LHSDRE, ConditionalOp);
}
if (ReductionOp.isUsable())
ReductionOp = S.ActOnFinishFullExpr(ReductionOp.get());
}
if (!ReductionOp.isUsable())
continue;
}
// OpenMP [2.15.4.6, Restrictions, p.2]
// A list item that appears in an in_reduction clause of a task construct
// must appear in a task_reduction clause of a construct associated with a
// taskgroup region that includes the participating task in its taskgroup
// set. The construct associated with the innermost region that meets this
// condition must specify the same reduction-identifier as the in_reduction
// clause.
if (ClauseKind == OMPC_in_reduction) {
SourceRange ParentSR;
BinaryOperatorKind ParentBOK;
const Expr *ParentReductionOp;
Expr *ParentBOKTD, *ParentReductionOpTD;
DSAStackTy::DSAVarData ParentBOKDSA =
Stack->getTopMostTaskgroupReductionData(D, ParentSR, ParentBOK,
ParentBOKTD);
DSAStackTy::DSAVarData ParentReductionOpDSA =
Stack->getTopMostTaskgroupReductionData(
D, ParentSR, ParentReductionOp, ParentReductionOpTD);
bool IsParentBOK = ParentBOKDSA.DKind != OMPD_unknown;
bool IsParentReductionOp = ParentReductionOpDSA.DKind != OMPD_unknown;
if (!IsParentBOK && !IsParentReductionOp) {
S.Diag(ELoc, diag::err_omp_in_reduction_not_task_reduction);
continue;
}
if ((DeclareReductionRef.isUnset() && IsParentReductionOp) ||
(DeclareReductionRef.isUsable() && IsParentBOK) || BOK != ParentBOK ||
IsParentReductionOp) {
bool EmitError = true;
if (IsParentReductionOp && DeclareReductionRef.isUsable()) {
llvm::FoldingSetNodeID RedId, ParentRedId;
ParentReductionOp->Profile(ParentRedId, Context, /*Canonical=*/true);
DeclareReductionRef.get()->Profile(RedId, Context,
/*Canonical=*/true);
EmitError = RedId != ParentRedId;
}
if (EmitError) {
S.Diag(ReductionId.getBeginLoc(),
diag::err_omp_reduction_identifier_mismatch)
<< ReductionIdRange << RefExpr->getSourceRange();
S.Diag(ParentSR.getBegin(),
diag::note_omp_previous_reduction_identifier)
<< ParentSR
<< (IsParentBOK ? ParentBOKDSA.RefExpr
: ParentReductionOpDSA.RefExpr)
->getSourceRange();
continue;
}
}
TaskgroupDescriptor = IsParentBOK ? ParentBOKTD : ParentReductionOpTD;
assert(TaskgroupDescriptor && "Taskgroup descriptor must be defined.");
}
DeclRefExpr *Ref = nullptr;
Expr *VarsExpr = RefExpr->IgnoreParens();
if (!VD && !S.CurContext->isDependentContext()) {
if (ASE || OASE) {
TransformExprToCaptures RebuildToCapture(S, D);
VarsExpr =
RebuildToCapture.TransformExpr(RefExpr->IgnoreParens()).get();
Ref = RebuildToCapture.getCapturedExpr();
} else {
VarsExpr = Ref = buildCapture(S, D, SimpleRefExpr, /*WithInit=*/false);
}
if (!S.isOpenMPCapturedDecl(D)) {
RD.ExprCaptures.emplace_back(Ref->getDecl());
if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) {
ExprResult RefRes = S.DefaultLvalueConversion(Ref);
if (!RefRes.isUsable())
continue;
ExprResult PostUpdateRes =
S.BuildBinOp(Stack->getCurScope(), ELoc, BO_Assign, SimpleRefExpr,
RefRes.get());
if (!PostUpdateRes.isUsable())
continue;
if (isOpenMPTaskingDirective(Stack->getCurrentDirective()) ||
Stack->getCurrentDirective() == OMPD_taskgroup) {
S.Diag(RefExpr->getExprLoc(),
diag::err_omp_reduction_non_addressable_expression)
<< RefExpr->getSourceRange();
continue;
}
RD.ExprPostUpdates.emplace_back(
S.IgnoredValueConversions(PostUpdateRes.get()).get());
}
}
}
// All reduction items are still marked as reduction (to do not increase
// code base size).
Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref);
if (CurrDir == OMPD_taskgroup) {
if (DeclareReductionRef.isUsable())
Stack->addTaskgroupReductionData(D, ReductionIdRange,
DeclareReductionRef.get());
else
Stack->addTaskgroupReductionData(D, ReductionIdRange, BOK);
}
RD.push(VarsExpr, PrivateDRE, LHSDRE, RHSDRE, ReductionOp.get(),
TaskgroupDescriptor);
}
return RD.Vars.empty();
}
OMPClause *Sema::ActOnOpenMPReductionClause(
ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation ColonLoc, SourceLocation EndLoc,
CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
ArrayRef<Expr *> UnresolvedReductions) {
ReductionData RD(VarList.size());
if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList,
StartLoc, LParenLoc, ColonLoc, EndLoc,
ReductionIdScopeSpec, ReductionId,
UnresolvedReductions, RD))
return nullptr;
return OMPReductionClause::Create(
Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars,
ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps,
buildPreInits(Context, RD.ExprCaptures),
buildPostUpdate(*this, RD.ExprPostUpdates));
}
OMPClause *Sema::ActOnOpenMPTaskReductionClause(
ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation ColonLoc, SourceLocation EndLoc,
CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
ArrayRef<Expr *> UnresolvedReductions) {
ReductionData RD(VarList.size());
if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_task_reduction, VarList,
StartLoc, LParenLoc, ColonLoc, EndLoc,
ReductionIdScopeSpec, ReductionId,
UnresolvedReductions, RD))
return nullptr;
return OMPTaskReductionClause::Create(
Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars,
ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps,
buildPreInits(Context, RD.ExprCaptures),
buildPostUpdate(*this, RD.ExprPostUpdates));
}
OMPClause *Sema::ActOnOpenMPInReductionClause(
ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation ColonLoc, SourceLocation EndLoc,
CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
ArrayRef<Expr *> UnresolvedReductions) {
ReductionData RD(VarList.size());
if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_in_reduction, VarList,
StartLoc, LParenLoc, ColonLoc, EndLoc,
ReductionIdScopeSpec, ReductionId,
UnresolvedReductions, RD))
return nullptr;
return OMPInReductionClause::Create(
Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars,
ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, RD.TaskgroupDescriptors,
buildPreInits(Context, RD.ExprCaptures),
buildPostUpdate(*this, RD.ExprPostUpdates));
}
bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
SourceLocation LinLoc) {
if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) ||
LinKind == OMPC_LINEAR_unknown) {
Diag(LinLoc, diag::err_omp_wrong_linear_modifier) << LangOpts.CPlusPlus;
return true;
}
return false;
}
bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc,
OpenMPLinearClauseKind LinKind,
QualType Type) {
const auto *VD = dyn_cast_or_null<VarDecl>(D);
// A variable must not have an incomplete type or a reference type.
if (RequireCompleteType(ELoc, Type, diag::err_omp_linear_incomplete_type))
return true;
if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) &&
!Type->isReferenceType()) {
Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference)
<< Type << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind);
return true;
}
Type = Type.getNonReferenceType();
// OpenMP 5.0 [2.19.3, List Item Privatization, Restrictions]
// A variable that is privatized must not have a const-qualified type
// unless it is of class type with a mutable member. This restriction does
// not apply to the firstprivate clause.
if (rejectConstNotMutableType(*this, D, Type, OMPC_linear, ELoc))
return true;
// A list item must be of integral or pointer type.
Type = Type.getUnqualifiedType().getCanonicalType();
const auto *Ty = Type.getTypePtrOrNull();
if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
!Ty->isPointerType())) {
Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << Type;
if (D) {
bool IsDecl =
!VD ||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
}
return true;
}
return false;
}
OMPClause *Sema::ActOnOpenMPLinearClause(
ArrayRef<Expr *> VarList, Expr *Step, SourceLocation StartLoc,
SourceLocation LParenLoc, OpenMPLinearClauseKind LinKind,
SourceLocation LinLoc, SourceLocation ColonLoc, SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> Privates;
SmallVector<Expr *, 8> Inits;
SmallVector<Decl *, 4> ExprCaptures;
SmallVector<Expr *, 4> ExprPostUpdates;
if (CheckOpenMPLinearModifier(LinKind, LinLoc))
LinKind = OMPC_LINEAR_val;
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP linear clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
Privates.push_back(nullptr);
Inits.push_back(nullptr);
}
ValueDecl *D = Res.first;
if (!D)
continue;
QualType Type = D->getType();
auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.14.3.7, linear clause]
// A list-item cannot appear in more than one linear clause.
// A list-item that appears in a linear clause cannot appear in any
// other data-sharing attribute clause.
DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false);
if (DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_linear);
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
if (CheckOpenMPLinearDecl(D, ELoc, LinKind, Type))
continue;
Type = Type.getNonReferenceType().getUnqualifiedType().getCanonicalType();
// Build private copy of original var.
VarDecl *Private =
buildVarDecl(*this, ELoc, Type, D->getName(),
D->hasAttrs() ? &D->getAttrs() : nullptr,
VD ? cast<DeclRefExpr>(SimpleRefExpr) : nullptr);
DeclRefExpr *PrivateRef = buildDeclRefExpr(*this, Private, Type, ELoc);
// Build var to save initial value.
VarDecl *Init = buildVarDecl(*this, ELoc, Type, ".linear.start");
Expr *InitExpr;
DeclRefExpr *Ref = nullptr;
if (!VD && !CurContext->isDependentContext()) {
Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
if (!isOpenMPCapturedDecl(D)) {
ExprCaptures.push_back(Ref->getDecl());
if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) {
ExprResult RefRes = DefaultLvalueConversion(Ref);
if (!RefRes.isUsable())
continue;
ExprResult PostUpdateRes =
BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign,
SimpleRefExpr, RefRes.get());
if (!PostUpdateRes.isUsable())
continue;
ExprPostUpdates.push_back(
IgnoredValueConversions(PostUpdateRes.get()).get());
}
}
}
if (LinKind == OMPC_LINEAR_uval)
InitExpr = VD ? VD->getInit() : SimpleRefExpr;
else
InitExpr = VD ? SimpleRefExpr : Ref;
AddInitializerToDecl(Init, DefaultLvalueConversion(InitExpr).get(),
/*DirectInit=*/false);
DeclRefExpr *InitRef = buildDeclRefExpr(*this, Init, Type, ELoc);
DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_linear, Ref);
Vars.push_back((VD || CurContext->isDependentContext())
? RefExpr->IgnoreParens()
: Ref);
Privates.push_back(PrivateRef);
Inits.push_back(InitRef);
}
if (Vars.empty())
return nullptr;
Expr *StepExpr = Step;
Expr *CalcStepExpr = nullptr;
if (Step && !Step->isValueDependent() && !Step->isTypeDependent() &&
!Step->isInstantiationDependent() &&
!Step->containsUnexpandedParameterPack()) {
SourceLocation StepLoc = Step->getBeginLoc();
ExprResult Val = PerformOpenMPImplicitIntegerConversion(StepLoc, Step);
if (Val.isInvalid())
return nullptr;
StepExpr = Val.get();
// Build var to save the step value.
VarDecl *SaveVar =
buildVarDecl(*this, StepLoc, StepExpr->getType(), ".linear.step");
ExprResult SaveRef =
buildDeclRefExpr(*this, SaveVar, StepExpr->getType(), StepLoc);
ExprResult CalcStep =
BuildBinOp(CurScope, StepLoc, BO_Assign, SaveRef.get(), StepExpr);
CalcStep = ActOnFinishFullExpr(CalcStep.get());
// Warn about zero linear step (it would be probably better specified as
// making corresponding variables 'const').
llvm::APSInt Result;
bool IsConstant = StepExpr->isIntegerConstantExpr(Result, Context);
if (IsConstant && !Result.isNegative() && !Result.isStrictlyPositive())
Diag(StepLoc, diag::warn_omp_linear_step_zero) << Vars[0]
<< (Vars.size() > 1);
if (!IsConstant && CalcStep.isUsable()) {
// Calculate the step beforehand instead of doing this on each iteration.
// (This is not used if the number of iterations may be kfold-ed).
CalcStepExpr = CalcStep.get();
}
}
return OMPLinearClause::Create(Context, StartLoc, LParenLoc, LinKind, LinLoc,
ColonLoc, EndLoc, Vars, Privates, Inits,
StepExpr, CalcStepExpr,
buildPreInits(Context, ExprCaptures),
buildPostUpdate(*this, ExprPostUpdates));
}
static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
Expr *NumIterations, Sema &SemaRef,
Scope *S, DSAStackTy *Stack) {
// Walk the vars and build update/final expressions for the CodeGen.
SmallVector<Expr *, 8> Updates;
SmallVector<Expr *, 8> Finals;
Expr *Step = Clause.getStep();
Expr *CalcStep = Clause.getCalcStep();
// OpenMP [2.14.3.7, linear clause]
// If linear-step is not specified it is assumed to be 1.
if (!Step)
Step = SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get();
else if (CalcStep)
Step = cast<BinaryOperator>(CalcStep)->getLHS();
bool HasErrors = false;
auto CurInit = Clause.inits().begin();
auto CurPrivate = Clause.privates().begin();
OpenMPLinearClauseKind LinKind = Clause.getModifier();
for (Expr *RefExpr : Clause.varlists()) {
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
auto Res = getPrivateItem(SemaRef, SimpleRefExpr, ELoc, ERange);
ValueDecl *D = Res.first;
if (Res.second || !D) {
Updates.push_back(nullptr);
Finals.push_back(nullptr);
HasErrors = true;
continue;
}
auto &&Info = Stack->isLoopControlVariable(D);
// OpenMP [2.15.11, distribute simd Construct]
// A list item may not appear in a linear clause, unless it is the loop
// iteration variable.
if (isOpenMPDistributeDirective(Stack->getCurrentDirective()) &&
isOpenMPSimdDirective(Stack->getCurrentDirective()) && !Info.first) {
SemaRef.Diag(ELoc,
diag::err_omp_linear_distribute_var_non_loop_iteration);
Updates.push_back(nullptr);
Finals.push_back(nullptr);
HasErrors = true;
continue;
}
Expr *InitExpr = *CurInit;
// Build privatized reference to the current linear var.
auto *DE = cast<DeclRefExpr>(SimpleRefExpr);
Expr *CapturedRef;
if (LinKind == OMPC_LINEAR_uval)
CapturedRef = cast<VarDecl>(DE->getDecl())->getInit();
else
CapturedRef =
buildDeclRefExpr(SemaRef, cast<VarDecl>(DE->getDecl()),
DE->getType().getUnqualifiedType(), DE->getExprLoc(),
/*RefersToCapture=*/true);
// Build update: Var = InitExpr + IV * Step
ExprResult Update;
if (!Info.first)
Update =
buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate,
InitExpr, IV, Step, /* Subtract */ false);
else
Update = *CurPrivate;
Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getBeginLoc(),
/*DiscardedValue=*/true);
// Build final: Var = InitExpr + NumIterations * Step
ExprResult Final;
if (!Info.first)
Final =
buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef,
InitExpr, NumIterations, Step, /*Subtract=*/false);
else
Final = *CurPrivate;
Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getBeginLoc(),
/*DiscardedValue=*/true);
if (!Update.isUsable() || !Final.isUsable()) {
Updates.push_back(nullptr);
Finals.push_back(nullptr);
HasErrors = true;
} else {
Updates.push_back(Update.get());
Finals.push_back(Final.get());
}
++CurInit;
++CurPrivate;
}
Clause.setUpdates(Updates);
Clause.setFinals(Finals);
return HasErrors;
}
OMPClause *Sema::ActOnOpenMPAlignedClause(
ArrayRef<Expr *> VarList, Expr *Alignment, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP linear clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
}
ValueDecl *D = Res.first;
if (!D)
continue;
QualType QType = D->getType();
auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.8.1, simd construct, Restrictions]
// The type of list items appearing in the aligned clause must be
// array, pointer, reference to array, or reference to pointer.
QType = QType.getNonReferenceType().getUnqualifiedType().getCanonicalType();
const Type *Ty = QType.getTypePtrOrNull();
if (!Ty || (!Ty->isArrayType() && !Ty->isPointerType())) {
Diag(ELoc, diag::err_omp_aligned_expected_array_or_ptr)
<< QType << getLangOpts().CPlusPlus << ERange;
bool IsDecl =
!VD ||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
continue;
}
// OpenMP [2.8.1, simd construct, Restrictions]
// A list-item cannot appear in more than one aligned clause.
if (const Expr *PrevRef = DSAStack->addUniqueAligned(D, SimpleRefExpr)) {
Diag(ELoc, diag::err_omp_aligned_twice) << 0 << ERange;
Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_aligned);
continue;
}
DeclRefExpr *Ref = nullptr;
if (!VD && isOpenMPCapturedDecl(D))
Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
Vars.push_back(DefaultFunctionArrayConversion(
(VD || !Ref) ? RefExpr->IgnoreParens() : Ref)
.get());
}
// OpenMP [2.8.1, simd construct, Description]
// The parameter of the aligned clause, alignment, must be a constant
// positive integer expression.
// If no optional parameter is specified, implementation-defined default
// alignments for SIMD instructions on the target platforms are assumed.
if (Alignment != nullptr) {
ExprResult AlignResult =
VerifyPositiveIntegerConstantInClause(Alignment, OMPC_aligned);
if (AlignResult.isInvalid())
return nullptr;
Alignment = AlignResult.get();
}
if (Vars.empty())
return nullptr;
return OMPAlignedClause::Create(Context, StartLoc, LParenLoc, ColonLoc,
EndLoc, Vars, Alignment);
}
OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> SrcExprs;
SmallVector<Expr *, 8> DstExprs;
SmallVector<Expr *, 8> AssignmentOps;
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP copyin clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
SrcExprs.push_back(nullptr);
DstExprs.push_back(nullptr);
AssignmentOps.push_back(nullptr);
continue;
}
SourceLocation ELoc = RefExpr->getExprLoc();
// OpenMP [2.1, C/C++]
// A list item is a variable name.
// OpenMP [2.14.4.1, Restrictions, p.1]
// A list item that appears in a copyin clause must be threadprivate.
auto *DE = dyn_cast<DeclRefExpr>(RefExpr);
if (!DE || !isa<VarDecl>(DE->getDecl())) {
Diag(ELoc, diag::err_omp_expected_var_name_member_expr)
<< 0 << RefExpr->getSourceRange();
continue;
}
Decl *D = DE->getDecl();
auto *VD = cast<VarDecl>(D);
QualType Type = VD->getType();
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
SrcExprs.push_back(nullptr);
DstExprs.push_back(nullptr);
AssignmentOps.push_back(nullptr);
continue;
}
// OpenMP [2.14.4.1, Restrictions, C/C++, p.1]
// A list item that appears in a copyin clause must be threadprivate.
if (!DSAStack->isThreadPrivate(VD)) {
Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_copyin)
<< getOpenMPDirectiveName(OMPD_threadprivate);
continue;
}
// OpenMP [2.14.4.1, Restrictions, C/C++, p.2]
// A variable of class type (or array thereof) that appears in a
// copyin clause requires an accessible, unambiguous copy assignment
// operator for the class type.
QualType ElemType = Context.getBaseElementType(Type).getNonReferenceType();
VarDecl *SrcVD =
buildVarDecl(*this, DE->getBeginLoc(), ElemType.getUnqualifiedType(),
".copyin.src", VD->hasAttrs() ? &VD->getAttrs() : nullptr);
DeclRefExpr *PseudoSrcExpr = buildDeclRefExpr(
*this, SrcVD, ElemType.getUnqualifiedType(), DE->getExprLoc());
VarDecl *DstVD =
buildVarDecl(*this, DE->getBeginLoc(), ElemType, ".copyin.dst",
VD->hasAttrs() ? &VD->getAttrs() : nullptr);
DeclRefExpr *PseudoDstExpr =
buildDeclRefExpr(*this, DstVD, ElemType, DE->getExprLoc());
// For arrays generate assignment operation for single element and replace
// it by the original array element in CodeGen.
ExprResult AssignmentOp =
BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, PseudoDstExpr,
PseudoSrcExpr);
if (AssignmentOp.isInvalid())
continue;
AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(),
/*DiscardedValue=*/true);
if (AssignmentOp.isInvalid())
continue;
DSAStack->addDSA(VD, DE, OMPC_copyin);
Vars.push_back(DE);
SrcExprs.push_back(PseudoSrcExpr);
DstExprs.push_back(PseudoDstExpr);
AssignmentOps.push_back(AssignmentOp.get());
}
if (Vars.empty())
return nullptr;
return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars,
SrcExprs, DstExprs, AssignmentOps);
}
OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> SrcExprs;
SmallVector<Expr *, 8> DstExprs;
SmallVector<Expr *, 8> AssignmentOps;
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP linear clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
SrcExprs.push_back(nullptr);
DstExprs.push_back(nullptr);
AssignmentOps.push_back(nullptr);
}
ValueDecl *D = Res.first;
if (!D)
continue;
QualType Type = D->getType();
auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.14.4.2, Restrictions, p.2]
// A list item that appears in a copyprivate clause may not appear in a
// private or firstprivate clause on the single construct.
if (!VD || !DSAStack->isThreadPrivate(VD)) {
DSAStackTy::DSAVarData DVar =
DSAStack->getTopDSA(D, /*FromParent=*/false);
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_copyprivate &&
DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_copyprivate);
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
// OpenMP [2.11.4.2, Restrictions, p.1]
// All list items that appear in a copyprivate clause must be either
// threadprivate or private in the enclosing context.
if (DVar.CKind == OMPC_unknown) {
DVar = DSAStack->getImplicitDSA(D, false);
if (DVar.CKind == OMPC_shared) {
Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_copyprivate)
<< "threadprivate or private in the enclosing context";
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
}
}
// Variably modified types are not supported.
if (!Type->isAnyPointerType() && Type->isVariablyModifiedType()) {
Diag(ELoc, diag::err_omp_variably_modified_type_not_supported)
<< getOpenMPClauseName(OMPC_copyprivate) << Type
<< getOpenMPDirectiveName(DSAStack->getCurrentDirective());
bool IsDecl =
!VD ||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
continue;
}
// OpenMP [2.14.4.1, Restrictions, C/C++, p.2]
// A variable of class type (or array thereof) that appears in a
// copyin clause requires an accessible, unambiguous copy assignment
// operator for the class type.
Type = Context.getBaseElementType(Type.getNonReferenceType())
.getUnqualifiedType();
VarDecl *SrcVD =
buildVarDecl(*this, RefExpr->getBeginLoc(), Type, ".copyprivate.src",
D->hasAttrs() ? &D->getAttrs() : nullptr);
DeclRefExpr *PseudoSrcExpr = buildDeclRefExpr(*this, SrcVD, Type, ELoc);
VarDecl *DstVD =
buildVarDecl(*this, RefExpr->getBeginLoc(), Type, ".copyprivate.dst",
D->hasAttrs() ? &D->getAttrs() : nullptr);
DeclRefExpr *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc);
ExprResult AssignmentOp = BuildBinOp(
DSAStack->getCurScope(), ELoc, BO_Assign, PseudoDstExpr, PseudoSrcExpr);
if (AssignmentOp.isInvalid())
continue;
AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), ELoc,
/*DiscardedValue=*/true);
if (AssignmentOp.isInvalid())
continue;
// No need to mark vars as copyprivate, they are already threadprivate or
// implicitly private.
assert(VD || isOpenMPCapturedDecl(D));
Vars.push_back(
VD ? RefExpr->IgnoreParens()
: buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false));
SrcExprs.push_back(PseudoSrcExpr);
DstExprs.push_back(PseudoDstExpr);
AssignmentOps.push_back(AssignmentOp.get());
}
if (Vars.empty())
return nullptr;
return OMPCopyprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
Vars, SrcExprs, DstExprs, AssignmentOps);
}
OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
if (VarList.empty())
return nullptr;
return OMPFlushClause::Create(Context, StartLoc, LParenLoc, EndLoc, VarList);
}
OMPClause *
Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
SourceLocation DepLoc, SourceLocation ColonLoc,
ArrayRef<Expr *> VarList, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc) {
if (DSAStack->getCurrentDirective() == OMPD_ordered &&
DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink) {
Diag(DepLoc, diag::err_omp_unexpected_clause_value)
<< "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend);
return nullptr;
}
if (DSAStack->getCurrentDirective() != OMPD_ordered &&
(DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source ||
DepKind == OMPC_DEPEND_sink)) {
unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink};
Diag(DepLoc, diag::err_omp_unexpected_clause_value)
<< getListOfPossibleValues(OMPC_depend, /*First=*/0,
/*Last=*/OMPC_DEPEND_unknown, Except)
<< getOpenMPClauseName(OMPC_depend);
return nullptr;
}
SmallVector<Expr *, 8> Vars;
DSAStackTy::OperatorOffsetTy OpsOffs;
llvm::APSInt DepCounter(/*BitWidth=*/32);
llvm::APSInt TotalDepCount(/*BitWidth=*/32);
if (DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) {
if (const Expr *OrderedCountExpr =
DSAStack->getParentOrderedRegionParam().first) {
TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(Context);
TotalDepCount.setIsUnsigned(/*Val=*/true);
}
}
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP shared clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
continue;
}
SourceLocation ELoc = RefExpr->getExprLoc();
Expr *SimpleExpr = RefExpr->IgnoreParenCasts();
if (DepKind == OMPC_DEPEND_sink) {
if (DSAStack->getParentOrderedRegionParam().first &&
DepCounter >= TotalDepCount) {
Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr);
continue;
}
++DepCounter;
// OpenMP [2.13.9, Summary]
// depend(dependence-type : vec), where dependence-type is:
// 'sink' and where vec is the iteration vector, which has the form:
// x1 [+- d1], x2 [+- d2 ], . . . , xn [+- dn]
// where n is the value specified by the ordered clause in the loop
// directive, xi denotes the loop iteration variable of the i-th nested
// loop associated with the loop directive, and di is a constant
// non-negative integer.
if (CurContext->isDependentContext()) {
// It will be analyzed later.
Vars.push_back(RefExpr);
continue;
}
SimpleExpr = SimpleExpr->IgnoreImplicit();
OverloadedOperatorKind OOK = OO_None;
SourceLocation OOLoc;
Expr *LHS = SimpleExpr;
Expr *RHS = nullptr;
if (auto *BO = dyn_cast<BinaryOperator>(SimpleExpr)) {
OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode());
OOLoc = BO->getOperatorLoc();
LHS = BO->getLHS()->IgnoreParenImpCasts();
RHS = BO->getRHS()->IgnoreParenImpCasts();
} else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(SimpleExpr)) {
OOK = OCE->getOperator();
OOLoc = OCE->getOperatorLoc();
LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
} else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SimpleExpr)) {
OOK = MCE->getMethodDecl()
->getNameInfo()
.getName()
.getCXXOverloadedOperator();
OOLoc = MCE->getCallee()->getExprLoc();
LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts();
RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
}
SourceLocation ELoc;
SourceRange ERange;
auto Res = getPrivateItem(*this, LHS, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
}
ValueDecl *D = Res.first;
if (!D)
continue;
if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) {
Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus);
continue;
}
if (RHS) {
ExprResult RHSRes = VerifyPositiveIntegerConstantInClause(
RHS, OMPC_depend, /*StrictlyPositive=*/false);
if (RHSRes.isInvalid())
continue;
}
if (!CurContext->isDependentContext() &&
DSAStack->getParentOrderedRegionParam().first &&
DepCounter != DSAStack->isParentLoopControlVariable(D).first) {
const ValueDecl *VD =
DSAStack->getParentLoopControlVariable(DepCounter.getZExtValue());
if (VD)
Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration)
<< 1 << VD;
else
Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) << 0;
continue;
}
OpsOffs.emplace_back(RHS, OOK);
} else {
auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
if (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
(ASE &&
!ASE->getBase()->getType().getNonReferenceType()->isPointerType() &&
!ASE->getBase()->getType().getNonReferenceType()->isArrayType())) {
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
<< RefExpr->getSourceRange();
continue;
}
bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
ExprResult Res =
CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RefExpr->IgnoreParenImpCasts());
getDiagnostics().setSuppressAllDiagnostics(Suppress);
if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) {
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
<< RefExpr->getSourceRange();
continue;
}
}
Vars.push_back(RefExpr->IgnoreParenImpCasts());
}
if (!CurContext->isDependentContext() && DepKind == OMPC_DEPEND_sink &&
TotalDepCount > VarList.size() &&
DSAStack->getParentOrderedRegionParam().first &&
DSAStack->getParentLoopControlVariable(VarList.size() + 1)) {
Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration)
<< 1 << DSAStack->getParentLoopControlVariable(VarList.size() + 1);
}
if (DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink &&
Vars.empty())
return nullptr;
auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc,
DepKind, DepLoc, ColonLoc, Vars,
TotalDepCount.getZExtValue());
if ((DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) &&
DSAStack->isParentOrderedRegion())
DSAStack->addDoacrossDependClause(C, OpsOffs);
return C;
}
OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Device;
Stmt *HelperValStmt = nullptr;
// OpenMP [2.9.1, Restrictions]
// The device expression must evaluate to a non-negative integer value.
if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_device,
/*StrictlyPositive=*/false))
return nullptr;
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
getOpenMPCaptureRegionForClause(DKind, OMPC_device);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
HelperValStmt = buildPreInits(Context, Captures);
}
return new (Context) OMPDeviceClause(ValExpr, HelperValStmt, CaptureRegion,
StartLoc, LParenLoc, EndLoc);
}
static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
DSAStackTy *Stack, QualType QTy,
bool FullCheck = true) {
NamedDecl *ND;
if (QTy->isIncompleteType(&ND)) {
SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR;
return false;
}
if (FullCheck && !SemaRef.CurContext->isDependentContext() &&
!QTy.isTrivialType(SemaRef.Context))
SemaRef.Diag(SL, diag::warn_omp_non_trivial_type_mapped) << QTy << SR;
return true;
}
/// Return true if it can be proven that the provided array expression
/// (array section or array subscript) does NOT specify the whole size of the
/// array whose base type is \a BaseQTy.
static bool checkArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef,
const Expr *E,
QualType BaseQTy) {
const auto *OASE = dyn_cast<OMPArraySectionExpr>(E);
// If this is an array subscript, it refers to the whole size if the size of
// the dimension is constant and equals 1. Also, an array section assumes the
// format of an array subscript if no colon is used.
if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) {
if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
return ATy->getSize().getSExtValue() != 1;
// Size can't be evaluated statically.
return false;
}
assert(OASE && "Expecting array section if not an array subscript.");
const Expr *LowerBound = OASE->getLowerBound();
const Expr *Length = OASE->getLength();
// If there is a lower bound that does not evaluates to zero, we are not
// covering the whole dimension.
if (LowerBound) {
Expr::EvalResult Result;
if (!LowerBound->EvaluateAsInt(Result, SemaRef.getASTContext()))
return false; // Can't get the integer value as a constant.
llvm::APSInt ConstLowerBound = Result.Val.getInt();
if (ConstLowerBound.getSExtValue())
return true;
}
// If we don't have a length we covering the whole dimension.
if (!Length)
return false;
// If the base is a pointer, we don't have a way to get the size of the
// pointee.
if (BaseQTy->isPointerType())
return false;
// We can only check if the length is the same as the size of the dimension
// if we have a constant array.
const auto *CATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr());
if (!CATy)
return false;
Expr::EvalResult Result;
if (!Length->EvaluateAsInt(Result, SemaRef.getASTContext()))
return false; // Can't get the integer value as a constant.
llvm::APSInt ConstLength = Result.Val.getInt();
return CATy->getSize().getSExtValue() != ConstLength.getSExtValue();
}
// Return true if it can be proven that the provided array expression (array
// section or array subscript) does NOT specify a single element of the array
// whose base type is \a BaseQTy.
static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef,
const Expr *E,
QualType BaseQTy) {
const auto *OASE = dyn_cast<OMPArraySectionExpr>(E);
// An array subscript always refer to a single element. Also, an array section
// assumes the format of an array subscript if no colon is used.
if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid()))
return false;
assert(OASE && "Expecting array section if not an array subscript.");
const Expr *Length = OASE->getLength();
// If we don't have a length we have to check if the array has unitary size
// for this dimension. Also, we should always expect a length if the base type
// is pointer.
if (!Length) {
if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
return ATy->getSize().getSExtValue() != 1;
// We cannot assume anything.
return false;
}
// Check if the length evaluates to 1.
Expr::EvalResult Result;
if (!Length->EvaluateAsInt(Result, SemaRef.getASTContext()))
return false; // Can't get the integer value as a constant.
llvm::APSInt ConstLength = Result.Val.getInt();
return ConstLength.getSExtValue() != 1;
}
// Return the expression of the base of the mappable expression or null if it
// cannot be determined and do all the necessary checks to see if the expression
// is valid as a standalone mappable expression. In the process, record all the
// components of the expression.
static const Expr *checkMapClauseExpressionBase(
Sema &SemaRef, Expr *E,
OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents,
OpenMPClauseKind CKind, bool NoDiagnose) {
SourceLocation ELoc = E->getExprLoc();
SourceRange ERange = E->getSourceRange();
// The base of elements of list in a map clause have to be either:
// - a reference to variable or field.
// - a member expression.
// - an array expression.
//
// E.g. if we have the expression 'r.S.Arr[:12]', we want to retrieve the
// reference to 'r'.
//
// If we have:
//
// struct SS {
// Bla S;
// foo() {
// #pragma omp target map (S.Arr[:12]);
// }
// }
//
// We want to retrieve the member expression 'this->S';
const Expr *RelevantExpr = nullptr;
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.2]
// If a list item is an array section, it must specify contiguous storage.
//
// For this restriction it is sufficient that we make sure only references
// to variables or fields and array expressions, and that no array sections
// exist except in the rightmost expression (unless they cover the whole
// dimension of the array). E.g. these would be invalid:
//
// r.ArrS[3:5].Arr[6:7]
//
// r.ArrS[3:5].x
//
// but these would be valid:
// r.ArrS[3].Arr[6:7]
//
// r.ArrS[3].x
bool AllowUnitySizeArraySection = true;
bool AllowWholeSizeArraySection = true;
while (!RelevantExpr) {
E = E->IgnoreParenImpCasts();
if (auto *CurE = dyn_cast<DeclRefExpr>(E)) {
if (!isa<VarDecl>(CurE->getDecl()))
return nullptr;
RelevantExpr = CurE;
// If we got a reference to a declaration, we should not expect any array
// section before that.
AllowUnitySizeArraySection = false;
AllowWholeSizeArraySection = false;
// Record the component.
CurComponents.emplace_back(CurE, CurE->getDecl());
} else if (auto *CurE = dyn_cast<MemberExpr>(E)) {
Expr *BaseE = CurE->getBase()->IgnoreParenImpCasts();
if (isa<CXXThisExpr>(BaseE))
// We found a base expression: this->Val.
RelevantExpr = CurE;
else
E = BaseE;
if (!isa<FieldDecl>(CurE->getMemberDecl())) {
if (!NoDiagnose) {
SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field)
<< CurE->getSourceRange();
return nullptr;
}
if (RelevantExpr)
return nullptr;
continue;
}
auto *FD = cast<FieldDecl>(CurE->getMemberDecl());
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3]
// A bit-field cannot appear in a map clause.
//
if (FD->isBitField()) {
if (!NoDiagnose) {
SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause)
<< CurE->getSourceRange() << getOpenMPClauseName(CKind);
return nullptr;
}
if (RelevantExpr)
return nullptr;
continue;
}
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
// If the type of a list item is a reference to a type T then the type
// will be considered to be T for all purposes of this clause.
QualType CurType = BaseE->getType().getNonReferenceType();
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.2]
// A list item cannot be a variable that is a member of a structure with
// a union type.
//
if (CurType->isUnionType()) {
if (!NoDiagnose) {
SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed)
<< CurE->getSourceRange();
return nullptr;
}
continue;
}
// If we got a member expression, we should not expect any array section
// before that:
//
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7]
// If a list item is an element of a structure, only the rightmost symbol
// of the variable reference can be an array section.
//
AllowUnitySizeArraySection = false;
AllowWholeSizeArraySection = false;
// Record the component.
CurComponents.emplace_back(CurE, FD);
} else if (auto *CurE = dyn_cast<ArraySubscriptExpr>(E)) {
E = CurE->getBase()->IgnoreParenImpCasts();
if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) {
if (!NoDiagnose) {
SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
<< 0 << CurE->getSourceRange();
return nullptr;
}
continue;
}
// If we got an array subscript that express the whole dimension we
// can have any array expressions before. If it only expressing part of
// the dimension, we can only have unitary-size array expressions.
if (checkArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE,
E->getType()))
AllowWholeSizeArraySection = false;
if (const auto *TE = dyn_cast<CXXThisExpr>(E)) {
Expr::EvalResult Result;
if (CurE->getIdx()->EvaluateAsInt(Result, SemaRef.getASTContext())) {
if (!Result.Val.getInt().isNullValue()) {
SemaRef.Diag(CurE->getIdx()->getExprLoc(),
diag::err_omp_invalid_map_this_expr);
SemaRef.Diag(CurE->getIdx()->getExprLoc(),
diag::note_omp_invalid_subscript_on_this_ptr_map);
}
}
RelevantExpr = TE;
}
// Record the component - we don't have any declaration associated.
CurComponents.emplace_back(CurE, nullptr);
} else if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) {
assert(!NoDiagnose && "Array sections cannot be implicitly mapped.");
E = CurE->getBase()->IgnoreParenImpCasts();
QualType CurType =
OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType();
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
// If the type of a list item is a reference to a type T then the type
// will be considered to be T for all purposes of this clause.
if (CurType->isReferenceType())
CurType = CurType->getPointeeType();
bool IsPointer = CurType->isAnyPointerType();
if (!IsPointer && !CurType->isArrayType()) {
SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
<< 0 << CurE->getSourceRange();
return nullptr;
}
bool NotWhole =
checkArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, CurType);
bool NotUnity =
checkArrayExpressionDoesNotReferToUnitySize(SemaRef, CurE, CurType);
if (AllowWholeSizeArraySection) {
// Any array section is currently allowed. Allowing a whole size array
// section implies allowing a unity array section as well.
//
// If this array section refers to the whole dimension we can still
// accept other array sections before this one, except if the base is a
// pointer. Otherwise, only unitary sections are accepted.
if (NotWhole || IsPointer)
AllowWholeSizeArraySection = false;
} else if (AllowUnitySizeArraySection && NotUnity) {
// A unity or whole array section is not allowed and that is not
// compatible with the properties of the current array section.
SemaRef.Diag(
ELoc, diag::err_array_section_does_not_specify_contiguous_storage)
<< CurE->getSourceRange();
return nullptr;
}
if (const auto *TE = dyn_cast<CXXThisExpr>(E)) {
Expr::EvalResult ResultR;
Expr::EvalResult ResultL;
if (CurE->getLength()->EvaluateAsInt(ResultR,
SemaRef.getASTContext())) {
if (!ResultR.Val.getInt().isOneValue()) {
SemaRef.Diag(CurE->getLength()->getExprLoc(),
diag::err_omp_invalid_map_this_expr);
SemaRef.Diag(CurE->getLength()->getExprLoc(),
diag::note_omp_invalid_length_on_this_ptr_mapping);
}
}
if (CurE->getLowerBound() && CurE->getLowerBound()->EvaluateAsInt(
ResultL, SemaRef.getASTContext())) {
if (!ResultL.Val.getInt().isNullValue()) {
SemaRef.Diag(CurE->getLowerBound()->getExprLoc(),
diag::err_omp_invalid_map_this_expr);
SemaRef.Diag(CurE->getLowerBound()->getExprLoc(),
diag::note_omp_invalid_lower_bound_on_this_ptr_mapping);
}
}
RelevantExpr = TE;
}
// Record the component - we don't have any declaration associated.
CurComponents.emplace_back(CurE, nullptr);
} else {
if (!NoDiagnose) {
// If nothing else worked, this is not a valid map clause expression.
SemaRef.Diag(
ELoc, diag::err_omp_expected_named_var_member_or_array_expression)
<< ERange;
}
return nullptr;
}
}
return RelevantExpr;
}
// Return true if expression E associated with value VD has conflicts with other
// map information.
static bool checkMapConflicts(
Sema &SemaRef, DSAStackTy *DSAS, const ValueDecl *VD, const Expr *E,
bool CurrentRegionOnly,
OMPClauseMappableExprCommon::MappableExprComponentListRef CurComponents,
OpenMPClauseKind CKind) {
assert(VD && E);
SourceLocation ELoc = E->getExprLoc();
SourceRange ERange = E->getSourceRange();
// In order to easily check the conflicts we need to match each component of
// the expression under test with the components of the expressions that are
// already in the stack.
assert(!CurComponents.empty() && "Map clause expression with no components!");
assert(CurComponents.back().getAssociatedDeclaration() == VD &&
"Map clause expression with unexpected base!");
// Variables to help detecting enclosing problems in data environment nests.
bool IsEnclosedByDataEnvironmentExpr = false;
const Expr *EnclosingExpr = nullptr;
bool FoundError = DSAS->checkMappableExprComponentListsForDecl(
VD, CurrentRegionOnly,
[&IsEnclosedByDataEnvironmentExpr, &SemaRef, VD, CurrentRegionOnly, ELoc,
ERange, CKind, &EnclosingExpr,
CurComponents](OMPClauseMappableExprCommon::MappableExprComponentListRef
StackComponents,
OpenMPClauseKind) {
assert(!StackComponents.empty() &&
"Map clause expression with no components!");
assert(StackComponents.back().getAssociatedDeclaration() == VD &&
"Map clause expression with unexpected base!");
(void)VD;
// The whole expression in the stack.
const Expr *RE = StackComponents.front().getAssociatedExpression();
// Expressions must start from the same base. Here we detect at which
// point both expressions diverge from each other and see if we can
// detect if the memory referred to both expressions is contiguous and
// do not overlap.
auto CI = CurComponents.rbegin();
auto CE = CurComponents.rend();
auto SI = StackComponents.rbegin();
auto SE = StackComponents.rend();
for (; CI != CE && SI != SE; ++CI, ++SI) {
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.3]
// At most one list item can be an array item derived from a given
// variable in map clauses of the same construct.
if (CurrentRegionOnly &&
(isa<ArraySubscriptExpr>(CI->getAssociatedExpression()) ||
isa<OMPArraySectionExpr>(CI->getAssociatedExpression())) &&
(isa<ArraySubscriptExpr>(SI->getAssociatedExpression()) ||
isa<OMPArraySectionExpr>(SI->getAssociatedExpression()))) {
SemaRef.Diag(CI->getAssociatedExpression()->getExprLoc(),
diag::err_omp_multiple_array_items_in_map_clause)
<< CI->getAssociatedExpression()->getSourceRange();
SemaRef.Diag(SI->getAssociatedExpression()->getExprLoc(),
diag::note_used_here)
<< SI->getAssociatedExpression()->getSourceRange();
return true;
}
// Do both expressions have the same kind?
if (CI->getAssociatedExpression()->getStmtClass() !=
SI->getAssociatedExpression()->getStmtClass())
break;
// Are we dealing with different variables/fields?
if (CI->getAssociatedDeclaration() != SI->getAssociatedDeclaration())
break;
}
// Check if the extra components of the expressions in the enclosing
// data environment are redundant for the current base declaration.
// If they are, the maps completely overlap, which is legal.
for (; SI != SE; ++SI) {
QualType Type;
if (const auto *ASE =
dyn_cast<ArraySubscriptExpr>(SI->getAssociatedExpression())) {
Type = ASE->getBase()->IgnoreParenImpCasts()->getType();
} else if (const auto *OASE = dyn_cast<OMPArraySectionExpr>(
SI->getAssociatedExpression())) {
const Expr *E = OASE->getBase()->IgnoreParenImpCasts();
Type =
OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType();
}
if (Type.isNull() || Type->isAnyPointerType() ||
checkArrayExpressionDoesNotReferToWholeSize(
SemaRef, SI->getAssociatedExpression(), Type))
break;
}
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.4]
// List items of map clauses in the same construct must not share
// original storage.
//
// If the expressions are exactly the same or one is a subset of the
// other, it means they are sharing storage.
if (CI == CE && SI == SE) {
if (CurrentRegionOnly) {
if (CKind == OMPC_map) {
SemaRef.Diag(ELoc, diag::err_omp_map_shared_storage) << ERange;
} else {
assert(CKind == OMPC_to || CKind == OMPC_from);
SemaRef.Diag(ELoc, diag::err_omp_once_referenced_in_target_update)
<< ERange;
}
SemaRef.Diag(RE->getExprLoc(), diag::note_used_here)
<< RE->getSourceRange();
return true;
}
// If we find the same expression in the enclosing data environment,
// that is legal.
IsEnclosedByDataEnvironmentExpr = true;
return false;
}
QualType DerivedType =
std::prev(CI)->getAssociatedDeclaration()->getType();
SourceLocation DerivedLoc =
std::prev(CI)->getAssociatedExpression()->getExprLoc();
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
// If the type of a list item is a reference to a type T then the type
// will be considered to be T for all purposes of this clause.
DerivedType = DerivedType.getNonReferenceType();
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.1]
// A variable for which the type is pointer and an array section
// derived from that variable must not appear as list items of map
// clauses of the same construct.
//
// Also, cover one of the cases in:
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.5]
// If any part of the original storage of a list item has corresponding
// storage in the device data environment, all of the original storage
// must have corresponding storage in the device data environment.
//
if (DerivedType->isAnyPointerType()) {
if (CI == CE || SI == SE) {
SemaRef.Diag(
DerivedLoc,
diag::err_omp_pointer_mapped_along_with_derived_section)
<< DerivedLoc;
SemaRef.Diag(RE->getExprLoc(), diag::note_used_here)
<< RE->getSourceRange();
return true;
}
if (CI->getAssociatedExpression()->getStmtClass() !=
SI->getAssociatedExpression()->getStmtClass() ||
CI->getAssociatedDeclaration()->getCanonicalDecl() ==
SI->getAssociatedDeclaration()->getCanonicalDecl()) {
assert(CI != CE && SI != SE);
SemaRef.Diag(DerivedLoc, diag::err_omp_same_pointer_dereferenced)
<< DerivedLoc;
SemaRef.Diag(RE->getExprLoc(), diag::note_used_here)
<< RE->getSourceRange();
return true;
}
}
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.4]
// List items of map clauses in the same construct must not share
// original storage.
//
// An expression is a subset of the other.
if (CurrentRegionOnly && (CI == CE || SI == SE)) {
if (CKind == OMPC_map) {
if (CI != CE || SI != SE) {
// Allow constructs like this: map(s, s.ptr[0:1]), where s.ptr is
// a pointer.
auto Begin =
CI != CE ? CurComponents.begin() : StackComponents.begin();
auto End = CI != CE ? CurComponents.end() : StackComponents.end();
auto It = Begin;
while (It != End && !It->getAssociatedDeclaration())
std::advance(It, 1);
assert(It != End &&
"Expected at least one component with the declaration.");
if (It != Begin && It->getAssociatedDeclaration()
->getType()
.getCanonicalType()
->isAnyPointerType()) {
IsEnclosedByDataEnvironmentExpr = false;
EnclosingExpr = nullptr;
return false;
}
}
SemaRef.Diag(ELoc, diag::err_omp_map_shared_storage) << ERange;
} else {
assert(CKind == OMPC_to || CKind == OMPC_from);
SemaRef.Diag(ELoc, diag::err_omp_once_referenced_in_target_update)
<< ERange;
}
SemaRef.Diag(RE->getExprLoc(), diag::note_used_here)
<< RE->getSourceRange();
return true;
}
// The current expression uses the same base as other expression in the
// data environment but does not contain it completely.
if (!CurrentRegionOnly && SI != SE)
EnclosingExpr = RE;
// The current expression is a subset of the expression in the data
// environment.
IsEnclosedByDataEnvironmentExpr |=
(!CurrentRegionOnly && CI != CE && SI == SE);
return false;
});
if (CurrentRegionOnly)
return FoundError;
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.5]
// If any part of the original storage of a list item has corresponding
// storage in the device data environment, all of the original storage must
// have corresponding storage in the device data environment.
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.6]
// If a list item is an element of a structure, and a different element of
// the structure has a corresponding list item in the device data environment
// prior to a task encountering the construct associated with the map clause,
// then the list item must also have a corresponding list item in the device
// data environment prior to the task encountering the construct.
//
if (EnclosingExpr && !IsEnclosedByDataEnvironmentExpr) {
SemaRef.Diag(ELoc,
diag::err_omp_original_storage_is_shared_and_does_not_contain)
<< ERange;
SemaRef.Diag(EnclosingExpr->getExprLoc(), diag::note_used_here)
<< EnclosingExpr->getSourceRange();
return true;
}
return FoundError;
}
namespace {
// Utility struct that gathers all the related lists associated with a mappable
// expression.
struct MappableVarListInfo {
// The list of expressions.
ArrayRef<Expr *> VarList;
// The list of processed expressions.
SmallVector<Expr *, 16> ProcessedVarList;
// The mappble components for each expression.
OMPClauseMappableExprCommon::MappableExprComponentLists VarComponents;
// The base declaration of the variable.
SmallVector<ValueDecl *, 16> VarBaseDeclarations;
MappableVarListInfo(ArrayRef<Expr *> VarList) : VarList(VarList) {
// We have a list of components and base declarations for each entry in the
// variable list.
VarComponents.reserve(VarList.size());
VarBaseDeclarations.reserve(VarList.size());
}
};
}
// Check the validity of the provided variable list for the provided clause kind
// \a CKind. In the check process the valid expressions, and mappable expression
// components and variables are extracted and used to fill \a Vars,
// \a ClauseComponents, and \a ClauseBaseDeclarations. \a MapType and
// \a IsMapTypeImplicit are expected to be valid if the clause kind is 'map'.
static void
checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS,
OpenMPClauseKind CKind, MappableVarListInfo &MVLI,
SourceLocation StartLoc,
OpenMPMapClauseKind MapType = OMPC_MAP_unknown,
bool IsMapTypeImplicit = false) {
// We only expect mappable expressions in 'to', 'from', and 'map' clauses.
assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from) &&
"Unexpected clause kind with mappable expressions!");
// Keep track of the mappable components and base declarations in this clause.
// Each entry in the list is going to have a list of components associated. We
// record each set of the components so that we can build the clause later on.
// In the end we should have the same amount of declarations and component
// lists.
for (Expr *RE : MVLI.VarList) {
assert(RE && "Null expr in omp to/from/map clause");
SourceLocation ELoc = RE->getExprLoc();
const Expr *VE = RE->IgnoreParenLValueCasts();
if (VE->isValueDependent() || VE->isTypeDependent() ||
VE->isInstantiationDependent() ||
VE->containsUnexpandedParameterPack()) {
// We can only analyze this information once the missing information is
// resolved.
MVLI.ProcessedVarList.push_back(RE);
continue;
}
Expr *SimpleExpr = RE->IgnoreParenCasts();
if (!RE->IgnoreParenImpCasts()->isLValue()) {
SemaRef.Diag(ELoc,
diag::err_omp_expected_named_var_member_or_array_expression)
<< RE->getSourceRange();
continue;
}
OMPClauseMappableExprCommon::MappableExprComponentList CurComponents;
ValueDecl *CurDeclaration = nullptr;
// Obtain the array or member expression bases if required. Also, fill the
// components array with all the components identified in the process.
const Expr *BE = checkMapClauseExpressionBase(
SemaRef, SimpleExpr, CurComponents, CKind, /*NoDiagnose=*/false);
if (!BE)
continue;
assert(!CurComponents.empty() &&
"Invalid mappable expression information.");
if (const auto *TE = dyn_cast<CXXThisExpr>(BE)) {
// Add store "this" pointer to class in DSAStackTy for future checking
DSAS->addMappedClassesQualTypes(TE->getType());
// Skip restriction checking for variable or field declarations
MVLI.ProcessedVarList.push_back(RE);
MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1);
MVLI.VarComponents.back().append(CurComponents.begin(),
CurComponents.end());
MVLI.VarBaseDeclarations.push_back(nullptr);
continue;
}
// For the following checks, we rely on the base declaration which is
// expected to be associated with the last component. The declaration is
// expected to be a variable or a field (if 'this' is being mapped).
CurDeclaration = CurComponents.back().getAssociatedDeclaration();
assert(CurDeclaration && "Null decl on map clause.");
assert(
CurDeclaration->isCanonicalDecl() &&
"Expecting components to have associated only canonical declarations.");
auto *VD = dyn_cast<VarDecl>(CurDeclaration);
const auto *FD = dyn_cast<FieldDecl>(CurDeclaration);
assert((VD || FD) && "Only variables or fields are expected here!");
(void)FD;
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.10]
// threadprivate variables cannot appear in a map clause.
// OpenMP 4.5 [2.10.5, target update Construct]
// threadprivate variables cannot appear in a from clause.
if (VD && DSAS->isThreadPrivate(VD)) {
DSAStackTy::DSAVarData DVar = DSAS->getTopDSA(VD, /*FromParent=*/false);
SemaRef.Diag(ELoc, diag::err_omp_threadprivate_in_clause)
<< getOpenMPClauseName(CKind);
reportOriginalDsa(SemaRef, DSAS, VD, DVar);
continue;
}
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.9]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct.
// Check conflicts with other map clause expressions. We check the conflicts
// with the current construct separately from the enclosing data
// environment, because the restrictions are different. We only have to
// check conflicts across regions for the map clauses.
if (checkMapConflicts(SemaRef, DSAS, CurDeclaration, SimpleExpr,
/*CurrentRegionOnly=*/true, CurComponents, CKind))
break;
if (CKind == OMPC_map &&
checkMapConflicts(SemaRef, DSAS, CurDeclaration, SimpleExpr,
/*CurrentRegionOnly=*/false, CurComponents, CKind))
break;
// OpenMP 4.5 [2.10.5, target update Construct]
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
// If the type of a list item is a reference to a type T then the type will
// be considered to be T for all purposes of this clause.
auto I = llvm::find_if(
CurComponents,
[](const OMPClauseMappableExprCommon::MappableComponent &MC) {
return MC.getAssociatedDeclaration();
});
assert(I != CurComponents.end() && "Null decl on map clause.");
QualType Type =
I->getAssociatedDeclaration()->getType().getNonReferenceType();
// OpenMP 4.5 [2.10.5, target update Construct, Restrictions, p.4]
// A list item in a to or from clause must have a mappable type.
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.9]
// A list item must have a mappable type.
if (!checkTypeMappable(VE->getExprLoc(), VE->getSourceRange(), SemaRef,
DSAS, Type))
continue;
if (CKind == OMPC_map) {
// target enter data
// OpenMP [2.10.2, Restrictions, p. 99]
// A map-type must be specified in all map clauses and must be either
// to or alloc.
OpenMPDirectiveKind DKind = DSAS->getCurrentDirective();
if (DKind == OMPD_target_enter_data &&
!(MapType == OMPC_MAP_to || MapType == OMPC_MAP_alloc)) {
SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive)
<< (IsMapTypeImplicit ? 1 : 0)
<< getOpenMPSimpleClauseTypeName(OMPC_map, MapType)
<< getOpenMPDirectiveName(DKind);
continue;
}
// target exit_data
// OpenMP [2.10.3, Restrictions, p. 102]
// A map-type must be specified in all map clauses and must be either
// from, release, or delete.
if (DKind == OMPD_target_exit_data &&
!(MapType == OMPC_MAP_from || MapType == OMPC_MAP_release ||
MapType == OMPC_MAP_delete)) {
SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive)
<< (IsMapTypeImplicit ? 1 : 0)
<< getOpenMPSimpleClauseTypeName(OMPC_map, MapType)
<< getOpenMPDirectiveName(DKind);
continue;
}
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
if (VD && isOpenMPTargetExecutionDirective(DKind)) {
DSAStackTy::DSAVarData DVar = DSAS->getTopDSA(VD, /*FromParent=*/false);
if (isOpenMPPrivate(DVar.CKind)) {
SemaRef.Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_map)
<< getOpenMPDirectiveName(DSAS->getCurrentDirective());
reportOriginalDsa(SemaRef, DSAS, CurDeclaration, DVar);
continue;
}
}
}
// Save the current expression.
MVLI.ProcessedVarList.push_back(RE);
// Store the components in the stack so that they can be used to check
// against other clauses later on.
DSAS->addMappableExpressionComponents(CurDeclaration, CurComponents,
/*WhereFoundClauseKind=*/OMPC_map);
// Save the components and declaration to create the clause. For purposes of
// the clause creation, any component list that has has base 'this' uses
// null as base declaration.
MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1);
MVLI.VarComponents.back().append(CurComponents.begin(),
CurComponents.end());
MVLI.VarBaseDeclarations.push_back(isa<MemberExpr>(BE) ? nullptr
: CurDeclaration);
}
}
OMPClause *
Sema::ActOnOpenMPMapClause(ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
ArrayRef<SourceLocation> MapTypeModifiersLoc,
OpenMPMapClauseKind MapType, bool IsMapTypeImplicit,
SourceLocation MapLoc, SourceLocation ColonLoc,
ArrayRef<Expr *> VarList, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc) {
MappableVarListInfo MVLI(VarList);
checkMappableExpressionList(*this, DSAStack, OMPC_map, MVLI, StartLoc,
MapType, IsMapTypeImplicit);
OpenMPMapModifierKind Modifiers[] = { OMPC_MAP_MODIFIER_unknown,
OMPC_MAP_MODIFIER_unknown };
SourceLocation ModifiersLoc[OMPMapClause::NumberOfModifiers];
// Process map-type-modifiers, flag errors for duplicate modifiers.
unsigned Count = 0;
for (unsigned I = 0, E = MapTypeModifiers.size(); I < E; ++I) {
if (MapTypeModifiers[I] != OMPC_MAP_MODIFIER_unknown &&
llvm::find(Modifiers, MapTypeModifiers[I]) != std::end(Modifiers)) {
Diag(MapTypeModifiersLoc[I], diag::err_omp_duplicate_map_type_modifier);
continue;
}
assert(Count < OMPMapClause::NumberOfModifiers &&
"Modifiers exceed the allowed number of map type modifiers");
Modifiers[Count] = MapTypeModifiers[I];
ModifiersLoc[Count] = MapTypeModifiersLoc[I];
++Count;
}
// We need to produce a map clause even if we don't have variables so that
// other diagnostics related with non-existing map clauses are accurate.
return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc,
MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
MVLI.VarComponents, Modifiers, ModifiersLoc,
MapType, IsMapTypeImplicit, MapLoc);
}
QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc,
TypeResult ParsedType) {
assert(ParsedType.isUsable());
QualType ReductionType = GetTypeFromParser(ParsedType.get());
if (ReductionType.isNull())
return QualType();
// [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions, C\C++
// A type name in a declare reduction directive cannot be a function type, an
// array type, a reference type, or a type qualified with const, volatile or
// restrict.
if (ReductionType.hasQualifiers()) {
Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 0;
return QualType();
}
if (ReductionType->isFunctionType()) {
Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 1;
return QualType();
}
if (ReductionType->isReferenceType()) {
Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 2;
return QualType();
}
if (ReductionType->isArrayType()) {
Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 3;
return QualType();
}
return ReductionType;
}
Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart(
Scope *S, DeclContext *DC, DeclarationName Name,
ArrayRef<std::pair<QualType, SourceLocation>> ReductionTypes,
AccessSpecifier AS, Decl *PrevDeclInScope) {
SmallVector<Decl *, 8> Decls;
Decls.reserve(ReductionTypes.size());
LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPReductionName,
forRedeclarationInCurContext());
// [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
// A reduction-identifier may not be re-declared in the current scope for the
// same type or for a type that is compatible according to the base language
// rules.
llvm::DenseMap<QualType, SourceLocation> PreviousRedeclTypes;
OMPDeclareReductionDecl *PrevDRD = nullptr;
bool InCompoundScope = true;
if (S != nullptr) {
// Find previous declaration with the same name not referenced in other
// declarations.
FunctionScopeInfo *ParentFn = getEnclosingFunction();
InCompoundScope =
(ParentFn != nullptr) && !ParentFn->CompoundScopes.empty();
LookupName(Lookup, S);
FilterLookupForScope(Lookup, DC, S, /*ConsiderLinkage=*/false,
/*AllowInlineNamespace=*/false);
llvm::DenseMap<OMPDeclareReductionDecl *, bool> UsedAsPrevious;
LookupResult::Filter Filter = Lookup.makeFilter();
while (Filter.hasNext()) {
auto *PrevDecl = cast<OMPDeclareReductionDecl>(Filter.next());
if (InCompoundScope) {
auto I = UsedAsPrevious.find(PrevDecl);
if (I == UsedAsPrevious.end())
UsedAsPrevious[PrevDecl] = false;
if (OMPDeclareReductionDecl *D = PrevDecl->getPrevDeclInScope())
UsedAsPrevious[D] = true;
}
PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] =
PrevDecl->getLocation();
}
Filter.done();
if (InCompoundScope) {
for (const auto &PrevData : UsedAsPrevious) {
if (!PrevData.second) {
PrevDRD = PrevData.first;
break;
}
}
}
} else if (PrevDeclInScope != nullptr) {
auto *PrevDRDInScope = PrevDRD =
cast<OMPDeclareReductionDecl>(PrevDeclInScope);
do {
PreviousRedeclTypes[PrevDRDInScope->getType().getCanonicalType()] =
PrevDRDInScope->getLocation();
PrevDRDInScope = PrevDRDInScope->getPrevDeclInScope();
} while (PrevDRDInScope != nullptr);
}
for (const auto &TyData : ReductionTypes) {
const auto I = PreviousRedeclTypes.find(TyData.first.getCanonicalType());
bool Invalid = false;
if (I != PreviousRedeclTypes.end()) {
Diag(TyData.second, diag::err_omp_declare_reduction_redefinition)
<< TyData.first;
Diag(I->second, diag::note_previous_definition);
Invalid = true;
}
PreviousRedeclTypes[TyData.first.getCanonicalType()] = TyData.second;
auto *DRD = OMPDeclareReductionDecl::Create(Context, DC, TyData.second,
Name, TyData.first, PrevDRD);
DC->addDecl(DRD);
DRD->setAccess(AS);
Decls.push_back(DRD);
if (Invalid)
DRD->setInvalidDecl();
else
PrevDRD = DRD;
}
return DeclGroupPtrTy::make(
DeclGroupRef::Create(Context, Decls.begin(), Decls.size()));
}
void Sema::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) {
auto *DRD = cast<OMPDeclareReductionDecl>(D);
// Enter new function scope.
PushFunctionScope();
setFunctionHasBranchProtectedScope();
getCurFunction()->setHasOMPDeclareReductionCombiner();
if (S != nullptr)
PushDeclContext(S, DRD);
else
CurContext = DRD;
PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated);
QualType ReductionType = DRD->getType();
// Create 'T* omp_parm;T omp_in;'. All references to 'omp_in' will
// be replaced by '*omp_parm' during codegen. This required because 'omp_in'
// uses semantics of argument handles by value, but it should be passed by
// reference. C lang does not support references, so pass all parameters as
// pointers.
// Create 'T omp_in;' variable.
VarDecl *OmpInParm =
buildVarDecl(*this, D->getLocation(), ReductionType, "omp_in");
// Create 'T* omp_parm;T omp_out;'. All references to 'omp_out' will
// be replaced by '*omp_parm' during codegen. This required because 'omp_out'
// uses semantics of argument handles by value, but it should be passed by
// reference. C lang does not support references, so pass all parameters as
// pointers.
// Create 'T omp_out;' variable.
VarDecl *OmpOutParm =
buildVarDecl(*this, D->getLocation(), ReductionType, "omp_out");
if (S != nullptr) {
PushOnScopeChains(OmpInParm, S);
PushOnScopeChains(OmpOutParm, S);
} else {
DRD->addDecl(OmpInParm);
DRD->addDecl(OmpOutParm);
}
Expr *InE =
::buildDeclRefExpr(*this, OmpInParm, ReductionType, D->getLocation());
Expr *OutE =
::buildDeclRefExpr(*this, OmpOutParm, ReductionType, D->getLocation());
DRD->setCombinerData(InE, OutE);
}
void Sema::ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner) {
auto *DRD = cast<OMPDeclareReductionDecl>(D);
DiscardCleanupsInEvaluationContext();
PopExpressionEvaluationContext();
PopDeclContext();
PopFunctionScopeInfo();
if (Combiner != nullptr)
DRD->setCombiner(Combiner);
else
DRD->setInvalidDecl();
}
VarDecl *Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) {
auto *DRD = cast<OMPDeclareReductionDecl>(D);
// Enter new function scope.
PushFunctionScope();
setFunctionHasBranchProtectedScope();
if (S != nullptr)
PushDeclContext(S, DRD);
else
CurContext = DRD;
PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated);
QualType ReductionType = DRD->getType();
// Create 'T* omp_parm;T omp_priv;'. All references to 'omp_priv' will
// be replaced by '*omp_parm' during codegen. This required because 'omp_priv'
// uses semantics of argument handles by value, but it should be passed by
// reference. C lang does not support references, so pass all parameters as
// pointers.
// Create 'T omp_priv;' variable.
VarDecl *OmpPrivParm =
buildVarDecl(*this, D->getLocation(), ReductionType, "omp_priv");
// Create 'T* omp_parm;T omp_orig;'. All references to 'omp_orig' will
// be replaced by '*omp_parm' during codegen. This required because 'omp_orig'
// uses semantics of argument handles by value, but it should be passed by
// reference. C lang does not support references, so pass all parameters as
// pointers.
// Create 'T omp_orig;' variable.
VarDecl *OmpOrigParm =
buildVarDecl(*this, D->getLocation(), ReductionType, "omp_orig");
if (S != nullptr) {
PushOnScopeChains(OmpPrivParm, S);
PushOnScopeChains(OmpOrigParm, S);
} else {
DRD->addDecl(OmpPrivParm);
DRD->addDecl(OmpOrigParm);
}
Expr *OrigE =
::buildDeclRefExpr(*this, OmpOrigParm, ReductionType, D->getLocation());
Expr *PrivE =
::buildDeclRefExpr(*this, OmpPrivParm, ReductionType, D->getLocation());
DRD->setInitializerData(OrigE, PrivE);
return OmpPrivParm;
}
void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer,
VarDecl *OmpPrivParm) {
auto *DRD = cast<OMPDeclareReductionDecl>(D);
DiscardCleanupsInEvaluationContext();
PopExpressionEvaluationContext();
PopDeclContext();
PopFunctionScopeInfo();
if (Initializer != nullptr) {
DRD->setInitializer(Initializer, OMPDeclareReductionDecl::CallInit);
} else if (OmpPrivParm->hasInit()) {
DRD->setInitializer(OmpPrivParm->getInit(),
OmpPrivParm->isDirectInit()
? OMPDeclareReductionDecl::DirectInit
: OMPDeclareReductionDecl::CopyInit);
} else {
DRD->setInvalidDecl();
}
}
Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd(
Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid) {
for (Decl *D : DeclReductions.get()) {
if (IsValid) {
if (S)
PushOnScopeChains(cast<OMPDeclareReductionDecl>(D), S,
/*AddToContext=*/false);
} else {
D->setInvalidDecl();
}
}
return DeclReductions;
}
OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = NumTeams;
Stmt *HelperValStmt = nullptr;
// OpenMP [teams Constrcut, Restrictions]
// The num_teams expression must evaluate to a positive integer value.
if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_num_teams,
/*StrictlyPositive=*/true))
return nullptr;
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
HelperValStmt = buildPreInits(Context, Captures);
}
return new (Context) OMPNumTeamsClause(ValExpr, HelperValStmt, CaptureRegion,
StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = ThreadLimit;
Stmt *HelperValStmt = nullptr;
// OpenMP [teams Constrcut, Restrictions]
// The thread_limit expression must evaluate to a positive integer value.
if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_thread_limit,
/*StrictlyPositive=*/true))
return nullptr;
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
getOpenMPCaptureRegionForClause(DKind, OMPC_thread_limit);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
HelperValStmt = buildPreInits(Context, Captures);
}
return new (Context) OMPThreadLimitClause(
ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Priority;
// OpenMP [2.9.1, task Constrcut]
// The priority-value is a non-negative numerical scalar expression.
if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_priority,
/*StrictlyPositive=*/false))
return nullptr;
return new (Context) OMPPriorityClause(ValExpr, StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Grainsize;
// OpenMP [2.9.2, taskloop Constrcut]
// The parameter of the grainsize clause must be a positive integer
// expression.
if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize,
/*StrictlyPositive=*/true))
return nullptr;
return new (Context) OMPGrainsizeClause(ValExpr, StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = NumTasks;
// OpenMP [2.9.2, taskloop Constrcut]
// The parameter of the num_tasks clause must be a positive integer
// expression.
if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_num_tasks,
/*StrictlyPositive=*/true))
return nullptr;
return new (Context) OMPNumTasksClause(ValExpr, StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
// OpenMP [2.13.2, critical construct, Description]
// ... where hint-expression is an integer constant expression that evaluates
// to a valid lock hint.
ExprResult HintExpr = VerifyPositiveIntegerConstantInClause(Hint, OMPC_hint);
if (HintExpr.isInvalid())
return nullptr;
return new (Context)
OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPDistScheduleClause(
OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc,
SourceLocation EndLoc) {
if (Kind == OMPC_DIST_SCHEDULE_unknown) {
std::string Values;
Values += "'";
Values += getOpenMPSimpleClauseTypeName(OMPC_dist_schedule, 0);
Values += "'";
Diag(KindLoc, diag::err_omp_unexpected_clause_value)
<< Values << getOpenMPClauseName(OMPC_dist_schedule);
return nullptr;
}
Expr *ValExpr = ChunkSize;
Stmt *HelperValStmt = nullptr;
if (ChunkSize) {
if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() &&
!ChunkSize->isInstantiationDependent() &&
!ChunkSize->containsUnexpandedParameterPack()) {
SourceLocation ChunkSizeLoc = ChunkSize->getBeginLoc();
ExprResult Val =
PerformOpenMPImplicitIntegerConversion(ChunkSizeLoc, ChunkSize);
if (Val.isInvalid())
return nullptr;
ValExpr = Val.get();
// OpenMP [2.7.1, Restrictions]
// chunk_size must be a loop invariant integer expression with a positive
// value.
llvm::APSInt Result;
if (ValExpr->isIntegerConstantExpr(Result, Context)) {
if (Result.isSigned() && !Result.isStrictlyPositive()) {
Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause)
<< "dist_schedule" << ChunkSize->getSourceRange();
return nullptr;
}
} else if (getOpenMPCaptureRegionForClause(
DSAStack->getCurrentDirective(), OMPC_dist_schedule) !=
OMPD_unknown &&
!CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
HelperValStmt = buildPreInits(Context, Captures);
}
}
}
return new (Context)
OMPDistScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc,
Kind, ValExpr, HelperValStmt);
}
OMPClause *Sema::ActOnOpenMPDefaultmapClause(
OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind,
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc,
SourceLocation KindLoc, SourceLocation EndLoc) {
// OpenMP 4.5 only supports 'defaultmap(tofrom: scalar)'
if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom || Kind != OMPC_DEFAULTMAP_scalar) {
std::string Value;
SourceLocation Loc;
Value += "'";
if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom) {
Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
OMPC_DEFAULTMAP_MODIFIER_tofrom);
Loc = MLoc;
} else {
Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
OMPC_DEFAULTMAP_scalar);
Loc = KindLoc;
}
Value += "'";
Diag(Loc, diag::err_omp_unexpected_clause_value)
<< Value << getOpenMPClauseName(OMPC_defaultmap);
return nullptr;
}
DSAStack->setDefaultDMAToFromScalar(StartLoc);
return new (Context)
OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M);
}
bool Sema::ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc) {
DeclContext *CurLexicalContext = getCurLexicalContext();
if (!CurLexicalContext->isFileContext() &&
!CurLexicalContext->isExternCContext() &&
!CurLexicalContext->isExternCXXContext() &&
!isa<CXXRecordDecl>(CurLexicalContext) &&
!isa<ClassTemplateDecl>(CurLexicalContext) &&
!isa<ClassTemplatePartialSpecializationDecl>(CurLexicalContext) &&
!isa<ClassTemplateSpecializationDecl>(CurLexicalContext)) {
Diag(Loc, diag::err_omp_region_not_file_context);
return false;
}
++DeclareTargetNestingLevel;
return true;
}
void Sema::ActOnFinishOpenMPDeclareTargetDirective() {
assert(DeclareTargetNestingLevel > 0 &&
"Unexpected ActOnFinishOpenMPDeclareTargetDirective");
--DeclareTargetNestingLevel;
}
void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope,
CXXScopeSpec &ScopeSpec,
const DeclarationNameInfo &Id,
OMPDeclareTargetDeclAttr::MapTypeTy MT,
NamedDeclSetType &SameDirectiveDecls) {
LookupResult Lookup(*this, Id, LookupOrdinaryName);
LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
if (Lookup.isAmbiguous())
return;
Lookup.suppressDiagnostics();
if (!Lookup.isSingleResult()) {
if (TypoCorrection Corrected =
CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr,
llvm::make_unique<VarOrFuncDeclFilterCCC>(*this),
CTK_ErrorRecovery)) {
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest)
<< Id.getName());
checkDeclIsAllowedInOpenMPTarget(nullptr, Corrected.getCorrectionDecl());
return;
}
Diag(Id.getLoc(), diag::err_undeclared_var_use) << Id.getName();
return;
}
NamedDecl *ND = Lookup.getAsSingle<NamedDecl>();
if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND) ||
isa<FunctionTemplateDecl>(ND)) {
if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl())))
Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName();
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
cast<ValueDecl>(ND));
if (!Res) {
auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT);
ND->addAttr(A);
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPDeclareTarget(ND, A);
checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Id.getLoc());
} else if (*Res != MT) {
Diag(Id.getLoc(), diag::err_omp_declare_target_to_and_link)
<< Id.getName();
}
} else {
Diag(Id.getLoc(), diag::err_omp_invalid_target_decl) << Id.getName();
}
}
static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
Sema &SemaRef, Decl *D) {
if (!D || !isa<VarDecl>(D))
return;
auto *VD = cast<VarDecl>(D);
if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
return;
SemaRef.Diag(VD->getLocation(), diag::warn_omp_not_in_target_context);
SemaRef.Diag(SL, diag::note_used_here) << SR;
}
static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR,
Sema &SemaRef, DSAStackTy *Stack,
ValueDecl *VD) {
return VD->hasAttr<OMPDeclareTargetDeclAttr>() ||
checkTypeMappable(SL, SR, SemaRef, Stack, VD->getType(),
/*FullCheck=*/false);
}
void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
SourceLocation IdLoc) {
if (!D || D->isInvalidDecl())
return;
SourceRange SR = E ? E->getSourceRange() : D->getSourceRange();
SourceLocation SL = E ? E->getBeginLoc() : D->getLocation();
if (auto *VD = dyn_cast<VarDecl>(D)) {
// Only global variables can be marked as declare target.
if (!VD->isFileVarDecl() && !VD->isStaticLocal() &&
!VD->isStaticDataMember())
return;
// 2.10.6: threadprivate variable cannot appear in a declare target
// directive.
if (DSAStack->isThreadPrivate(VD)) {
Diag(SL, diag::err_omp_threadprivate_in_target);
reportOriginalDsa(*this, DSAStack, VD, DSAStack->getTopDSA(VD, false));
return;
}
}
if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
D = FTD->getTemplatedDecl();
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD);
if (Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) {
assert(IdLoc.isValid() && "Source location is expected");
Diag(IdLoc, diag::err_omp_function_in_link_clause);
Diag(FD->getLocation(), diag::note_defined_here) << FD;
return;
}
}
if (auto *VD = dyn_cast<ValueDecl>(D)) {
// Problem if any with var declared with incomplete type will be reported
// as normal, so no need to check it here.
if ((E || !VD->getType()->isIncompleteType()) &&
!checkValueDeclInTarget(SL, SR, *this, DSAStack, VD))
return;
if (!E && !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) {
// Checking declaration inside declare target region.
if (isa<VarDecl>(D) || isa<FunctionDecl>(D) ||
isa<FunctionTemplateDecl>(D)) {
auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(
Context, OMPDeclareTargetDeclAttr::MT_To);
D->addAttr(A);
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPDeclareTarget(D, A);
}
return;
}
}
if (!E)
return;
checkDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, D);
}
OMPClause *Sema::ActOnOpenMPToClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
MappableVarListInfo MVLI(VarList);
checkMappableExpressionList(*this, DSAStack, OMPC_to, MVLI, StartLoc);
if (MVLI.ProcessedVarList.empty())
return nullptr;
return OMPToClause::Create(Context, StartLoc, LParenLoc, EndLoc,
MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
MVLI.VarComponents);
}
OMPClause *Sema::ActOnOpenMPFromClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
MappableVarListInfo MVLI(VarList);
checkMappableExpressionList(*this, DSAStack, OMPC_from, MVLI, StartLoc);
if (MVLI.ProcessedVarList.empty())
return nullptr;
return OMPFromClause::Create(Context, StartLoc, LParenLoc, EndLoc,
MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
MVLI.VarComponents);
}
OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
MappableVarListInfo MVLI(VarList);
SmallVector<Expr *, 8> PrivateCopies;
SmallVector<Expr *, 8> Inits;
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP use_device_ptr clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
MVLI.ProcessedVarList.push_back(RefExpr);
PrivateCopies.push_back(nullptr);
Inits.push_back(nullptr);
}
ValueDecl *D = Res.first;
if (!D)
continue;
QualType Type = D->getType();
Type = Type.getNonReferenceType().getUnqualifiedType();
auto *VD = dyn_cast<VarDecl>(D);
// Item should be a pointer or reference to pointer.
if (!Type->isPointerType()) {
Diag(ELoc, diag::err_omp_usedeviceptr_not_a_pointer)
<< 0 << RefExpr->getSourceRange();
continue;
}
// Build the private variable and the expression that refers to it.
auto VDPrivate =
buildVarDecl(*this, ELoc, Type, D->getName(),
D->hasAttrs() ? &D->getAttrs() : nullptr,
VD ? cast<DeclRefExpr>(SimpleRefExpr) : nullptr);
if (VDPrivate->isInvalidDecl())
continue;
CurContext->addDecl(VDPrivate);
DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr(
*this, VDPrivate, RefExpr->getType().getUnqualifiedType(), ELoc);
// Add temporary variable to initialize the private copy of the pointer.
VarDecl *VDInit =
buildVarDecl(*this, RefExpr->getExprLoc(), Type, ".devptr.temp");
DeclRefExpr *VDInitRefExpr = buildDeclRefExpr(
*this, VDInit, RefExpr->getType(), RefExpr->getExprLoc());
AddInitializerToDecl(VDPrivate,
DefaultLvalueConversion(VDInitRefExpr).get(),
/*DirectInit=*/false);
// If required, build a capture to implement the privatization initialized
// with the current list item value.
DeclRefExpr *Ref = nullptr;
if (!VD)
Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
MVLI.ProcessedVarList.push_back(VD ? RefExpr->IgnoreParens() : Ref);
PrivateCopies.push_back(VDPrivateRefExpr);
Inits.push_back(VDInitRefExpr);
// We need to add a data sharing attribute for this variable to make sure it
// is correctly captured. A variable that shows up in a use_device_ptr has
// similar properties of a first private variable.
DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref);
// Create a mappable component for the list item. List items in this clause
// only need a component.
MVLI.VarBaseDeclarations.push_back(D);
MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1);
MVLI.VarComponents.back().push_back(
OMPClauseMappableExprCommon::MappableComponent(SimpleRefExpr, D));
}
if (MVLI.ProcessedVarList.empty())
return nullptr;
return OMPUseDevicePtrClause::Create(
Context, StartLoc, LParenLoc, EndLoc, MVLI.ProcessedVarList,
PrivateCopies, Inits, MVLI.VarBaseDeclarations, MVLI.VarComponents);
}
OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
MappableVarListInfo MVLI(VarList);
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP is_device_ptr clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
if (Res.second) {
// It will be analyzed later.
MVLI.ProcessedVarList.push_back(RefExpr);
}
ValueDecl *D = Res.first;
if (!D)
continue;
QualType Type = D->getType();
// item should be a pointer or array or reference to pointer or array
if (!Type.getNonReferenceType()->isPointerType() &&
!Type.getNonReferenceType()->isArrayType()) {
Diag(ELoc, diag::err_omp_argument_type_isdeviceptr)
<< 0 << RefExpr->getSourceRange();
continue;
}
// Check if the declaration in the clause does not show up in any data
// sharing attribute.
DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false);
if (isOpenMPPrivate(DVar.CKind)) {
Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_is_device_ptr)
<< getOpenMPDirectiveName(DSAStack->getCurrentDirective());
reportOriginalDsa(*this, DSAStack, D, DVar);
continue;
}
const Expr *ConflictExpr;
if (DSAStack->checkMappableExprComponentListsForDecl(
D, /*CurrentRegionOnly=*/true,
[&ConflictExpr](
OMPClauseMappableExprCommon::MappableExprComponentListRef R,
OpenMPClauseKind) -> bool {
ConflictExpr = R.front().getAssociatedExpression();
return true;
})) {
Diag(ELoc, diag::err_omp_map_shared_storage) << RefExpr->getSourceRange();
Diag(ConflictExpr->getExprLoc(), diag::note_used_here)
<< ConflictExpr->getSourceRange();
continue;
}
// Store the components in the stack so that they can be used to check
// against other clauses later on.
OMPClauseMappableExprCommon::MappableComponent MC(SimpleRefExpr, D);
DSAStack->addMappableExpressionComponents(
D, MC, /*WhereFoundClauseKind=*/OMPC_is_device_ptr);
// Record the expression we've just processed.
MVLI.ProcessedVarList.push_back(SimpleRefExpr);
// Create a mappable component for the list item. List items in this clause
// only need a component. We use a null declaration to signal fields in
// 'this'.
assert((isa<DeclRefExpr>(SimpleRefExpr) ||
isa<CXXThisExpr>(cast<MemberExpr>(SimpleRefExpr)->getBase())) &&
"Unexpected device pointer expression!");
MVLI.VarBaseDeclarations.push_back(
isa<DeclRefExpr>(SimpleRefExpr) ? D : nullptr);
MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1);
MVLI.VarComponents.back().push_back(MC);
}
if (MVLI.ProcessedVarList.empty())
return nullptr;
return OMPIsDevicePtrClause::Create(
Context, StartLoc, LParenLoc, EndLoc, MVLI.ProcessedVarList,
MVLI.VarBaseDeclarations, MVLI.VarComponents);
}
Index: stable/11/contrib/llvm/tools/lld/COFF/Writer.cpp
===================================================================
--- stable/11/contrib/llvm/tools/lld/COFF/Writer.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/lld/COFF/Writer.cpp (revision 350259)
@@ -1,1745 +1,1773 @@
//===- Writer.cpp ---------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Writer.h"
#include "Config.h"
#include "DLL.h"
#include "InputFiles.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/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 SectorSize = 512;
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 Chunk {
public:
DebugDirectoryChunk(const std::vector<Chunk *> &R, bool WriteRepro)
: Records(R), WriteRepro(WriteRepro) {}
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 + OutputSectionOff);
for (const Chunk *Record : Records) {
OutputSection *OS = Record->getOutputSection();
uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA());
fillEntry(D, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, Record->getSize(),
Record->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<Chunk *> &Records;
bool WriteRepro;
};
class CVDebugRecordChunk : public Chunk {
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 + OutputSectionOff);
// variable sized field (PDB Path)
char *P = reinterpret_cast<char *>(B + OutputSectionOff + sizeof(*BuildId));
if (!Config->PDBAltPath.empty())
memcpy(P, Config->PDBAltPath.data(), Config->PDBAltPath.size());
P[Config->PDBAltPath.size()] = '\0';
}
mutable codeview::DebugInfo *BuildId = nullptr;
};
// The writer writes a SymbolTable result to a file.
class Writer {
public:
Writer() : Buffer(errorHandler().OutputBuffer) {}
void run();
private:
void createSections();
void createMiscChunks();
void createImportTables();
void appendImportThunks();
void locateImportTables(
std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map);
void createExportTable();
void mergeSections();
void readRelocTargets();
void removeUnusedSections();
void assignAddresses();
void finalizeAddresses();
void removeEmptySections();
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 maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
StringRef CountSym);
void setSectionPermissions();
void writeSections();
void writeBuildId();
void sortExceptionTable();
void sortCRTSectionChunks(std::vector<Chunk *> &Chunks);
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::map<StringRef, std::vector<DefinedImportData *>> binImports();
std::unique_ptr<FileOutputBuffer> &Buffer;
std::vector<OutputSection *> OutputSections;
std::vector<char> Strtab;
std::vector<llvm::object::coff_symbol16> OutputSymtab;
IdataContents Idata;
Chunk *ImportTableStart = nullptr;
uint64_t ImportTableSize = 0;
Chunk *IATStart = nullptr;
uint64_t IATSize = 0;
DelayLoadContents DelayIdata;
EdataContents Edata;
bool SetNoSEHCharacteristic = false;
DebugDirectoryChunk *DebugDirectory = nullptr;
std::vector<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;
};
} // anonymous namespace
namespace lld {
namespace coff {
static Timer CodeLayoutTimer("Code Layout", Timer::root());
static Timer DiskCommitTimer("Commit Output File", Timer::root());
void writeResult() { Writer().run(); }
void OutputSection::addChunk(Chunk *C) {
Chunks.push_back(C);
C->setOutputSection(this);
}
void OutputSection::insertChunkAtStart(Chunk *C) {
Chunks.insert(Chunks.begin(), C);
C->setOutputSection(this);
}
void OutputSection::setPermissions(uint32_t C) {
Header.Characteristics &= ~PermMask;
Header.Characteristics |= C;
}
void OutputSection::merge(OutputSection *Other) {
for (Chunk *C : Other->Chunks)
C->setOutputSection(this);
Chunks.insert(Chunks.end(), Other->Chunks.begin(), Other->Chunks.end());
Other->Chunks.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.
sprintf(Hdr->Name, "/%d", 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));
}
}
} // namespace coff
} // namespace lld
// 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);
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;
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;
for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) {
const coff_relocation &Rel = SC->Relocs[J];
Symbol *&RelocTarget = SC->RelocTargets[J];
// 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 ThunkSize 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.
ThunkChunk->setOutputSection(OS);
OS->Chunks.insert(OS->Chunks.begin() + ThunkInsertionSpot, ThunkChunk);
ThunkInsertionSpot++;
ThunksSize += ThunkChunk->getSize();
ThunkInsertionRVA += ThunkChunk->getSize();
AddressesChanged = true;
}
RelocTarget = Thunk;
}
}
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;
for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) {
const coff_relocation &Rel = SC->Relocs[J];
Symbol *RelocTarget = SC->RelocTargets[J];
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 : 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 : 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 : OutputSections) {
Sec->Chunks = Sec->OrigChunks;
for (Chunk *C : Sec->Chunks)
C->resetRelocTargets();
}
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 : OutputSections)
AddressesChanged |= createThunks(Sec, Margin);
// If the verification above thought we needed thunks, we should have
// added some.
assert(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(CodeLayoutTimer);
createImportTables();
createSections();
createMiscChunks();
appendImportThunks();
createExportTable();
mergeSections();
readRelocTargets();
removeUnusedSections();
finalizeAddresses();
removeEmptySections();
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();
T1.stop();
if (!Config->PDBPath.empty() && Config->Debug) {
assert(BuildId);
createPDB(Symtab, OutputSections, SectionTable, BuildId->BuildId);
}
writeBuildId();
writeMapFile(OutputSections);
ScopedTimer T2(DiskCommitTimer);
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;
};
std::stable_sort(Chunks.begin(), Chunks.end(),
[=](const Chunk *A, const Chunk *B) {
return GetPriority(A) < GetPriority(B);
});
}
// 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).
static bool fixGnuImportChunks(
std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map) {
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.
for (auto &Pair : Map) {
StringRef SectionName = Pair.first.first;
uint32_t OutChars = Pair.first.second;
if (!SectionName.startswith(".idata"))
continue;
if (OutChars == RDATA)
continue;
std::vector<Chunk *> &SrcVect = Pair.second;
std::vector<Chunk *> &DestVect = Map[{SectionName, RDATA}];
DestVect.insert(DestVect.end(), SrcVect.begin(), SrcVect.end());
SrcVect.clear();
}
bool HasIdata = false;
// Sort all .idata$* chunks, grouping chunks from the same library,
// with alphabetical ordering of the object fils within a library.
for (auto &Pair : Map) {
StringRef SectionName = Pair.first.first;
if (!SectionName.startswith(".idata"))
continue;
std::vector<Chunk *> &Chunks = Pair.second;
if (!Chunks.empty())
HasIdata = true;
std::stable_sort(Chunks.begin(), Chunks.end(), [&](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.
static void addSyntheticIdata(
IdataContents &Idata,
std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map) {
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) {
std::vector<Chunk *> &DestVect = Map[{N, RDATA}];
DestVect.insert(DestVect.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);
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(
std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map) {
uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
std::vector<Chunk *> &ImportTables = Map[{".idata$2", RDATA}];
if (!ImportTables.empty())
ImportTableStart = ImportTables.front();
for (Chunk *C : ImportTables)
ImportTableSize += C->getSize();
std::vector<Chunk *> &IAT = Map[{".idata$5", RDATA}];
if (!IAT.empty())
IATStart = IAT.front();
for (Chunk *C : IAT)
IATSize += C->getSize();
}
// 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);
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.
std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> Map;
for (Chunk *C : Symtab->getChunks()) {
auto *SC = dyn_cast<SectionChunk>(C);
if (SC && !SC->Live) {
if (Config->Verbose)
SC->printDiscardedMessage();
continue;
}
Map[{C->getSectionName(), C->getOutputCharacteristics()}].push_back(C);
}
// Even in non MinGW cases, we might need to link against GNU import
// libraries.
bool HasIdata = fixGnuImportChunks(Map);
if (!Idata.empty())
HasIdata = true;
if (HasIdata)
addSyntheticIdata(Idata, Map);
// Process an /order option.
if (!Config->Order.empty())
for (auto &Pair : Map)
sortBySectionOrder(Pair.second);
if (HasIdata)
locateImportTables(Map);
// 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 &Pair : Map) {
StringRef Name = getOutputSectionName(Pair.first.first);
uint32_t OutChars = Pair.first.second;
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 " + Pair.first.first + " -> " + Name);
sortCRTSectionChunks(Pair.second);
}
OutputSection *Sec = CreateSection(Name, OutChars);
std::vector<Chunk *> &Chunks = Pair.second;
for (Chunk *C : Chunks)
Sec->addChunk(C);
}
// Finally, move some output sections to the end.
auto SectionOrder = [&](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)
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;
};
std::stable_sort(OutputSections.begin(), OutputSections.end(),
[&](OutputSection *S, OutputSection *T) {
return SectionOrder(S) < SectionOrder(T);
});
}
void Writer::createMiscChunks() {
for (auto &P : MergeChunk::Instances)
RdataSec->addChunk(P.second);
// Create thunks for locally-dllimported symbols.
if (!Symtab->LocalImportChunks.empty()) {
for (Chunk *C : Symtab->LocalImportChunks)
RdataSec->addChunk(C);
}
// Create Debug Information Chunks
OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec;
if (Config->Debug || Config->Repro) {
DebugDirectory = make<DebugDirectoryChunk>(DebugRecords, Config->Repro);
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(BuildId);
for (Chunk *C : DebugRecords)
DebugInfoSec->addChunk(C);
}
// Create SEH table. x86-only.
if (Config->Machine == I386)
createSEHTable();
// Create /guard:cf tables if requested.
if (Config->GuardCF != GuardCFLevel::Off)
createGuardCFTables();
if (Config->MinGW) {
createRuntimePseudoRelocs();
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 : ImportFile::Instances) {
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 (ImportFile::Instances.empty())
return;
for (ImportFile *File : ImportFile::Instances) {
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(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 (Config->Exports.empty())
return;
for (Chunk *C : Edata.Chunks)
EdataSec->addChunk(C);
}
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();
};
OutputSections.erase(
std::remove_if(OutputSections.begin(), OutputSections.end(), IsUnused),
OutputSections.end());
}
// 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; };
OutputSections.erase(
std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty),
OutputSections.end());
uint32_t Idx = 1;
for (OutputSection *Sec : OutputSections)
Sec->SectionIndex = Idx++;
}
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 = C->getOutputSection();
if (!OS)
return None;
Sym.Value = Def->getRVA() - OS->getRVA();
Sym.SectionNumber = OS->SectionIndex;
break;
}
}
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 : OutputSections) {
if (Sec->Name.size() <= COFF::NameSize)
continue;
if ((Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
continue;
Sec->setStringTableOff(addEntryToStringTable(Sec->Name));
}
if (Config->DebugDwarf || Config->DebugSymtab) {
for (ObjFile *File : ObjFile::Instances) {
for (Symbol *B : File->getSymbols()) {
auto *D = dyn_cast_or_null<Defined>(B);
if (!D || D->WrittenToSymtab)
continue;
D->WrittenToSymtab = true;
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, SectorSize);
}
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 (1) {
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 initialize their relocation targets.
void Writer::readRelocTargets() {
for (OutputSection *Sec : OutputSections)
for_each(parallel::par, Sec->Chunks.begin(), Sec->Chunks.end(),
[&](Chunk *C) { C->readRelocTargets(); });
}
// 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) * OutputSections.size();
SizeOfHeaders +=
Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize);
uint64_t RVA = PageSize; // The first page is kept unmapped.
FileSize = SizeOfHeaders;
for (OutputSection *Sec : OutputSections) {
if (Sec == RelocSec)
addBaserels();
uint64_t RawSize = 0, VirtualSize = 0;
Sec->Header.VirtualAddress = RVA;
for (Chunk *C : Sec->Chunks) {
VirtualSize = alignTo(VirtualSize, C->Alignment);
C->setRVA(RVA + VirtualSize);
C->OutputSectionOff = VirtualSize;
C->finalizeContents();
VirtualSize += C->getSize();
if (C->hasData())
RawSize = alignTo(VirtualSize, SectorSize);
}
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, PageSize);
FileSize += alignTo(RawSize, SectorSize);
}
SizeOfImage = alignTo(RVA, PageSize);
}
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 = 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->Relocatable)
COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
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 = PageSize;
PE->FileAlignment = SectorSize;
PE->MajorImageVersion = Config->MajorImageVersion;
PE->MinorImageVersion = Config->MinorImageVersion;
PE->MajorOperatingSystemVersion = Config->MajorOSVersion;
PE->MinorOperatingSystemVersion = Config->MinorOSVersion;
PE->MajorSubsystemVersion = Config->MajorOSVersion;
PE->MinorSubsystemVersion = Config->MinorOSVersion;
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->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)
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 (!Config->Exports.empty()) {
Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA();
Dir[EXPORT_TABLE].Size = Edata.getSize();
}
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 = 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 = 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 : OutputSections) {
Sec->writeHeaderTo(Buf);
Buf += sizeof(coff_section);
}
SectionTable = ArrayRef<uint8_t>(
Buf - 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() {
// Set the no SEH characteristic on x86 binaries unless we find exception
// handlers.
SetNoSEHCharacteristic = true;
SymbolRVASet Handlers;
for (ObjFile *File : ObjFile::Instances) {
// FIXME: We should error here instead of earlier unless /safeseh:no was
// passed.
if (!File->hasSafeSEH())
return;
markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers);
}
// Remove the "no SEH" characteristic if all object files were built with
// safeseh, we found some exception handlers, and there is a load config in
// the object.
SetNoSEHCharacteristic =
Handlers.empty() || !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) {
- auto *D = dyn_cast_or_null<DefinedCOFF>(S);
-
- // Ignore undefined symbols and references to non-functions (e.g. globals and
- // labels).
- if (!D ||
- D->getCOFFSymbol().getComplexType() != COFF::IMAGE_SYM_DTYPE_FUNCTION)
+ if (!S)
return;
- // Mark the symbol as address taken if it's in an executable section.
- Chunk *RefChunk = D->getChunk();
- OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
- if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
- addSymbolToRVASet(AddressTakenSyms, D);
+ 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::LazyKind:
+ 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) {
+ Chunk *RefChunk = D->getChunk();
+ OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
+ if (OS && OS->Header.Characteristics & 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->Relocs) {
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 LongJmpTargets;
for (ObjFile *File : ObjFile::Instances) {
// If the object was compiled with /guard:cf, the address taken symbols
// are in .gfids$y sections, and the longjmp targets are in .gljmp$y
// sections. If the object was not compiled with /guard:cf, we assume there
// were no setjmp targets, and that all code symbols with relocations are
// possibly address-taken.
if (File->hasGuardCF()) {
markSymbolsForRVATable(File, File->getGuardFidChunks(), AddressTakenSyms);
markSymbolsForRVATable(File, File->getGuardLJmpChunks(), LongJmpTargets);
} 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);
// Ensure sections referenced in the gfid table are 16-byte aligned.
for (const ChunkAndOffset &C : AddressTakenSyms)
if (C.InputChunk->Alignment < 16)
C.InputChunk->Alignment = 16;
maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table",
"__guard_fids_count");
// Add the longjmp target table unless the user told us not to.
if (Config->GuardCF == GuardCFLevel::Full)
maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table",
"__guard_longjmp_count");
// 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::Full)
GuardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable);
Symbol *FlagSym = Symtab->findUnderscore("__guard_flags");
cast<DefinedAbsolute>(FlagSym)->setVA(GuardFlags);
}
// Take a list of input sections containing symbol table indices and add those
// symbols to an RVA table. 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::markSymbolsForRVATable(ObjFile *File,
ArrayRef<SectionChunk *> SymIdxChunks,
SymbolRVASet &TableSymbols) {
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 table symbol set.
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())
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) {
if (TableSymbols.empty())
return;
RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols));
RdataSec->addChunk(TableChunk);
Symbol *T = Symtab->findUnderscore(TableSym);
Symbol *C = Symtab->findUnderscore(CountSym);
replaceSymbol<DefinedSynthetic>(T, T->getName(), TableChunk);
cast<DefinedAbsolute>(C)->setVA(TableChunk->getSize() / 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 : Symtab->getChunks()) {
auto *SC = dyn_cast<SectionChunk>(C);
if (!SC || !SC->Live)
continue;
SC->getRuntimePseudoRelocs(Rels);
}
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 = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");
Symbol *EndSym = 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 = Symtab->findUnderscore("__CTOR_LIST__");
Symbol *DtorListSym = 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 : 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 = OutputSections.size();
uint8_t *Buf = Buffer->getBufferStart();
for (OutputSection *Sec : 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());
for_each(parallel::par, Sec->Chunks.begin(), Sec->Chunks.end(),
[&](Chunk *C) { C->writeTo(SecBuf); });
}
}
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) {
return Buffer->getBufferStart() + C->getOutputSection()->getFileOff() +
C->getRVA() - C->getOutputSection()->getRVA();
};
uint8_t *Begin = BufAddr(FirstPdata);
uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize();
if (Config->Machine == AMD64) {
struct Entry { ulittle32_t Begin, End, Unwind; };
sort(parallel::par, (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; };
sort(parallel::par, (Entry *)Begin, (Entry *)End,
[](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
return;
}
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();
};
std::stable_sort(Chunks.begin(), Chunks.end(), 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 : OutputSections)
if (Sec->Name == Name)
return Sec;
return nullptr;
}
uint32_t Writer::getSizeOfInitializedData() {
uint32_t Res = 0;
for (OutputSection *S : 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 : 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));
}
Index: stable/11/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp
===================================================================
--- stable/11/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp (revision 350259)
@@ -1,931 +1,943 @@
//===- PPC64.cpp ----------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
static uint64_t PPC64TocOffset = 0x8000;
static uint64_t DynamicThreadPointerOffset = 0x8000;
// The instruction encoding of bits 21-30 from the ISA for the Xform and Dform
// instructions that can be used as part of the initial exec TLS sequence.
enum XFormOpcd {
LBZX = 87,
LHZX = 279,
LWZX = 23,
LDX = 21,
STBX = 215,
STHX = 407,
STWX = 151,
STDX = 149,
ADD = 266,
};
enum DFormOpcd {
LBZ = 34,
LBZU = 35,
LHZ = 40,
LHZU = 41,
LHAU = 43,
LWZ = 32,
LWZU = 33,
LFSU = 49,
LD = 58,
LFDU = 51,
STB = 38,
STBU = 39,
STH = 44,
STHU = 45,
STW = 36,
STWU = 37,
STFSU = 53,
STFDU = 55,
STD = 62,
ADDI = 14
};
uint64_t elf::getPPC64TocBase() {
// The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
// TOC starts where the first of these sections starts. We always create a
// .got when we see a relocation that uses it, so for us the start is always
// the .got.
uint64_t TocVA = In.Got->getVA();
// Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
// thus permitting a full 64 Kbytes segment. Note that the glibc startup
// code (crt1.o) assumes that you can get from the TOC base to the
// start of the .toc section with only a single (signed) 16-bit relocation.
return TocVA + PPC64TocOffset;
}
unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther) {
// The offset is encoded into the 3 most significant bits of the st_other
// field, with some special values described in section 3.4.1 of the ABI:
// 0 --> Zero offset between the GEP and LEP, and the function does NOT use
// the TOC pointer (r2). r2 will hold the same value on returning from
// the function as it did on entering the function.
// 1 --> Zero offset between the GEP and LEP, and r2 should be treated as a
// caller-saved register for all callers.
// 2-6 --> The binary logarithm of the offset eg:
// 2 --> 2^2 = 4 bytes --> 1 instruction.
// 6 --> 2^6 = 64 bytes --> 16 instructions.
// 7 --> Reserved.
uint8_t GepToLep = (StOther >> 5) & 7;
if (GepToLep < 2)
return 0;
// The value encoded in the st_other bits is the
// log-base-2(offset).
if (GepToLep < 7)
return 1 << GepToLep;
error("reserved value of 7 in the 3 most-significant-bits of st_other");
return 0;
}
namespace {
class PPC64 final : public TargetInfo {
public:
PPC64();
uint32_t calcEFlags() const override;
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void writeGotHeader(uint8_t *Buf) const override;
bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
uint64_t BranchAddr, const Symbol &S) const override;
+ uint32_t getThunkSectionSpacing() const override;
bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
RelExpr Expr) const override;
void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
uint8_t StOther) const override;
};
} // namespace
// Relocation masks following the #lo(value), #hi(value), #ha(value),
// #higher(value), #highera(value), #highest(value), and #highesta(value)
// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi
// document.
static uint16_t lo(uint64_t V) { return V; }
static uint16_t hi(uint64_t V) { return V >> 16; }
static uint16_t ha(uint64_t V) { return (V + 0x8000) >> 16; }
static uint16_t higher(uint64_t V) { return V >> 32; }
static uint16_t highera(uint64_t V) { return (V + 0x8000) >> 32; }
static uint16_t highest(uint64_t V) { return V >> 48; }
static uint16_t highesta(uint64_t V) { return (V + 0x8000) >> 48; }
// Extracts the 'PO' field of an instruction encoding.
static uint8_t getPrimaryOpCode(uint32_t Encoding) { return (Encoding >> 26); }
static bool isDQFormInstruction(uint32_t Encoding) {
switch (getPrimaryOpCode(Encoding)) {
default:
return false;
case 56:
// The only instruction with a primary opcode of 56 is `lq`.
return true;
case 61:
// There are both DS and DQ instruction forms with this primary opcode.
// Namely `lxv` and `stxv` are the DQ-forms that use it.
// The DS 'XO' bits being set to 01 is restricted to DQ form.
return (Encoding & 3) == 0x1;
}
}
static bool isInstructionUpdateForm(uint32_t Encoding) {
switch (getPrimaryOpCode(Encoding)) {
default:
return false;
case LBZU:
case LHAU:
case LHZU:
case LWZU:
case LFSU:
case LFDU:
case STBU:
case STHU:
case STWU:
case STFSU:
case STFDU:
return true;
// LWA has the same opcode as LD, and the DS bits is what differentiates
// between LD/LDU/LWA
case LD:
case STD:
return (Encoding & 3) == 1;
}
}
// There are a number of places when we either want to read or write an
// instruction when handling a half16 relocation type. On big-endian the buffer
// pointer is pointing into the middle of the word we want to extract, and on
// little-endian it is pointing to the start of the word. These 2 helpers are to
// simplify reading and writing in that context.
static void writeInstrFromHalf16(uint8_t *Loc, uint32_t Instr) {
write32(Loc - (Config->EKind == ELF64BEKind ? 2 : 0), Instr);
}
static uint32_t readInstrFromHalf16(const uint8_t *Loc) {
return read32(Loc - (Config->EKind == ELF64BEKind ? 2 : 0));
}
PPC64::PPC64() {
GotRel = R_PPC64_GLOB_DAT;
NoneRel = R_PPC64_NONE;
PltRel = R_PPC64_JMP_SLOT;
RelativeRel = R_PPC64_RELATIVE;
IRelativeRel = R_PPC64_IRELATIVE;
GotEntrySize = 8;
PltEntrySize = 4;
GotPltEntrySize = 8;
GotBaseSymInGotPlt = false;
GotBaseSymOff = 0x8000;
GotHeaderEntriesNum = 1;
GotPltHeaderEntriesNum = 2;
PltHeaderSize = 60;
NeedsThunks = true;
TlsModuleIndexRel = R_PPC64_DTPMOD64;
TlsOffsetRel = R_PPC64_DTPREL64;
TlsGotRel = R_PPC64_TPREL64;
NeedsMoreStackNonSplit = false;
// We need 64K pages (at least under glibc/Linux, the loader won't
// set different permissions on a finer granularity than that).
DefaultMaxPageSize = 65536;
// The PPC64 ELF ABI v1 spec, says:
//
// It is normally desirable to put segments with different characteristics
// in separate 256 Mbyte portions of the address space, to give the
// operating system full paging flexibility in the 64-bit address space.
//
// And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers
// use 0x10000000 as the starting address.
DefaultImageBase = 0x10000000;
write32(TrapInstr.data(), 0x7fe00008);
}
static uint32_t getEFlags(InputFile *File) {
if (Config->EKind == ELF64BEKind)
return cast<ObjFile<ELF64BE>>(File)->getObj().getHeader()->e_flags;
return cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags;
}
// This file implements v2 ABI. This function makes sure that all
// object files have v2 or an unspecified version as an ABI version.
uint32_t PPC64::calcEFlags() const {
for (InputFile *F : ObjectFiles) {
uint32_t Flag = getEFlags(F);
if (Flag == 1)
error(toString(F) + ": ABI version 1 is not supported");
else if (Flag > 2)
error(toString(F) + ": unrecognized e_flags: " + Twine(Flag));
}
return 2;
}
void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// Reference: 3.7.4.2 of the 64-bit ELF V2 abi supplement.
// The general dynamic code sequence for a global `x` will look like:
// Instruction Relocation Symbol
// addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x
// addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x
// bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x
// R_PPC64_REL24 __tls_get_addr
// nop None None
// Relaxing to local exec entails converting:
// addis r3, r2, x@got@tlsgd@ha into nop
// addi r3, r3, x@got@tlsgd@l into addis r3, r13, x@tprel@ha
// bl __tls_get_addr(x@tlsgd) into nop
// nop into addi r3, r3, x@tprel@l
switch (Type) {
case R_PPC64_GOT_TLSGD16_HA:
writeInstrFromHalf16(Loc, 0x60000000); // nop
break;
case R_PPC64_GOT_TLSGD16:
case R_PPC64_GOT_TLSGD16_LO:
writeInstrFromHalf16(Loc, 0x3c6d0000); // addis r3, r13
relocateOne(Loc, R_PPC64_TPREL16_HA, Val);
break;
case R_PPC64_TLSGD:
write32(Loc, 0x60000000); // nop
write32(Loc + 4, 0x38630000); // addi r3, r3
// Since we are relocating a half16 type relocation and Loc + 4 points to
// the start of an instruction we need to advance the buffer by an extra
// 2 bytes on BE.
relocateOne(Loc + 4 + (Config->EKind == ELF64BEKind ? 2 : 0),
R_PPC64_TPREL16_LO, Val);
break;
default:
llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
}
}
void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// Reference: 3.7.4.3 of the 64-bit ELF V2 abi supplement.
// The local dynamic code sequence for a global `x` will look like:
// Instruction Relocation Symbol
// addis r3, r2, x@got@tlsld@ha R_PPC64_GOT_TLSLD16_HA x
// addi r3, r3, x@got@tlsld@l R_PPC64_GOT_TLSLD16_LO x
// bl __tls_get_addr(x@tlsgd) R_PPC64_TLSLD x
// R_PPC64_REL24 __tls_get_addr
// nop None None
// Relaxing to local exec entails converting:
// addis r3, r2, x@got@tlsld@ha into nop
// addi r3, r3, x@got@tlsld@l into addis r3, r13, 0
// bl __tls_get_addr(x@tlsgd) into nop
// nop into addi r3, r3, 4096
switch (Type) {
case R_PPC64_GOT_TLSLD16_HA:
writeInstrFromHalf16(Loc, 0x60000000); // nop
break;
case R_PPC64_GOT_TLSLD16_LO:
writeInstrFromHalf16(Loc, 0x3c6d0000); // addis r3, r13, 0
break;
case R_PPC64_TLSLD:
write32(Loc, 0x60000000); // nop
write32(Loc + 4, 0x38631000); // addi r3, r3, 4096
break;
case R_PPC64_DTPREL16:
case R_PPC64_DTPREL16_HA:
case R_PPC64_DTPREL16_HI:
case R_PPC64_DTPREL16_DS:
case R_PPC64_DTPREL16_LO:
case R_PPC64_DTPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_HA:
case R_PPC64_GOT_DTPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_DS:
case R_PPC64_GOT_DTPREL16_HI:
relocateOne(Loc, Type, Val);
break;
default:
llvm_unreachable("unsupported relocation for TLS LD to LE relaxation");
}
}
static unsigned getDFormOp(unsigned SecondaryOp) {
switch (SecondaryOp) {
case LBZX:
return LBZ;
case LHZX:
return LHZ;
case LWZX:
return LWZ;
case LDX:
return LD;
case STBX:
return STB;
case STHX:
return STH;
case STWX:
return STW;
case STDX:
return STD;
case ADD:
return ADDI;
default:
error("unrecognized instruction for IE to LE R_PPC64_TLS");
return 0;
}
}
void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// The initial exec code sequence for a global `x` will look like:
// Instruction Relocation Symbol
// addis r9, r2, x@got@tprel@ha R_PPC64_GOT_TPREL16_HA x
// ld r9, x@got@tprel@l(r9) R_PPC64_GOT_TPREL16_LO_DS x
// add r9, r9, x@tls R_PPC64_TLS x
// Relaxing to local exec entails converting:
// addis r9, r2, x@got@tprel@ha into nop
// ld r9, x@got@tprel@l(r9) into addis r9, r13, x@tprel@ha
// add r9, r9, x@tls into addi r9, r9, x@tprel@l
// x@tls R_PPC64_TLS is a relocation which does not compute anything,
// it is replaced with r13 (thread pointer).
// The add instruction in the initial exec sequence has multiple variations
// that need to be handled. If we are building an address it will use an add
// instruction, if we are accessing memory it will use any of the X-form
// indexed load or store instructions.
unsigned Offset = (Config->EKind == ELF64BEKind) ? 2 : 0;
switch (Type) {
case R_PPC64_GOT_TPREL16_HA:
write32(Loc - Offset, 0x60000000); // nop
break;
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_TPREL16_DS: {
uint32_t RegNo = read32(Loc - Offset) & 0x03E00000; // bits 6-10
write32(Loc - Offset, 0x3C0D0000 | RegNo); // addis RegNo, r13
relocateOne(Loc, R_PPC64_TPREL16_HA, Val);
break;
}
case R_PPC64_TLS: {
uint32_t PrimaryOp = getPrimaryOpCode(read32(Loc));
if (PrimaryOp != 31)
error("unrecognized instruction for IE to LE R_PPC64_TLS");
uint32_t SecondaryOp = (read32(Loc) & 0x000007FE) >> 1; // bits 21-30
uint32_t DFormOp = getDFormOp(SecondaryOp);
write32(Loc, ((DFormOp << 26) | (read32(Loc) & 0x03FFFFFF)));
relocateOne(Loc + Offset, R_PPC64_TPREL16_LO, Val);
break;
}
default:
llvm_unreachable("unknown relocation for IE to LE");
break;
}
}
RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
case R_PPC64_GOT16:
case R_PPC64_GOT16_DS:
case R_PPC64_GOT16_HA:
case R_PPC64_GOT16_HI:
case R_PPC64_GOT16_LO:
case R_PPC64_GOT16_LO_DS:
return R_GOT_OFF;
case R_PPC64_TOC16:
case R_PPC64_TOC16_DS:
case R_PPC64_TOC16_HA:
case R_PPC64_TOC16_HI:
case R_PPC64_TOC16_LO:
case R_PPC64_TOC16_LO_DS:
return R_GOTREL;
case R_PPC64_TOC:
return R_PPC_TOC;
case R_PPC64_REL14:
case R_PPC64_REL24:
return R_PPC_CALL_PLT;
case R_PPC64_REL16_LO:
case R_PPC64_REL16_HA:
case R_PPC64_REL32:
case R_PPC64_REL64:
return R_PC;
case R_PPC64_GOT_TLSGD16:
case R_PPC64_GOT_TLSGD16_HA:
case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSGD16_LO:
return R_TLSGD_GOT;
case R_PPC64_GOT_TLSLD16:
case R_PPC64_GOT_TLSLD16_HA:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_LO:
return R_TLSLD_GOT;
case R_PPC64_GOT_TPREL16_HA:
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_TPREL16_DS:
case R_PPC64_GOT_TPREL16_HI:
return R_GOT_OFF;
case R_PPC64_GOT_DTPREL16_HA:
case R_PPC64_GOT_DTPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_DS:
case R_PPC64_GOT_DTPREL16_HI:
return R_TLSLD_GOT_OFF;
case R_PPC64_TPREL16:
case R_PPC64_TPREL16_HA:
case R_PPC64_TPREL16_LO:
case R_PPC64_TPREL16_HI:
case R_PPC64_TPREL16_DS:
case R_PPC64_TPREL16_LO_DS:
case R_PPC64_TPREL16_HIGHER:
case R_PPC64_TPREL16_HIGHERA:
case R_PPC64_TPREL16_HIGHEST:
case R_PPC64_TPREL16_HIGHESTA:
return R_TLS;
case R_PPC64_DTPREL16:
case R_PPC64_DTPREL16_DS:
case R_PPC64_DTPREL16_HA:
case R_PPC64_DTPREL16_HI:
case R_PPC64_DTPREL16_HIGHER:
case R_PPC64_DTPREL16_HIGHERA:
case R_PPC64_DTPREL16_HIGHEST:
case R_PPC64_DTPREL16_HIGHESTA:
case R_PPC64_DTPREL16_LO:
case R_PPC64_DTPREL16_LO_DS:
case R_PPC64_DTPREL64:
return R_ABS;
case R_PPC64_TLSGD:
return R_TLSDESC_CALL;
case R_PPC64_TLSLD:
return R_TLSLD_HINT;
case R_PPC64_TLS:
return R_TLSIE_HINT;
default:
return R_ABS;
}
}
void PPC64::writeGotHeader(uint8_t *Buf) const {
write64(Buf, getPPC64TocBase());
}
void PPC64::writePltHeader(uint8_t *Buf) const {
// The generic resolver stub goes first.
write32(Buf + 0, 0x7c0802a6); // mflr r0
write32(Buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8>
write32(Buf + 8, 0x7d6802a6); // mflr r11
write32(Buf + 12, 0x7c0803a6); // mtlr r0
write32(Buf + 16, 0x7d8b6050); // subf r12, r11, r12
write32(Buf + 20, 0x380cffcc); // subi r0,r12,52
write32(Buf + 24, 0x7800f082); // srdi r0,r0,62,2
write32(Buf + 28, 0xe98b002c); // ld r12,44(r11)
write32(Buf + 32, 0x7d6c5a14); // add r11,r12,r11
write32(Buf + 36, 0xe98b0000); // ld r12,0(r11)
write32(Buf + 40, 0xe96b0008); // ld r11,8(r11)
write32(Buf + 44, 0x7d8903a6); // mtctr r12
write32(Buf + 48, 0x4e800420); // bctr
// The 'bcl' instruction will set the link register to the address of the
// following instruction ('mflr r11'). Here we store the offset from that
// instruction to the first entry in the GotPlt section.
int64_t GotPltOffset = In.GotPlt->getVA() - (In.Plt->getVA() + 8);
write64(Buf + 52, GotPltOffset);
}
void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
int32_t Offset = PltHeaderSize + Index * PltEntrySize;
// bl __glink_PLTresolve
write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc));
}
static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
// Relocations relative to the toc-base need to be adjusted by the Toc offset.
uint64_t TocBiasedVal = Val - PPC64TocOffset;
// Relocations relative to dtv[dtpmod] need to be adjusted by the DTP offset.
uint64_t DTPBiasedVal = Val - DynamicThreadPointerOffset;
switch (Type) {
// TOC biased relocation.
case R_PPC64_GOT16:
case R_PPC64_GOT_TLSGD16:
case R_PPC64_GOT_TLSLD16:
case R_PPC64_TOC16:
return {R_PPC64_ADDR16, TocBiasedVal};
case R_PPC64_GOT16_DS:
case R_PPC64_TOC16_DS:
case R_PPC64_GOT_TPREL16_DS:
case R_PPC64_GOT_DTPREL16_DS:
return {R_PPC64_ADDR16_DS, TocBiasedVal};
case R_PPC64_GOT16_HA:
case R_PPC64_GOT_TLSGD16_HA:
case R_PPC64_GOT_TLSLD16_HA:
case R_PPC64_GOT_TPREL16_HA:
case R_PPC64_GOT_DTPREL16_HA:
case R_PPC64_TOC16_HA:
return {R_PPC64_ADDR16_HA, TocBiasedVal};
case R_PPC64_GOT16_HI:
case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TPREL16_HI:
case R_PPC64_GOT_DTPREL16_HI:
case R_PPC64_TOC16_HI:
return {R_PPC64_ADDR16_HI, TocBiasedVal};
case R_PPC64_GOT16_LO:
case R_PPC64_GOT_TLSGD16_LO:
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_TOC16_LO:
return {R_PPC64_ADDR16_LO, TocBiasedVal};
case R_PPC64_GOT16_LO_DS:
case R_PPC64_TOC16_LO_DS:
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_LO_DS:
return {R_PPC64_ADDR16_LO_DS, TocBiasedVal};
// Dynamic Thread pointer biased relocation types.
case R_PPC64_DTPREL16:
return {R_PPC64_ADDR16, DTPBiasedVal};
case R_PPC64_DTPREL16_DS:
return {R_PPC64_ADDR16_DS, DTPBiasedVal};
case R_PPC64_DTPREL16_HA:
return {R_PPC64_ADDR16_HA, DTPBiasedVal};
case R_PPC64_DTPREL16_HI:
return {R_PPC64_ADDR16_HI, DTPBiasedVal};
case R_PPC64_DTPREL16_HIGHER:
return {R_PPC64_ADDR16_HIGHER, DTPBiasedVal};
case R_PPC64_DTPREL16_HIGHERA:
return {R_PPC64_ADDR16_HIGHERA, DTPBiasedVal};
case R_PPC64_DTPREL16_HIGHEST:
return {R_PPC64_ADDR16_HIGHEST, DTPBiasedVal};
case R_PPC64_DTPREL16_HIGHESTA:
return {R_PPC64_ADDR16_HIGHESTA, DTPBiasedVal};
case R_PPC64_DTPREL16_LO:
return {R_PPC64_ADDR16_LO, DTPBiasedVal};
case R_PPC64_DTPREL16_LO_DS:
return {R_PPC64_ADDR16_LO_DS, DTPBiasedVal};
case R_PPC64_DTPREL64:
return {R_PPC64_ADDR64, DTPBiasedVal};
default:
return {Type, Val};
}
}
static bool isTocOptType(RelType Type) {
switch (Type) {
case R_PPC64_GOT16_HA:
case R_PPC64_GOT16_LO_DS:
case R_PPC64_TOC16_HA:
case R_PPC64_TOC16_LO_DS:
case R_PPC64_TOC16_LO:
return true;
default:
return false;
}
}
void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
// We need to save the original relocation type to use in diagnostics, and
// use the original type to determine if we should toc-optimize the
// instructions being relocated.
RelType OriginalType = Type;
bool ShouldTocOptimize = isTocOptType(Type);
// For dynamic thread pointer relative, toc-relative, and got-indirect
// relocations, proceed in terms of the corresponding ADDR16 relocation type.
std::tie(Type, Val) = toAddr16Rel(Type, Val);
switch (Type) {
case R_PPC64_ADDR14: {
checkAlignment(Loc, Val, 4, Type);
// Preserve the AA/LK bits in the branch instruction
uint8_t AALK = Loc[3];
write16(Loc + 2, (AALK & 3) | (Val & 0xfffc));
break;
}
case R_PPC64_ADDR16:
case R_PPC64_TPREL16:
checkInt(Loc, Val, 16, OriginalType);
write16(Loc, Val);
break;
case R_PPC64_ADDR16_DS:
case R_PPC64_TPREL16_DS: {
checkInt(Loc, Val, 16, OriginalType);
// DQ-form instructions use bits 28-31 as part of the instruction encoding
// DS-form instructions only use bits 30-31.
uint16_t Mask = isDQFormInstruction(readInstrFromHalf16(Loc)) ? 0xF : 0x3;
checkAlignment(Loc, lo(Val), Mask + 1, OriginalType);
write16(Loc, (read16(Loc) & Mask) | lo(Val));
} break;
case R_PPC64_ADDR16_HA:
case R_PPC64_REL16_HA:
case R_PPC64_TPREL16_HA:
if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0)
writeInstrFromHalf16(Loc, 0x60000000);
else
write16(Loc, ha(Val));
break;
case R_PPC64_ADDR16_HI:
case R_PPC64_REL16_HI:
case R_PPC64_TPREL16_HI:
write16(Loc, hi(Val));
break;
case R_PPC64_ADDR16_HIGHER:
case R_PPC64_TPREL16_HIGHER:
write16(Loc, higher(Val));
break;
case R_PPC64_ADDR16_HIGHERA:
case R_PPC64_TPREL16_HIGHERA:
write16(Loc, highera(Val));
break;
case R_PPC64_ADDR16_HIGHEST:
case R_PPC64_TPREL16_HIGHEST:
write16(Loc, highest(Val));
break;
case R_PPC64_ADDR16_HIGHESTA:
case R_PPC64_TPREL16_HIGHESTA:
write16(Loc, highesta(Val));
break;
case R_PPC64_ADDR16_LO:
case R_PPC64_REL16_LO:
case R_PPC64_TPREL16_LO:
// When the high-adjusted part of a toc relocation evalutes to 0, it is
// changed into a nop. The lo part then needs to be updated to use the
// toc-pointer register r2, as the base register.
if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) {
uint32_t Instr = readInstrFromHalf16(Loc);
if (isInstructionUpdateForm(Instr))
error(getErrorLocation(Loc) +
"can't toc-optimize an update instruction: 0x" +
utohexstr(Instr));
Instr = (Instr & 0xFFE00000) | 0x00020000;
writeInstrFromHalf16(Loc, Instr);
}
write16(Loc, lo(Val));
break;
case R_PPC64_ADDR16_LO_DS:
case R_PPC64_TPREL16_LO_DS: {
// DQ-form instructions use bits 28-31 as part of the instruction encoding
// DS-form instructions only use bits 30-31.
uint32_t Inst = readInstrFromHalf16(Loc);
uint16_t Mask = isDQFormInstruction(Inst) ? 0xF : 0x3;
checkAlignment(Loc, lo(Val), Mask + 1, OriginalType);
if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) {
// When the high-adjusted part of a toc relocation evalutes to 0, it is
// changed into a nop. The lo part then needs to be updated to use the toc
// pointer register r2, as the base register.
if (isInstructionUpdateForm(Inst))
error(getErrorLocation(Loc) +
"Can't toc-optimize an update instruction: 0x" +
Twine::utohexstr(Inst));
Inst = (Inst & 0xFFE0000F) | 0x00020000;
writeInstrFromHalf16(Loc, Inst);
}
write16(Loc, (read16(Loc) & Mask) | lo(Val));
} break;
case R_PPC64_ADDR32:
case R_PPC64_REL32:
checkInt(Loc, Val, 32, Type);
write32(Loc, Val);
break;
case R_PPC64_ADDR64:
case R_PPC64_REL64:
case R_PPC64_TOC:
write64(Loc, Val);
break;
case R_PPC64_REL14: {
uint32_t Mask = 0x0000FFFC;
checkInt(Loc, Val, 16, Type);
checkAlignment(Loc, Val, 4, Type);
write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
break;
}
case R_PPC64_REL24: {
uint32_t Mask = 0x03FFFFFC;
checkInt(Loc, Val, 26, Type);
checkAlignment(Loc, Val, 4, Type);
write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
break;
}
case R_PPC64_DTPREL64:
write64(Loc, Val - DynamicThreadPointerOffset);
break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
bool PPC64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
uint64_t BranchAddr, const Symbol &S) const {
if (Type != R_PPC64_REL14 && Type != R_PPC64_REL24)
return false;
// If a function is in the Plt it needs to be called with a call-stub.
if (S.isInPlt())
return true;
// If a symbol is a weak undefined and we are compiling an executable
// it doesn't need a range-extending thunk since it can't be called.
if (S.isUndefWeak() && !Config->Shared)
return false;
// If the offset exceeds the range of the branch type then it will need
// a range-extending thunk.
- return !inBranchRange(Type, BranchAddr, S.getVA());
+ // See the comment in getRelocTargetVA() about R_PPC64_CALL.
+ return !inBranchRange(Type, BranchAddr,
+ S.getVA() +
+ getPPC64GlobalEntryToLocalEntryOffset(S.StOther));
+}
+
+uint32_t PPC64::getThunkSectionSpacing() const {
+ // See comment in Arch/ARM.cpp for a more detailed explanation of
+ // getThunkSectionSpacing(). For PPC64 we pick the constant here based on
+ // R_PPC64_REL24, which is used by unconditional branch instructions.
+ // 0x2000000 = (1 << 24-1) * 4
+ return 0x2000000;
}
bool PPC64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
int64_t Offset = Dst - Src;
if (Type == R_PPC64_REL14)
return isInt<16>(Offset);
if (Type == R_PPC64_REL24)
return isInt<26>(Offset);
llvm_unreachable("unsupported relocation type used in branch");
}
RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data,
RelExpr Expr) const {
if (Expr == R_RELAX_TLS_GD_TO_IE)
return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
if (Expr == R_RELAX_TLS_LD_TO_LE)
return R_RELAX_TLS_LD_TO_LE_ABS;
return Expr;
}
// Reference: 3.7.4.1 of the 64-bit ELF V2 abi supplement.
// The general dynamic code sequence for a global `x` uses 4 instructions.
// Instruction Relocation Symbol
// addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x
// addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x
// bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x
// R_PPC64_REL24 __tls_get_addr
// nop None None
//
// Relaxing to initial-exec entails:
// 1) Convert the addis/addi pair that builds the address of the tls_index
// struct for 'x' to an addis/ld pair that loads an offset from a got-entry.
// 2) Convert the call to __tls_get_addr to a nop.
// 3) Convert the nop following the call to an add of the loaded offset to the
// thread pointer.
// Since the nop must directly follow the call, the R_PPC64_TLSGD relocation is
// used as the relaxation hint for both steps 2 and 3.
void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_PPC64_GOT_TLSGD16_HA:
// This is relaxed from addis rT, r2, sym@got@tlsgd@ha to
// addis rT, r2, sym@got@tprel@ha.
relocateOne(Loc, R_PPC64_GOT_TPREL16_HA, Val);
return;
case R_PPC64_GOT_TLSGD16_LO: {
// Relax from addi r3, rA, sym@got@tlsgd@l to
// ld r3, sym@got@tprel@l(rA)
uint32_t InputRegister = (readInstrFromHalf16(Loc) & (0x1f << 16));
writeInstrFromHalf16(Loc, 0xE8600000 | InputRegister);
relocateOne(Loc, R_PPC64_GOT_TPREL16_LO_DS, Val);
return;
}
case R_PPC64_TLSGD:
write32(Loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop
write32(Loc + 4, 0x7c636A14); // nop --> add r3, r3, r13
return;
default:
llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
}
}
// The prologue for a split-stack function is expected to look roughly
// like this:
// .Lglobal_entry_point:
// # TOC pointer initalization.
// ...
// .Llocal_entry_point:
// # load the __private_ss member of the threads tcbhead.
// ld r0,-0x7000-64(r13)
// # subtract the functions stack size from the stack pointer.
// addis r12, r1, ha(-stack-frame size)
// addi r12, r12, l(-stack-frame size)
// # compare needed to actual and branch to allocate_more_stack if more
// # space is needed, otherwise fallthrough to 'normal' function body.
// cmpld cr7,r12,r0
// blt- cr7, .Lallocate_more_stack
//
// -) The allocate_more_stack block might be placed after the split-stack
// prologue and the `blt-` replaced with a `bge+ .Lnormal_func_body`
// instead.
// -) If either the addis or addi is not needed due to the stack size being
// smaller then 32K or a multiple of 64K they will be replaced with a nop,
// but there will always be 2 instructions the linker can overwrite for the
// adjusted stack size.
//
// The linkers job here is to increase the stack size used in the addis/addi
// pair by split-stack-size-adjust.
// addis r12, r1, ha(-stack-frame size - split-stack-adjust-size)
// addi r12, r12, l(-stack-frame size - split-stack-adjust-size)
bool PPC64::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
uint8_t StOther) const {
// If the caller has a global entry point adjust the buffer past it. The start
// of the split-stack prologue will be at the local entry point.
Loc += getPPC64GlobalEntryToLocalEntryOffset(StOther);
// At the very least we expect to see a load of some split-stack data from the
// tcb, and 2 instructions that calculate the ending stack address this
// function will require. If there is not enough room for at least 3
// instructions it can't be a split-stack prologue.
if (Loc + 12 >= End)
return false;
// First instruction must be `ld r0, -0x7000-64(r13)`
if (read32(Loc) != 0xe80d8fc0)
return false;
int16_t HiImm = 0;
int16_t LoImm = 0;
// First instruction can be either an addis if the frame size is larger then
// 32K, or an addi if the size is less then 32K.
int32_t FirstInstr = read32(Loc + 4);
if (getPrimaryOpCode(FirstInstr) == 15) {
HiImm = FirstInstr & 0xFFFF;
} else if (getPrimaryOpCode(FirstInstr) == 14) {
LoImm = FirstInstr & 0xFFFF;
} else {
return false;
}
// Second instruction is either an addi or a nop. If the first instruction was
// an addi then LoImm is set and the second instruction must be a nop.
uint32_t SecondInstr = read32(Loc + 8);
if (!LoImm && getPrimaryOpCode(SecondInstr) == 14) {
LoImm = SecondInstr & 0xFFFF;
} else if (SecondInstr != 0x60000000) {
return false;
}
// The register operands of the first instruction should be the stack-pointer
// (r1) as the input (RA) and r12 as the output (RT). If the second
// instruction is not a nop, then it should use r12 as both input and output.
auto CheckRegOperands = [](uint32_t Instr, uint8_t ExpectedRT,
uint8_t ExpectedRA) {
return ((Instr & 0x3E00000) >> 21 == ExpectedRT) &&
((Instr & 0x1F0000) >> 16 == ExpectedRA);
};
if (!CheckRegOperands(FirstInstr, 12, 1))
return false;
if (SecondInstr != 0x60000000 && !CheckRegOperands(SecondInstr, 12, 12))
return false;
int32_t StackFrameSize = (HiImm * 65536) + LoImm;
// Check that the adjusted size doesn't overflow what we can represent with 2
// instructions.
if (StackFrameSize < Config->SplitStackAdjustSize + INT32_MIN) {
error(getErrorLocation(Loc) + "split-stack prologue adjustment overflows");
return false;
}
int32_t AdjustedStackFrameSize =
StackFrameSize - Config->SplitStackAdjustSize;
LoImm = AdjustedStackFrameSize & 0xFFFF;
HiImm = (AdjustedStackFrameSize + 0x8000) >> 16;
if (HiImm) {
write32(Loc + 4, 0x3D810000 | (uint16_t)HiImm);
// If the low immediate is zero the second instruction will be a nop.
SecondInstr = LoImm ? 0x398C0000 | (uint16_t)LoImm : 0x60000000;
write32(Loc + 8, SecondInstr);
} else {
// addi r12, r1, imm
write32(Loc + 4, (0x39810000) | (uint16_t)LoImm);
write32(Loc + 8, 0x60000000);
}
return true;
}
TargetInfo *elf::getPPC64TargetInfo() {
static PPC64 Target;
return &Target;
}
Index: stable/11/contrib/llvm/tools/lld/ELF/InputSection.cpp
===================================================================
--- stable/11/contrib/llvm/tools/lld/ELF/InputSection.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/lld/ELF/InputSection.cpp (revision 350259)
@@ -1,1283 +1,1281 @@
//===- InputSection.cpp ---------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "InputSection.h"
#include "Config.h"
#include "EhFrame.h"
#include "InputFiles.h"
#include "LinkerScript.h"
#include "OutputSections.h"
#include "Relocations.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/xxhash.h"
#include <algorithm>
#include <mutex>
#include <set>
#include <vector>
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support;
using namespace llvm::support::endian;
using namespace llvm::sys;
using namespace lld;
using namespace lld::elf;
std::vector<InputSectionBase *> elf::InputSections;
// Returns a string to construct an error message.
std::string lld::toString(const InputSectionBase *Sec) {
return (toString(Sec->File) + ":(" + Sec->Name + ")").str();
}
template <class ELFT>
static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &File,
const typename ELFT::Shdr &Hdr) {
if (Hdr.sh_type == SHT_NOBITS)
return makeArrayRef<uint8_t>(nullptr, Hdr.sh_size);
return check(File.getObj().getSectionContents(&Hdr));
}
InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags,
uint32_t Type, uint64_t Entsize,
uint32_t Link, uint32_t Info,
uint32_t Alignment, ArrayRef<uint8_t> Data,
StringRef Name, Kind SectionKind)
: SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info,
Link),
File(File), RawData(Data) {
// In order to reduce memory allocation, we assume that mergeable
// sections are smaller than 4 GiB, which is not an unreasonable
// assumption as of 2017.
if (SectionKind == SectionBase::Merge && RawData.size() > UINT32_MAX)
error(toString(this) + ": section too large");
NumRelocations = 0;
AreRelocsRela = false;
// The ELF spec states that a value of 0 means the section has
// no alignment constraits.
uint32_t V = std::max<uint64_t>(Alignment, 1);
if (!isPowerOf2_64(V))
fatal(toString(File) + ": section sh_addralign is not a power of 2");
this->Alignment = V;
// In ELF, each section can be compressed by zlib, and if compressed,
// section name may be mangled by appending "z" (e.g. ".zdebug_info").
// If that's the case, demangle section name so that we can handle a
// section as if it weren't compressed.
if ((Flags & SHF_COMPRESSED) || Name.startswith(".zdebug")) {
if (!zlib::isAvailable())
error(toString(File) + ": contains a compressed section, " +
"but zlib is not available");
parseCompressedHeader();
}
}
// Drop SHF_GROUP bit unless we are producing a re-linkable object file.
// SHF_GROUP is a marker that a section belongs to some comdat group.
// That flag doesn't make sense in an executable.
static uint64_t getFlags(uint64_t Flags) {
Flags &= ~(uint64_t)SHF_INFO_LINK;
if (!Config->Relocatable)
Flags &= ~(uint64_t)SHF_GROUP;
return Flags;
}
// GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of
// March 2017) fail to infer section types for sections starting with
// ".init_array." or ".fini_array.". They set SHT_PROGBITS instead of
// SHF_INIT_ARRAY. As a result, the following assembler directive
// creates ".init_array.100" with SHT_PROGBITS, for example.
//
// .section .init_array.100, "aw"
//
// This function forces SHT_{INIT,FINI}_ARRAY so that we can handle
// incorrect inputs as if they were correct from the beginning.
static uint64_t getType(uint64_t Type, StringRef Name) {
if (Type == SHT_PROGBITS && Name.startswith(".init_array."))
return SHT_INIT_ARRAY;
if (Type == SHT_PROGBITS && Name.startswith(".fini_array."))
return SHT_FINI_ARRAY;
return Type;
}
template <class ELFT>
InputSectionBase::InputSectionBase(ObjFile<ELFT> &File,
const typename ELFT::Shdr &Hdr,
StringRef Name, Kind SectionKind)
: InputSectionBase(&File, getFlags(Hdr.sh_flags),
getType(Hdr.sh_type, Name), Hdr.sh_entsize, Hdr.sh_link,
Hdr.sh_info, Hdr.sh_addralign,
getSectionContents(File, Hdr), Name, SectionKind) {
// We reject object files having insanely large alignments even though
// they are allowed by the spec. I think 4GB is a reasonable limitation.
// We might want to relax this in the future.
if (Hdr.sh_addralign > UINT32_MAX)
fatal(toString(&File) + ": section sh_addralign is too large");
}
size_t InputSectionBase::getSize() const {
if (auto *S = dyn_cast<SyntheticSection>(this))
return S->getSize();
if (UncompressedSize >= 0)
return UncompressedSize;
return RawData.size();
}
void InputSectionBase::uncompress() const {
size_t Size = UncompressedSize;
UncompressedBuf.reset(new char[Size]);
if (Error E =
zlib::uncompress(toStringRef(RawData), UncompressedBuf.get(), Size))
fatal(toString(this) +
": uncompress failed: " + llvm::toString(std::move(E)));
RawData = makeArrayRef((uint8_t *)UncompressedBuf.get(), Size);
}
uint64_t InputSectionBase::getOffsetInFile() const {
const uint8_t *FileStart = (const uint8_t *)File->MB.getBufferStart();
const uint8_t *SecStart = data().begin();
return SecStart - FileStart;
}
uint64_t SectionBase::getOffset(uint64_t Offset) const {
switch (kind()) {
case Output: {
auto *OS = cast<OutputSection>(this);
// For output sections we treat offset -1 as the end of the section.
return Offset == uint64_t(-1) ? OS->Size : Offset;
}
case Regular:
case Synthetic:
return cast<InputSection>(this)->getOffset(Offset);
case EHFrame:
// The file crtbeginT.o has relocations pointing to the start of an empty
// .eh_frame that is known to be the first in the link. It does that to
// identify the start of the output .eh_frame.
return Offset;
case Merge:
const MergeInputSection *MS = cast<MergeInputSection>(this);
if (InputSection *IS = MS->getParent())
return IS->getOffset(MS->getParentOffset(Offset));
return MS->getParentOffset(Offset);
}
llvm_unreachable("invalid section kind");
}
uint64_t SectionBase::getVA(uint64_t Offset) const {
const OutputSection *Out = getOutputSection();
return (Out ? Out->Addr : 0) + getOffset(Offset);
}
OutputSection *SectionBase::getOutputSection() {
InputSection *Sec;
if (auto *IS = dyn_cast<InputSection>(this))
Sec = IS;
else if (auto *MS = dyn_cast<MergeInputSection>(this))
Sec = MS->getParent();
else if (auto *EH = dyn_cast<EhInputSection>(this))
Sec = EH->getParent();
else
return cast<OutputSection>(this);
return Sec ? Sec->getParent() : nullptr;
}
// When a section is compressed, `RawData` consists with a header followed
// by zlib-compressed data. This function parses a header to initialize
// `UncompressedSize` member and remove the header from `RawData`.
void InputSectionBase::parseCompressedHeader() {
typedef typename ELF64LE::Chdr Chdr64;
typedef typename ELF32LE::Chdr Chdr32;
// Old-style header
if (Name.startswith(".zdebug")) {
if (!toStringRef(RawData).startswith("ZLIB")) {
error(toString(this) + ": corrupted compressed section header");
return;
}
RawData = RawData.slice(4);
if (RawData.size() < 8) {
error(toString(this) + ": corrupted compressed section header");
return;
}
UncompressedSize = read64be(RawData.data());
RawData = RawData.slice(8);
// Restore the original section name.
// (e.g. ".zdebug_info" -> ".debug_info")
Name = Saver.save("." + Name.substr(2));
return;
}
assert(Flags & SHF_COMPRESSED);
Flags &= ~(uint64_t)SHF_COMPRESSED;
// New-style 64-bit header
if (Config->Is64) {
if (RawData.size() < sizeof(Chdr64)) {
error(toString(this) + ": corrupted compressed section");
return;
}
auto *Hdr = reinterpret_cast<const Chdr64 *>(RawData.data());
if (Hdr->ch_type != ELFCOMPRESS_ZLIB) {
error(toString(this) + ": unsupported compression type");
return;
}
UncompressedSize = Hdr->ch_size;
+ Alignment = std::max<uint64_t>(Hdr->ch_addralign, 1);
RawData = RawData.slice(sizeof(*Hdr));
return;
}
// New-style 32-bit header
if (RawData.size() < sizeof(Chdr32)) {
error(toString(this) + ": corrupted compressed section");
return;
}
auto *Hdr = reinterpret_cast<const Chdr32 *>(RawData.data());
if (Hdr->ch_type != ELFCOMPRESS_ZLIB) {
error(toString(this) + ": unsupported compression type");
return;
}
UncompressedSize = Hdr->ch_size;
+ Alignment = std::max<uint64_t>(Hdr->ch_addralign, 1);
RawData = RawData.slice(sizeof(*Hdr));
}
InputSection *InputSectionBase::getLinkOrderDep() const {
assert(Link);
assert(Flags & SHF_LINK_ORDER);
return cast<InputSection>(File->getSections()[Link]);
}
// Find a function symbol that encloses a given location.
template <class ELFT>
Defined *InputSectionBase::getEnclosingFunction(uint64_t Offset) {
for (Symbol *B : File->getSymbols())
if (Defined *D = dyn_cast<Defined>(B))
if (D->Section == this && D->Type == STT_FUNC && D->Value <= Offset &&
Offset < D->Value + D->Size)
return D;
return nullptr;
}
// Returns a source location string. Used to construct an error message.
template <class ELFT>
std::string InputSectionBase::getLocation(uint64_t Offset) {
std::string SecAndOffset = (Name + "+0x" + utohexstr(Offset)).str();
// We don't have file for synthetic sections.
if (getFile<ELFT>() == nullptr)
return (Config->OutputFile + ":(" + SecAndOffset + ")")
.str();
// First check if we can get desired values from debugging information.
if (Optional<DILineInfo> Info = getFile<ELFT>()->getDILineInfo(this, Offset))
return Info->FileName + ":" + std::to_string(Info->Line) + ":(" +
SecAndOffset + ")";
// File->SourceFile contains STT_FILE symbol that contains a
// source file name. If it's missing, we use an object file name.
std::string SrcFile = getFile<ELFT>()->SourceFile;
if (SrcFile.empty())
SrcFile = toString(File);
if (Defined *D = getEnclosingFunction<ELFT>(Offset))
return SrcFile + ":(function " + toString(*D) + ": " + SecAndOffset + ")";
// If there's no symbol, print out the offset in the section.
return (SrcFile + ":(" + SecAndOffset + ")");
}
// This function is intended to be used for constructing an error message.
// The returned message looks like this:
//
// foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42)
//
// Returns an empty string if there's no way to get line info.
std::string InputSectionBase::getSrcMsg(const Symbol &Sym, uint64_t Offset) {
return File->getSrcMsg(Sym, *this, Offset);
}
// Returns a filename string along with an optional section name. This
// function is intended to be used for constructing an error
// message. The returned message looks like this:
//
// path/to/foo.o:(function bar)
//
// or
//
// path/to/foo.o:(function bar) in archive path/to/bar.a
std::string InputSectionBase::getObjMsg(uint64_t Off) {
std::string Filename = File->getName();
std::string Archive;
if (!File->ArchiveName.empty())
Archive = " in archive " + File->ArchiveName;
// Find a symbol that encloses a given location.
for (Symbol *B : File->getSymbols())
if (auto *D = dyn_cast<Defined>(B))
if (D->Section == this && D->Value <= Off && Off < D->Value + D->Size)
return Filename + ":(" + toString(*D) + ")" + Archive;
// If there's no symbol, print out the offset in the section.
return (Filename + ":(" + Name + "+0x" + utohexstr(Off) + ")" + Archive)
.str();
}
InputSection InputSection::Discarded(nullptr, 0, 0, 0, ArrayRef<uint8_t>(), "");
InputSection::InputSection(InputFile *F, uint64_t Flags, uint32_t Type,
uint32_t Alignment, ArrayRef<uint8_t> Data,
StringRef Name, Kind K)
: InputSectionBase(F, Flags, Type,
/*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Alignment, Data,
Name, K) {}
template <class ELFT>
InputSection::InputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header,
StringRef Name)
: InputSectionBase(F, Header, Name, InputSectionBase::Regular) {}
bool InputSection::classof(const SectionBase *S) {
return S->kind() == SectionBase::Regular ||
S->kind() == SectionBase::Synthetic;
}
OutputSection *InputSection::getParent() const {
return cast_or_null<OutputSection>(Parent);
}
// Copy SHT_GROUP section contents. Used only for the -r option.
template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) {
// ELFT::Word is the 32-bit integral type in the target endianness.
typedef typename ELFT::Word u32;
ArrayRef<u32> From = getDataAs<u32>();
auto *To = reinterpret_cast<u32 *>(Buf);
// The first entry is not a section number but a flag.
*To++ = From[0];
// Adjust section numbers because section numbers in an input object
// files are different in the output.
ArrayRef<InputSectionBase *> Sections = File->getSections();
for (uint32_t Idx : From.slice(1))
*To++ = Sections[Idx]->getOutputSection()->SectionIndex;
}
InputSectionBase *InputSection::getRelocatedSection() const {
if (!File || (Type != SHT_RELA && Type != SHT_REL))
return nullptr;
ArrayRef<InputSectionBase *> Sections = File->getSections();
return Sections[Info];
}
// This is used for -r and --emit-relocs. We can't use memcpy to copy
// relocations because we need to update symbol table offset and section index
// for each relocation. So we copy relocations one by one.
template <class ELFT, class RelTy>
void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
InputSectionBase *Sec = getRelocatedSection();
for (const RelTy &Rel : Rels) {
RelType Type = Rel.getType(Config->IsMips64EL);
Symbol &Sym = getFile<ELFT>()->getRelocTargetSym(Rel);
auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf);
Buf += sizeof(RelTy);
if (RelTy::IsRela)
P->r_addend = getAddend<ELFT>(Rel);
// Output section VA is zero for -r, so r_offset is an offset within the
// section, but for --emit-relocs it is an virtual address.
P->r_offset = Sec->getVA(Rel.r_offset);
P->setSymbolAndType(In.SymTab->getSymbolIndex(&Sym), Type,
Config->IsMips64EL);
if (Sym.Type == STT_SECTION) {
// We combine multiple section symbols into only one per
// section. This means we have to update the addend. That is
// trivial for Elf_Rela, but for Elf_Rel we have to write to the
// section data. We do that by adding to the Relocation vector.
// .eh_frame is horribly special and can reference discarded sections. To
// avoid having to parse and recreate .eh_frame, we just replace any
// relocation in it pointing to discarded sections with R_*_NONE, which
// hopefully creates a frame that is ignored at runtime.
auto *D = dyn_cast<Defined>(&Sym);
if (!D) {
error("STT_SECTION symbol should be defined");
continue;
}
SectionBase *Section = D->Section->Repl;
if (!Section->Live) {
P->setSymbolAndType(0, 0, false);
continue;
}
int64_t Addend = getAddend<ELFT>(Rel);
const uint8_t *BufLoc = Sec->data().begin() + Rel.r_offset;
if (!RelTy::IsRela)
Addend = Target->getImplicitAddend(BufLoc, Type);
if (Config->EMachine == EM_MIPS && Config->Relocatable &&
Target->getRelExpr(Type, Sym, BufLoc) == R_MIPS_GOTREL) {
// Some MIPS relocations depend on "gp" value. By default,
// this value has 0x7ff0 offset from a .got section. But
// relocatable files produced by a complier or a linker
// might redefine this default value and we must use it
// for a calculation of the relocation result. When we
// generate EXE or DSO it's trivial. Generating a relocatable
// output is more difficult case because the linker does
// not calculate relocations in this mode and loses
// individual "gp" values used by each input object file.
// As a workaround we add the "gp" value to the relocation
// addend and save it back to the file.
Addend += Sec->getFile<ELFT>()->MipsGp0;
}
if (RelTy::IsRela)
P->r_addend = Sym.getVA(Addend) - Section->getOutputSection()->Addr;
else if (Config->Relocatable)
Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, Addend, &Sym});
}
}
}
// The ARM and AArch64 ABI handle pc-relative relocations to undefined weak
// references specially. The general rule is that the value of the symbol in
// this context is the address of the place P. A further special case is that
// branch relocations to an undefined weak reference resolve to the next
// instruction.
static uint32_t getARMUndefinedRelativeWeakVA(RelType Type, uint32_t A,
uint32_t P) {
switch (Type) {
// Unresolved branch relocations to weak references resolve to next
// instruction, this will be either 2 or 4 bytes on from P.
case R_ARM_THM_JUMP11:
return P + 2 + A;
case R_ARM_CALL:
case R_ARM_JUMP24:
case R_ARM_PC24:
case R_ARM_PLT32:
case R_ARM_PREL31:
case R_ARM_THM_JUMP19:
case R_ARM_THM_JUMP24:
return P + 4 + A;
case R_ARM_THM_CALL:
// We don't want an interworking BLX to ARM
return P + 5 + A;
// Unresolved non branch pc-relative relocations
// R_ARM_TARGET2 which can be resolved relatively is not present as it never
// targets a weak-reference.
case R_ARM_MOVW_PREL_NC:
case R_ARM_MOVT_PREL:
case R_ARM_REL32:
case R_ARM_THM_MOVW_PREL_NC:
case R_ARM_THM_MOVT_PREL:
return P + A;
}
llvm_unreachable("ARM pc-relative relocation expected\n");
}
// The comment above getARMUndefinedRelativeWeakVA applies to this function.
static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
uint64_t P) {
switch (Type) {
// Unresolved branch relocations to weak references resolve to next
// instruction, this is 4 bytes on from P.
case R_AARCH64_CALL26:
case R_AARCH64_CONDBR19:
case R_AARCH64_JUMP26:
case R_AARCH64_TSTBR14:
return P + 4 + A;
// Unresolved non branch pc-relative relocations
case R_AARCH64_PREL16:
case R_AARCH64_PREL32:
case R_AARCH64_PREL64:
case R_AARCH64_ADR_PREL_LO21:
case R_AARCH64_LD_PREL_LO19:
return P + A;
}
llvm_unreachable("AArch64 pc-relative relocation expected\n");
}
// ARM SBREL relocations are of the form S + A - B where B is the static base
// The ARM ABI defines base to be "addressing origin of the output segment
// defining the symbol S". We defined the "addressing origin"/static base to be
// the base of the PT_LOAD segment containing the Sym.
// The procedure call standard only defines a Read Write Position Independent
// RWPI variant so in practice we should expect the static base to be the base
// of the RW segment.
static uint64_t getARMStaticBase(const Symbol &Sym) {
OutputSection *OS = Sym.getOutputSection();
if (!OS || !OS->PtLoad || !OS->PtLoad->FirstSec)
fatal("SBREL relocation to " + Sym.getName() + " without static base");
return OS->PtLoad->FirstSec->Addr;
}
// For R_RISCV_PC_INDIRECT (R_RISCV_PCREL_LO12_{I,S}), the symbol actually
// points the corresponding R_RISCV_PCREL_HI20 relocation, and the target VA
// is calculated using PCREL_HI20's symbol.
//
// This function returns the R_RISCV_PCREL_HI20 relocation from
// R_RISCV_PCREL_LO12's symbol and addend.
static Relocation *getRISCVPCRelHi20(const Symbol *Sym, uint64_t Addend) {
const Defined *D = cast<Defined>(Sym);
InputSection *IS = cast<InputSection>(D->Section);
if (Addend != 0)
warn("Non-zero addend in R_RISCV_PCREL_LO12 relocation to " +
IS->getObjMsg(D->Value) + " is ignored");
// Relocations are sorted by offset, so we can use std::equal_range to do
// binary search.
auto Range = std::equal_range(IS->Relocations.begin(), IS->Relocations.end(),
D->Value, RelocationOffsetComparator{});
for (auto It = std::get<0>(Range); It != std::get<1>(Range); ++It)
if (isRelExprOneOf<R_PC>(It->Expr))
return &*It;
error("R_RISCV_PCREL_LO12 relocation points to " + IS->getObjMsg(D->Value) +
" without an associated R_RISCV_PCREL_HI20 relocation");
return nullptr;
}
// A TLS symbol's virtual address is relative to the TLS segment. Add a
// target-specific adjustment to produce a thread-pointer-relative offset.
static int64_t getTlsTpOffset() {
switch (Config->EMachine) {
case EM_ARM:
case EM_AARCH64:
// Variant 1. The thread pointer points to a TCB with a fixed 2-word size,
// followed by a variable amount of alignment padding, followed by the TLS
// segment.
- //
- // NB: While the ARM/AArch64 ABI formally has a 2-word TCB size, lld
- // effectively increases the TCB size to 8 words for Android compatibility.
- // It accomplishes this by increasing the segment's alignment.
return alignTo(Config->Wordsize * 2, Out::TlsPhdr->p_align);
case EM_386:
case EM_X86_64:
// Variant 2. The TLS segment is located just before the thread pointer.
return -Out::TlsPhdr->p_memsz;
case EM_PPC64:
// The thread pointer points to a fixed offset from the start of the
// executable's TLS segment. An offset of 0x7000 allows a signed 16-bit
// offset to reach 0x1000 of TCB/thread-library data and 0xf000 of the
// program's TLS segment.
return -0x7000;
default:
llvm_unreachable("unhandled Config->EMachine");
}
}
static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
uint64_t P, const Symbol &Sym, RelExpr Expr) {
switch (Expr) {
case R_INVALID:
return 0;
case R_ABS:
case R_RELAX_TLS_LD_TO_LE_ABS:
case R_RELAX_GOT_PC_NOPIC:
return Sym.getVA(A);
case R_ADDEND:
return A;
case R_ARM_SBREL:
return Sym.getVA(A) - getARMStaticBase(Sym);
case R_GOT:
case R_GOT_PLT:
case R_RELAX_TLS_GD_TO_IE_ABS:
return Sym.getGotVA() + A;
case R_GOTONLY_PC:
return In.Got->getVA() + A - P;
case R_GOTONLY_PC_FROM_END:
return In.Got->getVA() + A - P + In.Got->getSize();
case R_GOTREL:
return Sym.getVA(A) - In.Got->getVA();
case R_GOTREL_FROM_END:
return Sym.getVA(A) - In.Got->getVA() - In.Got->getSize();
case R_GOT_FROM_END:
case R_RELAX_TLS_GD_TO_IE_END:
return Sym.getGotOffset() + A - In.Got->getSize();
case R_TLSLD_GOT_OFF:
case R_GOT_OFF:
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
return Sym.getGotOffset() + A;
case R_AARCH64_GOT_PAGE_PC:
case R_AARCH64_GOT_PAGE_PC_PLT:
case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
return getAArch64Page(Sym.getGotVA() + A) - getAArch64Page(P);
case R_GOT_PC:
case R_RELAX_TLS_GD_TO_IE:
return Sym.getGotVA() + A - P;
case R_HEXAGON_GOT:
return Sym.getGotVA() - In.GotPlt->getVA();
case R_MIPS_GOTREL:
return Sym.getVA(A) - In.MipsGot->getGp(File);
case R_MIPS_GOT_GP:
return In.MipsGot->getGp(File) + A;
case R_MIPS_GOT_GP_PC: {
// R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target
// is _gp_disp symbol. In that case we should use the following
// formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
// microMIPS variants of these relocations use slightly different
// expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi()
// to correctly handle less-sugnificant bit of the microMIPS symbol.
uint64_t V = In.MipsGot->getGp(File) + A - P;
if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16)
V += 4;
if (Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_HI16)
V -= 1;
return V;
}
case R_MIPS_GOT_LOCAL_PAGE:
// If relocation against MIPS local symbol requires GOT entry, this entry
// should be initialized by 'page address'. This address is high 16-bits
// of sum the symbol's value and the addend.
return In.MipsGot->getVA() + In.MipsGot->getPageEntryOffset(File, Sym, A) -
In.MipsGot->getGp(File);
case R_MIPS_GOT_OFF:
case R_MIPS_GOT_OFF32:
// In case of MIPS if a GOT relocation has non-zero addend this addend
// should be applied to the GOT entry content not to the GOT entry offset.
// That is why we use separate expression type.
return In.MipsGot->getVA() + In.MipsGot->getSymEntryOffset(File, Sym, A) -
In.MipsGot->getGp(File);
case R_MIPS_TLSGD:
return In.MipsGot->getVA() + In.MipsGot->getGlobalDynOffset(File, Sym) -
In.MipsGot->getGp(File);
case R_MIPS_TLSLD:
return In.MipsGot->getVA() + In.MipsGot->getTlsIndexOffset(File) -
In.MipsGot->getGp(File);
case R_AARCH64_PAGE_PC: {
uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getVA(A);
return getAArch64Page(Val) - getAArch64Page(P);
}
case R_AARCH64_PLT_PAGE_PC: {
uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getPltVA() + A;
return getAArch64Page(Val) - getAArch64Page(P);
}
case R_RISCV_PC_INDIRECT: {
if (const Relocation *HiRel = getRISCVPCRelHi20(&Sym, A))
return getRelocTargetVA(File, HiRel->Type, HiRel->Addend, Sym.getVA(),
*HiRel->Sym, HiRel->Expr);
return 0;
}
case R_PC: {
uint64_t Dest;
if (Sym.isUndefWeak()) {
// On ARM and AArch64 a branch to an undefined weak resolves to the
// next instruction, otherwise the place.
if (Config->EMachine == EM_ARM)
Dest = getARMUndefinedRelativeWeakVA(Type, A, P);
else if (Config->EMachine == EM_AARCH64)
Dest = getAArch64UndefinedRelativeWeakVA(Type, A, P);
else
Dest = Sym.getVA(A);
} else {
Dest = Sym.getVA(A);
}
return Dest - P;
}
case R_PLT:
return Sym.getPltVA() + A;
case R_PLT_PC:
case R_PPC_CALL_PLT:
return Sym.getPltVA() + A - P;
case R_PPC_CALL: {
uint64_t SymVA = Sym.getVA(A);
// If we have an undefined weak symbol, we might get here with a symbol
// address of zero. That could overflow, but the code must be unreachable,
// so don't bother doing anything at all.
if (!SymVA)
return 0;
// PPC64 V2 ABI describes two entry points to a function. The global entry
// point is used for calls where the caller and callee (may) have different
// TOC base pointers and r2 needs to be modified to hold the TOC base for
// the callee. For local calls the caller and callee share the same
// TOC base and so the TOC pointer initialization code should be skipped by
// branching to the local entry point.
return SymVA - P + getPPC64GlobalEntryToLocalEntryOffset(Sym.StOther);
}
case R_PPC_TOC:
return getPPC64TocBase() + A;
case R_RELAX_GOT_PC:
return Sym.getVA(A) - P;
case R_RELAX_TLS_GD_TO_LE:
case R_RELAX_TLS_IE_TO_LE:
case R_RELAX_TLS_LD_TO_LE:
case R_TLS:
// A weak undefined TLS symbol resolves to the base of the TLS
// block, i.e. gets a value of zero. If we pass --gc-sections to
// lld and .tbss is not referenced, it gets reclaimed and we don't
// create a TLS program header. Therefore, we resolve this
// statically to zero.
if (Sym.isTls() && Sym.isUndefWeak())
return 0;
return Sym.getVA(A) + getTlsTpOffset();
case R_RELAX_TLS_GD_TO_LE_NEG:
case R_NEG_TLS:
return Out::TlsPhdr->p_memsz - Sym.getVA(A);
case R_SIZE:
return Sym.getSize() + A;
case R_TLSDESC:
return In.Got->getGlobalDynAddr(Sym) + A;
case R_AARCH64_TLSDESC_PAGE:
return getAArch64Page(In.Got->getGlobalDynAddr(Sym) + A) -
getAArch64Page(P);
case R_TLSGD_GOT:
return In.Got->getGlobalDynOffset(Sym) + A;
case R_TLSGD_GOT_FROM_END:
return In.Got->getGlobalDynOffset(Sym) + A - In.Got->getSize();
case R_TLSGD_PC:
return In.Got->getGlobalDynAddr(Sym) + A - P;
case R_TLSLD_GOT_FROM_END:
return In.Got->getTlsIndexOff() + A - In.Got->getSize();
case R_TLSLD_GOT:
return In.Got->getTlsIndexOff() + A;
case R_TLSLD_PC:
return In.Got->getTlsIndexVA() + A - P;
default:
llvm_unreachable("invalid expression");
}
}
// This function applies relocations to sections without SHF_ALLOC bit.
// Such sections are never mapped to memory at runtime. Debug sections are
// an example. Relocations in non-alloc sections are much easier to
// handle than in allocated sections because it will never need complex
// treatement such as GOT or PLT (because at runtime no one refers them).
// So, we handle relocations for non-alloc sections directly in this
// function as a performance optimization.
template <class ELFT, class RelTy>
void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
const unsigned Bits = sizeof(typename ELFT::uint) * 8;
for (const RelTy &Rel : Rels) {
RelType Type = Rel.getType(Config->IsMips64EL);
// GCC 8.0 or earlier have a bug that they emit R_386_GOTPC relocations
// against _GLOBAL_OFFSET_TABLE_ for .debug_info. The bug has been fixed
// in 2017 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630), but we
// need to keep this bug-compatible code for a while.
if (Config->EMachine == EM_386 && Type == R_386_GOTPC)
continue;
uint64_t Offset = getOffset(Rel.r_offset);
uint8_t *BufLoc = Buf + Offset;
int64_t Addend = getAddend<ELFT>(Rel);
if (!RelTy::IsRela)
Addend += Target->getImplicitAddend(BufLoc, Type);
Symbol &Sym = getFile<ELFT>()->getRelocTargetSym(Rel);
RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc);
if (Expr == R_NONE)
continue;
if (Expr != R_ABS) {
std::string Msg = getLocation<ELFT>(Offset) +
": has non-ABS relocation " + toString(Type) +
" against symbol '" + toString(Sym) + "'";
if (Expr != R_PC) {
error(Msg);
return;
}
// If the control reaches here, we found a PC-relative relocation in a
// non-ALLOC section. Since non-ALLOC section is not loaded into memory
// at runtime, the notion of PC-relative doesn't make sense here. So,
// this is a usage error. However, GNU linkers historically accept such
// relocations without any errors and relocate them as if they were at
// address 0. For bug-compatibilty, we accept them with warnings. We
// know Steel Bank Common Lisp as of 2018 have this bug.
warn(Msg);
Target->relocateOne(BufLoc, Type,
SignExtend64<Bits>(Sym.getVA(Addend - Offset)));
continue;
}
if (Sym.isTls() && !Out::TlsPhdr)
Target->relocateOne(BufLoc, Type, 0);
else
Target->relocateOne(BufLoc, Type, SignExtend64<Bits>(Sym.getVA(Addend)));
}
}
// This is used when '-r' is given.
// For REL targets, InputSection::copyRelocations() may store artificial
// relocations aimed to update addends. They are handled in relocateAlloc()
// for allocatable sections, and this function does the same for
// non-allocatable sections, such as sections with debug information.
static void relocateNonAllocForRelocatable(InputSection *Sec, uint8_t *Buf) {
const unsigned Bits = Config->Is64 ? 64 : 32;
for (const Relocation &Rel : Sec->Relocations) {
// InputSection::copyRelocations() adds only R_ABS relocations.
assert(Rel.Expr == R_ABS);
uint8_t *BufLoc = Buf + Rel.Offset + Sec->OutSecOff;
uint64_t TargetVA = SignExtend64(Rel.Sym->getVA(Rel.Addend), Bits);
Target->relocateOne(BufLoc, Rel.Type, TargetVA);
}
}
template <class ELFT>
void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) {
if (Flags & SHF_EXECINSTR)
adjustSplitStackFunctionPrologues<ELFT>(Buf, BufEnd);
if (Flags & SHF_ALLOC) {
relocateAlloc(Buf, BufEnd);
return;
}
auto *Sec = cast<InputSection>(this);
if (Config->Relocatable)
relocateNonAllocForRelocatable(Sec, Buf);
else if (Sec->AreRelocsRela)
Sec->relocateNonAlloc<ELFT>(Buf, Sec->template relas<ELFT>());
else
Sec->relocateNonAlloc<ELFT>(Buf, Sec->template rels<ELFT>());
}
void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
assert(Flags & SHF_ALLOC);
const unsigned Bits = Config->Wordsize * 8;
for (const Relocation &Rel : Relocations) {
uint64_t Offset = Rel.Offset;
if (auto *Sec = dyn_cast<InputSection>(this))
Offset += Sec->OutSecOff;
uint8_t *BufLoc = Buf + Offset;
RelType Type = Rel.Type;
uint64_t AddrLoc = getOutputSection()->Addr + Offset;
RelExpr Expr = Rel.Expr;
uint64_t TargetVA = SignExtend64(
getRelocTargetVA(File, Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr),
Bits);
switch (Expr) {
case R_RELAX_GOT_PC:
case R_RELAX_GOT_PC_NOPIC:
Target->relaxGot(BufLoc, TargetVA);
break;
case R_RELAX_TLS_IE_TO_LE:
Target->relaxTlsIeToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_LD_TO_LE:
case R_RELAX_TLS_LD_TO_LE_ABS:
Target->relaxTlsLdToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_GD_TO_LE:
case R_RELAX_TLS_GD_TO_LE_NEG:
Target->relaxTlsGdToLe(BufLoc, Type, TargetVA);
break;
case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE:
case R_RELAX_TLS_GD_TO_IE_ABS:
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
case R_RELAX_TLS_GD_TO_IE_END:
Target->relaxTlsGdToIe(BufLoc, Type, TargetVA);
break;
case R_PPC_CALL:
// If this is a call to __tls_get_addr, it may be part of a TLS
// sequence that has been relaxed and turned into a nop. In this
// case, we don't want to handle it as a call.
if (read32(BufLoc) == 0x60000000) // nop
break;
// Patch a nop (0x60000000) to a ld.
if (Rel.Sym->NeedsTocRestore) {
if (BufLoc + 8 > BufEnd || read32(BufLoc + 4) != 0x60000000) {
error(getErrorLocation(BufLoc) + "call lacks nop, can't restore toc");
break;
}
write32(BufLoc + 4, 0xe8410018); // ld %r2, 24(%r1)
}
Target->relocateOne(BufLoc, Type, TargetVA);
break;
default:
Target->relocateOne(BufLoc, Type, TargetVA);
break;
}
}
}
// For each function-defining prologue, find any calls to __morestack,
// and replace them with calls to __morestack_non_split.
static void switchMorestackCallsToMorestackNonSplit(
DenseSet<Defined *> &Prologues, std::vector<Relocation *> &MorestackCalls) {
// If the target adjusted a function's prologue, all calls to
// __morestack inside that function should be switched to
// __morestack_non_split.
Symbol *MoreStackNonSplit = Symtab->find("__morestack_non_split");
if (!MoreStackNonSplit) {
error("Mixing split-stack objects requires a definition of "
"__morestack_non_split");
return;
}
// Sort both collections to compare addresses efficiently.
llvm::sort(MorestackCalls, [](const Relocation *L, const Relocation *R) {
return L->Offset < R->Offset;
});
std::vector<Defined *> Functions(Prologues.begin(), Prologues.end());
llvm::sort(Functions, [](const Defined *L, const Defined *R) {
return L->Value < R->Value;
});
auto It = MorestackCalls.begin();
for (Defined *F : Functions) {
// Find the first call to __morestack within the function.
while (It != MorestackCalls.end() && (*It)->Offset < F->Value)
++It;
// Adjust all calls inside the function.
while (It != MorestackCalls.end() && (*It)->Offset < F->Value + F->Size) {
(*It)->Sym = MoreStackNonSplit;
++It;
}
}
}
static bool enclosingPrologueAttempted(uint64_t Offset,
const DenseSet<Defined *> &Prologues) {
for (Defined *F : Prologues)
if (F->Value <= Offset && Offset < F->Value + F->Size)
return true;
return false;
}
// If a function compiled for split stack calls a function not
// compiled for split stack, then the caller needs its prologue
// adjusted to ensure that the called function will have enough stack
// available. Find those functions, and adjust their prologues.
template <class ELFT>
void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf,
uint8_t *End) {
if (!getFile<ELFT>()->SplitStack)
return;
DenseSet<Defined *> Prologues;
std::vector<Relocation *> MorestackCalls;
for (Relocation &Rel : Relocations) {
// Local symbols can't possibly be cross-calls, and should have been
// resolved long before this line.
if (Rel.Sym->isLocal())
continue;
// Ignore calls into the split-stack api.
if (Rel.Sym->getName().startswith("__morestack")) {
if (Rel.Sym->getName().equals("__morestack"))
MorestackCalls.push_back(&Rel);
continue;
}
// A relocation to non-function isn't relevant. Sometimes
// __morestack is not marked as a function, so this check comes
// after the name check.
if (Rel.Sym->Type != STT_FUNC)
continue;
// If the callee's-file was compiled with split stack, nothing to do. In
// this context, a "Defined" symbol is one "defined by the binary currently
// being produced". So an "undefined" symbol might be provided by a shared
// library. It is not possible to tell how such symbols were compiled, so be
// conservative.
if (Defined *D = dyn_cast<Defined>(Rel.Sym))
if (InputSection *IS = cast_or_null<InputSection>(D->Section))
if (!IS || !IS->getFile<ELFT>() || IS->getFile<ELFT>()->SplitStack)
continue;
if (enclosingPrologueAttempted(Rel.Offset, Prologues))
continue;
if (Defined *F = getEnclosingFunction<ELFT>(Rel.Offset)) {
Prologues.insert(F);
if (Target->adjustPrologueForCrossSplitStack(Buf + getOffset(F->Value),
End, F->StOther))
continue;
if (!getFile<ELFT>()->SomeNoSplitStack)
error(lld::toString(this) + ": " + F->getName() +
" (with -fsplit-stack) calls " + Rel.Sym->getName() +
" (without -fsplit-stack), but couldn't adjust its prologue");
}
}
if (Target->NeedsMoreStackNonSplit)
switchMorestackCallsToMorestackNonSplit(Prologues, MorestackCalls);
}
template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
if (Type == SHT_NOBITS)
return;
if (auto *S = dyn_cast<SyntheticSection>(this)) {
S->writeTo(Buf + OutSecOff);
return;
}
// If -r or --emit-relocs is given, then an InputSection
// may be a relocation section.
if (Type == SHT_RELA) {
copyRelocations<ELFT>(Buf + OutSecOff, getDataAs<typename ELFT::Rela>());
return;
}
if (Type == SHT_REL) {
copyRelocations<ELFT>(Buf + OutSecOff, getDataAs<typename ELFT::Rel>());
return;
}
// If -r is given, we may have a SHT_GROUP section.
if (Type == SHT_GROUP) {
copyShtGroup<ELFT>(Buf + OutSecOff);
return;
}
// If this is a compressed section, uncompress section contents directly
// to the buffer.
if (UncompressedSize >= 0 && !UncompressedBuf) {
size_t Size = UncompressedSize;
if (Error E = zlib::uncompress(toStringRef(RawData),
(char *)(Buf + OutSecOff), Size))
fatal(toString(this) +
": uncompress failed: " + llvm::toString(std::move(E)));
uint8_t *BufEnd = Buf + OutSecOff + Size;
relocate<ELFT>(Buf, BufEnd);
return;
}
// Copy section contents from source object file to output file
// and then apply relocations.
memcpy(Buf + OutSecOff, data().data(), data().size());
uint8_t *BufEnd = Buf + OutSecOff + data().size();
relocate<ELFT>(Buf, BufEnd);
}
void InputSection::replace(InputSection *Other) {
Alignment = std::max(Alignment, Other->Alignment);
Other->Repl = Repl;
Other->Live = false;
}
template <class ELFT>
EhInputSection::EhInputSection(ObjFile<ELFT> &F,
const typename ELFT::Shdr &Header,
StringRef Name)
: InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) {}
SyntheticSection *EhInputSection::getParent() const {
return cast_or_null<SyntheticSection>(Parent);
}
// Returns the index of the first relocation that points to a region between
// Begin and Begin+Size.
template <class IntTy, class RelTy>
static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels,
unsigned &RelocI) {
// Start search from RelocI for fast access. That works because the
// relocations are sorted in .eh_frame.
for (unsigned N = Rels.size(); RelocI < N; ++RelocI) {
const RelTy &Rel = Rels[RelocI];
if (Rel.r_offset < Begin)
continue;
if (Rel.r_offset < Begin + Size)
return RelocI;
return -1;
}
return -1;
}
// .eh_frame is a sequence of CIE or FDE records.
// This function splits an input section into records and returns them.
template <class ELFT> void EhInputSection::split() {
if (AreRelocsRela)
split<ELFT>(relas<ELFT>());
else
split<ELFT>(rels<ELFT>());
}
template <class ELFT, class RelTy>
void EhInputSection::split(ArrayRef<RelTy> Rels) {
unsigned RelI = 0;
for (size_t Off = 0, End = data().size(); Off != End;) {
size_t Size = readEhRecordSize(this, Off);
Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI));
// The empty record is the end marker.
if (Size == 4)
break;
Off += Size;
}
}
static size_t findNull(StringRef S, size_t EntSize) {
// Optimize the common case.
if (EntSize == 1)
return S.find(0);
for (unsigned I = 0, N = S.size(); I != N; I += EntSize) {
const char *B = S.begin() + I;
if (std::all_of(B, B + EntSize, [](char C) { return C == 0; }))
return I;
}
return StringRef::npos;
}
SyntheticSection *MergeInputSection::getParent() const {
return cast_or_null<SyntheticSection>(Parent);
}
// Split SHF_STRINGS section. Such section is a sequence of
// null-terminated strings.
void MergeInputSection::splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) {
size_t Off = 0;
bool IsAlloc = Flags & SHF_ALLOC;
StringRef S = toStringRef(Data);
while (!S.empty()) {
size_t End = findNull(S, EntSize);
if (End == StringRef::npos)
fatal(toString(this) + ": string is not null terminated");
size_t Size = End + EntSize;
Pieces.emplace_back(Off, xxHash64(S.substr(0, Size)), !IsAlloc);
S = S.substr(Size);
Off += Size;
}
}
// Split non-SHF_STRINGS section. Such section is a sequence of
// fixed size records.
void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data,
size_t EntSize) {
size_t Size = Data.size();
assert((Size % EntSize) == 0);
bool IsAlloc = Flags & SHF_ALLOC;
for (size_t I = 0; I != Size; I += EntSize)
Pieces.emplace_back(I, xxHash64(Data.slice(I, EntSize)), !IsAlloc);
}
template <class ELFT>
MergeInputSection::MergeInputSection(ObjFile<ELFT> &F,
const typename ELFT::Shdr &Header,
StringRef Name)
: InputSectionBase(F, Header, Name, InputSectionBase::Merge) {}
MergeInputSection::MergeInputSection(uint64_t Flags, uint32_t Type,
uint64_t Entsize, ArrayRef<uint8_t> Data,
StringRef Name)
: InputSectionBase(nullptr, Flags, Type, Entsize, /*Link*/ 0, /*Info*/ 0,
/*Alignment*/ Entsize, Data, Name, SectionBase::Merge) {}
// This function is called after we obtain a complete list of input sections
// that need to be linked. This is responsible to split section contents
// into small chunks for further processing.
//
// Note that this function is called from parallelForEach. This must be
// thread-safe (i.e. no memory allocation from the pools).
void MergeInputSection::splitIntoPieces() {
assert(Pieces.empty());
if (Flags & SHF_STRINGS)
splitStrings(data(), Entsize);
else
splitNonStrings(data(), Entsize);
}
SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
if (this->data().size() <= Offset)
fatal(toString(this) + ": offset is outside the section");
// If Offset is not at beginning of a section piece, it is not in the map.
// In that case we need to do a binary search of the original section piece vector.
auto It2 =
llvm::upper_bound(Pieces, Offset, [](uint64_t Offset, SectionPiece P) {
return Offset < P.InputOff;
});
return &It2[-1];
}
// Returns the offset in an output section for a given input offset.
// Because contents of a mergeable section is not contiguous in output,
// it is not just an addition to a base output offset.
uint64_t MergeInputSection::getParentOffset(uint64_t Offset) const {
// If Offset is not at beginning of a section piece, it is not in the map.
// In that case we need to search from the original section piece vector.
const SectionPiece &Piece =
*(const_cast<MergeInputSection *>(this)->getSectionPiece (Offset));
uint64_t Addend = Offset - Piece.InputOff;
return Piece.OutputOff + Addend;
}
template InputSection::InputSection(ObjFile<ELF32LE> &, const ELF32LE::Shdr &,
StringRef);
template InputSection::InputSection(ObjFile<ELF32BE> &, const ELF32BE::Shdr &,
StringRef);
template InputSection::InputSection(ObjFile<ELF64LE> &, const ELF64LE::Shdr &,
StringRef);
template InputSection::InputSection(ObjFile<ELF64BE> &, const ELF64BE::Shdr &,
StringRef);
template std::string InputSectionBase::getLocation<ELF32LE>(uint64_t);
template std::string InputSectionBase::getLocation<ELF32BE>(uint64_t);
template std::string InputSectionBase::getLocation<ELF64LE>(uint64_t);
template std::string InputSectionBase::getLocation<ELF64BE>(uint64_t);
template void InputSection::writeTo<ELF32LE>(uint8_t *);
template void InputSection::writeTo<ELF32BE>(uint8_t *);
template void InputSection::writeTo<ELF64LE>(uint8_t *);
template void InputSection::writeTo<ELF64BE>(uint8_t *);
template MergeInputSection::MergeInputSection(ObjFile<ELF32LE> &,
const ELF32LE::Shdr &, StringRef);
template MergeInputSection::MergeInputSection(ObjFile<ELF32BE> &,
const ELF32BE::Shdr &, StringRef);
template MergeInputSection::MergeInputSection(ObjFile<ELF64LE> &,
const ELF64LE::Shdr &, StringRef);
template MergeInputSection::MergeInputSection(ObjFile<ELF64BE> &,
const ELF64BE::Shdr &, StringRef);
template EhInputSection::EhInputSection(ObjFile<ELF32LE> &,
const ELF32LE::Shdr &, StringRef);
template EhInputSection::EhInputSection(ObjFile<ELF32BE> &,
const ELF32BE::Shdr &, StringRef);
template EhInputSection::EhInputSection(ObjFile<ELF64LE> &,
const ELF64LE::Shdr &, StringRef);
template EhInputSection::EhInputSection(ObjFile<ELF64BE> &,
const ELF64BE::Shdr &, StringRef);
template void EhInputSection::split<ELF32LE>();
template void EhInputSection::split<ELF32BE>();
template void EhInputSection::split<ELF64LE>();
template void EhInputSection::split<ELF64BE>();
Index: stable/11/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
===================================================================
--- stable/11/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp (revision 350259)
@@ -1,3228 +1,3233 @@
//===- SyntheticSections.cpp ----------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains linker-synthesized sections. Currently,
// synthetic sections are created either output sections or input sections,
// but we are rewriting code so that all synthetic sections are created as
// input sections.
//
//===----------------------------------------------------------------------===//
#include "SyntheticSections.h"
#include "Bits.h"
#include "Config.h"
#include "InputFiles.h"
#include "LinkerScript.h"
#include "OutputSections.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "Target.h"
#include "Writer.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/RandomNumberGenerator.h"
#include "llvm/Support/SHA1.h"
#include "llvm/Support/xxhash.h"
#include <cstdlib>
#include <thread>
using namespace llvm;
using namespace llvm::dwarf;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support;
using namespace lld;
using namespace lld::elf;
using llvm::support::endian::read32le;
using llvm::support::endian::write32le;
using llvm::support::endian::write64le;
constexpr size_t MergeNoTailSection::NumShards;
// Returns an LLD version string.
static ArrayRef<uint8_t> getVersion() {
// Check LLD_VERSION first for ease of testing.
// You can get consistent output by using the environment variable.
// This is only for testing.
StringRef S = getenv("LLD_VERSION");
if (S.empty())
S = Saver.save(Twine("Linker: ") + getLLDVersion());
// +1 to include the terminating '\0'.
return {(const uint8_t *)S.data(), S.size() + 1};
}
// Creates a .comment section containing LLD version info.
// With this feature, you can identify LLD-generated binaries easily
// by "readelf --string-dump .comment <file>".
// The returned object is a mergeable string section.
MergeInputSection *elf::createCommentSection() {
return make<MergeInputSection>(SHF_MERGE | SHF_STRINGS, SHT_PROGBITS, 1,
getVersion(), ".comment");
}
// .MIPS.abiflags section.
template <class ELFT>
MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags)
: SyntheticSection(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"),
Flags(Flags) {
this->Entsize = sizeof(Elf_Mips_ABIFlags);
}
template <class ELFT> void MipsAbiFlagsSection<ELFT>::writeTo(uint8_t *Buf) {
memcpy(Buf, &Flags, sizeof(Flags));
}
template <class ELFT>
MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
Elf_Mips_ABIFlags Flags = {};
bool Create = false;
for (InputSectionBase *Sec : InputSections) {
if (Sec->Type != SHT_MIPS_ABIFLAGS)
continue;
Sec->Live = false;
Create = true;
std::string Filename = toString(Sec->File);
const size_t Size = Sec->data().size();
// Older version of BFD (such as the default FreeBSD linker) concatenate
// .MIPS.abiflags instead of merging. To allow for this case (or potential
// zero padding) we ignore everything after the first Elf_Mips_ABIFlags
if (Size < sizeof(Elf_Mips_ABIFlags)) {
error(Filename + ": invalid size of .MIPS.abiflags section: got " +
Twine(Size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags)));
return nullptr;
}
auto *S = reinterpret_cast<const Elf_Mips_ABIFlags *>(Sec->data().data());
if (S->version != 0) {
error(Filename + ": unexpected .MIPS.abiflags version " +
Twine(S->version));
return nullptr;
}
// LLD checks ISA compatibility in calcMipsEFlags(). Here we just
// select the highest number of ISA/Rev/Ext.
Flags.isa_level = std::max(Flags.isa_level, S->isa_level);
Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev);
Flags.isa_ext = std::max(Flags.isa_ext, S->isa_ext);
Flags.gpr_size = std::max(Flags.gpr_size, S->gpr_size);
Flags.cpr1_size = std::max(Flags.cpr1_size, S->cpr1_size);
Flags.cpr2_size = std::max(Flags.cpr2_size, S->cpr2_size);
Flags.ases |= S->ases;
Flags.flags1 |= S->flags1;
Flags.flags2 |= S->flags2;
Flags.fp_abi = elf::getMipsFpAbiFlag(Flags.fp_abi, S->fp_abi, Filename);
};
if (Create)
return make<MipsAbiFlagsSection<ELFT>>(Flags);
return nullptr;
}
// .MIPS.options section.
template <class ELFT>
MipsOptionsSection<ELFT>::MipsOptionsSection(Elf_Mips_RegInfo Reginfo)
: SyntheticSection(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"),
Reginfo(Reginfo) {
this->Entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
}
template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) {
auto *Options = reinterpret_cast<Elf_Mips_Options *>(Buf);
Options->kind = ODK_REGINFO;
Options->size = getSize();
if (!Config->Relocatable)
Reginfo.ri_gp_value = In.MipsGot->getGp();
memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo));
}
template <class ELFT>
MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
// N64 ABI only.
if (!ELFT::Is64Bits)
return nullptr;
std::vector<InputSectionBase *> Sections;
for (InputSectionBase *Sec : InputSections)
if (Sec->Type == SHT_MIPS_OPTIONS)
Sections.push_back(Sec);
if (Sections.empty())
return nullptr;
Elf_Mips_RegInfo Reginfo = {};
for (InputSectionBase *Sec : Sections) {
Sec->Live = false;
std::string Filename = toString(Sec->File);
ArrayRef<uint8_t> D = Sec->data();
while (!D.empty()) {
if (D.size() < sizeof(Elf_Mips_Options)) {
error(Filename + ": invalid size of .MIPS.options section");
break;
}
auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data());
if (Opt->kind == ODK_REGINFO) {
Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask;
Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
break;
}
if (!Opt->size)
fatal(Filename + ": zero option descriptor size");
D = D.slice(Opt->size);
}
};
return make<MipsOptionsSection<ELFT>>(Reginfo);
}
// MIPS .reginfo section.
template <class ELFT>
MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo)
: SyntheticSection(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"),
Reginfo(Reginfo) {
this->Entsize = sizeof(Elf_Mips_RegInfo);
}
template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) {
if (!Config->Relocatable)
Reginfo.ri_gp_value = In.MipsGot->getGp();
memcpy(Buf, &Reginfo, sizeof(Reginfo));
}
template <class ELFT>
MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
// Section should be alive for O32 and N32 ABIs only.
if (ELFT::Is64Bits)
return nullptr;
std::vector<InputSectionBase *> Sections;
for (InputSectionBase *Sec : InputSections)
if (Sec->Type == SHT_MIPS_REGINFO)
Sections.push_back(Sec);
if (Sections.empty())
return nullptr;
Elf_Mips_RegInfo Reginfo = {};
for (InputSectionBase *Sec : Sections) {
Sec->Live = false;
if (Sec->data().size() != sizeof(Elf_Mips_RegInfo)) {
error(toString(Sec->File) + ": invalid size of .reginfo section");
return nullptr;
}
auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->data().data());
Reginfo.ri_gprmask |= R->ri_gprmask;
Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value;
};
return make<MipsReginfoSection<ELFT>>(Reginfo);
}
InputSection *elf::createInterpSection() {
// StringSaver guarantees that the returned string ends with '\0'.
StringRef S = Saver.save(Config->DynamicLinker);
ArrayRef<uint8_t> Contents = {(const uint8_t *)S.data(), S.size() + 1};
auto *Sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, Contents,
".interp");
Sec->Live = true;
return Sec;
}
Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
uint64_t Size, InputSectionBase &Section) {
auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type,
Value, Size, &Section);
if (In.SymTab)
In.SymTab->addSymbol(S);
return S;
}
static size_t getHashSize() {
switch (Config->BuildId) {
case BuildIdKind::Fast:
return 8;
case BuildIdKind::Md5:
case BuildIdKind::Uuid:
return 16;
case BuildIdKind::Sha1:
return 20;
case BuildIdKind::Hexstring:
return Config->BuildIdVector.size();
default:
llvm_unreachable("unknown BuildIdKind");
}
}
BuildIdSection::BuildIdSection()
: SyntheticSection(SHF_ALLOC, SHT_NOTE, 4, ".note.gnu.build-id"),
HashSize(getHashSize()) {}
void BuildIdSection::writeTo(uint8_t *Buf) {
write32(Buf, 4); // Name size
write32(Buf + 4, HashSize); // Content size
write32(Buf + 8, NT_GNU_BUILD_ID); // Type
memcpy(Buf + 12, "GNU", 4); // Name string
HashBuf = Buf + 16;
}
// Split one uint8 array into small pieces of uint8 arrays.
static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> Arr,
size_t ChunkSize) {
std::vector<ArrayRef<uint8_t>> Ret;
while (Arr.size() > ChunkSize) {
Ret.push_back(Arr.take_front(ChunkSize));
Arr = Arr.drop_front(ChunkSize);
}
if (!Arr.empty())
Ret.push_back(Arr);
return Ret;
}
// Computes a hash value of Data using a given hash function.
// In order to utilize multiple cores, we first split data into 1MB
// chunks, compute a hash for each chunk, and then compute a hash value
// of the hash values.
void BuildIdSection::computeHash(
llvm::ArrayRef<uint8_t> Data,
std::function<void(uint8_t *Dest, ArrayRef<uint8_t> Arr)> HashFn) {
std::vector<ArrayRef<uint8_t>> Chunks = split(Data, 1024 * 1024);
std::vector<uint8_t> Hashes(Chunks.size() * HashSize);
// Compute hash values.
parallelForEachN(0, Chunks.size(), [&](size_t I) {
HashFn(Hashes.data() + I * HashSize, Chunks[I]);
});
// Write to the final output buffer.
HashFn(HashBuf, Hashes);
}
BssSection::BssSection(StringRef Name, uint64_t Size, uint32_t Alignment)
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, Alignment, Name) {
this->Bss = true;
this->Size = Size;
}
void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) {
switch (Config->BuildId) {
case BuildIdKind::Fast:
computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
write64le(Dest, xxHash64(Arr));
});
break;
case BuildIdKind::Md5:
computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
memcpy(Dest, MD5::hash(Arr).data(), 16);
});
break;
case BuildIdKind::Sha1:
computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
memcpy(Dest, SHA1::hash(Arr).data(), 20);
});
break;
case BuildIdKind::Uuid:
if (auto EC = getRandomBytes(HashBuf, HashSize))
error("entropy source failure: " + EC.message());
break;
case BuildIdKind::Hexstring:
memcpy(HashBuf, Config->BuildIdVector.data(), Config->BuildIdVector.size());
break;
default:
llvm_unreachable("unknown BuildIdKind");
}
}
EhFrameSection::EhFrameSection()
: SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame") {}
// Search for an existing CIE record or create a new one.
// CIE records from input object files are uniquified by their contents
// and where their relocations point to.
template <class ELFT, class RelTy>
CieRecord *EhFrameSection::addCie(EhSectionPiece &Cie, ArrayRef<RelTy> Rels) {
Symbol *Personality = nullptr;
unsigned FirstRelI = Cie.FirstRelocation;
if (FirstRelI != (unsigned)-1)
Personality =
&Cie.Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
// Search for an existing CIE by CIE contents/relocation target pair.
CieRecord *&Rec = CieMap[{Cie.data(), Personality}];
// If not found, create a new one.
if (!Rec) {
Rec = make<CieRecord>();
Rec->Cie = &Cie;
CieRecords.push_back(Rec);
}
return Rec;
}
// There is one FDE per function. Returns true if a given FDE
// points to a live function.
template <class ELFT, class RelTy>
bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) {
auto *Sec = cast<EhInputSection>(Fde.Sec);
unsigned FirstRelI = Fde.FirstRelocation;
// An FDE should point to some function because FDEs are to describe
// functions. That's however not always the case due to an issue of
// ld.gold with -r. ld.gold may discard only functions and leave their
// corresponding FDEs, which results in creating bad .eh_frame sections.
// To deal with that, we ignore such FDEs.
if (FirstRelI == (unsigned)-1)
return false;
const RelTy &Rel = Rels[FirstRelI];
Symbol &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel);
// FDEs for garbage-collected or merged-by-ICF sections are dead.
if (auto *D = dyn_cast<Defined>(&B))
if (SectionBase *Sec = D->Section)
return Sec->Live;
return false;
}
// .eh_frame is a sequence of CIE or FDE records. In general, there
// is one CIE record per input object file which is followed by
// a list of FDEs. This function searches an existing CIE or create a new
// one and associates FDEs to the CIE.
template <class ELFT, class RelTy>
void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef<RelTy> Rels) {
OffsetToCie.clear();
for (EhSectionPiece &Piece : Sec->Pieces) {
// The empty record is the end marker.
if (Piece.Size == 4)
return;
size_t Offset = Piece.InputOff;
uint32_t ID = read32(Piece.data().data() + 4);
if (ID == 0) {
OffsetToCie[Offset] = addCie<ELFT>(Piece, Rels);
continue;
}
uint32_t CieOffset = Offset + 4 - ID;
CieRecord *Rec = OffsetToCie[CieOffset];
if (!Rec)
fatal(toString(Sec) + ": invalid CIE reference");
if (!isFdeLive<ELFT>(Piece, Rels))
continue;
Rec->Fdes.push_back(&Piece);
NumFdes++;
}
}
template <class ELFT> void EhFrameSection::addSection(InputSectionBase *C) {
auto *Sec = cast<EhInputSection>(C);
Sec->Parent = this;
Alignment = std::max(Alignment, Sec->Alignment);
Sections.push_back(Sec);
for (auto *DS : Sec->DependentSections)
DependentSections.push_back(DS);
if (Sec->Pieces.empty())
return;
if (Sec->AreRelocsRela)
addSectionAux<ELFT>(Sec, Sec->template relas<ELFT>());
else
addSectionAux<ELFT>(Sec, Sec->template rels<ELFT>());
}
static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
memcpy(Buf, D.data(), D.size());
size_t Aligned = alignTo(D.size(), Config->Wordsize);
// Zero-clear trailing padding if it exists.
memset(Buf + D.size(), 0, Aligned - D.size());
// Fix the size field. -4 since size does not include the size field itself.
write32(Buf, Aligned - 4);
}
void EhFrameSection::finalizeContents() {
assert(!this->Size); // Not finalized.
size_t Off = 0;
for (CieRecord *Rec : CieRecords) {
Rec->Cie->OutputOff = Off;
Off += alignTo(Rec->Cie->Size, Config->Wordsize);
for (EhSectionPiece *Fde : Rec->Fdes) {
Fde->OutputOff = Off;
Off += alignTo(Fde->Size, Config->Wordsize);
}
}
// The LSB standard does not allow a .eh_frame section with zero
// Call Frame Information records. glibc unwind-dw2-fde.c
// classify_object_over_fdes expects there is a CIE record length 0 as a
// terminator. Thus we add one unconditionally.
Off += 4;
this->Size = Off;
}
// Returns data for .eh_frame_hdr. .eh_frame_hdr is a binary search table
// to get an FDE from an address to which FDE is applied. This function
// returns a list of such pairs.
std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const {
uint8_t *Buf = getParent()->Loc + OutSecOff;
std::vector<FdeData> Ret;
uint64_t VA = In.EhFrameHdr->getVA();
for (CieRecord *Rec : CieRecords) {
uint8_t Enc = getFdeEncoding(Rec->Cie);
for (EhSectionPiece *Fde : Rec->Fdes) {
uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
uint64_t FdeVA = getParent()->Addr + Fde->OutputOff;
if (!isInt<32>(Pc - VA))
fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" +
Twine::utohexstr(Pc - VA));
Ret.push_back({uint32_t(Pc - VA), uint32_t(FdeVA - VA)});
}
}
// Sort the FDE list by their PC and uniqueify. Usually there is only
// one FDE for a PC (i.e. function), but if ICF merges two functions
// into one, there can be more than one FDEs pointing to the address.
auto Less = [](const FdeData &A, const FdeData &B) {
return A.PcRel < B.PcRel;
};
std::stable_sort(Ret.begin(), Ret.end(), Less);
auto Eq = [](const FdeData &A, const FdeData &B) {
return A.PcRel == B.PcRel;
};
Ret.erase(std::unique(Ret.begin(), Ret.end(), Eq), Ret.end());
return Ret;
}
static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
switch (Size) {
case DW_EH_PE_udata2:
return read16(Buf);
case DW_EH_PE_sdata2:
return (int16_t)read16(Buf);
case DW_EH_PE_udata4:
return read32(Buf);
case DW_EH_PE_sdata4:
return (int32_t)read32(Buf);
case DW_EH_PE_udata8:
case DW_EH_PE_sdata8:
return read64(Buf);
case DW_EH_PE_absptr:
return readUint(Buf);
}
fatal("unknown FDE size encoding");
}
// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
// We need it to create .eh_frame_hdr section.
uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff,
uint8_t Enc) const {
// The starting address to which this FDE applies is
// stored at FDE + 8 byte.
size_t Off = FdeOff + 8;
uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0xf);
if ((Enc & 0x70) == DW_EH_PE_absptr)
return Addr;
if ((Enc & 0x70) == DW_EH_PE_pcrel)
return Addr + getParent()->Addr + Off;
fatal("unknown FDE size relative encoding");
}
void EhFrameSection::writeTo(uint8_t *Buf) {
// Write CIE and FDE records.
for (CieRecord *Rec : CieRecords) {
size_t CieOffset = Rec->Cie->OutputOff;
writeCieFde(Buf + CieOffset, Rec->Cie->data());
for (EhSectionPiece *Fde : Rec->Fdes) {
size_t Off = Fde->OutputOff;
writeCieFde(Buf + Off, Fde->data());
// FDE's second word should have the offset to an associated CIE.
// Write it.
write32(Buf + Off + 4, Off + 4 - CieOffset);
}
}
// Apply relocations. .eh_frame section contents are not contiguous
// in the output buffer, but relocateAlloc() still works because
// getOffset() takes care of discontiguous section pieces.
for (EhInputSection *S : Sections)
S->relocateAlloc(Buf, nullptr);
}
GotSection::GotSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
Target->GotEntrySize, ".got") {
// PPC64 saves the ElfSym::GlobalOffsetTable .TOC. as the first entry in the
// .got. If there are no references to .TOC. in the symbol table,
// ElfSym::GlobalOffsetTable will not be defined and we won't need to save
// .TOC. in the .got. When it is defined, we increase NumEntries by the number
// of entries used to emit ElfSym::GlobalOffsetTable.
if (ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt)
NumEntries += Target->GotHeaderEntriesNum;
}
void GotSection::addEntry(Symbol &Sym) {
Sym.GotIndex = NumEntries;
++NumEntries;
}
bool GotSection::addDynTlsEntry(Symbol &Sym) {
if (Sym.GlobalDynIndex != -1U)
return false;
Sym.GlobalDynIndex = NumEntries;
// Global Dynamic TLS entries take two GOT slots.
NumEntries += 2;
return true;
}
// Reserves TLS entries for a TLS module ID and a TLS block offset.
// In total it takes two GOT slots.
bool GotSection::addTlsIndex() {
if (TlsIndexOff != uint32_t(-1))
return false;
TlsIndexOff = NumEntries * Config->Wordsize;
NumEntries += 2;
return true;
}
uint64_t GotSection::getGlobalDynAddr(const Symbol &B) const {
return this->getVA() + B.GlobalDynIndex * Config->Wordsize;
}
uint64_t GotSection::getGlobalDynOffset(const Symbol &B) const {
return B.GlobalDynIndex * Config->Wordsize;
}
void GotSection::finalizeContents() {
Size = NumEntries * Config->Wordsize;
}
bool GotSection::empty() const {
// We need to emit a GOT even if it's empty if there's a relocation that is
// relative to GOT(such as GOTOFFREL) or there's a symbol that points to a GOT
// (i.e. _GLOBAL_OFFSET_TABLE_) that the target defines relative to the .got.
return NumEntries == 0 && !HasGotOffRel &&
!(ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt);
}
void GotSection::writeTo(uint8_t *Buf) {
// Buf points to the start of this section's buffer,
// whereas InputSectionBase::relocateAlloc() expects its argument
// to point to the start of the output section.
Target->writeGotHeader(Buf);
relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size);
}
static uint64_t getMipsPageAddr(uint64_t Addr) {
return (Addr + 0x8000) & ~0xffff;
}
static uint64_t getMipsPageCount(uint64_t Size) {
return (Size + 0xfffe) / 0xffff + 1;
}
MipsGotSection::MipsGotSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
".got") {}
void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend,
RelExpr Expr) {
FileGot &G = getGot(File);
if (Expr == R_MIPS_GOT_LOCAL_PAGE) {
if (const OutputSection *OS = Sym.getOutputSection())
G.PagesMap.insert({OS, {}});
else
G.Local16.insert({{nullptr, getMipsPageAddr(Sym.getVA(Addend))}, 0});
} else if (Sym.isTls())
G.Tls.insert({&Sym, 0});
else if (Sym.IsPreemptible && Expr == R_ABS)
G.Relocs.insert({&Sym, 0});
else if (Sym.IsPreemptible)
G.Global.insert({&Sym, 0});
else if (Expr == R_MIPS_GOT_OFF32)
G.Local32.insert({{&Sym, Addend}, 0});
else
G.Local16.insert({{&Sym, Addend}, 0});
}
void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) {
getGot(File).DynTlsSymbols.insert({&Sym, 0});
}
void MipsGotSection::addTlsIndex(InputFile &File) {
getGot(File).DynTlsSymbols.insert({nullptr, 0});
}
size_t MipsGotSection::FileGot::getEntriesNum() const {
return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() +
Tls.size() + DynTlsSymbols.size() * 2;
}
size_t MipsGotSection::FileGot::getPageEntriesNum() const {
size_t Num = 0;
for (const std::pair<const OutputSection *, FileGot::PageBlock> &P : PagesMap)
Num += P.second.Count;
return Num;
}
size_t MipsGotSection::FileGot::getIndexedEntriesNum() const {
size_t Count = getPageEntriesNum() + Local16.size() + Global.size();
// If there are relocation-only entries in the GOT, TLS entries
// are allocated after them. TLS entries should be addressable
// by 16-bit index so count both reloc-only and TLS entries.
if (!Tls.empty() || !DynTlsSymbols.empty())
Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2;
return Count;
}
MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) {
if (!F.MipsGotIndex.hasValue()) {
Gots.emplace_back();
Gots.back().File = &F;
F.MipsGotIndex = Gots.size() - 1;
}
return Gots[*F.MipsGotIndex];
}
uint64_t MipsGotSection::getPageEntryOffset(const InputFile *F,
const Symbol &Sym,
int64_t Addend) const {
const FileGot &G = Gots[*F->MipsGotIndex];
uint64_t Index = 0;
if (const OutputSection *OutSec = Sym.getOutputSection()) {
uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend));
Index = G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff;
} else {
Index = G.Local16.lookup({nullptr, getMipsPageAddr(Sym.getVA(Addend))});
}
return Index * Config->Wordsize;
}
uint64_t MipsGotSection::getSymEntryOffset(const InputFile *F, const Symbol &S,
int64_t Addend) const {
const FileGot &G = Gots[*F->MipsGotIndex];
Symbol *Sym = const_cast<Symbol *>(&S);
if (Sym->isTls())
return G.Tls.lookup(Sym) * Config->Wordsize;
if (Sym->IsPreemptible)
return G.Global.lookup(Sym) * Config->Wordsize;
return G.Local16.lookup({Sym, Addend}) * Config->Wordsize;
}
uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *F) const {
const FileGot &G = Gots[*F->MipsGotIndex];
return G.DynTlsSymbols.lookup(nullptr) * Config->Wordsize;
}
uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *F,
const Symbol &S) const {
const FileGot &G = Gots[*F->MipsGotIndex];
Symbol *Sym = const_cast<Symbol *>(&S);
return G.DynTlsSymbols.lookup(Sym) * Config->Wordsize;
}
const Symbol *MipsGotSection::getFirstGlobalEntry() const {
if (Gots.empty())
return nullptr;
const FileGot &PrimGot = Gots.front();
if (!PrimGot.Global.empty())
return PrimGot.Global.front().first;
if (!PrimGot.Relocs.empty())
return PrimGot.Relocs.front().first;
return nullptr;
}
unsigned MipsGotSection::getLocalEntriesNum() const {
if (Gots.empty())
return HeaderEntriesNum;
return HeaderEntriesNum + Gots.front().getPageEntriesNum() +
Gots.front().Local16.size();
}
bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) {
FileGot Tmp = Dst;
set_union(Tmp.PagesMap, Src.PagesMap);
set_union(Tmp.Local16, Src.Local16);
set_union(Tmp.Global, Src.Global);
set_union(Tmp.Relocs, Src.Relocs);
set_union(Tmp.Tls, Src.Tls);
set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols);
size_t Count = IsPrimary ? HeaderEntriesNum : 0;
Count += Tmp.getIndexedEntriesNum();
if (Count * Config->Wordsize > Config->MipsGotSize)
return false;
std::swap(Tmp, Dst);
return true;
}
void MipsGotSection::finalizeContents() { updateAllocSize(); }
bool MipsGotSection::updateAllocSize() {
Size = HeaderEntriesNum * Config->Wordsize;
for (const FileGot &G : Gots)
Size += G.getEntriesNum() * Config->Wordsize;
return false;
}
template <class ELFT> void MipsGotSection::build() {
if (Gots.empty())
return;
std::vector<FileGot> MergedGots(1);
// For each GOT move non-preemptible symbols from the `Global`
// to `Local16` list. Preemptible symbol might become non-preemptible
// one if, for example, it gets a related copy relocation.
for (FileGot &Got : Gots) {
for (auto &P: Got.Global)
if (!P.first->IsPreemptible)
Got.Local16.insert({{P.first, 0}, 0});
Got.Global.remove_if([&](const std::pair<Symbol *, size_t> &P) {
return !P.first->IsPreemptible;
});
}
// For each GOT remove "reloc-only" entry if there is "global"
// entry for the same symbol. And add local entries which indexed
// using 32-bit value at the end of 16-bit entries.
for (FileGot &Got : Gots) {
Got.Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
return Got.Global.count(P.first);
});
set_union(Got.Local16, Got.Local32);
Got.Local32.clear();
}
// Evaluate number of "reloc-only" entries in the resulting GOT.
// To do that put all unique "reloc-only" and "global" entries
// from all GOTs to the future primary GOT.
FileGot *PrimGot = &MergedGots.front();
for (FileGot &Got : Gots) {
set_union(PrimGot->Relocs, Got.Global);
set_union(PrimGot->Relocs, Got.Relocs);
Got.Relocs.clear();
}
// Evaluate number of "page" entries in each GOT.
for (FileGot &Got : Gots) {
for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
Got.PagesMap) {
const OutputSection *OS = P.first;
uint64_t SecSize = 0;
for (BaseCommand *Cmd : OS->SectionCommands) {
if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
for (InputSection *IS : ISD->Sections) {
uint64_t Off = alignTo(SecSize, IS->Alignment);
SecSize = Off + IS->getSize();
}
}
P.second.Count = getMipsPageCount(SecSize);
}
}
// Merge GOTs. Try to join as much as possible GOTs but do not exceed
// maximum GOT size. At first, try to fill the primary GOT because
// the primary GOT can be accessed in the most effective way. If it
// is not possible, try to fill the last GOT in the list, and finally
// create a new GOT if both attempts failed.
for (FileGot &SrcGot : Gots) {
InputFile *File = SrcGot.File;
if (tryMergeGots(MergedGots.front(), SrcGot, true)) {
File->MipsGotIndex = 0;
} else {
// If this is the first time we failed to merge with the primary GOT,
// MergedGots.back() will also be the primary GOT. We must make sure not
// to try to merge again with IsPrimary=false, as otherwise, if the
// inputs are just right, we could allow the primary GOT to become 1 or 2
// words too big due to ignoring the header size.
if (MergedGots.size() == 1 ||
!tryMergeGots(MergedGots.back(), SrcGot, false)) {
MergedGots.emplace_back();
std::swap(MergedGots.back(), SrcGot);
}
File->MipsGotIndex = MergedGots.size() - 1;
}
}
std::swap(Gots, MergedGots);
// Reduce number of "reloc-only" entries in the primary GOT
// by substracting "global" entries exist in the primary GOT.
PrimGot = &Gots.front();
PrimGot->Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
return PrimGot->Global.count(P.first);
});
// Calculate indexes for each GOT entry.
size_t Index = HeaderEntriesNum;
for (FileGot &Got : Gots) {
Got.StartIndex = &Got == PrimGot ? 0 : Index;
for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
Got.PagesMap) {
// For each output section referenced by GOT page relocations calculate
// and save into PagesMap an upper bound of MIPS GOT entries required
// to store page addresses of local symbols. We assume the worst case -
// each 64kb page of the output section has at least one GOT relocation
// against it. And take in account the case when the section intersects
// page boundaries.
P.second.FirstIndex = Index;
Index += P.second.Count;
}
for (auto &P: Got.Local16)
P.second = Index++;
for (auto &P: Got.Global)
P.second = Index++;
for (auto &P: Got.Relocs)
P.second = Index++;
for (auto &P: Got.Tls)
P.second = Index++;
for (auto &P: Got.DynTlsSymbols) {
P.second = Index;
Index += 2;
}
}
// Update Symbol::GotIndex field to use this
// value later in the `sortMipsSymbols` function.
for (auto &P : PrimGot->Global)
P.first->GotIndex = P.second;
for (auto &P : PrimGot->Relocs)
P.first->GotIndex = P.second;
// Create dynamic relocations.
for (FileGot &Got : Gots) {
// Create dynamic relocations for TLS entries.
for (std::pair<Symbol *, size_t> &P : Got.Tls) {
Symbol *S = P.first;
uint64_t Offset = P.second * Config->Wordsize;
if (S->IsPreemptible)
In.RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S);
}
for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) {
Symbol *S = P.first;
uint64_t Offset = P.second * Config->Wordsize;
if (S == nullptr) {
if (!Config->Pic)
continue;
In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
} else {
// When building a shared library we still need a dynamic relocation
// for the module index. Therefore only checking for
// S->IsPreemptible is not sufficient (this happens e.g. for
// thread-locals that have been marked as local through a linker script)
if (!S->IsPreemptible && !Config->Pic)
continue;
In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
// However, we can skip writing the TLS offset reloc for non-preemptible
// symbols since it is known even in shared libraries
if (!S->IsPreemptible)
continue;
Offset += Config->Wordsize;
In.RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S);
}
}
// Do not create dynamic relocations for non-TLS
// entries in the primary GOT.
if (&Got == PrimGot)
continue;
// Dynamic relocations for "global" entries.
for (const std::pair<Symbol *, size_t> &P : Got.Global) {
uint64_t Offset = P.second * Config->Wordsize;
In.RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first);
}
if (!Config->Pic)
continue;
// Dynamic relocations for "local" entries in case of PIC.
for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
Got.PagesMap) {
size_t PageCount = L.second.Count;
for (size_t PI = 0; PI < PageCount; ++PI) {
uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize;
In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first,
int64_t(PI * 0x10000)});
}
}
for (const std::pair<GotEntry, size_t> &P : Got.Local16) {
uint64_t Offset = P.second * Config->Wordsize;
In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, true,
P.first.first, P.first.second});
}
}
}
bool MipsGotSection::empty() const {
// We add the .got section to the result for dynamic MIPS target because
// its address and properties are mentioned in the .dynamic section.
return Config->Relocatable;
}
uint64_t MipsGotSection::getGp(const InputFile *F) const {
// For files without related GOT or files refer a primary GOT
// returns "common" _gp value. For secondary GOTs calculate
// individual _gp values.
if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0)
return ElfSym::MipsGp->getVA(0);
return getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize +
0x7ff0;
}
void MipsGotSection::writeTo(uint8_t *Buf) {
// Set the MSB of the second GOT slot. This is not required by any
// MIPS ABI documentation, though.
//
// There is a comment in glibc saying that "The MSB of got[1] of a
// gnu object is set to identify gnu objects," and in GNU gold it
// says "the second entry will be used by some runtime loaders".
// But how this field is being used is unclear.
//
// We are not really willing to mimic other linkers behaviors
// without understanding why they do that, but because all files
// generated by GNU tools have this special GOT value, and because
// we've been doing this for years, it is probably a safe bet to
// keep doing this for now. We really need to revisit this to see
// if we had to do this.
writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1));
for (const FileGot &G : Gots) {
auto Write = [&](size_t I, const Symbol *S, int64_t A) {
uint64_t VA = A;
if (S) {
VA = S->getVA(A);
if (S->StOther & STO_MIPS_MICROMIPS)
VA |= 1;
}
writeUint(Buf + I * Config->Wordsize, VA);
};
// Write 'page address' entries to the local part of the GOT.
for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
G.PagesMap) {
size_t PageCount = L.second.Count;
uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
for (size_t PI = 0; PI < PageCount; ++PI)
Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000);
}
// Local, global, TLS, reloc-only entries.
// If TLS entry has a corresponding dynamic relocations, leave it
// initialized by zero. Write down adjusted TLS symbol's values otherwise.
// To calculate the adjustments use offsets for thread-local storage.
// https://www.linux-mips.org/wiki/NPTL
for (const std::pair<GotEntry, size_t> &P : G.Local16)
Write(P.second, P.first.first, P.first.second);
// Write VA to the primary GOT only. For secondary GOTs that
// will be done by REL32 dynamic relocations.
if (&G == &Gots.front())
for (const std::pair<const Symbol *, size_t> &P : G.Global)
Write(P.second, P.first, 0);
for (const std::pair<Symbol *, size_t> &P : G.Relocs)
Write(P.second, P.first, 0);
for (const std::pair<Symbol *, size_t> &P : G.Tls)
Write(P.second, P.first, P.first->IsPreemptible ? 0 : -0x7000);
for (const std::pair<Symbol *, size_t> &P : G.DynTlsSymbols) {
if (P.first == nullptr && !Config->Pic)
Write(P.second, nullptr, 1);
else if (P.first && !P.first->IsPreemptible) {
// If we are emitting PIC code with relocations we mustn't write
// anything to the GOT here. When using Elf_Rel relocations the value
// one will be treated as an addend and will cause crashes at runtime
if (!Config->Pic)
Write(P.second, nullptr, 1);
Write(P.second + 1, P.first, -0x8000);
}
}
}
}
// On PowerPC the .plt section is used to hold the table of function addresses
// instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss
// section. I don't know why we have a BSS style type for the section but it is
// consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI.
GotPltSection::GotPltSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE,
Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
Target->GotPltEntrySize,
Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {}
void GotPltSection::addEntry(Symbol &Sym) {
assert(Sym.PltIndex == Entries.size());
Entries.push_back(&Sym);
}
size_t GotPltSection::getSize() const {
return (Target->GotPltHeaderEntriesNum + Entries.size()) *
Target->GotPltEntrySize;
}
void GotPltSection::writeTo(uint8_t *Buf) {
Target->writeGotPltHeader(Buf);
Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize;
for (const Symbol *B : Entries) {
Target->writeGotPlt(Buf, *B);
Buf += Config->Wordsize;
}
}
bool GotPltSection::empty() const {
// We need to emit a GOT.PLT even if it's empty if there's a symbol that
// references the _GLOBAL_OFFSET_TABLE_ and the Target defines the symbol
// relative to the .got.plt section.
return Entries.empty() &&
!(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt);
}
static StringRef getIgotPltName() {
// On ARM the IgotPltSection is part of the GotSection.
if (Config->EMachine == EM_ARM)
return ".got";
// On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection
// needs to be named the same.
if (Config->EMachine == EM_PPC64)
return ".plt";
return ".got.plt";
}
// On PowerPC64 the GotPltSection type is SHT_NOBITS so we have to follow suit
// with the IgotPltSection.
IgotPltSection::IgotPltSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE,
Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
Target->GotPltEntrySize, getIgotPltName()) {}
void IgotPltSection::addEntry(Symbol &Sym) {
Sym.IsInIgot = true;
assert(Sym.PltIndex == Entries.size());
Entries.push_back(&Sym);
}
size_t IgotPltSection::getSize() const {
return Entries.size() * Target->GotPltEntrySize;
}
void IgotPltSection::writeTo(uint8_t *Buf) {
for (const Symbol *B : Entries) {
Target->writeIgotPlt(Buf, *B);
Buf += Config->Wordsize;
}
}
StringTableSection::StringTableSection(StringRef Name, bool Dynamic)
: SyntheticSection(Dynamic ? (uint64_t)SHF_ALLOC : 0, SHT_STRTAB, 1, Name),
Dynamic(Dynamic) {
// ELF string tables start with a NUL byte.
addString("");
}
// Adds a string to the string table. If HashIt is true we hash and check for
// duplicates. It is optional because the name of global symbols are already
// uniqued and hashing them again has a big cost for a small value: uniquing
// them with some other string that happens to be the same.
unsigned StringTableSection::addString(StringRef S, bool HashIt) {
if (HashIt) {
auto R = StringMap.insert(std::make_pair(S, this->Size));
if (!R.second)
return R.first->second;
}
unsigned Ret = this->Size;
this->Size = this->Size + S.size() + 1;
Strings.push_back(S);
return Ret;
}
void StringTableSection::writeTo(uint8_t *Buf) {
for (StringRef S : Strings) {
memcpy(Buf, S.data(), S.size());
Buf[S.size()] = '\0';
Buf += S.size() + 1;
}
}
// Returns the number of version definition entries. Because the first entry
// is for the version definition itself, it is the number of versioned symbols
// plus one. Note that we don't support multiple versions yet.
static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; }
template <class ELFT>
DynamicSection<ELFT>::DynamicSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, Config->Wordsize,
".dynamic") {
this->Entsize = ELFT::Is64Bits ? 16 : 8;
// .dynamic section is not writable on MIPS and on Fuchsia OS
// which passes -z rodynamic.
// See "Special Section" in Chapter 4 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
if (Config->EMachine == EM_MIPS || Config->ZRodynamic)
this->Flags = SHF_ALLOC;
// Add strings to .dynstr early so that .dynstr's size will be
// fixed early.
for (StringRef S : Config->FilterList)
addInt(DT_FILTER, In.DynStrTab->addString(S));
for (StringRef S : Config->AuxiliaryList)
addInt(DT_AUXILIARY, In.DynStrTab->addString(S));
if (!Config->Rpath.empty())
addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
In.DynStrTab->addString(Config->Rpath));
for (InputFile *File : SharedFiles) {
SharedFile<ELFT> *F = cast<SharedFile<ELFT>>(File);
if (F->IsNeeded)
addInt(DT_NEEDED, In.DynStrTab->addString(F->SoName));
}
if (!Config->SoName.empty())
addInt(DT_SONAME, In.DynStrTab->addString(Config->SoName));
}
template <class ELFT>
void DynamicSection<ELFT>::add(int32_t Tag, std::function<uint64_t()> Fn) {
Entries.push_back({Tag, Fn});
}
template <class ELFT>
void DynamicSection<ELFT>::addInt(int32_t Tag, uint64_t Val) {
Entries.push_back({Tag, [=] { return Val; }});
}
template <class ELFT>
void DynamicSection<ELFT>::addInSec(int32_t Tag, InputSection *Sec) {
Entries.push_back({Tag, [=] { return Sec->getVA(0); }});
}
template <class ELFT>
void DynamicSection<ELFT>::addInSecRelative(int32_t Tag, InputSection *Sec) {
size_t TagOffset = Entries.size() * Entsize;
Entries.push_back(
{Tag, [=] { return Sec->getVA(0) - (getVA() + TagOffset); }});
}
template <class ELFT>
void DynamicSection<ELFT>::addOutSec(int32_t Tag, OutputSection *Sec) {
Entries.push_back({Tag, [=] { return Sec->Addr; }});
}
template <class ELFT>
void DynamicSection<ELFT>::addSize(int32_t Tag, OutputSection *Sec) {
Entries.push_back({Tag, [=] { return Sec->Size; }});
}
template <class ELFT>
void DynamicSection<ELFT>::addSym(int32_t Tag, Symbol *Sym) {
Entries.push_back({Tag, [=] { return Sym->getVA(); }});
}
// A Linker script may assign the RELA relocation sections to the same
// output section. When this occurs we cannot just use the OutputSection
// Size. Moreover the [DT_JMPREL, DT_JMPREL + DT_PLTRELSZ) is permitted to
// overlap with the [DT_RELA, DT_RELA + DT_RELASZ).
static uint64_t addPltRelSz() {
size_t Size = In.RelaPlt->getSize();
if (In.RelaIplt->getParent() == In.RelaPlt->getParent() &&
In.RelaIplt->Name == In.RelaPlt->Name)
Size += In.RelaIplt->getSize();
return Size;
}
// Add remaining entries to complete .dynamic contents.
template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
// Set DT_FLAGS and DT_FLAGS_1.
uint32_t DtFlags = 0;
uint32_t DtFlags1 = 0;
if (Config->Bsymbolic)
DtFlags |= DF_SYMBOLIC;
if (Config->ZGlobal)
DtFlags1 |= DF_1_GLOBAL;
if (Config->ZInitfirst)
DtFlags1 |= DF_1_INITFIRST;
if (Config->ZInterpose)
DtFlags1 |= DF_1_INTERPOSE;
if (Config->ZNodefaultlib)
DtFlags1 |= DF_1_NODEFLIB;
if (Config->ZNodelete)
DtFlags1 |= DF_1_NODELETE;
if (Config->ZNodlopen)
DtFlags1 |= DF_1_NOOPEN;
if (Config->ZNow) {
DtFlags |= DF_BIND_NOW;
DtFlags1 |= DF_1_NOW;
}
if (Config->ZOrigin) {
DtFlags |= DF_ORIGIN;
DtFlags1 |= DF_1_ORIGIN;
}
if (!Config->ZText)
DtFlags |= DF_TEXTREL;
if (Config->HasStaticTlsModel)
DtFlags |= DF_STATIC_TLS;
if (DtFlags)
addInt(DT_FLAGS, DtFlags);
if (DtFlags1)
addInt(DT_FLAGS_1, DtFlags1);
// DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We
// need it for each process, so we don't write it for DSOs. The loader writes
// the pointer into this entry.
//
// DT_DEBUG is the only .dynamic entry that needs to be written to. Some
// systems (currently only Fuchsia OS) provide other means to give the
// debugger this information. Such systems may choose make .dynamic read-only.
// If the target is such a system (used -z rodynamic) don't write DT_DEBUG.
if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic)
addInt(DT_DEBUG, 0);
if (OutputSection *Sec = In.DynStrTab->getParent())
this->Link = Sec->SectionIndex;
if (!In.RelaDyn->empty()) {
addInSec(In.RelaDyn->DynamicTag, In.RelaDyn);
addSize(In.RelaDyn->SizeDynamicTag, In.RelaDyn->getParent());
bool IsRela = Config->IsRela;
addInt(IsRela ? DT_RELAENT : DT_RELENT,
IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel));
// MIPS dynamic loader does not support RELCOUNT tag.
// The problem is in the tight relation between dynamic
// relocations and GOT. So do not emit this tag on MIPS.
if (Config->EMachine != EM_MIPS) {
size_t NumRelativeRels = In.RelaDyn->getRelativeRelocCount();
if (Config->ZCombreloc && NumRelativeRels)
addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels);
}
}
if (In.RelrDyn && !In.RelrDyn->Relocs.empty()) {
addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
In.RelrDyn);
addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
In.RelrDyn->getParent());
addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
sizeof(Elf_Relr));
}
// .rel[a].plt section usually consists of two parts, containing plt and
// iplt relocations. It is possible to have only iplt relocations in the
// output. In that case RelaPlt is empty and have zero offset, the same offset
// as RelaIplt have. And we still want to emit proper dynamic tags for that
// case, so here we always use RelaPlt as marker for the begining of
// .rel[a].plt section.
if (In.RelaPlt->getParent()->Live) {
addInSec(DT_JMPREL, In.RelaPlt);
Entries.push_back({DT_PLTRELSZ, addPltRelSz});
switch (Config->EMachine) {
case EM_MIPS:
addInSec(DT_MIPS_PLTGOT, In.GotPlt);
break;
case EM_SPARCV9:
addInSec(DT_PLTGOT, In.Plt);
break;
default:
addInSec(DT_PLTGOT, In.GotPlt);
break;
}
addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL);
}
addInSec(DT_SYMTAB, In.DynSymTab);
addInt(DT_SYMENT, sizeof(Elf_Sym));
addInSec(DT_STRTAB, In.DynStrTab);
addInt(DT_STRSZ, In.DynStrTab->getSize());
if (!Config->ZText)
addInt(DT_TEXTREL, 0);
if (In.GnuHashTab)
addInSec(DT_GNU_HASH, In.GnuHashTab);
if (In.HashTab)
addInSec(DT_HASH, In.HashTab);
if (Out::PreinitArray) {
addOutSec(DT_PREINIT_ARRAY, Out::PreinitArray);
addSize(DT_PREINIT_ARRAYSZ, Out::PreinitArray);
}
if (Out::InitArray) {
addOutSec(DT_INIT_ARRAY, Out::InitArray);
addSize(DT_INIT_ARRAYSZ, Out::InitArray);
}
if (Out::FiniArray) {
addOutSec(DT_FINI_ARRAY, Out::FiniArray);
addSize(DT_FINI_ARRAYSZ, Out::FiniArray);
}
if (Symbol *B = Symtab->find(Config->Init))
if (B->isDefined())
addSym(DT_INIT, B);
if (Symbol *B = Symtab->find(Config->Fini))
if (B->isDefined())
addSym(DT_FINI, B);
bool HasVerNeed = InX<ELFT>::VerNeed->getNeedNum() != 0;
if (HasVerNeed || In.VerDef)
addInSec(DT_VERSYM, InX<ELFT>::VerSym);
if (In.VerDef) {
addInSec(DT_VERDEF, In.VerDef);
addInt(DT_VERDEFNUM, getVerDefNum());
}
if (HasVerNeed) {
addInSec(DT_VERNEED, InX<ELFT>::VerNeed);
addInt(DT_VERNEEDNUM, InX<ELFT>::VerNeed->getNeedNum());
}
if (Config->EMachine == EM_MIPS) {
addInt(DT_MIPS_RLD_VERSION, 1);
addInt(DT_MIPS_FLAGS, RHF_NOTPOT);
addInt(DT_MIPS_BASE_ADDRESS, Target->getImageBase());
addInt(DT_MIPS_SYMTABNO, In.DynSymTab->getNumSymbols());
add(DT_MIPS_LOCAL_GOTNO, [] { return In.MipsGot->getLocalEntriesNum(); });
if (const Symbol *B = In.MipsGot->getFirstGlobalEntry())
addInt(DT_MIPS_GOTSYM, B->DynsymIndex);
else
addInt(DT_MIPS_GOTSYM, In.DynSymTab->getNumSymbols());
addInSec(DT_PLTGOT, In.MipsGot);
if (In.MipsRldMap) {
if (!Config->Pie)
addInSec(DT_MIPS_RLD_MAP, In.MipsRldMap);
// Store the offset to the .rld_map section
// relative to the address of the tag.
addInSecRelative(DT_MIPS_RLD_MAP_REL, In.MipsRldMap);
}
}
// Glink dynamic tag is required by the V2 abi if the plt section isn't empty.
if (Config->EMachine == EM_PPC64 && !In.Plt->empty()) {
// The Glink tag points to 32 bytes before the first lazy symbol resolution
// stub, which starts directly after the header.
Entries.push_back({DT_PPC64_GLINK, [=] {
unsigned Offset = Target->PltHeaderSize - 32;
return In.Plt->getVA(0) + Offset;
}});
}
addInt(DT_NULL, 0);
getParent()->Link = this->Link;
this->Size = Entries.size() * this->Entsize;
}
template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
auto *P = reinterpret_cast<Elf_Dyn *>(Buf);
for (std::pair<int32_t, std::function<uint64_t()>> &KV : Entries) {
P->d_tag = KV.first;
P->d_un.d_val = KV.second();
++P;
}
}
uint64_t DynamicReloc::getOffset() const {
return InputSec->getVA(OffsetInSec);
}
int64_t DynamicReloc::computeAddend() const {
if (UseSymVA)
return Sym->getVA(Addend);
if (!OutputSec)
return Addend;
// See the comment in the DynamicReloc ctor.
return getMipsPageAddr(OutputSec->Addr) + Addend;
}
uint32_t DynamicReloc::getSymIndex() const {
if (Sym && !UseSymVA)
return Sym->DynsymIndex;
return 0;
}
RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type,
int32_t DynamicTag,
int32_t SizeDynamicTag)
: SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name),
DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {}
void RelocationBaseSection::addReloc(RelType DynType, InputSectionBase *IS,
uint64_t OffsetInSec, Symbol *Sym) {
addReloc({DynType, IS, OffsetInSec, false, Sym, 0});
}
void RelocationBaseSection::addReloc(RelType DynType,
InputSectionBase *InputSec,
uint64_t OffsetInSec, Symbol *Sym,
int64_t Addend, RelExpr Expr,
RelType Type) {
// Write the addends to the relocated address if required. We skip
// it if the written value would be zero.
if (Config->WriteAddends && (Expr != R_ADDEND || Addend != 0))
InputSec->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
addReloc({DynType, InputSec, OffsetInSec, Expr != R_ADDEND, Sym, Addend});
}
void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) {
if (Reloc.Type == Target->RelativeRel)
++NumRelativeRelocs;
Relocs.push_back(Reloc);
}
void RelocationBaseSection::finalizeContents() {
// When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE
// relocations due to IFUNC (e.g. strcpy). sh_link will be set to 0 in that
// case.
InputSection *SymTab = Config->Relocatable ? In.SymTab : In.DynSymTab;
if (SymTab && SymTab->getParent())
getParent()->Link = SymTab->getParent()->SectionIndex;
else
getParent()->Link = 0;
if (In.RelaPlt == this)
getParent()->Info = In.GotPlt->getParent()->SectionIndex;
if (In.RelaIplt == this)
getParent()->Info = In.IgotPlt->getParent()->SectionIndex;
}
RelrBaseSection::RelrBaseSection()
: SyntheticSection(SHF_ALLOC,
Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR,
Config->Wordsize, ".relr.dyn") {}
template <class ELFT>
static void encodeDynamicReloc(typename ELFT::Rela *P,
const DynamicReloc &Rel) {
if (Config->IsRela)
P->r_addend = Rel.computeAddend();
P->r_offset = Rel.getOffset();
P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL);
}
template <class ELFT>
RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
: RelocationBaseSection(Name, Config->IsRela ? SHT_RELA : SHT_REL,
Config->IsRela ? DT_RELA : DT_REL,
Config->IsRela ? DT_RELASZ : DT_RELSZ),
Sort(Sort) {
this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
}
static bool compRelocations(const DynamicReloc &A, const DynamicReloc &B) {
bool AIsRel = A.Type == Target->RelativeRel;
bool BIsRel = B.Type == Target->RelativeRel;
if (AIsRel != BIsRel)
return AIsRel;
return A.getSymIndex() < B.getSymIndex();
}
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
if (Sort)
std::stable_sort(Relocs.begin(), Relocs.end(), compRelocations);
for (const DynamicReloc &Rel : Relocs) {
encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(Buf), Rel);
Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
}
}
template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
return this->Entsize * Relocs.size();
}
template <class ELFT>
AndroidPackedRelocationSection<ELFT>::AndroidPackedRelocationSection(
StringRef Name)
: RelocationBaseSection(
Name, Config->IsRela ? SHT_ANDROID_RELA : SHT_ANDROID_REL,
Config->IsRela ? DT_ANDROID_RELA : DT_ANDROID_REL,
Config->IsRela ? DT_ANDROID_RELASZ : DT_ANDROID_RELSZ) {
this->Entsize = 1;
}
template <class ELFT>
bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
// This function computes the contents of an Android-format packed relocation
// section.
//
// This format compresses relocations by using relocation groups to factor out
// fields that are common between relocations and storing deltas from previous
// relocations in SLEB128 format (which has a short representation for small
// numbers). A good example of a relocation type with common fields is
// R_*_RELATIVE, which is normally used to represent function pointers in
// vtables. In the REL format, each relative relocation has the same r_info
// field, and is only different from other relative relocations in terms of
// the r_offset field. By sorting relocations by offset, grouping them by
// r_info and representing each relocation with only the delta from the
// previous offset, each 8-byte relocation can be compressed to as little as 1
// byte (or less with run-length encoding). This relocation packer was able to
// reduce the size of the relocation section in an Android Chromium DSO from
// 2,911,184 bytes to 174,693 bytes, or 6% of the original size.
//
// A relocation section consists of a header containing the literal bytes
// 'APS2' followed by a sequence of SLEB128-encoded integers. The first two
// elements are the total number of relocations in the section and an initial
// r_offset value. The remaining elements define a sequence of relocation
// groups. Each relocation group starts with a header consisting of the
// following elements:
//
// - the number of relocations in the relocation group
// - flags for the relocation group
// - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is set) the r_offset delta
// for each relocation in the group.
// - (if RELOCATION_GROUPED_BY_INFO_FLAG is set) the value of the r_info
// field for each relocation in the group.
// - (if RELOCATION_GROUP_HAS_ADDEND_FLAG and
// RELOCATION_GROUPED_BY_ADDEND_FLAG are set) the r_addend delta for
// each relocation in the group.
//
// Following the relocation group header are descriptions of each of the
// relocations in the group. They consist of the following elements:
//
// - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is not set) the r_offset
// delta for this relocation.
// - (if RELOCATION_GROUPED_BY_INFO_FLAG is not set) the value of the r_info
// field for this relocation.
// - (if RELOCATION_GROUP_HAS_ADDEND_FLAG is set and
// RELOCATION_GROUPED_BY_ADDEND_FLAG is not set) the r_addend delta for
// this relocation.
size_t OldSize = RelocData.size();
RelocData = {'A', 'P', 'S', '2'};
raw_svector_ostream OS(RelocData);
auto Add = [&](int64_t V) { encodeSLEB128(V, OS); };
// The format header includes the number of relocations and the initial
// offset (we set this to zero because the first relocation group will
// perform the initial adjustment).
Add(Relocs.size());
Add(0);
std::vector<Elf_Rela> Relatives, NonRelatives;
for (const DynamicReloc &Rel : Relocs) {
Elf_Rela R;
encodeDynamicReloc<ELFT>(&R, Rel);
if (R.getType(Config->IsMips64EL) == Target->RelativeRel)
Relatives.push_back(R);
else
NonRelatives.push_back(R);
}
llvm::sort(Relatives, [](const Elf_Rel &A, const Elf_Rel &B) {
return A.r_offset < B.r_offset;
});
// Try to find groups of relative relocations which are spaced one word
// apart from one another. These generally correspond to vtable entries. The
// format allows these groups to be encoded using a sort of run-length
// encoding, but each group will cost 7 bytes in addition to the offset from
// the previous group, so it is only profitable to do this for groups of
// size 8 or larger.
std::vector<Elf_Rela> UngroupedRelatives;
std::vector<std::vector<Elf_Rela>> RelativeGroups;
for (auto I = Relatives.begin(), E = Relatives.end(); I != E;) {
std::vector<Elf_Rela> Group;
do {
Group.push_back(*I++);
} while (I != E && (I - 1)->r_offset + Config->Wordsize == I->r_offset);
if (Group.size() < 8)
UngroupedRelatives.insert(UngroupedRelatives.end(), Group.begin(),
Group.end());
else
RelativeGroups.emplace_back(std::move(Group));
}
unsigned HasAddendIfRela =
Config->IsRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0;
uint64_t Offset = 0;
uint64_t Addend = 0;
// Emit the run-length encoding for the groups of adjacent relative
// relocations. Each group is represented using two groups in the packed
// format. The first is used to set the current offset to the start of the
// group (and also encodes the first relocation), and the second encodes the
// remaining relocations.
for (std::vector<Elf_Rela> &G : RelativeGroups) {
// The first relocation in the group.
Add(1);
Add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG |
RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela);
Add(G[0].r_offset - Offset);
Add(Target->RelativeRel);
if (Config->IsRela) {
Add(G[0].r_addend - Addend);
Addend = G[0].r_addend;
}
// The remaining relocations.
Add(G.size() - 1);
Add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG |
RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela);
Add(Config->Wordsize);
Add(Target->RelativeRel);
if (Config->IsRela) {
for (auto I = G.begin() + 1, E = G.end(); I != E; ++I) {
Add(I->r_addend - Addend);
Addend = I->r_addend;
}
}
Offset = G.back().r_offset;
}
// Now the ungrouped relatives.
if (!UngroupedRelatives.empty()) {
Add(UngroupedRelatives.size());
Add(RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela);
Add(Target->RelativeRel);
for (Elf_Rela &R : UngroupedRelatives) {
Add(R.r_offset - Offset);
Offset = R.r_offset;
if (Config->IsRela) {
Add(R.r_addend - Addend);
Addend = R.r_addend;
}
}
}
// Finally the non-relative relocations.
llvm::sort(NonRelatives, [](const Elf_Rela &A, const Elf_Rela &B) {
return A.r_offset < B.r_offset;
});
if (!NonRelatives.empty()) {
Add(NonRelatives.size());
Add(HasAddendIfRela);
for (Elf_Rela &R : NonRelatives) {
Add(R.r_offset - Offset);
Offset = R.r_offset;
Add(R.r_info);
if (Config->IsRela) {
Add(R.r_addend - Addend);
Addend = R.r_addend;
}
}
}
// Don't allow the section to shrink; otherwise the size of the section can
// oscillate infinitely.
if (RelocData.size() < OldSize)
RelocData.append(OldSize - RelocData.size(), 0);
// Returns whether the section size changed. We need to keep recomputing both
// section layout and the contents of this section until the size converges
// because changing this section's size can affect section layout, which in
// turn can affect the sizes of the LEB-encoded integers stored in this
// section.
return RelocData.size() != OldSize;
}
template <class ELFT> RelrSection<ELFT>::RelrSection() {
this->Entsize = Config->Wordsize;
}
template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() {
// This function computes the contents of an SHT_RELR packed relocation
// section.
//
// Proposal for adding SHT_RELR sections to generic-abi is here:
// https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
//
// The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks
// like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
//
// i.e. start with an address, followed by any number of bitmaps. The address
// entry encodes 1 relocation. The subsequent bitmap entries encode up to 63
// relocations each, at subsequent offsets following the last address entry.
//
// The bitmap entries must have 1 in the least significant bit. The assumption
// here is that an address cannot have 1 in lsb. Odd addresses are not
// supported.
//
// Excluding the least significant bit in the bitmap, each non-zero bit in
// the bitmap represents a relocation to be applied to a corresponding machine
// word that follows the base address word. The second least significant bit
// represents the machine word immediately following the initial address, and
// each bit that follows represents the next word, in linear order. As such,
// a single bitmap can encode up to 31 relocations in a 32-bit object, and
// 63 relocations in a 64-bit object.
//
// This encoding has a couple of interesting properties:
// 1. Looking at any entry, it is clear whether it's an address or a bitmap:
// even means address, odd means bitmap.
// 2. Just a simple list of addresses is a valid encoding.
size_t OldSize = RelrRelocs.size();
RelrRelocs.clear();
// Same as Config->Wordsize but faster because this is a compile-time
// constant.
const size_t Wordsize = sizeof(typename ELFT::uint);
// Number of bits to use for the relocation offsets bitmap.
// Must be either 63 or 31.
const size_t NBits = Wordsize * 8 - 1;
// Get offsets for all relative relocations and sort them.
std::vector<uint64_t> Offsets;
for (const RelativeReloc &Rel : Relocs)
Offsets.push_back(Rel.getOffset());
llvm::sort(Offsets.begin(), Offsets.end());
// For each leading relocation, find following ones that can be folded
// as a bitmap and fold them.
for (size_t I = 0, E = Offsets.size(); I < E;) {
// Add a leading relocation.
RelrRelocs.push_back(Elf_Relr(Offsets[I]));
uint64_t Base = Offsets[I] + Wordsize;
++I;
// Find foldable relocations to construct bitmaps.
while (I < E) {
uint64_t Bitmap = 0;
while (I < E) {
uint64_t Delta = Offsets[I] - Base;
// If it is too far, it cannot be folded.
if (Delta >= NBits * Wordsize)
break;
// If it is not a multiple of wordsize away, it cannot be folded.
if (Delta % Wordsize)
break;
// Fold it.
Bitmap |= 1ULL << (Delta / Wordsize);
++I;
}
if (!Bitmap)
break;
RelrRelocs.push_back(Elf_Relr((Bitmap << 1) | 1));
Base += NBits * Wordsize;
}
}
return RelrRelocs.size() != OldSize;
}
SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
: SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0,
StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
Config->Wordsize,
StrTabSec.isDynamic() ? ".dynsym" : ".symtab"),
StrTabSec(StrTabSec) {}
// Orders symbols according to their positions in the GOT,
// in compliance with MIPS ABI rules.
// See "Global Offset Table" in Chapter 5 in the following document
// for detailed description:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
static bool sortMipsSymbols(const SymbolTableEntry &L,
const SymbolTableEntry &R) {
// Sort entries related to non-local preemptible symbols by GOT indexes.
// All other entries go to the beginning of a dynsym in arbitrary order.
if (L.Sym->isInGot() && R.Sym->isInGot())
return L.Sym->GotIndex < R.Sym->GotIndex;
if (!L.Sym->isInGot() && !R.Sym->isInGot())
return false;
return !L.Sym->isInGot();
}
void SymbolTableBaseSection::finalizeContents() {
if (OutputSection *Sec = StrTabSec.getParent())
getParent()->Link = Sec->SectionIndex;
if (this->Type != SHT_DYNSYM) {
sortSymTabSymbols();
return;
}
// If it is a .dynsym, there should be no local symbols, but we need
// to do a few things for the dynamic linker.
// Section's Info field has the index of the first non-local symbol.
// Because the first symbol entry is a null entry, 1 is the first.
getParent()->Info = 1;
if (In.GnuHashTab) {
// NB: It also sorts Symbols to meet the GNU hash table requirements.
In.GnuHashTab->addSymbols(Symbols);
} else if (Config->EMachine == EM_MIPS) {
std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
}
size_t I = 0;
for (const SymbolTableEntry &S : Symbols)
S.Sym->DynsymIndex = ++I;
}
// The ELF spec requires that all local symbols precede global symbols, so we
// sort symbol entries in this function. (For .dynsym, we don't do that because
// symbols for dynamic linking are inherently all globals.)
//
// Aside from above, we put local symbols in groups starting with the STT_FILE
// symbol. That is convenient for purpose of identifying where are local symbols
// coming from.
void SymbolTableBaseSection::sortSymTabSymbols() {
// Move all local symbols before global symbols.
auto E = std::stable_partition(
Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL;
});
size_t NumLocals = E - Symbols.begin();
getParent()->Info = NumLocals + 1;
// We want to group the local symbols by file. For that we rebuild the local
// part of the symbols vector. We do not need to care about the STT_FILE
// symbols, they are already naturally placed first in each group. That
// happens because STT_FILE is always the first symbol in the object and hence
// precede all other local symbols we add for a file.
MapVector<InputFile *, std::vector<SymbolTableEntry>> Arr;
for (const SymbolTableEntry &S : llvm::make_range(Symbols.begin(), E))
Arr[S.Sym->File].push_back(S);
auto I = Symbols.begin();
for (std::pair<InputFile *, std::vector<SymbolTableEntry>> &P : Arr)
for (SymbolTableEntry &Entry : P.second)
*I++ = Entry;
}
void SymbolTableBaseSection::addSymbol(Symbol *B) {
// Adding a local symbol to a .dynsym is a bug.
assert(this->Type != SHT_DYNSYM || !B->isLocal());
bool HashIt = B->isLocal();
Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)});
}
size_t SymbolTableBaseSection::getSymbolIndex(Symbol *Sym) {
// Initializes symbol lookup tables lazily. This is used only
// for -r or -emit-relocs.
llvm::call_once(OnceFlag, [&] {
SymbolIndexMap.reserve(Symbols.size());
size_t I = 0;
for (const SymbolTableEntry &E : Symbols) {
if (E.Sym->Type == STT_SECTION)
SectionIndexMap[E.Sym->getOutputSection()] = ++I;
else
SymbolIndexMap[E.Sym] = ++I;
}
});
// Section symbols are mapped based on their output sections
// to maintain their semantics.
if (Sym->Type == STT_SECTION)
return SectionIndexMap.lookup(Sym->getOutputSection());
return SymbolIndexMap.lookup(Sym);
}
template <class ELFT>
SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec)
: SymbolTableBaseSection(StrTabSec) {
this->Entsize = sizeof(Elf_Sym);
}
static BssSection *getCommonSec(Symbol *Sym) {
if (!Config->DefineCommon)
if (auto *D = dyn_cast<Defined>(Sym))
return dyn_cast_or_null<BssSection>(D->Section);
return nullptr;
}
static uint32_t getSymSectionIndex(Symbol *Sym) {
if (getCommonSec(Sym))
return SHN_COMMON;
if (!isa<Defined>(Sym) || Sym->NeedsPltAddr)
return SHN_UNDEF;
if (const OutputSection *OS = Sym->getOutputSection())
return OS->SectionIndex >= SHN_LORESERVE ? (uint32_t)SHN_XINDEX
: OS->SectionIndex;
return SHN_ABS;
}
// Write the internal symbol table contents to the output symbol table.
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
// The first entry is a null entry as per the ELF spec.
memset(Buf, 0, sizeof(Elf_Sym));
Buf += sizeof(Elf_Sym);
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
for (SymbolTableEntry &Ent : Symbols) {
Symbol *Sym = Ent.Sym;
// Set st_info and st_other.
ESym->st_other = 0;
if (Sym->isLocal()) {
ESym->setBindingAndType(STB_LOCAL, Sym->Type);
} else {
ESym->setBindingAndType(Sym->computeBinding(), Sym->Type);
ESym->setVisibility(Sym->Visibility);
}
+ // The 3 most significant bits of st_other are used by OpenPOWER ABI.
+ // See getPPC64GlobalEntryToLocalEntryOffset() for more details.
+ if (Config->EMachine == EM_PPC64)
+ ESym->st_other |= Sym->StOther & 0xe0;
+
ESym->st_name = Ent.StrTabOffset;
ESym->st_shndx = getSymSectionIndex(Ent.Sym);
// Copy symbol size if it is a defined symbol. st_size is not significant
// for undefined symbols, so whether copying it or not is up to us if that's
// the case. We'll leave it as zero because by not setting a value, we can
// get the exact same outputs for two sets of input files that differ only
// in undefined symbol size in DSOs.
if (ESym->st_shndx == SHN_UNDEF)
ESym->st_size = 0;
else
ESym->st_size = Sym->getSize();
// st_value is usually an address of a symbol, but that has a
// special meaining for uninstantiated common symbols (this can
// occur if -r is given).
if (BssSection *CommonSec = getCommonSec(Ent.Sym))
ESym->st_value = CommonSec->Alignment;
else
ESym->st_value = Sym->getVA();
++ESym;
}
// On MIPS we need to mark symbol which has a PLT entry and requires
// pointer equality by STO_MIPS_PLT flag. That is necessary to help
// dynamic linker distinguish such symbols and MIPS lazy-binding stubs.
// https://sourceware.org/ml/binutils/2008-07/txt00000.txt
if (Config->EMachine == EM_MIPS) {
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
for (SymbolTableEntry &Ent : Symbols) {
Symbol *Sym = Ent.Sym;
if (Sym->isInPlt() && Sym->NeedsPltAddr)
ESym->st_other |= STO_MIPS_PLT;
if (isMicroMips()) {
// Set STO_MIPS_MICROMIPS flag and less-significant bit for
// a defined microMIPS symbol and symbol should point to its
// PLT entry (in case of microMIPS, PLT entries always contain
// microMIPS code).
if (Sym->isDefined() &&
((Sym->StOther & STO_MIPS_MICROMIPS) || Sym->NeedsPltAddr)) {
if (StrTabSec.isDynamic())
ESym->st_value |= 1;
ESym->st_other |= STO_MIPS_MICROMIPS;
}
}
if (Config->Relocatable)
if (auto *D = dyn_cast<Defined>(Sym))
if (isMipsPIC<ELFT>(D))
ESym->st_other |= STO_MIPS_PIC;
++ESym;
}
}
}
SymtabShndxSection::SymtabShndxSection()
: SyntheticSection(0, SHT_SYMTAB_SHNDX, 4, ".symtab_shndxr") {
this->Entsize = 4;
}
void SymtabShndxSection::writeTo(uint8_t *Buf) {
// We write an array of 32 bit values, where each value has 1:1 association
// with an entry in .symtab. If the corresponding entry contains SHN_XINDEX,
// we need to write actual index, otherwise, we must write SHN_UNDEF(0).
Buf += 4; // Ignore .symtab[0] entry.
for (const SymbolTableEntry &Entry : In.SymTab->getSymbols()) {
if (getSymSectionIndex(Entry.Sym) == SHN_XINDEX)
write32(Buf, Entry.Sym->getOutputSection()->SectionIndex);
Buf += 4;
}
}
bool SymtabShndxSection::empty() const {
// SHT_SYMTAB can hold symbols with section indices values up to
// SHN_LORESERVE. If we need more, we want to use extension SHT_SYMTAB_SHNDX
// section. Problem is that we reveal the final section indices a bit too
// late, and we do not know them here. For simplicity, we just always create
// a .symtab_shndxr section when the amount of output sections is huge.
size_t Size = 0;
for (BaseCommand *Base : Script->SectionCommands)
if (isa<OutputSection>(Base))
++Size;
return Size < SHN_LORESERVE;
}
void SymtabShndxSection::finalizeContents() {
getParent()->Link = In.SymTab->getParent()->SectionIndex;
}
size_t SymtabShndxSection::getSize() const {
return In.SymTab->getNumSymbols() * 4;
}
// .hash and .gnu.hash sections contain on-disk hash tables that map
// symbol names to their dynamic symbol table indices. Their purpose
// is to help the dynamic linker resolve symbols quickly. If ELF files
// don't have them, the dynamic linker has to do linear search on all
// dynamic symbols, which makes programs slower. Therefore, a .hash
// section is added to a DSO by default. A .gnu.hash is added if you
// give the -hash-style=gnu or -hash-style=both option.
//
// The Unix semantics of resolving dynamic symbols is somewhat expensive.
// Each ELF file has a list of DSOs that the ELF file depends on and a
// list of dynamic symbols that need to be resolved from any of the
// DSOs. That means resolving all dynamic symbols takes O(m)*O(n)
// where m is the number of DSOs and n is the number of dynamic
// symbols. For modern large programs, both m and n are large. So
// making each step faster by using hash tables substiantially
// improves time to load programs.
//
// (Note that this is not the only way to design the shared library.
// For instance, the Windows DLL takes a different approach. On
// Windows, each dynamic symbol has a name of DLL from which the symbol
// has to be resolved. That makes the cost of symbol resolution O(n).
// This disables some hacky techniques you can use on Unix such as
// LD_PRELOAD, but this is arguably better semantics than the Unix ones.)
//
// Due to historical reasons, we have two different hash tables, .hash
// and .gnu.hash. They are for the same purpose, and .gnu.hash is a new
// and better version of .hash. .hash is just an on-disk hash table, but
// .gnu.hash has a bloom filter in addition to a hash table to skip
// DSOs very quickly. If you are sure that your dynamic linker knows
// about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a
// safe bet is to specify -hash-style=both for backward compatibilty.
GnuHashTableSection::GnuHashTableSection()
: SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") {
}
void GnuHashTableSection::finalizeContents() {
if (OutputSection *Sec = In.DynSymTab->getParent())
getParent()->Link = Sec->SectionIndex;
// Computes bloom filter size in word size. We want to allocate 12
// bits for each symbol. It must be a power of two.
if (Symbols.empty()) {
MaskWords = 1;
} else {
uint64_t NumBits = Symbols.size() * 12;
MaskWords = NextPowerOf2(NumBits / (Config->Wordsize * 8));
}
Size = 16; // Header
Size += Config->Wordsize * MaskWords; // Bloom filter
Size += NBuckets * 4; // Hash buckets
Size += Symbols.size() * 4; // Hash values
}
void GnuHashTableSection::writeTo(uint8_t *Buf) {
// The output buffer is not guaranteed to be zero-cleared because we pre-
// fill executable sections with trap instructions. This is a precaution
// for that case, which happens only when -no-rosegment is given.
memset(Buf, 0, Size);
// Write a header.
write32(Buf, NBuckets);
write32(Buf + 4, In.DynSymTab->getNumSymbols() - Symbols.size());
write32(Buf + 8, MaskWords);
write32(Buf + 12, Shift2);
Buf += 16;
// Write a bloom filter and a hash table.
writeBloomFilter(Buf);
Buf += Config->Wordsize * MaskWords;
writeHashTable(Buf);
}
// This function writes a 2-bit bloom filter. This bloom filter alone
// usually filters out 80% or more of all symbol lookups [1].
// The dynamic linker uses the hash table only when a symbol is not
// filtered out by a bloom filter.
//
// [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2),
// p.9, https://www.akkadia.org/drepper/dsohowto.pdf
void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) {
unsigned C = Config->Is64 ? 64 : 32;
for (const Entry &Sym : Symbols) {
// When C = 64, we choose a word with bits [6:...] and set 1 to two bits in
// the word using bits [0:5] and [26:31].
size_t I = (Sym.Hash / C) & (MaskWords - 1);
uint64_t Val = readUint(Buf + I * Config->Wordsize);
Val |= uint64_t(1) << (Sym.Hash % C);
Val |= uint64_t(1) << ((Sym.Hash >> Shift2) % C);
writeUint(Buf + I * Config->Wordsize, Val);
}
}
void GnuHashTableSection::writeHashTable(uint8_t *Buf) {
uint32_t *Buckets = reinterpret_cast<uint32_t *>(Buf);
uint32_t OldBucket = -1;
uint32_t *Values = Buckets + NBuckets;
for (auto I = Symbols.begin(), E = Symbols.end(); I != E; ++I) {
// Write a hash value. It represents a sequence of chains that share the
// same hash modulo value. The last element of each chain is terminated by
// LSB 1.
uint32_t Hash = I->Hash;
bool IsLastInChain = (I + 1) == E || I->BucketIdx != (I + 1)->BucketIdx;
Hash = IsLastInChain ? Hash | 1 : Hash & ~1;
write32(Values++, Hash);
if (I->BucketIdx == OldBucket)
continue;
// Write a hash bucket. Hash buckets contain indices in the following hash
// value table.
write32(Buckets + I->BucketIdx, I->Sym->DynsymIndex);
OldBucket = I->BucketIdx;
}
}
static uint32_t hashGnu(StringRef Name) {
uint32_t H = 5381;
for (uint8_t C : Name)
H = (H << 5) + H + C;
return H;
}
// Add symbols to this symbol hash table. Note that this function
// destructively sort a given vector -- which is needed because
// GNU-style hash table places some sorting requirements.
void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) {
// We cannot use 'auto' for Mid because GCC 6.1 cannot deduce
// its type correctly.
std::vector<SymbolTableEntry>::iterator Mid =
std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) {
return !S.Sym->isDefined();
});
// We chose load factor 4 for the on-disk hash table. For each hash
// collision, the dynamic linker will compare a uint32_t hash value.
// Since the integer comparison is quite fast, we believe we can
// make the load factor even larger. 4 is just a conservative choice.
//
// Note that we don't want to create a zero-sized hash table because
// Android loader as of 2018 doesn't like a .gnu.hash containing such
// table. If that's the case, we create a hash table with one unused
// dummy slot.
NBuckets = std::max<size_t>((V.end() - Mid) / 4, 1);
if (Mid == V.end())
return;
for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) {
Symbol *B = Ent.Sym;
uint32_t Hash = hashGnu(B->getName());
uint32_t BucketIdx = Hash % NBuckets;
Symbols.push_back({B, Ent.StrTabOffset, Hash, BucketIdx});
}
std::stable_sort(
Symbols.begin(), Symbols.end(),
[](const Entry &L, const Entry &R) { return L.BucketIdx < R.BucketIdx; });
V.erase(Mid, V.end());
for (const Entry &Ent : Symbols)
V.push_back({Ent.Sym, Ent.StrTabOffset});
}
HashTableSection::HashTableSection()
: SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") {
this->Entsize = 4;
}
void HashTableSection::finalizeContents() {
if (OutputSection *Sec = In.DynSymTab->getParent())
getParent()->Link = Sec->SectionIndex;
unsigned NumEntries = 2; // nbucket and nchain.
NumEntries += In.DynSymTab->getNumSymbols(); // The chain entries.
// Create as many buckets as there are symbols.
NumEntries += In.DynSymTab->getNumSymbols();
this->Size = NumEntries * 4;
}
void HashTableSection::writeTo(uint8_t *Buf) {
// See comment in GnuHashTableSection::writeTo.
memset(Buf, 0, Size);
unsigned NumSymbols = In.DynSymTab->getNumSymbols();
uint32_t *P = reinterpret_cast<uint32_t *>(Buf);
write32(P++, NumSymbols); // nbucket
write32(P++, NumSymbols); // nchain
uint32_t *Buckets = P;
uint32_t *Chains = P + NumSymbols;
for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) {
Symbol *Sym = S.Sym;
StringRef Name = Sym->getName();
unsigned I = Sym->DynsymIndex;
uint32_t Hash = hashSysV(Name) % NumSymbols;
Chains[I] = Buckets[Hash];
write32(Buckets + Hash, I);
}
}
// On PowerPC64 the lazy symbol resolvers go into the `global linkage table`
// in the .glink section, rather then the typical .plt section.
PltSection::PltSection(bool IsIplt)
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
Config->EMachine == EM_PPC64 ? ".glink" : ".plt"),
HeaderSize(!IsIplt || Config->ZRetpolineplt ? Target->PltHeaderSize : 0),
IsIplt(IsIplt) {
// The PLT needs to be writable on SPARC as the dynamic linker will
// modify the instructions in the PLT entries.
if (Config->EMachine == EM_SPARCV9)
this->Flags |= SHF_WRITE;
}
void PltSection::writeTo(uint8_t *Buf) {
// At beginning of PLT or retpoline IPLT, we have code to call the dynamic
// linker to resolve dynsyms at runtime. Write such code.
if (HeaderSize > 0)
Target->writePltHeader(Buf);
size_t Off = HeaderSize;
// The IPlt is immediately after the Plt, account for this in RelOff
unsigned PltOff = getPltRelocOff();
for (auto &I : Entries) {
const Symbol *B = I.first;
unsigned RelOff = I.second + PltOff;
uint64_t Got = B->getGotPltVA();
uint64_t Plt = this->getVA() + Off;
Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
Off += Target->PltEntrySize;
}
}
template <class ELFT> void PltSection::addEntry(Symbol &Sym) {
Sym.PltIndex = Entries.size();
RelocationBaseSection *PltRelocSection = In.RelaPlt;
if (IsIplt) {
PltRelocSection = In.RelaIplt;
Sym.IsInIplt = true;
}
unsigned RelOff =
static_cast<RelocationSection<ELFT> *>(PltRelocSection)->getRelocOffset();
Entries.push_back(std::make_pair(&Sym, RelOff));
}
size_t PltSection::getSize() const {
return HeaderSize + Entries.size() * Target->PltEntrySize;
}
// Some architectures such as additional symbols in the PLT section. For
// example ARM uses mapping symbols to aid disassembly
void PltSection::addSymbols() {
// The PLT may have symbols defined for the Header, the IPLT has no header
if (!IsIplt)
Target->addPltHeaderSymbols(*this);
size_t Off = HeaderSize;
for (size_t I = 0; I < Entries.size(); ++I) {
Target->addPltSymbols(*this, Off);
Off += Target->PltEntrySize;
}
}
unsigned PltSection::getPltRelocOff() const {
return IsIplt ? In.Plt->getSize() : 0;
}
// The string hash function for .gdb_index.
static uint32_t computeGdbHash(StringRef S) {
uint32_t H = 0;
for (uint8_t C : S)
H = H * 67 + toLower(C) - 113;
return H;
}
GdbIndexSection::GdbIndexSection()
: SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index") {}
// Returns the desired size of an on-disk hash table for a .gdb_index section.
// There's a tradeoff between size and collision rate. We aim 75% utilization.
size_t GdbIndexSection::computeSymtabSize() const {
return std::max<size_t>(NextPowerOf2(Symbols.size() * 4 / 3), 1024);
}
// Compute the output section size.
void GdbIndexSection::initOutputSize() {
Size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8;
for (GdbChunk &Chunk : Chunks)
Size += Chunk.CompilationUnits.size() * 16 + Chunk.AddressAreas.size() * 20;
// Add the constant pool size if exists.
if (!Symbols.empty()) {
GdbSymbol &Sym = Symbols.back();
Size += Sym.NameOff + Sym.Name.size() + 1;
}
}
static std::vector<InputSection *> getDebugInfoSections() {
std::vector<InputSection *> Ret;
for (InputSectionBase *S : InputSections)
if (InputSection *IS = dyn_cast<InputSection>(S))
if (IS->Name == ".debug_info")
Ret.push_back(IS);
return Ret;
}
static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &Dwarf) {
std::vector<GdbIndexSection::CuEntry> Ret;
for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units())
Ret.push_back({Cu->getOffset(), Cu->getLength() + 4});
return Ret;
}
static std::vector<GdbIndexSection::AddressEntry>
readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
std::vector<GdbIndexSection::AddressEntry> Ret;
uint32_t CuIdx = 0;
for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units()) {
Expected<DWARFAddressRangesVector> Ranges = Cu->collectAddressRanges();
if (!Ranges) {
error(toString(Sec) + ": " + toString(Ranges.takeError()));
return {};
}
ArrayRef<InputSectionBase *> Sections = Sec->File->getSections();
for (DWARFAddressRange &R : *Ranges) {
InputSectionBase *S = Sections[R.SectionIndex];
if (!S || S == &InputSection::Discarded || !S->Live)
continue;
// Range list with zero size has no effect.
if (R.LowPC == R.HighPC)
continue;
auto *IS = cast<InputSection>(S);
uint64_t Offset = IS->getOffsetInFile();
Ret.push_back({IS, R.LowPC - Offset, R.HighPC - Offset, CuIdx});
}
++CuIdx;
}
return Ret;
}
template <class ELFT>
static std::vector<GdbIndexSection::NameAttrEntry>
readPubNamesAndTypes(const LLDDwarfObj<ELFT> &Obj,
const std::vector<GdbIndexSection::CuEntry> &CUs) {
const DWARFSection &PubNames = Obj.getGnuPubNamesSection();
const DWARFSection &PubTypes = Obj.getGnuPubTypesSection();
std::vector<GdbIndexSection::NameAttrEntry> Ret;
for (const DWARFSection *Pub : {&PubNames, &PubTypes}) {
DWARFDebugPubTable Table(Obj, *Pub, Config->IsLE, true);
for (const DWARFDebugPubTable::Set &Set : Table.getData()) {
// The value written into the constant pool is Kind << 24 | CuIndex. As we
// don't know how many compilation units precede this object to compute
// CuIndex, we compute (Kind << 24 | CuIndexInThisObject) instead, and add
// the number of preceding compilation units later.
uint32_t I =
lower_bound(CUs, Set.Offset,
[](GdbIndexSection::CuEntry CU, uint32_t Offset) {
return CU.CuOffset < Offset;
}) -
CUs.begin();
for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)},
(Ent.Descriptor.toBits() << 24) | I});
}
}
return Ret;
}
// Create a list of symbols from a given list of symbol names and types
// by uniquifying them by name.
static std::vector<GdbIndexSection::GdbSymbol>
createSymbols(ArrayRef<std::vector<GdbIndexSection::NameAttrEntry>> NameAttrs,
const std::vector<GdbIndexSection::GdbChunk> &Chunks) {
typedef GdbIndexSection::GdbSymbol GdbSymbol;
typedef GdbIndexSection::NameAttrEntry NameAttrEntry;
// For each chunk, compute the number of compilation units preceding it.
uint32_t CuIdx = 0;
std::vector<uint32_t> CuIdxs(Chunks.size());
for (uint32_t I = 0, E = Chunks.size(); I != E; ++I) {
CuIdxs[I] = CuIdx;
CuIdx += Chunks[I].CompilationUnits.size();
}
// The number of symbols we will handle in this function is of the order
// of millions for very large executables, so we use multi-threading to
// speed it up.
size_t NumShards = 32;
size_t Concurrency = 1;
if (ThreadsEnabled)
Concurrency =
std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards);
// A sharded map to uniquify symbols by name.
std::vector<DenseMap<CachedHashStringRef, size_t>> Map(NumShards);
size_t Shift = 32 - countTrailingZeros(NumShards);
// Instantiate GdbSymbols while uniqufying them by name.
std::vector<std::vector<GdbSymbol>> Symbols(NumShards);
parallelForEachN(0, Concurrency, [&](size_t ThreadId) {
uint32_t I = 0;
for (ArrayRef<NameAttrEntry> Entries : NameAttrs) {
for (const NameAttrEntry &Ent : Entries) {
size_t ShardId = Ent.Name.hash() >> Shift;
if ((ShardId & (Concurrency - 1)) != ThreadId)
continue;
uint32_t V = Ent.CuIndexAndAttrs + CuIdxs[I];
size_t &Idx = Map[ShardId][Ent.Name];
if (Idx) {
Symbols[ShardId][Idx - 1].CuVector.push_back(V);
continue;
}
Idx = Symbols[ShardId].size() + 1;
Symbols[ShardId].push_back({Ent.Name, {V}, 0, 0});
}
++I;
}
});
size_t NumSymbols = 0;
for (ArrayRef<GdbSymbol> V : Symbols)
NumSymbols += V.size();
// The return type is a flattened vector, so we'll copy each vector
// contents to Ret.
std::vector<GdbSymbol> Ret;
Ret.reserve(NumSymbols);
for (std::vector<GdbSymbol> &Vec : Symbols)
for (GdbSymbol &Sym : Vec)
Ret.push_back(std::move(Sym));
// CU vectors and symbol names are adjacent in the output file.
// We can compute their offsets in the output file now.
size_t Off = 0;
for (GdbSymbol &Sym : Ret) {
Sym.CuVectorOff = Off;
Off += (Sym.CuVector.size() + 1) * 4;
}
for (GdbSymbol &Sym : Ret) {
Sym.NameOff = Off;
Off += Sym.Name.size() + 1;
}
return Ret;
}
// Returns a newly-created .gdb_index section.
template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
std::vector<InputSection *> Sections = getDebugInfoSections();
// .debug_gnu_pub{names,types} are useless in executables.
// They are present in input object files solely for creating
// a .gdb_index. So we can remove them from the output.
for (InputSectionBase *S : InputSections)
if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes")
S->Live = false;
std::vector<GdbChunk> Chunks(Sections.size());
std::vector<std::vector<NameAttrEntry>> NameAttrs(Sections.size());
parallelForEachN(0, Sections.size(), [&](size_t I) {
ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>();
DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File));
Chunks[I].Sec = Sections[I];
Chunks[I].CompilationUnits = readCuList(Dwarf);
Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]);
NameAttrs[I] = readPubNamesAndTypes<ELFT>(
static_cast<const LLDDwarfObj<ELFT> &>(Dwarf.getDWARFObj()),
Chunks[I].CompilationUnits);
});
auto *Ret = make<GdbIndexSection>();
Ret->Chunks = std::move(Chunks);
Ret->Symbols = createSymbols(NameAttrs, Ret->Chunks);
Ret->initOutputSize();
return Ret;
}
void GdbIndexSection::writeTo(uint8_t *Buf) {
// Write the header.
auto *Hdr = reinterpret_cast<GdbIndexHeader *>(Buf);
uint8_t *Start = Buf;
Hdr->Version = 7;
Buf += sizeof(*Hdr);
// Write the CU list.
Hdr->CuListOff = Buf - Start;
for (GdbChunk &Chunk : Chunks) {
for (CuEntry &Cu : Chunk.CompilationUnits) {
write64le(Buf, Chunk.Sec->OutSecOff + Cu.CuOffset);
write64le(Buf + 8, Cu.CuLength);
Buf += 16;
}
}
// Write the address area.
Hdr->CuTypesOff = Buf - Start;
Hdr->AddressAreaOff = Buf - Start;
uint32_t CuOff = 0;
for (GdbChunk &Chunk : Chunks) {
for (AddressEntry &E : Chunk.AddressAreas) {
uint64_t BaseAddr = E.Section->getVA(0);
write64le(Buf, BaseAddr + E.LowAddress);
write64le(Buf + 8, BaseAddr + E.HighAddress);
write32le(Buf + 16, E.CuIndex + CuOff);
Buf += 20;
}
CuOff += Chunk.CompilationUnits.size();
}
// Write the on-disk open-addressing hash table containing symbols.
Hdr->SymtabOff = Buf - Start;
size_t SymtabSize = computeSymtabSize();
uint32_t Mask = SymtabSize - 1;
for (GdbSymbol &Sym : Symbols) {
uint32_t H = Sym.Name.hash();
uint32_t I = H & Mask;
uint32_t Step = ((H * 17) & Mask) | 1;
while (read32le(Buf + I * 8))
I = (I + Step) & Mask;
write32le(Buf + I * 8, Sym.NameOff);
write32le(Buf + I * 8 + 4, Sym.CuVectorOff);
}
Buf += SymtabSize * 8;
// Write the string pool.
Hdr->ConstantPoolOff = Buf - Start;
parallelForEach(Symbols, [&](GdbSymbol &Sym) {
memcpy(Buf + Sym.NameOff, Sym.Name.data(), Sym.Name.size());
});
// Write the CU vectors.
for (GdbSymbol &Sym : Symbols) {
write32le(Buf, Sym.CuVector.size());
Buf += 4;
for (uint32_t Val : Sym.CuVector) {
write32le(Buf, Val);
Buf += 4;
}
}
}
bool GdbIndexSection::empty() const { return Chunks.empty(); }
EhFrameHeader::EhFrameHeader()
: SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {}
// .eh_frame_hdr contains a binary search table of pointers to FDEs.
// Each entry of the search table consists of two values,
// the starting PC from where FDEs covers, and the FDE's address.
// It is sorted by PC.
void EhFrameHeader::writeTo(uint8_t *Buf) {
typedef EhFrameSection::FdeData FdeData;
std::vector<FdeData> Fdes = In.EhFrame->getFdeData();
Buf[0] = 1;
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
Buf[2] = DW_EH_PE_udata4;
Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
write32(Buf + 4, In.EhFrame->getParent()->Addr - this->getVA() - 4);
write32(Buf + 8, Fdes.size());
Buf += 12;
for (FdeData &Fde : Fdes) {
write32(Buf, Fde.PcRel);
write32(Buf + 4, Fde.FdeVARel);
Buf += 8;
}
}
size_t EhFrameHeader::getSize() const {
// .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
return 12 + In.EhFrame->NumFdes * 8;
}
bool EhFrameHeader::empty() const { return In.EhFrame->empty(); }
VersionDefinitionSection::VersionDefinitionSection()
: SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t),
".gnu.version_d") {}
static StringRef getFileDefName() {
if (!Config->SoName.empty())
return Config->SoName;
return Config->OutputFile;
}
void VersionDefinitionSection::finalizeContents() {
FileDefNameOff = In.DynStrTab->addString(getFileDefName());
for (VersionDefinition &V : Config->VersionDefinitions)
V.NameOff = In.DynStrTab->addString(V.Name);
if (OutputSection *Sec = In.DynStrTab->getParent())
getParent()->Link = Sec->SectionIndex;
// sh_info should be set to the number of definitions. This fact is missed in
// documentation, but confirmed by binutils community:
// https://sourceware.org/ml/binutils/2014-11/msg00355.html
getParent()->Info = getVerDefNum();
}
void VersionDefinitionSection::writeOne(uint8_t *Buf, uint32_t Index,
StringRef Name, size_t NameOff) {
uint16_t Flags = Index == 1 ? VER_FLG_BASE : 0;
// Write a verdef.
write16(Buf, 1); // vd_version
write16(Buf + 2, Flags); // vd_flags
write16(Buf + 4, Index); // vd_ndx
write16(Buf + 6, 1); // vd_cnt
write32(Buf + 8, hashSysV(Name)); // vd_hash
write32(Buf + 12, 20); // vd_aux
write32(Buf + 16, 28); // vd_next
// Write a veraux.
write32(Buf + 20, NameOff); // vda_name
write32(Buf + 24, 0); // vda_next
}
void VersionDefinitionSection::writeTo(uint8_t *Buf) {
writeOne(Buf, 1, getFileDefName(), FileDefNameOff);
for (VersionDefinition &V : Config->VersionDefinitions) {
Buf += EntrySize;
writeOne(Buf, V.Id, V.Name, V.NameOff);
}
// Need to terminate the last version definition.
write32(Buf + 16, 0); // vd_next
}
size_t VersionDefinitionSection::getSize() const {
return EntrySize * getVerDefNum();
}
// .gnu.version is a table where each entry is 2 byte long.
template <class ELFT>
VersionTableSection<ELFT>::VersionTableSection()
: SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t),
".gnu.version") {
this->Entsize = 2;
}
template <class ELFT> void VersionTableSection<ELFT>::finalizeContents() {
// At the moment of june 2016 GNU docs does not mention that sh_link field
// should be set, but Sun docs do. Also readelf relies on this field.
getParent()->Link = In.DynSymTab->getParent()->SectionIndex;
}
template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const {
return (In.DynSymTab->getSymbols().size() + 1) * 2;
}
template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
Buf += 2;
for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) {
write16(Buf, S.Sym->VersionId);
Buf += 2;
}
}
template <class ELFT> bool VersionTableSection<ELFT>::empty() const {
return !In.VerDef && InX<ELFT>::VerNeed->empty();
}
template <class ELFT>
VersionNeedSection<ELFT>::VersionNeedSection()
: SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t),
".gnu.version_r") {
// Identifiers in verneed section start at 2 because 0 and 1 are reserved
// for VER_NDX_LOCAL and VER_NDX_GLOBAL.
// First identifiers are reserved by verdef section if it exist.
NextIndex = getVerDefNum() + 1;
}
template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
auto &File = cast<SharedFile<ELFT>>(*SS->File);
if (SS->VerdefIndex == VER_NDX_GLOBAL) {
SS->VersionId = VER_NDX_GLOBAL;
return;
}
// If we don't already know that we need an Elf_Verneed for this DSO, prepare
// to create one by adding it to our needed list and creating a dynstr entry
// for the soname.
if (File.VerdefMap.empty())
Needed.push_back({&File, In.DynStrTab->addString(File.SoName)});
const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex];
typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver];
// If we don't already know that we need an Elf_Vernaux for this Elf_Verdef,
// prepare to create one by allocating a version identifier and creating a
// dynstr entry for the version name.
if (NV.Index == 0) {
NV.StrTab = In.DynStrTab->addString(File.getStringTable().data() +
Ver->getAux()->vda_name);
NV.Index = NextIndex++;
}
SS->VersionId = NV.Index;
}
template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
// The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs.
auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf);
auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Needed.size());
for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) {
// Create an Elf_Verneed for this DSO.
Verneed->vn_version = 1;
Verneed->vn_cnt = P.first->VerdefMap.size();
Verneed->vn_file = P.second;
Verneed->vn_aux =
reinterpret_cast<char *>(Vernaux) - reinterpret_cast<char *>(Verneed);
Verneed->vn_next = sizeof(Elf_Verneed);
++Verneed;
// Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over
// VerdefMap, which will only contain references to needed version
// definitions. Each Elf_Vernaux is based on the information contained in
// the Elf_Verdef in the source DSO. This loop iterates over a std::map of
// pointers, but is deterministic because the pointers refer to Elf_Verdef
// data structures within a single input file.
for (auto &NV : P.first->VerdefMap) {
Vernaux->vna_hash = NV.first->vd_hash;
Vernaux->vna_flags = 0;
Vernaux->vna_other = NV.second.Index;
Vernaux->vna_name = NV.second.StrTab;
Vernaux->vna_next = sizeof(Elf_Vernaux);
++Vernaux;
}
Vernaux[-1].vna_next = 0;
}
Verneed[-1].vn_next = 0;
}
template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
if (OutputSection *Sec = In.DynStrTab->getParent())
getParent()->Link = Sec->SectionIndex;
getParent()->Info = Needed.size();
}
template <class ELFT> size_t VersionNeedSection<ELFT>::getSize() const {
unsigned Size = Needed.size() * sizeof(Elf_Verneed);
for (const std::pair<SharedFile<ELFT> *, size_t> &P : Needed)
Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux);
return Size;
}
template <class ELFT> bool VersionNeedSection<ELFT>::empty() const {
return getNeedNum() == 0;
}
void MergeSyntheticSection::addSection(MergeInputSection *MS) {
MS->Parent = this;
Sections.push_back(MS);
}
MergeTailSection::MergeTailSection(StringRef Name, uint32_t Type,
uint64_t Flags, uint32_t Alignment)
: MergeSyntheticSection(Name, Type, Flags, Alignment),
Builder(StringTableBuilder::RAW, Alignment) {}
size_t MergeTailSection::getSize() const { return Builder.getSize(); }
void MergeTailSection::writeTo(uint8_t *Buf) { Builder.write(Buf); }
void MergeTailSection::finalizeContents() {
// Add all string pieces to the string table builder to create section
// contents.
for (MergeInputSection *Sec : Sections)
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
if (Sec->Pieces[I].Live)
Builder.add(Sec->getData(I));
// Fix the string table content. After this, the contents will never change.
Builder.finalize();
// finalize() fixed tail-optimized strings, so we can now get
// offsets of strings. Get an offset for each string and save it
// to a corresponding StringPiece for easy access.
for (MergeInputSection *Sec : Sections)
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
if (Sec->Pieces[I].Live)
Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
}
void MergeNoTailSection::writeTo(uint8_t *Buf) {
for (size_t I = 0; I < NumShards; ++I)
Shards[I].write(Buf + ShardOffsets[I]);
}
// This function is very hot (i.e. it can take several seconds to finish)
// because sometimes the number of inputs is in an order of magnitude of
// millions. So, we use multi-threading.
//
// For any strings S and T, we know S is not mergeable with T if S's hash
// value is different from T's. If that's the case, we can safely put S and
// T into different string builders without worrying about merge misses.
// We do it in parallel.
void MergeNoTailSection::finalizeContents() {
// Initializes string table builders.
for (size_t I = 0; I < NumShards; ++I)
Shards.emplace_back(StringTableBuilder::RAW, Alignment);
// Concurrency level. Must be a power of 2 to avoid expensive modulo
// operations in the following tight loop.
size_t Concurrency = 1;
if (ThreadsEnabled)
Concurrency =
std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards);
// Add section pieces to the builders.
parallelForEachN(0, Concurrency, [&](size_t ThreadId) {
for (MergeInputSection *Sec : Sections) {
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) {
size_t ShardId = getShardId(Sec->Pieces[I].Hash);
if ((ShardId & (Concurrency - 1)) == ThreadId && Sec->Pieces[I].Live)
Sec->Pieces[I].OutputOff = Shards[ShardId].add(Sec->getData(I));
}
}
});
// Compute an in-section offset for each shard.
size_t Off = 0;
for (size_t I = 0; I < NumShards; ++I) {
Shards[I].finalizeInOrder();
if (Shards[I].getSize() > 0)
Off = alignTo(Off, Alignment);
ShardOffsets[I] = Off;
Off += Shards[I].getSize();
}
Size = Off;
// So far, section pieces have offsets from beginning of shards, but
// we want offsets from beginning of the whole section. Fix them.
parallelForEach(Sections, [&](MergeInputSection *Sec) {
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
if (Sec->Pieces[I].Live)
Sec->Pieces[I].OutputOff +=
ShardOffsets[getShardId(Sec->Pieces[I].Hash)];
});
}
static MergeSyntheticSection *createMergeSynthetic(StringRef Name,
uint32_t Type,
uint64_t Flags,
uint32_t Alignment) {
bool ShouldTailMerge = (Flags & SHF_STRINGS) && Config->Optimize >= 2;
if (ShouldTailMerge)
return make<MergeTailSection>(Name, Type, Flags, Alignment);
return make<MergeNoTailSection>(Name, Type, Flags, Alignment);
}
template <class ELFT> void elf::splitSections() {
// splitIntoPieces needs to be called on each MergeInputSection
// before calling finalizeContents().
parallelForEach(InputSections, [](InputSectionBase *Sec) {
if (auto *S = dyn_cast<MergeInputSection>(Sec))
S->splitIntoPieces();
else if (auto *Eh = dyn_cast<EhInputSection>(Sec))
Eh->split<ELFT>();
});
}
// This function scans over the inputsections to create mergeable
// synthetic sections.
//
// It removes MergeInputSections from the input section array and adds
// new synthetic sections at the location of the first input section
// that it replaces. It then finalizes each synthetic section in order
// to compute an output offset for each piece of each input section.
void elf::mergeSections() {
std::vector<MergeSyntheticSection *> MergeSections;
for (InputSectionBase *&S : InputSections) {
MergeInputSection *MS = dyn_cast<MergeInputSection>(S);
if (!MS)
continue;
// We do not want to handle sections that are not alive, so just remove
// them instead of trying to merge.
if (!MS->Live) {
S = nullptr;
continue;
}
StringRef OutsecName = getOutputSectionName(MS);
uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);
auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
// While we could create a single synthetic section for two different
// values of Entsize, it is better to take Entsize into consideration.
//
// With a single synthetic section no two pieces with different Entsize
// could be equal, so we may as well have two sections.
//
// Using Entsize in here also allows us to propagate it to the synthetic
// section.
return Sec->Name == OutsecName && Sec->Flags == MS->Flags &&
Sec->Entsize == MS->Entsize && Sec->Alignment == Alignment;
});
if (I == MergeSections.end()) {
MergeSyntheticSection *Syn =
createMergeSynthetic(OutsecName, MS->Type, MS->Flags, Alignment);
MergeSections.push_back(Syn);
I = std::prev(MergeSections.end());
S = Syn;
Syn->Entsize = MS->Entsize;
} else {
S = nullptr;
}
(*I)->addSection(MS);
}
for (auto *MS : MergeSections)
MS->finalizeContents();
std::vector<InputSectionBase *> &V = InputSections;
V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
}
MipsRldMapSection::MipsRldMapSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize,
".rld_map") {}
ARMExidxSentinelSection::ARMExidxSentinelSection()
: SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX,
Config->Wordsize, ".ARM.exidx") {}
// Write a terminating sentinel entry to the end of the .ARM.exidx table.
// This section will have been sorted last in the .ARM.exidx table.
// This table entry will have the form:
// | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND |
// The sentinel must have the PREL31 value of an address higher than any
// address described by any other table entry.
void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
assert(Highest);
uint64_t S = Highest->getVA(Highest->getSize());
uint64_t P = getVA();
Target->relocateOne(Buf, R_ARM_PREL31, S - P);
write32le(Buf + 4, 1);
}
// The sentinel has to be removed if there are no other .ARM.exidx entries.
bool ARMExidxSentinelSection::empty() const {
for (InputSection *IS : getInputSections(getParent()))
if (!isa<ARMExidxSentinelSection>(IS))
return false;
return true;
}
bool ARMExidxSentinelSection::classof(const SectionBase *D) {
return D->kind() == InputSectionBase::Synthetic && D->Type == SHT_ARM_EXIDX;
}
ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
Config->Wordsize, ".text.thunk") {
this->Parent = OS;
this->OutSecOff = Off;
}
void ThunkSection::addThunk(Thunk *T) {
Thunks.push_back(T);
T->addSymbols(*this);
}
void ThunkSection::writeTo(uint8_t *Buf) {
for (Thunk *T : Thunks)
T->writeTo(Buf + T->Offset);
}
InputSection *ThunkSection::getTargetInputSection() const {
if (Thunks.empty())
return nullptr;
const Thunk *T = Thunks.front();
return T->getTargetInputSection();
}
bool ThunkSection::assignOffsets() {
uint64_t Off = 0;
for (Thunk *T : Thunks) {
Off = alignTo(Off, T->Alignment);
T->setOffset(Off);
uint32_t Size = T->size();
T->getThunkTargetSym()->Size = Size;
Off += Size;
}
bool Changed = Off != Size;
Size = Off;
return Changed;
}
// If linking position-dependent code then the table will store the addresses
// directly in the binary so the section has type SHT_PROGBITS. If linking
// position-independent code the section has type SHT_NOBITS since it will be
// allocated and filled in by the dynamic linker.
PPC64LongBranchTargetSection::PPC64LongBranchTargetSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE,
Config->Pic ? SHT_NOBITS : SHT_PROGBITS, 8,
".branch_lt") {}
void PPC64LongBranchTargetSection::addEntry(Symbol &Sym) {
assert(Sym.PPC64BranchltIndex == 0xffff);
Sym.PPC64BranchltIndex = Entries.size();
Entries.push_back(&Sym);
}
size_t PPC64LongBranchTargetSection::getSize() const {
return Entries.size() * 8;
}
void PPC64LongBranchTargetSection::writeTo(uint8_t *Buf) {
assert(Target->GotPltEntrySize == 8);
// If linking non-pic we have the final addresses of the targets and they get
// written to the table directly. For pic the dynamic linker will allocate
// the section and fill it it.
if (Config->Pic)
return;
for (const Symbol *Sym : Entries) {
assert(Sym->getVA());
// Need calls to branch to the local entry-point since a long-branch
// must be a local-call.
write64(Buf,
Sym->getVA() + getPPC64GlobalEntryToLocalEntryOffset(Sym->StOther));
Buf += Target->GotPltEntrySize;
}
}
bool PPC64LongBranchTargetSection::empty() const {
// `removeUnusedSyntheticSections()` is called before thunk allocation which
// is too early to determine if this section will be empty or not. We need
// Finalized to keep the section alive until after thunk creation. Finalized
// only gets set to true once `finalizeSections()` is called after thunk
// creation. Becuase of this, if we don't create any long-branch thunks we end
// up with an empty .branch_lt section in the binary.
return Finalized && Entries.empty();
}
InStruct elf::In;
template GdbIndexSection *GdbIndexSection::create<ELF32LE>();
template GdbIndexSection *GdbIndexSection::create<ELF32BE>();
template GdbIndexSection *GdbIndexSection::create<ELF64LE>();
template GdbIndexSection *GdbIndexSection::create<ELF64BE>();
template void elf::splitSections<ELF32LE>();
template void elf::splitSections<ELF32BE>();
template void elf::splitSections<ELF64LE>();
template void elf::splitSections<ELF64BE>();
template void EhFrameSection::addSection<ELF32LE>(InputSectionBase *);
template void EhFrameSection::addSection<ELF32BE>(InputSectionBase *);
template void EhFrameSection::addSection<ELF64LE>(InputSectionBase *);
template void EhFrameSection::addSection<ELF64BE>(InputSectionBase *);
template void PltSection::addEntry<ELF32LE>(Symbol &Sym);
template void PltSection::addEntry<ELF32BE>(Symbol &Sym);
template void PltSection::addEntry<ELF64LE>(Symbol &Sym);
template void PltSection::addEntry<ELF64BE>(Symbol &Sym);
template void MipsGotSection::build<ELF32LE>();
template void MipsGotSection::build<ELF32BE>();
template void MipsGotSection::build<ELF64LE>();
template void MipsGotSection::build<ELF64BE>();
template class elf::MipsAbiFlagsSection<ELF32LE>;
template class elf::MipsAbiFlagsSection<ELF32BE>;
template class elf::MipsAbiFlagsSection<ELF64LE>;
template class elf::MipsAbiFlagsSection<ELF64BE>;
template class elf::MipsOptionsSection<ELF32LE>;
template class elf::MipsOptionsSection<ELF32BE>;
template class elf::MipsOptionsSection<ELF64LE>;
template class elf::MipsOptionsSection<ELF64BE>;
template class elf::MipsReginfoSection<ELF32LE>;
template class elf::MipsReginfoSection<ELF32BE>;
template class elf::MipsReginfoSection<ELF64LE>;
template class elf::MipsReginfoSection<ELF64BE>;
template class elf::DynamicSection<ELF32LE>;
template class elf::DynamicSection<ELF32BE>;
template class elf::DynamicSection<ELF64LE>;
template class elf::DynamicSection<ELF64BE>;
template class elf::RelocationSection<ELF32LE>;
template class elf::RelocationSection<ELF32BE>;
template class elf::RelocationSection<ELF64LE>;
template class elf::RelocationSection<ELF64BE>;
template class elf::AndroidPackedRelocationSection<ELF32LE>;
template class elf::AndroidPackedRelocationSection<ELF32BE>;
template class elf::AndroidPackedRelocationSection<ELF64LE>;
template class elf::AndroidPackedRelocationSection<ELF64BE>;
template class elf::RelrSection<ELF32LE>;
template class elf::RelrSection<ELF32BE>;
template class elf::RelrSection<ELF64LE>;
template class elf::RelrSection<ELF64BE>;
template class elf::SymbolTableSection<ELF32LE>;
template class elf::SymbolTableSection<ELF32BE>;
template class elf::SymbolTableSection<ELF64LE>;
template class elf::SymbolTableSection<ELF64BE>;
template class elf::VersionTableSection<ELF32LE>;
template class elf::VersionTableSection<ELF32BE>;
template class elf::VersionTableSection<ELF64LE>;
template class elf::VersionTableSection<ELF64BE>;
template class elf::VersionNeedSection<ELF32LE>;
template class elf::VersionNeedSection<ELF32BE>;
template class elf::VersionNeedSection<ELF64LE>;
template class elf::VersionNeedSection<ELF64BE>;
Index: stable/11/contrib/llvm/tools/lld/ELF/Writer.cpp
===================================================================
--- stable/11/contrib/llvm/tools/lld/ELF/Writer.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/lld/ELF/Writer.cpp (revision 350259)
@@ -1,2551 +1,2545 @@
//===- Writer.cpp ---------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Writer.h"
#include "AArch64ErrataFix.h"
#include "CallGraphSort.h"
#include "Config.h"
#include "Filesystem.h"
#include "LinkerScript.h"
#include "MapFile.h"
#include "OutputSections.h"
#include "Relocations.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include <climits>
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support;
using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
namespace {
// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
Writer() : Buffer(errorHandler().OutputBuffer) {}
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Ehdr Elf_Ehdr;
typedef typename ELFT::Phdr Elf_Phdr;
void run();
private:
void copyLocalSymbols();
void addSectionSymbols();
void forEachRelSec(llvm::function_ref<void(InputSectionBase &)> Fn);
void sortSections();
void resolveShfLinkOrder();
void maybeAddThunks();
void sortInputSections();
void finalizeSections();
void checkExecuteOnly();
void setReservedSymbolSections();
std::vector<PhdrEntry *> createPhdrs();
void removeEmptyPTLoad();
void addPtArmExid(std::vector<PhdrEntry *> &Phdrs);
void assignFileOffsets();
void assignFileOffsetsBinary();
void setPhdrs();
void checkSections();
void fixSectionAlignments();
void openFile();
void writeTrapInstr();
void writeHeader();
void writeSections();
void writeSectionsBinary();
void writeBuildId();
std::unique_ptr<FileOutputBuffer> &Buffer;
void addRelIpltSymbols();
void addStartEndSymbols();
void addStartStopSymbols(OutputSection *Sec);
std::vector<PhdrEntry *> Phdrs;
uint64_t FileSize;
uint64_t SectionHeaderOff;
};
} // anonymous namespace
static bool isSectionPrefix(StringRef Prefix, StringRef Name) {
return Name.startswith(Prefix) || Name == Prefix.drop_back();
}
StringRef elf::getOutputSectionName(const InputSectionBase *S) {
if (Config->Relocatable)
return S->Name;
// This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want
// to emit .rela.text.foo as .rela.text.bar for consistency (this is not
// technically required, but not doing it is odd). This code guarantees that.
if (auto *IS = dyn_cast<InputSection>(S)) {
if (InputSectionBase *Rel = IS->getRelocatedSection()) {
OutputSection *Out = Rel->getOutputSection();
if (S->Type == SHT_RELA)
return Saver.save(".rela" + Out->Name);
return Saver.save(".rel" + Out->Name);
}
}
// This check is for -z keep-text-section-prefix. This option separates text
// sections with prefix ".text.hot", ".text.unlikely", ".text.startup" or
// ".text.exit".
// When enabled, this allows identifying the hot code region (.text.hot) in
// the final binary which can be selectively mapped to huge pages or mlocked,
// for instance.
if (Config->ZKeepTextSectionPrefix)
for (StringRef V :
{".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."})
if (isSectionPrefix(V, S->Name))
return V.drop_back();
for (StringRef V :
{".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."})
if (isSectionPrefix(V, S->Name))
return V.drop_back();
// CommonSection is identified as "COMMON" in linker scripts.
// By default, it should go to .bss section.
if (S->Name == "COMMON")
return ".bss";
return S->Name;
}
static bool needsInterpSection() {
return !SharedFiles.empty() && !Config->DynamicLinker.empty() &&
Script->needsInterpSection();
}
template <class ELFT> void elf::writeResult() { Writer<ELFT>().run(); }
template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() {
llvm::erase_if(Phdrs, [&](const PhdrEntry *P) {
if (P->p_type != PT_LOAD)
return false;
if (!P->FirstSec)
return true;
uint64_t Size = P->LastSec->Addr + P->LastSec->Size - P->FirstSec->Addr;
return Size == 0;
});
}
template <class ELFT> static void combineEhFrameSections() {
for (InputSectionBase *&S : InputSections) {
EhInputSection *ES = dyn_cast<EhInputSection>(S);
if (!ES || !ES->Live)
continue;
In.EhFrame->addSection<ELFT>(ES);
S = nullptr;
}
std::vector<InputSectionBase *> &V = InputSections;
V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
}
static Defined *addOptionalRegular(StringRef Name, SectionBase *Sec,
uint64_t Val, uint8_t StOther = STV_HIDDEN,
uint8_t Binding = STB_GLOBAL) {
Symbol *S = Symtab->find(Name);
if (!S || S->isDefined())
return nullptr;
return Symtab->addDefined(Name, StOther, STT_NOTYPE, Val,
/*Size=*/0, Binding, Sec,
/*File=*/nullptr);
}
static Defined *addAbsolute(StringRef Name) {
return Symtab->addDefined(Name, STV_HIDDEN, STT_NOTYPE, 0, 0, STB_GLOBAL,
nullptr, nullptr);
}
// The linker is expected to define some symbols depending on
// the linking result. This function defines such symbols.
void elf::addReservedSymbols() {
if (Config->EMachine == EM_MIPS) {
// Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
// so that it points to an absolute address which by default is relative
// to GOT. Default offset is 0x7ff0.
// See "Global Data Symbols" in Chapter 6 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
ElfSym::MipsGp = addAbsolute("_gp");
// On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
// start of function and 'gp' pointer into GOT.
if (Symtab->find("_gp_disp"))
ElfSym::MipsGpDisp = addAbsolute("_gp_disp");
// The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
// pointer. This symbol is used in the code generated by .cpload pseudo-op
// in case of using -mno-shared option.
// https://sourceware.org/ml/binutils/2004-12/msg00094.html
if (Symtab->find("__gnu_local_gp"))
ElfSym::MipsLocalGp = addAbsolute("__gnu_local_gp");
}
// The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which
// combines the typical ELF GOT with the small data sections. It commonly
// includes .got .toc .sdata .sbss. The .TOC. symbol replaces both
// _GLOBAL_OFFSET_TABLE_ and _SDA_BASE_ from the 32-bit ABI. It is used to
// represent the TOC base which is offset by 0x8000 bytes from the start of
// the .got section.
// We do not allow _GLOBAL_OFFSET_TABLE_ to be defined by input objects as the
// correctness of some relocations depends on its value.
StringRef GotTableSymName =
(Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_";
if (Symbol *S = Symtab->find(GotTableSymName)) {
if (S->isDefined())
error(toString(S->File) + " cannot redefine linker defined symbol '" +
GotTableSymName + "'");
else
ElfSym::GlobalOffsetTable = Symtab->addDefined(
GotTableSymName, STV_HIDDEN, STT_NOTYPE, Target->GotBaseSymOff,
/*Size=*/0, STB_GLOBAL, Out::ElfHeader,
/*File=*/nullptr);
}
// __ehdr_start is the location of ELF file headers. Note that we define
// this symbol unconditionally even when using a linker script, which
// differs from the behavior implemented by GNU linker which only define
// this symbol if ELF headers are in the memory mapped segment.
addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN);
// __executable_start is not documented, but the expectation of at
// least the Android libc is that it points to the ELF header.
addOptionalRegular("__executable_start", Out::ElfHeader, 0, STV_HIDDEN);
// __dso_handle symbol is passed to cxa_finalize as a marker to identify
// each DSO. The address of the symbol doesn't matter as long as they are
// different in different DSOs, so we chose the start address of the DSO.
addOptionalRegular("__dso_handle", Out::ElfHeader, 0, STV_HIDDEN);
// If linker script do layout we do not need to create any standart symbols.
if (Script->HasSectionsCommand)
return;
auto Add = [](StringRef S, int64_t Pos) {
return addOptionalRegular(S, Out::ElfHeader, Pos, STV_DEFAULT);
};
ElfSym::Bss = Add("__bss_start", 0);
ElfSym::End1 = Add("end", -1);
ElfSym::End2 = Add("_end", -1);
ElfSym::Etext1 = Add("etext", -1);
ElfSym::Etext2 = Add("_etext", -1);
ElfSym::Edata1 = Add("edata", -1);
ElfSym::Edata2 = Add("_edata", -1);
}
static OutputSection *findSection(StringRef Name) {
for (BaseCommand *Base : Script->SectionCommands)
if (auto *Sec = dyn_cast<OutputSection>(Base))
if (Sec->Name == Name)
return Sec;
return nullptr;
}
// Initialize Out members.
template <class ELFT> static void createSyntheticSections() {
// Initialize all pointers with NULL. This is needed because
// you can call lld::elf::main more than once as a library.
memset(&Out::First, 0, sizeof(Out));
auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); };
In.DynStrTab = make<StringTableSection>(".dynstr", true);
In.Dynamic = make<DynamicSection<ELFT>>();
if (Config->AndroidPackDynRelocs) {
In.RelaDyn = make<AndroidPackedRelocationSection<ELFT>>(
Config->IsRela ? ".rela.dyn" : ".rel.dyn");
} else {
In.RelaDyn = make<RelocationSection<ELFT>>(
Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
}
In.ShStrTab = make<StringTableSection>(".shstrtab", false);
Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC);
Out::ProgramHeaders->Alignment = Config->Wordsize;
if (needsInterpSection()) {
In.Interp = createInterpSection();
Add(In.Interp);
}
if (Config->Strip != StripPolicy::All) {
In.StrTab = make<StringTableSection>(".strtab", false);
In.SymTab = make<SymbolTableSection<ELFT>>(*In.StrTab);
In.SymTabShndx = make<SymtabShndxSection>();
}
if (Config->BuildId != BuildIdKind::None) {
In.BuildId = make<BuildIdSection>();
Add(In.BuildId);
}
In.Bss = make<BssSection>(".bss", 0, 1);
Add(In.Bss);
// If there is a SECTIONS command and a .data.rel.ro section name use name
// .data.rel.ro.bss so that we match in the .data.rel.ro output section.
// This makes sure our relro is contiguous.
bool HasDataRelRo = Script->HasSectionsCommand && findSection(".data.rel.ro");
In.BssRelRo =
make<BssSection>(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
Add(In.BssRelRo);
// Add MIPS-specific sections.
if (Config->EMachine == EM_MIPS) {
if (!Config->Shared && Config->HasDynSymTab) {
In.MipsRldMap = make<MipsRldMapSection>();
Add(In.MipsRldMap);
}
if (auto *Sec = MipsAbiFlagsSection<ELFT>::create())
Add(Sec);
if (auto *Sec = MipsOptionsSection<ELFT>::create())
Add(Sec);
if (auto *Sec = MipsReginfoSection<ELFT>::create())
Add(Sec);
}
if (Config->HasDynSymTab) {
In.DynSymTab = make<SymbolTableSection<ELFT>>(*In.DynStrTab);
Add(In.DynSymTab);
InX<ELFT>::VerSym = make<VersionTableSection<ELFT>>();
Add(InX<ELFT>::VerSym);
if (!Config->VersionDefinitions.empty()) {
In.VerDef = make<VersionDefinitionSection>();
Add(In.VerDef);
}
InX<ELFT>::VerNeed = make<VersionNeedSection<ELFT>>();
Add(InX<ELFT>::VerNeed);
if (Config->GnuHash) {
In.GnuHashTab = make<GnuHashTableSection>();
Add(In.GnuHashTab);
}
if (Config->SysvHash) {
In.HashTab = make<HashTableSection>();
Add(In.HashTab);
}
Add(In.Dynamic);
Add(In.DynStrTab);
Add(In.RelaDyn);
}
if (Config->RelrPackDynRelocs) {
In.RelrDyn = make<RelrSection<ELFT>>();
Add(In.RelrDyn);
}
// Add .got. MIPS' .got is so different from the other archs,
// it has its own class.
if (Config->EMachine == EM_MIPS) {
In.MipsGot = make<MipsGotSection>();
Add(In.MipsGot);
} else {
In.Got = make<GotSection>();
Add(In.Got);
}
if (Config->EMachine == EM_PPC64) {
In.PPC64LongBranchTarget = make<PPC64LongBranchTargetSection>();
Add(In.PPC64LongBranchTarget);
}
In.GotPlt = make<GotPltSection>();
Add(In.GotPlt);
In.IgotPlt = make<IgotPltSection>();
Add(In.IgotPlt);
if (Config->GdbIndex) {
In.GdbIndex = GdbIndexSection::create<ELFT>();
Add(In.GdbIndex);
}
// We always need to add rel[a].plt to output if it has entries.
// Even for static linking it can contain R_[*]_IRELATIVE relocations.
In.RelaPlt = make<RelocationSection<ELFT>>(
Config->IsRela ? ".rela.plt" : ".rel.plt", false /*Sort*/);
Add(In.RelaPlt);
// The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure
// that the IRelative relocations are processed last by the dynamic loader.
// We cannot place the iplt section in .rel.dyn when Android relocation
// packing is enabled because that would cause a section type mismatch.
// However, because the Android dynamic loader reads .rel.plt after .rel.dyn,
// we can get the desired behaviour by placing the iplt section in .rel.plt.
In.RelaIplt = make<RelocationSection<ELFT>>(
(Config->EMachine == EM_ARM && !Config->AndroidPackDynRelocs)
? ".rel.dyn"
: In.RelaPlt->Name,
false /*Sort*/);
Add(In.RelaIplt);
In.Plt = make<PltSection>(false);
Add(In.Plt);
In.Iplt = make<PltSection>(true);
Add(In.Iplt);
// .note.GNU-stack is always added when we are creating a re-linkable
// object file. Other linkers are using the presence of this marker
// section to control the executable-ness of the stack area, but that
// is irrelevant these days. Stack area should always be non-executable
// by default. So we emit this section unconditionally.
if (Config->Relocatable)
Add(make<GnuStackSection>());
if (!Config->Relocatable) {
if (Config->EhFrameHdr) {
In.EhFrameHdr = make<EhFrameHeader>();
Add(In.EhFrameHdr);
}
In.EhFrame = make<EhFrameSection>();
Add(In.EhFrame);
}
if (In.SymTab)
Add(In.SymTab);
if (In.SymTabShndx)
Add(In.SymTabShndx);
Add(In.ShStrTab);
if (In.StrTab)
Add(In.StrTab);
if (Config->EMachine == EM_ARM && !Config->Relocatable)
// Add a sentinel to terminate .ARM.exidx. It helps an unwinder
// to find the exact address range of the last entry.
Add(make<ARMExidxSentinelSection>());
}
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
// Create linker-synthesized sections such as .got or .plt.
// Such sections are of type input section.
createSyntheticSections<ELFT>();
if (!Config->Relocatable)
combineEhFrameSections<ELFT>();
// We want to process linker script commands. When SECTIONS command
// is given we let it create sections.
Script->processSectionCommands();
// Linker scripts controls how input sections are assigned to output sections.
// Input sections that were not handled by scripts are called "orphans", and
// they are assigned to output sections by the default rule. Process that.
Script->addOrphanSections();
if (Config->Discard != DiscardPolicy::All)
copyLocalSymbols();
if (Config->CopyRelocs)
addSectionSymbols();
// Now that we have a complete set of output sections. This function
// completes section contents. For example, we need to add strings
// to the string table, and add entries to .got and .plt.
// finalizeSections does that.
finalizeSections();
checkExecuteOnly();
if (errorCount())
return;
Script->assignAddresses();
// If -compressed-debug-sections is specified, we need to compress
// .debug_* sections. Do it right now because it changes the size of
// output sections.
for (OutputSection *Sec : OutputSections)
Sec->maybeCompress<ELFT>();
Script->allocateHeaders(Phdrs);
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
// 0 sized region. This has to be done late since only after assignAddresses
// we know the size of the sections.
removeEmptyPTLoad();
if (!Config->OFormatBinary)
assignFileOffsets();
else
assignFileOffsetsBinary();
setPhdrs();
if (Config->Relocatable)
for (OutputSection *Sec : OutputSections)
Sec->Addr = 0;
if (Config->CheckSections)
checkSections();
// It does not make sense try to open the file if we have error already.
if (errorCount())
return;
// Write the result down to a file.
openFile();
if (errorCount())
return;
if (!Config->OFormatBinary) {
writeTrapInstr();
writeHeader();
writeSections();
} else {
writeSectionsBinary();
}
// Backfill .note.gnu.build-id section content. This is done at last
// because the content is usually a hash value of the entire output file.
writeBuildId();
if (errorCount())
return;
// Handle -Map and -cref options.
writeMapFile();
writeCrossReferenceTable();
if (errorCount())
return;
if (auto E = Buffer->commit())
error("failed to write to the output file: " + toString(std::move(E)));
}
static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName,
const Symbol &B) {
if (B.isSection())
return false;
if (Config->Discard == DiscardPolicy::None)
return true;
+ // If -emit-reloc is given, all symbols including local ones need to be
+ // copied because they may be referenced by relocations.
+ if (Config->EmitRelocs)
+ return true;
+
// In ELF assembly .L symbols are normally discarded by the assembler.
// If the assembler fails to do so, the linker discards them if
// * --discard-locals is used.
// * The symbol is in a SHF_MERGE section, which is normally the reason for
// the assembler keeping the .L symbol.
if (!SymName.startswith(".L") && !SymName.empty())
return true;
if (Config->Discard == DiscardPolicy::Locals)
return false;
return !Sec || !(Sec->Flags & SHF_MERGE);
}
static bool includeInSymtab(const Symbol &B) {
if (!B.isLocal() && !B.IsUsedInRegularObj)
return false;
if (auto *D = dyn_cast<Defined>(&B)) {
// Always include absolute symbols.
SectionBase *Sec = D->Section;
if (!Sec)
return true;
Sec = Sec->Repl;
// Exclude symbols pointing to garbage-collected sections.
if (isa<InputSectionBase>(Sec) && !Sec->Live)
return false;
if (auto *S = dyn_cast<MergeInputSection>(Sec))
if (!S->getSectionPiece(D->Value)->Live)
return false;
return true;
}
return B.Used;
}
// Local symbols are not in the linker's symbol table. This function scans
// each object file's symbol table to copy local symbols to the output.
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
if (!In.SymTab)
return;
for (InputFile *File : ObjectFiles) {
ObjFile<ELFT> *F = cast<ObjFile<ELFT>>(File);
for (Symbol *B : F->getLocalSymbols()) {
if (!B->isLocal())
fatal(toString(F) +
": broken object: getLocalSymbols returns a non-local symbol");
auto *DR = dyn_cast<Defined>(B);
// No reason to keep local undefined symbol in symtab.
if (!DR)
continue;
if (!includeInSymtab(*B))
continue;
SectionBase *Sec = DR->Section;
if (!shouldKeepInSymtab(Sec, B->getName(), *B))
continue;
In.SymTab->addSymbol(B);
}
}
}
// Create a section symbol for each output section so that we can represent
// relocations that point to the section. If we know that no relocation is
// referring to a section (that happens if the section is a synthetic one), we
// don't create a section symbol for that section.
template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
for (BaseCommand *Base : Script->SectionCommands) {
auto *Sec = dyn_cast<OutputSection>(Base);
if (!Sec)
continue;
auto I = llvm::find_if(Sec->SectionCommands, [](BaseCommand *Base) {
if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
return !ISD->Sections.empty();
return false;
});
if (I == Sec->SectionCommands.end())
continue;
InputSection *IS = cast<InputSectionDescription>(*I)->Sections[0];
// Relocations are not using REL[A] section symbols.
if (IS->Type == SHT_REL || IS->Type == SHT_RELA)
continue;
// Unlike other synthetic sections, mergeable output sections contain data
// copied from input sections, and there may be a relocation pointing to its
// contents if -r or -emit-reloc are given.
if (isa<SyntheticSection>(IS) && !(IS->Flags & SHF_MERGE))
continue;
auto *Sym =
make<Defined>(IS->File, "", STB_LOCAL, /*StOther=*/0, STT_SECTION,
/*Value=*/0, /*Size=*/0, IS);
In.SymTab->addSymbol(Sym);
}
}
// Today's loaders have a feature to make segments read-only after
// processing dynamic relocations to enhance security. PT_GNU_RELRO
// is defined for that.
//
// This function returns true if a section needs to be put into a
// PT_GNU_RELRO segment.
static bool isRelroSection(const OutputSection *Sec) {
if (!Config->ZRelro)
return false;
uint64_t Flags = Sec->Flags;
// Non-allocatable or non-writable sections don't need RELRO because
// they are not writable or not even mapped to memory in the first place.
// RELRO is for sections that are essentially read-only but need to
// be writable only at process startup to allow dynamic linker to
// apply relocations.
if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE))
return false;
// Once initialized, TLS data segments are used as data templates
// for a thread-local storage. For each new thread, runtime
// allocates memory for a TLS and copy templates there. No thread
// are supposed to use templates directly. Thus, it can be in RELRO.
if (Flags & SHF_TLS)
return true;
// .init_array, .preinit_array and .fini_array contain pointers to
// functions that are executed on process startup or exit. These
// pointers are set by the static linker, and they are not expected
// to change at runtime. But if you are an attacker, you could do
// interesting things by manipulating pointers in .fini_array, for
// example. So they are put into RELRO.
uint32_t Type = Sec->Type;
if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY ||
Type == SHT_PREINIT_ARRAY)
return true;
// .got contains pointers to external symbols. They are resolved by
// the dynamic linker when a module is loaded into memory, and after
// that they are not expected to change. So, it can be in RELRO.
if (In.Got && Sec == In.Got->getParent())
return true;
// .toc is a GOT-ish section for PowerPC64. Their contents are accessed
// through r2 register, which is reserved for that purpose. Since r2 is used
// for accessing .got as well, .got and .toc need to be close enough in the
// virtual address space. Usually, .toc comes just after .got. Since we place
// .got into RELRO, .toc needs to be placed into RELRO too.
if (Sec->Name.equals(".toc"))
return true;
// .got.plt contains pointers to external function symbols. They are
// by default resolved lazily, so we usually cannot put it into RELRO.
// However, if "-z now" is given, the lazy symbol resolution is
// disabled, which enables us to put it into RELRO.
if (Sec == In.GotPlt->getParent())
return Config->ZNow;
// .dynamic section contains data for the dynamic linker, and
// there's no need to write to it at runtime, so it's better to put
// it into RELRO.
if (Sec == In.Dynamic->getParent())
return true;
// Sections with some special names are put into RELRO. This is a
// bit unfortunate because section names shouldn't be significant in
// ELF in spirit. But in reality many linker features depend on
// magic section names.
StringRef S = Sec->Name;
return S == ".data.rel.ro" || S == ".bss.rel.ro" || S == ".ctors" ||
S == ".dtors" || S == ".jcr" || S == ".eh_frame" ||
S == ".openbsd.randomdata";
}
// We compute a rank for each section. The rank indicates where the
// section should be placed in the file. Instead of using simple
// numbers (0,1,2...), we use a series of flags. One for each decision
// point when placing the section.
// Using flags has two key properties:
// * It is easy to check if a give branch was taken.
// * It is easy two see how similar two ranks are (see getRankProximity).
enum RankFlags {
RF_NOT_ADDR_SET = 1 << 18,
RF_NOT_ALLOC = 1 << 17,
RF_NOT_INTERP = 1 << 16,
RF_NOT_NOTE = 1 << 15,
RF_WRITE = 1 << 14,
RF_EXEC_WRITE = 1 << 13,
RF_EXEC = 1 << 12,
RF_RODATA = 1 << 11,
RF_NON_TLS_BSS = 1 << 10,
RF_NON_TLS_BSS_RO = 1 << 9,
RF_NOT_TLS = 1 << 8,
RF_BSS = 1 << 7,
RF_PPC_NOT_TOCBSS = 1 << 6,
RF_PPC_TOCL = 1 << 5,
RF_PPC_TOC = 1 << 4,
RF_PPC_GOT = 1 << 3,
RF_PPC_BRANCH_LT = 1 << 2,
RF_MIPS_GPREL = 1 << 1,
RF_MIPS_NOT_GOT = 1 << 0
};
static unsigned getSectionRank(const OutputSection *Sec) {
unsigned Rank = 0;
// We want to put section specified by -T option first, so we
// can start assigning VA starting from them later.
if (Config->SectionStartMap.count(Sec->Name))
return Rank;
Rank |= RF_NOT_ADDR_SET;
// Allocatable sections go first to reduce the total PT_LOAD size and
// so debug info doesn't change addresses in actual code.
if (!(Sec->Flags & SHF_ALLOC))
return Rank | RF_NOT_ALLOC;
// Put .interp first because some loaders want to see that section
// on the first page of the executable file when loaded into memory.
if (Sec->Name == ".interp")
return Rank;
Rank |= RF_NOT_INTERP;
// Put .note sections (which make up one PT_NOTE) at the beginning so that
// they are likely to be included in a core file even if core file size is
// limited. In particular, we want a .note.gnu.build-id and a .note.tag to be
// included in a core to match core files with executables.
if (Sec->Type == SHT_NOTE)
return Rank;
Rank |= RF_NOT_NOTE;
// Sort sections based on their access permission in the following
// order: R, RX, RWX, RW. This order is based on the following
// considerations:
// * Read-only sections come first such that they go in the
// PT_LOAD covering the program headers at the start of the file.
// * Read-only, executable sections come next.
// * Writable, executable sections follow such that .plt on
// architectures where it needs to be writable will be placed
// between .text and .data.
// * Writable sections come last, such that .bss lands at the very
// end of the last PT_LOAD.
bool IsExec = Sec->Flags & SHF_EXECINSTR;
bool IsWrite = Sec->Flags & SHF_WRITE;
if (IsExec) {
if (IsWrite)
Rank |= RF_EXEC_WRITE;
else
Rank |= RF_EXEC;
} else if (IsWrite) {
Rank |= RF_WRITE;
} else if (Sec->Type == SHT_PROGBITS) {
// Make non-executable and non-writable PROGBITS sections (e.g .rodata
// .eh_frame) closer to .text. They likely contain PC or GOT relative
// relocations and there could be relocation overflow if other huge sections
// (.dynstr .dynsym) were placed in between.
Rank |= RF_RODATA;
}
// If we got here we know that both A and B are in the same PT_LOAD.
bool IsTls = Sec->Flags & SHF_TLS;
bool IsNoBits = Sec->Type == SHT_NOBITS;
// The first requirement we have is to put (non-TLS) nobits sections last. The
// reason is that the only thing the dynamic linker will see about them is a
// p_memsz that is larger than p_filesz. Seeing that it zeros the end of the
// PT_LOAD, so that has to correspond to the nobits sections.
bool IsNonTlsNoBits = IsNoBits && !IsTls;
if (IsNonTlsNoBits)
Rank |= RF_NON_TLS_BSS;
// We place nobits RelRo sections before plain r/w ones, and non-nobits RelRo
// sections after r/w ones, so that the RelRo sections are contiguous.
bool IsRelRo = isRelroSection(Sec);
if (IsNonTlsNoBits && !IsRelRo)
Rank |= RF_NON_TLS_BSS_RO;
if (!IsNonTlsNoBits && IsRelRo)
Rank |= RF_NON_TLS_BSS_RO;
// The TLS initialization block needs to be a single contiguous block in a R/W
// PT_LOAD, so stick TLS sections directly before the other RelRo R/W
// sections. The TLS NOBITS sections are placed here as they don't take up
// virtual address space in the PT_LOAD.
if (!IsTls)
Rank |= RF_NOT_TLS;
// Within the TLS initialization block, the non-nobits sections need to appear
// first.
if (IsNoBits)
Rank |= RF_BSS;
// Some architectures have additional ordering restrictions for sections
// within the same PT_LOAD.
if (Config->EMachine == EM_PPC64) {
// PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections
// that we would like to make sure appear is a specific order to maximize
// their coverage by a single signed 16-bit offset from the TOC base
// pointer. Conversely, the special .tocbss section should be first among
// all SHT_NOBITS sections. This will put it next to the loaded special
// PPC64 sections (and, thus, within reach of the TOC base pointer).
StringRef Name = Sec->Name;
if (Name != ".tocbss")
Rank |= RF_PPC_NOT_TOCBSS;
if (Name == ".toc1")
Rank |= RF_PPC_TOCL;
if (Name == ".toc")
Rank |= RF_PPC_TOC;
if (Name == ".got")
Rank |= RF_PPC_GOT;
if (Name == ".branch_lt")
Rank |= RF_PPC_BRANCH_LT;
}
if (Config->EMachine == EM_MIPS) {
// All sections with SHF_MIPS_GPREL flag should be grouped together
// because data in these sections is addressable with a gp relative address.
if (Sec->Flags & SHF_MIPS_GPREL)
Rank |= RF_MIPS_GPREL;
if (Sec->Name != ".got")
Rank |= RF_MIPS_NOT_GOT;
}
return Rank;
}
static bool compareSections(const BaseCommand *ACmd, const BaseCommand *BCmd) {
const OutputSection *A = cast<OutputSection>(ACmd);
const OutputSection *B = cast<OutputSection>(BCmd);
if (A->SortRank != B->SortRank)
return A->SortRank < B->SortRank;
if (!(A->SortRank & RF_NOT_ADDR_SET))
return Config->SectionStartMap.lookup(A->Name) <
Config->SectionStartMap.lookup(B->Name);
return false;
}
void PhdrEntry::add(OutputSection *Sec) {
LastSec = Sec;
if (!FirstSec)
FirstSec = Sec;
p_align = std::max(p_align, Sec->Alignment);
if (p_type == PT_LOAD)
Sec->PtLoad = this;
}
// The beginning and the ending of .rel[a].plt section are marked
// with __rel[a]_iplt_{start,end} symbols if it is a statically linked
// executable. The runtime needs these symbols in order to resolve
// all IRELATIVE relocs on startup. For dynamic executables, we don't
// need these symbols, since IRELATIVE relocs are resolved through GOT
// and PLT. For details, see http://www.airs.com/blog/archives/403.
template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
if (Config->Relocatable || needsInterpSection())
return;
// By default, __rela_iplt_{start,end} belong to a dummy section 0
// because .rela.plt might be empty and thus removed from output.
// We'll override Out::ElfHeader with In.RelaIplt later when we are
// sure that .rela.plt exists in output.
ElfSym::RelaIpltStart = addOptionalRegular(
Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start",
Out::ElfHeader, 0, STV_HIDDEN, STB_WEAK);
ElfSym::RelaIpltEnd = addOptionalRegular(
Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end",
Out::ElfHeader, 0, STV_HIDDEN, STB_WEAK);
}
template <class ELFT>
void Writer<ELFT>::forEachRelSec(
llvm::function_ref<void(InputSectionBase &)> Fn) {
// Scan all relocations. Each relocation goes through a series
// of tests to determine if it needs special treatment, such as
// creating GOT, PLT, copy relocations, etc.
// Note that relocations for non-alloc sections are directly
// processed by InputSection::relocateNonAlloc.
for (InputSectionBase *IS : InputSections)
if (IS->Live && isa<InputSection>(IS) && (IS->Flags & SHF_ALLOC))
Fn(*IS);
for (EhInputSection *ES : In.EhFrame->Sections)
Fn(*ES);
}
// This function generates assignments for predefined symbols (e.g. _end or
// _etext) and inserts them into the commands sequence to be processed at the
// appropriate time. This ensures that the value is going to be correct by the
// time any references to these symbols are processed and is equivalent to
// defining these symbols explicitly in the linker script.
template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
if (ElfSym::GlobalOffsetTable) {
// The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention usually
// to the start of the .got or .got.plt section.
InputSection *GotSection = In.GotPlt;
if (!Target->GotBaseSymInGotPlt)
GotSection = In.MipsGot ? cast<InputSection>(In.MipsGot)
: cast<InputSection>(In.Got);
ElfSym::GlobalOffsetTable->Section = GotSection;
}
// .rela_iplt_{start,end} mark the start and the end of .rela.plt section.
if (ElfSym::RelaIpltStart && !In.RelaIplt->empty()) {
ElfSym::RelaIpltStart->Section = In.RelaIplt;
ElfSym::RelaIpltEnd->Section = In.RelaIplt;
ElfSym::RelaIpltEnd->Value = In.RelaIplt->getSize();
}
PhdrEntry *Last = nullptr;
PhdrEntry *LastRO = nullptr;
for (PhdrEntry *P : Phdrs) {
if (P->p_type != PT_LOAD)
continue;
Last = P;
if (!(P->p_flags & PF_W))
LastRO = P;
}
if (LastRO) {
// _etext is the first location after the last read-only loadable segment.
if (ElfSym::Etext1)
ElfSym::Etext1->Section = LastRO->LastSec;
if (ElfSym::Etext2)
ElfSym::Etext2->Section = LastRO->LastSec;
}
if (Last) {
// _edata points to the end of the last mapped initialized section.
OutputSection *Edata = nullptr;
for (OutputSection *OS : OutputSections) {
if (OS->Type != SHT_NOBITS)
Edata = OS;
if (OS == Last->LastSec)
break;
}
if (ElfSym::Edata1)
ElfSym::Edata1->Section = Edata;
if (ElfSym::Edata2)
ElfSym::Edata2->Section = Edata;
// _end is the first location after the uninitialized data region.
if (ElfSym::End1)
ElfSym::End1->Section = Last->LastSec;
if (ElfSym::End2)
ElfSym::End2->Section = Last->LastSec;
}
if (ElfSym::Bss)
ElfSym::Bss->Section = findSection(".bss");
// Setup MIPS _gp_disp/__gnu_local_gp symbols which should
// be equal to the _gp symbol's value.
if (ElfSym::MipsGp) {
// Find GP-relative section with the lowest address
// and use this address to calculate default _gp value.
for (OutputSection *OS : OutputSections) {
if (OS->Flags & SHF_MIPS_GPREL) {
ElfSym::MipsGp->Section = OS;
ElfSym::MipsGp->Value = 0x7ff0;
break;
}
}
}
}
// We want to find how similar two ranks are.
// The more branches in getSectionRank that match, the more similar they are.
// Since each branch corresponds to a bit flag, we can just use
// countLeadingZeros.
static int getRankProximityAux(OutputSection *A, OutputSection *B) {
return countLeadingZeros(A->SortRank ^ B->SortRank);
}
static int getRankProximity(OutputSection *A, BaseCommand *B) {
if (auto *Sec = dyn_cast<OutputSection>(B))
return getRankProximityAux(A, Sec);
return -1;
}
// When placing orphan sections, we want to place them after symbol assignments
// so that an orphan after
// begin_foo = .;
// foo : { *(foo) }
// end_foo = .;
// doesn't break the intended meaning of the begin/end symbols.
// We don't want to go over sections since findOrphanPos is the
// one in charge of deciding the order of the sections.
// We don't want to go over changes to '.', since doing so in
// rx_sec : { *(rx_sec) }
// . = ALIGN(0x1000);
// /* The RW PT_LOAD starts here*/
// rw_sec : { *(rw_sec) }
// would mean that the RW PT_LOAD would become unaligned.
static bool shouldSkip(BaseCommand *Cmd) {
if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd))
return Assign->Name != ".";
return false;
}
// We want to place orphan sections so that they share as much
// characteristics with their neighbors as possible. For example, if
// both are rw, or both are tls.
template <typename ELFT>
static std::vector<BaseCommand *>::iterator
findOrphanPos(std::vector<BaseCommand *>::iterator B,
std::vector<BaseCommand *>::iterator E) {
OutputSection *Sec = cast<OutputSection>(*E);
// Find the first element that has as close a rank as possible.
auto I = std::max_element(B, E, [=](BaseCommand *A, BaseCommand *B) {
return getRankProximity(Sec, A) < getRankProximity(Sec, B);
});
if (I == E)
return E;
// Consider all existing sections with the same proximity.
int Proximity = getRankProximity(Sec, *I);
for (; I != E; ++I) {
auto *CurSec = dyn_cast<OutputSection>(*I);
if (!CurSec)
continue;
if (getRankProximity(Sec, CurSec) != Proximity ||
Sec->SortRank < CurSec->SortRank)
break;
}
auto IsOutputSec = [](BaseCommand *Cmd) { return isa<OutputSection>(Cmd); };
auto J = std::find_if(llvm::make_reverse_iterator(I),
llvm::make_reverse_iterator(B), IsOutputSec);
I = J.base();
// As a special case, if the orphan section is the last section, put
// it at the very end, past any other commands.
// This matches bfd's behavior and is convenient when the linker script fully
// specifies the start of the file, but doesn't care about the end (the non
// alloc sections for example).
auto NextSec = std::find_if(I, E, IsOutputSec);
if (NextSec == E)
return E;
while (I != E && shouldSkip(*I))
++I;
return I;
}
// Builds section order for handling --symbol-ordering-file.
static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
DenseMap<const InputSectionBase *, int> SectionOrder;
// Use the rarely used option -call-graph-ordering-file to sort sections.
if (!Config->CallGraphProfile.empty())
return computeCallGraphProfileOrder();
if (Config->SymbolOrderingFile.empty())
return SectionOrder;
struct SymbolOrderEntry {
int Priority;
bool Present;
};
// Build a map from symbols to their priorities. Symbols that didn't
// appear in the symbol ordering file have the lowest priority 0.
// All explicitly mentioned symbols have negative (higher) priorities.
DenseMap<StringRef, SymbolOrderEntry> SymbolOrder;
int Priority = -Config->SymbolOrderingFile.size();
for (StringRef S : Config->SymbolOrderingFile)
SymbolOrder.insert({S, {Priority++, false}});
// Build a map from sections to their priorities.
auto AddSym = [&](Symbol &Sym) {
auto It = SymbolOrder.find(Sym.getName());
if (It == SymbolOrder.end())
return;
SymbolOrderEntry &Ent = It->second;
Ent.Present = true;
maybeWarnUnorderableSymbol(&Sym);
if (auto *D = dyn_cast<Defined>(&Sym)) {
if (auto *Sec = dyn_cast_or_null<InputSectionBase>(D->Section)) {
int &Priority = SectionOrder[cast<InputSectionBase>(Sec->Repl)];
Priority = std::min(Priority, Ent.Priority);
}
}
};
// We want both global and local symbols. We get the global ones from the
// symbol table and iterate the object files for the local ones.
for (Symbol *Sym : Symtab->getSymbols())
if (!Sym->isLazy())
AddSym(*Sym);
for (InputFile *File : ObjectFiles)
for (Symbol *Sym : File->getSymbols())
if (Sym->isLocal())
AddSym(*Sym);
if (Config->WarnSymbolOrdering)
for (auto OrderEntry : SymbolOrder)
if (!OrderEntry.second.Present)
warn("symbol ordering file: no such symbol: " + OrderEntry.first);
return SectionOrder;
}
// Sorts the sections in ISD according to the provided section order.
static void
sortISDBySectionOrder(InputSectionDescription *ISD,
const DenseMap<const InputSectionBase *, int> &Order) {
std::vector<InputSection *> UnorderedSections;
std::vector<std::pair<InputSection *, int>> OrderedSections;
uint64_t UnorderedSize = 0;
for (InputSection *IS : ISD->Sections) {
auto I = Order.find(IS);
if (I == Order.end()) {
UnorderedSections.push_back(IS);
UnorderedSize += IS->getSize();
continue;
}
OrderedSections.push_back({IS, I->second});
}
llvm::sort(OrderedSections, [&](std::pair<InputSection *, int> A,
std::pair<InputSection *, int> B) {
return A.second < B.second;
});
// Find an insertion point for the ordered section list in the unordered
// section list. On targets with limited-range branches, this is the mid-point
// of the unordered section list. This decreases the likelihood that a range
// extension thunk will be needed to enter or exit the ordered region. If the
// ordered section list is a list of hot functions, we can generally expect
// the ordered functions to be called more often than the unordered functions,
// making it more likely that any particular call will be within range, and
// therefore reducing the number of thunks required.
//
// For example, imagine that you have 8MB of hot code and 32MB of cold code.
// If the layout is:
//
// 8MB hot
// 32MB cold
//
// only the first 8-16MB of the cold code (depending on which hot function it
// is actually calling) can call the hot code without a range extension thunk.
// However, if we use this layout:
//
// 16MB cold
// 8MB hot
// 16MB cold
//
// both the last 8-16MB of the first block of cold code and the first 8-16MB
// of the second block of cold code can call the hot code without a thunk. So
// we effectively double the amount of code that could potentially call into
// the hot code without a thunk.
size_t InsPt = 0;
if (Target->getThunkSectionSpacing() && !OrderedSections.empty()) {
uint64_t UnorderedPos = 0;
for (; InsPt != UnorderedSections.size(); ++InsPt) {
UnorderedPos += UnorderedSections[InsPt]->getSize();
if (UnorderedPos > UnorderedSize / 2)
break;
}
}
ISD->Sections.clear();
for (InputSection *IS : makeArrayRef(UnorderedSections).slice(0, InsPt))
ISD->Sections.push_back(IS);
for (std::pair<InputSection *, int> P : OrderedSections)
ISD->Sections.push_back(P.first);
for (InputSection *IS : makeArrayRef(UnorderedSections).slice(InsPt))
ISD->Sections.push_back(IS);
}
static void sortSection(OutputSection *Sec,
const DenseMap<const InputSectionBase *, int> &Order) {
StringRef Name = Sec->Name;
// Sort input sections by section name suffixes for
// __attribute__((init_priority(N))).
if (Name == ".init_array" || Name == ".fini_array") {
if (!Script->HasSectionsCommand)
Sec->sortInitFini();
return;
}
// Sort input sections by the special rule for .ctors and .dtors.
if (Name == ".ctors" || Name == ".dtors") {
if (!Script->HasSectionsCommand)
Sec->sortCtorsDtors();
return;
}
// Never sort these.
if (Name == ".init" || Name == ".fini")
return;
// Sort input sections by priority using the list provided
// by --symbol-ordering-file.
if (!Order.empty())
for (BaseCommand *B : Sec->SectionCommands)
if (auto *ISD = dyn_cast<InputSectionDescription>(B))
sortISDBySectionOrder(ISD, Order);
}
// If no layout was provided by linker script, we want to apply default
// sorting for special input sections. This also handles --symbol-ordering-file.
template <class ELFT> void Writer<ELFT>::sortInputSections() {
// Build the order once since it is expensive.
DenseMap<const InputSectionBase *, int> Order = buildSectionOrder();
for (BaseCommand *Base : Script->SectionCommands)
if (auto *Sec = dyn_cast<OutputSection>(Base))
sortSection(Sec, Order);
}
template <class ELFT> void Writer<ELFT>::sortSections() {
Script->adjustSectionsBeforeSorting();
// Don't sort if using -r. It is not necessary and we want to preserve the
// relative order for SHF_LINK_ORDER sections.
if (Config->Relocatable)
return;
sortInputSections();
for (BaseCommand *Base : Script->SectionCommands) {
auto *OS = dyn_cast<OutputSection>(Base);
if (!OS)
continue;
OS->SortRank = getSectionRank(OS);
// We want to assign rude approximation values to OutSecOff fields
// to know the relative order of the input sections. We use it for
// sorting SHF_LINK_ORDER sections. See resolveShfLinkOrder().
uint64_t I = 0;
for (InputSection *Sec : getInputSections(OS))
Sec->OutSecOff = I++;
}
if (!Script->HasSectionsCommand) {
// We know that all the OutputSections are contiguous in this case.
auto IsSection = [](BaseCommand *Base) { return isa<OutputSection>(Base); };
std::stable_sort(
llvm::find_if(Script->SectionCommands, IsSection),
llvm::find_if(llvm::reverse(Script->SectionCommands), IsSection).base(),
compareSections);
return;
}
// Orphan sections are sections present in the input files which are
// not explicitly placed into the output file by the linker script.
//
// The sections in the linker script are already in the correct
// order. We have to figuere out where to insert the orphan
// sections.
//
// The order of the sections in the script is arbitrary and may not agree with
// compareSections. This means that we cannot easily define a strict weak
// ordering. To see why, consider a comparison of a section in the script and
// one not in the script. We have a two simple options:
// * Make them equivalent (a is not less than b, and b is not less than a).
// The problem is then that equivalence has to be transitive and we can
// have sections a, b and c with only b in a script and a less than c
// which breaks this property.
// * Use compareSectionsNonScript. Given that the script order doesn't have
// to match, we can end up with sections a, b, c, d where b and c are in the
// script and c is compareSectionsNonScript less than b. In which case d
// can be equivalent to c, a to b and d < a. As a concrete example:
// .a (rx) # not in script
// .b (rx) # in script
// .c (ro) # in script
// .d (ro) # not in script
//
// The way we define an order then is:
// * Sort only the orphan sections. They are in the end right now.
// * Move each orphan section to its preferred position. We try
// to put each section in the last position where it can share
// a PT_LOAD.
//
// There is some ambiguity as to where exactly a new entry should be
// inserted, because Commands contains not only output section
// commands but also other types of commands such as symbol assignment
// expressions. There's no correct answer here due to the lack of the
// formal specification of the linker script. We use heuristics to
// determine whether a new output command should be added before or
// after another commands. For the details, look at shouldSkip
// function.
auto I = Script->SectionCommands.begin();
auto E = Script->SectionCommands.end();
auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) {
if (auto *Sec = dyn_cast<OutputSection>(Base))
return Sec->SectionIndex == UINT32_MAX;
return false;
});
// Sort the orphan sections.
std::stable_sort(NonScriptI, E, compareSections);
// As a horrible special case, skip the first . assignment if it is before any
// section. We do this because it is common to set a load address by starting
// the script with ". = 0xabcd" and the expectation is that every section is
// after that.
auto FirstSectionOrDotAssignment =
std::find_if(I, E, [](BaseCommand *Cmd) { return !shouldSkip(Cmd); });
if (FirstSectionOrDotAssignment != E &&
isa<SymbolAssignment>(**FirstSectionOrDotAssignment))
++FirstSectionOrDotAssignment;
I = FirstSectionOrDotAssignment;
while (NonScriptI != E) {
auto Pos = findOrphanPos<ELFT>(I, NonScriptI);
OutputSection *Orphan = cast<OutputSection>(*NonScriptI);
// As an optimization, find all sections with the same sort rank
// and insert them with one rotate.
unsigned Rank = Orphan->SortRank;
auto End = std::find_if(NonScriptI + 1, E, [=](BaseCommand *Cmd) {
return cast<OutputSection>(Cmd)->SortRank != Rank;
});
std::rotate(Pos, NonScriptI, End);
NonScriptI = End;
}
Script->adjustSectionsAfterSorting();
}
static bool compareByFilePosition(InputSection *A, InputSection *B) {
// Synthetic, i. e. a sentinel section, should go last.
if (A->kind() == InputSectionBase::Synthetic ||
B->kind() == InputSectionBase::Synthetic)
return A->kind() != InputSectionBase::Synthetic;
InputSection *LA = A->getLinkOrderDep();
InputSection *LB = B->getLinkOrderDep();
OutputSection *AOut = LA->getParent();
OutputSection *BOut = LB->getParent();
if (AOut != BOut)
return AOut->SectionIndex < BOut->SectionIndex;
return LA->OutSecOff < LB->OutSecOff;
}
// This function is used by the --merge-exidx-entries to detect duplicate
// .ARM.exidx sections. It is Arm only.
//
// The .ARM.exidx section is of the form:
// | PREL31 offset to function | Unwind instructions for function |
// where the unwind instructions are either a small number of unwind
// instructions inlined into the table entry, the special CANT_UNWIND value of
// 0x1 or a PREL31 offset into a .ARM.extab Section that contains unwind
// instructions.
//
// We return true if all the unwind instructions in the .ARM.exidx entries of
// Cur can be merged into the last entry of Prev.
static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) {
// References to .ARM.Extab Sections have bit 31 clear and are not the
// special EXIDX_CANTUNWIND bit-pattern.
auto IsExtabRef = [](uint32_t Unwind) {
return (Unwind & 0x80000000) == 0 && Unwind != 0x1;
};
struct ExidxEntry {
ulittle32_t Fn;
ulittle32_t Unwind;
};
// Get the last table Entry from the previous .ARM.exidx section.
const ExidxEntry &PrevEntry = Prev->getDataAs<ExidxEntry>().back();
if (IsExtabRef(PrevEntry.Unwind))
return false;
// We consider the unwind instructions of an .ARM.exidx table entry
// a duplicate if the previous unwind instructions if:
// - Both are the special EXIDX_CANTUNWIND.
// - Both are the same inline unwind instructions.
// We do not attempt to follow and check links into .ARM.extab tables as
// consecutive identical entries are rare and the effort to check that they
// are identical is high.
for (const ExidxEntry Entry : Cur->getDataAs<ExidxEntry>())
if (IsExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind)
return false;
// All table entries in this .ARM.exidx Section can be merged into the
// previous Section.
return true;
}
template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
for (OutputSection *Sec : OutputSections) {
if (!(Sec->Flags & SHF_LINK_ORDER))
continue;
// Link order may be distributed across several InputSectionDescriptions
// but sort must consider them all at once.
std::vector<InputSection **> ScriptSections;
std::vector<InputSection *> Sections;
for (BaseCommand *Base : Sec->SectionCommands) {
if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) {
for (InputSection *&IS : ISD->Sections) {
ScriptSections.push_back(&IS);
Sections.push_back(IS);
}
}
}
std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition);
if (!Config->Relocatable && Config->EMachine == EM_ARM &&
Sec->Type == SHT_ARM_EXIDX) {
if (auto *Sentinel = dyn_cast<ARMExidxSentinelSection>(Sections.back())) {
assert(Sections.size() >= 2 &&
"We should create a sentinel section only if there are "
"alive regular exidx sections.");
// The last executable section is required to fill the sentinel.
// Remember it here so that we don't have to find it again.
Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep();
}
// The EHABI for the Arm Architecture permits consecutive identical
// table entries to be merged. We use a simple implementation that
// removes a .ARM.exidx Input Section if it can be merged into the
// previous one. This does not require any rewriting of InputSection
// contents but misses opportunities for fine grained deduplication
// where only a subset of the InputSection contents can be merged.
if (Config->MergeArmExidx) {
size_t Prev = 0;
// The last one is a sentinel entry which should not be removed.
for (size_t I = 1; I < Sections.size() - 1; ++I) {
if (isDuplicateArmExidxSec(Sections[Prev], Sections[I]))
Sections[I] = nullptr;
else
Prev = I;
}
}
}
for (int I = 0, N = Sections.size(); I < N; ++I)
*ScriptSections[I] = Sections[I];
// Remove the Sections we marked as duplicate earlier.
for (BaseCommand *Base : Sec->SectionCommands)
if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
llvm::erase_if(ISD->Sections, [](InputSection *IS) { return !IS; });
}
}
// For most RISC ISAs, we need to generate content that depends on the address
// of InputSections. For example some architectures such as AArch64 use small
// displacements for jump instructions that is the linker's responsibility for
// creating range extension thunks for. As the generation of the content may
// also alter InputSection addresses we must converge to a fixed point.
template <class ELFT> void Writer<ELFT>::maybeAddThunks() {
if (!Target->NeedsThunks && !Config->AndroidPackDynRelocs &&
!Config->RelrPackDynRelocs)
return;
ThunkCreator TC;
AArch64Err843419Patcher A64P;
for (;;) {
bool Changed = false;
Script->assignAddresses();
if (Target->NeedsThunks)
Changed |= TC.createThunks(OutputSections);
if (Config->FixCortexA53Errata843419) {
if (Changed)
Script->assignAddresses();
Changed |= A64P.createFixes();
}
if (In.MipsGot)
In.MipsGot->updateAllocSize();
Changed |= In.RelaDyn->updateAllocSize();
if (In.RelrDyn)
Changed |= In.RelrDyn->updateAllocSize();
if (!Changed)
return;
}
}
static void finalizeSynthetic(SyntheticSection *Sec) {
if (Sec && !Sec->empty() && Sec->getParent())
Sec->finalizeContents();
}
// In order to allow users to manipulate linker-synthesized sections,
// we had to add synthetic sections to the input section list early,
// even before we make decisions whether they are needed. This allows
// users to write scripts like this: ".mygot : { .got }".
//
// Doing it has an unintended side effects. If it turns out that we
// don't need a .got (for example) at all because there's no
// relocation that needs a .got, we don't want to emit .got.
//
// To deal with the above problem, this function is called after
// scanRelocations is called to remove synthetic sections that turn
// out to be empty.
static void removeUnusedSyntheticSections() {
// All input synthetic sections that can be empty are placed after
// all regular ones. We iterate over them all and exit at first
// non-synthetic.
for (InputSectionBase *S : llvm::reverse(InputSections)) {
SyntheticSection *SS = dyn_cast<SyntheticSection>(S);
if (!SS)
return;
OutputSection *OS = SS->getParent();
if (!OS || !SS->empty())
continue;
// If we reach here, then SS is an unused synthetic section and we want to
// remove it from corresponding input section description of output section.
for (BaseCommand *B : OS->SectionCommands)
if (auto *ISD = dyn_cast<InputSectionDescription>(B))
llvm::erase_if(ISD->Sections,
[=](InputSection *IS) { return IS == SS; });
}
}
// Returns true if a symbol can be replaced at load-time by a symbol
// with the same name defined in other ELF executable or DSO.
static bool computeIsPreemptible(const Symbol &B) {
assert(!B.isLocal());
// Only symbols that appear in dynsym can be preempted.
if (!B.includeInDynsym())
return false;
// Only default visibility symbols can be preempted.
if (B.Visibility != STV_DEFAULT)
return false;
// At this point copy relocations have not been created yet, so any
// symbol that is not defined locally is preemptible.
if (!B.isDefined())
return true;
// If we have a dynamic list it specifies which local symbols are preemptible.
if (Config->HasDynamicList)
return false;
if (!Config->Shared)
return false;
// -Bsymbolic means that definitions are not preempted.
if (Config->Bsymbolic || (Config->BsymbolicFunctions && B.isFunc()))
return false;
return true;
}
// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::finalizeSections() {
Out::PreinitArray = findSection(".preinit_array");
Out::InitArray = findSection(".init_array");
Out::FiniArray = findSection(".fini_array");
// The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
// symbols for sections, so that the runtime can get the start and end
// addresses of each section by section name. Add such symbols.
if (!Config->Relocatable) {
addStartEndSymbols();
for (BaseCommand *Base : Script->SectionCommands)
if (auto *Sec = dyn_cast<OutputSection>(Base))
addStartStopSymbols(Sec);
}
// Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type.
// It should be okay as no one seems to care about the type.
// Even the author of gold doesn't remember why gold behaves that way.
// https://sourceware.org/ml/binutils/2002-03/msg00360.html
if (In.Dynamic->Parent)
Symtab->addDefined("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/,
/*Size=*/0, STB_WEAK, In.Dynamic,
/*File=*/nullptr);
// Define __rel[a]_iplt_{start,end} symbols if needed.
addRelIpltSymbols();
// RISC-V's gp can address +/- 2 KiB, set it to .sdata + 0x800 if not defined.
if (Config->EMachine == EM_RISCV)
if (!dyn_cast_or_null<Defined>(Symtab->find("__global_pointer$")))
addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800);
// This responsible for splitting up .eh_frame section into
// pieces. The relocation scan uses those pieces, so this has to be
// earlier.
finalizeSynthetic(In.EhFrame);
for (Symbol *S : Symtab->getSymbols()) {
if (!S->IsPreemptible)
S->IsPreemptible = computeIsPreemptible(*S);
if (S->isGnuIFunc() && Config->ZIfuncnoplt)
S->ExportDynamic = true;
}
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
if (!Config->Relocatable)
forEachRelSec(scanRelocations<ELFT>);
if (In.Plt && !In.Plt->empty())
In.Plt->addSymbols();
if (In.Iplt && !In.Iplt->empty())
In.Iplt->addSymbols();
if (!Config->AllowShlibUndefined) {
// Error on undefined symbols in a shared object, if all of its DT_NEEDED
// entires are seen. These cases would otherwise lead to runtime errors
// reported by the dynamic linker.
//
// ld.bfd traces all DT_NEEDED to emulate the logic of the dynamic linker to
// catch more cases. That is too much for us. Our approach resembles the one
// used in ld.gold, achieves a good balance to be useful but not too smart.
for (InputFile *File : SharedFiles) {
SharedFile<ELFT> *F = cast<SharedFile<ELFT>>(File);
F->AllNeededIsKnown = llvm::all_of(F->DtNeeded, [&](StringRef Needed) {
return Symtab->SoNames.count(Needed);
});
}
for (Symbol *Sym : Symtab->getSymbols())
if (Sym->isUndefined() && !Sym->isWeak())
if (auto *F = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File))
if (F->AllNeededIsKnown)
error(toString(F) + ": undefined reference to " + toString(*Sym));
}
// Now that we have defined all possible global symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
for (Symbol *Sym : Symtab->getSymbols()) {
if (!includeInSymtab(*Sym))
continue;
if (In.SymTab)
In.SymTab->addSymbol(Sym);
if (Sym->includeInDynsym()) {
In.DynSymTab->addSymbol(Sym);
if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File))
if (File->IsNeeded && !Sym->isUndefined())
InX<ELFT>::VerNeed->addSymbol(Sym);
}
}
// Do not proceed if there was an undefined symbol.
if (errorCount())
return;
if (In.MipsGot)
In.MipsGot->build<ELFT>();
removeUnusedSyntheticSections();
sortSections();
// Now that we have the final list, create a list of all the
// OutputSections for convenience.
for (BaseCommand *Base : Script->SectionCommands)
if (auto *Sec = dyn_cast<OutputSection>(Base))
OutputSections.push_back(Sec);
// Prefer command line supplied address over other constraints.
for (OutputSection *Sec : OutputSections) {
auto I = Config->SectionStartMap.find(Sec->Name);
if (I != Config->SectionStartMap.end())
Sec->AddrExpr = [=] { return I->second; };
}
// This is a bit of a hack. A value of 0 means undef, so we set it
// to 1 to make __ehdr_start defined. The section number is not
// particularly relevant.
Out::ElfHeader->SectionIndex = 1;
for (size_t I = 0, E = OutputSections.size(); I != E; ++I) {
OutputSection *Sec = OutputSections[I];
Sec->SectionIndex = I + 1;
Sec->ShName = In.ShStrTab->addString(Sec->Name);
}
// Binary and relocatable output does not have PHDRS.
// The headers have to be created before finalize as that can influence the
// image base and the dynamic section on mips includes the image base.
if (!Config->Relocatable && !Config->OFormatBinary) {
Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() : createPhdrs();
addPtArmExid(Phdrs);
Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size();
// Find the TLS segment. This happens before the section layout loop so that
// Android relocation packing can look up TLS symbol addresses.
for (PhdrEntry *P : Phdrs)
if (P->p_type == PT_TLS)
Out::TlsPhdr = P;
}
// Some symbols are defined in term of program headers. Now that we
// have the headers, we can find out which sections they point to.
setReservedSymbolSections();
// Dynamic section must be the last one in this list and dynamic
// symbol table section (DynSymTab) must be the first one.
finalizeSynthetic(In.DynSymTab);
finalizeSynthetic(In.Bss);
finalizeSynthetic(In.BssRelRo);
finalizeSynthetic(In.GnuHashTab);
finalizeSynthetic(In.HashTab);
finalizeSynthetic(In.SymTabShndx);
finalizeSynthetic(In.ShStrTab);
finalizeSynthetic(In.StrTab);
finalizeSynthetic(In.VerDef);
finalizeSynthetic(In.DynStrTab);
finalizeSynthetic(In.Got);
finalizeSynthetic(In.MipsGot);
finalizeSynthetic(In.IgotPlt);
finalizeSynthetic(In.GotPlt);
finalizeSynthetic(In.RelaDyn);
finalizeSynthetic(In.RelrDyn);
finalizeSynthetic(In.RelaIplt);
finalizeSynthetic(In.RelaPlt);
finalizeSynthetic(In.Plt);
finalizeSynthetic(In.Iplt);
finalizeSynthetic(In.EhFrameHdr);
finalizeSynthetic(InX<ELFT>::VerSym);
finalizeSynthetic(InX<ELFT>::VerNeed);
finalizeSynthetic(In.Dynamic);
if (!Script->HasSectionsCommand && !Config->Relocatable)
fixSectionAlignments();
// After link order processing .ARM.exidx sections can be deduplicated, which
// needs to be resolved before any other address dependent operation.
resolveShfLinkOrder();
// Jump instructions in many ISAs have small displacements, and therefore they
// cannot jump to arbitrary addresses in memory. For example, RISC-V JAL
// instruction can target only +-1 MiB from PC. It is a linker's
// responsibility to create and insert small pieces of code between sections
// to extend the ranges if jump targets are out of range. Such code pieces are
// called "thunks".
//
// We add thunks at this stage. We couldn't do this before this point because
// this is the earliest point where we know sizes of sections and their
// layouts (that are needed to determine if jump targets are in range).
maybeAddThunks();
// maybeAddThunks may have added local symbols to the static symbol table.
finalizeSynthetic(In.SymTab);
finalizeSynthetic(In.PPC64LongBranchTarget);
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
// of finalizing other sections.
for (OutputSection *Sec : OutputSections)
Sec->finalize<ELFT>();
}
// Ensure data sections are not mixed with executable sections when
// -execute-only is used. -execute-only is a feature to make pages executable
// but not readable, and the feature is currently supported only on AArch64.
template <class ELFT> void Writer<ELFT>::checkExecuteOnly() {
if (!Config->ExecuteOnly)
return;
for (OutputSection *OS : OutputSections)
if (OS->Flags & SHF_EXECINSTR)
for (InputSection *IS : getInputSections(OS))
if (!(IS->Flags & SHF_EXECINSTR))
error("cannot place " + toString(IS) + " into " + toString(OS->Name) +
": -execute-only does not support intermingling data and code");
}
// The linker is expected to define SECNAME_start and SECNAME_end
// symbols for a few sections. This function defines them.
template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
// If a section does not exist, there's ambiguity as to how we
// define _start and _end symbols for an init/fini section. Since
// the loader assume that the symbols are always defined, we need to
// always define them. But what value? The loader iterates over all
// pointers between _start and _end to run global ctors/dtors, so if
// the section is empty, their symbol values don't actually matter
// as long as _start and _end point to the same location.
//
// That said, we don't want to set the symbols to 0 (which is
// probably the simplest value) because that could cause some
// program to fail to link due to relocation overflow, if their
// program text is above 2 GiB. We use the address of the .text
// section instead to prevent that failure.
//
// In a rare sitaution, .text section may not exist. If that's the
// case, use the image base address as a last resort.
OutputSection *Default = findSection(".text");
if (!Default)
Default = Out::ElfHeader;
auto Define = [=](StringRef Start, StringRef End, OutputSection *OS) {
if (OS) {
addOptionalRegular(Start, OS, 0);
addOptionalRegular(End, OS, -1);
} else {
addOptionalRegular(Start, Default, 0);
addOptionalRegular(End, Default, 0);
}
};
Define("__preinit_array_start", "__preinit_array_end", Out::PreinitArray);
Define("__init_array_start", "__init_array_end", Out::InitArray);
Define("__fini_array_start", "__fini_array_end", Out::FiniArray);
if (OutputSection *Sec = findSection(".ARM.exidx"))
Define("__exidx_start", "__exidx_end", Sec);
}
// If a section name is valid as a C identifier (which is rare because of
// the leading '.'), linkers are expected to define __start_<secname> and
// __stop_<secname> symbols. They are at beginning and end of the section,
// respectively. This is not requested by the ELF standard, but GNU ld and
// gold provide the feature, and used by many programs.
template <class ELFT>
void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
StringRef S = Sec->Name;
if (!isValidCIdentifier(S))
return;
addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_PROTECTED);
addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_PROTECTED);
}
static bool needsPtLoad(OutputSection *Sec) {
if (!(Sec->Flags & SHF_ALLOC) || Sec->Noload)
return false;
// Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
// responsible for allocating space for them, not the PT_LOAD that
// contains the TLS initialization image.
if ((Sec->Flags & SHF_TLS) && Sec->Type == SHT_NOBITS)
return false;
return true;
}
// Linker scripts are responsible for aligning addresses. Unfortunately, most
// linker scripts are designed for creating two PT_LOADs only, one RX and one
// RW. This means that there is no alignment in the RO to RX transition and we
// cannot create a PT_LOAD there.
static uint64_t computeFlags(uint64_t Flags) {
if (Config->Omagic)
return PF_R | PF_W | PF_X;
if (Config->ExecuteOnly && (Flags & PF_X))
return Flags & ~PF_R;
if (Config->SingleRoRx && !(Flags & PF_W))
return Flags | PF_X;
return Flags;
}
// Decide which program headers to create and which sections to include in each
// one.
template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
std::vector<PhdrEntry *> Ret;
auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * {
Ret.push_back(make<PhdrEntry>(Type, Flags));
return Ret.back();
};
// The first phdr entry is PT_PHDR which describes the program header itself.
AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders);
// PT_INTERP must be the second entry if exists.
if (OutputSection *Cmd = findSection(".interp"))
AddHdr(PT_INTERP, Cmd->getPhdrFlags())->add(Cmd);
// Add the first PT_LOAD segment for regular output sections.
uint64_t Flags = computeFlags(PF_R);
PhdrEntry *Load = AddHdr(PT_LOAD, Flags);
// Add the headers. We will remove them if they don't fit.
Load->add(Out::ElfHeader);
Load->add(Out::ProgramHeaders);
for (OutputSection *Sec : OutputSections) {
if (!(Sec->Flags & SHF_ALLOC))
break;
if (!needsPtLoad(Sec))
continue;
// Segments are contiguous memory regions that has the same attributes
// (e.g. executable or writable). There is one phdr for each segment.
// Therefore, we need to create a new phdr when the next section has
// different flags or is loaded at a discontiguous address or memory
// region using AT or AT> linker script command, respectively. At the same
// time, we don't want to create a separate load segment for the headers,
// even if the first output section has an AT or AT> attribute.
uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
if (((Sec->LMAExpr ||
(Sec->LMARegion && (Sec->LMARegion != Load->FirstSec->LMARegion))) &&
Load->LastSec != Out::ProgramHeaders) ||
Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags) {
Load = AddHdr(PT_LOAD, NewFlags);
Flags = NewFlags;
}
Load->add(Sec);
}
// Add a TLS segment if any.
PhdrEntry *TlsHdr = make<PhdrEntry>(PT_TLS, PF_R);
for (OutputSection *Sec : OutputSections)
if (Sec->Flags & SHF_TLS)
TlsHdr->add(Sec);
if (TlsHdr->FirstSec)
Ret.push_back(TlsHdr);
// Add an entry for .dynamic.
if (OutputSection *Sec = In.Dynamic->getParent())
AddHdr(PT_DYNAMIC, Sec->getPhdrFlags())->add(Sec);
// PT_GNU_RELRO includes all sections that should be marked as
// read-only by dynamic linker after proccessing relocations.
// Current dynamic loaders only support one PT_GNU_RELRO PHDR, give
// an error message if more than one PT_GNU_RELRO PHDR is required.
PhdrEntry *RelRo = make<PhdrEntry>(PT_GNU_RELRO, PF_R);
bool InRelroPhdr = false;
bool IsRelroFinished = false;
for (OutputSection *Sec : OutputSections) {
if (!needsPtLoad(Sec))
continue;
if (isRelroSection(Sec)) {
InRelroPhdr = true;
if (!IsRelroFinished)
RelRo->add(Sec);
else
error("section: " + Sec->Name + " is not contiguous with other relro" +
" sections");
} else if (InRelroPhdr) {
InRelroPhdr = false;
IsRelroFinished = true;
}
}
if (RelRo->FirstSec)
Ret.push_back(RelRo);
// PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
if (!In.EhFrame->empty() && In.EhFrameHdr && In.EhFrame->getParent() &&
In.EhFrameHdr->getParent())
AddHdr(PT_GNU_EH_FRAME, In.EhFrameHdr->getParent()->getPhdrFlags())
->add(In.EhFrameHdr->getParent());
// PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes
// the dynamic linker fill the segment with random data.
if (OutputSection *Cmd = findSection(".openbsd.randomdata"))
AddHdr(PT_OPENBSD_RANDOMIZE, Cmd->getPhdrFlags())->add(Cmd);
// PT_GNU_STACK is a special section to tell the loader to make the
// pages for the stack non-executable. If you really want an executable
// stack, you can pass -z execstack, but that's not recommended for
// security reasons.
unsigned Perm = PF_R | PF_W;
if (Config->ZExecstack)
Perm |= PF_X;
AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize;
// PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable
// is expected to perform W^X violations, such as calling mprotect(2) or
// mmap(2) with PROT_WRITE | PROT_EXEC, which is prohibited by default on
// OpenBSD.
if (Config->ZWxneeded)
AddHdr(PT_OPENBSD_WXNEEDED, PF_X);
// Create one PT_NOTE per a group of contiguous .note sections.
PhdrEntry *Note = nullptr;
for (OutputSection *Sec : OutputSections) {
if (Sec->Type == SHT_NOTE && (Sec->Flags & SHF_ALLOC)) {
if (!Note || Sec->LMAExpr)
Note = AddHdr(PT_NOTE, PF_R);
Note->add(Sec);
} else {
Note = nullptr;
}
}
return Ret;
}
template <class ELFT>
void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry *> &Phdrs) {
if (Config->EMachine != EM_ARM)
return;
auto I = llvm::find_if(OutputSections, [](OutputSection *Cmd) {
return Cmd->Type == SHT_ARM_EXIDX;
});
if (I == OutputSections.end())
return;
// PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME
PhdrEntry *ARMExidx = make<PhdrEntry>(PT_ARM_EXIDX, PF_R);
ARMExidx->add(*I);
Phdrs.push_back(ARMExidx);
}
// The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the
// first section after PT_GNU_RELRO have to be page aligned so that the dynamic
// linker can set the permissions.
template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
auto PageAlign = [](OutputSection *Cmd) {
if (Cmd && !Cmd->AddrExpr)
Cmd->AddrExpr = [=] {
return alignTo(Script->getDot(), Config->MaxPageSize);
};
};
for (const PhdrEntry *P : Phdrs)
if (P->p_type == PT_LOAD && P->FirstSec)
PageAlign(P->FirstSec);
for (const PhdrEntry *P : Phdrs) {
if (P->p_type != PT_GNU_RELRO)
continue;
if (P->FirstSec)
PageAlign(P->FirstSec);
// Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we
// have to align it to a page.
auto End = OutputSections.end();
auto I = std::find(OutputSections.begin(), End, P->LastSec);
if (I == End || (I + 1) == End)
continue;
OutputSection *Cmd = (*(I + 1));
if (needsPtLoad(Cmd))
PageAlign(Cmd);
}
}
// Compute an in-file position for a given section. The file offset must be the
// same with its virtual address modulo the page size, so that the loader can
// load executables without any address adjustment.
static uint64_t computeFileOffset(OutputSection *OS, uint64_t Off) {
// File offsets are not significant for .bss sections. By convention, we keep
// section offsets monotonically increasing rather than setting to zero.
if (OS->Type == SHT_NOBITS)
return Off;
// If the section is not in a PT_LOAD, we just have to align it.
if (!OS->PtLoad)
return alignTo(Off, OS->Alignment);
// The first section in a PT_LOAD has to have congruent offset and address
// module the page size.
OutputSection *First = OS->PtLoad->FirstSec;
if (OS == First) {
uint64_t Alignment = std::max<uint64_t>(OS->Alignment, Config->MaxPageSize);
return alignTo(Off, Alignment, OS->Addr);
}
// If two sections share the same PT_LOAD the file offset is calculated
// using this formula: Off2 = Off1 + (VA2 - VA1).
return First->Offset + OS->Addr - First->Addr;
}
// Set an in-file position to a given section and returns the end position of
// the section.
static uint64_t setFileOffset(OutputSection *OS, uint64_t Off) {
Off = computeFileOffset(OS, Off);
OS->Offset = Off;
if (OS->Type == SHT_NOBITS)
return Off;
return Off + OS->Size;
}
template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
uint64_t Off = 0;
for (OutputSection *Sec : OutputSections)
if (Sec->Flags & SHF_ALLOC)
Off = setFileOffset(Sec, Off);
FileSize = alignTo(Off, Config->Wordsize);
}
static std::string rangeToString(uint64_t Addr, uint64_t Len) {
return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]";
}
// Assign file offsets to output sections.
template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
uint64_t Off = 0;
Off = setFileOffset(Out::ElfHeader, Off);
Off = setFileOffset(Out::ProgramHeaders, Off);
PhdrEntry *LastRX = nullptr;
for (PhdrEntry *P : Phdrs)
if (P->p_type == PT_LOAD && (P->p_flags & PF_X))
LastRX = P;
for (OutputSection *Sec : OutputSections) {
Off = setFileOffset(Sec, Off);
if (Script->HasSectionsCommand)
continue;
// If this is a last section of the last executable segment and that
// segment is the last loadable segment, align the offset of the
// following section to avoid loading non-segments parts of the file.
if (LastRX && LastRX->LastSec == Sec)
Off = alignTo(Off, Target->PageSize);
}
SectionHeaderOff = alignTo(Off, Config->Wordsize);
FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
// Our logic assumes that sections have rising VA within the same segment.
// With use of linker scripts it is possible to violate this rule and get file
// offset overlaps or overflows. That should never happen with a valid script
// which does not move the location counter backwards and usually scripts do
// not do that. Unfortunately, there are apps in the wild, for example, Linux
// kernel, which control segment distribution explicitly and move the counter
// backwards, so we have to allow doing that to support linking them. We
// perform non-critical checks for overlaps in checkSectionOverlap(), but here
// we want to prevent file size overflows because it would crash the linker.
for (OutputSection *Sec : OutputSections) {
if (Sec->Type == SHT_NOBITS)
continue;
if ((Sec->Offset > FileSize) || (Sec->Offset + Sec->Size > FileSize))
error("unable to place section " + Sec->Name + " at file offset " +
rangeToString(Sec->Offset, Sec->Size) +
"; check your linker script for overflows");
}
}
// Finalize the program headers. We call this function after we assign
// file offsets and VAs to all sections.
template <class ELFT> void Writer<ELFT>::setPhdrs() {
for (PhdrEntry *P : Phdrs) {
OutputSection *First = P->FirstSec;
OutputSection *Last = P->LastSec;
if (First) {
P->p_filesz = Last->Offset - First->Offset;
if (Last->Type != SHT_NOBITS)
P->p_filesz += Last->Size;
P->p_memsz = Last->Addr + Last->Size - First->Addr;
P->p_offset = First->Offset;
P->p_vaddr = First->Addr;
if (!P->HasLMA)
P->p_paddr = First->getLMA();
}
if (P->p_type == PT_LOAD) {
P->p_align = std::max<uint64_t>(P->p_align, Config->MaxPageSize);
} else if (P->p_type == PT_GNU_RELRO) {
P->p_align = 1;
// The glibc dynamic loader rounds the size down, so we need to round up
// to protect the last page. This is a no-op on FreeBSD which always
// rounds up.
P->p_memsz = alignTo(P->p_memsz, Target->PageSize);
}
if (P->p_type == PT_TLS && P->p_memsz) {
- if (!Config->Shared &&
- (Config->EMachine == EM_ARM || Config->EMachine == EM_AARCH64)) {
- // On ARM/AArch64, reserve extra space (8 words) between the thread
- // pointer and an executable's TLS segment by overaligning the segment.
- // This reservation is needed for backwards compatibility with Android's
- // TCB, which allocates several slots after the thread pointer (e.g.
- // TLS_SLOT_STACK_GUARD==5). For simplicity, this overalignment is also
- // done on other operating systems.
- P->p_align = std::max<uint64_t>(P->p_align, Config->Wordsize * 8);
- }
-
// The TLS pointer goes after PT_TLS for variant 2 targets. At least glibc
// will align it, so round up the size to make sure the offsets are
// correct.
P->p_memsz = alignTo(P->p_memsz, P->p_align);
}
}
}
// A helper struct for checkSectionOverlap.
namespace {
struct SectionOffset {
OutputSection *Sec;
uint64_t Offset;
};
} // namespace
// Check whether sections overlap for a specific address range (file offsets,
// load and virtual adresses).
static void checkOverlap(StringRef Name, std::vector<SectionOffset> &Sections,
bool IsVirtualAddr) {
llvm::sort(Sections, [=](const SectionOffset &A, const SectionOffset &B) {
return A.Offset < B.Offset;
});
// Finding overlap is easy given a vector is sorted by start position.
// If an element starts before the end of the previous element, they overlap.
for (size_t I = 1, End = Sections.size(); I < End; ++I) {
SectionOffset A = Sections[I - 1];
SectionOffset B = Sections[I];
if (B.Offset >= A.Offset + A.Sec->Size)
continue;
// If both sections are in OVERLAY we allow the overlapping of virtual
// addresses, because it is what OVERLAY was designed for.
if (IsVirtualAddr && A.Sec->InOverlay && B.Sec->InOverlay)
continue;
errorOrWarn("section " + A.Sec->Name + " " + Name +
" range overlaps with " + B.Sec->Name + "\n>>> " + A.Sec->Name +
" range is " + rangeToString(A.Offset, A.Sec->Size) + "\n>>> " +
B.Sec->Name + " range is " +
rangeToString(B.Offset, B.Sec->Size));
}
}
// Check for overlapping sections and address overflows.
//
// In this function we check that none of the output sections have overlapping
// file offsets. For SHF_ALLOC sections we also check that the load address
// ranges and the virtual address ranges don't overlap
template <class ELFT> void Writer<ELFT>::checkSections() {
// First, check that section's VAs fit in available address space for target.
for (OutputSection *OS : OutputSections)
if ((OS->Addr + OS->Size < OS->Addr) ||
(!ELFT::Is64Bits && OS->Addr + OS->Size > UINT32_MAX))
errorOrWarn("section " + OS->Name + " at 0x" + utohexstr(OS->Addr) +
" of size 0x" + utohexstr(OS->Size) +
" exceeds available address space");
// Check for overlapping file offsets. In this case we need to skip any
// section marked as SHT_NOBITS. These sections don't actually occupy space in
// the file so Sec->Offset + Sec->Size can overlap with others. If --oformat
// binary is specified only add SHF_ALLOC sections are added to the output
// file so we skip any non-allocated sections in that case.
std::vector<SectionOffset> FileOffs;
for (OutputSection *Sec : OutputSections)
if (Sec->Size > 0 && Sec->Type != SHT_NOBITS &&
(!Config->OFormatBinary || (Sec->Flags & SHF_ALLOC)))
FileOffs.push_back({Sec, Sec->Offset});
checkOverlap("file", FileOffs, false);
// When linking with -r there is no need to check for overlapping virtual/load
// addresses since those addresses will only be assigned when the final
// executable/shared object is created.
if (Config->Relocatable)
return;
// Checking for overlapping virtual and load addresses only needs to take
// into account SHF_ALLOC sections since others will not be loaded.
// Furthermore, we also need to skip SHF_TLS sections since these will be
// mapped to other addresses at runtime and can therefore have overlapping
// ranges in the file.
std::vector<SectionOffset> VMAs;
for (OutputSection *Sec : OutputSections)
if (Sec->Size > 0 && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
VMAs.push_back({Sec, Sec->Addr});
checkOverlap("virtual address", VMAs, true);
// Finally, check that the load addresses don't overlap. This will usually be
// the same as the virtual addresses but can be different when using a linker
// script with AT().
std::vector<SectionOffset> LMAs;
for (OutputSection *Sec : OutputSections)
if (Sec->Size > 0 && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
LMAs.push_back({Sec, Sec->getLMA()});
checkOverlap("load address", LMAs, false);
}
// The entry point address is chosen in the following ways.
//
// 1. the '-e' entry command-line option;
// 2. the ENTRY(symbol) command in a linker control script;
// 3. the value of the symbol _start, if present;
// 4. the number represented by the entry symbol, if it is a number;
// 5. the address of the first byte of the .text section, if present;
// 6. the address 0.
static uint64_t getEntryAddr() {
// Case 1, 2 or 3
if (Symbol *B = Symtab->find(Config->Entry))
return B->getVA();
// Case 4
uint64_t Addr;
if (to_integer(Config->Entry, Addr))
return Addr;
// Case 5
if (OutputSection *Sec = findSection(".text")) {
if (Config->WarnMissingEntry)
warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" +
utohexstr(Sec->Addr));
return Sec->Addr;
}
// Case 6
if (Config->WarnMissingEntry)
warn("cannot find entry symbol " + Config->Entry +
"; not setting start address");
return 0;
}
static uint16_t getELFType() {
if (Config->Pic)
return ET_DYN;
if (Config->Relocatable)
return ET_REL;
return ET_EXEC;
}
static uint8_t getAbiVersion() {
// MIPS non-PIC executable gets ABI version 1.
if (Config->EMachine == EM_MIPS && getELFType() == ET_EXEC &&
(Config->EFlags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC)
return 1;
return 0;
}
template <class ELFT> void Writer<ELFT>::writeHeader() {
uint8_t *Buf = Buffer->getBufferStart();
// For executable segments, the trap instructions are written before writing
// the header. Setting Elf header bytes to zero ensures that any unused bytes
// in header are zero-cleared, instead of having trap instructions.
memset(Buf, 0, sizeof(Elf_Ehdr));
memcpy(Buf, "\177ELF", 4);
// Write the ELF header.
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32;
EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB;
EHdr->e_ident[EI_VERSION] = EV_CURRENT;
EHdr->e_ident[EI_OSABI] = Config->OSABI;
EHdr->e_ident[EI_ABIVERSION] = getAbiVersion();
EHdr->e_type = getELFType();
EHdr->e_machine = Config->EMachine;
EHdr->e_version = EV_CURRENT;
EHdr->e_entry = getEntryAddr();
EHdr->e_shoff = SectionHeaderOff;
EHdr->e_flags = Config->EFlags;
EHdr->e_ehsize = sizeof(Elf_Ehdr);
EHdr->e_phnum = Phdrs.size();
EHdr->e_shentsize = sizeof(Elf_Shdr);
if (!Config->Relocatable) {
EHdr->e_phoff = sizeof(Elf_Ehdr);
EHdr->e_phentsize = sizeof(Elf_Phdr);
}
// Write the program header table.
auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
for (PhdrEntry *P : Phdrs) {
HBuf->p_type = P->p_type;
HBuf->p_flags = P->p_flags;
HBuf->p_offset = P->p_offset;
HBuf->p_vaddr = P->p_vaddr;
HBuf->p_paddr = P->p_paddr;
HBuf->p_filesz = P->p_filesz;
HBuf->p_memsz = P->p_memsz;
HBuf->p_align = P->p_align;
++HBuf;
}
// Write the section header table.
//
// The ELF header can only store numbers up to SHN_LORESERVE in the e_shnum
// and e_shstrndx fields. When the value of one of these fields exceeds
// SHN_LORESERVE ELF requires us to put sentinel values in the ELF header and
// use fields in the section header at index 0 to store
// the value. The sentinel values and fields are:
// e_shnum = 0, SHdrs[0].sh_size = number of sections.
// e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index.
auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
size_t Num = OutputSections.size() + 1;
if (Num >= SHN_LORESERVE)
SHdrs->sh_size = Num;
else
EHdr->e_shnum = Num;
uint32_t StrTabIndex = In.ShStrTab->getParent()->SectionIndex;
if (StrTabIndex >= SHN_LORESERVE) {
SHdrs->sh_link = StrTabIndex;
EHdr->e_shstrndx = SHN_XINDEX;
} else {
EHdr->e_shstrndx = StrTabIndex;
}
for (OutputSection *Sec : OutputSections)
Sec->writeHeaderTo<ELFT>(++SHdrs);
}
// Open a result file.
template <class ELFT> void Writer<ELFT>::openFile() {
uint64_t MaxSize = Config->Is64 ? INT64_MAX : UINT32_MAX;
if (MaxSize < FileSize) {
error("output file too large: " + Twine(FileSize) + " bytes");
return;
}
unlinkAsync(Config->OutputFile);
unsigned Flags = 0;
if (!Config->Relocatable)
Flags = FileOutputBuffer::F_executable;
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
FileOutputBuffer::create(Config->OutputFile, FileSize, Flags);
if (!BufferOrErr)
error("failed to open " + Config->OutputFile + ": " +
llvm::toString(BufferOrErr.takeError()));
else
Buffer = std::move(*BufferOrErr);
}
template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
uint8_t *Buf = Buffer->getBufferStart();
for (OutputSection *Sec : OutputSections)
if (Sec->Flags & SHF_ALLOC)
Sec->writeTo<ELFT>(Buf + Sec->Offset);
}
static void fillTrap(uint8_t *I, uint8_t *End) {
for (; I + 4 <= End; I += 4)
memcpy(I, &Target->TrapInstr, 4);
}
// Fill the last page of executable segments with trap instructions
// instead of leaving them as zero. Even though it is not required by any
// standard, it is in general a good thing to do for security reasons.
//
// We'll leave other pages in segments as-is because the rest will be
// overwritten by output sections.
template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
if (Script->HasSectionsCommand)
return;
// Fill the last page.
uint8_t *Buf = Buffer->getBufferStart();
for (PhdrEntry *P : Phdrs)
if (P->p_type == PT_LOAD && (P->p_flags & PF_X))
fillTrap(Buf + alignDown(P->p_offset + P->p_filesz, Target->PageSize),
Buf + alignTo(P->p_offset + P->p_filesz, Target->PageSize));
// Round up the file size of the last segment to the page boundary iff it is
// an executable segment to ensure that other tools don't accidentally
// trim the instruction padding (e.g. when stripping the file).
PhdrEntry *Last = nullptr;
for (PhdrEntry *P : Phdrs)
if (P->p_type == PT_LOAD)
Last = P;
if (Last && (Last->p_flags & PF_X))
Last->p_memsz = Last->p_filesz = alignTo(Last->p_filesz, Target->PageSize);
}
// Write section contents to a mmap'ed file.
template <class ELFT> void Writer<ELFT>::writeSections() {
uint8_t *Buf = Buffer->getBufferStart();
OutputSection *EhFrameHdr = nullptr;
if (In.EhFrameHdr && !In.EhFrameHdr->empty())
EhFrameHdr = In.EhFrameHdr->getParent();
// In -r or -emit-relocs mode, write the relocation sections first as in
// ELf_Rel targets we might find out that we need to modify the relocated
// section while doing it.
for (OutputSection *Sec : OutputSections)
if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
Sec->writeTo<ELFT>(Buf + Sec->Offset);
for (OutputSection *Sec : OutputSections)
if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA)
Sec->writeTo<ELFT>(Buf + Sec->Offset);
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
// it should be written after .eh_frame is written.
if (EhFrameHdr)
EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
}
template <class ELFT> void Writer<ELFT>::writeBuildId() {
if (!In.BuildId || !In.BuildId->getParent())
return;
// Compute a hash of all sections of the output file.
uint8_t *Start = Buffer->getBufferStart();
uint8_t *End = Start + FileSize;
In.BuildId->writeBuildId({Start, End});
}
template void elf::writeResult<ELF32LE>();
template void elf::writeResult<ELF32BE>();
template void elf::writeResult<ELF64LE>();
template void elf::writeResult<ELF64BE>();
Index: stable/11/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp
===================================================================
--- stable/11/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp (revision 350258)
+++ stable/11/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp (revision 350259)
@@ -1,2528 +1,2546 @@
//===-- llvm-objdump.cpp - Object file dumping utility for llvm -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This program is a utility that works like binutils "objdump", that is, it
// dumps out a plethora of information about an object file depending on the
// flags.
//
// The flags and output of this program should be near identical to those of
// binutils objdump.
//
//===----------------------------------------------------------------------===//
#include "llvm-objdump.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Triple.h"
#include "llvm/CodeGen/FaultMaps.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
#include "llvm/MC/MCDisassembler/MCRelocationInfo.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/Wasm.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cctype>
#include <cstring>
#include <system_error>
#include <unordered_map>
#include <utility>
using namespace llvm;
using namespace object;
cl::opt<bool>
llvm::AllHeaders("all-headers",
cl::desc("Display all available header information"));
static cl::alias AllHeadersShort("x", cl::desc("Alias for --all-headers"),
cl::aliasopt(AllHeaders));
static cl::list<std::string>
InputFilenames(cl::Positional, cl::desc("<input object files>"),cl::ZeroOrMore);
cl::opt<bool>
llvm::Disassemble("disassemble",
cl::desc("Display assembler mnemonics for the machine instructions"));
static cl::alias
Disassembled("d", cl::desc("Alias for --disassemble"),
cl::aliasopt(Disassemble));
cl::opt<bool>
llvm::DisassembleAll("disassemble-all",
cl::desc("Display assembler mnemonics for the machine instructions"));
static cl::alias
DisassembleAlld("D", cl::desc("Alias for --disassemble-all"),
cl::aliasopt(DisassembleAll));
cl::opt<bool> llvm::Demangle("demangle", cl::desc("Demangle symbols names"),
cl::init(false));
static cl::alias DemangleShort("C", cl::desc("Alias for --demangle"),
cl::aliasopt(llvm::Demangle));
static cl::list<std::string>
DisassembleFunctions("df",
cl::CommaSeparated,
cl::desc("List of functions to disassemble"));
static StringSet<> DisasmFuncsSet;
cl::opt<bool>
llvm::Relocations("reloc",
cl::desc("Display the relocation entries in the file"));
static cl::alias RelocationsShort("r", cl::desc("Alias for --reloc"),
cl::NotHidden,
cl::aliasopt(llvm::Relocations));
cl::opt<bool>
llvm::DynamicRelocations("dynamic-reloc",
cl::desc("Display the dynamic relocation entries in the file"));
static cl::alias
DynamicRelocationsd("R", cl::desc("Alias for --dynamic-reloc"),
cl::aliasopt(DynamicRelocations));
cl::opt<bool>
llvm::SectionContents("full-contents",
cl::desc("Display the content of each section"));
static cl::alias SectionContentsShort("s",
cl::desc("Alias for --full-contents"),
cl::aliasopt(SectionContents));
cl::opt<bool> llvm::SymbolTable("syms", cl::desc("Display the symbol table"));
static cl::alias SymbolTableShort("t", cl::desc("Alias for --syms"),
cl::NotHidden,
cl::aliasopt(llvm::SymbolTable));
cl::opt<bool>
llvm::ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols"));
cl::opt<bool>
llvm::Rebase("rebase", cl::desc("Display mach-o rebasing info"));
cl::opt<bool>
llvm::Bind("bind", cl::desc("Display mach-o binding info"));
cl::opt<bool>
llvm::LazyBind("lazy-bind", cl::desc("Display mach-o lazy binding info"));
cl::opt<bool>
llvm::WeakBind("weak-bind", cl::desc("Display mach-o weak binding info"));
cl::opt<bool>
llvm::RawClangAST("raw-clang-ast",
cl::desc("Dump the raw binary contents of the clang AST section"));
static cl::opt<bool>
MachOOpt("macho", cl::desc("Use MachO specific object file parser"));
static cl::alias
MachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachOOpt));
cl::opt<std::string>
llvm::TripleName("triple", cl::desc("Target triple to disassemble for, "
"see -version for available targets"));
cl::opt<std::string>
llvm::MCPU("mcpu",
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
cl::value_desc("cpu-name"),
cl::init(""));
cl::opt<std::string>
llvm::ArchName("arch-name", cl::desc("Target arch to disassemble for, "
"see -version for available targets"));
cl::opt<bool>
llvm::SectionHeaders("section-headers", cl::desc("Display summaries of the "
"headers for each section."));
static cl::alias
SectionHeadersShort("headers", cl::desc("Alias for --section-headers"),
cl::aliasopt(SectionHeaders));
static cl::alias
SectionHeadersShorter("h", cl::desc("Alias for --section-headers"),
cl::aliasopt(SectionHeaders));
cl::list<std::string>
llvm::FilterSections("section", cl::desc("Operate on the specified sections only. "
"With -macho dump segment,section"));
cl::alias
static FilterSectionsj("j", cl::desc("Alias for --section"),
cl::aliasopt(llvm::FilterSections));
cl::list<std::string>
llvm::MAttrs("mattr",
cl::CommaSeparated,
cl::desc("Target specific attributes"),
cl::value_desc("a1,+a2,-a3,..."));
cl::opt<bool>
llvm::NoShowRawInsn("no-show-raw-insn", cl::desc("When disassembling "
"instructions, do not print "
"the instruction bytes."));
cl::opt<bool>
llvm::NoLeadingAddr("no-leading-addr", cl::desc("Print no leading address"));
cl::opt<bool>
llvm::UnwindInfo("unwind-info", cl::desc("Display unwind information"));
static cl::alias
UnwindInfoShort("u", cl::desc("Alias for --unwind-info"),
cl::aliasopt(UnwindInfo));
cl::opt<bool>
llvm::PrivateHeaders("private-headers",
cl::desc("Display format specific file headers"));
cl::opt<bool>
llvm::FirstPrivateHeader("private-header",
cl::desc("Display only the first format specific file "
"header"));
static cl::alias
PrivateHeadersShort("p", cl::desc("Alias for --private-headers"),
cl::aliasopt(PrivateHeaders));
cl::opt<bool> llvm::FileHeaders(
"file-headers",
cl::desc("Display the contents of the overall file header"));
static cl::alias FileHeadersShort("f", cl::desc("Alias for --file-headers"),
cl::aliasopt(FileHeaders));
cl::opt<bool>
llvm::ArchiveHeaders("archive-headers",
cl::desc("Display archive header information"));
cl::alias
ArchiveHeadersShort("a", cl::desc("Alias for --archive-headers"),
cl::aliasopt(ArchiveHeaders));
cl::opt<bool>
llvm::PrintImmHex("print-imm-hex",
cl::desc("Use hex format for immediate values"));
cl::opt<bool> PrintFaultMaps("fault-map-section",
cl::desc("Display contents of faultmap section"));
cl::opt<DIDumpType> llvm::DwarfDumpType(
"dwarf", cl::init(DIDT_Null), cl::desc("Dump of dwarf debug sections:"),
cl::values(clEnumValN(DIDT_DebugFrame, "frames", ".debug_frame")));
cl::opt<bool> PrintSource(
"source",
cl::desc(
"Display source inlined with disassembly. Implies disassemble object"));
cl::alias PrintSourceShort("S", cl::desc("Alias for -source"),
cl::aliasopt(PrintSource));
cl::opt<bool> PrintLines("line-numbers",
cl::desc("Display source line numbers with "
"disassembly. Implies disassemble object"));
cl::alias PrintLinesShort("l", cl::desc("Alias for -line-numbers"),
cl::aliasopt(PrintLines));
cl::opt<unsigned long long>
StartAddress("start-address", cl::desc("Disassemble beginning at address"),
cl::value_desc("address"), cl::init(0));
cl::opt<unsigned long long>
StopAddress("stop-address",
cl::desc("Stop disassembly at address"),
cl::value_desc("address"), cl::init(UINT64_MAX));
cl::opt<bool> DisassembleZeroes(
"disassemble-zeroes",
cl::desc("Do not skip blocks of zeroes when disassembling"));
cl::alias DisassembleZeroesShort("z",
cl::desc("Alias for --disassemble-zeroes"),
cl::aliasopt(DisassembleZeroes));
static StringRef ToolName;
typedef std::vector<std::tuple<uint64_t, StringRef, uint8_t>> SectionSymbolsTy;
namespace {
typedef std::function<bool(llvm::object::SectionRef const &)> FilterPredicate;
class SectionFilterIterator {
public:
SectionFilterIterator(FilterPredicate P,
llvm::object::section_iterator const &I,
llvm::object::section_iterator const &E)
: Predicate(std::move(P)), Iterator(I), End(E) {
ScanPredicate();
}
const llvm::object::SectionRef &operator*() const { return *Iterator; }
SectionFilterIterator &operator++() {
++Iterator;
ScanPredicate();
return *this;
}
bool operator!=(SectionFilterIterator const &Other) const {
return Iterator != Other.Iterator;
}
private:
void ScanPredicate() {
while (Iterator != End && !Predicate(*Iterator)) {
++Iterator;
}
}
FilterPredicate Predicate;
llvm::object::section_iterator Iterator;
llvm::object::section_iterator End;
};
class SectionFilter {
public:
SectionFilter(FilterPredicate P, llvm::object::ObjectFile const &O)
: Predicate(std::move(P)), Object(O) {}
SectionFilterIterator begin() {
return SectionFilterIterator(Predicate, Object.section_begin(),
Object.section_end());
}
SectionFilterIterator end() {
return SectionFilterIterator(Predicate, Object.section_end(),
Object.section_end());
}
private:
FilterPredicate Predicate;
llvm::object::ObjectFile const &Object;
};
SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O) {
return SectionFilter(
[](llvm::object::SectionRef const &S) {
if (FilterSections.empty())
return true;
llvm::StringRef String;
std::error_code error = S.getName(String);
if (error)
return false;
return is_contained(FilterSections, String);
},
O);
}
}
void llvm::error(std::error_code EC) {
if (!EC)
return;
WithColor::error(errs(), ToolName)
<< "reading file: " << EC.message() << ".\n";
errs().flush();
exit(1);
}
LLVM_ATTRIBUTE_NORETURN void llvm::error(Twine Message) {
WithColor::error(errs(), ToolName) << Message << ".\n";
errs().flush();
exit(1);
}
void llvm::warn(StringRef Message) {
WithColor::warning(errs(), ToolName) << Message << ".\n";
errs().flush();
}
LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File,
Twine Message) {
WithColor::error(errs(), ToolName)
<< "'" << File << "': " << Message << ".\n";
exit(1);
}
LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File,
std::error_code EC) {
assert(EC);
WithColor::error(errs(), ToolName)
<< "'" << File << "': " << EC.message() << ".\n";
exit(1);
}
LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File,
llvm::Error E) {
assert(E);
std::string Buf;
raw_string_ostream OS(Buf);
logAllUnhandledErrors(std::move(E), OS);
OS.flush();
WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
exit(1);
}
LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef ArchiveName,
StringRef FileName,
llvm::Error E,
StringRef ArchitectureName) {
assert(E);
WithColor::error(errs(), ToolName);
if (ArchiveName != "")
errs() << ArchiveName << "(" << FileName << ")";
else
errs() << "'" << FileName << "'";
if (!ArchitectureName.empty())
errs() << " (for architecture " << ArchitectureName << ")";
std::string Buf;
raw_string_ostream OS(Buf);
logAllUnhandledErrors(std::move(E), OS);
OS.flush();
errs() << ": " << Buf;
exit(1);
}
LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef ArchiveName,
const object::Archive::Child &C,
llvm::Error E,
StringRef ArchitectureName) {
Expected<StringRef> NameOrErr = C.getName();
// TODO: if we have a error getting the name then it would be nice to print
// the index of which archive member this is and or its offset in the
// archive instead of "???" as the name.
if (!NameOrErr) {
consumeError(NameOrErr.takeError());
llvm::report_error(ArchiveName, "???", std::move(E), ArchitectureName);
} else
llvm::report_error(ArchiveName, NameOrErr.get(), std::move(E),
ArchitectureName);
}
static const Target *getTarget(const ObjectFile *Obj = nullptr) {
// Figure out the target triple.
llvm::Triple TheTriple("unknown-unknown-unknown");
if (TripleName.empty()) {
if (Obj)
TheTriple = Obj->makeTriple();
} else {
TheTriple.setTriple(Triple::normalize(TripleName));
// Use the triple, but also try to combine with ARM build attributes.
if (Obj) {
auto Arch = Obj->getArch();
if (Arch == Triple::arm || Arch == Triple::armeb)
Obj->setARMSubArch(TheTriple);
}
}
// Get the target specific parser.
std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,
Error);
if (!TheTarget) {
if (Obj)
report_error(Obj->getFileName(), "can't find target: " + Error);
else
error("can't find target: " + Error);
}
// Update the triple name and return the found target.
TripleName = TheTriple.getTriple();
return TheTarget;
}
bool llvm::isRelocAddressLess(RelocationRef A, RelocationRef B) {
return A.getOffset() < B.getOffset();
}
static std::string demangle(StringRef Name) {
char *Demangled = nullptr;
if (Name.startswith("_Z"))
Demangled = itaniumDemangle(Name.data(), Demangled, nullptr, nullptr);
else if (Name.startswith("?"))
Demangled = microsoftDemangle(Name.data(), Demangled, nullptr, nullptr);
if (!Demangled)
return Name;
std::string Ret = Demangled;
free(Demangled);
return Ret;
}
template <class ELFT>
static std::error_code getRelocationValueString(const ELFObjectFile<ELFT> *Obj,
const RelocationRef &RelRef,
SmallVectorImpl<char> &Result) {
typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename ELFObjectFile<ELFT>::Elf_Rela Elf_Rela;
const ELFFile<ELFT> &EF = *Obj->getELFFile();
DataRefImpl Rel = RelRef.getRawDataRefImpl();
auto SecOrErr = EF.getSection(Rel.d.a);
if (!SecOrErr)
return errorToErrorCode(SecOrErr.takeError());
const Elf_Shdr *Sec = *SecOrErr;
auto SymTabOrErr = EF.getSection(Sec->sh_link);
if (!SymTabOrErr)
return errorToErrorCode(SymTabOrErr.takeError());
const Elf_Shdr *SymTab = *SymTabOrErr;
assert(SymTab->sh_type == ELF::SHT_SYMTAB ||
SymTab->sh_type == ELF::SHT_DYNSYM);
auto StrTabSec = EF.getSection(SymTab->sh_link);
if (!StrTabSec)
return errorToErrorCode(StrTabSec.takeError());
auto StrTabOrErr = EF.getStringTable(*StrTabSec);
if (!StrTabOrErr)
return errorToErrorCode(StrTabOrErr.takeError());
StringRef StrTab = *StrTabOrErr;
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.
bool Undef = false;
switch (Sec->sh_type) {
default:
return object_error::parse_failed;
case ELF::SHT_REL: {
// TODO: Read implicit addend from section data.
break;
}
case ELF::SHT_RELA: {
const Elf_Rela *ERela = Obj->getRela(Rel);
Addend = ERela->r_addend;
Undef = ERela->getSymbol(false) == 0;
break;
}
}
std::string Target;
if (!Undef) {
symbol_iterator SI = RelRef.getSymbol();
const Elf_Sym *symb = Obj->getSymbol(SI->getRawDataRefImpl());
if (symb->getType() == ELF::STT_SECTION) {
Expected<section_iterator> SymSI = SI->getSection();
if (!SymSI)
return errorToErrorCode(SymSI.takeError());
const Elf_Shdr *SymSec = Obj->getSection((*SymSI)->getRawDataRefImpl());
auto SecName = EF.getSectionName(SymSec);
if (!SecName)
return errorToErrorCode(SecName.takeError());
Target = *SecName;
} else {
Expected<StringRef> SymName = symb->getName(StrTab);
if (!SymName)
return errorToErrorCode(SymName.takeError());
if (Demangle)
Target = demangle(*SymName);
else
Target = *SymName;
}
} else
Target = "*ABS*";
// 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);
Fmt << Target;
if (Addend != 0)
Fmt << (Addend < 0 ? "" : "+") << Addend;
Fmt.flush();
Result.append(FmtBuf.begin(), FmtBuf.end());
return std::error_code();
}
static std::error_code getRelocationValueString(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);
}
static std::error_code getRelocationValueString(const COFFObjectFile *Obj,
const RelocationRef &Rel,
SmallVectorImpl<char> &Result) {
symbol_iterator SymI = Rel.getSymbol();
Expected<StringRef> SymNameOrErr = SymI->getName();
if (!SymNameOrErr)
return errorToErrorCode(SymNameOrErr.takeError());
StringRef SymName = *SymNameOrErr;
Result.append(SymName.begin(), SymName.end());
return std::error_code();
}
static void printRelocationTargetName(const MachOObjectFile *O,
const MachO::any_relocation_info &RE,
raw_string_ostream &Fmt) {
// Target of a scattered relocation is an address. In the interest of
// generating pretty output, scan through the symbol table looking for a
// symbol that aligns with that address. If we find one, print it.
// Otherwise, we just print the hex address of the target.
if (O->isRelocationScattered(RE)) {
uint32_t Val = O->getPlainRelocationSymbolNum(RE);
for (const SymbolRef &Symbol : O->symbols()) {
Expected<uint64_t> Addr = Symbol.getAddress();
if (!Addr)
report_error(O->getFileName(), Addr.takeError());
if (*Addr != Val)
continue;
Expected<StringRef> Name = Symbol.getName();
if (!Name)
report_error(O->getFileName(), Name.takeError());
Fmt << *Name;
return;
}
// If we couldn't find a symbol that this relocation refers to, try
// to find a section beginning instead.
for (const SectionRef &Section : ToolSectionFilter(*O)) {
std::error_code ec;
StringRef Name;
uint64_t Addr = Section.getAddress();
if (Addr != Val)
continue;
if ((ec = Section.getName(Name)))
report_error(O->getFileName(), ec);
Fmt << Name;
return;
}
Fmt << format("0x%x", Val);
return;
}
StringRef S;
bool isExtern = O->getPlainRelocationExternal(RE);
uint64_t Val = O->getPlainRelocationSymbolNum(RE);
if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND) {
Fmt << format("0x%0" PRIx64, Val);
return;
}
if (isExtern) {
symbol_iterator SI = O->symbol_begin();
advance(SI, Val);
Expected<StringRef> SOrErr = SI->getName();
if (!SOrErr)
report_error(O->getFileName(), SOrErr.takeError());
S = *SOrErr;
} else {
section_iterator SI = O->section_begin();
// Adjust for the fact that sections are 1-indexed.
if (Val == 0) {
Fmt << "0 (?,?)";
return;
}
uint32_t I = Val - 1;
while (I != 0 && SI != O->section_end()) {
--I;
advance(SI, 1);
}
if (SI == O->section_end())
Fmt << Val << " (?,?)";
else
SI->getName(S);
}
Fmt << S;
}
static std::error_code getRelocationValueString(const WasmObjectFile *Obj,
const RelocationRef &RelRef,
SmallVectorImpl<char> &Result) {
const wasm::WasmRelocation& Rel = Obj->getWasmRelocation(RelRef);
symbol_iterator SI = RelRef.getSymbol();
std::string FmtBuf;
raw_string_ostream Fmt(FmtBuf);
if (SI == Obj->symbol_end()) {
// Not all wasm relocations have symbols associated with them.
// In particular R_WEBASSEMBLY_TYPE_INDEX_LEB.
Fmt << Rel.Index;
} else {
Expected<StringRef> SymNameOrErr = SI->getName();
if (!SymNameOrErr)
return errorToErrorCode(SymNameOrErr.takeError());
StringRef SymName = *SymNameOrErr;
Result.append(SymName.begin(), SymName.end());
}
Fmt << (Rel.Addend < 0 ? "" : "+") << Rel.Addend;
Fmt.flush();
Result.append(FmtBuf.begin(), FmtBuf.end());
return std::error_code();
}
static std::error_code getRelocationValueString(const MachOObjectFile *Obj,
const RelocationRef &RelRef,
SmallVectorImpl<char> &Result) {
DataRefImpl Rel = RelRef.getRawDataRefImpl();
MachO::any_relocation_info RE = Obj->getRelocation(Rel);
unsigned Arch = Obj->getArch();
std::string FmtBuf;
raw_string_ostream Fmt(FmtBuf);
unsigned Type = Obj->getAnyRelocationType(RE);
bool IsPCRel = Obj->getAnyRelocationPCRel(RE);
// Determine any addends that should be displayed with the relocation.
// These require decoding the relocation type, which is triple-specific.
// X86_64 has entirely custom relocation types.
if (Arch == Triple::x86_64) {
switch (Type) {
case MachO::X86_64_RELOC_GOT_LOAD:
case MachO::X86_64_RELOC_GOT: {
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "@GOT";
if (IsPCRel)
Fmt << "PCREL";
break;
}
case MachO::X86_64_RELOC_SUBTRACTOR: {
DataRefImpl RelNext = Rel;
Obj->moveRelocationNext(RelNext);
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
// X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type
// X86_64_RELOC_UNSIGNED.
// NOTE: Scattered relocations don't exist on x86_64.
unsigned RType = Obj->getAnyRelocationType(RENext);
if (RType != MachO::X86_64_RELOC_UNSIGNED)
report_error(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after "
"X86_64_RELOC_SUBTRACTOR.");
// The X86_64_RELOC_UNSIGNED contains the minuend symbol;
// X86_64_RELOC_SUBTRACTOR contains the subtrahend.
printRelocationTargetName(Obj, RENext, Fmt);
Fmt << "-";
printRelocationTargetName(Obj, RE, Fmt);
break;
}
case MachO::X86_64_RELOC_TLV:
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "@TLV";
if (IsPCRel)
Fmt << "P";
break;
case MachO::X86_64_RELOC_SIGNED_1:
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-1";
break;
case MachO::X86_64_RELOC_SIGNED_2:
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-2";
break;
case MachO::X86_64_RELOC_SIGNED_4:
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-4";
break;
default:
printRelocationTargetName(Obj, RE, Fmt);
break;
}
// X86 and ARM share some relocation types in common.
} else if (Arch == Triple::x86 || Arch == Triple::arm ||
Arch == Triple::ppc) {
// Generic relocation types...
switch (Type) {
case MachO::GENERIC_RELOC_PAIR: // prints no info
return std::error_code();
case MachO::GENERIC_RELOC_SECTDIFF: {
DataRefImpl RelNext = Rel;
Obj->moveRelocationNext(RelNext);
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
// X86 sect diff's must be followed by a relocation of type
// GENERIC_RELOC_PAIR.
unsigned RType = Obj->getAnyRelocationType(RENext);
if (RType != MachO::GENERIC_RELOC_PAIR)
report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
"GENERIC_RELOC_SECTDIFF.");
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-";
printRelocationTargetName(Obj, RENext, Fmt);
break;
}
}
if (Arch == Triple::x86 || Arch == Triple::ppc) {
switch (Type) {
case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
DataRefImpl RelNext = Rel;
Obj->moveRelocationNext(RelNext);
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
// X86 sect diff's must be followed by a relocation of type
// GENERIC_RELOC_PAIR.
unsigned RType = Obj->getAnyRelocationType(RENext);
if (RType != MachO::GENERIC_RELOC_PAIR)
report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
"GENERIC_RELOC_LOCAL_SECTDIFF.");
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-";
printRelocationTargetName(Obj, RENext, Fmt);
break;
}
case MachO::GENERIC_RELOC_TLV: {
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "@TLV";
if (IsPCRel)
Fmt << "P";
break;
}
default:
printRelocationTargetName(Obj, RE, Fmt);
}
} else { // ARM-specific relocations
switch (Type) {
case MachO::ARM_RELOC_HALF:
case MachO::ARM_RELOC_HALF_SECTDIFF: {
// Half relocations steal a bit from the length field to encode
// whether this is an upper16 or a lower16 relocation.
bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;
if (isUpper)
Fmt << ":upper16:(";
else
Fmt << ":lower16:(";
printRelocationTargetName(Obj, RE, Fmt);
DataRefImpl RelNext = Rel;
Obj->moveRelocationNext(RelNext);
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
// ARM half relocs must be followed by a relocation of type
// ARM_RELOC_PAIR.
unsigned RType = Obj->getAnyRelocationType(RENext);
if (RType != MachO::ARM_RELOC_PAIR)
report_error(Obj->getFileName(), "Expected ARM_RELOC_PAIR after "
"ARM_RELOC_HALF");
// NOTE: The half of the target virtual address is stashed in the
// address field of the secondary relocation, but we can't reverse
// engineer the constant offset from it without decoding the movw/movt
// instruction to find the other half in its immediate field.
// ARM_RELOC_HALF_SECTDIFF encodes the second section in the
// symbol/section pointer of the follow-on relocation.
if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
Fmt << "-";
printRelocationTargetName(Obj, RENext, Fmt);
}
Fmt << ")";
break;
}
default: { printRelocationTargetName(Obj, RE, Fmt); }
}
}
} else
printRelocationTargetName(Obj, RE, Fmt);
Fmt.flush();
Result.append(FmtBuf.begin(), FmtBuf.end());
return std::error_code();
}
static std::error_code getRelocationValueString(const RelocationRef &Rel,
SmallVectorImpl<char> &Result) {
const ObjectFile *Obj = Rel.getObject();
if (auto *ELF = dyn_cast<ELFObjectFileBase>(Obj))
return getRelocationValueString(ELF, Rel, Result);
if (auto *COFF = dyn_cast<COFFObjectFile>(Obj))
return getRelocationValueString(COFF, Rel, Result);
if (auto *Wasm = dyn_cast<WasmObjectFile>(Obj))
return getRelocationValueString(Wasm, Rel, Result);
if (auto *MachO = dyn_cast<MachOObjectFile>(Obj))
return getRelocationValueString(MachO, Rel, Result);
llvm_unreachable("unknown object file format");
}
/// Indicates whether this relocation should hidden when listing
/// relocations, usually because it is the trailing part of a multipart
/// relocation that will be printed as part of the leading relocation.
static bool getHidden(RelocationRef RelRef) {
auto *MachO = dyn_cast<MachOObjectFile>(RelRef.getObject());
if (!MachO)
return false;
unsigned Arch = MachO->getArch();
DataRefImpl Rel = RelRef.getRawDataRefImpl();
uint64_t Type = MachO->getRelocationType(Rel);
// On arches that use the generic relocations, GENERIC_RELOC_PAIR
// is always hidden.
if (Arch == Triple::x86 || Arch == Triple::arm || Arch == Triple::ppc)
return Type == MachO::GENERIC_RELOC_PAIR;
if (Arch == Triple::x86_64) {
// On x86_64, X86_64_RELOC_UNSIGNED is hidden only when it follows
// an X86_64_RELOC_SUBTRACTOR.
if (Type == MachO::X86_64_RELOC_UNSIGNED && Rel.d.a > 0) {
DataRefImpl RelPrev = Rel;
RelPrev.d.a--;
uint64_t PrevType = MachO->getRelocationType(RelPrev);
if (PrevType == MachO::X86_64_RELOC_SUBTRACTOR)
return true;
}
}
return false;
}
namespace {
class SourcePrinter {
protected:
DILineInfo OldLineInfo;
const ObjectFile *Obj = nullptr;
std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer;
// File name to file contents of source
std::unordered_map<std::string, std::unique_ptr<MemoryBuffer>> SourceCache;
// Mark the line endings of the cached source
std::unordered_map<std::string, std::vector<StringRef>> LineCache;
private:
bool cacheSource(const DILineInfo& LineInfoFile);
public:
SourcePrinter() = default;
SourcePrinter(const ObjectFile *Obj, StringRef DefaultArch) : Obj(Obj) {
symbolize::LLVMSymbolizer::Options SymbolizerOpts(
DILineInfoSpecifier::FunctionNameKind::None, true, false, false,
DefaultArch);
Symbolizer.reset(new symbolize::LLVMSymbolizer(SymbolizerOpts));
}
virtual ~SourcePrinter() = default;
virtual void printSourceLine(raw_ostream &OS, uint64_t Address,
StringRef Delimiter = "; ");
};
bool SourcePrinter::cacheSource(const DILineInfo &LineInfo) {
std::unique_ptr<MemoryBuffer> Buffer;
if (LineInfo.Source) {
Buffer = MemoryBuffer::getMemBuffer(*LineInfo.Source);
} else {
auto BufferOrError = MemoryBuffer::getFile(LineInfo.FileName);
if (!BufferOrError)
return false;
Buffer = std::move(*BufferOrError);
}
// Chomp the file to get lines
size_t BufferSize = Buffer->getBufferSize();
const char *BufferStart = Buffer->getBufferStart();
for (const char *Start = BufferStart, *End = BufferStart;
End < BufferStart + BufferSize; End++)
if (*End == '\n' || End == BufferStart + BufferSize - 1 ||
(*End == '\r' && *(End + 1) == '\n')) {
LineCache[LineInfo.FileName].push_back(StringRef(Start, End - Start));
if (*End == '\r')
End++;
Start = End + 1;
}
SourceCache[LineInfo.FileName] = std::move(Buffer);
return true;
}
void SourcePrinter::printSourceLine(raw_ostream &OS, uint64_t Address,
StringRef Delimiter) {
if (!Symbolizer)
return;
DILineInfo LineInfo = DILineInfo();
auto ExpectecLineInfo =
Symbolizer->symbolizeCode(Obj->getFileName(), Address);
if (!ExpectecLineInfo)
consumeError(ExpectecLineInfo.takeError());
else
LineInfo = *ExpectecLineInfo;
if ((LineInfo.FileName == "<invalid>") || OldLineInfo.Line == LineInfo.Line ||
LineInfo.Line == 0)
return;
if (PrintLines)
OS << Delimiter << LineInfo.FileName << ":" << LineInfo.Line << "\n";
if (PrintSource) {
if (SourceCache.find(LineInfo.FileName) == SourceCache.end())
if (!cacheSource(LineInfo))
return;
auto FileBuffer = SourceCache.find(LineInfo.FileName);
if (FileBuffer != SourceCache.end()) {
auto LineBuffer = LineCache.find(LineInfo.FileName);
if (LineBuffer != LineCache.end()) {
if (LineInfo.Line > LineBuffer->second.size())
return;
// Vector begins at 0, line numbers are non-zero
OS << Delimiter << LineBuffer->second[LineInfo.Line - 1].ltrim()
<< "\n";
}
}
}
OldLineInfo = LineInfo;
}
static bool isArmElf(const ObjectFile *Obj) {
return (Obj->isELF() &&
(Obj->getArch() == Triple::aarch64 ||
Obj->getArch() == Triple::aarch64_be ||
Obj->getArch() == Triple::arm || Obj->getArch() == Triple::armeb ||
Obj->getArch() == Triple::thumb ||
Obj->getArch() == Triple::thumbeb));
}
class PrettyPrinter {
public:
virtual ~PrettyPrinter() = default;
virtual void printInst(MCInstPrinter &IP, const MCInst *MI,
ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &OS, StringRef Annot,
MCSubtargetInfo const &STI, SourcePrinter *SP,
std::vector<RelocationRef> *Rels = nullptr) {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
if (!NoLeadingAddr)
OS << format("%8" PRIx64 ":", Address);
if (!NoShowRawInsn) {
OS << "\t";
dumpBytes(Bytes, OS);
}
if (MI)
IP.printInst(MI, OS, "", STI);
else
OS << " <unknown>";
}
};
PrettyPrinter PrettyPrinterInst;
class HexagonPrettyPrinter : public PrettyPrinter {
public:
void printLead(ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &OS) {
uint32_t opcode =
(Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0];
if (!NoLeadingAddr)
OS << format("%8" PRIx64 ":", Address);
if (!NoShowRawInsn) {
OS << "\t";
dumpBytes(Bytes.slice(0, 4), OS);
OS << format("%08" PRIx32, opcode);
}
}
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
uint64_t Address, raw_ostream &OS, StringRef Annot,
MCSubtargetInfo const &STI, SourcePrinter *SP,
std::vector<RelocationRef> *Rels) override {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address, "");
if (!MI) {
printLead(Bytes, Address, OS);
OS << " <unknown>";
return;
}
std::string Buffer;
{
raw_string_ostream TempStream(Buffer);
IP.printInst(MI, TempStream, "", STI);
}
StringRef Contents(Buffer);
// Split off bundle attributes
auto PacketBundle = Contents.rsplit('\n');
// Split off first instruction from the rest
auto HeadTail = PacketBundle.first.split('\n');
auto Preamble = " { ";
auto Separator = "";
StringRef Fmt = "\t\t\t%08" PRIx64 ": ";
std::vector<RelocationRef>::const_iterator RelCur = Rels->begin();
std::vector<RelocationRef>::const_iterator RelEnd = Rels->end();
// Hexagon's packets require relocations to be inline rather than
// clustered at the end of the packet.
auto PrintReloc = [&]() -> void {
while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address)) {
if (RelCur->getOffset() == Address) {
SmallString<16> Name;
SmallString<32> Val;
RelCur->getTypeName(Name);
error(getRelocationValueString(*RelCur, Val));
OS << Separator << format(Fmt.data(), Address) << Name << "\t" << Val
<< "\n";
return;
}
++RelCur;
}
};
while (!HeadTail.first.empty()) {
OS << Separator;
Separator = "\n";
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address, "");
printLead(Bytes, Address, OS);
OS << Preamble;
Preamble = " ";
StringRef Inst;
auto Duplex = HeadTail.first.split('\v');
if (!Duplex.second.empty()) {
OS << Duplex.first;
OS << "; ";
Inst = Duplex.second;
}
else
Inst = HeadTail.first;
OS << Inst;
HeadTail = HeadTail.second.split('\n');
if (HeadTail.first.empty())
OS << " } " << PacketBundle.second;
PrintReloc();
Bytes = Bytes.slice(4);
Address += 4;
}
}
};
HexagonPrettyPrinter HexagonPrettyPrinterInst;
class AMDGCNPrettyPrinter : public PrettyPrinter {
public:
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
uint64_t Address, raw_ostream &OS, StringRef Annot,
MCSubtargetInfo const &STI, SourcePrinter *SP,
std::vector<RelocationRef> *Rels) override {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
typedef support::ulittle32_t U32;
if (MI) {
SmallString<40> InstStr;
raw_svector_ostream IS(InstStr);
IP.printInst(MI, IS, "", STI);
OS << left_justify(IS.str(), 60);
} else {
// an unrecognized encoding - this is probably data so represent it
// using the .long directive, or .byte directive if fewer than 4 bytes
// remaining
if (Bytes.size() >= 4) {
OS << format("\t.long 0x%08" PRIx32 " ",
static_cast<uint32_t>(*reinterpret_cast<const U32*>(Bytes.data())));
OS.indent(42);
} else {
OS << format("\t.byte 0x%02" PRIx8, Bytes[0]);
for (unsigned int i = 1; i < Bytes.size(); i++)
OS << format(", 0x%02" PRIx8, Bytes[i]);
OS.indent(55 - (6 * Bytes.size()));
}
}
OS << format("// %012" PRIX64 ": ", Address);
if (Bytes.size() >=4) {
for (auto D : makeArrayRef(reinterpret_cast<const U32*>(Bytes.data()),
Bytes.size() / sizeof(U32)))
// D should be explicitly casted to uint32_t here as it is passed
// by format to snprintf as vararg.
OS << format("%08" PRIX32 " ", static_cast<uint32_t>(D));
} else {
for (unsigned int i = 0; i < Bytes.size(); i++)
OS << format("%02" PRIX8 " ", Bytes[i]);
}
if (!Annot.empty())
OS << "// " << Annot;
}
};
AMDGCNPrettyPrinter AMDGCNPrettyPrinterInst;
class BPFPrettyPrinter : public PrettyPrinter {
public:
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
uint64_t Address, raw_ostream &OS, StringRef Annot,
MCSubtargetInfo const &STI, SourcePrinter *SP,
std::vector<RelocationRef> *Rels) override {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
if (!NoLeadingAddr)
OS << format("%8" PRId64 ":", Address / 8);
if (!NoShowRawInsn) {
OS << "\t";
dumpBytes(Bytes, OS);
}
if (MI)
IP.printInst(MI, OS, "", STI);
else
OS << " <unknown>";
}
};
BPFPrettyPrinter BPFPrettyPrinterInst;
PrettyPrinter &selectPrettyPrinter(Triple const &Triple) {
switch(Triple.getArch()) {
default:
return PrettyPrinterInst;
case Triple::hexagon:
return HexagonPrettyPrinterInst;
case Triple::amdgcn:
return AMDGCNPrettyPrinterInst;
case Triple::bpfel:
case Triple::bpfeb:
return BPFPrettyPrinterInst;
}
}
}
static uint8_t getElfSymbolType(const ObjectFile *Obj, const SymbolRef &Sym) {
assert(Obj->isELF());
if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Obj))
return Elf32LEObj->getSymbol(Sym.getRawDataRefImpl())->getType();
if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj))
return Elf64LEObj->getSymbol(Sym.getRawDataRefImpl())->getType();
if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj))
return Elf32BEObj->getSymbol(Sym.getRawDataRefImpl())->getType();
if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj))
return Elf64BEObj->getSymbol(Sym.getRawDataRefImpl())->getType();
llvm_unreachable("Unsupported binary format");
}
template <class ELFT> static void
addDynamicElfSymbols(const ELFObjectFile<ELFT> *Obj,
std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
for (auto Symbol : Obj->getDynamicSymbolIterators()) {
uint8_t SymbolType = Symbol.getELFType();
if (SymbolType != ELF::STT_FUNC || Symbol.getSize() == 0)
continue;
Expected<uint64_t> AddressOrErr = Symbol.getAddress();
if (!AddressOrErr)
report_error(Obj->getFileName(), AddressOrErr.takeError());
Expected<StringRef> Name = Symbol.getName();
if (!Name)
report_error(Obj->getFileName(), Name.takeError());
if (Name->empty())
continue;
Expected<section_iterator> SectionOrErr = Symbol.getSection();
if (!SectionOrErr)
report_error(Obj->getFileName(), SectionOrErr.takeError());
section_iterator SecI = *SectionOrErr;
if (SecI == Obj->section_end())
continue;
AllSymbols[*SecI].emplace_back(*AddressOrErr, *Name, SymbolType);
}
}
static void
addDynamicElfSymbols(const ObjectFile *Obj,
std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
assert(Obj->isELF());
if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Obj))
addDynamicElfSymbols(Elf32LEObj, AllSymbols);
else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj))
addDynamicElfSymbols(Elf64LEObj, AllSymbols);
else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj))
addDynamicElfSymbols(Elf32BEObj, AllSymbols);
else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj))
addDynamicElfSymbols(Elf64BEObj, AllSymbols);
else
llvm_unreachable("Unsupported binary format");
}
static void addPltEntries(const ObjectFile *Obj,
std::map<SectionRef, SectionSymbolsTy> &AllSymbols,
StringSaver &Saver) {
Optional<SectionRef> Plt = None;
for (const SectionRef &Section : Obj->sections()) {
StringRef Name;
if (Section.getName(Name))
continue;
if (Name == ".plt")
Plt = Section;
}
if (!Plt)
return;
if (auto *ElfObj = dyn_cast<ELFObjectFileBase>(Obj)) {
for (auto PltEntry : ElfObj->getPltAddresses()) {
SymbolRef Symbol(PltEntry.first, ElfObj);
uint8_t SymbolType = getElfSymbolType(Obj, Symbol);
Expected<StringRef> NameOrErr = Symbol.getName();
if (!NameOrErr)
report_error(Obj->getFileName(), NameOrErr.takeError());
if (NameOrErr->empty())
continue;
StringRef Name = Saver.save((*NameOrErr + "@plt").str());
AllSymbols[*Plt].emplace_back(PltEntry.second, Name, SymbolType);
}
}
}
// Normally the disassembly output will skip blocks of zeroes. This function
// returns the number of zero bytes that can be skipped when dumping the
// disassembly of the instructions in Buf.
static size_t countSkippableZeroBytes(ArrayRef<uint8_t> Buf) {
// When -z or --disassemble-zeroes are given we always dissasemble them.
if (DisassembleZeroes)
return 0;
// Find the number of leading zeroes.
size_t N = 0;
while (N < Buf.size() && !Buf[N])
++N;
// We may want to skip blocks of zero bytes, but unless we see
// at least 8 of them in a row.
if (N < 8)
return 0;
// We skip zeroes in multiples of 4 because do not want to truncate an
// instruction if it starts with a zero byte.
return N & ~0x3;
}
static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
if (StartAddress > StopAddress)
error("Start address should be less than stop address");
const Target *TheTarget = getTarget(Obj);
// Package up features to be passed to target/subtarget
SubtargetFeatures Features = Obj->getFeatures();
if (!MAttrs.empty())
for (unsigned I = 0; I != MAttrs.size(); ++I)
Features.AddFeature(MAttrs[I]);
std::unique_ptr<const MCRegisterInfo> MRI(
TheTarget->createMCRegInfo(TripleName));
if (!MRI)
report_error(Obj->getFileName(), "no register info for target " +
TripleName);
// Set up disassembler.
std::unique_ptr<const MCAsmInfo> AsmInfo(
TheTarget->createMCAsmInfo(*MRI, TripleName));
if (!AsmInfo)
report_error(Obj->getFileName(), "no assembly info for target " +
TripleName);
std::unique_ptr<const MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString()));
if (!STI)
report_error(Obj->getFileName(), "no subtarget info for target " +
TripleName);
std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
if (!MII)
report_error(Obj->getFileName(), "no instruction info for target " +
TripleName);
MCObjectFileInfo MOFI;
MCContext Ctx(AsmInfo.get(), MRI.get(), &MOFI);
// FIXME: for now initialize MCObjectFileInfo with default values
MOFI.InitMCObjectFileInfo(Triple(TripleName), false, Ctx);
std::unique_ptr<MCDisassembler> DisAsm(
TheTarget->createMCDisassembler(*STI, Ctx));
if (!DisAsm)
report_error(Obj->getFileName(), "no disassembler for target " +
TripleName);
std::unique_ptr<const MCInstrAnalysis> MIA(
TheTarget->createMCInstrAnalysis(MII.get()));
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI));
if (!IP)
report_error(Obj->getFileName(), "no instruction printer for target " +
TripleName);
IP->setPrintImmHex(PrintImmHex);
PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName));
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "\t\t%016" PRIx64 ": " :
"\t\t\t%08" PRIx64 ": ";
SourcePrinter SP(Obj, TheTarget->getName());
// Create a mapping, RelocSecs = SectionRelocMap[S], where sections
// in RelocSecs contain the relocations for section S.
std::error_code EC;
std::map<SectionRef, SmallVector<SectionRef, 1>> SectionRelocMap;
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
section_iterator Sec2 = Section.getRelocatedSection();
if (Sec2 != Obj->section_end())
SectionRelocMap[*Sec2].push_back(Section);
}
// Create a mapping from virtual address to symbol name. This is used to
// pretty print the symbols while disassembling.
std::map<SectionRef, SectionSymbolsTy> AllSymbols;
SectionSymbolsTy AbsoluteSymbols;
for (const SymbolRef &Symbol : Obj->symbols()) {
Expected<uint64_t> AddressOrErr = Symbol.getAddress();
if (!AddressOrErr)
report_error(Obj->getFileName(), AddressOrErr.takeError());
uint64_t Address = *AddressOrErr;
Expected<StringRef> Name = Symbol.getName();
if (!Name)
report_error(Obj->getFileName(), Name.takeError());
if (Name->empty())
continue;
Expected<section_iterator> SectionOrErr = Symbol.getSection();
if (!SectionOrErr)
report_error(Obj->getFileName(), SectionOrErr.takeError());
uint8_t SymbolType = ELF::STT_NOTYPE;
if (Obj->isELF())
SymbolType = getElfSymbolType(Obj, Symbol);
section_iterator SecI = *SectionOrErr;
if (SecI != Obj->section_end())
AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType);
else
AbsoluteSymbols.emplace_back(Address, *Name, SymbolType);
}
if (AllSymbols.empty() && Obj->isELF())
addDynamicElfSymbols(Obj, AllSymbols);
BumpPtrAllocator A;
StringSaver Saver(A);
addPltEntries(Obj, AllSymbols, Saver);
// Create a mapping from virtual address to section.
std::vector<std::pair<uint64_t, SectionRef>> SectionAddresses;
for (SectionRef Sec : Obj->sections())
SectionAddresses.emplace_back(Sec.getAddress(), Sec);
array_pod_sort(SectionAddresses.begin(), SectionAddresses.end());
// Linked executables (.exe and .dll files) typically don't include a real
// symbol table but they might contain an export table.
if (const auto *COFFObj = dyn_cast<COFFObjectFile>(Obj)) {
for (const auto &ExportEntry : COFFObj->export_directories()) {
StringRef Name;
error(ExportEntry.getSymbolName(Name));
if (Name.empty())
continue;
uint32_t RVA;
error(ExportEntry.getExportRVA(RVA));
uint64_t VA = COFFObj->getImageBase() + RVA;
auto Sec = std::upper_bound(
SectionAddresses.begin(), SectionAddresses.end(), VA,
[](uint64_t LHS, const std::pair<uint64_t, SectionRef> &RHS) {
return LHS < RHS.first;
});
if (Sec != SectionAddresses.begin())
--Sec;
else
Sec = SectionAddresses.end();
if (Sec != SectionAddresses.end())
AllSymbols[Sec->second].emplace_back(VA, Name, ELF::STT_NOTYPE);
else
AbsoluteSymbols.emplace_back(VA, Name, ELF::STT_NOTYPE);
}
}
// Sort all the symbols, this allows us to use a simple binary search to find
// a symbol near an address.
for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols)
array_pod_sort(SecSyms.second.begin(), SecSyms.second.end());
array_pod_sort(AbsoluteSymbols.begin(), AbsoluteSymbols.end());
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
if (!DisassembleAll && (!Section.isText() || Section.isVirtual()))
continue;
uint64_t SectionAddr = Section.getAddress();
uint64_t SectSize = Section.getSize();
if (!SectSize)
continue;
// Get the list of all the symbols in this section.
SectionSymbolsTy &Symbols = AllSymbols[Section];
std::vector<uint64_t> DataMappingSymsAddr;
std::vector<uint64_t> TextMappingSymsAddr;
if (isArmElf(Obj)) {
for (const auto &Symb : Symbols) {
uint64_t Address = std::get<0>(Symb);
StringRef Name = std::get<1>(Symb);
if (Name.startswith("$d"))
DataMappingSymsAddr.push_back(Address - SectionAddr);
if (Name.startswith("$x"))
TextMappingSymsAddr.push_back(Address - SectionAddr);
if (Name.startswith("$a"))
TextMappingSymsAddr.push_back(Address - SectionAddr);
if (Name.startswith("$t"))
TextMappingSymsAddr.push_back(Address - SectionAddr);
}
}
llvm::sort(DataMappingSymsAddr);
llvm::sort(TextMappingSymsAddr);
if (Obj->isELF() && Obj->getArch() == Triple::amdgcn) {
// AMDGPU disassembler uses symbolizer for printing labels
std::unique_ptr<MCRelocationInfo> RelInfo(
TheTarget->createMCRelocationInfo(TripleName, Ctx));
if (RelInfo) {
std::unique_ptr<MCSymbolizer> Symbolizer(
TheTarget->createMCSymbolizer(
TripleName, nullptr, nullptr, &Symbols, &Ctx, std::move(RelInfo)));
DisAsm->setSymbolizer(std::move(Symbolizer));
}
}
// Make a list of all the relocations for this section.
std::vector<RelocationRef> Rels;
if (InlineRelocs) {
for (const SectionRef &RelocSec : SectionRelocMap[Section]) {
for (const RelocationRef &Reloc : RelocSec.relocations()) {
Rels.push_back(Reloc);
}
}
}
// Sort relocations by address.
llvm::sort(Rels, isRelocAddressLess);
StringRef SegmentName = "";
if (const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj)) {
DataRefImpl DR = Section.getRawDataRefImpl();
SegmentName = MachO->getSectionFinalSegmentName(DR);
}
StringRef SectionName;
error(Section.getName(SectionName));
// If the section has no symbol at the start, just insert a dummy one.
if (Symbols.empty() || std::get<0>(Symbols[0]) != 0) {
Symbols.insert(
Symbols.begin(),
std::make_tuple(SectionAddr, SectionName,
Section.isText() ? ELF::STT_FUNC : ELF::STT_OBJECT));
}
SmallString<40> Comments;
raw_svector_ostream CommentStream(Comments);
StringRef BytesStr;
error(Section.getContents(BytesStr));
ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()),
BytesStr.size());
uint64_t Size;
uint64_t Index;
bool PrintedSection = false;
std::vector<RelocationRef>::const_iterator RelCur = Rels.begin();
std::vector<RelocationRef>::const_iterator RelEnd = Rels.end();
// Disassemble symbol by symbol.
for (unsigned SI = 0, SE = Symbols.size(); SI != SE; ++SI) {
uint64_t Start = std::get<0>(Symbols[SI]) - SectionAddr;
// The end is either the section end or the beginning of the next
// symbol.
uint64_t End = (SI == SE - 1)
? SectSize
: std::get<0>(Symbols[SI + 1]) - SectionAddr;
// Don't try to disassemble beyond the end of section contents.
if (End > SectSize)
End = SectSize;
// If this symbol has the same address as the next symbol, then skip it.
if (Start >= End)
continue;
// Check if we need to skip symbol
// Skip if the symbol's data is not between StartAddress and StopAddress
if (End + SectionAddr < StartAddress ||
Start + SectionAddr > StopAddress) {
continue;
}
/// Skip if user requested specific symbols and this is not in the list
if (!DisasmFuncsSet.empty() &&
!DisasmFuncsSet.count(std::get<1>(Symbols[SI])))
continue;
if (!PrintedSection) {
PrintedSection = true;
outs() << "Disassembly of section ";
if (!SegmentName.empty())
outs() << SegmentName << ",";
outs() << SectionName << ':';
}
// Stop disassembly at the stop address specified
if (End + SectionAddr > StopAddress)
End = StopAddress - SectionAddr;
if (Obj->isELF() && Obj->getArch() == Triple::amdgcn) {
if (std::get<2>(Symbols[SI]) == ELF::STT_AMDGPU_HSA_KERNEL) {
// skip amd_kernel_code_t at the begining of kernel symbol (256 bytes)
Start += 256;
}
if (SI == SE - 1 ||
std::get<2>(Symbols[SI + 1]) == ELF::STT_AMDGPU_HSA_KERNEL) {
// cut trailing zeroes at the end of kernel
// cut up to 256 bytes
const uint64_t EndAlign = 256;
const auto Limit = End - (std::min)(EndAlign, End - Start);
while (End > Limit &&
*reinterpret_cast<const support::ulittle32_t*>(&Bytes[End - 4]) == 0)
End -= 4;
}
}
outs() << '\n';
if (!NoLeadingAddr)
outs() << format("%016" PRIx64 " ", SectionAddr + Start);
StringRef SymbolName = std::get<1>(Symbols[SI]);
if (Demangle)
outs() << demangle(SymbolName) << ":\n";
else
outs() << SymbolName << ":\n";
// Don't print raw contents of a virtual section. A virtual section
// doesn't have any contents in the file.
if (Section.isVirtual()) {
outs() << "...\n";
continue;
}
#ifndef NDEBUG
raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls();
#else
raw_ostream &DebugOut = nulls();
#endif
for (Index = Start; Index < End; Index += Size) {
MCInst Inst;
if (Index + SectionAddr < StartAddress ||
Index + SectionAddr > StopAddress) {
// skip byte by byte till StartAddress is reached
Size = 1;
continue;
}
// AArch64 ELF binaries can interleave data and text in the
// same section. We rely on the markers introduced to
// understand what we need to dump. If the data marker is within a
// function, it is denoted as a word/short etc
if (isArmElf(Obj) && std::get<2>(Symbols[SI]) != ELF::STT_OBJECT &&
!DisassembleAll) {
uint64_t Stride = 0;
auto DAI = std::lower_bound(DataMappingSymsAddr.begin(),
DataMappingSymsAddr.end(), Index);
if (DAI != DataMappingSymsAddr.end() && *DAI == Index) {
// Switch to data.
while (Index < End) {
outs() << format("%8" PRIx64 ":", SectionAddr + Index);
outs() << "\t";
if (Index + 4 <= End) {
Stride = 4;
dumpBytes(Bytes.slice(Index, 4), outs());
outs() << "\t.word\t";
uint32_t Data = 0;
if (Obj->isLittleEndian()) {
const auto Word =
reinterpret_cast<const support::ulittle32_t *>(
Bytes.data() + Index);
Data = *Word;
} else {
const auto Word = reinterpret_cast<const support::ubig32_t *>(
Bytes.data() + Index);
Data = *Word;
}
outs() << "0x" << format("%08" PRIx32, Data);
} else if (Index + 2 <= End) {
Stride = 2;
dumpBytes(Bytes.slice(Index, 2), outs());
outs() << "\t\t.short\t";
uint16_t Data = 0;
if (Obj->isLittleEndian()) {
const auto Short =
reinterpret_cast<const support::ulittle16_t *>(
Bytes.data() + Index);
Data = *Short;
} else {
const auto Short =
reinterpret_cast<const support::ubig16_t *>(Bytes.data() +
Index);
Data = *Short;
}
outs() << "0x" << format("%04" PRIx16, Data);
} else {
Stride = 1;
dumpBytes(Bytes.slice(Index, 1), outs());
outs() << "\t\t.byte\t";
outs() << "0x" << format("%02" PRIx8, Bytes.slice(Index, 1)[0]);
}
Index += Stride;
outs() << "\n";
auto TAI = std::lower_bound(TextMappingSymsAddr.begin(),
TextMappingSymsAddr.end(), Index);
if (TAI != TextMappingSymsAddr.end() && *TAI == Index)
break;
}
}
}
// If there is a data symbol inside an ELF text section and we are only
// disassembling text (applicable all architectures),
// we are in a situation where we must print the data and not
// disassemble it.
if (Obj->isELF() && std::get<2>(Symbols[SI]) == ELF::STT_OBJECT &&
!DisassembleAll && Section.isText()) {
// print out data up to 8 bytes at a time in hex and ascii
uint8_t AsciiData[9] = {'\0'};
uint8_t Byte;
int NumBytes = 0;
for (Index = Start; Index < End; Index += 1) {
if (((SectionAddr + Index) < StartAddress) ||
((SectionAddr + Index) > StopAddress))
continue;
if (NumBytes == 0) {
outs() << format("%8" PRIx64 ":", SectionAddr + Index);
outs() << "\t";
}
Byte = Bytes.slice(Index)[0];
outs() << format(" %02x", Byte);
AsciiData[NumBytes] = isPrint(Byte) ? Byte : '.';
uint8_t IndentOffset = 0;
NumBytes++;
if (Index == End - 1 || NumBytes > 8) {
// Indent the space for less than 8 bytes data.
// 2 spaces for byte and one for space between bytes
IndentOffset = 3 * (8 - NumBytes);
for (int Excess = 8 - NumBytes; Excess < 8; Excess++)
AsciiData[Excess] = '\0';
NumBytes = 8;
}
if (NumBytes == 8) {
AsciiData[8] = '\0';
outs() << std::string(IndentOffset, ' ') << " ";
outs() << reinterpret_cast<char *>(AsciiData);
outs() << '\n';
NumBytes = 0;
}
}
}
if (Index >= End)
break;
if (size_t N =
countSkippableZeroBytes(Bytes.slice(Index, End - Index))) {
outs() << "\t\t..." << '\n';
Index += N;
if (Index >= End)
break;
}
// Disassemble a real instruction or a data when disassemble all is
// provided
bool Disassembled = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
SectionAddr + Index, DebugOut,
CommentStream);
if (Size == 0)
Size = 1;
PIP.printInst(*IP, Disassembled ? &Inst : nullptr,
Bytes.slice(Index, Size), SectionAddr + Index, outs(), "",
*STI, &SP, &Rels);
outs() << CommentStream.str();
Comments.clear();
// Try to resolve the target of a call, tail call, etc. to a specific
// symbol.
if (MIA && (MIA->isCall(Inst) || MIA->isUnconditionalBranch(Inst) ||
MIA->isConditionalBranch(Inst))) {
uint64_t Target;
if (MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target)) {
// In a relocatable object, the target's section must reside in
// the same section as the call instruction or it is accessed
// through a relocation.
//
// In a non-relocatable object, the target may be in any section.
//
// N.B. We don't walk the relocations in the relocatable case yet.
auto *TargetSectionSymbols = &Symbols;
if (!Obj->isRelocatableObject()) {
auto SectionAddress = std::upper_bound(
SectionAddresses.begin(), SectionAddresses.end(), Target,
[](uint64_t LHS,
const std::pair<uint64_t, SectionRef> &RHS) {
return LHS < RHS.first;
});
if (SectionAddress != SectionAddresses.begin()) {
--SectionAddress;
TargetSectionSymbols = &AllSymbols[SectionAddress->second];
} else {
TargetSectionSymbols = &AbsoluteSymbols;
}
}
// Find the first symbol in the section whose offset is less than
// or equal to the target. If there isn't a section that contains
// the target, find the nearest preceding absolute symbol.
auto TargetSym = std::upper_bound(
TargetSectionSymbols->begin(), TargetSectionSymbols->end(),
Target, [](uint64_t LHS,
const std::tuple<uint64_t, StringRef, uint8_t> &RHS) {
return LHS < std::get<0>(RHS);
});
if (TargetSym == TargetSectionSymbols->begin()) {
TargetSectionSymbols = &AbsoluteSymbols;
TargetSym = std::upper_bound(
AbsoluteSymbols.begin(), AbsoluteSymbols.end(),
Target, [](uint64_t LHS,
const std::tuple<uint64_t, StringRef, uint8_t> &RHS) {
return LHS < std::get<0>(RHS);
});
}
if (TargetSym != TargetSectionSymbols->begin()) {
--TargetSym;
uint64_t TargetAddress = std::get<0>(*TargetSym);
StringRef TargetName = std::get<1>(*TargetSym);
outs() << " <" << TargetName;
uint64_t Disp = Target - TargetAddress;
if (Disp)
outs() << "+0x" << Twine::utohexstr(Disp);
outs() << '>';
}
}
}
outs() << "\n";
// Hexagon does this in pretty printer
if (Obj->getArch() != Triple::hexagon)
// Print relocation for instruction.
while (RelCur != RelEnd) {
uint64_t Addr = RelCur->getOffset();
SmallString<16> Name;
SmallString<32> Val;
// If this relocation is hidden, skip it.
if (getHidden(*RelCur) || ((SectionAddr + Addr) < StartAddress)) {
++RelCur;
continue;
}
// Stop when rel_cur's address is past the current instruction.
if (Addr >= Index + Size)
break;
RelCur->getTypeName(Name);
error(getRelocationValueString(*RelCur, Val));
outs() << format(Fmt.data(), SectionAddr + Addr) << Name << "\t"
<< Val << "\n";
++RelCur;
}
}
}
}
}
void llvm::printRelocations(const ObjectFile *Obj) {
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 :
"%08" PRIx64;
// Regular objdump doesn't print relocations in non-relocatable object
// files.
if (!Obj->isRelocatableObject())
return;
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
if (Section.relocation_begin() == Section.relocation_end())
continue;
StringRef SecName;
error(Section.getName(SecName));
outs() << "RELOCATION RECORDS FOR [" << SecName << "]:\n";
for (const RelocationRef &Reloc : Section.relocations()) {
uint64_t Address = Reloc.getOffset();
SmallString<32> RelocName;
SmallString<32> ValueStr;
if (Address < StartAddress || Address > StopAddress || getHidden(Reloc))
continue;
Reloc.getTypeName(RelocName);
error(getRelocationValueString(Reloc, ValueStr));
outs() << format(Fmt.data(), Address) << " " << RelocName << " "
<< ValueStr << "\n";
}
outs() << "\n";
}
}
void llvm::printDynamicRelocations(const ObjectFile *Obj) {
// For the moment, this option is for ELF only
if (!Obj->isELF())
return;
const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj);
if (!Elf || Elf->getEType() != ELF::ET_DYN) {
error("not a dynamic object");
return;
}
std::vector<SectionRef> DynRelSec = Obj->dynamic_relocation_sections();
if (DynRelSec.empty())
return;
outs() << "DYNAMIC RELOCATION RECORDS\n";
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;
for (const SectionRef &Section : DynRelSec) {
if (Section.relocation_begin() == Section.relocation_end())
continue;
for (const RelocationRef &Reloc : Section.relocations()) {
uint64_t Address = Reloc.getOffset();
SmallString<32> RelocName;
SmallString<32> ValueStr;
Reloc.getTypeName(RelocName);
error(getRelocationValueString(Reloc, ValueStr));
outs() << format(Fmt.data(), Address) << " " << RelocName << " "
<< ValueStr << "\n";
}
}
}
void llvm::printSectionHeaders(const ObjectFile *Obj) {
outs() << "Sections:\n"
"Idx Name Size Address Type\n";
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
StringRef Name;
error(Section.getName(Name));
uint64_t Address = Section.getAddress();
uint64_t Size = Section.getSize();
bool Text = Section.isText();
bool Data = Section.isData();
bool BSS = Section.isBSS();
std::string Type = (std::string(Text ? "TEXT " : "") +
(Data ? "DATA " : "") + (BSS ? "BSS" : ""));
outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n",
(unsigned)Section.getIndex(), Name.str().c_str(), Size,
Address, Type.c_str());
}
outs() << "\n";
}
void llvm::printSectionContents(const ObjectFile *Obj) {
std::error_code EC;
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
StringRef Name;
StringRef Contents;
error(Section.getName(Name));
uint64_t BaseAddr = Section.getAddress();
uint64_t Size = Section.getSize();
if (!Size)
continue;
outs() << "Contents of section " << Name << ":\n";
if (Section.isBSS()) {
outs() << format("<skipping contents of bss section at [%04" PRIx64
", %04" PRIx64 ")>\n",
BaseAddr, BaseAddr + Size);
continue;
}
error(Section.getContents(Contents));
// Dump out the content as hex and printable ascii characters.
for (std::size_t Addr = 0, End = Contents.size(); Addr < End; Addr += 16) {
outs() << format(" %04" PRIx64 " ", BaseAddr + Addr);
// Dump line of hex.
for (std::size_t I = 0; I < 16; ++I) {
if (I != 0 && I % 4 == 0)
outs() << ' ';
if (Addr + I < End)
outs() << hexdigit((Contents[Addr + I] >> 4) & 0xF, true)
<< hexdigit(Contents[Addr + I] & 0xF, true);
else
outs() << " ";
}
// Print ascii.
outs() << " ";
for (std::size_t I = 0; I < 16 && Addr + I < End; ++I) {
if (isPrint(static_cast<unsigned char>(Contents[Addr + I]) & 0xFF))
outs() << Contents[Addr + I];
else
outs() << ".";
}
outs() << "\n";
}
}
}
void llvm::printSymbolTable(const ObjectFile *O, StringRef ArchiveName,
StringRef ArchitectureName) {
outs() << "SYMBOL TABLE:\n";
if (const COFFObjectFile *Coff = dyn_cast<const COFFObjectFile>(O)) {
printCOFFSymbolTable(Coff);
return;
}
for (auto I = O->symbol_begin(), E = O->symbol_end(); I != E; ++I) {
// Skip printing the special zero symbol when dumping an ELF file.
// This makes the output consistent with the GNU objdump.
if (I == O->symbol_begin() && isa<ELFObjectFileBase>(O))
continue;
const SymbolRef &Symbol = *I;
Expected<uint64_t> AddressOrError = Symbol.getAddress();
if (!AddressOrError)
report_error(ArchiveName, O->getFileName(), AddressOrError.takeError(),
ArchitectureName);
uint64_t Address = *AddressOrError;
if ((Address < StartAddress) || (Address > StopAddress))
continue;
Expected<SymbolRef::Type> TypeOrError = Symbol.getType();
if (!TypeOrError)
report_error(ArchiveName, O->getFileName(), TypeOrError.takeError(),
ArchitectureName);
SymbolRef::Type Type = *TypeOrError;
uint32_t Flags = Symbol.getFlags();
Expected<section_iterator> SectionOrErr = Symbol.getSection();
if (!SectionOrErr)
report_error(ArchiveName, O->getFileName(), SectionOrErr.takeError(),
ArchitectureName);
section_iterator Section = *SectionOrErr;
StringRef Name;
if (Type == SymbolRef::ST_Debug && Section != O->section_end()) {
Section->getName(Name);
} else {
Expected<StringRef> NameOrErr = Symbol.getName();
if (!NameOrErr)
report_error(ArchiveName, O->getFileName(), NameOrErr.takeError(),
ArchitectureName);
Name = *NameOrErr;
}
bool Global = Flags & SymbolRef::SF_Global;
bool Weak = Flags & SymbolRef::SF_Weak;
bool Absolute = Flags & SymbolRef::SF_Absolute;
bool Common = Flags & SymbolRef::SF_Common;
bool Hidden = Flags & SymbolRef::SF_Hidden;
char GlobLoc = ' ';
if (Type != SymbolRef::ST_Unknown)
GlobLoc = Global ? 'g' : 'l';
char Debug = (Type == SymbolRef::ST_Debug || Type == SymbolRef::ST_File)
? 'd' : ' ';
char FileFunc = ' ';
if (Type == SymbolRef::ST_File)
FileFunc = 'f';
else if (Type == SymbolRef::ST_Function)
FileFunc = 'F';
else if (Type == SymbolRef::ST_Data)
FileFunc = 'O';
const char *Fmt = O->getBytesInAddress() > 4 ? "%016" PRIx64 :
"%08" PRIx64;
outs() << format(Fmt, Address) << " "
<< GlobLoc // Local -> 'l', Global -> 'g', Neither -> ' '
<< (Weak ? 'w' : ' ') // Weak?
<< ' ' // Constructor. Not supported yet.
<< ' ' // Warning. Not supported yet.
<< ' ' // Indirect reference to another symbol.
<< Debug // Debugging (d) or dynamic (D) symbol.
<< FileFunc // Name of function (F), file (f) or object (O).
<< ' ';
if (Absolute) {
outs() << "*ABS*";
} else if (Common) {
outs() << "*COM*";
} else if (Section == O->section_end()) {
outs() << "*UND*";
} else {
if (const MachOObjectFile *MachO =
dyn_cast<const MachOObjectFile>(O)) {
DataRefImpl DR = Section->getRawDataRefImpl();
StringRef SegmentName = MachO->getSectionFinalSegmentName(DR);
outs() << SegmentName << ",";
}
StringRef SectionName;
error(Section->getName(SectionName));
outs() << SectionName;
}
- outs() << '\t';
if (Common || isa<ELFObjectFileBase>(O)) {
uint64_t Val =
Common ? Symbol.getAlignment() : ELFSymbolRef(Symbol).getSize();
- outs() << format("\t %08" PRIx64 " ", Val);
+ outs() << format("\t%08" PRIx64, Val);
}
- if (Hidden)
- outs() << ".hidden ";
+ if (isa<ELFObjectFileBase>(O)) {
+ uint8_t Other = ELFSymbolRef(Symbol).getOther();
+ switch (Other) {
+ case ELF::STV_DEFAULT:
+ break;
+ case ELF::STV_INTERNAL:
+ outs() << " .internal";
+ break;
+ case ELF::STV_HIDDEN:
+ outs() << " .hidden";
+ break;
+ case ELF::STV_PROTECTED:
+ outs() << " .protected";
+ break;
+ default:
+ outs() << format(" 0x%02x", Other);
+ break;
+ }
+ } else if (Hidden) {
+ outs() << " .hidden";
+ }
if (Demangle)
- outs() << demangle(Name) << '\n';
+ outs() << ' ' << demangle(Name) << '\n';
else
- outs() << Name << '\n';
+ outs() << ' ' << Name << '\n';
}
}
static void printUnwindInfo(const ObjectFile *O) {
outs() << "Unwind info:\n\n";
if (const COFFObjectFile *Coff = dyn_cast<COFFObjectFile>(O))
printCOFFUnwindInfo(Coff);
else if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O))
printMachOUnwindInfo(MachO);
else
// TODO: Extract DWARF dump tool to objdump.
WithColor::error(errs(), ToolName)
<< "This operation is only currently supported "
"for COFF and MachO object files.\n";
}
void llvm::printExportsTrie(const ObjectFile *o) {
outs() << "Exports trie:\n";
if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachOExportsTrie(MachO);
else
WithColor::error(errs(), ToolName)
<< "This operation is only currently supported "
"for Mach-O executable files.\n";
}
void llvm::printRebaseTable(ObjectFile *o) {
outs() << "Rebase table:\n";
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachORebaseTable(MachO);
else
WithColor::error(errs(), ToolName)
<< "This operation is only currently supported "
"for Mach-O executable files.\n";
}
void llvm::printBindTable(ObjectFile *o) {
outs() << "Bind table:\n";
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachOBindTable(MachO);
else
WithColor::error(errs(), ToolName)
<< "This operation is only currently supported "
"for Mach-O executable files.\n";
}
void llvm::printLazyBindTable(ObjectFile *o) {
outs() << "Lazy bind table:\n";
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachOLazyBindTable(MachO);
else
WithColor::error(errs(), ToolName)
<< "This operation is only currently supported "
"for Mach-O executable files.\n";
}
void llvm::printWeakBindTable(ObjectFile *o) {
outs() << "Weak bind table:\n";
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachOWeakBindTable(MachO);
else
WithColor::error(errs(), ToolName)
<< "This operation is only currently supported "
"for Mach-O executable files.\n";
}
/// Dump the raw contents of the __clangast section so the output can be piped
/// into llvm-bcanalyzer.
void llvm::printRawClangAST(const ObjectFile *Obj) {
if (outs().is_displayed()) {
WithColor::error(errs(), ToolName)
<< "The -raw-clang-ast option will dump the raw binary contents of "
"the clang ast section.\n"
"Please redirect the output to a file or another program such as "
"llvm-bcanalyzer.\n";
return;
}
StringRef ClangASTSectionName("__clangast");
if (isa<COFFObjectFile>(Obj)) {
ClangASTSectionName = "clangast";
}
Optional<object::SectionRef> ClangASTSection;
for (auto Sec : ToolSectionFilter(*Obj)) {
StringRef Name;
Sec.getName(Name);
if (Name == ClangASTSectionName) {
ClangASTSection = Sec;
break;
}
}
if (!ClangASTSection)
return;
StringRef ClangASTContents;
error(ClangASTSection.getValue().getContents(ClangASTContents));
outs().write(ClangASTContents.data(), ClangASTContents.size());
}
static void printFaultMaps(const ObjectFile *Obj) {
StringRef FaultMapSectionName;
if (isa<ELFObjectFileBase>(Obj)) {
FaultMapSectionName = ".llvm_faultmaps";
} else if (isa<MachOObjectFile>(Obj)) {
FaultMapSectionName = "__llvm_faultmaps";
} else {
WithColor::error(errs(), ToolName)
<< "This operation is only currently supported "
"for ELF and Mach-O executable files.\n";
return;
}
Optional<object::SectionRef> FaultMapSection;
for (auto Sec : ToolSectionFilter(*Obj)) {
StringRef Name;
Sec.getName(Name);
if (Name == FaultMapSectionName) {
FaultMapSection = Sec;
break;
}
}
outs() << "FaultMap table:\n";
if (!FaultMapSection.hasValue()) {
outs() << "<not found>\n";
return;
}
StringRef FaultMapContents;
error(FaultMapSection.getValue().getContents(FaultMapContents));
FaultMapParser FMP(FaultMapContents.bytes_begin(),
FaultMapContents.bytes_end());
outs() << FMP;
}
static void printPrivateFileHeaders(const ObjectFile *O, bool OnlyFirst) {
if (O->isELF()) {
printELFFileHeader(O);
return printELFDynamicSection(O);
}
if (O->isCOFF())
return printCOFFFileHeader(O);
if (O->isWasm())
return printWasmFileHeader(O);
if (O->isMachO()) {
printMachOFileHeader(O);
if (!OnlyFirst)
printMachOLoadCommands(O);
return;
}
report_error(O->getFileName(), "Invalid/Unsupported object file format");
}
static void printFileHeaders(const ObjectFile *O) {
if (!O->isELF() && !O->isCOFF())
report_error(O->getFileName(), "Invalid/Unsupported object file format");
Triple::ArchType AT = O->getArch();
outs() << "architecture: " << Triple::getArchTypeName(AT) << "\n";
Expected<uint64_t> StartAddrOrErr = O->getStartAddress();
if (!StartAddrOrErr)
report_error(O->getFileName(), StartAddrOrErr.takeError());
StringRef Fmt = O->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;
uint64_t Address = StartAddrOrErr.get();
outs() << "start address: "
<< "0x" << format(Fmt.data(), Address) << "\n\n";
}
static void printArchiveChild(StringRef Filename, const Archive::Child &C) {
Expected<sys::fs::perms> ModeOrErr = C.getAccessMode();
if (!ModeOrErr) {
WithColor::error(errs(), ToolName) << "ill-formed archive entry.\n";
consumeError(ModeOrErr.takeError());
return;
}
sys::fs::perms Mode = ModeOrErr.get();
outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");
outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");
outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");
outs() << ((Mode & sys::fs::group_read) ? "r" : "-");
outs() << ((Mode & sys::fs::group_write) ? "w" : "-");
outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");
outs() << ((Mode & sys::fs::others_read) ? "r" : "-");
outs() << ((Mode & sys::fs::others_write) ? "w" : "-");
outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");
outs() << " ";
Expected<unsigned> UIDOrErr = C.getUID();
if (!UIDOrErr)
report_error(Filename, UIDOrErr.takeError());
unsigned UID = UIDOrErr.get();
outs() << format("%d/", UID);
Expected<unsigned> GIDOrErr = C.getGID();
if (!GIDOrErr)
report_error(Filename, GIDOrErr.takeError());
unsigned GID = GIDOrErr.get();
outs() << format("%-d ", GID);
Expected<uint64_t> Size = C.getRawSize();
if (!Size)
report_error(Filename, Size.takeError());
outs() << format("%6" PRId64, Size.get()) << " ";
StringRef RawLastModified = C.getRawLastModified();
unsigned Seconds;
if (RawLastModified.getAsInteger(10, Seconds))
outs() << "(date: \"" << RawLastModified
<< "\" contains non-decimal chars) ";
else {
// Since ctime(3) returns a 26 character string of the form:
// "Sun Sep 16 01:03:52 1973\n\0"
// just print 24 characters.
time_t t = Seconds;
outs() << format("%.24s ", ctime(&t));
}
StringRef Name = "";
Expected<StringRef> NameOrErr = C.getName();
if (!NameOrErr) {
consumeError(NameOrErr.takeError());
Expected<StringRef> RawNameOrErr = C.getRawName();
if (!RawNameOrErr)
report_error(Filename, NameOrErr.takeError());
Name = RawNameOrErr.get();
} else {
Name = NameOrErr.get();
}
outs() << Name << "\n";
}
static void dumpObject(ObjectFile *O, const Archive *A = nullptr,
const Archive::Child *C = nullptr) {
// Avoid other output when using a raw option.
if (!RawClangAST) {
outs() << '\n';
if (A)
outs() << A->getFileName() << "(" << O->getFileName() << ")";
else
outs() << O->getFileName();
outs() << ":\tfile format " << O->getFileFormatName() << "\n\n";
}
StringRef ArchiveName = A ? A->getFileName() : "";
if (FileHeaders)
printFileHeaders(O);
if (ArchiveHeaders && !MachOOpt && C)
printArchiveChild(ArchiveName, *C);
if (Disassemble)
disassembleObject(O, Relocations);
if (Relocations && !Disassemble)
printRelocations(O);
if (DynamicRelocations)
printDynamicRelocations(O);
if (SectionHeaders)
printSectionHeaders(O);
if (SectionContents)
printSectionContents(O);
if (SymbolTable)
printSymbolTable(O, ArchiveName);
if (UnwindInfo)
printUnwindInfo(O);
if (PrivateHeaders || FirstPrivateHeader)
printPrivateFileHeaders(O, FirstPrivateHeader);
if (ExportsTrie)
printExportsTrie(O);
if (Rebase)
printRebaseTable(O);
if (Bind)
printBindTable(O);
if (LazyBind)
printLazyBindTable(O);
if (WeakBind)
printWeakBindTable(O);
if (RawClangAST)
printRawClangAST(O);
if (PrintFaultMaps)
printFaultMaps(O);
if (DwarfDumpType != DIDT_Null) {
std::unique_ptr<DIContext> DICtx = DWARFContext::create(*O);
// Dump the complete DWARF structure.
DIDumpOptions DumpOpts;
DumpOpts.DumpType = DwarfDumpType;
DICtx->dump(outs(), DumpOpts);
}
}
static void dumpObject(const COFFImportFile *I, const Archive *A,
const Archive::Child *C = nullptr) {
StringRef ArchiveName = A ? A->getFileName() : "";
// Avoid other output when using a raw option.
if (!RawClangAST)
outs() << '\n'
<< ArchiveName << "(" << I->getFileName() << ")"
<< ":\tfile format COFF-import-file"
<< "\n\n";
if (ArchiveHeaders && !MachOOpt && C)
printArchiveChild(ArchiveName, *C);
if (SymbolTable)
printCOFFSymbolTable(I);
}
/// Dump each object file in \a a;
static void dumpArchive(const Archive *A) {
Error Err = Error::success();
for (auto &C : A->children(Err)) {
Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
report_error(A->getFileName(), C, std::move(E));
continue;
}
if (ObjectFile *O = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
dumpObject(O, A, &C);
else if (COFFImportFile *I = dyn_cast<COFFImportFile>(&*ChildOrErr.get()))
dumpObject(I, A, &C);
else
report_error(A->getFileName(), object_error::invalid_file_type);
}
if (Err)
report_error(A->getFileName(), std::move(Err));
}
/// Open file and figure out how to dump it.
static void dumpInput(StringRef file) {
// If we are using the Mach-O specific object file parser, then let it parse
// the file and process the command line options. So the -arch flags can
// be used to select specific slices, etc.
if (MachOOpt) {
parseInputMachO(file);
return;
}
// Attempt to open the binary.
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
if (!BinaryOrErr)
report_error(file, BinaryOrErr.takeError());
Binary &Binary = *BinaryOrErr.get().getBinary();
if (Archive *A = dyn_cast<Archive>(&Binary))
dumpArchive(A);
else if (ObjectFile *O = dyn_cast<ObjectFile>(&Binary))
dumpObject(O);
else if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Binary))
parseInputMachO(UB);
else
report_error(file, object_error::invalid_file_type);
}
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
// Initialize targets and assembly printers/parsers.
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllDisassemblers();
// Register the target printer for --version.
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
cl::ParseCommandLineOptions(argc, argv, "llvm object file dumper\n");
ToolName = argv[0];
// Defaults to a.out if no filenames specified.
if (InputFilenames.empty())
InputFilenames.push_back("a.out");
if (AllHeaders)
FileHeaders = PrivateHeaders = Relocations = SectionHeaders = SymbolTable =
true;
if (DisassembleAll || PrintSource || PrintLines)
Disassemble = true;
if (!Disassemble
&& !Relocations
&& !DynamicRelocations
&& !SectionHeaders
&& !SectionContents
&& !SymbolTable
&& !UnwindInfo
&& !PrivateHeaders
&& !FileHeaders
&& !FirstPrivateHeader
&& !ExportsTrie
&& !Rebase
&& !Bind
&& !LazyBind
&& !WeakBind
&& !RawClangAST
&& !(UniversalHeaders && MachOOpt)
&& !ArchiveHeaders
&& !(IndirectSymbols && MachOOpt)
&& !(DataInCode && MachOOpt)
&& !(LinkOptHints && MachOOpt)
&& !(InfoPlist && MachOOpt)
&& !(DylibsUsed && MachOOpt)
&& !(DylibId && MachOOpt)
&& !(ObjcMetaData && MachOOpt)
&& !(!FilterSections.empty() && MachOOpt)
&& !PrintFaultMaps
&& DwarfDumpType == DIDT_Null) {
cl::PrintHelpMessage();
return 2;
}
DisasmFuncsSet.insert(DisassembleFunctions.begin(),
DisassembleFunctions.end());
llvm::for_each(InputFilenames, dumpInput);
return EXIT_SUCCESS;
}
Index: stable/11/contrib/openmp/runtime/src/kmp_atomic.h
===================================================================
--- stable/11/contrib/openmp/runtime/src/kmp_atomic.h (revision 350258)
+++ stable/11/contrib/openmp/runtime/src/kmp_atomic.h (revision 350259)
@@ -1,1776 +1,1776 @@
/*
* kmp_atomic.h - ATOMIC header file
*/
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef KMP_ATOMIC_H
#define KMP_ATOMIC_H
#include "kmp_lock.h"
#include "kmp_os.h"
#if OMPT_SUPPORT
#include "ompt-specific.h"
#endif
// C++ build port.
// Intel compiler does not support _Complex datatype on win.
// Intel compiler supports _Complex datatype on lin and mac.
// On the other side, there is a problem of stack alignment on lin_32 and mac_32
// if the rhs is cmplx80 or cmplx128 typedef'ed datatype.
// The decision is: to use compiler supported _Complex type on lin and mac,
// to use typedef'ed types on win.
// Condition for WIN64 was modified in anticipation of 10.1 build compiler.
#if defined(__cplusplus) && (KMP_OS_WINDOWS)
// create shortcuts for c99 complex types
// Visual Studio cannot have function parameters that have the
// align __declspec attribute, so we must remove it. (Compiler Error C2719)
#if KMP_COMPILER_MSVC
#undef KMP_DO_ALIGN
#define KMP_DO_ALIGN(alignment) /* Nothing */
#endif
#if (_MSC_VER < 1600) && defined(_DEBUG)
// Workaround for the problem of _DebugHeapTag unresolved external.
// This problem prevented to use our static debug library for C tests
// compiled with /MDd option (the library itself built with /MTd),
#undef _DEBUG
#define _DEBUG_TEMPORARILY_UNSET_
#endif
#include <complex>
template <typename type_lhs, typename type_rhs>
std::complex<type_lhs> __kmp_lhs_div_rhs(const std::complex<type_lhs> &lhs,
const std::complex<type_rhs> &rhs) {
type_lhs a = lhs.real();
type_lhs b = lhs.imag();
type_rhs c = rhs.real();
type_rhs d = rhs.imag();
type_rhs den = c * c + d * d;
type_rhs r = (a * c + b * d);
type_rhs i = (b * c - a * d);
std::complex<type_lhs> ret(r / den, i / den);
return ret;
}
// complex8
struct __kmp_cmplx64_t : std::complex<double> {
__kmp_cmplx64_t() : std::complex<double>() {}
__kmp_cmplx64_t(const std::complex<double> &cd) : std::complex<double>(cd) {}
void operator/=(const __kmp_cmplx64_t &rhs) {
std::complex<double> lhs = *this;
*this = __kmp_lhs_div_rhs(lhs, rhs);
}
__kmp_cmplx64_t operator/(const __kmp_cmplx64_t &rhs) {
std::complex<double> lhs = *this;
return __kmp_lhs_div_rhs(lhs, rhs);
}
};
typedef struct __kmp_cmplx64_t kmp_cmplx64;
// complex4
struct __kmp_cmplx32_t : std::complex<float> {
__kmp_cmplx32_t() : std::complex<float>() {}
__kmp_cmplx32_t(const std::complex<float> &cf) : std::complex<float>(cf) {}
__kmp_cmplx32_t operator+(const __kmp_cmplx32_t &b) {
std::complex<float> lhs = *this;
std::complex<float> rhs = b;
return (lhs + rhs);
}
__kmp_cmplx32_t operator-(const __kmp_cmplx32_t &b) {
std::complex<float> lhs = *this;
std::complex<float> rhs = b;
return (lhs - rhs);
}
__kmp_cmplx32_t operator*(const __kmp_cmplx32_t &b) {
std::complex<float> lhs = *this;
std::complex<float> rhs = b;
return (lhs * rhs);
}
__kmp_cmplx32_t operator+(const kmp_cmplx64 &b) {
kmp_cmplx64 t = kmp_cmplx64(*this) + b;
std::complex<double> d(t);
std::complex<float> f(d);
__kmp_cmplx32_t r(f);
return r;
}
__kmp_cmplx32_t operator-(const kmp_cmplx64 &b) {
kmp_cmplx64 t = kmp_cmplx64(*this) - b;
std::complex<double> d(t);
std::complex<float> f(d);
__kmp_cmplx32_t r(f);
return r;
}
__kmp_cmplx32_t operator*(const kmp_cmplx64 &b) {
kmp_cmplx64 t = kmp_cmplx64(*this) * b;
std::complex<double> d(t);
std::complex<float> f(d);
__kmp_cmplx32_t r(f);
return r;
}
void operator/=(const __kmp_cmplx32_t &rhs) {
std::complex<float> lhs = *this;
*this = __kmp_lhs_div_rhs(lhs, rhs);
}
__kmp_cmplx32_t operator/(const __kmp_cmplx32_t &rhs) {
std::complex<float> lhs = *this;
return __kmp_lhs_div_rhs(lhs, rhs);
}
void operator/=(const kmp_cmplx64 &rhs) {
std::complex<float> lhs = *this;
*this = __kmp_lhs_div_rhs(lhs, rhs);
}
__kmp_cmplx32_t operator/(const kmp_cmplx64 &rhs) {
std::complex<float> lhs = *this;
return __kmp_lhs_div_rhs(lhs, rhs);
}
};
typedef struct __kmp_cmplx32_t kmp_cmplx32;
// complex10
struct KMP_DO_ALIGN(16) __kmp_cmplx80_t : std::complex<long double> {
__kmp_cmplx80_t() : std::complex<long double>() {}
__kmp_cmplx80_t(const std::complex<long double> &cld)
: std::complex<long double>(cld) {}
void operator/=(const __kmp_cmplx80_t &rhs) {
std::complex<long double> lhs = *this;
*this = __kmp_lhs_div_rhs(lhs, rhs);
}
__kmp_cmplx80_t operator/(const __kmp_cmplx80_t &rhs) {
std::complex<long double> lhs = *this;
return __kmp_lhs_div_rhs(lhs, rhs);
}
};
typedef KMP_DO_ALIGN(16) struct __kmp_cmplx80_t kmp_cmplx80;
// complex16
#if KMP_HAVE_QUAD
struct __kmp_cmplx128_t : std::complex<_Quad> {
__kmp_cmplx128_t() : std::complex<_Quad>() {}
__kmp_cmplx128_t(const std::complex<_Quad> &cq) : std::complex<_Quad>(cq) {}
void operator/=(const __kmp_cmplx128_t &rhs) {
std::complex<_Quad> lhs = *this;
*this = __kmp_lhs_div_rhs(lhs, rhs);
}
__kmp_cmplx128_t operator/(const __kmp_cmplx128_t &rhs) {
std::complex<_Quad> lhs = *this;
return __kmp_lhs_div_rhs(lhs, rhs);
}
};
typedef struct __kmp_cmplx128_t kmp_cmplx128;
#endif /* KMP_HAVE_QUAD */
#ifdef _DEBUG_TEMPORARILY_UNSET_
#undef _DEBUG_TEMPORARILY_UNSET_
// Set it back now
#define _DEBUG 1
#endif
#else
// create shortcuts for c99 complex types
typedef float _Complex kmp_cmplx32;
typedef double _Complex kmp_cmplx64;
typedef long double _Complex kmp_cmplx80;
#if KMP_HAVE_QUAD
typedef _Quad _Complex kmp_cmplx128;
#endif
#endif
// Compiler 12.0 changed alignment of 16 and 32-byte arguments (like _Quad
// and kmp_cmplx128) on IA-32 architecture. The following aligned structures
// are implemented to support the old alignment in 10.1, 11.0, 11.1 and
// introduce the new alignment in 12.0. See CQ88405.
#if KMP_ARCH_X86 && KMP_HAVE_QUAD
// 4-byte aligned structures for backward compatibility.
#pragma pack(push, 4)
struct KMP_DO_ALIGN(4) Quad_a4_t {
_Quad q;
Quad_a4_t() : q() {}
Quad_a4_t(const _Quad &cq) : q(cq) {}
Quad_a4_t operator+(const Quad_a4_t &b) {
_Quad lhs = (*this).q;
_Quad rhs = b.q;
return (Quad_a4_t)(lhs + rhs);
}
Quad_a4_t operator-(const Quad_a4_t &b) {
_Quad lhs = (*this).q;
_Quad rhs = b.q;
return (Quad_a4_t)(lhs - rhs);
}
Quad_a4_t operator*(const Quad_a4_t &b) {
_Quad lhs = (*this).q;
_Quad rhs = b.q;
return (Quad_a4_t)(lhs * rhs);
}
Quad_a4_t operator/(const Quad_a4_t &b) {
_Quad lhs = (*this).q;
_Quad rhs = b.q;
return (Quad_a4_t)(lhs / rhs);
}
};
struct KMP_DO_ALIGN(4) kmp_cmplx128_a4_t {
kmp_cmplx128 q;
kmp_cmplx128_a4_t() : q() {}
kmp_cmplx128_a4_t(const kmp_cmplx128 &c128) : q(c128) {}
kmp_cmplx128_a4_t operator+(const kmp_cmplx128_a4_t &b) {
kmp_cmplx128 lhs = (*this).q;
kmp_cmplx128 rhs = b.q;
return (kmp_cmplx128_a4_t)(lhs + rhs);
}
kmp_cmplx128_a4_t operator-(const kmp_cmplx128_a4_t &b) {
kmp_cmplx128 lhs = (*this).q;
kmp_cmplx128 rhs = b.q;
return (kmp_cmplx128_a4_t)(lhs - rhs);
}
kmp_cmplx128_a4_t operator*(const kmp_cmplx128_a4_t &b) {
kmp_cmplx128 lhs = (*this).q;
kmp_cmplx128 rhs = b.q;
return (kmp_cmplx128_a4_t)(lhs * rhs);
}
kmp_cmplx128_a4_t operator/(const kmp_cmplx128_a4_t &b) {
kmp_cmplx128 lhs = (*this).q;
kmp_cmplx128 rhs = b.q;
return (kmp_cmplx128_a4_t)(lhs / rhs);
}
};
#pragma pack(pop)
// New 16-byte aligned structures for 12.0 compiler.
struct KMP_DO_ALIGN(16) Quad_a16_t {
_Quad q;
Quad_a16_t() : q() {}
Quad_a16_t(const _Quad &cq) : q(cq) {}
Quad_a16_t operator+(const Quad_a16_t &b) {
_Quad lhs = (*this).q;
_Quad rhs = b.q;
return (Quad_a16_t)(lhs + rhs);
}
Quad_a16_t operator-(const Quad_a16_t &b) {
_Quad lhs = (*this).q;
_Quad rhs = b.q;
return (Quad_a16_t)(lhs - rhs);
}
Quad_a16_t operator*(const Quad_a16_t &b) {
_Quad lhs = (*this).q;
_Quad rhs = b.q;
return (Quad_a16_t)(lhs * rhs);
}
Quad_a16_t operator/(const Quad_a16_t &b) {
_Quad lhs = (*this).q;
_Quad rhs = b.q;
return (Quad_a16_t)(lhs / rhs);
}
};
struct KMP_DO_ALIGN(16) kmp_cmplx128_a16_t {
kmp_cmplx128 q;
kmp_cmplx128_a16_t() : q() {}
kmp_cmplx128_a16_t(const kmp_cmplx128 &c128) : q(c128) {}
kmp_cmplx128_a16_t operator+(const kmp_cmplx128_a16_t &b) {
kmp_cmplx128 lhs = (*this).q;
kmp_cmplx128 rhs = b.q;
return (kmp_cmplx128_a16_t)(lhs + rhs);
}
kmp_cmplx128_a16_t operator-(const kmp_cmplx128_a16_t &b) {
kmp_cmplx128 lhs = (*this).q;
kmp_cmplx128 rhs = b.q;
return (kmp_cmplx128_a16_t)(lhs - rhs);
}
kmp_cmplx128_a16_t operator*(const kmp_cmplx128_a16_t &b) {
kmp_cmplx128 lhs = (*this).q;
kmp_cmplx128 rhs = b.q;
return (kmp_cmplx128_a16_t)(lhs * rhs);
}
kmp_cmplx128_a16_t operator/(const kmp_cmplx128_a16_t &b) {
kmp_cmplx128 lhs = (*this).q;
kmp_cmplx128 rhs = b.q;
return (kmp_cmplx128_a16_t)(lhs / rhs);
}
};
#endif
#if (KMP_ARCH_X86)
#define QUAD_LEGACY Quad_a4_t
#define CPLX128_LEG kmp_cmplx128_a4_t
#else
#define QUAD_LEGACY _Quad
#define CPLX128_LEG kmp_cmplx128
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern int __kmp_atomic_mode;
// Atomic locks can easily become contended, so we use queuing locks for them.
typedef kmp_queuing_lock_t kmp_atomic_lock_t;
static inline void __kmp_acquire_atomic_lock(kmp_atomic_lock_t *lck,
kmp_int32 gtid) {
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
- ompt_mutex_atomic, 0, kmp_mutex_impl_queuing, (ompt_wait_id_t)lck,
+ ompt_mutex_atomic, 0, kmp_mutex_impl_queuing, (ompt_wait_id_t)(uintptr_t)lck,
OMPT_GET_RETURN_ADDRESS(0));
}
#endif
__kmp_acquire_queuing_lock(lck, gtid);
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.ompt_callback_mutex_acquired) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
- ompt_mutex_atomic, (ompt_wait_id_t)lck, OMPT_GET_RETURN_ADDRESS(0));
+ ompt_mutex_atomic, (ompt_wait_id_t)(uintptr_t)lck, OMPT_GET_RETURN_ADDRESS(0));
}
#endif
}
static inline int __kmp_test_atomic_lock(kmp_atomic_lock_t *lck,
kmp_int32 gtid) {
return __kmp_test_queuing_lock(lck, gtid);
}
static inline void __kmp_release_atomic_lock(kmp_atomic_lock_t *lck,
kmp_int32 gtid) {
__kmp_release_queuing_lock(lck, gtid);
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.ompt_callback_mutex_released) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
- ompt_mutex_atomic, (ompt_wait_id_t)lck, OMPT_GET_RETURN_ADDRESS(0));
+ ompt_mutex_atomic, (ompt_wait_id_t)(uintptr_t)lck, OMPT_GET_RETURN_ADDRESS(0));
}
#endif
}
static inline void __kmp_init_atomic_lock(kmp_atomic_lock_t *lck) {
__kmp_init_queuing_lock(lck);
}
static inline void __kmp_destroy_atomic_lock(kmp_atomic_lock_t *lck) {
__kmp_destroy_queuing_lock(lck);
}
// Global Locks
extern kmp_atomic_lock_t __kmp_atomic_lock; /* Control access to all user coded
atomics in Gnu compat mode */
extern kmp_atomic_lock_t __kmp_atomic_lock_1i; /* Control access to all user
coded atomics for 1-byte fixed
data types */
extern kmp_atomic_lock_t __kmp_atomic_lock_2i; /* Control access to all user
coded atomics for 2-byte fixed
data types */
extern kmp_atomic_lock_t __kmp_atomic_lock_4i; /* Control access to all user
coded atomics for 4-byte fixed
data types */
extern kmp_atomic_lock_t __kmp_atomic_lock_4r; /* Control access to all user
coded atomics for kmp_real32
data type */
extern kmp_atomic_lock_t __kmp_atomic_lock_8i; /* Control access to all user
coded atomics for 8-byte fixed
data types */
extern kmp_atomic_lock_t __kmp_atomic_lock_8r; /* Control access to all user
coded atomics for kmp_real64
data type */
extern kmp_atomic_lock_t
__kmp_atomic_lock_8c; /* Control access to all user coded atomics for
complex byte data type */
extern kmp_atomic_lock_t
__kmp_atomic_lock_10r; /* Control access to all user coded atomics for long
double data type */
extern kmp_atomic_lock_t __kmp_atomic_lock_16r; /* Control access to all user
coded atomics for _Quad data
type */
extern kmp_atomic_lock_t __kmp_atomic_lock_16c; /* Control access to all user
coded atomics for double
complex data type*/
extern kmp_atomic_lock_t
__kmp_atomic_lock_20c; /* Control access to all user coded atomics for long
double complex type*/
extern kmp_atomic_lock_t __kmp_atomic_lock_32c; /* Control access to all user
coded atomics for _Quad
complex data type */
// Below routines for atomic UPDATE are listed
// 1-byte
void __kmpc_atomic_fixed1_add(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed1_andb(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed1_div(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed1u_div(ident_t *id_ref, int gtid, unsigned char *lhs,
unsigned char rhs);
void __kmpc_atomic_fixed1_mul(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed1_orb(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed1_shl(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed1_shr(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed1u_shr(ident_t *id_ref, int gtid, unsigned char *lhs,
unsigned char rhs);
void __kmpc_atomic_fixed1_sub(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed1_xor(ident_t *id_ref, int gtid, char *lhs, char rhs);
// 2-byte
void __kmpc_atomic_fixed2_add(ident_t *id_ref, int gtid, short *lhs, short rhs);
void __kmpc_atomic_fixed2_andb(ident_t *id_ref, int gtid, short *lhs,
short rhs);
void __kmpc_atomic_fixed2_div(ident_t *id_ref, int gtid, short *lhs, short rhs);
void __kmpc_atomic_fixed2u_div(ident_t *id_ref, int gtid, unsigned short *lhs,
unsigned short rhs);
void __kmpc_atomic_fixed2_mul(ident_t *id_ref, int gtid, short *lhs, short rhs);
void __kmpc_atomic_fixed2_orb(ident_t *id_ref, int gtid, short *lhs, short rhs);
void __kmpc_atomic_fixed2_shl(ident_t *id_ref, int gtid, short *lhs, short rhs);
void __kmpc_atomic_fixed2_shr(ident_t *id_ref, int gtid, short *lhs, short rhs);
void __kmpc_atomic_fixed2u_shr(ident_t *id_ref, int gtid, unsigned short *lhs,
unsigned short rhs);
void __kmpc_atomic_fixed2_sub(ident_t *id_ref, int gtid, short *lhs, short rhs);
void __kmpc_atomic_fixed2_xor(ident_t *id_ref, int gtid, short *lhs, short rhs);
// 4-byte add / sub fixed
void __kmpc_atomic_fixed4_add(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4_sub(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
// 4-byte add / sub float
void __kmpc_atomic_float4_add(ident_t *id_ref, int gtid, kmp_real32 *lhs,
kmp_real32 rhs);
void __kmpc_atomic_float4_sub(ident_t *id_ref, int gtid, kmp_real32 *lhs,
kmp_real32 rhs);
// 8-byte add / sub fixed
void __kmpc_atomic_fixed8_add(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8_sub(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
// 8-byte add / sub float
void __kmpc_atomic_float8_add(ident_t *id_ref, int gtid, kmp_real64 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_float8_sub(ident_t *id_ref, int gtid, kmp_real64 *lhs,
kmp_real64 rhs);
// 4-byte fixed
void __kmpc_atomic_fixed4_andb(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4_div(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4u_div(ident_t *id_ref, int gtid, kmp_uint32 *lhs,
kmp_uint32 rhs);
void __kmpc_atomic_fixed4_mul(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4_orb(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4_shl(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4_shr(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4u_shr(ident_t *id_ref, int gtid, kmp_uint32 *lhs,
kmp_uint32 rhs);
void __kmpc_atomic_fixed4_xor(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
// 8-byte fixed
void __kmpc_atomic_fixed8_andb(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8_div(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8u_div(ident_t *id_ref, int gtid, kmp_uint64 *lhs,
kmp_uint64 rhs);
void __kmpc_atomic_fixed8_mul(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8_orb(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8_shl(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8_shr(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8u_shr(ident_t *id_ref, int gtid, kmp_uint64 *lhs,
kmp_uint64 rhs);
void __kmpc_atomic_fixed8_xor(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
// 4-byte float
void __kmpc_atomic_float4_div(ident_t *id_ref, int gtid, kmp_real32 *lhs,
kmp_real32 rhs);
void __kmpc_atomic_float4_mul(ident_t *id_ref, int gtid, kmp_real32 *lhs,
kmp_real32 rhs);
// 8-byte float
void __kmpc_atomic_float8_div(ident_t *id_ref, int gtid, kmp_real64 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_float8_mul(ident_t *id_ref, int gtid, kmp_real64 *lhs,
kmp_real64 rhs);
// 1-, 2-, 4-, 8-byte logical (&&, ||)
void __kmpc_atomic_fixed1_andl(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed1_orl(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed2_andl(ident_t *id_ref, int gtid, short *lhs,
short rhs);
void __kmpc_atomic_fixed2_orl(ident_t *id_ref, int gtid, short *lhs, short rhs);
void __kmpc_atomic_fixed4_andl(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4_orl(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed8_andl(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8_orl(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
// MIN / MAX
void __kmpc_atomic_fixed1_max(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed1_min(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed2_max(ident_t *id_ref, int gtid, short *lhs, short rhs);
void __kmpc_atomic_fixed2_min(ident_t *id_ref, int gtid, short *lhs, short rhs);
void __kmpc_atomic_fixed4_max(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4_min(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed8_max(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8_min(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_float4_max(ident_t *id_ref, int gtid, kmp_real32 *lhs,
kmp_real32 rhs);
void __kmpc_atomic_float4_min(ident_t *id_ref, int gtid, kmp_real32 *lhs,
kmp_real32 rhs);
void __kmpc_atomic_float8_max(ident_t *id_ref, int gtid, kmp_real64 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_float8_min(ident_t *id_ref, int gtid, kmp_real64 *lhs,
kmp_real64 rhs);
#if KMP_HAVE_QUAD
void __kmpc_atomic_float16_max(ident_t *id_ref, int gtid, QUAD_LEGACY *lhs,
QUAD_LEGACY rhs);
void __kmpc_atomic_float16_min(ident_t *id_ref, int gtid, QUAD_LEGACY *lhs,
QUAD_LEGACY rhs);
#if (KMP_ARCH_X86)
// Routines with 16-byte arguments aligned to 16-byte boundary; IA-32
// architecture only
void __kmpc_atomic_float16_max_a16(ident_t *id_ref, int gtid, Quad_a16_t *lhs,
Quad_a16_t rhs);
void __kmpc_atomic_float16_min_a16(ident_t *id_ref, int gtid, Quad_a16_t *lhs,
Quad_a16_t rhs);
#endif
#endif
// .NEQV. (same as xor)
void __kmpc_atomic_fixed1_neqv(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed2_neqv(ident_t *id_ref, int gtid, short *lhs,
short rhs);
void __kmpc_atomic_fixed4_neqv(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed8_neqv(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
// .EQV. (same as ~xor)
void __kmpc_atomic_fixed1_eqv(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed2_eqv(ident_t *id_ref, int gtid, short *lhs, short rhs);
void __kmpc_atomic_fixed4_eqv(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed8_eqv(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
// long double type
void __kmpc_atomic_float10_add(ident_t *id_ref, int gtid, long double *lhs,
long double rhs);
void __kmpc_atomic_float10_sub(ident_t *id_ref, int gtid, long double *lhs,
long double rhs);
void __kmpc_atomic_float10_mul(ident_t *id_ref, int gtid, long double *lhs,
long double rhs);
void __kmpc_atomic_float10_div(ident_t *id_ref, int gtid, long double *lhs,
long double rhs);
// _Quad type
#if KMP_HAVE_QUAD
void __kmpc_atomic_float16_add(ident_t *id_ref, int gtid, QUAD_LEGACY *lhs,
QUAD_LEGACY rhs);
void __kmpc_atomic_float16_sub(ident_t *id_ref, int gtid, QUAD_LEGACY *lhs,
QUAD_LEGACY rhs);
void __kmpc_atomic_float16_mul(ident_t *id_ref, int gtid, QUAD_LEGACY *lhs,
QUAD_LEGACY rhs);
void __kmpc_atomic_float16_div(ident_t *id_ref, int gtid, QUAD_LEGACY *lhs,
QUAD_LEGACY rhs);
#if (KMP_ARCH_X86)
// Routines with 16-byte arguments aligned to 16-byte boundary
void __kmpc_atomic_float16_add_a16(ident_t *id_ref, int gtid, Quad_a16_t *lhs,
Quad_a16_t rhs);
void __kmpc_atomic_float16_sub_a16(ident_t *id_ref, int gtid, Quad_a16_t *lhs,
Quad_a16_t rhs);
void __kmpc_atomic_float16_mul_a16(ident_t *id_ref, int gtid, Quad_a16_t *lhs,
Quad_a16_t rhs);
void __kmpc_atomic_float16_div_a16(ident_t *id_ref, int gtid, Quad_a16_t *lhs,
Quad_a16_t rhs);
#endif
#endif
// routines for complex types
void __kmpc_atomic_cmplx4_add(ident_t *id_ref, int gtid, kmp_cmplx32 *lhs,
kmp_cmplx32 rhs);
void __kmpc_atomic_cmplx4_sub(ident_t *id_ref, int gtid, kmp_cmplx32 *lhs,
kmp_cmplx32 rhs);
void __kmpc_atomic_cmplx4_mul(ident_t *id_ref, int gtid, kmp_cmplx32 *lhs,
kmp_cmplx32 rhs);
void __kmpc_atomic_cmplx4_div(ident_t *id_ref, int gtid, kmp_cmplx32 *lhs,
kmp_cmplx32 rhs);
void __kmpc_atomic_cmplx8_add(ident_t *id_ref, int gtid, kmp_cmplx64 *lhs,
kmp_cmplx64 rhs);
void __kmpc_atomic_cmplx8_sub(ident_t *id_ref, int gtid, kmp_cmplx64 *lhs,
kmp_cmplx64 rhs);
void __kmpc_atomic_cmplx8_mul(ident_t *id_ref, int gtid, kmp_cmplx64 *lhs,
kmp_cmplx64 rhs);
void __kmpc_atomic_cmplx8_div(ident_t *id_ref, int gtid, kmp_cmplx64 *lhs,
kmp_cmplx64 rhs);
void __kmpc_atomic_cmplx10_add(ident_t *id_ref, int gtid, kmp_cmplx80 *lhs,
kmp_cmplx80 rhs);
void __kmpc_atomic_cmplx10_sub(ident_t *id_ref, int gtid, kmp_cmplx80 *lhs,
kmp_cmplx80 rhs);
void __kmpc_atomic_cmplx10_mul(ident_t *id_ref, int gtid, kmp_cmplx80 *lhs,
kmp_cmplx80 rhs);
void __kmpc_atomic_cmplx10_div(ident_t *id_ref, int gtid, kmp_cmplx80 *lhs,
kmp_cmplx80 rhs);
#if KMP_HAVE_QUAD
void __kmpc_atomic_cmplx16_add(ident_t *id_ref, int gtid, CPLX128_LEG *lhs,
CPLX128_LEG rhs);
void __kmpc_atomic_cmplx16_sub(ident_t *id_ref, int gtid, CPLX128_LEG *lhs,
CPLX128_LEG rhs);
void __kmpc_atomic_cmplx16_mul(ident_t *id_ref, int gtid, CPLX128_LEG *lhs,
CPLX128_LEG rhs);
void __kmpc_atomic_cmplx16_div(ident_t *id_ref, int gtid, CPLX128_LEG *lhs,
CPLX128_LEG rhs);
#if (KMP_ARCH_X86)
// Routines with 16-byte arguments aligned to 16-byte boundary
void __kmpc_atomic_cmplx16_add_a16(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs);
void __kmpc_atomic_cmplx16_sub_a16(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs);
void __kmpc_atomic_cmplx16_mul_a16(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs);
void __kmpc_atomic_cmplx16_div_a16(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs);
#endif
#endif
#if OMP_40_ENABLED
// OpenMP 4.0: x = expr binop x for non-commutative operations.
// Supported only on IA-32 architecture and Intel(R) 64
#if KMP_ARCH_X86 || KMP_ARCH_X86_64
void __kmpc_atomic_fixed1_sub_rev(ident_t *id_ref, int gtid, char *lhs,
char rhs);
void __kmpc_atomic_fixed1_div_rev(ident_t *id_ref, int gtid, char *lhs,
char rhs);
void __kmpc_atomic_fixed1u_div_rev(ident_t *id_ref, int gtid,
unsigned char *lhs, unsigned char rhs);
void __kmpc_atomic_fixed1_shl_rev(ident_t *id_ref, int gtid, char *lhs,
char rhs);
void __kmpc_atomic_fixed1_shr_rev(ident_t *id_ref, int gtid, char *lhs,
char rhs);
void __kmpc_atomic_fixed1u_shr_rev(ident_t *id_ref, int gtid,
unsigned char *lhs, unsigned char rhs);
void __kmpc_atomic_fixed2_sub_rev(ident_t *id_ref, int gtid, short *lhs,
short rhs);
void __kmpc_atomic_fixed2_div_rev(ident_t *id_ref, int gtid, short *lhs,
short rhs);
void __kmpc_atomic_fixed2u_div_rev(ident_t *id_ref, int gtid,
unsigned short *lhs, unsigned short rhs);
void __kmpc_atomic_fixed2_shl_rev(ident_t *id_ref, int gtid, short *lhs,
short rhs);
void __kmpc_atomic_fixed2_shr_rev(ident_t *id_ref, int gtid, short *lhs,
short rhs);
void __kmpc_atomic_fixed2u_shr_rev(ident_t *id_ref, int gtid,
unsigned short *lhs, unsigned short rhs);
void __kmpc_atomic_fixed4_sub_rev(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4_div_rev(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4u_div_rev(ident_t *id_ref, int gtid, kmp_uint32 *lhs,
kmp_uint32 rhs);
void __kmpc_atomic_fixed4_shl_rev(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4_shr_rev(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed4u_shr_rev(ident_t *id_ref, int gtid, kmp_uint32 *lhs,
kmp_uint32 rhs);
void __kmpc_atomic_fixed8_sub_rev(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8_div_rev(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8u_div_rev(ident_t *id_ref, int gtid, kmp_uint64 *lhs,
kmp_uint64 rhs);
void __kmpc_atomic_fixed8_shl_rev(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8_shr_rev(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_fixed8u_shr_rev(ident_t *id_ref, int gtid, kmp_uint64 *lhs,
kmp_uint64 rhs);
void __kmpc_atomic_float4_sub_rev(ident_t *id_ref, int gtid, float *lhs,
float rhs);
void __kmpc_atomic_float4_div_rev(ident_t *id_ref, int gtid, float *lhs,
float rhs);
void __kmpc_atomic_float8_sub_rev(ident_t *id_ref, int gtid, double *lhs,
double rhs);
void __kmpc_atomic_float8_div_rev(ident_t *id_ref, int gtid, double *lhs,
double rhs);
void __kmpc_atomic_float10_sub_rev(ident_t *id_ref, int gtid, long double *lhs,
long double rhs);
void __kmpc_atomic_float10_div_rev(ident_t *id_ref, int gtid, long double *lhs,
long double rhs);
#if KMP_HAVE_QUAD
void __kmpc_atomic_float16_sub_rev(ident_t *id_ref, int gtid, QUAD_LEGACY *lhs,
QUAD_LEGACY rhs);
void __kmpc_atomic_float16_div_rev(ident_t *id_ref, int gtid, QUAD_LEGACY *lhs,
QUAD_LEGACY rhs);
#endif
void __kmpc_atomic_cmplx4_sub_rev(ident_t *id_ref, int gtid, kmp_cmplx32 *lhs,
kmp_cmplx32 rhs);
void __kmpc_atomic_cmplx4_div_rev(ident_t *id_ref, int gtid, kmp_cmplx32 *lhs,
kmp_cmplx32 rhs);
void __kmpc_atomic_cmplx8_sub_rev(ident_t *id_ref, int gtid, kmp_cmplx64 *lhs,
kmp_cmplx64 rhs);
void __kmpc_atomic_cmplx8_div_rev(ident_t *id_ref, int gtid, kmp_cmplx64 *lhs,
kmp_cmplx64 rhs);
void __kmpc_atomic_cmplx10_sub_rev(ident_t *id_ref, int gtid, kmp_cmplx80 *lhs,
kmp_cmplx80 rhs);
void __kmpc_atomic_cmplx10_div_rev(ident_t *id_ref, int gtid, kmp_cmplx80 *lhs,
kmp_cmplx80 rhs);
#if KMP_HAVE_QUAD
void __kmpc_atomic_cmplx16_sub_rev(ident_t *id_ref, int gtid, CPLX128_LEG *lhs,
CPLX128_LEG rhs);
void __kmpc_atomic_cmplx16_div_rev(ident_t *id_ref, int gtid, CPLX128_LEG *lhs,
CPLX128_LEG rhs);
#if (KMP_ARCH_X86)
// Routines with 16-byte arguments aligned to 16-byte boundary
void __kmpc_atomic_float16_sub_a16_rev(ident_t *id_ref, int gtid,
Quad_a16_t *lhs, Quad_a16_t rhs);
void __kmpc_atomic_float16_div_a16_rev(ident_t *id_ref, int gtid,
Quad_a16_t *lhs, Quad_a16_t rhs);
void __kmpc_atomic_cmplx16_sub_a16_rev(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs);
void __kmpc_atomic_cmplx16_div_a16_rev(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs);
#endif
#endif // KMP_HAVE_QUAD
#endif // KMP_ARCH_X86 || KMP_ARCH_X86_64
#endif // OMP_40_ENABLED
// routines for mixed types
// RHS=float8
void __kmpc_atomic_fixed1_mul_float8(ident_t *id_ref, int gtid, char *lhs,
kmp_real64 rhs);
void __kmpc_atomic_fixed1_div_float8(ident_t *id_ref, int gtid, char *lhs,
kmp_real64 rhs);
void __kmpc_atomic_fixed2_mul_float8(ident_t *id_ref, int gtid, short *lhs,
kmp_real64 rhs);
void __kmpc_atomic_fixed2_div_float8(ident_t *id_ref, int gtid, short *lhs,
kmp_real64 rhs);
void __kmpc_atomic_fixed4_mul_float8(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_fixed4_div_float8(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_fixed8_mul_float8(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_fixed8_div_float8(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_float4_add_float8(ident_t *id_ref, int gtid, kmp_real32 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_float4_sub_float8(ident_t *id_ref, int gtid, kmp_real32 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_float4_mul_float8(ident_t *id_ref, int gtid, kmp_real32 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_float4_div_float8(ident_t *id_ref, int gtid, kmp_real32 *lhs,
kmp_real64 rhs);
// RHS=float16 (deprecated, to be removed when we are sure the compiler does not
// use them)
#if KMP_HAVE_QUAD
void __kmpc_atomic_fixed1_add_fp(ident_t *id_ref, int gtid, char *lhs,
_Quad rhs);
void __kmpc_atomic_fixed1u_add_fp(ident_t *id_ref, int gtid, unsigned char *lhs,
_Quad rhs);
void __kmpc_atomic_fixed1_sub_fp(ident_t *id_ref, int gtid, char *lhs,
_Quad rhs);
void __kmpc_atomic_fixed1u_sub_fp(ident_t *id_ref, int gtid, unsigned char *lhs,
_Quad rhs);
void __kmpc_atomic_fixed1_mul_fp(ident_t *id_ref, int gtid, char *lhs,
_Quad rhs);
void __kmpc_atomic_fixed1u_mul_fp(ident_t *id_ref, int gtid, unsigned char *lhs,
_Quad rhs);
void __kmpc_atomic_fixed1_div_fp(ident_t *id_ref, int gtid, char *lhs,
_Quad rhs);
void __kmpc_atomic_fixed1u_div_fp(ident_t *id_ref, int gtid, unsigned char *lhs,
_Quad rhs);
void __kmpc_atomic_fixed2_add_fp(ident_t *id_ref, int gtid, short *lhs,
_Quad rhs);
void __kmpc_atomic_fixed2u_add_fp(ident_t *id_ref, int gtid,
unsigned short *lhs, _Quad rhs);
void __kmpc_atomic_fixed2_sub_fp(ident_t *id_ref, int gtid, short *lhs,
_Quad rhs);
void __kmpc_atomic_fixed2u_sub_fp(ident_t *id_ref, int gtid,
unsigned short *lhs, _Quad rhs);
void __kmpc_atomic_fixed2_mul_fp(ident_t *id_ref, int gtid, short *lhs,
_Quad rhs);
void __kmpc_atomic_fixed2u_mul_fp(ident_t *id_ref, int gtid,
unsigned short *lhs, _Quad rhs);
void __kmpc_atomic_fixed2_div_fp(ident_t *id_ref, int gtid, short *lhs,
_Quad rhs);
void __kmpc_atomic_fixed2u_div_fp(ident_t *id_ref, int gtid,
unsigned short *lhs, _Quad rhs);
void __kmpc_atomic_fixed4_add_fp(ident_t *id_ref, int gtid, kmp_int32 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed4u_add_fp(ident_t *id_ref, int gtid, kmp_uint32 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed4_sub_fp(ident_t *id_ref, int gtid, kmp_int32 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed4u_sub_fp(ident_t *id_ref, int gtid, kmp_uint32 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed4_mul_fp(ident_t *id_ref, int gtid, kmp_int32 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed4u_mul_fp(ident_t *id_ref, int gtid, kmp_uint32 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed4_div_fp(ident_t *id_ref, int gtid, kmp_int32 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed4u_div_fp(ident_t *id_ref, int gtid, kmp_uint32 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed8_add_fp(ident_t *id_ref, int gtid, kmp_int64 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed8u_add_fp(ident_t *id_ref, int gtid, kmp_uint64 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed8_sub_fp(ident_t *id_ref, int gtid, kmp_int64 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed8u_sub_fp(ident_t *id_ref, int gtid, kmp_uint64 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed8_mul_fp(ident_t *id_ref, int gtid, kmp_int64 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed8u_mul_fp(ident_t *id_ref, int gtid, kmp_uint64 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed8_div_fp(ident_t *id_ref, int gtid, kmp_int64 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed8u_div_fp(ident_t *id_ref, int gtid, kmp_uint64 *lhs,
_Quad rhs);
void __kmpc_atomic_float4_add_fp(ident_t *id_ref, int gtid, kmp_real32 *lhs,
_Quad rhs);
void __kmpc_atomic_float4_sub_fp(ident_t *id_ref, int gtid, kmp_real32 *lhs,
_Quad rhs);
void __kmpc_atomic_float4_mul_fp(ident_t *id_ref, int gtid, kmp_real32 *lhs,
_Quad rhs);
void __kmpc_atomic_float4_div_fp(ident_t *id_ref, int gtid, kmp_real32 *lhs,
_Quad rhs);
void __kmpc_atomic_float8_add_fp(ident_t *id_ref, int gtid, kmp_real64 *lhs,
_Quad rhs);
void __kmpc_atomic_float8_sub_fp(ident_t *id_ref, int gtid, kmp_real64 *lhs,
_Quad rhs);
void __kmpc_atomic_float8_mul_fp(ident_t *id_ref, int gtid, kmp_real64 *lhs,
_Quad rhs);
void __kmpc_atomic_float8_div_fp(ident_t *id_ref, int gtid, kmp_real64 *lhs,
_Quad rhs);
void __kmpc_atomic_float10_add_fp(ident_t *id_ref, int gtid, long double *lhs,
_Quad rhs);
void __kmpc_atomic_float10_sub_fp(ident_t *id_ref, int gtid, long double *lhs,
_Quad rhs);
void __kmpc_atomic_float10_mul_fp(ident_t *id_ref, int gtid, long double *lhs,
_Quad rhs);
void __kmpc_atomic_float10_div_fp(ident_t *id_ref, int gtid, long double *lhs,
_Quad rhs);
// Reverse operations
void __kmpc_atomic_fixed1_sub_rev_fp(ident_t *id_ref, int gtid, char *lhs,
_Quad rhs);
void __kmpc_atomic_fixed1u_sub_rev_fp(ident_t *id_ref, int gtid,
unsigned char *lhs, _Quad rhs);
void __kmpc_atomic_fixed1_div_rev_fp(ident_t *id_ref, int gtid, char *lhs,
_Quad rhs);
void __kmpc_atomic_fixed1u_div_rev_fp(ident_t *id_ref, int gtid,
unsigned char *lhs, _Quad rhs);
void __kmpc_atomic_fixed2_sub_rev_fp(ident_t *id_ref, int gtid, short *lhs,
_Quad rhs);
void __kmpc_atomic_fixed2u_sub_rev_fp(ident_t *id_ref, int gtid,
unsigned short *lhs, _Quad rhs);
void __kmpc_atomic_fixed2_div_rev_fp(ident_t *id_ref, int gtid, short *lhs,
_Quad rhs);
void __kmpc_atomic_fixed2u_div_rev_fp(ident_t *id_ref, int gtid,
unsigned short *lhs, _Quad rhs);
void __kmpc_atomic_fixed4_sub_rev_fp(ident_t *id_ref, int gtid, kmp_int32 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed4u_sub_rev_fp(ident_t *id_ref, int gtid,
kmp_uint32 *lhs, _Quad rhs);
void __kmpc_atomic_fixed4_div_rev_fp(ident_t *id_ref, int gtid, kmp_int32 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed4u_div_rev_fp(ident_t *id_ref, int gtid,
kmp_uint32 *lhs, _Quad rhs);
void __kmpc_atomic_fixed8_sub_rev_fp(ident_t *id_ref, int gtid, kmp_int64 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed8u_sub_rev_fp(ident_t *id_ref, int gtid,
kmp_uint64 *lhs, _Quad rhs);
void __kmpc_atomic_fixed8_div_rev_fp(ident_t *id_ref, int gtid, kmp_int64 *lhs,
_Quad rhs);
void __kmpc_atomic_fixed8u_div_rev_fp(ident_t *id_ref, int gtid,
kmp_uint64 *lhs, _Quad rhs);
void __kmpc_atomic_float4_sub_rev_fp(ident_t *id_ref, int gtid, float *lhs,
_Quad rhs);
void __kmpc_atomic_float4_div_rev_fp(ident_t *id_ref, int gtid, float *lhs,
_Quad rhs);
void __kmpc_atomic_float8_sub_rev_fp(ident_t *id_ref, int gtid, double *lhs,
_Quad rhs);
void __kmpc_atomic_float8_div_rev_fp(ident_t *id_ref, int gtid, double *lhs,
_Quad rhs);
void __kmpc_atomic_float10_sub_rev_fp(ident_t *id_ref, int gtid,
long double *lhs, _Quad rhs);
void __kmpc_atomic_float10_div_rev_fp(ident_t *id_ref, int gtid,
long double *lhs, _Quad rhs);
#endif // KMP_HAVE_QUAD
// RHS=cmplx8
void __kmpc_atomic_cmplx4_add_cmplx8(ident_t *id_ref, int gtid,
kmp_cmplx32 *lhs, kmp_cmplx64 rhs);
void __kmpc_atomic_cmplx4_sub_cmplx8(ident_t *id_ref, int gtid,
kmp_cmplx32 *lhs, kmp_cmplx64 rhs);
void __kmpc_atomic_cmplx4_mul_cmplx8(ident_t *id_ref, int gtid,
kmp_cmplx32 *lhs, kmp_cmplx64 rhs);
void __kmpc_atomic_cmplx4_div_cmplx8(ident_t *id_ref, int gtid,
kmp_cmplx32 *lhs, kmp_cmplx64 rhs);
// generic atomic routines
void __kmpc_atomic_1(ident_t *id_ref, int gtid, void *lhs, void *rhs,
void (*f)(void *, void *, void *));
void __kmpc_atomic_2(ident_t *id_ref, int gtid, void *lhs, void *rhs,
void (*f)(void *, void *, void *));
void __kmpc_atomic_4(ident_t *id_ref, int gtid, void *lhs, void *rhs,
void (*f)(void *, void *, void *));
void __kmpc_atomic_8(ident_t *id_ref, int gtid, void *lhs, void *rhs,
void (*f)(void *, void *, void *));
void __kmpc_atomic_10(ident_t *id_ref, int gtid, void *lhs, void *rhs,
void (*f)(void *, void *, void *));
void __kmpc_atomic_16(ident_t *id_ref, int gtid, void *lhs, void *rhs,
void (*f)(void *, void *, void *));
void __kmpc_atomic_20(ident_t *id_ref, int gtid, void *lhs, void *rhs,
void (*f)(void *, void *, void *));
void __kmpc_atomic_32(ident_t *id_ref, int gtid, void *lhs, void *rhs,
void (*f)(void *, void *, void *));
// READ, WRITE, CAPTURE are supported only on IA-32 architecture and Intel(R) 64
#if KMP_ARCH_X86 || KMP_ARCH_X86_64
// Below routines for atomic READ are listed
char __kmpc_atomic_fixed1_rd(ident_t *id_ref, int gtid, char *loc);
short __kmpc_atomic_fixed2_rd(ident_t *id_ref, int gtid, short *loc);
kmp_int32 __kmpc_atomic_fixed4_rd(ident_t *id_ref, int gtid, kmp_int32 *loc);
kmp_int64 __kmpc_atomic_fixed8_rd(ident_t *id_ref, int gtid, kmp_int64 *loc);
kmp_real32 __kmpc_atomic_float4_rd(ident_t *id_ref, int gtid, kmp_real32 *loc);
kmp_real64 __kmpc_atomic_float8_rd(ident_t *id_ref, int gtid, kmp_real64 *loc);
long double __kmpc_atomic_float10_rd(ident_t *id_ref, int gtid,
long double *loc);
#if KMP_HAVE_QUAD
QUAD_LEGACY __kmpc_atomic_float16_rd(ident_t *id_ref, int gtid,
QUAD_LEGACY *loc);
#endif
// Fix for CQ220361: cmplx4 READ will return void on Windows* OS; read value
// will be returned through an additional parameter
#if (KMP_OS_WINDOWS)
void __kmpc_atomic_cmplx4_rd(kmp_cmplx32 *out, ident_t *id_ref, int gtid,
kmp_cmplx32 *loc);
#else
kmp_cmplx32 __kmpc_atomic_cmplx4_rd(ident_t *id_ref, int gtid,
kmp_cmplx32 *loc);
#endif
kmp_cmplx64 __kmpc_atomic_cmplx8_rd(ident_t *id_ref, int gtid,
kmp_cmplx64 *loc);
kmp_cmplx80 __kmpc_atomic_cmplx10_rd(ident_t *id_ref, int gtid,
kmp_cmplx80 *loc);
#if KMP_HAVE_QUAD
CPLX128_LEG __kmpc_atomic_cmplx16_rd(ident_t *id_ref, int gtid,
CPLX128_LEG *loc);
#if (KMP_ARCH_X86)
// Routines with 16-byte arguments aligned to 16-byte boundary
Quad_a16_t __kmpc_atomic_float16_a16_rd(ident_t *id_ref, int gtid,
Quad_a16_t *loc);
kmp_cmplx128_a16_t __kmpc_atomic_cmplx16_a16_rd(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *loc);
#endif
#endif
// Below routines for atomic WRITE are listed
void __kmpc_atomic_fixed1_wr(ident_t *id_ref, int gtid, char *lhs, char rhs);
void __kmpc_atomic_fixed2_wr(ident_t *id_ref, int gtid, short *lhs, short rhs);
void __kmpc_atomic_fixed4_wr(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
void __kmpc_atomic_fixed8_wr(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
void __kmpc_atomic_float4_wr(ident_t *id_ref, int gtid, kmp_real32 *lhs,
kmp_real32 rhs);
void __kmpc_atomic_float8_wr(ident_t *id_ref, int gtid, kmp_real64 *lhs,
kmp_real64 rhs);
void __kmpc_atomic_float10_wr(ident_t *id_ref, int gtid, long double *lhs,
long double rhs);
#if KMP_HAVE_QUAD
void __kmpc_atomic_float16_wr(ident_t *id_ref, int gtid, QUAD_LEGACY *lhs,
QUAD_LEGACY rhs);
#endif
void __kmpc_atomic_cmplx4_wr(ident_t *id_ref, int gtid, kmp_cmplx32 *lhs,
kmp_cmplx32 rhs);
void __kmpc_atomic_cmplx8_wr(ident_t *id_ref, int gtid, kmp_cmplx64 *lhs,
kmp_cmplx64 rhs);
void __kmpc_atomic_cmplx10_wr(ident_t *id_ref, int gtid, kmp_cmplx80 *lhs,
kmp_cmplx80 rhs);
#if KMP_HAVE_QUAD
void __kmpc_atomic_cmplx16_wr(ident_t *id_ref, int gtid, CPLX128_LEG *lhs,
CPLX128_LEG rhs);
#if (KMP_ARCH_X86)
// Routines with 16-byte arguments aligned to 16-byte boundary
void __kmpc_atomic_float16_a16_wr(ident_t *id_ref, int gtid, Quad_a16_t *lhs,
Quad_a16_t rhs);
void __kmpc_atomic_cmplx16_a16_wr(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs);
#endif
#endif
// Below routines for atomic CAPTURE are listed
// 1-byte
char __kmpc_atomic_fixed1_add_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
char __kmpc_atomic_fixed1_andb_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
char __kmpc_atomic_fixed1_div_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
unsigned char __kmpc_atomic_fixed1u_div_cpt(ident_t *id_ref, int gtid,
unsigned char *lhs,
unsigned char rhs, int flag);
char __kmpc_atomic_fixed1_mul_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
char __kmpc_atomic_fixed1_orb_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
char __kmpc_atomic_fixed1_shl_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
char __kmpc_atomic_fixed1_shr_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
unsigned char __kmpc_atomic_fixed1u_shr_cpt(ident_t *id_ref, int gtid,
unsigned char *lhs,
unsigned char rhs, int flag);
char __kmpc_atomic_fixed1_sub_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
char __kmpc_atomic_fixed1_xor_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
// 2-byte
short __kmpc_atomic_fixed2_add_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
short __kmpc_atomic_fixed2_andb_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
short __kmpc_atomic_fixed2_div_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
unsigned short __kmpc_atomic_fixed2u_div_cpt(ident_t *id_ref, int gtid,
unsigned short *lhs,
unsigned short rhs, int flag);
short __kmpc_atomic_fixed2_mul_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
short __kmpc_atomic_fixed2_orb_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
short __kmpc_atomic_fixed2_shl_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
short __kmpc_atomic_fixed2_shr_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
unsigned short __kmpc_atomic_fixed2u_shr_cpt(ident_t *id_ref, int gtid,
unsigned short *lhs,
unsigned short rhs, int flag);
short __kmpc_atomic_fixed2_sub_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
short __kmpc_atomic_fixed2_xor_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
// 4-byte add / sub fixed
kmp_int32 __kmpc_atomic_fixed4_add_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_sub_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs, int flag);
// 4-byte add / sub float
kmp_real32 __kmpc_atomic_float4_add_cpt(ident_t *id_ref, int gtid,
kmp_real32 *lhs, kmp_real32 rhs,
int flag);
kmp_real32 __kmpc_atomic_float4_sub_cpt(ident_t *id_ref, int gtid,
kmp_real32 *lhs, kmp_real32 rhs,
int flag);
// 8-byte add / sub fixed
kmp_int64 __kmpc_atomic_fixed8_add_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs, int flag);
kmp_int64 __kmpc_atomic_fixed8_sub_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs, int flag);
// 8-byte add / sub float
kmp_real64 __kmpc_atomic_float8_add_cpt(ident_t *id_ref, int gtid,
kmp_real64 *lhs, kmp_real64 rhs,
int flag);
kmp_real64 __kmpc_atomic_float8_sub_cpt(ident_t *id_ref, int gtid,
kmp_real64 *lhs, kmp_real64 rhs,
int flag);
// 4-byte fixed
kmp_int32 __kmpc_atomic_fixed4_andb_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs,
int flag);
kmp_int32 __kmpc_atomic_fixed4_div_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs, int flag);
kmp_uint32 __kmpc_atomic_fixed4u_div_cpt(ident_t *id_ref, int gtid,
kmp_uint32 *lhs, kmp_uint32 rhs,
int flag);
kmp_int32 __kmpc_atomic_fixed4_mul_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_orb_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_shl_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_shr_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs, int flag);
kmp_uint32 __kmpc_atomic_fixed4u_shr_cpt(ident_t *id_ref, int gtid,
kmp_uint32 *lhs, kmp_uint32 rhs,
int flag);
kmp_int32 __kmpc_atomic_fixed4_xor_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs, int flag);
// 8-byte fixed
kmp_int64 __kmpc_atomic_fixed8_andb_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs,
int flag);
kmp_int64 __kmpc_atomic_fixed8_div_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs, int flag);
kmp_uint64 __kmpc_atomic_fixed8u_div_cpt(ident_t *id_ref, int gtid,
kmp_uint64 *lhs, kmp_uint64 rhs,
int flag);
kmp_int64 __kmpc_atomic_fixed8_mul_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs, int flag);
kmp_int64 __kmpc_atomic_fixed8_orb_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs, int flag);
kmp_int64 __kmpc_atomic_fixed8_shl_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs, int flag);
kmp_int64 __kmpc_atomic_fixed8_shr_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs, int flag);
kmp_uint64 __kmpc_atomic_fixed8u_shr_cpt(ident_t *id_ref, int gtid,
kmp_uint64 *lhs, kmp_uint64 rhs,
int flag);
kmp_int64 __kmpc_atomic_fixed8_xor_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs, int flag);
// 4-byte float
kmp_real32 __kmpc_atomic_float4_div_cpt(ident_t *id_ref, int gtid,
kmp_real32 *lhs, kmp_real32 rhs,
int flag);
kmp_real32 __kmpc_atomic_float4_mul_cpt(ident_t *id_ref, int gtid,
kmp_real32 *lhs, kmp_real32 rhs,
int flag);
// 8-byte float
kmp_real64 __kmpc_atomic_float8_div_cpt(ident_t *id_ref, int gtid,
kmp_real64 *lhs, kmp_real64 rhs,
int flag);
kmp_real64 __kmpc_atomic_float8_mul_cpt(ident_t *id_ref, int gtid,
kmp_real64 *lhs, kmp_real64 rhs,
int flag);
// 1-, 2-, 4-, 8-byte logical (&&, ||)
char __kmpc_atomic_fixed1_andl_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
char __kmpc_atomic_fixed1_orl_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
short __kmpc_atomic_fixed2_andl_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
short __kmpc_atomic_fixed2_orl_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_andl_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs,
int flag);
kmp_int32 __kmpc_atomic_fixed4_orl_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs, int flag);
kmp_int64 __kmpc_atomic_fixed8_andl_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs,
int flag);
kmp_int64 __kmpc_atomic_fixed8_orl_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs, int flag);
// MIN / MAX
char __kmpc_atomic_fixed1_max_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
char __kmpc_atomic_fixed1_min_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
short __kmpc_atomic_fixed2_max_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
short __kmpc_atomic_fixed2_min_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_max_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_min_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs, int flag);
kmp_int64 __kmpc_atomic_fixed8_max_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs, int flag);
kmp_int64 __kmpc_atomic_fixed8_min_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs, int flag);
kmp_real32 __kmpc_atomic_float4_max_cpt(ident_t *id_ref, int gtid,
kmp_real32 *lhs, kmp_real32 rhs,
int flag);
kmp_real32 __kmpc_atomic_float4_min_cpt(ident_t *id_ref, int gtid,
kmp_real32 *lhs, kmp_real32 rhs,
int flag);
kmp_real64 __kmpc_atomic_float8_max_cpt(ident_t *id_ref, int gtid,
kmp_real64 *lhs, kmp_real64 rhs,
int flag);
kmp_real64 __kmpc_atomic_float8_min_cpt(ident_t *id_ref, int gtid,
kmp_real64 *lhs, kmp_real64 rhs,
int flag);
#if KMP_HAVE_QUAD
QUAD_LEGACY __kmpc_atomic_float16_max_cpt(ident_t *id_ref, int gtid,
QUAD_LEGACY *lhs, QUAD_LEGACY rhs,
int flag);
QUAD_LEGACY __kmpc_atomic_float16_min_cpt(ident_t *id_ref, int gtid,
QUAD_LEGACY *lhs, QUAD_LEGACY rhs,
int flag);
#endif
// .NEQV. (same as xor)
char __kmpc_atomic_fixed1_neqv_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
short __kmpc_atomic_fixed2_neqv_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_neqv_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs,
int flag);
kmp_int64 __kmpc_atomic_fixed8_neqv_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs,
int flag);
// .EQV. (same as ~xor)
char __kmpc_atomic_fixed1_eqv_cpt(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
short __kmpc_atomic_fixed2_eqv_cpt(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_eqv_cpt(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs, int flag);
kmp_int64 __kmpc_atomic_fixed8_eqv_cpt(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs, int flag);
// long double type
long double __kmpc_atomic_float10_add_cpt(ident_t *id_ref, int gtid,
long double *lhs, long double rhs,
int flag);
long double __kmpc_atomic_float10_sub_cpt(ident_t *id_ref, int gtid,
long double *lhs, long double rhs,
int flag);
long double __kmpc_atomic_float10_mul_cpt(ident_t *id_ref, int gtid,
long double *lhs, long double rhs,
int flag);
long double __kmpc_atomic_float10_div_cpt(ident_t *id_ref, int gtid,
long double *lhs, long double rhs,
int flag);
#if KMP_HAVE_QUAD
// _Quad type
QUAD_LEGACY __kmpc_atomic_float16_add_cpt(ident_t *id_ref, int gtid,
QUAD_LEGACY *lhs, QUAD_LEGACY rhs,
int flag);
QUAD_LEGACY __kmpc_atomic_float16_sub_cpt(ident_t *id_ref, int gtid,
QUAD_LEGACY *lhs, QUAD_LEGACY rhs,
int flag);
QUAD_LEGACY __kmpc_atomic_float16_mul_cpt(ident_t *id_ref, int gtid,
QUAD_LEGACY *lhs, QUAD_LEGACY rhs,
int flag);
QUAD_LEGACY __kmpc_atomic_float16_div_cpt(ident_t *id_ref, int gtid,
QUAD_LEGACY *lhs, QUAD_LEGACY rhs,
int flag);
#endif
// routines for complex types
// Workaround for cmplx4 routines - return void; captured value is returned via
// the argument
void __kmpc_atomic_cmplx4_add_cpt(ident_t *id_ref, int gtid, kmp_cmplx32 *lhs,
kmp_cmplx32 rhs, kmp_cmplx32 *out, int flag);
void __kmpc_atomic_cmplx4_sub_cpt(ident_t *id_ref, int gtid, kmp_cmplx32 *lhs,
kmp_cmplx32 rhs, kmp_cmplx32 *out, int flag);
void __kmpc_atomic_cmplx4_mul_cpt(ident_t *id_ref, int gtid, kmp_cmplx32 *lhs,
kmp_cmplx32 rhs, kmp_cmplx32 *out, int flag);
void __kmpc_atomic_cmplx4_div_cpt(ident_t *id_ref, int gtid, kmp_cmplx32 *lhs,
kmp_cmplx32 rhs, kmp_cmplx32 *out, int flag);
kmp_cmplx64 __kmpc_atomic_cmplx8_add_cpt(ident_t *id_ref, int gtid,
kmp_cmplx64 *lhs, kmp_cmplx64 rhs,
int flag);
kmp_cmplx64 __kmpc_atomic_cmplx8_sub_cpt(ident_t *id_ref, int gtid,
kmp_cmplx64 *lhs, kmp_cmplx64 rhs,
int flag);
kmp_cmplx64 __kmpc_atomic_cmplx8_mul_cpt(ident_t *id_ref, int gtid,
kmp_cmplx64 *lhs, kmp_cmplx64 rhs,
int flag);
kmp_cmplx64 __kmpc_atomic_cmplx8_div_cpt(ident_t *id_ref, int gtid,
kmp_cmplx64 *lhs, kmp_cmplx64 rhs,
int flag);
kmp_cmplx80 __kmpc_atomic_cmplx10_add_cpt(ident_t *id_ref, int gtid,
kmp_cmplx80 *lhs, kmp_cmplx80 rhs,
int flag);
kmp_cmplx80 __kmpc_atomic_cmplx10_sub_cpt(ident_t *id_ref, int gtid,
kmp_cmplx80 *lhs, kmp_cmplx80 rhs,
int flag);
kmp_cmplx80 __kmpc_atomic_cmplx10_mul_cpt(ident_t *id_ref, int gtid,
kmp_cmplx80 *lhs, kmp_cmplx80 rhs,
int flag);
kmp_cmplx80 __kmpc_atomic_cmplx10_div_cpt(ident_t *id_ref, int gtid,
kmp_cmplx80 *lhs, kmp_cmplx80 rhs,
int flag);
#if KMP_HAVE_QUAD
CPLX128_LEG __kmpc_atomic_cmplx16_add_cpt(ident_t *id_ref, int gtid,
CPLX128_LEG *lhs, CPLX128_LEG rhs,
int flag);
CPLX128_LEG __kmpc_atomic_cmplx16_sub_cpt(ident_t *id_ref, int gtid,
CPLX128_LEG *lhs, CPLX128_LEG rhs,
int flag);
CPLX128_LEG __kmpc_atomic_cmplx16_mul_cpt(ident_t *id_ref, int gtid,
CPLX128_LEG *lhs, CPLX128_LEG rhs,
int flag);
CPLX128_LEG __kmpc_atomic_cmplx16_div_cpt(ident_t *id_ref, int gtid,
CPLX128_LEG *lhs, CPLX128_LEG rhs,
int flag);
#if (KMP_ARCH_X86)
// Routines with 16-byte arguments aligned to 16-byte boundary
Quad_a16_t __kmpc_atomic_float16_add_a16_cpt(ident_t *id_ref, int gtid,
Quad_a16_t *lhs, Quad_a16_t rhs,
int flag);
Quad_a16_t __kmpc_atomic_float16_sub_a16_cpt(ident_t *id_ref, int gtid,
Quad_a16_t *lhs, Quad_a16_t rhs,
int flag);
Quad_a16_t __kmpc_atomic_float16_mul_a16_cpt(ident_t *id_ref, int gtid,
Quad_a16_t *lhs, Quad_a16_t rhs,
int flag);
Quad_a16_t __kmpc_atomic_float16_div_a16_cpt(ident_t *id_ref, int gtid,
Quad_a16_t *lhs, Quad_a16_t rhs,
int flag);
Quad_a16_t __kmpc_atomic_float16_max_a16_cpt(ident_t *id_ref, int gtid,
Quad_a16_t *lhs, Quad_a16_t rhs,
int flag);
Quad_a16_t __kmpc_atomic_float16_min_a16_cpt(ident_t *id_ref, int gtid,
Quad_a16_t *lhs, Quad_a16_t rhs,
int flag);
kmp_cmplx128_a16_t __kmpc_atomic_cmplx16_add_a16_cpt(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs,
int flag);
kmp_cmplx128_a16_t __kmpc_atomic_cmplx16_sub_a16_cpt(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs,
int flag);
kmp_cmplx128_a16_t __kmpc_atomic_cmplx16_mul_a16_cpt(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs,
int flag);
kmp_cmplx128_a16_t __kmpc_atomic_cmplx16_div_a16_cpt(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs,
int flag);
#endif
#endif
void __kmpc_atomic_start(void);
void __kmpc_atomic_end(void);
#if OMP_40_ENABLED
// OpenMP 4.0: v = x = expr binop x; { v = x; x = expr binop x; } { x = expr
// binop x; v = x; } for non-commutative operations.
char __kmpc_atomic_fixed1_sub_cpt_rev(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
char __kmpc_atomic_fixed1_div_cpt_rev(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
unsigned char __kmpc_atomic_fixed1u_div_cpt_rev(ident_t *id_ref, int gtid,
unsigned char *lhs,
unsigned char rhs, int flag);
char __kmpc_atomic_fixed1_shl_cpt_rev(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
char __kmpc_atomic_fixed1_shr_cpt_rev(ident_t *id_ref, int gtid, char *lhs,
char rhs, int flag);
unsigned char __kmpc_atomic_fixed1u_shr_cpt_rev(ident_t *id_ref, int gtid,
unsigned char *lhs,
unsigned char rhs, int flag);
short __kmpc_atomic_fixed2_sub_cpt_rev(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
short __kmpc_atomic_fixed2_div_cpt_rev(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
unsigned short __kmpc_atomic_fixed2u_div_cpt_rev(ident_t *id_ref, int gtid,
unsigned short *lhs,
unsigned short rhs, int flag);
short __kmpc_atomic_fixed2_shl_cpt_rev(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
short __kmpc_atomic_fixed2_shr_cpt_rev(ident_t *id_ref, int gtid, short *lhs,
short rhs, int flag);
unsigned short __kmpc_atomic_fixed2u_shr_cpt_rev(ident_t *id_ref, int gtid,
unsigned short *lhs,
unsigned short rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_sub_cpt_rev(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs,
int flag);
kmp_int32 __kmpc_atomic_fixed4_div_cpt_rev(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs,
int flag);
kmp_uint32 __kmpc_atomic_fixed4u_div_cpt_rev(ident_t *id_ref, int gtid,
kmp_uint32 *lhs, kmp_uint32 rhs,
int flag);
kmp_int32 __kmpc_atomic_fixed4_shl_cpt_rev(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs,
int flag);
kmp_int32 __kmpc_atomic_fixed4_shr_cpt_rev(ident_t *id_ref, int gtid,
kmp_int32 *lhs, kmp_int32 rhs,
int flag);
kmp_uint32 __kmpc_atomic_fixed4u_shr_cpt_rev(ident_t *id_ref, int gtid,
kmp_uint32 *lhs, kmp_uint32 rhs,
int flag);
kmp_int64 __kmpc_atomic_fixed8_sub_cpt_rev(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs,
int flag);
kmp_int64 __kmpc_atomic_fixed8_div_cpt_rev(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs,
int flag);
kmp_uint64 __kmpc_atomic_fixed8u_div_cpt_rev(ident_t *id_ref, int gtid,
kmp_uint64 *lhs, kmp_uint64 rhs,
int flag);
kmp_int64 __kmpc_atomic_fixed8_shl_cpt_rev(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs,
int flag);
kmp_int64 __kmpc_atomic_fixed8_shr_cpt_rev(ident_t *id_ref, int gtid,
kmp_int64 *lhs, kmp_int64 rhs,
int flag);
kmp_uint64 __kmpc_atomic_fixed8u_shr_cpt_rev(ident_t *id_ref, int gtid,
kmp_uint64 *lhs, kmp_uint64 rhs,
int flag);
float __kmpc_atomic_float4_sub_cpt_rev(ident_t *id_ref, int gtid, float *lhs,
float rhs, int flag);
float __kmpc_atomic_float4_div_cpt_rev(ident_t *id_ref, int gtid, float *lhs,
float rhs, int flag);
double __kmpc_atomic_float8_sub_cpt_rev(ident_t *id_ref, int gtid, double *lhs,
double rhs, int flag);
double __kmpc_atomic_float8_div_cpt_rev(ident_t *id_ref, int gtid, double *lhs,
double rhs, int flag);
long double __kmpc_atomic_float10_sub_cpt_rev(ident_t *id_ref, int gtid,
long double *lhs, long double rhs,
int flag);
long double __kmpc_atomic_float10_div_cpt_rev(ident_t *id_ref, int gtid,
long double *lhs, long double rhs,
int flag);
#if KMP_HAVE_QUAD
QUAD_LEGACY __kmpc_atomic_float16_sub_cpt_rev(ident_t *id_ref, int gtid,
QUAD_LEGACY *lhs, QUAD_LEGACY rhs,
int flag);
QUAD_LEGACY __kmpc_atomic_float16_div_cpt_rev(ident_t *id_ref, int gtid,
QUAD_LEGACY *lhs, QUAD_LEGACY rhs,
int flag);
#endif
// Workaround for cmplx4 routines - return void; captured value is returned via
// the argument
void __kmpc_atomic_cmplx4_sub_cpt_rev(ident_t *id_ref, int gtid,
kmp_cmplx32 *lhs, kmp_cmplx32 rhs,
kmp_cmplx32 *out, int flag);
void __kmpc_atomic_cmplx4_div_cpt_rev(ident_t *id_ref, int gtid,
kmp_cmplx32 *lhs, kmp_cmplx32 rhs,
kmp_cmplx32 *out, int flag);
kmp_cmplx64 __kmpc_atomic_cmplx8_sub_cpt_rev(ident_t *id_ref, int gtid,
kmp_cmplx64 *lhs, kmp_cmplx64 rhs,
int flag);
kmp_cmplx64 __kmpc_atomic_cmplx8_div_cpt_rev(ident_t *id_ref, int gtid,
kmp_cmplx64 *lhs, kmp_cmplx64 rhs,
int flag);
kmp_cmplx80 __kmpc_atomic_cmplx10_sub_cpt_rev(ident_t *id_ref, int gtid,
kmp_cmplx80 *lhs, kmp_cmplx80 rhs,
int flag);
kmp_cmplx80 __kmpc_atomic_cmplx10_div_cpt_rev(ident_t *id_ref, int gtid,
kmp_cmplx80 *lhs, kmp_cmplx80 rhs,
int flag);
#if KMP_HAVE_QUAD
CPLX128_LEG __kmpc_atomic_cmplx16_sub_cpt_rev(ident_t *id_ref, int gtid,
CPLX128_LEG *lhs, CPLX128_LEG rhs,
int flag);
CPLX128_LEG __kmpc_atomic_cmplx16_div_cpt_rev(ident_t *id_ref, int gtid,
CPLX128_LEG *lhs, CPLX128_LEG rhs,
int flag);
#if (KMP_ARCH_X86)
Quad_a16_t __kmpc_atomic_float16_sub_a16_cpt_rev(ident_t *id_ref, int gtid,
Quad_a16_t *lhs,
Quad_a16_t rhs, int flag);
Quad_a16_t __kmpc_atomic_float16_div_a16_cpt_rev(ident_t *id_ref, int gtid,
Quad_a16_t *lhs,
Quad_a16_t rhs, int flag);
kmp_cmplx128_a16_t
__kmpc_atomic_cmplx16_sub_a16_cpt_rev(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs, int flag);
kmp_cmplx128_a16_t
__kmpc_atomic_cmplx16_div_a16_cpt_rev(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs, int flag);
#endif
#endif
// OpenMP 4.0 Capture-write (swap): {v = x; x = expr;}
char __kmpc_atomic_fixed1_swp(ident_t *id_ref, int gtid, char *lhs, char rhs);
short __kmpc_atomic_fixed2_swp(ident_t *id_ref, int gtid, short *lhs,
short rhs);
kmp_int32 __kmpc_atomic_fixed4_swp(ident_t *id_ref, int gtid, kmp_int32 *lhs,
kmp_int32 rhs);
kmp_int64 __kmpc_atomic_fixed8_swp(ident_t *id_ref, int gtid, kmp_int64 *lhs,
kmp_int64 rhs);
float __kmpc_atomic_float4_swp(ident_t *id_ref, int gtid, float *lhs,
float rhs);
double __kmpc_atomic_float8_swp(ident_t *id_ref, int gtid, double *lhs,
double rhs);
long double __kmpc_atomic_float10_swp(ident_t *id_ref, int gtid,
long double *lhs, long double rhs);
#if KMP_HAVE_QUAD
QUAD_LEGACY __kmpc_atomic_float16_swp(ident_t *id_ref, int gtid,
QUAD_LEGACY *lhs, QUAD_LEGACY rhs);
#endif
// !!! TODO: check if we need a workaround here
void __kmpc_atomic_cmplx4_swp(ident_t *id_ref, int gtid, kmp_cmplx32 *lhs,
kmp_cmplx32 rhs, kmp_cmplx32 *out);
// kmp_cmplx32 __kmpc_atomic_cmplx4_swp( ident_t *id_ref, int gtid,
// kmp_cmplx32 * lhs, kmp_cmplx32 rhs );
kmp_cmplx64 __kmpc_atomic_cmplx8_swp(ident_t *id_ref, int gtid,
kmp_cmplx64 *lhs, kmp_cmplx64 rhs);
kmp_cmplx80 __kmpc_atomic_cmplx10_swp(ident_t *id_ref, int gtid,
kmp_cmplx80 *lhs, kmp_cmplx80 rhs);
#if KMP_HAVE_QUAD
CPLX128_LEG __kmpc_atomic_cmplx16_swp(ident_t *id_ref, int gtid,
CPLX128_LEG *lhs, CPLX128_LEG rhs);
#if (KMP_ARCH_X86)
Quad_a16_t __kmpc_atomic_float16_a16_swp(ident_t *id_ref, int gtid,
Quad_a16_t *lhs, Quad_a16_t rhs);
kmp_cmplx128_a16_t __kmpc_atomic_cmplx16_a16_swp(ident_t *id_ref, int gtid,
kmp_cmplx128_a16_t *lhs,
kmp_cmplx128_a16_t rhs);
#endif
#endif
// Capture routines for mixed types (RHS=float16)
#if KMP_HAVE_QUAD
char __kmpc_atomic_fixed1_add_cpt_fp(ident_t *id_ref, int gtid, char *lhs,
_Quad rhs, int flag);
char __kmpc_atomic_fixed1_sub_cpt_fp(ident_t *id_ref, int gtid, char *lhs,
_Quad rhs, int flag);
char __kmpc_atomic_fixed1_mul_cpt_fp(ident_t *id_ref, int gtid, char *lhs,
_Quad rhs, int flag);
char __kmpc_atomic_fixed1_div_cpt_fp(ident_t *id_ref, int gtid, char *lhs,
_Quad rhs, int flag);
unsigned char __kmpc_atomic_fixed1u_add_cpt_fp(ident_t *id_ref, int gtid,
unsigned char *lhs, _Quad rhs,
int flag);
unsigned char __kmpc_atomic_fixed1u_sub_cpt_fp(ident_t *id_ref, int gtid,
unsigned char *lhs, _Quad rhs,
int flag);
unsigned char __kmpc_atomic_fixed1u_mul_cpt_fp(ident_t *id_ref, int gtid,
unsigned char *lhs, _Quad rhs,
int flag);
unsigned char __kmpc_atomic_fixed1u_div_cpt_fp(ident_t *id_ref, int gtid,
unsigned char *lhs, _Quad rhs,
int flag);
short __kmpc_atomic_fixed2_add_cpt_fp(ident_t *id_ref, int gtid, short *lhs,
_Quad rhs, int flag);
short __kmpc_atomic_fixed2_sub_cpt_fp(ident_t *id_ref, int gtid, short *lhs,
_Quad rhs, int flag);
short __kmpc_atomic_fixed2_mul_cpt_fp(ident_t *id_ref, int gtid, short *lhs,
_Quad rhs, int flag);
short __kmpc_atomic_fixed2_div_cpt_fp(ident_t *id_ref, int gtid, short *lhs,
_Quad rhs, int flag);
unsigned short __kmpc_atomic_fixed2u_add_cpt_fp(ident_t *id_ref, int gtid,
unsigned short *lhs, _Quad rhs,
int flag);
unsigned short __kmpc_atomic_fixed2u_sub_cpt_fp(ident_t *id_ref, int gtid,
unsigned short *lhs, _Quad rhs,
int flag);
unsigned short __kmpc_atomic_fixed2u_mul_cpt_fp(ident_t *id_ref, int gtid,
unsigned short *lhs, _Quad rhs,
int flag);
unsigned short __kmpc_atomic_fixed2u_div_cpt_fp(ident_t *id_ref, int gtid,
unsigned short *lhs, _Quad rhs,
int flag);
kmp_int32 __kmpc_atomic_fixed4_add_cpt_fp(ident_t *id_ref, int gtid,
kmp_int32 *lhs, _Quad rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_sub_cpt_fp(ident_t *id_ref, int gtid,
kmp_int32 *lhs, _Quad rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_mul_cpt_fp(ident_t *id_ref, int gtid,
kmp_int32 *lhs, _Quad rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_div_cpt_fp(ident_t *id_ref, int gtid,
kmp_int32 *lhs, _Quad rhs, int flag);
kmp_uint32 __kmpc_atomic_fixed4u_add_cpt_fp(ident_t *id_ref, int gtid,
kmp_uint32 *lhs, _Quad rhs,
int flag);
kmp_uint32 __kmpc_atomic_fixed4u_sub_cpt_fp(ident_t *id_ref, int gtid,
kmp_uint32 *lhs, _Quad rhs,
int flag);
kmp_uint32 __kmpc_atomic_fixed4u_mul_cpt_fp(ident_t *id_ref, int gtid,
kmp_uint32 *lhs, _Quad rhs,
int flag);
kmp_uint32 __kmpc_atomic_fixed4u_div_cpt_fp(ident_t *id_ref, int gtid,
kmp_uint32 *lhs, _Quad rhs,
int flag);
kmp_int64 __kmpc_atomic_fixed8_add_cpt_fp(ident_t *id_ref, int gtid,
kmp_int64 *lhs, _Quad rhs, int flag);
kmp_int64 __kmpc_atomic_fixed8_sub_cpt_fp(ident_t *id_ref, int gtid,
kmp_int64 *lhs, _Quad rhs, int flag);
kmp_int64 __kmpc_atomic_fixed8_mul_cpt_fp(ident_t *id_ref, int gtid,
kmp_int64 *lhs, _Quad rhs, int flag);
kmp_int64 __kmpc_atomic_fixed8_div_cpt_fp(ident_t *id_ref, int gtid,
kmp_int64 *lhs, _Quad rhs, int flag);
kmp_uint64 __kmpc_atomic_fixed8u_add_cpt_fp(ident_t *id_ref, int gtid,
kmp_uint64 *lhs, _Quad rhs,
int flag);
kmp_uint64 __kmpc_atomic_fixed8u_sub_cpt_fp(ident_t *id_ref, int gtid,
kmp_uint64 *lhs, _Quad rhs,
int flag);
kmp_uint64 __kmpc_atomic_fixed8u_mul_cpt_fp(ident_t *id_ref, int gtid,
kmp_uint64 *lhs, _Quad rhs,
int flag);
kmp_uint64 __kmpc_atomic_fixed8u_div_cpt_fp(ident_t *id_ref, int gtid,
kmp_uint64 *lhs, _Quad rhs,
int flag);
float __kmpc_atomic_float4_add_cpt_fp(ident_t *id_ref, int gtid,
kmp_real32 *lhs, _Quad rhs, int flag);
float __kmpc_atomic_float4_sub_cpt_fp(ident_t *id_ref, int gtid,
kmp_real32 *lhs, _Quad rhs, int flag);
float __kmpc_atomic_float4_mul_cpt_fp(ident_t *id_ref, int gtid,
kmp_real32 *lhs, _Quad rhs, int flag);
float __kmpc_atomic_float4_div_cpt_fp(ident_t *id_ref, int gtid,
kmp_real32 *lhs, _Quad rhs, int flag);
double __kmpc_atomic_float8_add_cpt_fp(ident_t *id_ref, int gtid,
kmp_real64 *lhs, _Quad rhs, int flag);
double __kmpc_atomic_float8_sub_cpt_fp(ident_t *id_ref, int gtid,
kmp_real64 *lhs, _Quad rhs, int flag);
double __kmpc_atomic_float8_mul_cpt_fp(ident_t *id_ref, int gtid,
kmp_real64 *lhs, _Quad rhs, int flag);
double __kmpc_atomic_float8_div_cpt_fp(ident_t *id_ref, int gtid,
kmp_real64 *lhs, _Quad rhs, int flag);
long double __kmpc_atomic_float10_add_cpt_fp(ident_t *id_ref, int gtid,
long double *lhs, _Quad rhs,
int flag);
long double __kmpc_atomic_float10_sub_cpt_fp(ident_t *id_ref, int gtid,
long double *lhs, _Quad rhs,
int flag);
long double __kmpc_atomic_float10_mul_cpt_fp(ident_t *id_ref, int gtid,
long double *lhs, _Quad rhs,
int flag);
long double __kmpc_atomic_float10_div_cpt_fp(ident_t *id_ref, int gtid,
long double *lhs, _Quad rhs,
int flag);
char __kmpc_atomic_fixed1_sub_cpt_rev_fp(ident_t *id_ref, int gtid, char *lhs,
_Quad rhs, int flag);
unsigned char __kmpc_atomic_fixed1u_sub_cpt_rev_fp(ident_t *id_ref, int gtid,
unsigned char *lhs,
_Quad rhs, int flag);
char __kmpc_atomic_fixed1_div_cpt_rev_fp(ident_t *id_ref, int gtid, char *lhs,
_Quad rhs, int flag);
unsigned char __kmpc_atomic_fixed1u_div_cpt_rev_fp(ident_t *id_ref, int gtid,
unsigned char *lhs,
_Quad rhs, int flag);
short __kmpc_atomic_fixed2_sub_cpt_rev_fp(ident_t *id_ref, int gtid, short *lhs,
_Quad rhs, int flag);
unsigned short __kmpc_atomic_fixed2u_sub_cpt_rev_fp(ident_t *id_ref, int gtid,
unsigned short *lhs,
_Quad rhs, int flag);
short __kmpc_atomic_fixed2_div_cpt_rev_fp(ident_t *id_ref, int gtid, short *lhs,
_Quad rhs, int flag);
unsigned short __kmpc_atomic_fixed2u_div_cpt_rev_fp(ident_t *id_ref, int gtid,
unsigned short *lhs,
_Quad rhs, int flag);
kmp_int32 __kmpc_atomic_fixed4_sub_cpt_rev_fp(ident_t *id_ref, int gtid,
kmp_int32 *lhs, _Quad rhs,
int flag);
kmp_uint32 __kmpc_atomic_fixed4u_sub_cpt_rev_fp(ident_t *id_ref, int gtid,
kmp_uint32 *lhs, _Quad rhs,
int flag);
kmp_int32 __kmpc_atomic_fixed4_div_cpt_rev_fp(ident_t *id_ref, int gtid,
kmp_int32 *lhs, _Quad rhs,
int flag);
kmp_uint32 __kmpc_atomic_fixed4u_div_cpt_rev_fp(ident_t *id_ref, int gtid,
kmp_uint32 *lhs, _Quad rhs,
int flag);
kmp_int64 __kmpc_atomic_fixed8_sub_cpt_rev_fp(ident_t *id_ref, int gtid,
kmp_int64 *lhs, _Quad rhs,
int flag);
kmp_uint64 __kmpc_atomic_fixed8u_sub_cpt_rev_fp(ident_t *id_ref, int gtid,
kmp_uint64 *lhs, _Quad rhs,
int flag);
kmp_int64 __kmpc_atomic_fixed8_div_cpt_rev_fp(ident_t *id_ref, int gtid,
kmp_int64 *lhs, _Quad rhs,
int flag);
kmp_uint64 __kmpc_atomic_fixed8u_div_cpt_rev_fp(ident_t *id_ref, int gtid,
kmp_uint64 *lhs, _Quad rhs,
int flag);
float __kmpc_atomic_float4_sub_cpt_rev_fp(ident_t *id_ref, int gtid, float *lhs,
_Quad rhs, int flag);
float __kmpc_atomic_float4_div_cpt_rev_fp(ident_t *id_ref, int gtid, float *lhs,
_Quad rhs, int flag);
double __kmpc_atomic_float8_sub_cpt_rev_fp(ident_t *id_ref, int gtid,
double *lhs, _Quad rhs, int flag);
double __kmpc_atomic_float8_div_cpt_rev_fp(ident_t *id_ref, int gtid,
double *lhs, _Quad rhs, int flag);
long double __kmpc_atomic_float10_sub_cpt_rev_fp(ident_t *id_ref, int gtid,
long double *lhs, _Quad rhs,
int flag);
long double __kmpc_atomic_float10_div_cpt_rev_fp(ident_t *id_ref, int gtid,
long double *lhs, _Quad rhs,
int flag);
#endif // KMP_HAVE_QUAD
// End of OpenMP 4.0 capture
#endif // OMP_40_ENABLED
#endif // KMP_ARCH_X86 || KMP_ARCH_X86_64
/* ------------------------------------------------------------------------ */
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* KMP_ATOMIC_H */
// end of file
Index: stable/11/contrib/openmp/runtime/src/kmp_csupport.cpp
===================================================================
--- stable/11/contrib/openmp/runtime/src/kmp_csupport.cpp (revision 350258)
+++ stable/11/contrib/openmp/runtime/src/kmp_csupport.cpp (revision 350259)
@@ -1,4164 +1,4173 @@
/*
* kmp_csupport.cpp -- kfront linkage support for OpenMP.
*/
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#define __KMP_IMP
#include "omp.h" /* extern "C" declarations of user-visible routines */
#include "kmp.h"
#include "kmp_error.h"
#include "kmp_i18n.h"
#include "kmp_itt.h"
#include "kmp_lock.h"
#include "kmp_stats.h"
#if OMPT_SUPPORT
#include "ompt-specific.h"
#endif
#define MAX_MESSAGE 512
// flags will be used in future, e.g. to implement openmp_strict library
// restrictions
/*!
* @ingroup STARTUP_SHUTDOWN
* @param loc in source location information
* @param flags in for future use (currently ignored)
*
* Initialize the runtime library. This call is optional; if it is not made then
* it will be implicitly called by attempts to use other library functions.
*/
void __kmpc_begin(ident_t *loc, kmp_int32 flags) {
// By default __kmpc_begin() is no-op.
char *env;
if ((env = getenv("KMP_INITIAL_THREAD_BIND")) != NULL &&
__kmp_str_match_true(env)) {
__kmp_middle_initialize();
KC_TRACE(10, ("__kmpc_begin: middle initialization called\n"));
} else if (__kmp_ignore_mppbeg() == FALSE) {
// By default __kmp_ignore_mppbeg() returns TRUE.
__kmp_internal_begin();
KC_TRACE(10, ("__kmpc_begin: called\n"));
}
}
/*!
* @ingroup STARTUP_SHUTDOWN
* @param loc source location information
*
* Shutdown the runtime library. This is also optional, and even if called will
* not do anything unless the `KMP_IGNORE_MPPEND` environment variable is set to
* zero.
*/
void __kmpc_end(ident_t *loc) {
// By default, __kmp_ignore_mppend() returns TRUE which makes __kmpc_end()
// call no-op. However, this can be overridden with KMP_IGNORE_MPPEND
// environment variable. If KMP_IGNORE_MPPEND is 0, __kmp_ignore_mppend()
// returns FALSE and __kmpc_end() will unregister this root (it can cause
// library shut down).
if (__kmp_ignore_mppend() == FALSE) {
KC_TRACE(10, ("__kmpc_end: called\n"));
KA_TRACE(30, ("__kmpc_end\n"));
__kmp_internal_end_thread(-1);
}
#if KMP_OS_WINDOWS && OMPT_SUPPORT
// Normal exit process on Windows does not allow worker threads of the final
// parallel region to finish reporting their events, so shutting down the
// library here fixes the issue at least for the cases where __kmpc_end() is
// placed properly.
if (ompt_enabled.enabled)
__kmp_internal_end_library(__kmp_gtid_get_specific());
#endif
}
/*!
@ingroup THREAD_STATES
@param loc Source location information.
@return The global thread index of the active thread.
This function can be called in any context.
If the runtime has ony been entered at the outermost level from a
single (necessarily non-OpenMP<sup>*</sup>) thread, then the thread number is
that which would be returned by omp_get_thread_num() in the outermost
active parallel construct. (Or zero if there is no active parallel
construct, since the master thread is necessarily thread zero).
If multiple non-OpenMP threads all enter an OpenMP construct then this
will be a unique thread identifier among all the threads created by
the OpenMP runtime (but the value cannote be defined in terms of
OpenMP thread ids returned by omp_get_thread_num()).
*/
kmp_int32 __kmpc_global_thread_num(ident_t *loc) {
kmp_int32 gtid = __kmp_entry_gtid();
KC_TRACE(10, ("__kmpc_global_thread_num: T#%d\n", gtid));
return gtid;
}
/*!
@ingroup THREAD_STATES
@param loc Source location information.
@return The number of threads under control of the OpenMP<sup>*</sup> runtime
This function can be called in any context.
It returns the total number of threads under the control of the OpenMP runtime.
That is not a number that can be determined by any OpenMP standard calls, since
the library may be called from more than one non-OpenMP thread, and this
reflects the total over all such calls. Similarly the runtime maintains
underlying threads even when they are not active (since the cost of creating
and destroying OS threads is high), this call counts all such threads even if
they are not waiting for work.
*/
kmp_int32 __kmpc_global_num_threads(ident_t *loc) {
KC_TRACE(10,
("__kmpc_global_num_threads: num_threads = %d\n", __kmp_all_nth));
return TCR_4(__kmp_all_nth);
}
/*!
@ingroup THREAD_STATES
@param loc Source location information.
@return The thread number of the calling thread in the innermost active parallel
construct.
*/
kmp_int32 __kmpc_bound_thread_num(ident_t *loc) {
KC_TRACE(10, ("__kmpc_bound_thread_num: called\n"));
return __kmp_tid_from_gtid(__kmp_entry_gtid());
}
/*!
@ingroup THREAD_STATES
@param loc Source location information.
@return The number of threads in the innermost active parallel construct.
*/
kmp_int32 __kmpc_bound_num_threads(ident_t *loc) {
KC_TRACE(10, ("__kmpc_bound_num_threads: called\n"));
return __kmp_entry_thread()->th.th_team->t.t_nproc;
}
/*!
* @ingroup DEPRECATED
* @param loc location description
*
* This function need not be called. It always returns TRUE.
*/
kmp_int32 __kmpc_ok_to_fork(ident_t *loc) {
#ifndef KMP_DEBUG
return TRUE;
#else
const char *semi2;
const char *semi3;
int line_no;
if (__kmp_par_range == 0) {
return TRUE;
}
semi2 = loc->psource;
if (semi2 == NULL) {
return TRUE;
}
semi2 = strchr(semi2, ';');
if (semi2 == NULL) {
return TRUE;
}
semi2 = strchr(semi2 + 1, ';');
if (semi2 == NULL) {
return TRUE;
}
if (__kmp_par_range_filename[0]) {
const char *name = semi2 - 1;
while ((name > loc->psource) && (*name != '/') && (*name != ';')) {
name--;
}
if ((*name == '/') || (*name == ';')) {
name++;
}
if (strncmp(__kmp_par_range_filename, name, semi2 - name)) {
return __kmp_par_range < 0;
}
}
semi3 = strchr(semi2 + 1, ';');
if (__kmp_par_range_routine[0]) {
if ((semi3 != NULL) && (semi3 > semi2) &&
(strncmp(__kmp_par_range_routine, semi2 + 1, semi3 - semi2 - 1))) {
return __kmp_par_range < 0;
}
}
if (KMP_SSCANF(semi3 + 1, "%d", &line_no) == 1) {
if ((line_no >= __kmp_par_range_lb) && (line_no <= __kmp_par_range_ub)) {
return __kmp_par_range > 0;
}
return __kmp_par_range < 0;
}
return TRUE;
#endif /* KMP_DEBUG */
}
/*!
@ingroup THREAD_STATES
@param loc Source location information.
@return 1 if this thread is executing inside an active parallel region, zero if
not.
*/
kmp_int32 __kmpc_in_parallel(ident_t *loc) {
return __kmp_entry_thread()->th.th_root->r.r_active;
}
/*!
@ingroup PARALLEL
@param loc source location information
@param global_tid global thread number
@param num_threads number of threads requested for this parallel construct
Set the number of threads to be used by the next fork spawned by this thread.
This call is only required if the parallel construct has a `num_threads` clause.
*/
void __kmpc_push_num_threads(ident_t *loc, kmp_int32 global_tid,
kmp_int32 num_threads) {
KA_TRACE(20, ("__kmpc_push_num_threads: enter T#%d num_threads=%d\n",
global_tid, num_threads));
__kmp_push_num_threads(loc, global_tid, num_threads);
}
void __kmpc_pop_num_threads(ident_t *loc, kmp_int32 global_tid) {
KA_TRACE(20, ("__kmpc_pop_num_threads: enter\n"));
/* the num_threads are automatically popped */
}
#if OMP_40_ENABLED
void __kmpc_push_proc_bind(ident_t *loc, kmp_int32 global_tid,
kmp_int32 proc_bind) {
KA_TRACE(20, ("__kmpc_push_proc_bind: enter T#%d proc_bind=%d\n", global_tid,
proc_bind));
__kmp_push_proc_bind(loc, global_tid, (kmp_proc_bind_t)proc_bind);
}
#endif /* OMP_40_ENABLED */
/*!
@ingroup PARALLEL
@param loc source location information
@param argc total number of arguments in the ellipsis
@param microtask pointer to callback routine consisting of outlined parallel
construct
@param ... pointers to shared variables that aren't global
Do the actual fork and call the microtask in the relevant number of threads.
*/
void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro microtask, ...) {
int gtid = __kmp_entry_gtid();
#if (KMP_STATS_ENABLED)
// If we were in a serial region, then stop the serial timer, record
// the event, and start parallel region timer
stats_state_e previous_state = KMP_GET_THREAD_STATE();
if (previous_state == stats_state_e::SERIAL_REGION) {
KMP_EXCHANGE_PARTITIONED_TIMER(OMP_parallel_overhead);
} else {
KMP_PUSH_PARTITIONED_TIMER(OMP_parallel_overhead);
}
int inParallel = __kmpc_in_parallel(loc);
if (inParallel) {
KMP_COUNT_BLOCK(OMP_NESTED_PARALLEL);
} else {
KMP_COUNT_BLOCK(OMP_PARALLEL);
}
#endif
// maybe to save thr_state is enough here
{
va_list ap;
va_start(ap, microtask);
#if OMPT_SUPPORT
ompt_frame_t *ompt_frame;
if (ompt_enabled.enabled) {
kmp_info_t *master_th = __kmp_threads[gtid];
kmp_team_t *parent_team = master_th->th.th_team;
ompt_lw_taskteam_t *lwt = parent_team->t.ompt_serialized_team_info;
if (lwt)
ompt_frame = &(lwt->ompt_task_info.frame);
else {
int tid = __kmp_tid_from_gtid(gtid);
ompt_frame = &(
parent_team->t.t_implicit_task_taskdata[tid].ompt_task_info.frame);
}
ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
OMPT_STORE_RETURN_ADDRESS(gtid);
}
#endif
#if INCLUDE_SSC_MARKS
SSC_MARK_FORKING();
#endif
__kmp_fork_call(loc, gtid, fork_context_intel, argc,
VOLATILE_CAST(microtask_t) microtask, // "wrapped" task
VOLATILE_CAST(launch_t) __kmp_invoke_task_func,
/* TODO: revert workaround for Intel(R) 64 tracker #96 */
#if (KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64) && KMP_OS_LINUX
&ap
#else
ap
#endif
);
#if INCLUDE_SSC_MARKS
SSC_MARK_JOINING();
#endif
__kmp_join_call(loc, gtid
#if OMPT_SUPPORT
,
fork_context_intel
#endif
);
va_end(ap);
}
#if KMP_STATS_ENABLED
if (previous_state == stats_state_e::SERIAL_REGION) {
KMP_EXCHANGE_PARTITIONED_TIMER(OMP_serial);
} else {
KMP_POP_PARTITIONED_TIMER();
}
#endif // KMP_STATS_ENABLED
}
#if OMP_40_ENABLED
/*!
@ingroup PARALLEL
@param loc source location information
@param global_tid global thread number
@param num_teams number of teams requested for the teams construct
@param num_threads number of threads per team requested for the teams construct
Set the number of teams to be used by the teams construct.
This call is only required if the teams construct has a `num_teams` clause
or a `thread_limit` clause (or both).
*/
void __kmpc_push_num_teams(ident_t *loc, kmp_int32 global_tid,
kmp_int32 num_teams, kmp_int32 num_threads) {
KA_TRACE(20,
("__kmpc_push_num_teams: enter T#%d num_teams=%d num_threads=%d\n",
global_tid, num_teams, num_threads));
__kmp_push_num_teams(loc, global_tid, num_teams, num_threads);
}
/*!
@ingroup PARALLEL
@param loc source location information
@param argc total number of arguments in the ellipsis
@param microtask pointer to callback routine consisting of outlined teams
construct
@param ... pointers to shared variables that aren't global
Do the actual fork and call the microtask in the relevant number of threads.
*/
void __kmpc_fork_teams(ident_t *loc, kmp_int32 argc, kmpc_micro microtask,
...) {
int gtid = __kmp_entry_gtid();
kmp_info_t *this_thr = __kmp_threads[gtid];
va_list ap;
va_start(ap, microtask);
KMP_COUNT_BLOCK(OMP_TEAMS);
// remember teams entry point and nesting level
this_thr->th.th_teams_microtask = microtask;
this_thr->th.th_teams_level =
this_thr->th.th_team->t.t_level; // AC: can be >0 on host
#if OMPT_SUPPORT
kmp_team_t *parent_team = this_thr->th.th_team;
int tid = __kmp_tid_from_gtid(gtid);
if (ompt_enabled.enabled) {
parent_team->t.t_implicit_task_taskdata[tid]
.ompt_task_info.frame.enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
}
OMPT_STORE_RETURN_ADDRESS(gtid);
#endif
// check if __kmpc_push_num_teams called, set default number of teams
// otherwise
if (this_thr->th.th_teams_size.nteams == 0) {
__kmp_push_num_teams(loc, gtid, 0, 0);
}
KMP_DEBUG_ASSERT(this_thr->th.th_set_nproc >= 1);
KMP_DEBUG_ASSERT(this_thr->th.th_teams_size.nteams >= 1);
KMP_DEBUG_ASSERT(this_thr->th.th_teams_size.nth >= 1);
__kmp_fork_call(loc, gtid, fork_context_intel, argc,
VOLATILE_CAST(microtask_t)
__kmp_teams_master, // "wrapped" task
VOLATILE_CAST(launch_t) __kmp_invoke_teams_master,
#if (KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64) && KMP_OS_LINUX
&ap
#else
ap
#endif
);
__kmp_join_call(loc, gtid
#if OMPT_SUPPORT
,
fork_context_intel
#endif
);
this_thr->th.th_teams_microtask = NULL;
this_thr->th.th_teams_level = 0;
*(kmp_int64 *)(&this_thr->th.th_teams_size) = 0L;
va_end(ap);
}
#endif /* OMP_40_ENABLED */
// I don't think this function should ever have been exported.
// The __kmpc_ prefix was misapplied. I'm fairly certain that no generated
// openmp code ever called it, but it's been exported from the RTL for so
// long that I'm afraid to remove the definition.
int __kmpc_invoke_task_func(int gtid) { return __kmp_invoke_task_func(gtid); }
/*!
@ingroup PARALLEL
@param loc source location information
@param global_tid global thread number
Enter a serialized parallel construct. This interface is used to handle a
conditional parallel region, like this,
@code
#pragma omp parallel if (condition)
@endcode
when the condition is false.
*/
void __kmpc_serialized_parallel(ident_t *loc, kmp_int32 global_tid) {
// The implementation is now in kmp_runtime.cpp so that it can share static
// functions with kmp_fork_call since the tasks to be done are similar in
// each case.
#if OMPT_SUPPORT
OMPT_STORE_RETURN_ADDRESS(global_tid);
#endif
__kmp_serialized_parallel(loc, global_tid);
}
/*!
@ingroup PARALLEL
@param loc source location information
@param global_tid global thread number
Leave a serialized parallel construct.
*/
void __kmpc_end_serialized_parallel(ident_t *loc, kmp_int32 global_tid) {
kmp_internal_control_t *top;
kmp_info_t *this_thr;
kmp_team_t *serial_team;
KC_TRACE(10,
("__kmpc_end_serialized_parallel: called by T#%d\n", global_tid));
/* skip all this code for autopar serialized loops since it results in
unacceptable overhead */
if (loc != NULL && (loc->flags & KMP_IDENT_AUTOPAR))
return;
// Not autopar code
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
this_thr = __kmp_threads[global_tid];
serial_team = this_thr->th.th_serial_team;
#if OMP_45_ENABLED
kmp_task_team_t *task_team = this_thr->th.th_task_team;
// we need to wait for the proxy tasks before finishing the thread
if (task_team != NULL && task_team->tt.tt_found_proxy_tasks)
__kmp_task_team_wait(this_thr, serial_team USE_ITT_BUILD_ARG(NULL));
#endif
KMP_MB();
KMP_DEBUG_ASSERT(serial_team);
KMP_ASSERT(serial_team->t.t_serialized);
KMP_DEBUG_ASSERT(this_thr->th.th_team == serial_team);
KMP_DEBUG_ASSERT(serial_team != this_thr->th.th_root->r.r_root_team);
KMP_DEBUG_ASSERT(serial_team->t.t_threads);
KMP_DEBUG_ASSERT(serial_team->t.t_threads[0] == this_thr);
#if OMPT_SUPPORT
if (ompt_enabled.enabled &&
this_thr->th.ompt_thread_info.state != ompt_state_overhead) {
OMPT_CUR_TASK_INFO(this_thr)->frame.exit_frame = ompt_data_none;
if (ompt_enabled.ompt_callback_implicit_task) {
ompt_callbacks.ompt_callback(ompt_callback_implicit_task)(
ompt_scope_end, NULL, OMPT_CUR_TASK_DATA(this_thr), 1,
OMPT_CUR_TASK_INFO(this_thr)->thread_num, ompt_task_implicit);
}
// reset clear the task id only after unlinking the task
ompt_data_t *parent_task_data;
__ompt_get_task_info_internal(1, NULL, &parent_task_data, NULL, NULL, NULL);
if (ompt_enabled.ompt_callback_parallel_end) {
ompt_callbacks.ompt_callback(ompt_callback_parallel_end)(
&(serial_team->t.ompt_team_info.parallel_data), parent_task_data,
ompt_parallel_invoker_program, OMPT_LOAD_RETURN_ADDRESS(global_tid));
}
__ompt_lw_taskteam_unlink(this_thr);
this_thr->th.ompt_thread_info.state = ompt_state_overhead;
}
#endif
/* If necessary, pop the internal control stack values and replace the team
* values */
top = serial_team->t.t_control_stack_top;
if (top && top->serial_nesting_level == serial_team->t.t_serialized) {
copy_icvs(&serial_team->t.t_threads[0]->th.th_current_task->td_icvs, top);
serial_team->t.t_control_stack_top = top->next;
__kmp_free(top);
}
// if( serial_team -> t.t_serialized > 1 )
serial_team->t.t_level--;
/* pop dispatch buffers stack */
KMP_DEBUG_ASSERT(serial_team->t.t_dispatch->th_disp_buffer);
{
dispatch_private_info_t *disp_buffer =
serial_team->t.t_dispatch->th_disp_buffer;
serial_team->t.t_dispatch->th_disp_buffer =
serial_team->t.t_dispatch->th_disp_buffer->next;
__kmp_free(disp_buffer);
}
#if OMP_50_ENABLED
this_thr->th.th_def_allocator = serial_team->t.t_def_allocator; // restore
#endif
--serial_team->t.t_serialized;
if (serial_team->t.t_serialized == 0) {
/* return to the parallel section */
#if KMP_ARCH_X86 || KMP_ARCH_X86_64
if (__kmp_inherit_fp_control && serial_team->t.t_fp_control_saved) {
__kmp_clear_x87_fpu_status_word();
__kmp_load_x87_fpu_control_word(&serial_team->t.t_x87_fpu_control_word);
__kmp_load_mxcsr(&serial_team->t.t_mxcsr);
}
#endif /* KMP_ARCH_X86 || KMP_ARCH_X86_64 */
this_thr->th.th_team = serial_team->t.t_parent;
this_thr->th.th_info.ds.ds_tid = serial_team->t.t_master_tid;
/* restore values cached in the thread */
this_thr->th.th_team_nproc = serial_team->t.t_parent->t.t_nproc; /* JPH */
this_thr->th.th_team_master =
serial_team->t.t_parent->t.t_threads[0]; /* JPH */
this_thr->th.th_team_serialized = this_thr->th.th_team->t.t_serialized;
/* TODO the below shouldn't need to be adjusted for serialized teams */
this_thr->th.th_dispatch =
&this_thr->th.th_team->t.t_dispatch[serial_team->t.t_master_tid];
__kmp_pop_current_task_from_thread(this_thr);
KMP_ASSERT(this_thr->th.th_current_task->td_flags.executing == 0);
this_thr->th.th_current_task->td_flags.executing = 1;
if (__kmp_tasking_mode != tskm_immediate_exec) {
// Copy the task team from the new child / old parent team to the thread.
this_thr->th.th_task_team =
this_thr->th.th_team->t.t_task_team[this_thr->th.th_task_state];
KA_TRACE(20,
("__kmpc_end_serialized_parallel: T#%d restoring task_team %p / "
"team %p\n",
global_tid, this_thr->th.th_task_team, this_thr->th.th_team));
}
} else {
if (__kmp_tasking_mode != tskm_immediate_exec) {
KA_TRACE(20, ("__kmpc_end_serialized_parallel: T#%d decreasing nesting "
"depth of serial team %p to %d\n",
global_tid, serial_team, serial_team->t.t_serialized));
}
}
if (__kmp_env_consistency_check)
__kmp_pop_parallel(global_tid, NULL);
#if OMPT_SUPPORT
if (ompt_enabled.enabled)
this_thr->th.ompt_thread_info.state =
((this_thr->th.th_team_serialized) ? ompt_state_work_serial
: ompt_state_work_parallel);
#endif
}
/*!
@ingroup SYNCHRONIZATION
@param loc source location information.
Execute <tt>flush</tt>. This is implemented as a full memory fence. (Though
depending on the memory ordering convention obeyed by the compiler
even that may not be necessary).
*/
void __kmpc_flush(ident_t *loc) {
KC_TRACE(10, ("__kmpc_flush: called\n"));
/* need explicit __mf() here since use volatile instead in library */
KMP_MB(); /* Flush all pending memory write invalidates. */
#if (KMP_ARCH_X86 || KMP_ARCH_X86_64)
#if KMP_MIC
// fence-style instructions do not exist, but lock; xaddl $0,(%rsp) can be used.
// We shouldn't need it, though, since the ABI rules require that
// * If the compiler generates NGO stores it also generates the fence
// * If users hand-code NGO stores they should insert the fence
// therefore no incomplete unordered stores should be visible.
#else
// C74404
// This is to address non-temporal store instructions (sfence needed).
// The clflush instruction is addressed either (mfence needed).
// Probably the non-temporal load monvtdqa instruction should also be
// addressed.
// mfence is a SSE2 instruction. Do not execute it if CPU is not SSE2.
if (!__kmp_cpuinfo.initialized) {
__kmp_query_cpuid(&__kmp_cpuinfo);
}
if (!__kmp_cpuinfo.sse2) {
// CPU cannot execute SSE2 instructions.
} else {
#if KMP_COMPILER_ICC
_mm_mfence();
#elif KMP_COMPILER_MSVC
MemoryBarrier();
#else
__sync_synchronize();
#endif // KMP_COMPILER_ICC
}
#endif // KMP_MIC
#elif (KMP_ARCH_ARM || KMP_ARCH_AARCH64 || KMP_ARCH_MIPS || KMP_ARCH_MIPS64)
// Nothing to see here move along
#elif KMP_ARCH_PPC64
// Nothing needed here (we have a real MB above).
#if KMP_OS_CNK
// The flushing thread needs to yield here; this prevents a
// busy-waiting thread from saturating the pipeline. flush is
// often used in loops like this:
// while (!flag) {
// #pragma omp flush(flag)
// }
// and adding the yield here is good for at least a 10x speedup
// when running >2 threads per core (on the NAS LU benchmark).
__kmp_yield(TRUE);
#endif
#else
#error Unknown or unsupported architecture
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.ompt_callback_flush) {
ompt_callbacks.ompt_callback(ompt_callback_flush)(
__ompt_get_thread_data_internal(), OMPT_GET_RETURN_ADDRESS(0));
}
#endif
}
/* -------------------------------------------------------------------------- */
/*!
@ingroup SYNCHRONIZATION
@param loc source location information
@param global_tid thread id.
Execute a barrier.
*/
void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid) {
KMP_COUNT_BLOCK(OMP_BARRIER);
KC_TRACE(10, ("__kmpc_barrier: called T#%d\n", global_tid));
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
if (__kmp_env_consistency_check) {
if (loc == 0) {
KMP_WARNING(ConstructIdentInvalid); // ??? What does it mean for the user?
}
__kmp_check_barrier(global_tid, ct_barrier, loc);
}
#if OMPT_SUPPORT
ompt_frame_t *ompt_frame;
if (ompt_enabled.enabled) {
__ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
if (ompt_frame->enter_frame.ptr == NULL)
ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
OMPT_STORE_RETURN_ADDRESS(global_tid);
}
#endif
__kmp_threads[global_tid]->th.th_ident = loc;
// TODO: explicit barrier_wait_id:
// this function is called when 'barrier' directive is present or
// implicit barrier at the end of a worksharing construct.
// 1) better to add a per-thread barrier counter to a thread data structure
// 2) set to 0 when a new team is created
// 4) no sync is required
__kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
ompt_frame->enter_frame = ompt_data_none;
}
#endif
}
/* The BARRIER for a MASTER section is always explicit */
/*!
@ingroup WORK_SHARING
@param loc source location information.
@param global_tid global thread number .
@return 1 if this thread should execute the <tt>master</tt> block, 0 otherwise.
*/
kmp_int32 __kmpc_master(ident_t *loc, kmp_int32 global_tid) {
int status = 0;
KC_TRACE(10, ("__kmpc_master: called T#%d\n", global_tid));
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
if (KMP_MASTER_GTID(global_tid)) {
KMP_COUNT_BLOCK(OMP_MASTER);
KMP_PUSH_PARTITIONED_TIMER(OMP_master);
status = 1;
}
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (status) {
if (ompt_enabled.ompt_callback_master) {
kmp_info_t *this_thr = __kmp_threads[global_tid];
kmp_team_t *team = this_thr->th.th_team;
int tid = __kmp_tid_from_gtid(global_tid);
ompt_callbacks.ompt_callback(ompt_callback_master)(
ompt_scope_begin, &(team->t.ompt_team_info.parallel_data),
&(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
OMPT_GET_RETURN_ADDRESS(0));
}
}
#endif
if (__kmp_env_consistency_check) {
#if KMP_USE_DYNAMIC_LOCK
if (status)
__kmp_push_sync(global_tid, ct_master, loc, NULL, 0);
else
__kmp_check_sync(global_tid, ct_master, loc, NULL, 0);
#else
if (status)
__kmp_push_sync(global_tid, ct_master, loc, NULL);
else
__kmp_check_sync(global_tid, ct_master, loc, NULL);
#endif
}
return status;
}
/*!
@ingroup WORK_SHARING
@param loc source location information.
@param global_tid global thread number .
Mark the end of a <tt>master</tt> region. This should only be called by the
thread that executes the <tt>master</tt> region.
*/
void __kmpc_end_master(ident_t *loc, kmp_int32 global_tid) {
KC_TRACE(10, ("__kmpc_end_master: called T#%d\n", global_tid));
KMP_DEBUG_ASSERT(KMP_MASTER_GTID(global_tid));
KMP_POP_PARTITIONED_TIMER();
#if OMPT_SUPPORT && OMPT_OPTIONAL
kmp_info_t *this_thr = __kmp_threads[global_tid];
kmp_team_t *team = this_thr->th.th_team;
if (ompt_enabled.ompt_callback_master) {
int tid = __kmp_tid_from_gtid(global_tid);
ompt_callbacks.ompt_callback(ompt_callback_master)(
ompt_scope_end, &(team->t.ompt_team_info.parallel_data),
&(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
OMPT_GET_RETURN_ADDRESS(0));
}
#endif
if (__kmp_env_consistency_check) {
if (global_tid < 0)
KMP_WARNING(ThreadIdentInvalid);
if (KMP_MASTER_GTID(global_tid))
__kmp_pop_sync(global_tid, ct_master, loc);
}
}
/*!
@ingroup WORK_SHARING
@param loc source location information.
@param gtid global thread number.
Start execution of an <tt>ordered</tt> construct.
*/
void __kmpc_ordered(ident_t *loc, kmp_int32 gtid) {
int cid = 0;
kmp_info_t *th;
KMP_DEBUG_ASSERT(__kmp_init_serial);
KC_TRACE(10, ("__kmpc_ordered: called T#%d\n", gtid));
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
#if USE_ITT_BUILD
__kmp_itt_ordered_prep(gtid);
// TODO: ordered_wait_id
#endif /* USE_ITT_BUILD */
th = __kmp_threads[gtid];
#if OMPT_SUPPORT && OMPT_OPTIONAL
kmp_team_t *team;
ompt_wait_id_t lck;
void *codeptr_ra;
if (ompt_enabled.enabled) {
OMPT_STORE_RETURN_ADDRESS(gtid);
team = __kmp_team_from_gtid(gtid);
- lck = (ompt_wait_id_t)&team->t.t_ordered.dt.t_value;
+ lck = (ompt_wait_id_t)(uintptr_t)&team->t.t_ordered.dt.t_value;
/* OMPT state update */
th->th.ompt_thread_info.wait_id = lck;
th->th.ompt_thread_info.state = ompt_state_wait_ordered;
/* OMPT event callback */
codeptr_ra = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
- ompt_mutex_ordered, omp_lock_hint_none, kmp_mutex_impl_spin,
- (ompt_wait_id_t)lck, codeptr_ra);
+ ompt_mutex_ordered, omp_lock_hint_none, kmp_mutex_impl_spin, lck,
+ codeptr_ra);
}
}
#endif
if (th->th.th_dispatch->th_deo_fcn != 0)
(*th->th.th_dispatch->th_deo_fcn)(&gtid, &cid, loc);
else
__kmp_parallel_deo(&gtid, &cid, loc);
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
/* OMPT state update */
th->th.ompt_thread_info.state = ompt_state_work_parallel;
th->th.ompt_thread_info.wait_id = 0;
/* OMPT event callback */
if (ompt_enabled.ompt_callback_mutex_acquired) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
- ompt_mutex_ordered, (ompt_wait_id_t)lck, codeptr_ra);
+ ompt_mutex_ordered, (ompt_wait_id_t)(uintptr_t)lck, codeptr_ra);
}
}
#endif
#if USE_ITT_BUILD
__kmp_itt_ordered_start(gtid);
#endif /* USE_ITT_BUILD */
}
/*!
@ingroup WORK_SHARING
@param loc source location information.
@param gtid global thread number.
End execution of an <tt>ordered</tt> construct.
*/
void __kmpc_end_ordered(ident_t *loc, kmp_int32 gtid) {
int cid = 0;
kmp_info_t *th;
KC_TRACE(10, ("__kmpc_end_ordered: called T#%d\n", gtid));
#if USE_ITT_BUILD
__kmp_itt_ordered_end(gtid);
// TODO: ordered_wait_id
#endif /* USE_ITT_BUILD */
th = __kmp_threads[gtid];
if (th->th.th_dispatch->th_dxo_fcn != 0)
(*th->th.th_dispatch->th_dxo_fcn)(&gtid, &cid, loc);
else
__kmp_parallel_dxo(&gtid, &cid, loc);
#if OMPT_SUPPORT && OMPT_OPTIONAL
OMPT_STORE_RETURN_ADDRESS(gtid);
if (ompt_enabled.ompt_callback_mutex_released) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
ompt_mutex_ordered,
- (ompt_wait_id_t)&__kmp_team_from_gtid(gtid)->t.t_ordered.dt.t_value,
+ (ompt_wait_id_t)(uintptr_t)&__kmp_team_from_gtid(gtid)
+ ->t.t_ordered.dt.t_value,
OMPT_LOAD_RETURN_ADDRESS(gtid));
}
#endif
}
#if KMP_USE_DYNAMIC_LOCK
static __forceinline void
__kmp_init_indirect_csptr(kmp_critical_name *crit, ident_t const *loc,
kmp_int32 gtid, kmp_indirect_locktag_t tag) {
// Pointer to the allocated indirect lock is written to crit, while indexing
// is ignored.
void *idx;
kmp_indirect_lock_t **lck;
lck = (kmp_indirect_lock_t **)crit;
kmp_indirect_lock_t *ilk = __kmp_allocate_indirect_lock(&idx, gtid, tag);
KMP_I_LOCK_FUNC(ilk, init)(ilk->lock);
KMP_SET_I_LOCK_LOCATION(ilk, loc);
KMP_SET_I_LOCK_FLAGS(ilk, kmp_lf_critical_section);
KA_TRACE(20,
("__kmp_init_indirect_csptr: initialized indirect lock #%d\n", tag));
#if USE_ITT_BUILD
__kmp_itt_critical_creating(ilk->lock, loc);
#endif
int status = KMP_COMPARE_AND_STORE_PTR(lck, nullptr, ilk);
if (status == 0) {
#if USE_ITT_BUILD
__kmp_itt_critical_destroyed(ilk->lock);
#endif
// We don't really need to destroy the unclaimed lock here since it will be
// cleaned up at program exit.
// KMP_D_LOCK_FUNC(&idx, destroy)((kmp_dyna_lock_t *)&idx);
}
KMP_DEBUG_ASSERT(*lck != NULL);
}
// Fast-path acquire tas lock
#define KMP_ACQUIRE_TAS_LOCK(lock, gtid) \
{ \
kmp_tas_lock_t *l = (kmp_tas_lock_t *)lock; \
kmp_int32 tas_free = KMP_LOCK_FREE(tas); \
kmp_int32 tas_busy = KMP_LOCK_BUSY(gtid + 1, tas); \
if (KMP_ATOMIC_LD_RLX(&l->lk.poll) != tas_free || \
!__kmp_atomic_compare_store_acq(&l->lk.poll, tas_free, tas_busy)) { \
kmp_uint32 spins; \
KMP_FSYNC_PREPARE(l); \
KMP_INIT_YIELD(spins); \
if (TCR_4(__kmp_nth) > \
(__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc)) { \
KMP_YIELD(TRUE); \
} else { \
KMP_YIELD_SPIN(spins); \
} \
kmp_backoff_t backoff = __kmp_spin_backoff_params; \
while ( \
KMP_ATOMIC_LD_RLX(&l->lk.poll) != tas_free || \
!__kmp_atomic_compare_store_acq(&l->lk.poll, tas_free, tas_busy)) { \
__kmp_spin_backoff(&backoff); \
if (TCR_4(__kmp_nth) > \
(__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc)) { \
KMP_YIELD(TRUE); \
} else { \
KMP_YIELD_SPIN(spins); \
} \
} \
} \
KMP_FSYNC_ACQUIRED(l); \
}
// Fast-path test tas lock
#define KMP_TEST_TAS_LOCK(lock, gtid, rc) \
{ \
kmp_tas_lock_t *l = (kmp_tas_lock_t *)lock; \
kmp_int32 tas_free = KMP_LOCK_FREE(tas); \
kmp_int32 tas_busy = KMP_LOCK_BUSY(gtid + 1, tas); \
rc = KMP_ATOMIC_LD_RLX(&l->lk.poll) == tas_free && \
__kmp_atomic_compare_store_acq(&l->lk.poll, tas_free, tas_busy); \
}
// Fast-path release tas lock
#define KMP_RELEASE_TAS_LOCK(lock, gtid) \
{ KMP_ATOMIC_ST_REL(&((kmp_tas_lock_t *)lock)->lk.poll, KMP_LOCK_FREE(tas)); }
#if KMP_USE_FUTEX
#include <sys/syscall.h>
#include <unistd.h>
#ifndef FUTEX_WAIT
#define FUTEX_WAIT 0
#endif
#ifndef FUTEX_WAKE
#define FUTEX_WAKE 1
#endif
// Fast-path acquire futex lock
#define KMP_ACQUIRE_FUTEX_LOCK(lock, gtid) \
{ \
kmp_futex_lock_t *ftx = (kmp_futex_lock_t *)lock; \
kmp_int32 gtid_code = (gtid + 1) << 1; \
KMP_MB(); \
KMP_FSYNC_PREPARE(ftx); \
kmp_int32 poll_val; \
while ((poll_val = KMP_COMPARE_AND_STORE_RET32( \
&(ftx->lk.poll), KMP_LOCK_FREE(futex), \
KMP_LOCK_BUSY(gtid_code, futex))) != KMP_LOCK_FREE(futex)) { \
kmp_int32 cond = KMP_LOCK_STRIP(poll_val) & 1; \
if (!cond) { \
if (!KMP_COMPARE_AND_STORE_RET32(&(ftx->lk.poll), poll_val, \
poll_val | \
KMP_LOCK_BUSY(1, futex))) { \
continue; \
} \
poll_val |= KMP_LOCK_BUSY(1, futex); \
} \
kmp_int32 rc; \
if ((rc = syscall(__NR_futex, &(ftx->lk.poll), FUTEX_WAIT, poll_val, \
NULL, NULL, 0)) != 0) { \
continue; \
} \
gtid_code |= 1; \
} \
KMP_FSYNC_ACQUIRED(ftx); \
}
// Fast-path test futex lock
#define KMP_TEST_FUTEX_LOCK(lock, gtid, rc) \
{ \
kmp_futex_lock_t *ftx = (kmp_futex_lock_t *)lock; \
if (KMP_COMPARE_AND_STORE_ACQ32(&(ftx->lk.poll), KMP_LOCK_FREE(futex), \
KMP_LOCK_BUSY(gtid + 1 << 1, futex))) { \
KMP_FSYNC_ACQUIRED(ftx); \
rc = TRUE; \
} else { \
rc = FALSE; \
} \
}
// Fast-path release futex lock
#define KMP_RELEASE_FUTEX_LOCK(lock, gtid) \
{ \
kmp_futex_lock_t *ftx = (kmp_futex_lock_t *)lock; \
KMP_MB(); \
KMP_FSYNC_RELEASING(ftx); \
kmp_int32 poll_val = \
KMP_XCHG_FIXED32(&(ftx->lk.poll), KMP_LOCK_FREE(futex)); \
if (KMP_LOCK_STRIP(poll_val) & 1) { \
syscall(__NR_futex, &(ftx->lk.poll), FUTEX_WAKE, \
KMP_LOCK_BUSY(1, futex), NULL, NULL, 0); \
} \
KMP_MB(); \
KMP_YIELD(TCR_4(__kmp_nth) > \
(__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc)); \
}
#endif // KMP_USE_FUTEX
#else // KMP_USE_DYNAMIC_LOCK
static kmp_user_lock_p __kmp_get_critical_section_ptr(kmp_critical_name *crit,
ident_t const *loc,
kmp_int32 gtid) {
kmp_user_lock_p *lck_pp = (kmp_user_lock_p *)crit;
// Because of the double-check, the following load doesn't need to be volatile
kmp_user_lock_p lck = (kmp_user_lock_p)TCR_PTR(*lck_pp);
if (lck == NULL) {
void *idx;
// Allocate & initialize the lock.
// Remember alloc'ed locks in table in order to free them in __kmp_cleanup()
lck = __kmp_user_lock_allocate(&idx, gtid, kmp_lf_critical_section);
__kmp_init_user_lock_with_checks(lck);
__kmp_set_user_lock_location(lck, loc);
#if USE_ITT_BUILD
__kmp_itt_critical_creating(lck);
// __kmp_itt_critical_creating() should be called *before* the first usage
// of underlying lock. It is the only place where we can guarantee it. There
// are chances the lock will destroyed with no usage, but it is not a
// problem, because this is not real event seen by user but rather setting
// name for object (lock). See more details in kmp_itt.h.
#endif /* USE_ITT_BUILD */
// Use a cmpxchg instruction to slam the start of the critical section with
// the lock pointer. If another thread beat us to it, deallocate the lock,
// and use the lock that the other thread allocated.
int status = KMP_COMPARE_AND_STORE_PTR(lck_pp, 0, lck);
if (status == 0) {
// Deallocate the lock and reload the value.
#if USE_ITT_BUILD
__kmp_itt_critical_destroyed(lck);
// Let ITT know the lock is destroyed and the same memory location may be reused
// for another purpose.
#endif /* USE_ITT_BUILD */
__kmp_destroy_user_lock_with_checks(lck);
__kmp_user_lock_free(&idx, gtid, lck);
lck = (kmp_user_lock_p)TCR_PTR(*lck_pp);
KMP_DEBUG_ASSERT(lck != NULL);
}
}
return lck;
}
#endif // KMP_USE_DYNAMIC_LOCK
/*!
@ingroup WORK_SHARING
@param loc source location information.
@param global_tid global thread number .
@param crit identity of the critical section. This could be a pointer to a lock
associated with the critical section, or some other suitably unique value.
Enter code protected by a `critical` construct.
This function blocks until the executing thread can enter the critical section.
*/
void __kmpc_critical(ident_t *loc, kmp_int32 global_tid,
kmp_critical_name *crit) {
#if KMP_USE_DYNAMIC_LOCK
#if OMPT_SUPPORT && OMPT_OPTIONAL
OMPT_STORE_RETURN_ADDRESS(global_tid);
#endif // OMPT_SUPPORT
__kmpc_critical_with_hint(loc, global_tid, crit, omp_lock_hint_none);
#else
KMP_COUNT_BLOCK(OMP_CRITICAL);
#if OMPT_SUPPORT && OMPT_OPTIONAL
ompt_state_t prev_state = ompt_state_undefined;
ompt_thread_info_t ti;
#endif
kmp_user_lock_p lck;
KC_TRACE(10, ("__kmpc_critical: called T#%d\n", global_tid));
// TODO: add THR_OVHD_STATE
KMP_PUSH_PARTITIONED_TIMER(OMP_critical_wait);
KMP_CHECK_USER_LOCK_INIT();
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) <= OMP_CRITICAL_SIZE)) {
lck = (kmp_user_lock_p)crit;
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) <= OMP_CRITICAL_SIZE)) {
lck = (kmp_user_lock_p)crit;
}
#endif
else { // ticket, queuing or drdpa
lck = __kmp_get_critical_section_ptr(crit, loc, global_tid);
}
if (__kmp_env_consistency_check)
__kmp_push_sync(global_tid, ct_critical, loc, lck);
// since the critical directive binds to all threads, not just the current
// team we have to check this even if we are in a serialized team.
// also, even if we are the uber thread, we still have to conduct the lock,
// as we have to contend with sibling threads.
#if USE_ITT_BUILD
__kmp_itt_critical_acquiring(lck);
#endif /* USE_ITT_BUILD */
#if OMPT_SUPPORT && OMPT_OPTIONAL
OMPT_STORE_RETURN_ADDRESS(gtid);
void *codeptr_ra = NULL;
if (ompt_enabled.enabled) {
ti = __kmp_threads[global_tid]->th.ompt_thread_info;
/* OMPT state update */
prev_state = ti.state;
- ti.wait_id = (ompt_wait_id_t)lck;
+ ti.wait_id = (ompt_wait_id_t)(uintptr_t)lck;
ti.state = ompt_state_wait_critical;
/* OMPT event callback */
codeptr_ra = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
ompt_mutex_critical, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
- (ompt_wait_id_t)crit, codeptr_ra);
+ (ompt_wait_id_t)(uintptr_t)lck, codeptr_ra);
}
}
#endif
// Value of 'crit' should be good for using as a critical_id of the critical
// section directive.
__kmp_acquire_user_lock_with_checks(lck, global_tid);
#if USE_ITT_BUILD
__kmp_itt_critical_acquired(lck);
#endif /* USE_ITT_BUILD */
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
/* OMPT state update */
ti.state = prev_state;
ti.wait_id = 0;
/* OMPT event callback */
if (ompt_enabled.ompt_callback_mutex_acquired) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
- ompt_mutex_critical, (ompt_wait_id_t)crit, codeptr_ra);
+ ompt_mutex_critical, (ompt_wait_id_t)(uintptr_t)lck, codeptr_ra);
}
}
#endif
KMP_POP_PARTITIONED_TIMER();
KMP_PUSH_PARTITIONED_TIMER(OMP_critical);
KA_TRACE(15, ("__kmpc_critical: done T#%d\n", global_tid));
#endif // KMP_USE_DYNAMIC_LOCK
}
#if KMP_USE_DYNAMIC_LOCK
// Converts the given hint to an internal lock implementation
static __forceinline kmp_dyna_lockseq_t __kmp_map_hint_to_lock(uintptr_t hint) {
#if KMP_USE_TSX
#define KMP_TSX_LOCK(seq) lockseq_##seq
#else
#define KMP_TSX_LOCK(seq) __kmp_user_lock_seq
#endif
#if KMP_ARCH_X86 || KMP_ARCH_X86_64
#define KMP_CPUINFO_RTM (__kmp_cpuinfo.rtm)
#else
#define KMP_CPUINFO_RTM 0
#endif
// Hints that do not require further logic
if (hint & kmp_lock_hint_hle)
return KMP_TSX_LOCK(hle);
if (hint & kmp_lock_hint_rtm)
return KMP_CPUINFO_RTM ? KMP_TSX_LOCK(rtm) : __kmp_user_lock_seq;
if (hint & kmp_lock_hint_adaptive)
return KMP_CPUINFO_RTM ? KMP_TSX_LOCK(adaptive) : __kmp_user_lock_seq;
// Rule out conflicting hints first by returning the default lock
if ((hint & omp_lock_hint_contended) && (hint & omp_lock_hint_uncontended))
return __kmp_user_lock_seq;
if ((hint & omp_lock_hint_speculative) &&
(hint & omp_lock_hint_nonspeculative))
return __kmp_user_lock_seq;
// Do not even consider speculation when it appears to be contended
if (hint & omp_lock_hint_contended)
return lockseq_queuing;
// Uncontended lock without speculation
if ((hint & omp_lock_hint_uncontended) && !(hint & omp_lock_hint_speculative))
return lockseq_tas;
// HLE lock for speculation
if (hint & omp_lock_hint_speculative)
return KMP_TSX_LOCK(hle);
return __kmp_user_lock_seq;
}
#if OMPT_SUPPORT && OMPT_OPTIONAL
#if KMP_USE_DYNAMIC_LOCK
static kmp_mutex_impl_t
__ompt_get_mutex_impl_type(void *user_lock, kmp_indirect_lock_t *ilock = 0) {
if (user_lock) {
switch (KMP_EXTRACT_D_TAG(user_lock)) {
case 0:
break;
#if KMP_USE_FUTEX
case locktag_futex:
return kmp_mutex_impl_queuing;
#endif
case locktag_tas:
return kmp_mutex_impl_spin;
#if KMP_USE_TSX
case locktag_hle:
return kmp_mutex_impl_speculative;
#endif
default:
return kmp_mutex_impl_none;
}
ilock = KMP_LOOKUP_I_LOCK(user_lock);
}
KMP_ASSERT(ilock);
switch (ilock->type) {
#if KMP_USE_TSX
case locktag_adaptive:
case locktag_rtm:
return kmp_mutex_impl_speculative;
#endif
case locktag_nested_tas:
return kmp_mutex_impl_spin;
#if KMP_USE_FUTEX
case locktag_nested_futex:
#endif
case locktag_ticket:
case locktag_queuing:
case locktag_drdpa:
case locktag_nested_ticket:
case locktag_nested_queuing:
case locktag_nested_drdpa:
return kmp_mutex_impl_queuing;
default:
return kmp_mutex_impl_none;
}
}
#else
// For locks without dynamic binding
static kmp_mutex_impl_t __ompt_get_mutex_impl_type() {
switch (__kmp_user_lock_kind) {
case lk_tas:
return kmp_mutex_impl_spin;
#if KMP_USE_FUTEX
case lk_futex:
#endif
case lk_ticket:
case lk_queuing:
case lk_drdpa:
return kmp_mutex_impl_queuing;
#if KMP_USE_TSX
case lk_hle:
case lk_rtm:
case lk_adaptive:
return kmp_mutex_impl_speculative;
#endif
default:
return kmp_mutex_impl_none;
}
}
#endif // KMP_USE_DYNAMIC_LOCK
#endif // OMPT_SUPPORT && OMPT_OPTIONAL
/*!
@ingroup WORK_SHARING
@param loc source location information.
@param global_tid global thread number.
@param crit identity of the critical section. This could be a pointer to a lock
associated with the critical section, or some other suitably unique value.
@param hint the lock hint.
Enter code protected by a `critical` construct with a hint. The hint value is
used to suggest a lock implementation. This function blocks until the executing
thread can enter the critical section unless the hint suggests use of
speculative execution and the hardware supports it.
*/
void __kmpc_critical_with_hint(ident_t *loc, kmp_int32 global_tid,
kmp_critical_name *crit, uint32_t hint) {
KMP_COUNT_BLOCK(OMP_CRITICAL);
kmp_user_lock_p lck;
#if OMPT_SUPPORT && OMPT_OPTIONAL
ompt_state_t prev_state = ompt_state_undefined;
ompt_thread_info_t ti;
// This is the case, if called from __kmpc_critical:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(global_tid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
#endif
KC_TRACE(10, ("__kmpc_critical: called T#%d\n", global_tid));
kmp_dyna_lock_t *lk = (kmp_dyna_lock_t *)crit;
// Check if it is initialized.
KMP_PUSH_PARTITIONED_TIMER(OMP_critical_wait);
if (*lk == 0) {
kmp_dyna_lockseq_t lckseq = __kmp_map_hint_to_lock(hint);
if (KMP_IS_D_LOCK(lckseq)) {
KMP_COMPARE_AND_STORE_ACQ32((volatile kmp_int32 *)crit, 0,
KMP_GET_D_TAG(lckseq));
} else {
__kmp_init_indirect_csptr(crit, loc, global_tid, KMP_GET_I_TAG(lckseq));
}
}
// Branch for accessing the actual lock object and set operation. This
// branching is inevitable since this lock initialization does not follow the
// normal dispatch path (lock table is not used).
if (KMP_EXTRACT_D_TAG(lk) != 0) {
lck = (kmp_user_lock_p)lk;
if (__kmp_env_consistency_check) {
__kmp_push_sync(global_tid, ct_critical, loc, lck,
__kmp_map_hint_to_lock(hint));
}
#if USE_ITT_BUILD
__kmp_itt_critical_acquiring(lck);
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
ti = __kmp_threads[global_tid]->th.ompt_thread_info;
/* OMPT state update */
prev_state = ti.state;
- ti.wait_id = (ompt_wait_id_t)lck;
+ ti.wait_id = (ompt_wait_id_t)(uintptr_t)lck;
ti.state = ompt_state_wait_critical;
/* OMPT event callback */
if (ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
ompt_mutex_critical, (unsigned int)hint,
- __ompt_get_mutex_impl_type(crit), (ompt_wait_id_t)crit, codeptr);
+ __ompt_get_mutex_impl_type(crit), (ompt_wait_id_t)(uintptr_t)lck,
+ codeptr);
}
}
#endif
#if KMP_USE_INLINED_TAS
if (__kmp_user_lock_seq == lockseq_tas && !__kmp_env_consistency_check) {
KMP_ACQUIRE_TAS_LOCK(lck, global_tid);
} else
#elif KMP_USE_INLINED_FUTEX
if (__kmp_user_lock_seq == lockseq_futex && !__kmp_env_consistency_check) {
KMP_ACQUIRE_FUTEX_LOCK(lck, global_tid);
} else
#endif
{
KMP_D_LOCK_FUNC(lk, set)(lk, global_tid);
}
} else {
kmp_indirect_lock_t *ilk = *((kmp_indirect_lock_t **)lk);
lck = ilk->lock;
if (__kmp_env_consistency_check) {
__kmp_push_sync(global_tid, ct_critical, loc, lck,
__kmp_map_hint_to_lock(hint));
}
#if USE_ITT_BUILD
__kmp_itt_critical_acquiring(lck);
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
ti = __kmp_threads[global_tid]->th.ompt_thread_info;
/* OMPT state update */
prev_state = ti.state;
- ti.wait_id = (ompt_wait_id_t)lck;
+ ti.wait_id = (ompt_wait_id_t)(uintptr_t)lck;
ti.state = ompt_state_wait_critical;
/* OMPT event callback */
if (ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
ompt_mutex_critical, (unsigned int)hint,
- __ompt_get_mutex_impl_type(0, ilk), (ompt_wait_id_t)crit, codeptr);
+ __ompt_get_mutex_impl_type(0, ilk), (ompt_wait_id_t)(uintptr_t)lck,
+ codeptr);
}
}
#endif
KMP_I_LOCK_FUNC(ilk, set)(lck, global_tid);
}
KMP_POP_PARTITIONED_TIMER();
#if USE_ITT_BUILD
__kmp_itt_critical_acquired(lck);
#endif /* USE_ITT_BUILD */
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
/* OMPT state update */
ti.state = prev_state;
ti.wait_id = 0;
/* OMPT event callback */
if (ompt_enabled.ompt_callback_mutex_acquired) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
- ompt_mutex_critical, (ompt_wait_id_t)crit, codeptr);
+ ompt_mutex_critical, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
}
#endif
KMP_PUSH_PARTITIONED_TIMER(OMP_critical);
KA_TRACE(15, ("__kmpc_critical: done T#%d\n", global_tid));
} // __kmpc_critical_with_hint
#endif // KMP_USE_DYNAMIC_LOCK
/*!
@ingroup WORK_SHARING
@param loc source location information.
@param global_tid global thread number .
@param crit identity of the critical section. This could be a pointer to a lock
associated with the critical section, or some other suitably unique value.
Leave a critical section, releasing any lock that was held during its execution.
*/
void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
kmp_critical_name *crit) {
kmp_user_lock_p lck;
KC_TRACE(10, ("__kmpc_end_critical: called T#%d\n", global_tid));
#if KMP_USE_DYNAMIC_LOCK
if (KMP_IS_D_LOCK(__kmp_user_lock_seq)) {
lck = (kmp_user_lock_p)crit;
KMP_ASSERT(lck != NULL);
if (__kmp_env_consistency_check) {
__kmp_pop_sync(global_tid, ct_critical, loc);
}
#if USE_ITT_BUILD
__kmp_itt_critical_releasing(lck);
#endif
#if KMP_USE_INLINED_TAS
if (__kmp_user_lock_seq == lockseq_tas && !__kmp_env_consistency_check) {
KMP_RELEASE_TAS_LOCK(lck, global_tid);
} else
#elif KMP_USE_INLINED_FUTEX
if (__kmp_user_lock_seq == lockseq_futex && !__kmp_env_consistency_check) {
KMP_RELEASE_FUTEX_LOCK(lck, global_tid);
} else
#endif
{
KMP_D_LOCK_FUNC(lck, unset)((kmp_dyna_lock_t *)lck, global_tid);
}
} else {
kmp_indirect_lock_t *ilk =
(kmp_indirect_lock_t *)TCR_PTR(*((kmp_indirect_lock_t **)crit));
KMP_ASSERT(ilk != NULL);
lck = ilk->lock;
if (__kmp_env_consistency_check) {
__kmp_pop_sync(global_tid, ct_critical, loc);
}
#if USE_ITT_BUILD
__kmp_itt_critical_releasing(lck);
#endif
KMP_I_LOCK_FUNC(ilk, unset)(lck, global_tid);
}
#else // KMP_USE_DYNAMIC_LOCK
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) <= OMP_CRITICAL_SIZE)) {
lck = (kmp_user_lock_p)crit;
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) <= OMP_CRITICAL_SIZE)) {
lck = (kmp_user_lock_p)crit;
}
#endif
else { // ticket, queuing or drdpa
lck = (kmp_user_lock_p)TCR_PTR(*((kmp_user_lock_p *)crit));
}
KMP_ASSERT(lck != NULL);
if (__kmp_env_consistency_check)
__kmp_pop_sync(global_tid, ct_critical, loc);
#if USE_ITT_BUILD
__kmp_itt_critical_releasing(lck);
#endif /* USE_ITT_BUILD */
// Value of 'crit' should be good for using as a critical_id of the critical
// section directive.
__kmp_release_user_lock_with_checks(lck, global_tid);
#endif // KMP_USE_DYNAMIC_LOCK
#if OMPT_SUPPORT && OMPT_OPTIONAL
/* OMPT release event triggers after lock is released; place here to trigger
* for all #if branches */
OMPT_STORE_RETURN_ADDRESS(global_tid);
if (ompt_enabled.ompt_callback_mutex_released) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
- ompt_mutex_critical, (ompt_wait_id_t)crit, OMPT_LOAD_RETURN_ADDRESS(0));
+ ompt_mutex_critical, (ompt_wait_id_t)(uintptr_t)lck,
+ OMPT_LOAD_RETURN_ADDRESS(0));
}
#endif
KMP_POP_PARTITIONED_TIMER();
KA_TRACE(15, ("__kmpc_end_critical: done T#%d\n", global_tid));
}
/*!
@ingroup SYNCHRONIZATION
@param loc source location information
@param global_tid thread id.
@return one if the thread should execute the master block, zero otherwise
Start execution of a combined barrier and master. The barrier is executed inside
this function.
*/
kmp_int32 __kmpc_barrier_master(ident_t *loc, kmp_int32 global_tid) {
int status;
KC_TRACE(10, ("__kmpc_barrier_master: called T#%d\n", global_tid));
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
if (__kmp_env_consistency_check)
__kmp_check_barrier(global_tid, ct_barrier, loc);
#if OMPT_SUPPORT
ompt_frame_t *ompt_frame;
if (ompt_enabled.enabled) {
__ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
if (ompt_frame->enter_frame.ptr == NULL)
ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
OMPT_STORE_RETURN_ADDRESS(global_tid);
}
#endif
#if USE_ITT_NOTIFY
__kmp_threads[global_tid]->th.th_ident = loc;
#endif
status = __kmp_barrier(bs_plain_barrier, global_tid, TRUE, 0, NULL, NULL);
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
ompt_frame->enter_frame = ompt_data_none;
}
#endif
return (status != 0) ? 0 : 1;
}
/*!
@ingroup SYNCHRONIZATION
@param loc source location information
@param global_tid thread id.
Complete the execution of a combined barrier and master. This function should
only be called at the completion of the <tt>master</tt> code. Other threads will
still be waiting at the barrier and this call releases them.
*/
void __kmpc_end_barrier_master(ident_t *loc, kmp_int32 global_tid) {
KC_TRACE(10, ("__kmpc_end_barrier_master: called T#%d\n", global_tid));
__kmp_end_split_barrier(bs_plain_barrier, global_tid);
}
/*!
@ingroup SYNCHRONIZATION
@param loc source location information
@param global_tid thread id.
@return one if the thread should execute the master block, zero otherwise
Start execution of a combined barrier and master(nowait) construct.
The barrier is executed inside this function.
There is no equivalent "end" function, since the
*/
kmp_int32 __kmpc_barrier_master_nowait(ident_t *loc, kmp_int32 global_tid) {
kmp_int32 ret;
KC_TRACE(10, ("__kmpc_barrier_master_nowait: called T#%d\n", global_tid));
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
if (__kmp_env_consistency_check) {
if (loc == 0) {
KMP_WARNING(ConstructIdentInvalid); // ??? What does it mean for the user?
}
__kmp_check_barrier(global_tid, ct_barrier, loc);
}
#if OMPT_SUPPORT
ompt_frame_t *ompt_frame;
if (ompt_enabled.enabled) {
__ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
if (ompt_frame->enter_frame.ptr == NULL)
ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
OMPT_STORE_RETURN_ADDRESS(global_tid);
}
#endif
#if USE_ITT_NOTIFY
__kmp_threads[global_tid]->th.th_ident = loc;
#endif
__kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
ompt_frame->enter_frame = ompt_data_none;
}
#endif
ret = __kmpc_master(loc, global_tid);
if (__kmp_env_consistency_check) {
/* there's no __kmpc_end_master called; so the (stats) */
/* actions of __kmpc_end_master are done here */
if (global_tid < 0) {
KMP_WARNING(ThreadIdentInvalid);
}
if (ret) {
/* only one thread should do the pop since only */
/* one did the push (see __kmpc_master()) */
__kmp_pop_sync(global_tid, ct_master, loc);
}
}
return (ret);
}
/* The BARRIER for a SINGLE process section is always explicit */
/*!
@ingroup WORK_SHARING
@param loc source location information
@param global_tid global thread number
@return One if this thread should execute the single construct, zero otherwise.
Test whether to execute a <tt>single</tt> construct.
There are no implicit barriers in the two "single" calls, rather the compiler
should introduce an explicit barrier if it is required.
*/
kmp_int32 __kmpc_single(ident_t *loc, kmp_int32 global_tid) {
kmp_int32 rc = __kmp_enter_single(global_tid, loc, TRUE);
if (rc) {
// We are going to execute the single statement, so we should count it.
KMP_COUNT_BLOCK(OMP_SINGLE);
KMP_PUSH_PARTITIONED_TIMER(OMP_single);
}
#if OMPT_SUPPORT && OMPT_OPTIONAL
kmp_info_t *this_thr = __kmp_threads[global_tid];
kmp_team_t *team = this_thr->th.th_team;
int tid = __kmp_tid_from_gtid(global_tid);
if (ompt_enabled.enabled) {
if (rc) {
if (ompt_enabled.ompt_callback_work) {
ompt_callbacks.ompt_callback(ompt_callback_work)(
ompt_work_single_executor, ompt_scope_begin,
&(team->t.ompt_team_info.parallel_data),
&(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
1, OMPT_GET_RETURN_ADDRESS(0));
}
} else {
if (ompt_enabled.ompt_callback_work) {
ompt_callbacks.ompt_callback(ompt_callback_work)(
ompt_work_single_other, ompt_scope_begin,
&(team->t.ompt_team_info.parallel_data),
&(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
1, OMPT_GET_RETURN_ADDRESS(0));
ompt_callbacks.ompt_callback(ompt_callback_work)(
ompt_work_single_other, ompt_scope_end,
&(team->t.ompt_team_info.parallel_data),
&(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
1, OMPT_GET_RETURN_ADDRESS(0));
}
}
}
#endif
return rc;
}
/*!
@ingroup WORK_SHARING
@param loc source location information
@param global_tid global thread number
Mark the end of a <tt>single</tt> construct. This function should
only be called by the thread that executed the block of code protected
by the `single` construct.
*/
void __kmpc_end_single(ident_t *loc, kmp_int32 global_tid) {
__kmp_exit_single(global_tid);
KMP_POP_PARTITIONED_TIMER();
#if OMPT_SUPPORT && OMPT_OPTIONAL
kmp_info_t *this_thr = __kmp_threads[global_tid];
kmp_team_t *team = this_thr->th.th_team;
int tid = __kmp_tid_from_gtid(global_tid);
if (ompt_enabled.ompt_callback_work) {
ompt_callbacks.ompt_callback(ompt_callback_work)(
ompt_work_single_executor, ompt_scope_end,
&(team->t.ompt_team_info.parallel_data),
&(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data), 1,
OMPT_GET_RETURN_ADDRESS(0));
}
#endif
}
/*!
@ingroup WORK_SHARING
@param loc Source location
@param global_tid Global thread id
Mark the end of a statically scheduled loop.
*/
void __kmpc_for_static_fini(ident_t *loc, kmp_int32 global_tid) {
KMP_POP_PARTITIONED_TIMER();
KE_TRACE(10, ("__kmpc_for_static_fini called T#%d\n", global_tid));
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.ompt_callback_work) {
ompt_work_t ompt_work_type = ompt_work_loop;
ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL);
ompt_task_info_t *task_info = __ompt_get_task_info_object(0);
// Determine workshare type
if (loc != NULL) {
if ((loc->flags & KMP_IDENT_WORK_LOOP) != 0) {
ompt_work_type = ompt_work_loop;
} else if ((loc->flags & KMP_IDENT_WORK_SECTIONS) != 0) {
ompt_work_type = ompt_work_sections;
} else if ((loc->flags & KMP_IDENT_WORK_DISTRIBUTE) != 0) {
ompt_work_type = ompt_work_distribute;
} else {
// use default set above.
// a warning about this case is provided in __kmpc_for_static_init
}
KMP_DEBUG_ASSERT(ompt_work_type);
}
ompt_callbacks.ompt_callback(ompt_callback_work)(
ompt_work_type, ompt_scope_end, &(team_info->parallel_data),
&(task_info->task_data), 0, OMPT_GET_RETURN_ADDRESS(0));
}
#endif
if (__kmp_env_consistency_check)
__kmp_pop_workshare(global_tid, ct_pdo, loc);
}
// User routines which take C-style arguments (call by value)
// different from the Fortran equivalent routines
void ompc_set_num_threads(int arg) {
// !!!!! TODO: check the per-task binding
__kmp_set_num_threads(arg, __kmp_entry_gtid());
}
void ompc_set_dynamic(int flag) {
kmp_info_t *thread;
/* For the thread-private implementation of the internal controls */
thread = __kmp_entry_thread();
__kmp_save_internal_controls(thread);
set__dynamic(thread, flag ? TRUE : FALSE);
}
void ompc_set_nested(int flag) {
kmp_info_t *thread;
/* For the thread-private internal controls implementation */
thread = __kmp_entry_thread();
__kmp_save_internal_controls(thread);
set__nested(thread, flag ? TRUE : FALSE);
}
void ompc_set_max_active_levels(int max_active_levels) {
/* TO DO */
/* we want per-task implementation of this internal control */
/* For the per-thread internal controls implementation */
__kmp_set_max_active_levels(__kmp_entry_gtid(), max_active_levels);
}
void ompc_set_schedule(omp_sched_t kind, int modifier) {
// !!!!! TODO: check the per-task binding
__kmp_set_schedule(__kmp_entry_gtid(), (kmp_sched_t)kind, modifier);
}
int ompc_get_ancestor_thread_num(int level) {
return __kmp_get_ancestor_thread_num(__kmp_entry_gtid(), level);
}
int ompc_get_team_size(int level) {
return __kmp_get_team_size(__kmp_entry_gtid(), level);
}
#if OMP_50_ENABLED
/* OpenMP 5.0 Affinity Format API */
void ompc_set_affinity_format(char const *format) {
if (!__kmp_init_serial) {
__kmp_serial_initialize();
}
__kmp_strncpy_truncate(__kmp_affinity_format, KMP_AFFINITY_FORMAT_SIZE,
format, KMP_STRLEN(format) + 1);
}
size_t ompc_get_affinity_format(char *buffer, size_t size) {
size_t format_size;
if (!__kmp_init_serial) {
__kmp_serial_initialize();
}
format_size = KMP_STRLEN(__kmp_affinity_format);
if (buffer && size) {
__kmp_strncpy_truncate(buffer, size, __kmp_affinity_format,
format_size + 1);
}
return format_size;
}
void ompc_display_affinity(char const *format) {
int gtid;
if (!TCR_4(__kmp_init_middle)) {
__kmp_middle_initialize();
}
gtid = __kmp_get_gtid();
__kmp_aux_display_affinity(gtid, format);
}
size_t ompc_capture_affinity(char *buffer, size_t buf_size,
char const *format) {
int gtid;
size_t num_required;
kmp_str_buf_t capture_buf;
if (!TCR_4(__kmp_init_middle)) {
__kmp_middle_initialize();
}
gtid = __kmp_get_gtid();
__kmp_str_buf_init(&capture_buf);
num_required = __kmp_aux_capture_affinity(gtid, format, &capture_buf);
if (buffer && buf_size) {
__kmp_strncpy_truncate(buffer, buf_size, capture_buf.str,
capture_buf.used + 1);
}
__kmp_str_buf_free(&capture_buf);
return num_required;
}
#endif /* OMP_50_ENABLED */
void kmpc_set_stacksize(int arg) {
// __kmp_aux_set_stacksize initializes the library if needed
__kmp_aux_set_stacksize(arg);
}
void kmpc_set_stacksize_s(size_t arg) {
// __kmp_aux_set_stacksize initializes the library if needed
__kmp_aux_set_stacksize(arg);
}
void kmpc_set_blocktime(int arg) {
int gtid, tid;
kmp_info_t *thread;
gtid = __kmp_entry_gtid();
tid = __kmp_tid_from_gtid(gtid);
thread = __kmp_thread_from_gtid(gtid);
__kmp_aux_set_blocktime(arg, thread, tid);
}
void kmpc_set_library(int arg) {
// __kmp_user_set_library initializes the library if needed
__kmp_user_set_library((enum library_type)arg);
}
void kmpc_set_defaults(char const *str) {
// __kmp_aux_set_defaults initializes the library if needed
__kmp_aux_set_defaults(str, KMP_STRLEN(str));
}
void kmpc_set_disp_num_buffers(int arg) {
// ignore after initialization because some teams have already
// allocated dispatch buffers
if (__kmp_init_serial == 0 && arg > 0)
__kmp_dispatch_num_buffers = arg;
}
int kmpc_set_affinity_mask_proc(int proc, void **mask) {
#if defined(KMP_STUB) || !KMP_AFFINITY_SUPPORTED
return -1;
#else
if (!TCR_4(__kmp_init_middle)) {
__kmp_middle_initialize();
}
return __kmp_aux_set_affinity_mask_proc(proc, mask);
#endif
}
int kmpc_unset_affinity_mask_proc(int proc, void **mask) {
#if defined(KMP_STUB) || !KMP_AFFINITY_SUPPORTED
return -1;
#else
if (!TCR_4(__kmp_init_middle)) {
__kmp_middle_initialize();
}
return __kmp_aux_unset_affinity_mask_proc(proc, mask);
#endif
}
int kmpc_get_affinity_mask_proc(int proc, void **mask) {
#if defined(KMP_STUB) || !KMP_AFFINITY_SUPPORTED
return -1;
#else
if (!TCR_4(__kmp_init_middle)) {
__kmp_middle_initialize();
}
return __kmp_aux_get_affinity_mask_proc(proc, mask);
#endif
}
/* -------------------------------------------------------------------------- */
/*!
@ingroup THREADPRIVATE
@param loc source location information
@param gtid global thread number
@param cpy_size size of the cpy_data buffer
@param cpy_data pointer to data to be copied
@param cpy_func helper function to call for copying data
@param didit flag variable: 1=single thread; 0=not single thread
__kmpc_copyprivate implements the interface for the private data broadcast
needed for the copyprivate clause associated with a single region in an
OpenMP<sup>*</sup> program (both C and Fortran).
All threads participating in the parallel region call this routine.
One of the threads (called the single thread) should have the <tt>didit</tt>
variable set to 1 and all other threads should have that variable set to 0.
All threads pass a pointer to a data buffer (cpy_data) that they have built.
The OpenMP specification forbids the use of nowait on the single region when a
copyprivate clause is present. However, @ref __kmpc_copyprivate implements a
barrier internally to avoid race conditions, so the code generation for the
single region should avoid generating a barrier after the call to @ref
__kmpc_copyprivate.
The <tt>gtid</tt> parameter is the global thread id for the current thread.
The <tt>loc</tt> parameter is a pointer to source location information.
Internal implementation: The single thread will first copy its descriptor
address (cpy_data) to a team-private location, then the other threads will each
call the function pointed to by the parameter cpy_func, which carries out the
copy by copying the data using the cpy_data buffer.
The cpy_func routine used for the copy and the contents of the data area defined
by cpy_data and cpy_size may be built in any fashion that will allow the copy
to be done. For instance, the cpy_data buffer can hold the actual data to be
copied or it may hold a list of pointers to the data. The cpy_func routine must
interpret the cpy_data buffer appropriately.
The interface to cpy_func is as follows:
@code
void cpy_func( void *destination, void *source )
@endcode
where void *destination is the cpy_data pointer for the thread being copied to
and void *source is the cpy_data pointer for the thread being copied from.
*/
void __kmpc_copyprivate(ident_t *loc, kmp_int32 gtid, size_t cpy_size,
void *cpy_data, void (*cpy_func)(void *, void *),
kmp_int32 didit) {
void **data_ptr;
KC_TRACE(10, ("__kmpc_copyprivate: called T#%d\n", gtid));
KMP_MB();
data_ptr = &__kmp_team_from_gtid(gtid)->t.t_copypriv_data;
if (__kmp_env_consistency_check) {
if (loc == 0) {
KMP_WARNING(ConstructIdentInvalid);
}
}
// ToDo: Optimize the following two barriers into some kind of split barrier
if (didit)
*data_ptr = cpy_data;
#if OMPT_SUPPORT
ompt_frame_t *ompt_frame;
if (ompt_enabled.enabled) {
__ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
if (ompt_frame->enter_frame.ptr == NULL)
ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
OMPT_STORE_RETURN_ADDRESS(gtid);
}
#endif
/* This barrier is not a barrier region boundary */
#if USE_ITT_NOTIFY
__kmp_threads[gtid]->th.th_ident = loc;
#endif
__kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL);
if (!didit)
(*cpy_func)(cpy_data, *data_ptr);
// Consider next barrier a user-visible barrier for barrier region boundaries
// Nesting checks are already handled by the single construct checks
#if OMPT_SUPPORT
if (ompt_enabled.enabled) {
OMPT_STORE_RETURN_ADDRESS(gtid);
}
#endif
#if USE_ITT_NOTIFY
__kmp_threads[gtid]->th.th_ident = loc; // TODO: check if it is needed (e.g.
// tasks can overwrite the location)
#endif
__kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL);
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
ompt_frame->enter_frame = ompt_data_none;
}
#endif
}
/* -------------------------------------------------------------------------- */
#define INIT_LOCK __kmp_init_user_lock_with_checks
#define INIT_NESTED_LOCK __kmp_init_nested_user_lock_with_checks
#define ACQUIRE_LOCK __kmp_acquire_user_lock_with_checks
#define ACQUIRE_LOCK_TIMED __kmp_acquire_user_lock_with_checks_timed
#define ACQUIRE_NESTED_LOCK __kmp_acquire_nested_user_lock_with_checks
#define ACQUIRE_NESTED_LOCK_TIMED \
__kmp_acquire_nested_user_lock_with_checks_timed
#define RELEASE_LOCK __kmp_release_user_lock_with_checks
#define RELEASE_NESTED_LOCK __kmp_release_nested_user_lock_with_checks
#define TEST_LOCK __kmp_test_user_lock_with_checks
#define TEST_NESTED_LOCK __kmp_test_nested_user_lock_with_checks
#define DESTROY_LOCK __kmp_destroy_user_lock_with_checks
#define DESTROY_NESTED_LOCK __kmp_destroy_nested_user_lock_with_checks
// TODO: Make check abort messages use location info & pass it into
// with_checks routines
#if KMP_USE_DYNAMIC_LOCK
// internal lock initializer
static __forceinline void __kmp_init_lock_with_hint(ident_t *loc, void **lock,
kmp_dyna_lockseq_t seq) {
if (KMP_IS_D_LOCK(seq)) {
KMP_INIT_D_LOCK(lock, seq);
#if USE_ITT_BUILD
__kmp_itt_lock_creating((kmp_user_lock_p)lock, NULL);
#endif
} else {
KMP_INIT_I_LOCK(lock, seq);
#if USE_ITT_BUILD
kmp_indirect_lock_t *ilk = KMP_LOOKUP_I_LOCK(lock);
__kmp_itt_lock_creating(ilk->lock, loc);
#endif
}
}
// internal nest lock initializer
static __forceinline void
__kmp_init_nest_lock_with_hint(ident_t *loc, void **lock,
kmp_dyna_lockseq_t seq) {
#if KMP_USE_TSX
// Don't have nested lock implementation for speculative locks
if (seq == lockseq_hle || seq == lockseq_rtm || seq == lockseq_adaptive)
seq = __kmp_user_lock_seq;
#endif
switch (seq) {
case lockseq_tas:
seq = lockseq_nested_tas;
break;
#if KMP_USE_FUTEX
case lockseq_futex:
seq = lockseq_nested_futex;
break;
#endif
case lockseq_ticket:
seq = lockseq_nested_ticket;
break;
case lockseq_queuing:
seq = lockseq_nested_queuing;
break;
case lockseq_drdpa:
seq = lockseq_nested_drdpa;
break;
default:
seq = lockseq_nested_queuing;
}
KMP_INIT_I_LOCK(lock, seq);
#if USE_ITT_BUILD
kmp_indirect_lock_t *ilk = KMP_LOOKUP_I_LOCK(lock);
__kmp_itt_lock_creating(ilk->lock, loc);
#endif
}
/* initialize the lock with a hint */
void __kmpc_init_lock_with_hint(ident_t *loc, kmp_int32 gtid, void **user_lock,
uintptr_t hint) {
KMP_DEBUG_ASSERT(__kmp_init_serial);
if (__kmp_env_consistency_check && user_lock == NULL) {
KMP_FATAL(LockIsUninitialized, "omp_init_lock_with_hint");
}
__kmp_init_lock_with_hint(loc, user_lock, __kmp_map_hint_to_lock(hint));
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_lock_init) {
ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
ompt_mutex_lock, (omp_lock_hint_t)hint,
- __ompt_get_mutex_impl_type(user_lock), (ompt_wait_id_t)user_lock,
- codeptr);
+ __ompt_get_mutex_impl_type(user_lock),
+ (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
}
/* initialize the lock with a hint */
void __kmpc_init_nest_lock_with_hint(ident_t *loc, kmp_int32 gtid,
void **user_lock, uintptr_t hint) {
KMP_DEBUG_ASSERT(__kmp_init_serial);
if (__kmp_env_consistency_check && user_lock == NULL) {
KMP_FATAL(LockIsUninitialized, "omp_init_nest_lock_with_hint");
}
__kmp_init_nest_lock_with_hint(loc, user_lock, __kmp_map_hint_to_lock(hint));
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_lock_init) {
ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
ompt_mutex_nest_lock, (omp_lock_hint_t)hint,
- __ompt_get_mutex_impl_type(user_lock), (ompt_wait_id_t)user_lock,
- codeptr);
+ __ompt_get_mutex_impl_type(user_lock),
+ (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
}
#endif // KMP_USE_DYNAMIC_LOCK
/* initialize the lock */
void __kmpc_init_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
#if KMP_USE_DYNAMIC_LOCK
KMP_DEBUG_ASSERT(__kmp_init_serial);
if (__kmp_env_consistency_check && user_lock == NULL) {
KMP_FATAL(LockIsUninitialized, "omp_init_lock");
}
__kmp_init_lock_with_hint(loc, user_lock, __kmp_user_lock_seq);
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_lock_init) {
ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
ompt_mutex_lock, omp_lock_hint_none,
- __ompt_get_mutex_impl_type(user_lock), (ompt_wait_id_t)user_lock,
- codeptr);
+ __ompt_get_mutex_impl_type(user_lock),
+ (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
#else // KMP_USE_DYNAMIC_LOCK
static char const *const func = "omp_init_lock";
kmp_user_lock_p lck;
KMP_DEBUG_ASSERT(__kmp_init_serial);
if (__kmp_env_consistency_check) {
if (user_lock == NULL) {
KMP_FATAL(LockIsUninitialized, func);
}
}
KMP_CHECK_USER_LOCK_INIT();
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#endif
else {
lck = __kmp_user_lock_allocate(user_lock, gtid, 0);
}
INIT_LOCK(lck);
__kmp_set_user_lock_location(lck, loc);
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_lock_init) {
ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
ompt_mutex_lock, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
- (ompt_wait_id_t)user_lock, codeptr);
+ (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
#if USE_ITT_BUILD
__kmp_itt_lock_creating(lck);
#endif /* USE_ITT_BUILD */
#endif // KMP_USE_DYNAMIC_LOCK
} // __kmpc_init_lock
/* initialize the lock */
void __kmpc_init_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
#if KMP_USE_DYNAMIC_LOCK
KMP_DEBUG_ASSERT(__kmp_init_serial);
if (__kmp_env_consistency_check && user_lock == NULL) {
KMP_FATAL(LockIsUninitialized, "omp_init_nest_lock");
}
__kmp_init_nest_lock_with_hint(loc, user_lock, __kmp_user_lock_seq);
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_lock_init) {
ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
ompt_mutex_nest_lock, omp_lock_hint_none,
- __ompt_get_mutex_impl_type(user_lock), (ompt_wait_id_t)user_lock,
- codeptr);
+ __ompt_get_mutex_impl_type(user_lock),
+ (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
#else // KMP_USE_DYNAMIC_LOCK
static char const *const func = "omp_init_nest_lock";
kmp_user_lock_p lck;
KMP_DEBUG_ASSERT(__kmp_init_serial);
if (__kmp_env_consistency_check) {
if (user_lock == NULL) {
KMP_FATAL(LockIsUninitialized, func);
}
}
KMP_CHECK_USER_LOCK_INIT();
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
OMP_NEST_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
OMP_NEST_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#endif
else {
lck = __kmp_user_lock_allocate(user_lock, gtid, 0);
}
INIT_NESTED_LOCK(lck);
__kmp_set_user_lock_location(lck, loc);
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_lock_init) {
ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
ompt_mutex_nest_lock, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
- (ompt_wait_id_t)user_lock, codeptr);
+ (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
#if USE_ITT_BUILD
__kmp_itt_lock_creating(lck);
#endif /* USE_ITT_BUILD */
#endif // KMP_USE_DYNAMIC_LOCK
} // __kmpc_init_nest_lock
void __kmpc_destroy_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
#if KMP_USE_DYNAMIC_LOCK
#if USE_ITT_BUILD
kmp_user_lock_p lck;
if (KMP_EXTRACT_D_TAG(user_lock) == 0) {
lck = ((kmp_indirect_lock_t *)KMP_LOOKUP_I_LOCK(user_lock))->lock;
} else {
lck = (kmp_user_lock_p)user_lock;
}
__kmp_itt_lock_destroyed(lck);
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_lock_destroy) {
kmp_user_lock_p lck;
if (KMP_EXTRACT_D_TAG(user_lock) == 0) {
lck = ((kmp_indirect_lock_t *)KMP_LOOKUP_I_LOCK(user_lock))->lock;
} else {
lck = (kmp_user_lock_p)user_lock;
}
ompt_callbacks.ompt_callback(ompt_callback_lock_destroy)(
- ompt_mutex_lock, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
KMP_D_LOCK_FUNC(user_lock, destroy)((kmp_dyna_lock_t *)user_lock);
#else
kmp_user_lock_p lck;
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#endif
else {
lck = __kmp_lookup_user_lock(user_lock, "omp_destroy_lock");
}
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_lock_destroy) {
ompt_callbacks.ompt_callback(ompt_callback_lock_destroy)(
- ompt_mutex_lock, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
#if USE_ITT_BUILD
__kmp_itt_lock_destroyed(lck);
#endif /* USE_ITT_BUILD */
DESTROY_LOCK(lck);
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
;
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
;
}
#endif
else {
__kmp_user_lock_free(user_lock, gtid, lck);
}
#endif // KMP_USE_DYNAMIC_LOCK
} // __kmpc_destroy_lock
/* destroy the lock */
void __kmpc_destroy_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
#if KMP_USE_DYNAMIC_LOCK
#if USE_ITT_BUILD
kmp_indirect_lock_t *ilk = KMP_LOOKUP_I_LOCK(user_lock);
__kmp_itt_lock_destroyed(ilk->lock);
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_lock_destroy) {
ompt_callbacks.ompt_callback(ompt_callback_lock_destroy)(
- ompt_mutex_nest_lock, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
KMP_D_LOCK_FUNC(user_lock, destroy)((kmp_dyna_lock_t *)user_lock);
#else // KMP_USE_DYNAMIC_LOCK
kmp_user_lock_p lck;
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
OMP_NEST_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
OMP_NEST_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#endif
else {
lck = __kmp_lookup_user_lock(user_lock, "omp_destroy_nest_lock");
}
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_lock_destroy) {
ompt_callbacks.ompt_callback(ompt_callback_lock_destroy)(
- ompt_mutex_nest_lock, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
#if USE_ITT_BUILD
__kmp_itt_lock_destroyed(lck);
#endif /* USE_ITT_BUILD */
DESTROY_NESTED_LOCK(lck);
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
OMP_NEST_LOCK_T_SIZE)) {
;
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
OMP_NEST_LOCK_T_SIZE)) {
;
}
#endif
else {
__kmp_user_lock_free(user_lock, gtid, lck);
}
#endif // KMP_USE_DYNAMIC_LOCK
} // __kmpc_destroy_nest_lock
void __kmpc_set_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
KMP_COUNT_BLOCK(OMP_set_lock);
#if KMP_USE_DYNAMIC_LOCK
int tag = KMP_EXTRACT_D_TAG(user_lock);
#if USE_ITT_BUILD
__kmp_itt_lock_acquiring(
(kmp_user_lock_p)
user_lock); // itt function will get to the right lock object.
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
ompt_mutex_lock, omp_lock_hint_none,
- __ompt_get_mutex_impl_type(user_lock), (ompt_wait_id_t)user_lock,
- codeptr);
+ __ompt_get_mutex_impl_type(user_lock),
+ (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
#if KMP_USE_INLINED_TAS
if (tag == locktag_tas && !__kmp_env_consistency_check) {
KMP_ACQUIRE_TAS_LOCK(user_lock, gtid);
} else
#elif KMP_USE_INLINED_FUTEX
if (tag == locktag_futex && !__kmp_env_consistency_check) {
KMP_ACQUIRE_FUTEX_LOCK(user_lock, gtid);
} else
#endif
{
__kmp_direct_set[tag]((kmp_dyna_lock_t *)user_lock, gtid);
}
#if USE_ITT_BUILD
__kmp_itt_lock_acquired((kmp_user_lock_p)user_lock);
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.ompt_callback_mutex_acquired) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
- ompt_mutex_lock, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
#else // KMP_USE_DYNAMIC_LOCK
kmp_user_lock_p lck;
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#endif
else {
lck = __kmp_lookup_user_lock(user_lock, "omp_set_lock");
}
#if USE_ITT_BUILD
__kmp_itt_lock_acquiring(lck);
#endif /* USE_ITT_BUILD */
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
ompt_mutex_lock, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
- (ompt_wait_id_t)lck, codeptr);
+ (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
#endif
ACQUIRE_LOCK(lck, gtid);
#if USE_ITT_BUILD
__kmp_itt_lock_acquired(lck);
#endif /* USE_ITT_BUILD */
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.ompt_callback_mutex_acquired) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
- ompt_mutex_lock, (ompt_wait_id_t)lck, codeptr);
+ ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
#endif
#endif // KMP_USE_DYNAMIC_LOCK
}
void __kmpc_set_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
#if KMP_USE_DYNAMIC_LOCK
#if USE_ITT_BUILD
__kmp_itt_lock_acquiring((kmp_user_lock_p)user_lock);
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.enabled) {
if (ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
ompt_mutex_nest_lock, omp_lock_hint_none,
- __ompt_get_mutex_impl_type(user_lock), (ompt_wait_id_t)user_lock,
- codeptr);
+ __ompt_get_mutex_impl_type(user_lock),
+ (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
}
#endif
int acquire_status =
KMP_D_LOCK_FUNC(user_lock, set)((kmp_dyna_lock_t *)user_lock, gtid);
(void) acquire_status;
#if USE_ITT_BUILD
__kmp_itt_lock_acquired((kmp_user_lock_p)user_lock);
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
if (acquire_status == KMP_LOCK_ACQUIRED_FIRST) {
if (ompt_enabled.ompt_callback_mutex_acquired) {
// lock_first
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
- ompt_mutex_nest_lock, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock,
+ codeptr);
}
} else {
if (ompt_enabled.ompt_callback_nest_lock) {
// lock_next
ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
- ompt_scope_begin, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_scope_begin, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
}
}
#endif
#else // KMP_USE_DYNAMIC_LOCK
int acquire_status;
kmp_user_lock_p lck;
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
OMP_NEST_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
OMP_NEST_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#endif
else {
lck = __kmp_lookup_user_lock(user_lock, "omp_set_nest_lock");
}
#if USE_ITT_BUILD
__kmp_itt_lock_acquiring(lck);
#endif /* USE_ITT_BUILD */
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.enabled) {
if (ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
ompt_mutex_nest_lock, omp_lock_hint_none,
- __ompt_get_mutex_impl_type(), (ompt_wait_id_t)lck, codeptr);
+ __ompt_get_mutex_impl_type(), (ompt_wait_id_t)(uintptr_t)lck,
+ codeptr);
}
}
#endif
ACQUIRE_NESTED_LOCK(lck, gtid, &acquire_status);
#if USE_ITT_BUILD
__kmp_itt_lock_acquired(lck);
#endif /* USE_ITT_BUILD */
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
if (acquire_status == KMP_LOCK_ACQUIRED_FIRST) {
if (ompt_enabled.ompt_callback_mutex_acquired) {
// lock_first
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
- ompt_mutex_nest_lock, (ompt_wait_id_t)lck, codeptr);
+ ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
} else {
if (ompt_enabled.ompt_callback_nest_lock) {
// lock_next
ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
- ompt_scope_begin, (ompt_wait_id_t)lck, codeptr);
+ ompt_scope_begin, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
}
}
#endif
#endif // KMP_USE_DYNAMIC_LOCK
}
void __kmpc_unset_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
#if KMP_USE_DYNAMIC_LOCK
int tag = KMP_EXTRACT_D_TAG(user_lock);
#if USE_ITT_BUILD
__kmp_itt_lock_releasing((kmp_user_lock_p)user_lock);
#endif
#if KMP_USE_INLINED_TAS
if (tag == locktag_tas && !__kmp_env_consistency_check) {
KMP_RELEASE_TAS_LOCK(user_lock, gtid);
} else
#elif KMP_USE_INLINED_FUTEX
if (tag == locktag_futex && !__kmp_env_consistency_check) {
KMP_RELEASE_FUTEX_LOCK(user_lock, gtid);
} else
#endif
{
__kmp_direct_unset[tag]((kmp_dyna_lock_t *)user_lock, gtid);
}
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_mutex_released) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
- ompt_mutex_lock, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
#else // KMP_USE_DYNAMIC_LOCK
kmp_user_lock_p lck;
/* Can't use serial interval since not block structured */
/* release the lock */
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
#if KMP_OS_LINUX && \
(KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
// "fast" path implemented to fix customer performance issue
#if USE_ITT_BUILD
__kmp_itt_lock_releasing((kmp_user_lock_p)user_lock);
#endif /* USE_ITT_BUILD */
TCW_4(((kmp_user_lock_p)user_lock)->tas.lk.poll, 0);
KMP_MB();
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_mutex_released) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
- ompt_mutex_lock, (ompt_wait_id_t)lck, codeptr);
+ ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
#endif
return;
#else
lck = (kmp_user_lock_p)user_lock;
#endif
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#endif
else {
lck = __kmp_lookup_user_lock(user_lock, "omp_unset_lock");
}
#if USE_ITT_BUILD
__kmp_itt_lock_releasing(lck);
#endif /* USE_ITT_BUILD */
RELEASE_LOCK(lck, gtid);
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_mutex_released) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
- ompt_mutex_lock, (ompt_wait_id_t)lck, codeptr);
+ ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
#endif
#endif // KMP_USE_DYNAMIC_LOCK
}
/* release the lock */
void __kmpc_unset_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
#if KMP_USE_DYNAMIC_LOCK
#if USE_ITT_BUILD
__kmp_itt_lock_releasing((kmp_user_lock_p)user_lock);
#endif
int release_status =
KMP_D_LOCK_FUNC(user_lock, unset)((kmp_dyna_lock_t *)user_lock, gtid);
(void) release_status;
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.enabled) {
if (release_status == KMP_LOCK_RELEASED) {
if (ompt_enabled.ompt_callback_mutex_released) {
// release_lock_last
ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
- ompt_mutex_nest_lock, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock,
+ codeptr);
}
} else if (ompt_enabled.ompt_callback_nest_lock) {
// release_lock_prev
ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
- ompt_scope_end, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_scope_end, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
}
#endif
#else // KMP_USE_DYNAMIC_LOCK
kmp_user_lock_p lck;
/* Can't use serial interval since not block structured */
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
OMP_NEST_LOCK_T_SIZE)) {
#if KMP_OS_LINUX && \
(KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
// "fast" path implemented to fix customer performance issue
kmp_tas_lock_t *tl = (kmp_tas_lock_t *)user_lock;
#if USE_ITT_BUILD
__kmp_itt_lock_releasing((kmp_user_lock_p)user_lock);
#endif /* USE_ITT_BUILD */
#if OMPT_SUPPORT && OMPT_OPTIONAL
int release_status = KMP_LOCK_STILL_HELD;
#endif
if (--(tl->lk.depth_locked) == 0) {
TCW_4(tl->lk.poll, 0);
#if OMPT_SUPPORT && OMPT_OPTIONAL
release_status = KMP_LOCK_RELEASED;
#endif
}
KMP_MB();
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.enabled) {
if (release_status == KMP_LOCK_RELEASED) {
if (ompt_enabled.ompt_callback_mutex_released) {
// release_lock_last
ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
- ompt_mutex_nest_lock, (ompt_wait_id_t)lck, codeptr);
+ ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
} else if (ompt_enabled.ompt_callback_nest_lock) {
// release_lock_previous
ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
- ompt_mutex_scope_end, (ompt_wait_id_t)lck, codeptr);
+ ompt_mutex_scope_end, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
}
#endif
return;
#else
lck = (kmp_user_lock_p)user_lock;
#endif
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
OMP_NEST_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#endif
else {
lck = __kmp_lookup_user_lock(user_lock, "omp_unset_nest_lock");
}
#if USE_ITT_BUILD
__kmp_itt_lock_releasing(lck);
#endif /* USE_ITT_BUILD */
int release_status;
release_status = RELEASE_NESTED_LOCK(lck, gtid);
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.enabled) {
if (release_status == KMP_LOCK_RELEASED) {
if (ompt_enabled.ompt_callback_mutex_released) {
// release_lock_last
ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
- ompt_mutex_nest_lock, (ompt_wait_id_t)lck, codeptr);
+ ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
} else if (ompt_enabled.ompt_callback_nest_lock) {
// release_lock_previous
ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
- ompt_mutex_scope_end, (ompt_wait_id_t)lck, codeptr);
+ ompt_mutex_scope_end, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
}
#endif
#endif // KMP_USE_DYNAMIC_LOCK
}
/* try to acquire the lock */
int __kmpc_test_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
KMP_COUNT_BLOCK(OMP_test_lock);
#if KMP_USE_DYNAMIC_LOCK
int rc;
int tag = KMP_EXTRACT_D_TAG(user_lock);
#if USE_ITT_BUILD
__kmp_itt_lock_acquiring((kmp_user_lock_p)user_lock);
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
ompt_mutex_lock, omp_lock_hint_none,
- __ompt_get_mutex_impl_type(user_lock), (ompt_wait_id_t)user_lock,
- codeptr);
+ __ompt_get_mutex_impl_type(user_lock),
+ (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
#if KMP_USE_INLINED_TAS
if (tag == locktag_tas && !__kmp_env_consistency_check) {
KMP_TEST_TAS_LOCK(user_lock, gtid, rc);
} else
#elif KMP_USE_INLINED_FUTEX
if (tag == locktag_futex && !__kmp_env_consistency_check) {
KMP_TEST_FUTEX_LOCK(user_lock, gtid, rc);
} else
#endif
{
rc = __kmp_direct_test[tag]((kmp_dyna_lock_t *)user_lock, gtid);
}
if (rc) {
#if USE_ITT_BUILD
__kmp_itt_lock_acquired((kmp_user_lock_p)user_lock);
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.ompt_callback_mutex_acquired) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
- ompt_mutex_lock, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
return FTN_TRUE;
} else {
#if USE_ITT_BUILD
__kmp_itt_lock_cancelled((kmp_user_lock_p)user_lock);
#endif
return FTN_FALSE;
}
#else // KMP_USE_DYNAMIC_LOCK
kmp_user_lock_p lck;
int rc;
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#endif
else {
lck = __kmp_lookup_user_lock(user_lock, "omp_test_lock");
}
#if USE_ITT_BUILD
__kmp_itt_lock_acquiring(lck);
#endif /* USE_ITT_BUILD */
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
ompt_mutex_lock, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
- (ompt_wait_id_t)lck, codeptr);
+ (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
#endif
rc = TEST_LOCK(lck, gtid);
#if USE_ITT_BUILD
if (rc) {
__kmp_itt_lock_acquired(lck);
} else {
__kmp_itt_lock_cancelled(lck);
}
#endif /* USE_ITT_BUILD */
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (rc && ompt_enabled.ompt_callback_mutex_acquired) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
- ompt_mutex_lock, (ompt_wait_id_t)lck, codeptr);
+ ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
#endif
return (rc ? FTN_TRUE : FTN_FALSE);
/* Can't use serial interval since not block structured */
#endif // KMP_USE_DYNAMIC_LOCK
}
/* try to acquire the lock */
int __kmpc_test_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
#if KMP_USE_DYNAMIC_LOCK
int rc;
#if USE_ITT_BUILD
__kmp_itt_lock_acquiring((kmp_user_lock_p)user_lock);
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
ompt_mutex_nest_lock, omp_lock_hint_none,
- __ompt_get_mutex_impl_type(user_lock), (ompt_wait_id_t)user_lock,
- codeptr);
+ __ompt_get_mutex_impl_type(user_lock),
+ (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
#endif
rc = KMP_D_LOCK_FUNC(user_lock, test)((kmp_dyna_lock_t *)user_lock, gtid);
#if USE_ITT_BUILD
if (rc) {
__kmp_itt_lock_acquired((kmp_user_lock_p)user_lock);
} else {
__kmp_itt_lock_cancelled((kmp_user_lock_p)user_lock);
}
#endif
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled && rc) {
if (rc == 1) {
if (ompt_enabled.ompt_callback_mutex_acquired) {
// lock_first
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
- ompt_mutex_nest_lock, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock,
+ codeptr);
}
} else {
if (ompt_enabled.ompt_callback_nest_lock) {
// lock_next
ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
- ompt_scope_begin, (ompt_wait_id_t)user_lock, codeptr);
+ ompt_scope_begin, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
}
}
}
#endif
return rc;
#else // KMP_USE_DYNAMIC_LOCK
kmp_user_lock_p lck;
int rc;
if ((__kmp_user_lock_kind == lk_tas) &&
(sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
OMP_NEST_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#if KMP_USE_FUTEX
else if ((__kmp_user_lock_kind == lk_futex) &&
(sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
OMP_NEST_LOCK_T_SIZE)) {
lck = (kmp_user_lock_p)user_lock;
}
#endif
else {
lck = __kmp_lookup_user_lock(user_lock, "omp_test_nest_lock");
}
#if USE_ITT_BUILD
__kmp_itt_lock_acquiring(lck);
#endif /* USE_ITT_BUILD */
#if OMPT_SUPPORT && OMPT_OPTIONAL
// This is the case, if called from omp_init_lock_with_hint:
void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
if (!codeptr)
codeptr = OMPT_GET_RETURN_ADDRESS(0);
if (ompt_enabled.enabled) &&
ompt_enabled.ompt_callback_mutex_acquire) {
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
ompt_mutex_nest_lock, omp_lock_hint_none,
- __ompt_get_mutex_impl_type(), (ompt_wait_id_t)lck, codeptr);
+ __ompt_get_mutex_impl_type(), (ompt_wait_id_t)(uintptr_t)lck,
+ codeptr);
}
#endif
rc = TEST_NESTED_LOCK(lck, gtid);
#if USE_ITT_BUILD
if (rc) {
__kmp_itt_lock_acquired(lck);
} else {
__kmp_itt_lock_cancelled(lck);
}
#endif /* USE_ITT_BUILD */
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled && rc) {
if (rc == 1) {
if (ompt_enabled.ompt_callback_mutex_acquired) {
// lock_first
ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
- ompt_mutex_nest_lock, (ompt_wait_id_t)lck, codeptr);
+ ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
} else {
if (ompt_enabled.ompt_callback_nest_lock) {
// lock_next
ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
- ompt_mutex_scope_begin, (ompt_wait_id_t)lck, codeptr);
+ ompt_mutex_scope_begin, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
}
}
}
#endif
return rc;
/* Can't use serial interval since not block structured */
#endif // KMP_USE_DYNAMIC_LOCK
}
// Interface to fast scalable reduce methods routines
// keep the selected method in a thread local structure for cross-function
// usage: will be used in __kmpc_end_reduce* functions;
// another solution: to re-determine the method one more time in
// __kmpc_end_reduce* functions (new prototype required then)
// AT: which solution is better?
#define __KMP_SET_REDUCTION_METHOD(gtid, rmethod) \
((__kmp_threads[(gtid)]->th.th_local.packed_reduction_method) = (rmethod))
#define __KMP_GET_REDUCTION_METHOD(gtid) \
(__kmp_threads[(gtid)]->th.th_local.packed_reduction_method)
// description of the packed_reduction_method variable: look at the macros in
// kmp.h
// used in a critical section reduce block
static __forceinline void
__kmp_enter_critical_section_reduce_block(ident_t *loc, kmp_int32 global_tid,
kmp_critical_name *crit) {
// this lock was visible to a customer and to the threading profile tool as a
// serial overhead span (although it's used for an internal purpose only)
// why was it visible in previous implementation?
// should we keep it visible in new reduce block?
kmp_user_lock_p lck;
#if KMP_USE_DYNAMIC_LOCK
kmp_dyna_lock_t *lk = (kmp_dyna_lock_t *)crit;
// Check if it is initialized.
if (*lk == 0) {
if (KMP_IS_D_LOCK(__kmp_user_lock_seq)) {
KMP_COMPARE_AND_STORE_ACQ32((volatile kmp_int32 *)crit, 0,
KMP_GET_D_TAG(__kmp_user_lock_seq));
} else {
__kmp_init_indirect_csptr(crit, loc, global_tid,
KMP_GET_I_TAG(__kmp_user_lock_seq));
}
}
// Branch for accessing the actual lock object and set operation. This
// branching is inevitable since this lock initialization does not follow the
// normal dispatch path (lock table is not used).
if (KMP_EXTRACT_D_TAG(lk) != 0) {
lck = (kmp_user_lock_p)lk;
KMP_DEBUG_ASSERT(lck != NULL);
if (__kmp_env_consistency_check) {
__kmp_push_sync(global_tid, ct_critical, loc, lck, __kmp_user_lock_seq);
}
KMP_D_LOCK_FUNC(lk, set)(lk, global_tid);
} else {
kmp_indirect_lock_t *ilk = *((kmp_indirect_lock_t **)lk);
lck = ilk->lock;
KMP_DEBUG_ASSERT(lck != NULL);
if (__kmp_env_consistency_check) {
__kmp_push_sync(global_tid, ct_critical, loc, lck, __kmp_user_lock_seq);
}
KMP_I_LOCK_FUNC(ilk, set)(lck, global_tid);
}
#else // KMP_USE_DYNAMIC_LOCK
// We know that the fast reduction code is only emitted by Intel compilers
// with 32 byte critical sections. If there isn't enough space, then we
// have to use a pointer.
if (__kmp_base_user_lock_size <= INTEL_CRITICAL_SIZE) {
lck = (kmp_user_lock_p)crit;
} else {
lck = __kmp_get_critical_section_ptr(crit, loc, global_tid);
}
KMP_DEBUG_ASSERT(lck != NULL);
if (__kmp_env_consistency_check)
__kmp_push_sync(global_tid, ct_critical, loc, lck);
__kmp_acquire_user_lock_with_checks(lck, global_tid);
#endif // KMP_USE_DYNAMIC_LOCK
}
// used in a critical section reduce block
static __forceinline void
__kmp_end_critical_section_reduce_block(ident_t *loc, kmp_int32 global_tid,
kmp_critical_name *crit) {
kmp_user_lock_p lck;
#if KMP_USE_DYNAMIC_LOCK
if (KMP_IS_D_LOCK(__kmp_user_lock_seq)) {
lck = (kmp_user_lock_p)crit;
if (__kmp_env_consistency_check)
__kmp_pop_sync(global_tid, ct_critical, loc);
KMP_D_LOCK_FUNC(lck, unset)((kmp_dyna_lock_t *)lck, global_tid);
} else {
kmp_indirect_lock_t *ilk =
(kmp_indirect_lock_t *)TCR_PTR(*((kmp_indirect_lock_t **)crit));
if (__kmp_env_consistency_check)
__kmp_pop_sync(global_tid, ct_critical, loc);
KMP_I_LOCK_FUNC(ilk, unset)(ilk->lock, global_tid);
}
#else // KMP_USE_DYNAMIC_LOCK
// We know that the fast reduction code is only emitted by Intel compilers
// with 32 byte critical sections. If there isn't enough space, then we have
// to use a pointer.
if (__kmp_base_user_lock_size > 32) {
lck = *((kmp_user_lock_p *)crit);
KMP_ASSERT(lck != NULL);
} else {
lck = (kmp_user_lock_p)crit;
}
if (__kmp_env_consistency_check)
__kmp_pop_sync(global_tid, ct_critical, loc);
__kmp_release_user_lock_with_checks(lck, global_tid);
#endif // KMP_USE_DYNAMIC_LOCK
} // __kmp_end_critical_section_reduce_block
#if OMP_40_ENABLED
static __forceinline int
__kmp_swap_teams_for_teams_reduction(kmp_info_t *th, kmp_team_t **team_p,
int *task_state) {
kmp_team_t *team;
// Check if we are inside the teams construct?
if (th->th.th_teams_microtask) {
*team_p = team = th->th.th_team;
if (team->t.t_level == th->th.th_teams_level) {
// This is reduction at teams construct.
KMP_DEBUG_ASSERT(!th->th.th_info.ds.ds_tid); // AC: check that tid == 0
// Let's swap teams temporarily for the reduction.
th->th.th_info.ds.ds_tid = team->t.t_master_tid;
th->th.th_team = team->t.t_parent;
th->th.th_team_nproc = th->th.th_team->t.t_nproc;
th->th.th_task_team = th->th.th_team->t.t_task_team[0];
*task_state = th->th.th_task_state;
th->th.th_task_state = 0;
return 1;
}
}
return 0;
}
static __forceinline void
__kmp_restore_swapped_teams(kmp_info_t *th, kmp_team_t *team, int task_state) {
// Restore thread structure swapped in __kmp_swap_teams_for_teams_reduction.
th->th.th_info.ds.ds_tid = 0;
th->th.th_team = team;
th->th.th_team_nproc = team->t.t_nproc;
th->th.th_task_team = team->t.t_task_team[task_state];
th->th.th_task_state = task_state;
}
#endif
/* 2.a.i. Reduce Block without a terminating barrier */
/*!
@ingroup SYNCHRONIZATION
@param loc source location information
@param global_tid global thread number
@param num_vars number of items (variables) to be reduced
@param reduce_size size of data in bytes to be reduced
@param reduce_data pointer to data to be reduced
@param reduce_func callback function providing reduction operation on two
operands and returning result of reduction in lhs_data
@param lck pointer to the unique lock data structure
@result 1 for the master thread, 0 for all other team threads, 2 for all team
threads if atomic reduction needed
The nowait version is used for a reduce clause with the nowait argument.
*/
kmp_int32
__kmpc_reduce_nowait(ident_t *loc, kmp_int32 global_tid, kmp_int32 num_vars,
size_t reduce_size, void *reduce_data,
void (*reduce_func)(void *lhs_data, void *rhs_data),
kmp_critical_name *lck) {
KMP_COUNT_BLOCK(REDUCE_nowait);
int retval = 0;
PACKED_REDUCTION_METHOD_T packed_reduction_method;
#if OMP_40_ENABLED
kmp_info_t *th;
kmp_team_t *team;
int teams_swapped = 0, task_state;
#endif
KA_TRACE(10, ("__kmpc_reduce_nowait() enter: called T#%d\n", global_tid));
// why do we need this initialization here at all?
// Reduction clause can not be used as a stand-alone directive.
// do not call __kmp_serial_initialize(), it will be called by
// __kmp_parallel_initialize() if needed
// possible detection of false-positive race by the threadchecker ???
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
// check correctness of reduce block nesting
#if KMP_USE_DYNAMIC_LOCK
if (__kmp_env_consistency_check)
__kmp_push_sync(global_tid, ct_reduce, loc, NULL, 0);
#else
if (__kmp_env_consistency_check)
__kmp_push_sync(global_tid, ct_reduce, loc, NULL);
#endif
#if OMP_40_ENABLED
th = __kmp_thread_from_gtid(global_tid);
teams_swapped = __kmp_swap_teams_for_teams_reduction(th, &team, &task_state);
#endif // OMP_40_ENABLED
// packed_reduction_method value will be reused by __kmp_end_reduce* function,
// the value should be kept in a variable
// the variable should be either a construct-specific or thread-specific
// property, not a team specific property
// (a thread can reach the next reduce block on the next construct, reduce
// method may differ on the next construct)
// an ident_t "loc" parameter could be used as a construct-specific property
// (what if loc == 0?)
// (if both construct-specific and team-specific variables were shared,
// then unness extra syncs should be needed)
// a thread-specific variable is better regarding two issues above (next
// construct and extra syncs)
// a thread-specific "th_local.reduction_method" variable is used currently
// each thread executes 'determine' and 'set' lines (no need to execute by one
// thread, to avoid unness extra syncs)
packed_reduction_method = __kmp_determine_reduction_method(
loc, global_tid, num_vars, reduce_size, reduce_data, reduce_func, lck);
__KMP_SET_REDUCTION_METHOD(global_tid, packed_reduction_method);
if (packed_reduction_method == critical_reduce_block) {
__kmp_enter_critical_section_reduce_block(loc, global_tid, lck);
retval = 1;
} else if (packed_reduction_method == empty_reduce_block) {
// usage: if team size == 1, no synchronization is required ( Intel
// platforms only )
retval = 1;
} else if (packed_reduction_method == atomic_reduce_block) {
retval = 2;
// all threads should do this pop here (because __kmpc_end_reduce_nowait()
// won't be called by the code gen)
// (it's not quite good, because the checking block has been closed by
// this 'pop',
// but atomic operation has not been executed yet, will be executed
// slightly later, literally on next instruction)
if (__kmp_env_consistency_check)
__kmp_pop_sync(global_tid, ct_reduce, loc);
} else if (TEST_REDUCTION_METHOD(packed_reduction_method,
tree_reduce_block)) {
// AT: performance issue: a real barrier here
// AT: (if master goes slow, other threads are blocked here waiting for the
// master to come and release them)
// AT: (it's not what a customer might expect specifying NOWAIT clause)
// AT: (specifying NOWAIT won't result in improvement of performance, it'll
// be confusing to a customer)
// AT: another implementation of *barrier_gather*nowait() (or some other design)
// might go faster and be more in line with sense of NOWAIT
// AT: TO DO: do epcc test and compare times
// this barrier should be invisible to a customer and to the threading profile
// tool (it's neither a terminating barrier nor customer's code, it's
// used for an internal purpose)
#if OMPT_SUPPORT
// JP: can this barrier potentially leed to task scheduling?
// JP: as long as there is a barrier in the implementation, OMPT should and
// will provide the barrier events
// so we set-up the necessary frame/return addresses.
ompt_frame_t *ompt_frame;
if (ompt_enabled.enabled) {
__ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
if (ompt_frame->enter_frame.ptr == NULL)
ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
OMPT_STORE_RETURN_ADDRESS(global_tid);
}
#endif
#if USE_ITT_NOTIFY
__kmp_threads[global_tid]->th.th_ident = loc;
#endif
retval =
__kmp_barrier(UNPACK_REDUCTION_BARRIER(packed_reduction_method),
global_tid, FALSE, reduce_size, reduce_data, reduce_func);
retval = (retval != 0) ? (0) : (1);
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
ompt_frame->enter_frame = ompt_data_none;
}
#endif
// all other workers except master should do this pop here
// ( none of other workers will get to __kmpc_end_reduce_nowait() )
if (__kmp_env_consistency_check) {
if (retval == 0) {
__kmp_pop_sync(global_tid, ct_reduce, loc);
}
}
} else {
// should never reach this block
KMP_ASSERT(0); // "unexpected method"
}
#if OMP_40_ENABLED
if (teams_swapped) {
__kmp_restore_swapped_teams(th, team, task_state);
}
#endif
KA_TRACE(
10,
("__kmpc_reduce_nowait() exit: called T#%d: method %08x, returns %08x\n",
global_tid, packed_reduction_method, retval));
return retval;
}
/*!
@ingroup SYNCHRONIZATION
@param loc source location information
@param global_tid global thread id.
@param lck pointer to the unique lock data structure
Finish the execution of a reduce nowait.
*/
void __kmpc_end_reduce_nowait(ident_t *loc, kmp_int32 global_tid,
kmp_critical_name *lck) {
PACKED_REDUCTION_METHOD_T packed_reduction_method;
KA_TRACE(10, ("__kmpc_end_reduce_nowait() enter: called T#%d\n", global_tid));
packed_reduction_method = __KMP_GET_REDUCTION_METHOD(global_tid);
if (packed_reduction_method == critical_reduce_block) {
__kmp_end_critical_section_reduce_block(loc, global_tid, lck);
} else if (packed_reduction_method == empty_reduce_block) {
// usage: if team size == 1, no synchronization is required ( on Intel
// platforms only )
} else if (packed_reduction_method == atomic_reduce_block) {
// neither master nor other workers should get here
// (code gen does not generate this call in case 2: atomic reduce block)
// actually it's better to remove this elseif at all;
// after removal this value will checked by the 'else' and will assert
} else if (TEST_REDUCTION_METHOD(packed_reduction_method,
tree_reduce_block)) {
// only master gets here
} else {
// should never reach this block
KMP_ASSERT(0); // "unexpected method"
}
if (__kmp_env_consistency_check)
__kmp_pop_sync(global_tid, ct_reduce, loc);
KA_TRACE(10, ("__kmpc_end_reduce_nowait() exit: called T#%d: method %08x\n",
global_tid, packed_reduction_method));
return;
}
/* 2.a.ii. Reduce Block with a terminating barrier */
/*!
@ingroup SYNCHRONIZATION
@param loc source location information
@param global_tid global thread number
@param num_vars number of items (variables) to be reduced
@param reduce_size size of data in bytes to be reduced
@param reduce_data pointer to data to be reduced
@param reduce_func callback function providing reduction operation on two
operands and returning result of reduction in lhs_data
@param lck pointer to the unique lock data structure
@result 1 for the master thread, 0 for all other team threads, 2 for all team
threads if atomic reduction needed
A blocking reduce that includes an implicit barrier.
*/
kmp_int32 __kmpc_reduce(ident_t *loc, kmp_int32 global_tid, kmp_int32 num_vars,
size_t reduce_size, void *reduce_data,
void (*reduce_func)(void *lhs_data, void *rhs_data),
kmp_critical_name *lck) {
KMP_COUNT_BLOCK(REDUCE_wait);
int retval = 0;
PACKED_REDUCTION_METHOD_T packed_reduction_method;
#if OMP_40_ENABLED
kmp_info_t *th;
kmp_team_t *team;
int teams_swapped = 0, task_state;
#endif
KA_TRACE(10, ("__kmpc_reduce() enter: called T#%d\n", global_tid));
// why do we need this initialization here at all?
// Reduction clause can not be a stand-alone directive.
// do not call __kmp_serial_initialize(), it will be called by
// __kmp_parallel_initialize() if needed
// possible detection of false-positive race by the threadchecker ???
if (!TCR_4(__kmp_init_parallel))
__kmp_parallel_initialize();
// check correctness of reduce block nesting
#if KMP_USE_DYNAMIC_LOCK
if (__kmp_env_consistency_check)
__kmp_push_sync(global_tid, ct_reduce, loc, NULL, 0);
#else
if (__kmp_env_consistency_check)
__kmp_push_sync(global_tid, ct_reduce, loc, NULL);
#endif
#if OMP_40_ENABLED
th = __kmp_thread_from_gtid(global_tid);
teams_swapped = __kmp_swap_teams_for_teams_reduction(th, &team, &task_state);
#endif // OMP_40_ENABLED
packed_reduction_method = __kmp_determine_reduction_method(
loc, global_tid, num_vars, reduce_size, reduce_data, reduce_func, lck);
__KMP_SET_REDUCTION_METHOD(global_tid, packed_reduction_method);
if (packed_reduction_method == critical_reduce_block) {
__kmp_enter_critical_section_reduce_block(loc, global_tid, lck);
retval = 1;
} else if (packed_reduction_method == empty_reduce_block) {
// usage: if team size == 1, no synchronization is required ( Intel
// platforms only )
retval = 1;
} else if (packed_reduction_method == atomic_reduce_block) {
retval = 2;
} else if (TEST_REDUCTION_METHOD(packed_reduction_method,
tree_reduce_block)) {
// case tree_reduce_block:
// this barrier should be visible to a customer and to the threading profile
// tool (it's a terminating barrier on constructs if NOWAIT not specified)
#if OMPT_SUPPORT
ompt_frame_t *ompt_frame;
if (ompt_enabled.enabled) {
__ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
if (ompt_frame->enter_frame.ptr == NULL)
ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
OMPT_STORE_RETURN_ADDRESS(global_tid);
}
#endif
#if USE_ITT_NOTIFY
__kmp_threads[global_tid]->th.th_ident =
loc; // needed for correct notification of frames
#endif
retval =
__kmp_barrier(UNPACK_REDUCTION_BARRIER(packed_reduction_method),
global_tid, TRUE, reduce_size, reduce_data, reduce_func);
retval = (retval != 0) ? (0) : (1);
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
ompt_frame->enter_frame = ompt_data_none;
}
#endif
// all other workers except master should do this pop here
// ( none of other workers except master will enter __kmpc_end_reduce() )
if (__kmp_env_consistency_check) {
if (retval == 0) { // 0: all other workers; 1: master
__kmp_pop_sync(global_tid, ct_reduce, loc);
}
}
} else {
// should never reach this block
KMP_ASSERT(0); // "unexpected method"
}
#if OMP_40_ENABLED
if (teams_swapped) {
__kmp_restore_swapped_teams(th, team, task_state);
}
#endif
KA_TRACE(10,
("__kmpc_reduce() exit: called T#%d: method %08x, returns %08x\n",
global_tid, packed_reduction_method, retval));
return retval;
}
/*!
@ingroup SYNCHRONIZATION
@param loc source location information
@param global_tid global thread id.
@param lck pointer to the unique lock data structure
Finish the execution of a blocking reduce.
The <tt>lck</tt> pointer must be the same as that used in the corresponding
start function.
*/
void __kmpc_end_reduce(ident_t *loc, kmp_int32 global_tid,
kmp_critical_name *lck) {
PACKED_REDUCTION_METHOD_T packed_reduction_method;
#if OMP_40_ENABLED
kmp_info_t *th;
kmp_team_t *team;
int teams_swapped = 0, task_state;
#endif
KA_TRACE(10, ("__kmpc_end_reduce() enter: called T#%d\n", global_tid));
#if OMP_40_ENABLED
th = __kmp_thread_from_gtid(global_tid);
teams_swapped = __kmp_swap_teams_for_teams_reduction(th, &team, &task_state);
#endif // OMP_40_ENABLED
packed_reduction_method = __KMP_GET_REDUCTION_METHOD(global_tid);
// this barrier should be visible to a customer and to the threading profile
// tool (it's a terminating barrier on constructs if NOWAIT not specified)
if (packed_reduction_method == critical_reduce_block) {
__kmp_end_critical_section_reduce_block(loc, global_tid, lck);
// TODO: implicit barrier: should be exposed
#if OMPT_SUPPORT
ompt_frame_t *ompt_frame;
if (ompt_enabled.enabled) {
__ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
if (ompt_frame->enter_frame.ptr == NULL)
ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
OMPT_STORE_RETURN_ADDRESS(global_tid);
}
#endif
#if USE_ITT_NOTIFY
__kmp_threads[global_tid]->th.th_ident = loc;
#endif
__kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
ompt_frame->enter_frame = ompt_data_none;
}
#endif
} else if (packed_reduction_method == empty_reduce_block) {
// usage: if team size==1, no synchronization is required (Intel platforms only)
// TODO: implicit barrier: should be exposed
#if OMPT_SUPPORT
ompt_frame_t *ompt_frame;
if (ompt_enabled.enabled) {
__ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
if (ompt_frame->enter_frame.ptr == NULL)
ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
OMPT_STORE_RETURN_ADDRESS(global_tid);
}
#endif
#if USE_ITT_NOTIFY
__kmp_threads[global_tid]->th.th_ident = loc;
#endif
__kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
ompt_frame->enter_frame = ompt_data_none;
}
#endif
} else if (packed_reduction_method == atomic_reduce_block) {
#if OMPT_SUPPORT
ompt_frame_t *ompt_frame;
if (ompt_enabled.enabled) {
__ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
if (ompt_frame->enter_frame.ptr == NULL)
ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
OMPT_STORE_RETURN_ADDRESS(global_tid);
}
#endif
// TODO: implicit barrier: should be exposed
#if USE_ITT_NOTIFY
__kmp_threads[global_tid]->th.th_ident = loc;
#endif
__kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
#if OMPT_SUPPORT && OMPT_OPTIONAL
if (ompt_enabled.enabled) {
ompt_frame->enter_frame = ompt_data_none;
}
#endif
} else if (TEST_REDUCTION_METHOD(packed_reduction_method,
tree_reduce_block)) {
// only master executes here (master releases all other workers)
__kmp_end_split_barrier(UNPACK_REDUCTION_BARRIER(packed_reduction_method),
global_tid);
} else {
// should never reach this block
KMP_ASSERT(0); // "unexpected method"
}
#if OMP_40_ENABLED
if (teams_swapped) {
__kmp_restore_swapped_teams(th, team, task_state);
}
#endif
if (__kmp_env_consistency_check)
__kmp_pop_sync(global_tid, ct_reduce, loc);
KA_TRACE(10, ("__kmpc_end_reduce() exit: called T#%d: method %08x\n",
global_tid, packed_reduction_method));
return;
}
#undef __KMP_GET_REDUCTION_METHOD
#undef __KMP_SET_REDUCTION_METHOD
/* end of interface to fast scalable reduce routines */
kmp_uint64 __kmpc_get_taskid() {
kmp_int32 gtid;
kmp_info_t *thread;
gtid = __kmp_get_gtid();
if (gtid < 0) {
return 0;
}
thread = __kmp_thread_from_gtid(gtid);
return thread->th.th_current_task->td_task_id;
} // __kmpc_get_taskid
kmp_uint64 __kmpc_get_parent_taskid() {
kmp_int32 gtid;
kmp_info_t *thread;
kmp_taskdata_t *parent_task;
gtid = __kmp_get_gtid();
if (gtid < 0) {
return 0;
}
thread = __kmp_thread_from_gtid(gtid);
parent_task = thread->th.th_current_task->td_parent;
return (parent_task == NULL ? 0 : parent_task->td_task_id);
} // __kmpc_get_parent_taskid
#if OMP_45_ENABLED
/*!
@ingroup WORK_SHARING
@param loc source location information.
@param gtid global thread number.
@param num_dims number of associated doacross loops.
@param dims info on loops bounds.
Initialize doacross loop information.
Expect compiler send us inclusive bounds,
e.g. for(i=2;i<9;i+=2) lo=2, up=8, st=2.
*/
void __kmpc_doacross_init(ident_t *loc, int gtid, int num_dims,
const struct kmp_dim *dims) {
int j, idx;
kmp_int64 last, trace_count;
kmp_info_t *th = __kmp_threads[gtid];
kmp_team_t *team = th->th.th_team;
kmp_uint32 *flags;
kmp_disp_t *pr_buf = th->th.th_dispatch;
dispatch_shared_info_t *sh_buf;
KA_TRACE(
20,
("__kmpc_doacross_init() enter: called T#%d, num dims %d, active %d\n",
gtid, num_dims, !team->t.t_serialized));
KMP_DEBUG_ASSERT(dims != NULL);
KMP_DEBUG_ASSERT(num_dims > 0);
if (team->t.t_serialized) {
KA_TRACE(20, ("__kmpc_doacross_init() exit: serialized team\n"));
return; // no dependencies if team is serialized
}
KMP_DEBUG_ASSERT(team->t.t_nproc > 1);
idx = pr_buf->th_doacross_buf_idx++; // Increment index of shared buffer for
// the next loop
sh_buf = &team->t.t_disp_buffer[idx % __kmp_dispatch_num_buffers];
// Save bounds info into allocated private buffer
KMP_DEBUG_ASSERT(pr_buf->th_doacross_info == NULL);
pr_buf->th_doacross_info = (kmp_int64 *)__kmp_thread_malloc(
th, sizeof(kmp_int64) * (4 * num_dims + 1));
KMP_DEBUG_ASSERT(pr_buf->th_doacross_info != NULL);
pr_buf->th_doacross_info[0] =
(kmp_int64)num_dims; // first element is number of dimensions
// Save also address of num_done in order to access it later without knowing
// the buffer index
pr_buf->th_doacross_info[1] = (kmp_int64)&sh_buf->doacross_num_done;
pr_buf->th_doacross_info[2] = dims[0].lo;
pr_buf->th_doacross_info[3] = dims[0].up;
pr_buf->th_doacross_info[4] = dims[0].st;
last = 5;
for (j = 1; j < num_dims; ++j) {
kmp_int64
range_length; // To keep ranges of all dimensions but the first dims[0]
if (dims[j].st == 1) { // most common case
// AC: should we care of ranges bigger than LLONG_MAX? (not for now)
range_length = dims[j].up - dims[j].lo + 1;
} else {
if (dims[j].st > 0) {
KMP_DEBUG_ASSERT(dims[j].up > dims[j].lo);
range_length = (kmp_uint64)(dims[j].up - dims[j].lo) / dims[j].st + 1;
} else { // negative increment
KMP_DEBUG_ASSERT(dims[j].lo > dims[j].up);
range_length =
(kmp_uint64)(dims[j].lo - dims[j].up) / (-dims[j].st) + 1;
}
}
pr_buf->th_doacross_info[last++] = range_length;
pr_buf->th_doacross_info[last++] = dims[j].lo;
pr_buf->th_doacross_info[last++] = dims[j].up;
pr_buf->th_doacross_info[last++] = dims[j].st;
}
// Compute total trip count.
// Start with range of dims[0] which we don't need to keep in the buffer.
if (dims[0].st == 1) { // most common case
trace_count = dims[0].up - dims[0].lo + 1;
} else if (dims[0].st > 0) {
KMP_DEBUG_ASSERT(dims[0].up > dims[0].lo);
trace_count = (kmp_uint64)(dims[0].up - dims[0].lo) / dims[0].st + 1;
} else { // negative increment
KMP_DEBUG_ASSERT(dims[0].lo > dims[0].up);
trace_count = (kmp_uint64)(dims[0].lo - dims[0].up) / (-dims[0].st) + 1;
}
for (j = 1; j < num_dims; ++j) {
trace_count *= pr_buf->th_doacross_info[4 * j + 1]; // use kept ranges
}
KMP_DEBUG_ASSERT(trace_count > 0);
// Check if shared buffer is not occupied by other loop (idx -
// __kmp_dispatch_num_buffers)
if (idx != sh_buf->doacross_buf_idx) {
// Shared buffer is occupied, wait for it to be free
__kmp_wait_yield_4((volatile kmp_uint32 *)&sh_buf->doacross_buf_idx, idx,
__kmp_eq_4, NULL);
}
#if KMP_32_BIT_ARCH
// Check if we are the first thread. After the CAS the first thread gets 0,
// others get 1 if initialization is in progress, allocated pointer otherwise.
// Treat pointer as volatile integer (value 0 or 1) until memory is allocated.
flags = (kmp_uint32 *)KMP_COMPARE_AND_STORE_RET32(
(volatile kmp_int32 *)&sh_buf->doacross_flags, NULL, 1);
#else
flags = (kmp_uint32 *)KMP_COMPARE_AND_STORE_RET64(
(volatile kmp_int64 *)&sh_buf->doacross_flags, NULL, 1LL);
#endif
if (flags == NULL) {
// we are the first thread, allocate the array of flags
size_t size = trace_count / 8 + 8; // in bytes, use single bit per iteration
flags = (kmp_uint32 *)__kmp_thread_calloc(th, size, 1);
KMP_MB();
sh_buf->doacross_flags = flags;
} else if (flags == (kmp_uint32 *)1) {
#if KMP_32_BIT_ARCH
// initialization is still in progress, need to wait
while (*(volatile kmp_int32 *)&sh_buf->doacross_flags == 1)
#else
while (*(volatile kmp_int64 *)&sh_buf->doacross_flags == 1LL)
#endif
KMP_YIELD(TRUE);
KMP_MB();
} else {
KMP_MB();
}
KMP_DEBUG_ASSERT(sh_buf->doacross_flags > (kmp_uint32 *)1); // check ptr value
pr_buf->th_doacross_flags =
sh_buf->doacross_flags; // save private copy in order to not
// touch shared buffer on each iteration
KA_TRACE(20, ("__kmpc_doacross_init() exit: T#%d\n", gtid));
}
void __kmpc_doacross_wait(ident_t *loc, int gtid, const kmp_int64 *vec) {
kmp_int32 shft, num_dims, i;
kmp_uint32 flag;
kmp_int64 iter_number; // iteration number of "collapsed" loop nest
kmp_info_t *th = __kmp_threads[gtid];
kmp_team_t *team = th->th.th_team;
kmp_disp_t *pr_buf;
kmp_int64 lo, up, st;
KA_TRACE(20, ("__kmpc_doacross_wait() enter: called T#%d\n", gtid));
if (team->t.t_serialized) {
KA_TRACE(20, ("__kmpc_doacross_wait() exit: serialized team\n"));
return; // no dependencies if team is serialized
}
// calculate sequential iteration number and check out-of-bounds condition
pr_buf = th->th.th_dispatch;
KMP_DEBUG_ASSERT(pr_buf->th_doacross_info != NULL);
num_dims = pr_buf->th_doacross_info[0];
lo = pr_buf->th_doacross_info[2];
up = pr_buf->th_doacross_info[3];
st = pr_buf->th_doacross_info[4];
if (st == 1) { // most common case
if (vec[0] < lo || vec[0] > up) {
KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
"bounds [%lld,%lld]\n",
gtid, vec[0], lo, up));
return;
}
iter_number = vec[0] - lo;
} else if (st > 0) {
if (vec[0] < lo || vec[0] > up) {
KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
"bounds [%lld,%lld]\n",
gtid, vec[0], lo, up));
return;
}
iter_number = (kmp_uint64)(vec[0] - lo) / st;
} else { // negative increment
if (vec[0] > lo || vec[0] < up) {
KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
"bounds [%lld,%lld]\n",
gtid, vec[0], lo, up));
return;
}
iter_number = (kmp_uint64)(lo - vec[0]) / (-st);
}
for (i = 1; i < num_dims; ++i) {
kmp_int64 iter, ln;
kmp_int32 j = i * 4;
ln = pr_buf->th_doacross_info[j + 1];
lo = pr_buf->th_doacross_info[j + 2];
up = pr_buf->th_doacross_info[j + 3];
st = pr_buf->th_doacross_info[j + 4];
if (st == 1) {
if (vec[i] < lo || vec[i] > up) {
KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
"bounds [%lld,%lld]\n",
gtid, vec[i], lo, up));
return;
}
iter = vec[i] - lo;
} else if (st > 0) {
if (vec[i] < lo || vec[i] > up) {
KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
"bounds [%lld,%lld]\n",
gtid, vec[i], lo, up));
return;
}
iter = (kmp_uint64)(vec[i] - lo) / st;
} else { // st < 0
if (vec[i] > lo || vec[i] < up) {
KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
"bounds [%lld,%lld]\n",
gtid, vec[i], lo, up));
return;
}
iter = (kmp_uint64)(lo - vec[i]) / (-st);
}
iter_number = iter + ln * iter_number;
}
shft = iter_number % 32; // use 32-bit granularity
iter_number >>= 5; // divided by 32
flag = 1 << shft;
while ((flag & pr_buf->th_doacross_flags[iter_number]) == 0) {
KMP_YIELD(TRUE);
}
KMP_MB();
KA_TRACE(20,
("__kmpc_doacross_wait() exit: T#%d wait for iter %lld completed\n",
gtid, (iter_number << 5) + shft));
}
void __kmpc_doacross_post(ident_t *loc, int gtid, const kmp_int64 *vec) {
kmp_int32 shft, num_dims, i;
kmp_uint32 flag;
kmp_int64 iter_number; // iteration number of "collapsed" loop nest
kmp_info_t *th = __kmp_threads[gtid];
kmp_team_t *team = th->th.th_team;
kmp_disp_t *pr_buf;
kmp_int64 lo, st;
KA_TRACE(20, ("__kmpc_doacross_post() enter: called T#%d\n", gtid));
if (team->t.t_serialized) {
KA_TRACE(20, ("__kmpc_doacross_post() exit: serialized team\n"));
return; // no dependencies if team is serialized
}
// calculate sequential iteration number (same as in "wait" but no
// out-of-bounds checks)
pr_buf = th->th.th_dispatch;
KMP_DEBUG_ASSERT(pr_buf->th_doacross_info != NULL);
num_dims = pr_buf->th_doacross_info[0];
lo = pr_buf->th_doacross_info[2];
st = pr_buf->th_doacross_info[4];
if (st == 1) { // most common case
iter_number = vec[0] - lo;
} else if (st > 0) {
iter_number = (kmp_uint64)(vec[0] - lo) / st;
} else { // negative increment
iter_number = (kmp_uint64)(lo - vec[0]) / (-st);
}
for (i = 1; i < num_dims; ++i) {
kmp_int64 iter, ln;
kmp_int32 j = i * 4;
ln = pr_buf->th_doacross_info[j + 1];
lo = pr_buf->th_doacross_info[j + 2];
st = pr_buf->th_doacross_info[j + 4];
if (st == 1) {
iter = vec[i] - lo;
} else if (st > 0) {
iter = (kmp_uint64)(vec[i] - lo) / st;
} else { // st < 0
iter = (kmp_uint64)(lo - vec[i]) / (-st);
}
iter_number = iter + ln * iter_number;
}
shft = iter_number % 32; // use 32-bit granularity
iter_number >>= 5; // divided by 32
flag = 1 << shft;
KMP_MB();
if ((flag & pr_buf->th_doacross_flags[iter_number]) == 0)
KMP_TEST_THEN_OR32(&pr_buf->th_doacross_flags[iter_number], flag);
KA_TRACE(20, ("__kmpc_doacross_post() exit: T#%d iter %lld posted\n", gtid,
(iter_number << 5) + shft));
}
void __kmpc_doacross_fini(ident_t *loc, int gtid) {
kmp_int32 num_done;
kmp_info_t *th = __kmp_threads[gtid];
kmp_team_t *team = th->th.th_team;
kmp_disp_t *pr_buf = th->th.th_dispatch;
KA_TRACE(20, ("__kmpc_doacross_fini() enter: called T#%d\n", gtid));
if (team->t.t_serialized) {
KA_TRACE(20, ("__kmpc_doacross_fini() exit: serialized team %p\n", team));
return; // nothing to do
}
num_done = KMP_TEST_THEN_INC32((kmp_int32 *)pr_buf->th_doacross_info[1]) + 1;
if (num_done == th->th.th_team_nproc) {
// we are the last thread, need to free shared resources
int idx = pr_buf->th_doacross_buf_idx - 1;
dispatch_shared_info_t *sh_buf =
&team->t.t_disp_buffer[idx % __kmp_dispatch_num_buffers];
KMP_DEBUG_ASSERT(pr_buf->th_doacross_info[1] ==
(kmp_int64)&sh_buf->doacross_num_done);
KMP_DEBUG_ASSERT(num_done == sh_buf->doacross_num_done);
KMP_DEBUG_ASSERT(idx == sh_buf->doacross_buf_idx);
__kmp_thread_free(th, CCAST(kmp_uint32 *, sh_buf->doacross_flags));
sh_buf->doacross_flags = NULL;
sh_buf->doacross_num_done = 0;
sh_buf->doacross_buf_idx +=
__kmp_dispatch_num_buffers; // free buffer for future re-use
}
// free private resources (need to keep buffer index forever)
pr_buf->th_doacross_flags = NULL;
__kmp_thread_free(th, (void *)pr_buf->th_doacross_info);
pr_buf->th_doacross_info = NULL;
KA_TRACE(20, ("__kmpc_doacross_fini() exit: T#%d\n", gtid));
}
#endif
#if OMP_50_ENABLED
int __kmpc_get_target_offload(void) {
if (!__kmp_init_serial) {
__kmp_serial_initialize();
}
return __kmp_target_offload;
}
#endif // OMP_50_ENABLED
// end of file //
Index: stable/11/contrib/openmp/runtime/src/ompt-specific.cpp
===================================================================
--- stable/11/contrib/openmp/runtime/src/ompt-specific.cpp (revision 350258)
+++ stable/11/contrib/openmp/runtime/src/ompt-specific.cpp (revision 350259)
@@ -1,451 +1,451 @@
/*
* ompt-specific.cpp -- OMPT internal functions
*/
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
//******************************************************************************
// include files
//******************************************************************************
#include "kmp.h"
#include "ompt-specific.h"
#if KMP_OS_UNIX
#include <dlfcn.h>
#endif
#if KMP_OS_WINDOWS
#define THREAD_LOCAL __declspec(thread)
#else
#define THREAD_LOCAL __thread
#endif
#define OMPT_WEAK_ATTRIBUTE KMP_WEAK_ATTRIBUTE
//******************************************************************************
// macros
//******************************************************************************
#define LWT_FROM_TEAM(team) (team)->t.ompt_serialized_team_info
#define OMPT_THREAD_ID_BITS 16
//******************************************************************************
// private operations
//******************************************************************************
//----------------------------------------------------------
// traverse the team and task hierarchy
// note: __ompt_get_teaminfo and __ompt_get_task_info_object
// traverse the hierarchy similarly and need to be
// kept consistent
//----------------------------------------------------------
ompt_team_info_t *__ompt_get_teaminfo(int depth, int *size) {
kmp_info_t *thr = ompt_get_thread();
if (thr) {
kmp_team *team = thr->th.th_team;
if (team == NULL)
return NULL;
ompt_lw_taskteam_t *next_lwt = LWT_FROM_TEAM(team), *lwt = NULL;
while (depth > 0) {
// next lightweight team (if any)
if (lwt)
lwt = lwt->parent;
// next heavyweight team (if any) after
// lightweight teams are exhausted
if (!lwt && team) {
if (next_lwt) {
lwt = next_lwt;
next_lwt = NULL;
} else {
team = team->t.t_parent;
if (team) {
next_lwt = LWT_FROM_TEAM(team);
}
}
}
depth--;
}
if (lwt) {
// lightweight teams have one task
if (size)
*size = 1;
// return team info for lightweight team
return &lwt->ompt_team_info;
} else if (team) {
// extract size from heavyweight team
if (size)
*size = team->t.t_nproc;
// return team info for heavyweight team
return &team->t.ompt_team_info;
}
}
return NULL;
}
ompt_task_info_t *__ompt_get_task_info_object(int depth) {
ompt_task_info_t *info = NULL;
kmp_info_t *thr = ompt_get_thread();
if (thr) {
kmp_taskdata_t *taskdata = thr->th.th_current_task;
ompt_lw_taskteam_t *lwt = NULL,
*next_lwt = LWT_FROM_TEAM(taskdata->td_team);
while (depth > 0) {
// next lightweight team (if any)
if (lwt)
lwt = lwt->parent;
// next heavyweight team (if any) after
// lightweight teams are exhausted
if (!lwt && taskdata) {
if (next_lwt) {
lwt = next_lwt;
next_lwt = NULL;
} else {
taskdata = taskdata->td_parent;
if (taskdata) {
next_lwt = LWT_FROM_TEAM(taskdata->td_team);
}
}
}
depth--;
}
if (lwt) {
info = &lwt->ompt_task_info;
} else if (taskdata) {
info = &taskdata->ompt_task_info;
}
}
return info;
}
ompt_task_info_t *__ompt_get_scheduling_taskinfo(int depth) {
ompt_task_info_t *info = NULL;
kmp_info_t *thr = ompt_get_thread();
if (thr) {
kmp_taskdata_t *taskdata = thr->th.th_current_task;
ompt_lw_taskteam_t *lwt = NULL,
*next_lwt = LWT_FROM_TEAM(taskdata->td_team);
while (depth > 0) {
// next lightweight team (if any)
if (lwt)
lwt = lwt->parent;
// next heavyweight team (if any) after
// lightweight teams are exhausted
if (!lwt && taskdata) {
// first try scheduling parent (for explicit task scheduling)
if (taskdata->ompt_task_info.scheduling_parent) {
taskdata = taskdata->ompt_task_info.scheduling_parent;
} else if (next_lwt) {
lwt = next_lwt;
next_lwt = NULL;
} else {
// then go for implicit tasks
taskdata = taskdata->td_parent;
if (taskdata) {
next_lwt = LWT_FROM_TEAM(taskdata->td_team);
}
}
}
depth--;
}
if (lwt) {
info = &lwt->ompt_task_info;
} else if (taskdata) {
info = &taskdata->ompt_task_info;
}
}
return info;
}
//******************************************************************************
// interface operations
//******************************************************************************
//----------------------------------------------------------
// thread support
//----------------------------------------------------------
ompt_data_t *__ompt_get_thread_data_internal() {
if (__kmp_get_gtid() >= 0) {
kmp_info_t *thread = ompt_get_thread();
if (thread == NULL)
return NULL;
return &(thread->th.ompt_thread_info.thread_data);
}
return NULL;
}
//----------------------------------------------------------
// state support
//----------------------------------------------------------
void __ompt_thread_assign_wait_id(void *variable) {
kmp_info_t *ti = ompt_get_thread();
- ti->th.ompt_thread_info.wait_id = (ompt_wait_id_t)variable;
+ ti->th.ompt_thread_info.wait_id = (ompt_wait_id_t)(uintptr_t)variable;
}
int __ompt_get_state_internal(ompt_wait_id_t *omp_wait_id) {
kmp_info_t *ti = ompt_get_thread();
if (ti) {
if (omp_wait_id)
*omp_wait_id = ti->th.ompt_thread_info.wait_id;
return ti->th.ompt_thread_info.state;
}
return ompt_state_undefined;
}
//----------------------------------------------------------
// parallel region support
//----------------------------------------------------------
int __ompt_get_parallel_info_internal(int ancestor_level,
ompt_data_t **parallel_data,
int *team_size) {
if (__kmp_get_gtid() >= 0) {
ompt_team_info_t *info;
if (team_size) {
info = __ompt_get_teaminfo(ancestor_level, team_size);
} else {
info = __ompt_get_teaminfo(ancestor_level, NULL);
}
if (parallel_data) {
*parallel_data = info ? &(info->parallel_data) : NULL;
}
return info ? 2 : 0;
} else {
return 0;
}
}
//----------------------------------------------------------
// lightweight task team support
//----------------------------------------------------------
void __ompt_lw_taskteam_init(ompt_lw_taskteam_t *lwt, kmp_info_t *thr, int gtid,
ompt_data_t *ompt_pid, void *codeptr) {
// initialize parallel_data with input, return address to parallel_data on
// exit
lwt->ompt_team_info.parallel_data = *ompt_pid;
lwt->ompt_team_info.master_return_address = codeptr;
lwt->ompt_task_info.task_data.value = 0;
lwt->ompt_task_info.frame.enter_frame = ompt_data_none;
lwt->ompt_task_info.frame.exit_frame = ompt_data_none;
lwt->ompt_task_info.scheduling_parent = NULL;
lwt->ompt_task_info.deps = NULL;
lwt->ompt_task_info.ndeps = 0;
lwt->heap = 0;
lwt->parent = 0;
}
void __ompt_lw_taskteam_link(ompt_lw_taskteam_t *lwt, kmp_info_t *thr,
int on_heap) {
ompt_lw_taskteam_t *link_lwt = lwt;
if (thr->th.th_team->t.t_serialized >
1) { // we already have a team, so link the new team and swap values
if (on_heap) { // the lw_taskteam cannot stay on stack, allocate it on heap
link_lwt =
(ompt_lw_taskteam_t *)__kmp_allocate(sizeof(ompt_lw_taskteam_t));
}
link_lwt->heap = on_heap;
// would be swap in the (on_stack) case.
ompt_team_info_t tmp_team = lwt->ompt_team_info;
link_lwt->ompt_team_info = *OMPT_CUR_TEAM_INFO(thr);
*OMPT_CUR_TEAM_INFO(thr) = tmp_team;
ompt_task_info_t tmp_task = lwt->ompt_task_info;
link_lwt->ompt_task_info = *OMPT_CUR_TASK_INFO(thr);
*OMPT_CUR_TASK_INFO(thr) = tmp_task;
// link the taskteam into the list of taskteams:
ompt_lw_taskteam_t *my_parent =
thr->th.th_team->t.ompt_serialized_team_info;
link_lwt->parent = my_parent;
thr->th.th_team->t.ompt_serialized_team_info = link_lwt;
} else {
// this is the first serialized team, so we just store the values in the
// team and drop the taskteam-object
*OMPT_CUR_TEAM_INFO(thr) = lwt->ompt_team_info;
*OMPT_CUR_TASK_INFO(thr) = lwt->ompt_task_info;
}
}
void __ompt_lw_taskteam_unlink(kmp_info_t *thr) {
ompt_lw_taskteam_t *lwtask = thr->th.th_team->t.ompt_serialized_team_info;
if (lwtask) {
thr->th.th_team->t.ompt_serialized_team_info = lwtask->parent;
ompt_team_info_t tmp_team = lwtask->ompt_team_info;
lwtask->ompt_team_info = *OMPT_CUR_TEAM_INFO(thr);
*OMPT_CUR_TEAM_INFO(thr) = tmp_team;
ompt_task_info_t tmp_task = lwtask->ompt_task_info;
lwtask->ompt_task_info = *OMPT_CUR_TASK_INFO(thr);
*OMPT_CUR_TASK_INFO(thr) = tmp_task;
if (lwtask->heap) {
__kmp_free(lwtask);
lwtask = NULL;
}
}
// return lwtask;
}
//----------------------------------------------------------
// task support
//----------------------------------------------------------
int __ompt_get_task_info_internal(int ancestor_level, int *type,
ompt_data_t **task_data,
ompt_frame_t **task_frame,
ompt_data_t **parallel_data,
int *thread_num) {
if (__kmp_get_gtid() < 0)
return 0;
if (ancestor_level < 0)
return 0;
// copied from __ompt_get_scheduling_taskinfo
ompt_task_info_t *info = NULL;
ompt_team_info_t *team_info = NULL;
kmp_info_t *thr = ompt_get_thread();
int level = ancestor_level;
if (thr) {
kmp_taskdata_t *taskdata = thr->th.th_current_task;
if (taskdata == NULL)
return 0;
kmp_team *team = thr->th.th_team, *prev_team = NULL;
if (team == NULL)
return 0;
ompt_lw_taskteam_t *lwt = NULL,
*next_lwt = LWT_FROM_TEAM(taskdata->td_team),
*prev_lwt = NULL;
while (ancestor_level > 0) {
// needed for thread_num
prev_team = team;
prev_lwt = lwt;
// next lightweight team (if any)
if (lwt)
lwt = lwt->parent;
// next heavyweight team (if any) after
// lightweight teams are exhausted
if (!lwt && taskdata) {
// first try scheduling parent (for explicit task scheduling)
if (taskdata->ompt_task_info.scheduling_parent) {
taskdata = taskdata->ompt_task_info.scheduling_parent;
} else if (next_lwt) {
lwt = next_lwt;
next_lwt = NULL;
} else {
// then go for implicit tasks
taskdata = taskdata->td_parent;
if (team == NULL)
return 0;
team = team->t.t_parent;
if (taskdata) {
next_lwt = LWT_FROM_TEAM(taskdata->td_team);
}
}
}
ancestor_level--;
}
if (lwt) {
info = &lwt->ompt_task_info;
team_info = &lwt->ompt_team_info;
if (type) {
*type = ompt_task_implicit;
}
} else if (taskdata) {
info = &taskdata->ompt_task_info;
team_info = &team->t.ompt_team_info;
if (type) {
if (taskdata->td_parent) {
*type = (taskdata->td_flags.tasktype ? ompt_task_explicit
: ompt_task_implicit) |
TASK_TYPE_DETAILS_FORMAT(taskdata);
} else {
*type = ompt_task_initial;
}
}
}
if (task_data) {
*task_data = info ? &info->task_data : NULL;
}
if (task_frame) {
// OpenMP spec asks for the scheduling task to be returned.
*task_frame = info ? &info->frame : NULL;
}
if (parallel_data) {
*parallel_data = team_info ? &(team_info->parallel_data) : NULL;
}
if (thread_num) {
if (level == 0)
*thread_num = __kmp_get_tid();
else if (prev_lwt)
*thread_num = 0;
else
*thread_num = prev_team->t.t_master_tid;
// *thread_num = team->t.t_master_tid;
}
return info ? 2 : 0;
}
return 0;
}
//----------------------------------------------------------
// team support
//----------------------------------------------------------
void __ompt_team_assign_id(kmp_team_t *team, ompt_data_t ompt_pid) {
team->t.ompt_team_info.parallel_data = ompt_pid;
}
//----------------------------------------------------------
// misc
//----------------------------------------------------------
static uint64_t __ompt_get_unique_id_internal() {
static uint64_t thread = 1;
static THREAD_LOCAL uint64_t ID = 0;
if (ID == 0) {
uint64_t new_thread = KMP_TEST_THEN_INC64((kmp_int64 *)&thread);
ID = new_thread << (sizeof(uint64_t) * 8 - OMPT_THREAD_ID_BITS);
}
return ++ID;
}
Index: stable/11/etc/mtree/BSD.debug.dist
===================================================================
--- stable/11/etc/mtree/BSD.debug.dist (revision 350258)
+++ stable/11/etc/mtree/BSD.debug.dist (revision 350259)
@@ -1,62 +1,62 @@
# $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
..
..
libexec
..
sbin
..
usr
bin
..
lib
clang
- 8.0.0
+ 8.0.1
lib
freebsd
..
..
..
..
engines
..
i18n
..
..
libexec
bsdinstall
..
lpr
ru
..
..
sendmail
..
sm.bin
..
..
sbin
..
tests
..
..
..
..
Index: stable/11/etc/mtree/BSD.usr.dist
===================================================================
--- stable/11/etc/mtree/BSD.usr.dist (revision 350258)
+++ stable/11/etc/mtree/BSD.usr.dist (revision 350259)
@@ -1,1502 +1,1502 @@
# $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
..
ucl
..
..
..
lib
aout
..
clang
- 8.0.0
+ 8.0.1
include
sanitizer
..
..
lib
freebsd
..
..
..
..
compat
aout
..
..
dtrace
..
engines
..
i18n
..
libxo
encoder
..
..
..
libdata
gcc
..
ldscripts
..
lint
..
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
..
..
local
..
obj nochange
..
sbin
..
share
atf
..
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
..
..
dict
..
doc
IPv6
..
atf
..
atm
..
legal
..
llvm
clang
..
..
ncurses
..
ntp
drivers
icons
..
scripts
..
..
hints
..
icons
..
pic
..
scripts
..
..
papers
..
pjdfstest
..
psd
01.cacm
..
02.implement
..
03.iosys
..
04.uprog
..
05.sysman
..
06.Clang
..
12.make
..
13.rcs
..
15.yacc
..
16.lex
..
17.m4
..
18.gprof
..
20.ipctut
..
21.ipc
..
22.rpcgen
..
23.rpc
..
24.xdr
..
25.xdrrfc
..
26.rpcrfc
..
27.nfsrfc
..
..
smm
01.setup
..
02.config
..
03.fsck
..
04.quotas
..
05.fastfs
..
06.nfs
..
07.lpd
..
08.sendmailop
..
11.timedop
..
12.timed
..
18.net
..
..
usd
04.csh
..
05.dc
..
06.bc
..
07.mail
..
10.exref
..
11.edit
..
12.vi
..
13.viref
..
18.msdiffs
..
19.memacros
..
20.meref
..
21.troff
..
22.trofftut
..
..
..
dtrace
..
examples
BSD_daemon
..
FreeBSD_version
..
IPv6
..
bhyve
..
bootforth
..
bsdconfig
..
csh
..
diskless
..
dma
..
drivers
..
dwatch
..
etc
defaults
..
..
find_interface
..
hast
..
hostapd
..
ibcs2
..
indent
..
ipfilter
..
ipfw
..
jails
..
kld
cdev
module
..
test
..
..
dyn_sysctl
..
firmware
fwconsumer
..
fwimage
..
..
khelp
..
syscall
module
..
test
..
..
..
libusb20
..
libvgl
..
mdoc
..
netgraph
..
pc-sysinstall
..
perfmon
..
pf
..
ppi
..
ppp
..
printing
..
scsi_target
..
ses
getencstat
..
sesd
..
setencstat
..
setobjstat
..
srcs
..
..
smbfs
print
..
..
sunrpc
dir
..
msg
..
sort
..
..
tcsh
..
uefisign
..
ypldap
..
..
firmware
..
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
..
trusted
..
..
..
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
..
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
/set uname=man
cat1
..
cat2
..
cat3
..
cat4
amd64
..
arm
..
i386
..
powerpc
..
sparc64
..
..
cat5
..
cat6
..
cat7
..
cat8
amd64
..
i386
..
powerpc
..
sparc64
..
..
cat9
..
en.ISO8859-1 uname=root
cat1
..
cat2
..
cat3
..
cat4
amd64
..
arm
..
i386
..
powerpc
..
sparc64
..
..
cat5
..
cat6
..
cat7
..
cat8
amd64
..
i386
..
powerpc
..
sparc64
..
..
cat9
..
..
en.UTF-8 uname=root
cat1
..
cat2
..
cat3
..
cat4
amd64
..
arm
..
i386
..
powerpc
..
sparc64
..
..
cat5
..
cat6
..
cat7
..
cat8
amd64
..
i386
..
powerpc
..
sparc64
..
..
cat9
..
..
ja uname=root
cat1
..
cat2
..
cat3
..
cat4
..
cat5
..
cat6
..
cat7
..
cat8
..
cat9
..
/set uname=root
man1
..
man2
..
man3
..
man4
..
man5
..
man6
..
man7
..
man8
..
man9
..
..
man1
..
man2
..
man3
..
man4
amd64
..
arm
..
i386
..
powerpc
..
sparc64
..
..
man5
..
man6
..
man7
..
man8
amd64
..
i386
..
powerpc
..
sparc64
..
..
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.Big5HKSCS
..
zh_HK.UTF-8
..
zh_TW.Big5
..
zh_TW.UTF-8
..
..
openssl
man
/set uname=man
cat1
..
cat3
..
en.ISO8859-1 uname=root
cat1
..
cat3
..
..
/set uname=root
man1
..
man3
..
..
..
pc-sysinstall
backend
..
backend-partmanager
..
backend-query
..
conf
license
..
..
doc
..
..
security
..
sendmail
..
skel
..
snmp
defs
..
mibs
..
..
syscons
fonts
..
keymaps
..
scrnmaps
..
..
tabset
..
vi
catalog
..
..
vt
fonts
..
keymaps
..
..
zoneinfo
Africa
..
America
Argentina
..
Indiana
..
Kentucky
..
North_Dakota
..
..
Antarctica
..
Arctic
..
Asia
..
Atlantic
..
Australia
..
Etc
..
Europe
..
Indian
..
Pacific
..
SystemV
..
..
..
src nochange
..
..
Index: stable/11/lib/clang/freebsd_cc_version.h
===================================================================
--- stable/11/lib/clang/freebsd_cc_version.h (revision 350258)
+++ stable/11/lib/clang/freebsd_cc_version.h (revision 350259)
@@ -1,3 +1,3 @@
/* $FreeBSD$ */
-#define FREEBSD_CC_VERSION 1100512
+#define FREEBSD_CC_VERSION 1100513
Index: stable/11/lib/clang/headers/Makefile
===================================================================
--- stable/11/lib/clang/headers/Makefile (revision 350258)
+++ stable/11/lib/clang/headers/Makefile (revision 350259)
@@ -1,145 +1,145 @@
# $FreeBSD$
.include "../clang.pre.mk"
.PATH: ${CLANG_SRCS}/lib/Headers
-INCSDIR= ${LIBDIR}/clang/8.0.0/include
+INCSDIR= ${LIBDIR}/clang/8.0.1/include
GENINCS+= arm_fp16.h
GENINCS+= arm_neon.h
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_forward_declares.h
INCS+= __clang_cuda_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+= arm64intr.h
INCS+= arm_acle.h
INCS+= armintr.h
INCS+= avx2intrin.h
INCS+= avx512bitalgintrin.h
INCS+= avx512bwintrin.h
INCS+= avx512cdintrin.h
INCS+= avx512dqintrin.h
INCS+= avx512erintrin.h
INCS+= avx512fintrin.h
INCS+= avx512ifmaintrin.h
INCS+= avx512ifmavlintrin.h
INCS+= avx512pfintrin.h
INCS+= avx512vbmi2intrin.h
INCS+= avx512vbmiintrin.h
INCS+= avx512vbmivlintrin.h
INCS+= avx512vlbitalgintrin.h
INCS+= avx512vlbwintrin.h
INCS+= avx512vlcdintrin.h
INCS+= avx512vldqintrin.h
INCS+= avx512vlintrin.h
INCS+= avx512vlvbmi2intrin.h
INCS+= avx512vlvnniintrin.h
INCS+= avx512vnniintrin.h
INCS+= avx512vpopcntdqintrin.h
INCS+= avx512vpopcntdqvlintrin.h
INCS+= avxintrin.h
INCS+= bmi2intrin.h
INCS+= bmiintrin.h
INCS+= cetintrin.h
INCS+= cldemoteintrin.h
INCS+= clflushoptintrin.h
INCS+= clwbintrin.h
INCS+= clzerointrin.h
INCS+= cpuid.h
INCS+= emmintrin.h
INCS+= f16cintrin.h
INCS+= fma4intrin.h
INCS+= fmaintrin.h
INCS+= fxsrintrin.h
INCS+= gfniintrin.h
INCS+= htmintrin.h
INCS+= htmxlintrin.h
INCS+= ia32intrin.h
INCS+= immintrin.h
INCS+= invpcidintrin.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.h
INCS+= pconfigintrin.h
INCS+= pkuintrin.h
INCS+= pmmintrin.h
INCS+= popcntintrin.h
INCS+= prfchwintrin.h
INCS+= ptwriteintrin.h
INCS+= rdseedintrin.h
INCS+= rtmintrin.h
INCS+= s390intrin.h
INCS+= sgxintrin.h
INCS+= shaintrin.h
INCS+= smmintrin.h
INCS+= tbmintrin.h
INCS+= tmmintrin.h
INCS+= vadefs.h
INCS+= vaesintrin.h
INCS+= vecintrin.h
INCS+= vpclmulqdqintrin.h
INCS+= waitpkgintrin.h
INCS+= wbnoinvdintrin.h
INCS+= wmmintrin.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:
.if defined(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
arm_fp16.h: ${CLANG_SRCS}/include/clang/Basic/arm_fp16.td
${CLANG_TBLGEN} -gen-arm-fp16 \
-I ${CLANG_SRCS}/include/clang/Basic -d ${.TARGET:C/$/.d/} \
-o ${.TARGET} ${CLANG_SRCS}/include/clang/Basic/arm_fp16.td
arm_neon.h: ${CLANG_SRCS}/include/clang/Basic/arm_neon.td
${CLANG_TBLGEN} -gen-arm-neon \
-I ${CLANG_SRCS}/include/clang/Basic -d ${.TARGET:C/$/.d/} \
-o ${.TARGET} ${CLANG_SRCS}/include/clang/Basic/arm_neon.td
CLEANFILES= ${GENINCS} ${GENINCS:C/$/.d/}
.include <bsd.prog.mk>
Index: stable/11/lib/clang/include/clang/Basic/Version.inc
===================================================================
--- stable/11/lib/clang/include/clang/Basic/Version.inc (revision 350258)
+++ stable/11/lib/clang/include/clang/Basic/Version.inc (revision 350259)
@@ -1,11 +1,11 @@
/* $FreeBSD$ */
-#define CLANG_VERSION 8.0.0
-#define CLANG_VERSION_STRING "8.0.0"
+#define CLANG_VERSION 8.0.1
+#define CLANG_VERSION_STRING "8.0.1"
#define CLANG_VERSION_MAJOR 8
#define CLANG_VERSION_MINOR 0
-#define CLANG_VERSION_PATCHLEVEL 0
+#define CLANG_VERSION_PATCHLEVEL 1
#define CLANG_VENDOR "FreeBSD "
-#define SVN_REVISION "356365"
+#define SVN_REVISION "366581"
Index: stable/11/lib/clang/include/clang/Config/config.h
===================================================================
--- stable/11/lib/clang/include/clang/Config/config.h (revision 350258)
+++ stable/11/lib/clang/include/clang/Config/config.h (revision 350259)
@@ -1,84 +1,84 @@
/* $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 linker to use. */
#define CLANG_DEFAULT_LINKER ""
/* Default C/ObjC standard to use. */
/* #undef CLANG_DEFAULT_STD_C */
/* Default C++/ObjC++ standard to use. */
/* #undef CLANG_DEFAULT_STD_CXX */
/* Default C++ stdlib to use. */
#define CLANG_DEFAULT_CXX_STDLIB ""
/* Default runtime library to use. */
#define CLANG_DEFAULT_RTLIB ""
/* 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"
/* 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 z3 and want to build it */
/* #undef CLANG_ANALYZER_WITH_Z3 */
/* Define if we have sys/resource.h (rlimits) */
#define CLANG_HAVE_RLIMITS 1
/* The LLVM product name and version */
-#define BACKEND_PACKAGE_STRING "LLVM 8.0.0"
+#define BACKEND_PACKAGE_STRING "LLVM 8.0.1"
/* 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 0
/* Enable the experimental new pass manager by default */
#define ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER 0
/* Enable each functionality of modules */
/* #undef CLANG_ENABLE_ARCMT */
/* #undef CLANG_ENABLE_OBJC_REWRITER */
/* #undef CLANG_ENABLE_STATIC_ANALYZER */
#endif
Index: stable/11/lib/clang/include/lld/Common/Version.inc
===================================================================
--- stable/11/lib/clang/include/lld/Common/Version.inc (revision 350258)
+++ stable/11/lib/clang/include/lld/Common/Version.inc (revision 350259)
@@ -1,10 +1,10 @@
// $FreeBSD$
-#define LLD_VERSION 8.0.0
-#define LLD_VERSION_STRING "8.0.0"
+#define LLD_VERSION 8.0.1
+#define LLD_VERSION_STRING "8.0.1"
#define LLD_VERSION_MAJOR 8
#define LLD_VERSION_MINOR 0
#define LLD_REPOSITORY_STRING "FreeBSD"
// <Upstream revision at import>-<Local identifier in __FreeBSD_version style>
-#define LLD_REVISION_STRING "356365-1100005"
+#define LLD_REVISION_STRING "366581-1100006"
Index: stable/11/lib/clang/include/llvm/Config/config.h
===================================================================
--- stable/11/lib/clang/include/llvm/Config/config.h (revision 350258)
+++ stable/11/lib/clang/include/llvm/Config/config.h (revision 350259)
@@ -1,356 +1,356 @@
/* $FreeBSD$ */
#ifndef CONFIG_H
#define CONFIG_H
/* 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 0
/* 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 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__ */
#define HAVE_CRASHREPORTER_INFO 0
/* 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 DIA SDK installed, and to 0 if you don't. */
#define LLVM_ENABLE_DIA_SDK 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
/* 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. */
#if __FreeBSD__ >= 11
#define HAVE_FUTIMENS 1
#endif
/* 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 1
/* Define to 1 if you have the `pfm' library (-lpfm). */
/* #undef HAVE_LIBPFM */
/* 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. */
/* #undef HAVE_PTHREAD_GETNAME_NP */
/* Define to 1 if you have the `pthread_setname_np' function. */
/* #undef HAVE_PTHREAD_SETNAME_NP */
/* Define to 1 if you have the `z' library (-lz). */
#define HAVE_LIBZ 1
/* Define to 1 if you have the <link.h> header file. */
#define HAVE_LINK_H 1
/* Define to 1 if you have the `lseek64' function. */
/* #undef HAVE_LSEEK64 */
/* Define to 1 if you have the <mach/mach.h> header file. */
/* #undef HAVE_MACH_MACH_H */
/* Define to 1 if you have the `mallctl' function. */
#define HAVE_MALLCTL 1
/* Define to 1 if you have the `mallinfo' function. */
/* #undef HAVE_MALLINFO */
/* Define to 1 if you have the <malloc.h> header file. */
/* #undef HAVE_MALLOC_H */
/* Define to 1 if you have the <malloc/malloc.h> header file. */
/* #undef HAVE_MALLOC_MALLOC_H */
/* Define to 1 if you have the `malloc_zone_statistics' function. */
/* #undef HAVE_MALLOC_ZONE_STATISTICS */
/* Define to 1 if you have the `posix_fallocate' function. */
#define HAVE_POSIX_FALLOCATE 1
/* 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
/* Have pthread_getspecific */
#define HAVE_PTHREAD_GETSPECIFIC 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 `realpath' function. */
#define HAVE_REALPATH 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 `sched_getaffinity' function. */
/* #undef HAVE_SCHED_GETAFFINITY */
/* Define to 1 if you have the `CPU_COUNT' macro. */
/* #undef HAVE_CPU_COUNT */
/* 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 .*/
#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
/* Define to 1 if stat struct has st_mtim member. */
#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1
/* 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. */
#define HAVE_TERMINFO 1
/* Define if the xar_open() function is supported this platform. */
/* #undef HAVE_LIBXAR */
/* 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 */
/* Define to 1 if you have the <zlib.h> header file. */
#define HAVE_ZLIB_H 1
/* 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. */
/* #undef HAVE__UNWIND_BACKTRACE */
/* 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 */
/* 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 zlib compression is available */
#define LLVM_ENABLE_ZLIB 1
/* Define if overriding target triple is enabled */
/* #undef LLVM_TARGET_TRIPLE_ENV */
/* LLVM version information */
/* #undef LLVM_VERSION_INFO */
/* 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_LIBXML2_ENABLED */
/* Define to the extension used for shared libraries, say, ".so". */
#define LTDL_SHLIB_EXT ".so"
/* 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 8.0.0"
+#define PACKAGE_STRING "LLVM 8.0.1"
/* Define to the version of this package. */
-#define PACKAGE_VERSION "8.0.0"
+#define PACKAGE_VERSION "8.0.1"
/* Define to the vendor of this package. */
/* #undef PACKAGE_VENDOR */
/* Define as the return type of signal handlers (`int' or `void'). */
#define RETSIGTYPE void
/* 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 */
#endif
Index: stable/11/lib/clang/include/llvm/Config/llvm-config.h
===================================================================
--- stable/11/lib/clang/include/llvm/Config/llvm-config.h (revision 350258)
+++ stable/11/lib/clang/include/llvm/Config/llvm-config.h (revision 350259)
@@ -1,86 +1,86 @@
/* $FreeBSD$ */
/*===------- llvm/Config/llvm-config.h - llvm configuration -------*- C -*-===*/
/* */
/* The LLVM Compiler Infrastructure */
/* */
/* This file is distributed under the University of Illinois Open Source */
/* License. See LICENSE.TXT for details. */
/* */
/*===----------------------------------------------------------------------===*/
/* 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 */
/* Define if we link Polly to the tools */
/* #undef LINK_POLLY_INTO_TOOLS */
/* Target triple LLVM will generate code for by default */
/* #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 */
/* 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 8
/* 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 1
/* LLVM version string */
-#define LLVM_VERSION_STRING "8.0.0"
+#define LLVM_VERSION_STRING "8.0.1"
/* Whether LLVM records statistics for use with GetStatistics(),
* PrintStatistics() or PrintStatisticsJSON()
*/
#define LLVM_FORCE_ENABLE_STATS 0
#endif
Index: stable/11/lib/clang/include/llvm/Support/VCSRevision.h
===================================================================
--- stable/11/lib/clang/include/llvm/Support/VCSRevision.h (revision 350258)
+++ stable/11/lib/clang/include/llvm/Support/VCSRevision.h (revision 350259)
@@ -1,2 +1,2 @@
/* $FreeBSD$ */
-#define LLVM_REVISION "svn-r356365"
+#define LLVM_REVISION "svn-r366581"
Index: stable/11/lib/clang/libllvm/Makefile
===================================================================
--- stable/11/lib/clang/libllvm/Makefile (revision 350258)
+++ stable/11/lib/clang/libllvm/Makefile (revision 350259)
@@ -1,1730 +1,1730 @@
# $FreeBSD$
.include <src.opts.mk>
.include "../llvm.pre.mk"
LIB= llvm
INTERNALLIB=
CFLAGS+= -I${.OBJDIR}
.if ${MK_LLVM_TARGET_AARCH64} == "no" && ${MK_LLVM_TARGET_ARM} == "no" && \
${MK_LLVM_TARGET_BPF} == "no" && ${MK_LLVM_TARGET_MIPS} == "no" && \
${MK_LLVM_TARGET_POWERPC} == "no" && ${MK_LLVM_TARGET_RISCV} == "no" && \
${MK_LLVM_TARGET_SPARC} == "no" && ${MK_LLVM_TARGET_X86} == "no"
.error Please enable at least one of: MK_LLVM_TARGET_AARCH64,\
MK_LLVM_TARGET_ARM, MK_LLVM_TARGET_BPF, MK_LLVM_TARGET_MIPS, \
MK_LLVM_TARGET_POWERPC, MK_LLVM_TARGET_RISCV, MK_LLVM_TARGET_SPARC, \
or MK_LLVM_TARGET_X86
.endif
.for arch in AArch64 ARM BPF Mips PowerPC RISCV Sparc X86
. if ${MK_LLVM_TARGET_${arch:tu}} != "no"
CFLAGS+= -I${LLVM_SRCS}/lib/Target/${arch}
. endif
.endfor
SRCDIR= lib
SRCS_MIN+= Analysis/AliasAnalysis.cpp
SRCS_MIN+= Analysis/AliasAnalysisEvaluator.cpp
SRCS_MIN+= Analysis/AliasAnalysisSummary.cpp
SRCS_MIN+= Analysis/AliasSetTracker.cpp
SRCS_EXT+= Analysis/Analysis.cpp
SRCS_MIN+= Analysis/AssumptionCache.cpp
SRCS_MIN+= Analysis/BasicAliasAnalysis.cpp
SRCS_MIN+= Analysis/BlockFrequencyInfo.cpp
SRCS_MIN+= Analysis/BlockFrequencyInfoImpl.cpp
SRCS_MIN+= Analysis/BranchProbabilityInfo.cpp
SRCS_MIN+= Analysis/CFG.cpp
SRCS_MIN+= Analysis/CFGPrinter.cpp
SRCS_MIN+= Analysis/CFLAndersAliasAnalysis.cpp
SRCS_MIN+= Analysis/CFLSteensAliasAnalysis.cpp
SRCS_MIN+= Analysis/CGSCCPassManager.cpp
SRCS_MIN+= Analysis/CallGraph.cpp
SRCS_MIN+= Analysis/CallGraphSCCPass.cpp
SRCS_MIN+= Analysis/CallPrinter.cpp
SRCS_MIN+= Analysis/CaptureTracking.cpp
SRCS_MIN+= Analysis/CmpInstAnalysis.cpp
SRCS_MIN+= Analysis/CodeMetrics.cpp
SRCS_MIN+= Analysis/ConstantFolding.cpp
SRCS_MIN+= Analysis/CostModel.cpp
SRCS_MIN+= Analysis/Delinearization.cpp
SRCS_MIN+= Analysis/DemandedBits.cpp
SRCS_MIN+= Analysis/DependenceAnalysis.cpp
SRCS_MIN+= Analysis/DivergenceAnalysis.cpp
SRCS_MIN+= Analysis/DomPrinter.cpp
SRCS_MIN+= Analysis/DominanceFrontier.cpp
SRCS_MIN+= Analysis/EHPersonalities.cpp
SRCS_MIN+= Analysis/GlobalsModRef.cpp
SRCS_MIN+= Analysis/GuardUtils.cpp
SRCS_MIN+= Analysis/IVDescriptors.cpp
SRCS_MIN+= Analysis/IVUsers.cpp
SRCS_MIN+= Analysis/IndirectCallPromotionAnalysis.cpp
SRCS_MIN+= Analysis/InlineCost.cpp
SRCS_MIN+= Analysis/InstCount.cpp
SRCS_MIN+= Analysis/InstructionPrecedenceTracking.cpp
SRCS_MIN+= Analysis/InstructionSimplify.cpp
SRCS_MIN+= Analysis/Interval.cpp
SRCS_MIN+= Analysis/IntervalPartition.cpp
SRCS_MIN+= Analysis/IteratedDominanceFrontier.cpp
SRCS_MIN+= Analysis/LazyBlockFrequencyInfo.cpp
SRCS_MIN+= Analysis/LazyBranchProbabilityInfo.cpp
SRCS_MIN+= Analysis/LazyCallGraph.cpp
SRCS_MIN+= Analysis/LazyValueInfo.cpp
SRCS_MIN+= Analysis/LegacyDivergenceAnalysis.cpp
SRCS_MIN+= Analysis/Lint.cpp
SRCS_MIN+= Analysis/Loads.cpp
SRCS_MIN+= Analysis/LoopAccessAnalysis.cpp
SRCS_MIN+= Analysis/LoopAnalysisManager.cpp
SRCS_MIN+= Analysis/LoopInfo.cpp
SRCS_MIN+= Analysis/LoopPass.cpp
SRCS_MIN+= Analysis/LoopUnrollAnalyzer.cpp
SRCS_MIN+= Analysis/MemDepPrinter.cpp
SRCS_MIN+= Analysis/MemDerefPrinter.cpp
SRCS_MIN+= Analysis/MemoryBuiltins.cpp
SRCS_MIN+= Analysis/MemoryDependenceAnalysis.cpp
SRCS_MIN+= Analysis/MemoryLocation.cpp
SRCS_MIN+= Analysis/MemorySSA.cpp
SRCS_MIN+= Analysis/MemorySSAUpdater.cpp
SRCS_MIN+= Analysis/ModuleDebugInfoPrinter.cpp
SRCS_MIN+= Analysis/ModuleSummaryAnalysis.cpp
SRCS_MIN+= Analysis/MustExecute.cpp
SRCS_MIN+= Analysis/ObjCARCAliasAnalysis.cpp
SRCS_MIN+= Analysis/ObjCARCAnalysisUtils.cpp
SRCS_MIN+= Analysis/ObjCARCInstKind.cpp
SRCS_MIN+= Analysis/OptimizationRemarkEmitter.cpp
SRCS_MIN+= Analysis/OrderedBasicBlock.cpp
SRCS_MIN+= Analysis/OrderedInstructions.cpp
SRCS_MIN+= Analysis/PHITransAddr.cpp
SRCS_MIN+= Analysis/PhiValues.cpp
SRCS_MIN+= Analysis/PostDominators.cpp
SRCS_MIN+= Analysis/ProfileSummaryInfo.cpp
SRCS_MIN+= Analysis/PtrUseVisitor.cpp
SRCS_MIN+= Analysis/RegionInfo.cpp
SRCS_MIN+= Analysis/RegionPass.cpp
SRCS_MIN+= Analysis/RegionPrinter.cpp
SRCS_MIN+= Analysis/ScalarEvolution.cpp
SRCS_MIN+= Analysis/ScalarEvolutionAliasAnalysis.cpp
SRCS_MIN+= Analysis/ScalarEvolutionExpander.cpp
SRCS_MIN+= Analysis/ScalarEvolutionNormalization.cpp
SRCS_MIN+= Analysis/ScopedNoAliasAA.cpp
SRCS_MIN+= Analysis/StackSafetyAnalysis.cpp
SRCS_MIN+= Analysis/SyncDependenceAnalysis.cpp
SRCS_MIN+= Analysis/SyntheticCountsUtils.cpp
SRCS_MIN+= Analysis/TargetLibraryInfo.cpp
SRCS_MIN+= Analysis/TargetTransformInfo.cpp
SRCS_MIN+= Analysis/Trace.cpp
SRCS_MIN+= Analysis/TypeBasedAliasAnalysis.cpp
SRCS_MIN+= Analysis/TypeMetadataUtils.cpp
SRCS_MIN+= Analysis/ValueLattice.cpp
SRCS_MIN+= Analysis/ValueLatticeUtils.cpp
SRCS_MIN+= Analysis/ValueTracking.cpp
SRCS_MIN+= Analysis/VectorUtils.cpp
SRCS_MIN+= AsmParser/LLLexer.cpp
SRCS_MIN+= AsmParser/LLParser.cpp
SRCS_MIN+= AsmParser/Parser.cpp
SRCS_MIN+= BinaryFormat/Dwarf.cpp
SRCS_MIN+= BinaryFormat/Magic.cpp
SRCS_MIN+= BinaryFormat/Wasm.cpp
SRCS_MIN+= Bitcode/Reader/BitReader.cpp
SRCS_MIN+= Bitcode/Reader/BitcodeReader.cpp
SRCS_MIN+= Bitcode/Reader/BitstreamReader.cpp
SRCS_MIN+= Bitcode/Reader/MetadataLoader.cpp
SRCS_MIN+= Bitcode/Reader/ValueList.cpp
SRCS_MIN+= Bitcode/Writer/BitWriter.cpp
SRCS_MIN+= Bitcode/Writer/BitcodeWriter.cpp
SRCS_MIN+= Bitcode/Writer/BitcodeWriterPass.cpp
SRCS_MIN+= Bitcode/Writer/ValueEnumerator.cpp
SRCS_MIN+= CodeGen/AggressiveAntiDepBreaker.cpp
SRCS_MIN+= CodeGen/AllocationOrder.cpp
SRCS_MIN+= CodeGen/Analysis.cpp
SRCS_MIN+= CodeGen/AsmPrinter/ARMException.cpp
SRCS_MIN+= CodeGen/AsmPrinter/AccelTable.cpp
SRCS_MIN+= CodeGen/AsmPrinter/AddressPool.cpp
SRCS_MIN+= CodeGen/AsmPrinter/AsmPrinter.cpp
SRCS_MIN+= CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
SRCS_MIN+= CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
SRCS_MIN+= CodeGen/AsmPrinter/CodeViewDebug.cpp
SRCS_MIN+= CodeGen/AsmPrinter/DIE.cpp
SRCS_MIN+= CodeGen/AsmPrinter/DIEHash.cpp
SRCS_MIN+= CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp
SRCS_MIN+= CodeGen/AsmPrinter/DebugHandlerBase.cpp
SRCS_MIN+= CodeGen/AsmPrinter/DebugLocStream.cpp
SRCS_MIN+= CodeGen/AsmPrinter/DwarfCFIException.cpp
SRCS_MIN+= CodeGen/AsmPrinter/DwarfCompileUnit.cpp
SRCS_MIN+= CodeGen/AsmPrinter/DwarfDebug.cpp
SRCS_MIN+= CodeGen/AsmPrinter/DwarfExpression.cpp
SRCS_MIN+= CodeGen/AsmPrinter/DwarfFile.cpp
SRCS_MIN+= CodeGen/AsmPrinter/DwarfStringPool.cpp
SRCS_MIN+= CodeGen/AsmPrinter/DwarfUnit.cpp
SRCS_MIN+= CodeGen/AsmPrinter/EHStreamer.cpp
SRCS_MIN+= CodeGen/AsmPrinter/ErlangGCPrinter.cpp
SRCS_MIN+= CodeGen/AsmPrinter/OcamlGCPrinter.cpp
SRCS_MIN+= CodeGen/AsmPrinter/WasmException.cpp
SRCS_MIN+= CodeGen/AsmPrinter/WinCFGuard.cpp
SRCS_MIN+= CodeGen/AsmPrinter/WinException.cpp
SRCS_MIN+= CodeGen/AtomicExpandPass.cpp
SRCS_MIN+= CodeGen/BasicTargetTransformInfo.cpp
SRCS_MIN+= CodeGen/BranchFolding.cpp
SRCS_MIN+= CodeGen/BranchRelaxation.cpp
SRCS_MIN+= CodeGen/BreakFalseDeps.cpp
SRCS_MIN+= CodeGen/BuiltinGCs.cpp
SRCS_MIN+= CodeGen/CFIInstrInserter.cpp
SRCS_MIN+= CodeGen/CalcSpillWeights.cpp
SRCS_MIN+= CodeGen/CallingConvLower.cpp
SRCS_MIN+= CodeGen/CodeGen.cpp
SRCS_MIN+= CodeGen/CodeGenPrepare.cpp
SRCS_MIN+= CodeGen/CriticalAntiDepBreaker.cpp
SRCS_MIN+= CodeGen/DFAPacketizer.cpp
SRCS_MIN+= CodeGen/DeadMachineInstructionElim.cpp
SRCS_MIN+= CodeGen/DetectDeadLanes.cpp
SRCS_MIN+= CodeGen/DwarfEHPrepare.cpp
SRCS_MIN+= CodeGen/EarlyIfConversion.cpp
SRCS_MIN+= CodeGen/EdgeBundles.cpp
SRCS_MIN+= CodeGen/ExecutionDomainFix.cpp
SRCS_MIN+= CodeGen/ExpandISelPseudos.cpp
SRCS_MIN+= CodeGen/ExpandMemCmp.cpp
SRCS_MIN+= CodeGen/ExpandPostRAPseudos.cpp
SRCS_MIN+= CodeGen/ExpandReductions.cpp
SRCS_MIN+= CodeGen/FEntryInserter.cpp
SRCS_MIN+= CodeGen/FaultMaps.cpp
SRCS_MIN+= CodeGen/FuncletLayout.cpp
SRCS_MIN+= CodeGen/GCMetadata.cpp
SRCS_MIN+= CodeGen/GCMetadataPrinter.cpp
SRCS_MIN+= CodeGen/GCRootLowering.cpp
SRCS_MIN+= CodeGen/GCStrategy.cpp
SRCS_MIN+= CodeGen/GlobalISel/CSEInfo.cpp
SRCS_MIN+= CodeGen/GlobalISel/CSEMIRBuilder.cpp
SRCS_MIN+= CodeGen/GlobalISel/Combiner.cpp
SRCS_MIN+= CodeGen/GlobalISel/CombinerHelper.cpp
SRCS_MIN+= CodeGen/GlobalISel/CallLowering.cpp
SRCS_MIN+= CodeGen/GlobalISel/GISelChangeObserver.cpp
SRCS_MIN+= CodeGen/GlobalISel/GlobalISel.cpp
SRCS_MIN+= CodeGen/GlobalISel/IRTranslator.cpp
SRCS_MIN+= CodeGen/GlobalISel/InstructionSelect.cpp
SRCS_MIN+= CodeGen/GlobalISel/InstructionSelector.cpp
SRCS_MIN+= CodeGen/GlobalISel/LegalityPredicates.cpp
SRCS_MIN+= CodeGen/GlobalISel/LegalizeMutations.cpp
SRCS_MIN+= CodeGen/GlobalISel/Legalizer.cpp
SRCS_MIN+= CodeGen/GlobalISel/LegalizerHelper.cpp
SRCS_MIN+= CodeGen/GlobalISel/LegalizerInfo.cpp
SRCS_MIN+= CodeGen/GlobalISel/Localizer.cpp
SRCS_MIN+= CodeGen/GlobalISel/MachineIRBuilder.cpp
SRCS_MIN+= CodeGen/GlobalISel/RegBankSelect.cpp
SRCS_MIN+= CodeGen/GlobalISel/RegisterBank.cpp
SRCS_MIN+= CodeGen/GlobalISel/RegisterBankInfo.cpp
SRCS_MIN+= CodeGen/GlobalISel/Utils.cpp
SRCS_MIN+= CodeGen/GlobalMerge.cpp
SRCS_MIN+= CodeGen/IfConversion.cpp
SRCS_MIN+= CodeGen/ImplicitNullChecks.cpp
SRCS_MIN+= CodeGen/IndirectBrExpandPass.cpp
SRCS_MIN+= CodeGen/InlineSpiller.cpp
SRCS_MIN+= CodeGen/InterferenceCache.cpp
SRCS_MIN+= CodeGen/InterleavedAccessPass.cpp
SRCS_MIN+= CodeGen/InterleavedLoadCombinePass.cpp
SRCS_MIN+= CodeGen/IntrinsicLowering.cpp
SRCS_MIN+= CodeGen/LLVMTargetMachine.cpp
SRCS_MIN+= CodeGen/LatencyPriorityQueue.cpp
SRCS_MIN+= CodeGen/LazyMachineBlockFrequencyInfo.cpp
SRCS_MIN+= CodeGen/LexicalScopes.cpp
SRCS_MIN+= CodeGen/LiveDebugValues.cpp
SRCS_MIN+= CodeGen/LiveDebugVariables.cpp
SRCS_MIN+= CodeGen/LiveInterval.cpp
SRCS_MIN+= CodeGen/LiveIntervalUnion.cpp
SRCS_MIN+= CodeGen/LiveIntervals.cpp
SRCS_MIN+= CodeGen/LivePhysRegs.cpp
SRCS_MIN+= CodeGen/LiveRangeCalc.cpp
SRCS_MIN+= CodeGen/LiveRangeEdit.cpp
SRCS_MIN+= CodeGen/LiveRangeShrink.cpp
SRCS_MIN+= CodeGen/LiveRegMatrix.cpp
SRCS_MIN+= CodeGen/LiveRegUnits.cpp
SRCS_MIN+= CodeGen/LiveStacks.cpp
SRCS_MIN+= CodeGen/LiveVariables.cpp
SRCS_MIN+= CodeGen/LocalStackSlotAllocation.cpp
SRCS_MIN+= CodeGen/LoopTraversal.cpp
SRCS_MIN+= CodeGen/LowLevelType.cpp
SRCS_MIN+= CodeGen/LowerEmuTLS.cpp
SRCS_MIN+= CodeGen/MIRCanonicalizerPass.cpp
SRCS_EXT+= CodeGen/MIRParser/MILexer.cpp
SRCS_EXT+= CodeGen/MIRParser/MIParser.cpp
SRCS_EXT+= CodeGen/MIRParser/MIRParser.cpp
SRCS_MIN+= CodeGen/MIRPrinter.cpp
SRCS_MIN+= CodeGen/MIRPrintingPass.cpp
SRCS_MIN+= CodeGen/MachineBasicBlock.cpp
SRCS_MIN+= CodeGen/MachineBlockFrequencyInfo.cpp
SRCS_MIN+= CodeGen/MachineBlockPlacement.cpp
SRCS_MIN+= CodeGen/MachineBranchProbabilityInfo.cpp
SRCS_MIN+= CodeGen/MachineCSE.cpp
SRCS_MIN+= CodeGen/MachineCombiner.cpp
SRCS_MIN+= CodeGen/MachineCopyPropagation.cpp
SRCS_MIN+= CodeGen/MachineDominanceFrontier.cpp
SRCS_MIN+= CodeGen/MachineDominators.cpp
SRCS_MIN+= CodeGen/MachineFrameInfo.cpp
SRCS_MIN+= CodeGen/MachineFunction.cpp
SRCS_MIN+= CodeGen/MachineFunctionPass.cpp
SRCS_MIN+= CodeGen/MachineFunctionPrinterPass.cpp
SRCS_MIN+= CodeGen/MachineInstr.cpp
SRCS_MIN+= CodeGen/MachineInstrBundle.cpp
SRCS_MIN+= CodeGen/MachineLICM.cpp
SRCS_MIN+= CodeGen/MachineLoopInfo.cpp
SRCS_MIN+= CodeGen/MachineModuleInfo.cpp
SRCS_MIN+= CodeGen/MachineModuleInfoImpls.cpp
SRCS_MIN+= CodeGen/MachineOperand.cpp
SRCS_MIN+= CodeGen/MachineOptimizationRemarkEmitter.cpp
SRCS_MIN+= CodeGen/MachineOutliner.cpp
SRCS_MIN+= CodeGen/MachinePipeliner.cpp
SRCS_MIN+= CodeGen/MachinePostDominators.cpp
SRCS_MIN+= CodeGen/MachineRegionInfo.cpp
SRCS_MIN+= CodeGen/MachineRegisterInfo.cpp
SRCS_MIN+= CodeGen/MachineSSAUpdater.cpp
SRCS_MIN+= CodeGen/MachineScheduler.cpp
SRCS_MIN+= CodeGen/MachineSink.cpp
SRCS_MIN+= CodeGen/MachineTraceMetrics.cpp
SRCS_MIN+= CodeGen/MachineVerifier.cpp
SRCS_MIN+= CodeGen/MacroFusion.cpp
SRCS_MIN+= CodeGen/OptimizePHIs.cpp
SRCS_MIN+= CodeGen/PHIElimination.cpp
SRCS_MIN+= CodeGen/PHIEliminationUtils.cpp
SRCS_MIN+= CodeGen/ParallelCG.cpp
SRCS_MIN+= CodeGen/PatchableFunction.cpp
SRCS_MIN+= CodeGen/PeepholeOptimizer.cpp
SRCS_MIN+= CodeGen/PostRAHazardRecognizer.cpp
SRCS_MIN+= CodeGen/PostRASchedulerList.cpp
SRCS_MIN+= CodeGen/PreISelIntrinsicLowering.cpp
SRCS_MIN+= CodeGen/ProcessImplicitDefs.cpp
SRCS_MIN+= CodeGen/PrologEpilogInserter.cpp
SRCS_MIN+= CodeGen/PseudoSourceValue.cpp
SRCS_MIN+= CodeGen/ReachingDefAnalysis.cpp
SRCS_MIN+= CodeGen/RegAllocBase.cpp
SRCS_MIN+= CodeGen/RegAllocBasic.cpp
SRCS_MIN+= CodeGen/RegAllocFast.cpp
SRCS_MIN+= CodeGen/RegAllocGreedy.cpp
SRCS_MIN+= CodeGen/RegAllocPBQP.cpp
SRCS_MIN+= CodeGen/RegUsageInfoCollector.cpp
SRCS_MIN+= CodeGen/RegUsageInfoPropagate.cpp
SRCS_MIN+= CodeGen/RegisterClassInfo.cpp
SRCS_MIN+= CodeGen/RegisterCoalescer.cpp
SRCS_MIN+= CodeGen/RegisterPressure.cpp
SRCS_MIN+= CodeGen/RegisterScavenging.cpp
SRCS_MIN+= CodeGen/RegisterUsageInfo.cpp
SRCS_MIN+= CodeGen/RenameIndependentSubregs.cpp
SRCS_MIN+= CodeGen/ResetMachineFunctionPass.cpp
SRCS_MIN+= CodeGen/SafeStack.cpp
SRCS_MIN+= CodeGen/SafeStackColoring.cpp
SRCS_MIN+= CodeGen/SafeStackLayout.cpp
SRCS_MIN+= CodeGen/ScalarizeMaskedMemIntrin.cpp
SRCS_MIN+= CodeGen/ScheduleDAG.cpp
SRCS_MIN+= CodeGen/ScheduleDAGInstrs.cpp
SRCS_MIN+= CodeGen/ScheduleDAGPrinter.cpp
SRCS_MIN+= CodeGen/ScoreboardHazardRecognizer.cpp
SRCS_MIN+= CodeGen/SelectionDAG/DAGCombiner.cpp
SRCS_MIN+= CodeGen/SelectionDAG/FastISel.cpp
SRCS_MIN+= CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
SRCS_MIN+= CodeGen/SelectionDAG/InstrEmitter.cpp
SRCS_MIN+= CodeGen/SelectionDAG/LegalizeDAG.cpp
SRCS_MIN+= CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
SRCS_MIN+= CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
SRCS_MIN+= CodeGen/SelectionDAG/LegalizeTypes.cpp
SRCS_MIN+= CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp
SRCS_MIN+= CodeGen/SelectionDAG/LegalizeVectorOps.cpp
SRCS_MIN+= CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
SRCS_MIN+= CodeGen/SelectionDAG/ResourcePriorityQueue.cpp
SRCS_MIN+= CodeGen/SelectionDAG/ScheduleDAGFast.cpp
SRCS_MIN+= CodeGen/SelectionDAG/ScheduleDAGRRList.cpp
SRCS_MIN+= CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp
SRCS_MIN+= CodeGen/SelectionDAG/ScheduleDAGVLIW.cpp
SRCS_MIN+= CodeGen/SelectionDAG/SelectionDAG.cpp
SRCS_MIN+= CodeGen/SelectionDAG/SelectionDAGAddressAnalysis.cpp
SRCS_MIN+= CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
SRCS_MIN+= CodeGen/SelectionDAG/SelectionDAGDumper.cpp
SRCS_MIN+= CodeGen/SelectionDAG/SelectionDAGISel.cpp
SRCS_MIN+= CodeGen/SelectionDAG/SelectionDAGPrinter.cpp
SRCS_MIN+= CodeGen/SelectionDAG/SelectionDAGTargetInfo.cpp
SRCS_MIN+= CodeGen/SelectionDAG/StatepointLowering.cpp
SRCS_MIN+= CodeGen/SelectionDAG/TargetLowering.cpp
SRCS_MIN+= CodeGen/ShadowStackGCLowering.cpp
SRCS_MIN+= CodeGen/ShrinkWrap.cpp
SRCS_MIN+= CodeGen/SjLjEHPrepare.cpp
SRCS_MIN+= CodeGen/SlotIndexes.cpp
SRCS_MIN+= CodeGen/SpillPlacement.cpp
SRCS_MIN+= CodeGen/SplitKit.cpp
SRCS_MIN+= CodeGen/StackColoring.cpp
SRCS_MIN+= CodeGen/StackMapLivenessAnalysis.cpp
SRCS_MIN+= CodeGen/StackMaps.cpp
SRCS_MIN+= CodeGen/StackProtector.cpp
SRCS_MIN+= CodeGen/StackSlotColoring.cpp
SRCS_MIN+= CodeGen/TailDuplication.cpp
SRCS_MIN+= CodeGen/TailDuplicator.cpp
SRCS_MIN+= CodeGen/TargetFrameLoweringImpl.cpp
SRCS_MIN+= CodeGen/TargetInstrInfo.cpp
SRCS_MIN+= CodeGen/TargetLoweringBase.cpp
SRCS_MIN+= CodeGen/TargetLoweringObjectFileImpl.cpp
SRCS_MIN+= CodeGen/TargetOptionsImpl.cpp
SRCS_MIN+= CodeGen/TargetPassConfig.cpp
SRCS_MIN+= CodeGen/TargetRegisterInfo.cpp
SRCS_MIN+= CodeGen/TargetSchedule.cpp
SRCS_MIN+= CodeGen/TargetSubtargetInfo.cpp
SRCS_MIN+= CodeGen/TwoAddressInstructionPass.cpp
SRCS_MIN+= CodeGen/UnreachableBlockElim.cpp
SRCS_MIN+= CodeGen/ValueTypes.cpp
SRCS_MIN+= CodeGen/VirtRegMap.cpp
SRCS_MIN+= CodeGen/WasmEHPrepare.cpp
SRCS_MIN+= CodeGen/WinEHPrepare.cpp
SRCS_MIN+= CodeGen/XRayInstrumentation.cpp
SRCS_EXT+= DebugInfo/CodeView/AppendingTypeTableBuilder.cpp
SRCS_MIN+= DebugInfo/CodeView/CVSymbolVisitor.cpp
SRCS_MIN+= DebugInfo/CodeView/CVTypeVisitor.cpp
SRCS_MIN+= DebugInfo/CodeView/CodeViewError.cpp
SRCS_MIN+= DebugInfo/CodeView/CodeViewRecordIO.cpp
SRCS_MIN+= DebugInfo/CodeView/ContinuationRecordBuilder.cpp
SRCS_EXT+= DebugInfo/CodeView/DebugChecksumsSubsection.cpp
SRCS_EXT+= DebugInfo/CodeView/DebugCrossExSubsection.cpp
SRCS_EXT+= DebugInfo/CodeView/DebugCrossImpSubsection.cpp
SRCS_EXT+= DebugInfo/CodeView/DebugFrameDataSubsection.cpp
SRCS_EXT+= DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp
SRCS_EXT+= DebugInfo/CodeView/DebugLinesSubsection.cpp
SRCS_EXT+= DebugInfo/CodeView/DebugStringTableSubsection.cpp
SRCS_EXT+= DebugInfo/CodeView/DebugSubsection.cpp
SRCS_EXT+= DebugInfo/CodeView/DebugSubsectionRecord.cpp
SRCS_EXT+= DebugInfo/CodeView/DebugSubsectionVisitor.cpp
SRCS_EXT+= DebugInfo/CodeView/DebugSymbolRVASubsection.cpp
SRCS_EXT+= DebugInfo/CodeView/DebugSymbolsSubsection.cpp
SRCS_MIN+= DebugInfo/CodeView/EnumTables.cpp
SRCS_MIN+= DebugInfo/CodeView/Formatters.cpp
SRCS_MIN+= DebugInfo/CodeView/GlobalTypeTableBuilder.cpp
SRCS_EXT+= DebugInfo/CodeView/LazyRandomTypeCollection.cpp
SRCS_MIN+= DebugInfo/CodeView/Line.cpp
SRCS_EXT+= DebugInfo/CodeView/MergingTypeTableBuilder.cpp
SRCS_MIN+= DebugInfo/CodeView/RecordName.cpp
SRCS_MIN+= DebugInfo/CodeView/RecordSerialization.cpp
SRCS_MIN+= DebugInfo/CodeView/SimpleTypeSerializer.cpp
SRCS_EXT+= DebugInfo/CodeView/StringsAndChecksums.cpp
SRCS_MIN+= DebugInfo/CodeView/SymbolDumper.cpp
SRCS_MIN+= DebugInfo/CodeView/SymbolRecordMapping.cpp
SRCS_EXT+= DebugInfo/CodeView/SymbolSerializer.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeDumpVisitor.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeHashing.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeIndex.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeIndexDiscovery.cpp
SRCS_EXT+= DebugInfo/CodeView/TypeRecordHelpers.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeRecordMapping.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeStreamMerger.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeTableCollection.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFAcceleratorTable.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFAddressRange.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFCompileUnit.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFContext.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDataExtractor.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDebugAbbrev.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDebugAddr.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDebugArangeSet.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDebugAranges.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDebugFrame.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDebugLine.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDebugLoc.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDebugMacro.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDebugPubTable.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDebugRangeList.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDebugRnglists.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFDie.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFExpression.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFFormValue.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFGdbIndex.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFListTable.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFTypeUnit.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFUnit.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFUnitIndex.cpp
SRCS_MIW+= DebugInfo/DWARF/DWARFVerifier.cpp
SRCS_MIN+= DebugInfo/MSF/MSFBuilder.cpp
SRCS_MIN+= DebugInfo/MSF/MSFCommon.cpp
SRCS_MIN+= DebugInfo/MSF/MSFError.cpp
SRCS_MIN+= DebugInfo/MSF/MappedBlockStream.cpp
SRCS_EXT+= DebugInfo/PDB/GenericError.cpp
SRCS_EXT+= DebugInfo/PDB/IPDBSourceFile.cpp
SRCS_EXT+= DebugInfo/PDB/Native/DbiModuleDescriptor.cpp
SRCS_EXT+= DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
SRCS_EXT+= DebugInfo/PDB/Native/DbiModuleList.cpp
SRCS_EXT+= DebugInfo/PDB/Native/DbiStream.cpp
SRCS_EXT+= DebugInfo/PDB/Native/DbiStreamBuilder.cpp
SRCS_EXT+= DebugInfo/PDB/Native/EnumTables.cpp
SRCS_EXT+= DebugInfo/PDB/Native/GSIStreamBuilder.cpp
SRCS_EXT+= DebugInfo/PDB/Native/GlobalsStream.cpp
SRCS_EXT+= DebugInfo/PDB/Native/Hash.cpp
SRCS_EXT+= DebugInfo/PDB/Native/HashTable.cpp
SRCS_EXT+= DebugInfo/PDB/Native/InfoStream.cpp
SRCS_EXT+= DebugInfo/PDB/Native/InfoStreamBuilder.cpp
SRCS_EXT+= DebugInfo/PDB/Native/ModuleDebugStream.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NamedStreamMap.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeCompilandSymbol.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeEnumGlobals.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeEnumModules.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeEnumTypes.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeExeSymbol.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeRawSymbol.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeSession.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeTypeArray.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeTypeBuiltin.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeTypeEnum.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeTypePointer.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeTypeTypedef.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeTypeUDT.cpp
SRCS_EXT+= DebugInfo/PDB/Native/NativeTypeVTShape.cpp
SRCS_EXT+= DebugInfo/PDB/Native/PDBFile.cpp
SRCS_EXT+= DebugInfo/PDB/Native/PDBFileBuilder.cpp
SRCS_EXT+= DebugInfo/PDB/Native/PDBStringTable.cpp
SRCS_EXT+= DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
SRCS_EXT+= DebugInfo/PDB/Native/PublicsStream.cpp
SRCS_EXT+= DebugInfo/PDB/Native/RawError.cpp
SRCS_EXT+= DebugInfo/PDB/Native/SymbolCache.cpp
SRCS_EXT+= DebugInfo/PDB/Native/SymbolStream.cpp
SRCS_EXT+= DebugInfo/PDB/Native/TpiHashing.cpp
SRCS_EXT+= DebugInfo/PDB/Native/TpiStream.cpp
SRCS_EXT+= DebugInfo/PDB/Native/TpiStreamBuilder.cpp
SRCS_EXT+= DebugInfo/PDB/PDB.cpp
SRCS_EXT+= DebugInfo/PDB/PDBContext.cpp
SRCS_EXT+= DebugInfo/PDB/PDBExtras.cpp
SRCS_EXT+= DebugInfo/PDB/PDBInterfaceAnchors.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymDumper.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbol.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolAnnotation.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolBlock.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolCompiland.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolCompilandDetails.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolCompilandEnv.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolCustom.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolData.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolExe.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolFunc.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolLabel.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolPublicSymbol.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolThunk.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeArray.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeCustom.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeDimension.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeEnum.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeFriend.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeManaged.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypePointer.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeTypedef.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeUDT.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeVTable.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolUnknown.cpp
SRCS_EXT+= DebugInfo/PDB/PDBSymbolUsingNamespace.cpp
SRCS_EXT+= DebugInfo/PDB/UDTLayout.cpp
-SRCS_EXT+= DebugInfo/Symbolize/DIPrinter.cpp
+SRCS_MIW+= DebugInfo/Symbolize/DIPrinter.cpp
SRCS_MIW+= DebugInfo/Symbolize/SymbolizableObjectFile.cpp
SRCS_MIW+= DebugInfo/Symbolize/Symbolize.cpp
SRCS_MIN+= Demangle/ItaniumDemangle.cpp
SRCS_MIW+= Demangle/MicrosoftDemangle.cpp
SRCS_MIW+= Demangle/MicrosoftDemangleNodes.cpp
SRCS_XDB+= ExecutionEngine/ExecutionEngine.cpp
SRCS_XDB+= ExecutionEngine/ExecutionEngineBindings.cpp
SRCS_XDB+= ExecutionEngine/GDBRegistrationListener.cpp
SRCS_XDB+= ExecutionEngine/Interpreter/Execution.cpp
SRCS_XDB+= ExecutionEngine/Interpreter/ExternalFunctions.cpp
SRCS_XDB+= ExecutionEngine/Interpreter/Interpreter.cpp
SRCS_XDB+= ExecutionEngine/MCJIT/MCJIT.cpp
SRCS_EXT+= ExecutionEngine/Orc/CompileOnDemandLayer.cpp
SRCS_EXT+= ExecutionEngine/Orc/Core.cpp
SRCS_EXT+= ExecutionEngine/Orc/ExecutionUtils.cpp
SRCS_EXT+= ExecutionEngine/Orc/IRCompileLayer.cpp
SRCS_EXT+= ExecutionEngine/Orc/IRTransformLayer.cpp
SRCS_EXT+= ExecutionEngine/Orc/IndirectionUtils.cpp
SRCS_EXT+= ExecutionEngine/Orc/JITTargetMachineBuilder.cpp
SRCS_EXT+= ExecutionEngine/Orc/LLJIT.cpp
SRCS_EXT+= ExecutionEngine/Orc/Layer.cpp
SRCS_EXT+= ExecutionEngine/Orc/LazyReexports.cpp
SRCS_EXT+= ExecutionEngine/Orc/Legacy.cpp
SRCS_EXT+= ExecutionEngine/Orc/NullResolver.cpp
SRCS_EXT+= ExecutionEngine/Orc/OrcABISupport.cpp
SRCS_EXT+= ExecutionEngine/Orc/OrcCBindings.cpp
SRCS_EXT+= ExecutionEngine/Orc/OrcError.cpp
SRCS_EXT+= ExecutionEngine/Orc/OrcMCJITReplacement.cpp
SRCS_EXT+= ExecutionEngine/Orc/RPCUtils.cpp
SRCS_EXT+= ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp
SRCS_EXT+= ExecutionEngine/Orc/ThreadSafeModule.cpp
SRCS_XDB+= ExecutionEngine/RuntimeDyld/JITSymbol.cpp
SRCS_XDB+= ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp
SRCS_XDB+= ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
SRCS_XDB+= ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp
SRCS_XDB+= ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
SRCS_XDB+= ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
SRCS_XDB+= ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
SRCS_XDB+= ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldELFMips.cpp
SRCS_XDB+= ExecutionEngine/SectionMemoryManager.cpp
SRCS_XDB+= ExecutionEngine/TargetSelect.cpp
SRCS_MIN+= IR/AsmWriter.cpp
SRCS_MIN+= IR/Attributes.cpp
SRCS_MIN+= IR/AutoUpgrade.cpp
SRCS_MIN+= IR/BasicBlock.cpp
SRCS_MIN+= IR/Comdat.cpp
SRCS_MIN+= IR/ConstantFold.cpp
SRCS_MIN+= IR/ConstantRange.cpp
SRCS_MIN+= IR/Constants.cpp
SRCS_MIN+= IR/Core.cpp
SRCS_MIN+= IR/DIBuilder.cpp
SRCS_MIN+= IR/DataLayout.cpp
SRCS_MIN+= IR/DebugInfo.cpp
SRCS_MIN+= IR/DebugInfoMetadata.cpp
SRCS_MIN+= IR/DebugLoc.cpp
SRCS_MIN+= IR/DiagnosticHandler.cpp
SRCS_MIN+= IR/DiagnosticInfo.cpp
SRCS_MIN+= IR/DiagnosticPrinter.cpp
SRCS_MIN+= IR/DomTreeUpdater.cpp
SRCS_MIN+= IR/Dominators.cpp
SRCS_MIN+= IR/Function.cpp
SRCS_MIN+= IR/GVMaterializer.cpp
SRCS_MIN+= IR/Globals.cpp
SRCS_MIN+= IR/IRBuilder.cpp
SRCS_MIN+= IR/IRPrintingPasses.cpp
SRCS_MIN+= IR/InlineAsm.cpp
SRCS_MIN+= IR/Instruction.cpp
SRCS_MIN+= IR/Instructions.cpp
SRCS_MIN+= IR/IntrinsicInst.cpp
SRCS_MIN+= IR/LLVMContext.cpp
SRCS_MIN+= IR/LLVMContextImpl.cpp
SRCS_MIN+= IR/LegacyPassManager.cpp
SRCS_MIN+= IR/MDBuilder.cpp
SRCS_MIN+= IR/Mangler.cpp
SRCS_MIN+= IR/Metadata.cpp
SRCS_MIN+= IR/Module.cpp
SRCS_MIN+= IR/ModuleSummaryIndex.cpp
SRCS_MIN+= IR/Operator.cpp
SRCS_MIN+= IR/OptBisect.cpp
SRCS_MIN+= IR/Pass.cpp
SRCS_MIN+= IR/PassInstrumentation.cpp
SRCS_MIN+= IR/PassManager.cpp
SRCS_MIN+= IR/PassRegistry.cpp
SRCS_MIN+= IR/PassTimingInfo.cpp
SRCS_MIN+= IR/ProfileSummary.cpp
SRCS_MIN+= IR/SafepointIRVerifier.cpp
SRCS_MIN+= IR/Statepoint.cpp
SRCS_MIN+= IR/Type.cpp
SRCS_MIN+= IR/TypeFinder.cpp
SRCS_MIN+= IR/Use.cpp
SRCS_MIN+= IR/User.cpp
SRCS_MIN+= IR/Value.cpp
SRCS_MIN+= IR/ValueSymbolTable.cpp
SRCS_MIN+= IR/Verifier.cpp
SRCS_MIN+= IRReader/IRReader.cpp
SRCS_EXL+= LTO/Caching.cpp
SRCS_MIN+= LTO/LTO.cpp
SRCS_MIN+= LTO/LTOBackend.cpp
SRCS_EXL+= LTO/LTOCodeGenerator.cpp
SRCS_EXL+= LTO/LTOModule.cpp
SRCS_EXL+= LTO/SummaryBasedOptimizations.cpp
SRCS_EXL+= LTO/ThinLTOCodeGenerator.cpp
SRCS_MIN+= LTO/UpdateCompilerUsed.cpp
SRCS_MIN+= LineEditor/LineEditor.cpp
SRCS_MIN+= Linker/IRMover.cpp
SRCS_MIN+= Linker/LinkModules.cpp
SRCS_MIN+= MC/ConstantPools.cpp
SRCS_MIN+= MC/ELFObjectWriter.cpp
SRCS_MIN+= MC/MCAsmBackend.cpp
SRCS_MIN+= MC/MCAsmInfo.cpp
SRCS_MIN+= MC/MCAsmInfoCOFF.cpp
SRCS_MIN+= MC/MCAsmInfoDarwin.cpp
SRCS_MIN+= MC/MCAsmInfoELF.cpp
SRCS_MIN+= MC/MCAsmMacro.cpp
SRCS_MIN+= MC/MCAsmStreamer.cpp
SRCS_MIN+= MC/MCAssembler.cpp
SRCS_MIN+= MC/MCCodeEmitter.cpp
SRCS_MIN+= MC/MCCodePadder.cpp
SRCS_MIN+= MC/MCCodeView.cpp
SRCS_MIN+= MC/MCContext.cpp
SRCS_XDL+= MC/MCDisassembler/Disassembler.cpp
SRCS_XDW+= MC/MCDisassembler/MCDisassembler.cpp
SRCS_XDW+= MC/MCDisassembler/MCExternalSymbolizer.cpp
SRCS_MIN+= MC/MCDisassembler/MCRelocationInfo.cpp
SRCS_XDW+= MC/MCDisassembler/MCSymbolizer.cpp
SRCS_MIN+= MC/MCDwarf.cpp
SRCS_MIN+= MC/MCELFObjectTargetWriter.cpp
SRCS_MIN+= MC/MCELFStreamer.cpp
SRCS_MIN+= MC/MCExpr.cpp
SRCS_MIN+= MC/MCFragment.cpp
SRCS_MIN+= MC/MCInst.cpp
SRCS_MIN+= MC/MCInstPrinter.cpp
SRCS_MIN+= MC/MCInstrAnalysis.cpp
SRCS_MIN+= MC/MCInstrDesc.cpp
SRCS_MIN+= MC/MCLinkerOptimizationHint.cpp
SRCS_MIN+= MC/MCMachOStreamer.cpp
SRCS_MIN+= MC/MCMachObjectTargetWriter.cpp
SRCS_MIN+= MC/MCNullStreamer.cpp
SRCS_MIN+= MC/MCObjectFileInfo.cpp
SRCS_MIN+= MC/MCObjectStreamer.cpp
SRCS_MIN+= MC/MCObjectWriter.cpp
SRCS_MIN+= MC/MCParser/AsmLexer.cpp
SRCS_MIN+= MC/MCParser/AsmParser.cpp
SRCS_MIN+= MC/MCParser/COFFAsmParser.cpp
SRCS_MIN+= MC/MCParser/DarwinAsmParser.cpp
SRCS_MIN+= MC/MCParser/ELFAsmParser.cpp
SRCS_MIN+= MC/MCParser/MCAsmLexer.cpp
SRCS_MIN+= MC/MCParser/MCAsmParser.cpp
SRCS_MIN+= MC/MCParser/MCAsmParserExtension.cpp
SRCS_MIN+= MC/MCParser/MCTargetAsmParser.cpp
SRCS_MIN+= MC/MCParser/WasmAsmParser.cpp
SRCS_MIN+= MC/MCRegisterInfo.cpp
SRCS_MIN+= MC/MCSchedule.cpp
SRCS_MIN+= MC/MCSection.cpp
SRCS_MIN+= MC/MCSectionCOFF.cpp
SRCS_MIN+= MC/MCSectionELF.cpp
SRCS_MIN+= MC/MCSectionMachO.cpp
SRCS_MIN+= MC/MCSectionWasm.cpp
SRCS_MIN+= MC/MCStreamer.cpp
SRCS_MIN+= MC/MCSubtargetInfo.cpp
SRCS_MIN+= MC/MCSymbol.cpp
SRCS_MIN+= MC/MCSymbolELF.cpp
SRCS_MIN+= MC/MCTargetOptions.cpp
SRCS_MIN+= MC/MCValue.cpp
SRCS_MIN+= MC/MCWasmStreamer.cpp
SRCS_MIN+= MC/MCWin64EH.cpp
SRCS_MIN+= MC/MCWinCOFFStreamer.cpp
SRCS_MIN+= MC/MCWinEH.cpp
SRCS_MIN+= MC/MachObjectWriter.cpp
SRCS_MIN+= MC/StringTableBuilder.cpp
SRCS_MIN+= MC/SubtargetFeature.cpp
SRCS_MIN+= MC/WasmObjectWriter.cpp
SRCS_MIN+= MC/WinCOFFObjectWriter.cpp
SRCS_EXT+= MCA/Context.cpp
SRCS_EXT+= MCA/HWEventListener.cpp
SRCS_EXT+= MCA/HardwareUnits/HardwareUnit.cpp
SRCS_EXT+= MCA/HardwareUnits/LSUnit.cpp
SRCS_EXT+= MCA/HardwareUnits/RegisterFile.cpp
SRCS_EXT+= MCA/HardwareUnits/ResourceManager.cpp
SRCS_EXT+= MCA/HardwareUnits/RetireControlUnit.cpp
SRCS_EXT+= MCA/HardwareUnits/Scheduler.cpp
SRCS_EXT+= MCA/InstrBuilder.cpp
SRCS_EXT+= MCA/Instruction.cpp
SRCS_EXT+= MCA/Pipeline.cpp
SRCS_EXT+= MCA/Stages/DispatchStage.cpp
SRCS_EXT+= MCA/Stages/EntryStage.cpp
SRCS_EXT+= MCA/Stages/ExecuteStage.cpp
SRCS_EXT+= MCA/Stages/InstructionTables.cpp
SRCS_EXT+= MCA/Stages/RetireStage.cpp
SRCS_EXT+= MCA/Stages/Stage.cpp
SRCS_EXT+= MCA/Support.cpp
SRCS_MIN+= Object/Archive.cpp
SRCS_MIN+= Object/ArchiveWriter.cpp
SRCS_MIN+= Object/Binary.cpp
SRCS_EXT+= Object/COFFImportFile.cpp
SRCS_EXT+= Object/COFFModuleDefinition.cpp
SRCS_MIN+= Object/COFFObjectFile.cpp
SRCS_MIN+= Object/Decompressor.cpp
SRCS_MIN+= Object/ELF.cpp
SRCS_MIN+= Object/ELFObjectFile.cpp
SRCS_MIN+= Object/Error.cpp
SRCS_MIN+= Object/IRObjectFile.cpp
SRCS_MIN+= Object/IRSymtab.cpp
SRCS_MIN+= Object/MachOObjectFile.cpp
SRCS_MIN+= Object/MachOUniversal.cpp
SRCS_MIN+= Object/ModuleSymbolTable.cpp
SRCS_EXT+= Object/Object.cpp
SRCS_MIN+= Object/ObjectFile.cpp
SRCS_MIN+= Object/RecordStreamer.cpp
SRCS_MIW+= Object/SymbolSize.cpp
SRCS_MIN+= Object/SymbolicFile.cpp
SRCS_MIN+= Object/WasmObjectFile.cpp
SRCS_MIN+= Object/WindowsResource.cpp
SRCS_MIN+= ObjectYAML/COFFYAML.cpp
SRCS_EXT+= ObjectYAML/CodeViewYAMLDebugSections.cpp
SRCS_EXT+= ObjectYAML/CodeViewYAMLSymbols.cpp
SRCS_EXT+= ObjectYAML/CodeViewYAMLTypes.cpp
SRCS_MIN+= ObjectYAML/DWARFYAML.cpp
SRCS_MIN+= ObjectYAML/ELFYAML.cpp
SRCS_MIN+= ObjectYAML/MachOYAML.cpp
SRCS_EXT+= ObjectYAML/YAML.cpp
SRCS_MIN+= Option/Arg.cpp
SRCS_MIN+= Option/ArgList.cpp
SRCS_MIN+= Option/OptTable.cpp
SRCS_MIN+= Option/Option.cpp
SRCS_MIN+= Passes/PassBuilder.cpp
SRCS_EXT+= Passes/PassPlugin.cpp
SRCS_EXT+= Passes/StandardInstrumentations.cpp
SRCS_MIN+= ProfileData/Coverage/CoverageMapping.cpp
SRCS_MIN+= ProfileData/Coverage/CoverageMappingReader.cpp
SRCS_MIN+= ProfileData/Coverage/CoverageMappingWriter.cpp
SRCS_MIN+= ProfileData/GCOV.cpp
SRCS_MIN+= ProfileData/InstrProf.cpp
SRCS_MIN+= ProfileData/InstrProfReader.cpp
SRCS_MIN+= ProfileData/InstrProfWriter.cpp
SRCS_MIN+= ProfileData/ProfileSummaryBuilder.cpp
SRCS_MIN+= ProfileData/SampleProf.cpp
SRCS_MIN+= ProfileData/SampleProfReader.cpp
SRCS_MIN+= ProfileData/SampleProfWriter.cpp
SRCS_MIN+= Support/AArch64TargetParser.cpp
SRCS_MIN+= Support/APFloat.cpp
SRCS_MIN+= Support/APInt.cpp
SRCS_MIN+= Support/APSInt.cpp
SRCS_MIN+= Support/ARMAttributeParser.cpp
SRCS_MIN+= Support/ARMBuildAttrs.cpp
SRCS_MIN+= Support/ARMTargetParser.cpp
SRCS_MIN+= Support/Allocator.cpp
SRCS_MIN+= Support/Atomic.cpp
SRCS_MIN+= Support/BinaryStreamError.cpp
SRCS_MIN+= Support/BinaryStreamReader.cpp
SRCS_MIN+= Support/BinaryStreamRef.cpp
SRCS_MIN+= Support/BinaryStreamWriter.cpp
SRCS_MIN+= Support/BlockFrequency.cpp
SRCS_MIN+= Support/BranchProbability.cpp
SRCS_MIN+= Support/BuryPointer.cpp
-SRCS_EXT+= Support/COM.cpp
+SRCS_MIW+= Support/COM.cpp
SRCS_MIN+= Support/CachePruning.cpp
SRCS_MIN+= Support/Chrono.cpp
SRCS_MIN+= Support/CodeGenCoverage.cpp
SRCS_MIN+= Support/CommandLine.cpp
SRCS_MIN+= Support/Compression.cpp
SRCS_MIN+= Support/ConvertUTF.cpp
SRCS_MIN+= Support/ConvertUTFWrapper.cpp
SRCS_MIN+= Support/CrashRecoveryContext.cpp
SRCS_MIN+= Support/DAGDeltaAlgorithm.cpp
SRCS_MIN+= Support/DJB.cpp
SRCS_MIN+= Support/DataExtractor.cpp
SRCS_MIN+= Support/Debug.cpp
SRCS_MIN+= Support/DebugCounter.cpp
SRCS_MIN+= Support/DeltaAlgorithm.cpp
SRCS_MIN+= Support/DynamicLibrary.cpp
SRCS_MIN+= Support/Errno.cpp
SRCS_MIN+= Support/Error.cpp
SRCS_MIN+= Support/ErrorHandling.cpp
SRCS_EXL+= Support/FileOutputBuffer.cpp
SRCS_EXT+= Support/FileUtilities.cpp
SRCS_MIN+= Support/FoldingSet.cpp
SRCS_MIN+= Support/FormatVariadic.cpp
SRCS_MIN+= Support/FormattedStream.cpp
SRCS_MIN+= Support/GlobPattern.cpp
SRCS_MIN+= Support/GraphWriter.cpp
SRCS_MIN+= Support/Hashing.cpp
SRCS_MIN+= Support/Host.cpp
SRCS_MIN+= Support/InitLLVM.cpp
SRCS_MIN+= Support/IntEqClasses.cpp
SRCS_MIN+= Support/IntervalMap.cpp
SRCS_MIN+= Support/ItaniumManglingCanonicalizer.cpp
SRCS_MIN+= Support/JSON.cpp
SRCS_MIN+= Support/JamCRC.cpp
SRCS_MIN+= Support/KnownBits.cpp
SRCS_MIN+= Support/LEB128.cpp
SRCS_MIN+= Support/LineIterator.cpp
SRCS_MIN+= Support/Locale.cpp
SRCS_MIN+= Support/LockFileManager.cpp
SRCS_MIN+= Support/LowLevelType.cpp
SRCS_MIN+= Support/MD5.cpp
SRCS_MIN+= Support/ManagedStatic.cpp
SRCS_MIN+= Support/MathExtras.cpp
SRCS_XDL+= Support/Memory.cpp
SRCS_MIN+= Support/MemoryBuffer.cpp
SRCS_MIN+= Support/Mutex.cpp
SRCS_MIN+= Support/NativeFormatting.cpp
SRCS_MIN+= Support/Options.cpp
SRCS_LLD+= Support/Parallel.cpp
SRCS_MIN+= Support/Path.cpp
SRCS_MIN+= Support/PluginLoader.cpp
SRCS_MIN+= Support/PrettyStackTrace.cpp
SRCS_MIN+= Support/Process.cpp
SRCS_MIN+= Support/Program.cpp
SRCS_MIN+= Support/RWMutex.cpp
SRCS_MIN+= Support/RandomNumberGenerator.cpp
SRCS_MIN+= Support/Regex.cpp
SRCS_MIN+= Support/SHA1.cpp
SRCS_MIN+= Support/ScaledNumber.cpp
SRCS_MIN+= Support/ScopedPrinter.cpp
SRCS_MIN+= Support/Signals.cpp
SRCS_MIN+= Support/SmallPtrSet.cpp
SRCS_MIN+= Support/SmallVector.cpp
SRCS_MIN+= Support/SourceMgr.cpp
SRCS_MIN+= Support/SpecialCaseList.cpp
SRCS_MIN+= Support/Statistic.cpp
SRCS_MIN+= Support/StringExtras.cpp
SRCS_MIN+= Support/StringMap.cpp
SRCS_MIN+= Support/StringRef.cpp
SRCS_MIN+= Support/StringSaver.cpp
SRCS_MIN+= Support/SymbolRemappingReader.cpp
SRCS_EXT+= Support/SystemUtils.cpp
SRCS_LLD+= Support/TarWriter.cpp
SRCS_MIN+= Support/TargetParser.cpp
SRCS_MIN+= Support/TargetRegistry.cpp
SRCS_MIN+= Support/ThreadLocal.cpp
SRCS_MIN+= Support/ThreadPool.cpp
SRCS_MIN+= Support/Threading.cpp
SRCS_MIN+= Support/Timer.cpp
SRCS_MIN+= Support/ToolOutputFile.cpp
SRCS_MIN+= Support/TrigramIndex.cpp
SRCS_MIN+= Support/Triple.cpp
SRCS_MIN+= Support/Twine.cpp
SRCS_MIN+= Support/Unicode.cpp
SRCS_MIN+= Support/UnicodeCaseFold.cpp
SRCS_MIN+= Support/Valgrind.cpp
SRCS_MIN+= Support/VirtualFileSystem.cpp
SRCS_MIN+= Support/VersionTuple.cpp
SRCS_MIN+= Support/WithColor.cpp
SRCS_MIN+= Support/YAMLParser.cpp
SRCS_MIN+= Support/YAMLTraits.cpp
SRCS_MIN+= Support/circular_raw_ostream.cpp
SRCS_MIN+= Support/raw_os_ostream.cpp
SRCS_MIN+= Support/raw_ostream.cpp
SRCS_MIN+= Support/regcomp.c
SRCS_MIN+= Support/regerror.c
SRCS_MIN+= Support/regexec.c
SRCS_MIN+= Support/regfree.c
SRCS_MIN+= Support/regstrlcpy.c
SRCS_MIN+= Support/xxhash.cpp
SRCS_MIN+= TableGen/Error.cpp
SRCS_MIN+= TableGen/JSONBackend.cpp
SRCS_MIN+= TableGen/Main.cpp
SRCS_MIN+= TableGen/Record.cpp
SRCS_MIN+= TableGen/SetTheory.cpp
SRCS_MIN+= TableGen/StringMatcher.cpp
SRCS_MIN+= TableGen/TGLexer.cpp
SRCS_MIN+= TableGen/TGParser.cpp
SRCS_MIN+= TableGen/TableGenBackend.cpp
.if ${MK_LLVM_TARGET_AARCH64} != "no"
SRCS_MIN+= Target/AArch64/AArch64A53Fix835769.cpp
SRCS_MIN+= Target/AArch64/AArch64A57FPLoadBalancing.cpp
SRCS_MIN+= Target/AArch64/AArch64AdvSIMDScalarPass.cpp
SRCS_MIN+= Target/AArch64/AArch64AsmPrinter.cpp
SRCS_MIN+= Target/AArch64/AArch64BranchTargets.cpp
SRCS_MIN+= Target/AArch64/AArch64CallLowering.cpp
SRCS_MIN+= Target/AArch64/AArch64CleanupLocalDynamicTLSPass.cpp
SRCS_MIN+= Target/AArch64/AArch64CollectLOH.cpp
SRCS_MIN+= Target/AArch64/AArch64CompressJumpTables.cpp
SRCS_MIN+= Target/AArch64/AArch64CondBrTuning.cpp
SRCS_MIN+= Target/AArch64/AArch64ConditionOptimizer.cpp
SRCS_MIN+= Target/AArch64/AArch64ConditionalCompares.cpp
SRCS_MIN+= Target/AArch64/AArch64DeadRegisterDefinitionsPass.cpp
SRCS_MIN+= Target/AArch64/AArch64ExpandPseudoInsts.cpp
SRCS_MIN+= Target/AArch64/AArch64FalkorHWPFFix.cpp
SRCS_MIN+= Target/AArch64/AArch64FastISel.cpp
SRCS_MIN+= Target/AArch64/AArch64FrameLowering.cpp
SRCS_MIN+= Target/AArch64/AArch64ISelDAGToDAG.cpp
SRCS_MIN+= Target/AArch64/AArch64ISelLowering.cpp
SRCS_MIN+= Target/AArch64/AArch64InstrInfo.cpp
SRCS_MIN+= Target/AArch64/AArch64InstructionSelector.cpp
SRCS_MIN+= Target/AArch64/AArch64LegalizerInfo.cpp
SRCS_MIN+= Target/AArch64/AArch64LoadStoreOptimizer.cpp
SRCS_MIN+= Target/AArch64/AArch64MCInstLower.cpp
SRCS_MIN+= Target/AArch64/AArch64MacroFusion.cpp
SRCS_MIN+= Target/AArch64/AArch64PBQPRegAlloc.cpp
SRCS_MIN+= Target/AArch64/AArch64PreLegalizerCombiner.cpp
SRCS_MIN+= Target/AArch64/AArch64PromoteConstant.cpp
SRCS_MIN+= Target/AArch64/AArch64RedundantCopyElimination.cpp
SRCS_MIN+= Target/AArch64/AArch64RegisterBankInfo.cpp
SRCS_MIN+= Target/AArch64/AArch64RegisterInfo.cpp
SRCS_MIN+= Target/AArch64/AArch64SIMDInstrOpt.cpp
SRCS_MIN+= Target/AArch64/AArch64SelectionDAGInfo.cpp
SRCS_MIN+= Target/AArch64/AArch64SpeculationHardening.cpp
SRCS_MIN+= Target/AArch64/AArch64StorePairSuppress.cpp
SRCS_MIN+= Target/AArch64/AArch64Subtarget.cpp
SRCS_MIN+= Target/AArch64/AArch64TargetMachine.cpp
SRCS_MIN+= Target/AArch64/AArch64TargetObjectFile.cpp
SRCS_MIN+= Target/AArch64/AArch64TargetTransformInfo.cpp
SRCS_MIN+= Target/AArch64/AsmParser/AArch64AsmParser.cpp
SRCS_XDW+= Target/AArch64/Disassembler/AArch64Disassembler.cpp
SRCS_XDW+= Target/AArch64/Disassembler/AArch64ExternalSymbolizer.cpp
SRCS_MIN+= Target/AArch64/InstPrinter/AArch64InstPrinter.cpp
SRCS_MIN+= Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
SRCS_MIN+= Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
SRCS_MIN+= Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
SRCS_MIN+= Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
SRCS_MIN+= Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
SRCS_MIN+= Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp
SRCS_MIN+= Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp
SRCS_MIN+= Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp
SRCS_MIN+= Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
SRCS_MIN+= Target/AArch64/MCTargetDesc/AArch64WinCOFFObjectWriter.cpp
SRCS_MIN+= Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp
SRCS_MIN+= Target/AArch64/TargetInfo/AArch64TargetInfo.cpp
SRCS_MIN+= Target/AArch64/Utils/AArch64BaseInfo.cpp
.endif # MK_LLVM_TARGET_AARCH64
.if ${MK_LLVM_TARGET_ARM} != "no"
SRCS_MIN+= Target/ARM/A15SDOptimizer.cpp
SRCS_MIN+= Target/ARM/ARMAsmPrinter.cpp
SRCS_MIN+= Target/ARM/ARMBaseInstrInfo.cpp
SRCS_MIN+= Target/ARM/ARMBaseRegisterInfo.cpp
SRCS_MIN+= Target/ARM/ARMCallLowering.cpp
SRCS_MIN+= Target/ARM/ARMCodeGenPrepare.cpp
SRCS_MIN+= Target/ARM/ARMComputeBlockSize.cpp
SRCS_MIN+= Target/ARM/ARMConstantIslandPass.cpp
SRCS_MIN+= Target/ARM/ARMConstantPoolValue.cpp
SRCS_MIN+= Target/ARM/ARMExpandPseudoInsts.cpp
SRCS_MIN+= Target/ARM/ARMFastISel.cpp
SRCS_MIN+= Target/ARM/ARMFrameLowering.cpp
SRCS_MIN+= Target/ARM/ARMHazardRecognizer.cpp
SRCS_MIN+= Target/ARM/ARMISelDAGToDAG.cpp
SRCS_MIN+= Target/ARM/ARMISelLowering.cpp
SRCS_MIN+= Target/ARM/ARMInstrInfo.cpp
SRCS_MIN+= Target/ARM/ARMInstructionSelector.cpp
SRCS_MIN+= Target/ARM/ARMLegalizerInfo.cpp
SRCS_MIN+= Target/ARM/ARMLoadStoreOptimizer.cpp
SRCS_MIN+= Target/ARM/ARMMCInstLower.cpp
SRCS_MIN+= Target/ARM/ARMMachineFunctionInfo.cpp
SRCS_MIN+= Target/ARM/ARMMacroFusion.cpp
SRCS_MIN+= Target/ARM/ARMOptimizeBarriersPass.cpp
SRCS_MIN+= Target/ARM/ARMParallelDSP.cpp
SRCS_MIN+= Target/ARM/ARMRegisterBankInfo.cpp
SRCS_MIN+= Target/ARM/ARMRegisterInfo.cpp
SRCS_MIN+= Target/ARM/ARMSelectionDAGInfo.cpp
SRCS_MIN+= Target/ARM/ARMSubtarget.cpp
SRCS_MIN+= Target/ARM/ARMTargetMachine.cpp
SRCS_MIN+= Target/ARM/ARMTargetObjectFile.cpp
SRCS_MIN+= Target/ARM/ARMTargetTransformInfo.cpp
SRCS_MIN+= Target/ARM/AsmParser/ARMAsmParser.cpp
SRCS_MIN+= Target/ARM/Disassembler/ARMDisassembler.cpp
SRCS_MIN+= Target/ARM/InstPrinter/ARMInstPrinter.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMMCExpr.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMMachORelocationInfo.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp
SRCS_MIN+= Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp
SRCS_MIN+= Target/ARM/MLxExpansionPass.cpp
SRCS_MIN+= Target/ARM/TargetInfo/ARMTargetInfo.cpp
SRCS_MIN+= Target/ARM/Thumb1FrameLowering.cpp
SRCS_MIN+= Target/ARM/Thumb1InstrInfo.cpp
SRCS_MIN+= Target/ARM/Thumb2ITBlockPass.cpp
SRCS_MIN+= Target/ARM/Thumb2InstrInfo.cpp
SRCS_MIN+= Target/ARM/Thumb2SizeReduction.cpp
SRCS_MIN+= Target/ARM/ThumbRegisterInfo.cpp
SRCS_MIN+= Target/ARM/Utils/ARMBaseInfo.cpp
.endif # MK_LLVM_TARGET_ARM
.if ${MK_LLVM_TARGET_BPF} != "no"
SRCS_MIN+= Target/BPF/AsmParser/BPFAsmParser.cpp
SRCS_MIN+= Target/BPF/BPFAsmPrinter.cpp
SRCS_MIN+= Target/BPF/BPFFrameLowering.cpp
SRCS_MIN+= Target/BPF/BPFISelDAGToDAG.cpp
SRCS_MIN+= Target/BPF/BPFISelLowering.cpp
SRCS_MIN+= Target/BPF/BPFInstrInfo.cpp
SRCS_MIN+= Target/BPF/BPFMCInstLower.cpp
SRCS_MIN+= Target/BPF/BPFMIChecking.cpp
SRCS_MIN+= Target/BPF/BPFMIPeephole.cpp
SRCS_MIN+= Target/BPF/BPFRegisterInfo.cpp
SRCS_MIN+= Target/BPF/BPFSelectionDAGInfo.cpp
SRCS_MIN+= Target/BPF/BPFSubtarget.cpp
SRCS_MIN+= Target/BPF/BPFTargetMachine.cpp
SRCS_MIN+= Target/BPF/BTFDebug.cpp
SRCS_MIN+= Target/BPF/Disassembler/BPFDisassembler.cpp
SRCS_MIN+= Target/BPF/InstPrinter/BPFInstPrinter.cpp
SRCS_MIN+= Target/BPF/MCTargetDesc/BPFAsmBackend.cpp
SRCS_MIN+= Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp
SRCS_MIN+= Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
SRCS_MIN+= Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp
SRCS_MIN+= Target/BPF/TargetInfo/BPFTargetInfo.cpp
.endif # MK_LLVM_TARGET_BPF
.if ${MK_LLVM_TARGET_MIPS} != "no"
SRCS_MIN+= Target/Mips/AsmParser/MipsAsmParser.cpp
SRCS_XDW+= Target/Mips/Disassembler/MipsDisassembler.cpp
SRCS_MIN+= Target/Mips/InstPrinter/MipsInstPrinter.cpp
SRCS_MIN+= Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp
SRCS_MIN+= Target/Mips/MCTargetDesc/MipsABIInfo.cpp
SRCS_MIN+= Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
SRCS_MIN+= Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
SRCS_MIN+= Target/Mips/MCTargetDesc/MipsELFStreamer.cpp
SRCS_MIN+= Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
SRCS_MIN+= Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
SRCS_MIN+= Target/Mips/MCTargetDesc/MipsMCExpr.cpp
SRCS_MIN+= Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
SRCS_MIN+= Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp
SRCS_MIN+= Target/Mips/MCTargetDesc/MipsOptionRecord.cpp
SRCS_MIN+= Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
SRCS_MIN+= Target/Mips/MicroMipsSizeReduction.cpp
SRCS_MIN+= Target/Mips/Mips16FrameLowering.cpp
SRCS_MIN+= Target/Mips/Mips16HardFloat.cpp
SRCS_MIN+= Target/Mips/Mips16HardFloatInfo.cpp
SRCS_MIN+= Target/Mips/Mips16ISelDAGToDAG.cpp
SRCS_MIN+= Target/Mips/Mips16ISelLowering.cpp
SRCS_MIN+= Target/Mips/Mips16InstrInfo.cpp
SRCS_MIN+= Target/Mips/Mips16RegisterInfo.cpp
SRCS_MIN+= Target/Mips/MipsAnalyzeImmediate.cpp
SRCS_MIN+= Target/Mips/MipsAsmPrinter.cpp
SRCS_MIN+= Target/Mips/MipsBranchExpansion.cpp
SRCS_MIN+= Target/Mips/MipsCCState.cpp
SRCS_MIN+= Target/Mips/MipsCallLowering.cpp
SRCS_MIN+= Target/Mips/MipsConstantIslandPass.cpp
SRCS_MIN+= Target/Mips/MipsDelaySlotFiller.cpp
SRCS_MIN+= Target/Mips/MipsExpandPseudo.cpp
SRCS_MIN+= Target/Mips/MipsFastISel.cpp
SRCS_MIN+= Target/Mips/MipsFrameLowering.cpp
SRCS_MIN+= Target/Mips/MipsISelDAGToDAG.cpp
SRCS_MIN+= Target/Mips/MipsISelLowering.cpp
SRCS_MIN+= Target/Mips/MipsInstrInfo.cpp
SRCS_MIN+= Target/Mips/MipsInstructionSelector.cpp
SRCS_MIN+= Target/Mips/MipsLegalizerInfo.cpp
SRCS_MIN+= Target/Mips/MipsMCInstLower.cpp
SRCS_MIN+= Target/Mips/MipsMachineFunction.cpp
SRCS_MIN+= Target/Mips/MipsModuleISelDAGToDAG.cpp
SRCS_MIN+= Target/Mips/MipsOptimizePICCall.cpp
SRCS_MIN+= Target/Mips/MipsOs16.cpp
SRCS_MIN+= Target/Mips/MipsPreLegalizerCombiner.cpp
SRCS_MIN+= Target/Mips/MipsRegisterBankInfo.cpp
SRCS_MIN+= Target/Mips/MipsRegisterInfo.cpp
SRCS_MIN+= Target/Mips/MipsSEFrameLowering.cpp
SRCS_MIN+= Target/Mips/MipsSEISelDAGToDAG.cpp
SRCS_MIN+= Target/Mips/MipsSEISelLowering.cpp
SRCS_MIN+= Target/Mips/MipsSEInstrInfo.cpp
SRCS_MIN+= Target/Mips/MipsSERegisterInfo.cpp
SRCS_MIN+= Target/Mips/MipsSubtarget.cpp
SRCS_MIN+= Target/Mips/MipsTargetMachine.cpp
SRCS_MIN+= Target/Mips/MipsTargetObjectFile.cpp
SRCS_MIN+= Target/Mips/TargetInfo/MipsTargetInfo.cpp
.endif # MK_LLVM_TARGET_MIPS
.if ${MK_LLVM_TARGET_POWERPC} != "no"
SRCS_MIN+= Target/PowerPC/AsmParser/PPCAsmParser.cpp
SRCS_MIN+= Target/PowerPC/Disassembler/PPCDisassembler.cpp
SRCS_MIN+= Target/PowerPC/InstPrinter/PPCInstPrinter.cpp
SRCS_MIN+= Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
SRCS_MIN+= Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
SRCS_MIN+= Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp
SRCS_MIN+= Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
SRCS_MIN+= Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp
SRCS_MIN+= Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
SRCS_MIN+= Target/PowerPC/MCTargetDesc/PPCMachObjectWriter.cpp
SRCS_MIN+= Target/PowerPC/MCTargetDesc/PPCPredicates.cpp
SRCS_MIN+= Target/PowerPC/PPCAsmPrinter.cpp
SRCS_MIN+= Target/PowerPC/PPCBoolRetToInt.cpp
SRCS_MIN+= Target/PowerPC/PPCBranchCoalescing.cpp
SRCS_MIN+= Target/PowerPC/PPCBranchSelector.cpp
SRCS_MIN+= Target/PowerPC/PPCCCState.cpp
SRCS_MIN+= Target/PowerPC/PPCCTRLoops.cpp
SRCS_MIN+= Target/PowerPC/PPCEarlyReturn.cpp
SRCS_MIN+= Target/PowerPC/PPCExpandISEL.cpp
SRCS_MIN+= Target/PowerPC/PPCFastISel.cpp
SRCS_MIN+= Target/PowerPC/PPCFrameLowering.cpp
SRCS_MIN+= Target/PowerPC/PPCHazardRecognizers.cpp
SRCS_MIN+= Target/PowerPC/PPCISelDAGToDAG.cpp
SRCS_MIN+= Target/PowerPC/PPCISelLowering.cpp
SRCS_MIN+= Target/PowerPC/PPCInstrInfo.cpp
SRCS_MIN+= Target/PowerPC/PPCLoopPreIncPrep.cpp
SRCS_MIN+= Target/PowerPC/PPCMCInstLower.cpp
SRCS_MIN+= Target/PowerPC/PPCMIPeephole.cpp
SRCS_MIN+= Target/PowerPC/PPCMachineFunctionInfo.cpp
SRCS_MIN+= Target/PowerPC/PPCPreEmitPeephole.cpp
SRCS_MIN+= Target/PowerPC/PPCQPXLoadSplat.cpp
SRCS_MIN+= Target/PowerPC/PPCReduceCRLogicals.cpp
SRCS_MIN+= Target/PowerPC/PPCRegisterInfo.cpp
SRCS_MIN+= Target/PowerPC/PPCSubtarget.cpp
SRCS_MIN+= Target/PowerPC/PPCTLSDynamicCall.cpp
SRCS_MIN+= Target/PowerPC/PPCTOCRegDeps.cpp
SRCS_MIN+= Target/PowerPC/PPCTargetMachine.cpp
SRCS_MIN+= Target/PowerPC/PPCTargetObjectFile.cpp
SRCS_MIN+= Target/PowerPC/PPCTargetTransformInfo.cpp
SRCS_MIN+= Target/PowerPC/PPCVSXCopy.cpp
SRCS_MIN+= Target/PowerPC/PPCVSXFMAMutate.cpp
SRCS_MIN+= Target/PowerPC/PPCVSXSwapRemoval.cpp
SRCS_MIN+= Target/PowerPC/TargetInfo/PowerPCTargetInfo.cpp
.endif # MK_LLVM_TARGET_POWERPC
.if ${MK_LLVM_TARGET_RISCV} != "no"
SRCS_MIN+= Target/RISCV/AsmParser/RISCVAsmParser.cpp
SRCS_MIN+= Target/RISCV/Disassembler/RISCVDisassembler.cpp
SRCS_MIN+= Target/RISCV/InstPrinter/RISCVInstPrinter.cpp
SRCS_MIN+= Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
SRCS_MIN+= Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
SRCS_MIN+= Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
SRCS_MIN+= Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
SRCS_MIN+= Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
SRCS_MIN+= Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
SRCS_MIN+= Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
SRCS_MIN+= Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
SRCS_MIN+= Target/RISCV/RISCVAsmPrinter.cpp
SRCS_MIN+= Target/RISCV/RISCVExpandPseudoInsts.cpp
SRCS_MIN+= Target/RISCV/RISCVFrameLowering.cpp
SRCS_MIN+= Target/RISCV/RISCVInstrInfo.cpp
SRCS_MIN+= Target/RISCV/RISCVISelDAGToDAG.cpp
SRCS_MIN+= Target/RISCV/RISCVISelLowering.cpp
SRCS_MIN+= Target/RISCV/RISCVMCInstLower.cpp
SRCS_MIN+= Target/RISCV/RISCVMergeBaseOffset.cpp
SRCS_MIN+= Target/RISCV/RISCVRegisterInfo.cpp
SRCS_MIN+= Target/RISCV/RISCVSubtarget.cpp
SRCS_MIN+= Target/RISCV/RISCVTargetMachine.cpp
SRCS_MIN+= Target/RISCV/RISCVTargetObjectFile.cpp
SRCS_MIN+= Target/RISCV/TargetInfo/RISCVTargetInfo.cpp
SRCS_MIN+= Target/RISCV/Utils/RISCVBaseInfo.cpp
SRCS_MIN+= Target/RISCV/Utils/RISCVMatInt.cpp
.endif # MK_LLVM_TARGET_RISCV
.if ${MK_LLVM_TARGET_SPARC} != "no"
SRCS_MIN+= Target/Sparc/AsmParser/SparcAsmParser.cpp
SRCS_MIN+= Target/Sparc/DelaySlotFiller.cpp
SRCS_XDW+= Target/Sparc/Disassembler/SparcDisassembler.cpp
SRCS_MIN+= Target/Sparc/InstPrinter/SparcInstPrinter.cpp
SRCS_MIN+= Target/Sparc/LeonPasses.cpp
SRCS_MIN+= Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
SRCS_MIN+= Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
SRCS_MIN+= Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp
SRCS_MIN+= Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
SRCS_MIN+= Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
SRCS_MIN+= Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
SRCS_MIN+= Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp
SRCS_MIN+= Target/Sparc/SparcAsmPrinter.cpp
SRCS_MIN+= Target/Sparc/SparcFrameLowering.cpp
SRCS_MIN+= Target/Sparc/SparcISelDAGToDAG.cpp
SRCS_MIN+= Target/Sparc/SparcISelLowering.cpp
SRCS_MIN+= Target/Sparc/SparcInstrInfo.cpp
SRCS_MIN+= Target/Sparc/SparcMCInstLower.cpp
SRCS_MIN+= Target/Sparc/SparcMachineFunctionInfo.cpp
SRCS_MIN+= Target/Sparc/SparcRegisterInfo.cpp
SRCS_MIN+= Target/Sparc/SparcSubtarget.cpp
SRCS_MIN+= Target/Sparc/SparcTargetMachine.cpp
SRCS_MIN+= Target/Sparc/SparcTargetObjectFile.cpp
SRCS_MIN+= Target/Sparc/TargetInfo/SparcTargetInfo.cpp
.endif # MK_LLVM_TARGET_SPARC
SRCS_MIN+= Target/Target.cpp
SRCS_MIN+= Target/TargetIntrinsicInfo.cpp
SRCS_MIN+= Target/TargetLoweringObjectFile.cpp
SRCS_MIN+= Target/TargetMachine.cpp
SRCS_MIN+= Target/TargetMachineC.cpp
.if ${MK_LLVM_TARGET_X86} != "no"
SRCS_MIN+= Target/X86/AsmParser/X86AsmInstrumentation.cpp
SRCS_MIN+= Target/X86/AsmParser/X86AsmParser.cpp
SRCS_XDW+= Target/X86/Disassembler/X86Disassembler.cpp
SRCS_XDW+= Target/X86/Disassembler/X86DisassemblerDecoder.cpp
SRCS_MIN+= Target/X86/InstPrinter/X86ATTInstPrinter.cpp
SRCS_MIN+= Target/X86/InstPrinter/X86InstComments.cpp
SRCS_MIN+= Target/X86/InstPrinter/X86InstPrinterCommon.cpp
SRCS_MIN+= Target/X86/InstPrinter/X86IntelInstPrinter.cpp
SRCS_MIN+= Target/X86/MCTargetDesc/X86AsmBackend.cpp
SRCS_MIN+= Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
SRCS_MIN+= Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
SRCS_MIN+= Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
SRCS_MIN+= Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
SRCS_MIN+= Target/X86/MCTargetDesc/X86MachObjectWriter.cpp
SRCS_MIN+= Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp
SRCS_MIN+= Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp
SRCS_MIN+= Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp
SRCS_MIN+= Target/X86/TargetInfo/X86TargetInfo.cpp
SRCS_MIN+= Target/X86/Utils/X86ShuffleDecode.cpp
SRCS_MIN+= Target/X86/ShadowCallStack.cpp
SRCS_MIN+= Target/X86/X86AsmPrinter.cpp
SRCS_MIN+= Target/X86/X86AvoidStoreForwardingBlocks.cpp
SRCS_MIN+= Target/X86/X86CallFrameOptimization.cpp
SRCS_MIN+= Target/X86/X86CallLowering.cpp
SRCS_MIN+= Target/X86/X86CallingConv.cpp
SRCS_MIN+= Target/X86/X86CmovConversion.cpp
SRCS_MIN+= Target/X86/X86CondBrFolding.cpp
SRCS_MIN+= Target/X86/X86DiscriminateMemOps.cpp
SRCS_MIN+= Target/X86/X86DomainReassignment.cpp
SRCS_MIN+= Target/X86/X86EvexToVex.cpp
SRCS_MIN+= Target/X86/X86ExpandPseudo.cpp
SRCS_MIN+= Target/X86/X86FastISel.cpp
SRCS_MIN+= Target/X86/X86FixupBWInsts.cpp
SRCS_MIN+= Target/X86/X86FixupLEAs.cpp
SRCS_MIN+= Target/X86/X86FixupSetCC.cpp
SRCS_MIN+= Target/X86/X86FlagsCopyLowering.cpp
SRCS_MIN+= Target/X86/X86FloatingPoint.cpp
SRCS_MIN+= Target/X86/X86FrameLowering.cpp
SRCS_MIN+= Target/X86/X86ISelDAGToDAG.cpp
SRCS_MIN+= Target/X86/X86ISelLowering.cpp
SRCS_MIN+= Target/X86/X86IndirectBranchTracking.cpp
SRCS_MIN+= Target/X86/X86InsertPrefetch.cpp
SRCS_MIN+= Target/X86/X86InstrFMA3Info.cpp
SRCS_MIN+= Target/X86/X86InstrFoldTables.cpp
SRCS_MIN+= Target/X86/X86InstrInfo.cpp
SRCS_MIN+= Target/X86/X86InstructionSelector.cpp
SRCS_MIN+= Target/X86/X86InterleavedAccess.cpp
SRCS_MIN+= Target/X86/X86LegalizerInfo.cpp
SRCS_MIN+= Target/X86/X86MCInstLower.cpp
SRCS_MIN+= Target/X86/X86MachineFunctionInfo.cpp
SRCS_MIN+= Target/X86/X86MacroFusion.cpp
SRCS_MIN+= Target/X86/X86OptimizeLEAs.cpp
SRCS_MIN+= Target/X86/X86PadShortFunction.cpp
SRCS_MIN+= Target/X86/X86RegisterBankInfo.cpp
SRCS_MIN+= Target/X86/X86RegisterInfo.cpp
SRCS_MIN+= Target/X86/X86RetpolineThunks.cpp
SRCS_MIN+= Target/X86/X86SelectionDAGInfo.cpp
SRCS_MIN+= Target/X86/X86ShuffleDecodeConstantPool.cpp
SRCS_MIN+= Target/X86/X86SpeculativeLoadHardening.cpp
SRCS_MIN+= Target/X86/X86Subtarget.cpp
SRCS_MIN+= Target/X86/X86TargetMachine.cpp
SRCS_MIN+= Target/X86/X86TargetObjectFile.cpp
SRCS_MIN+= Target/X86/X86TargetTransformInfo.cpp
SRCS_MIN+= Target/X86/X86VZeroUpper.cpp
SRCS_MIN+= Target/X86/X86WinAllocaExpander.cpp
SRCS_MIN+= Target/X86/X86WinEHState.cpp
.endif # MK_LLVM_TARGET_X86
SRCS_EXT+= ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
SRCS_EXL+= ToolDrivers/llvm-lib/LibDriver.cpp
SRCS_MIN+= Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
SRCS_MIN+= Transforms/AggressiveInstCombine/TruncInstCombine.cpp
SRCS_MIN+= Transforms/Coroutines/CoroCleanup.cpp
SRCS_MIN+= Transforms/Coroutines/CoroEarly.cpp
SRCS_MIN+= Transforms/Coroutines/CoroElide.cpp
SRCS_MIN+= Transforms/Coroutines/CoroFrame.cpp
SRCS_MIN+= Transforms/Coroutines/CoroSplit.cpp
SRCS_MIN+= Transforms/Coroutines/Coroutines.cpp
SRCS_MIN+= Transforms/IPO/AlwaysInliner.cpp
SRCS_MIN+= Transforms/IPO/ArgumentPromotion.cpp
SRCS_MIN+= Transforms/IPO/BarrierNoopPass.cpp
SRCS_EXT+= Transforms/IPO/BlockExtractor.cpp
SRCS_MIN+= Transforms/IPO/CalledValuePropagation.cpp
SRCS_MIN+= Transforms/IPO/ConstantMerge.cpp
SRCS_MIN+= Transforms/IPO/CrossDSOCFI.cpp
SRCS_MIN+= Transforms/IPO/DeadArgumentElimination.cpp
SRCS_MIN+= Transforms/IPO/ElimAvailExtern.cpp
SRCS_MIN+= Transforms/IPO/ExtractGV.cpp
SRCS_MIN+= Transforms/IPO/ForceFunctionAttrs.cpp
SRCS_MIN+= Transforms/IPO/FunctionAttrs.cpp
SRCS_MIN+= Transforms/IPO/FunctionImport.cpp
SRCS_MIN+= Transforms/IPO/GlobalDCE.cpp
SRCS_MIN+= Transforms/IPO/GlobalOpt.cpp
SRCS_MIN+= Transforms/IPO/GlobalSplit.cpp
SRCS_MIN+= Transforms/IPO/HotColdSplitting.cpp
SRCS_MIN+= Transforms/IPO/IPConstantPropagation.cpp
SRCS_EXT+= Transforms/IPO/IPO.cpp
SRCS_MIN+= Transforms/IPO/InferFunctionAttrs.cpp
SRCS_MIN+= Transforms/IPO/InlineSimple.cpp
SRCS_MIN+= Transforms/IPO/Inliner.cpp
SRCS_MIN+= Transforms/IPO/Internalize.cpp
SRCS_MIN+= Transforms/IPO/LoopExtractor.cpp
SRCS_MIN+= Transforms/IPO/LowerTypeTests.cpp
SRCS_MIN+= Transforms/IPO/MergeFunctions.cpp
SRCS_MIN+= Transforms/IPO/PartialInlining.cpp
SRCS_MIN+= Transforms/IPO/PassManagerBuilder.cpp
SRCS_MIN+= Transforms/IPO/PruneEH.cpp
SRCS_MIN+= Transforms/IPO/SCCP.cpp
SRCS_MIN+= Transforms/IPO/SampleProfile.cpp
SRCS_MIN+= Transforms/IPO/StripDeadPrototypes.cpp
SRCS_MIN+= Transforms/IPO/StripSymbols.cpp
SRCS_MIN+= Transforms/IPO/SyntheticCountsPropagation.cpp
SRCS_MIN+= Transforms/IPO/ThinLTOBitcodeWriter.cpp
SRCS_MIN+= Transforms/IPO/WholeProgramDevirt.cpp
SRCS_MIN+= Transforms/InstCombine/InstCombineAddSub.cpp
SRCS_MIN+= Transforms/InstCombine/InstCombineAndOrXor.cpp
SRCS_MIN+= Transforms/InstCombine/InstCombineCalls.cpp
SRCS_MIN+= Transforms/InstCombine/InstCombineCasts.cpp
SRCS_MIN+= Transforms/InstCombine/InstCombineCompares.cpp
SRCS_MIN+= Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
SRCS_MIN+= Transforms/InstCombine/InstCombineMulDivRem.cpp
SRCS_MIN+= Transforms/InstCombine/InstCombinePHI.cpp
SRCS_MIN+= Transforms/InstCombine/InstCombineSelect.cpp
SRCS_MIN+= Transforms/InstCombine/InstCombineShifts.cpp
SRCS_MIN+= Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
SRCS_MIN+= Transforms/InstCombine/InstCombineVectorOps.cpp
SRCS_MIN+= Transforms/InstCombine/InstructionCombining.cpp
SRCS_MIN+= Transforms/Instrumentation/AddressSanitizer.cpp
SRCS_MIN+= Transforms/Instrumentation/BoundsChecking.cpp
SRCS_MIN+= Transforms/Instrumentation/CGProfile.cpp
SRCS_MIN+= Transforms/Instrumentation/ControlHeightReduction.cpp
SRCS_MIN+= Transforms/Instrumentation/DataFlowSanitizer.cpp
SRCS_MIN+= Transforms/Instrumentation/EfficiencySanitizer.cpp
SRCS_MIN+= Transforms/Instrumentation/GCOVProfiling.cpp
SRCS_MIN+= Transforms/Instrumentation/HWAddressSanitizer.cpp
SRCS_MIN+= Transforms/Instrumentation/IndirectCallPromotion.cpp
SRCS_MIN+= Transforms/Instrumentation/InstrProfiling.cpp
SRCS_MIN+= Transforms/Instrumentation/Instrumentation.cpp
SRCS_MIN+= Transforms/Instrumentation/MemorySanitizer.cpp
SRCS_MIN+= Transforms/Instrumentation/PGOInstrumentation.cpp
SRCS_MIN+= Transforms/Instrumentation/PGOMemOPSizeOpt.cpp
SRCS_MIN+= Transforms/Instrumentation/SanitizerCoverage.cpp
SRCS_MIN+= Transforms/Instrumentation/ThreadSanitizer.cpp
SRCS_MIN+= Transforms/ObjCARC/DependencyAnalysis.cpp
SRCS_EXT+= Transforms/ObjCARC/ObjCARC.cpp
SRCS_MIN+= Transforms/ObjCARC/ObjCARCAPElim.cpp
SRCS_MIN+= Transforms/ObjCARC/ObjCARCContract.cpp
SRCS_MIN+= Transforms/ObjCARC/ObjCARCExpand.cpp
SRCS_MIN+= Transforms/ObjCARC/ObjCARCOpts.cpp
SRCS_MIN+= Transforms/ObjCARC/ProvenanceAnalysis.cpp
SRCS_MIN+= Transforms/ObjCARC/ProvenanceAnalysisEvaluator.cpp
SRCS_MIN+= Transforms/ObjCARC/PtrState.cpp
SRCS_MIN+= Transforms/Scalar/ADCE.cpp
SRCS_MIN+= Transforms/Scalar/AlignmentFromAssumptions.cpp
SRCS_MIN+= Transforms/Scalar/BDCE.cpp
SRCS_MIN+= Transforms/Scalar/CallSiteSplitting.cpp
SRCS_MIN+= Transforms/Scalar/ConstantHoisting.cpp
SRCS_MIN+= Transforms/Scalar/ConstantProp.cpp
SRCS_MIN+= Transforms/Scalar/CorrelatedValuePropagation.cpp
SRCS_MIN+= Transforms/Scalar/DCE.cpp
SRCS_MIN+= Transforms/Scalar/DeadStoreElimination.cpp
SRCS_MIN+= Transforms/Scalar/DivRemPairs.cpp
SRCS_MIN+= Transforms/Scalar/EarlyCSE.cpp
SRCS_MIN+= Transforms/Scalar/FlattenCFGPass.cpp
SRCS_MIN+= Transforms/Scalar/Float2Int.cpp
SRCS_MIN+= Transforms/Scalar/GVN.cpp
SRCS_MIN+= Transforms/Scalar/GVNHoist.cpp
SRCS_MIN+= Transforms/Scalar/GVNSink.cpp
SRCS_MIN+= Transforms/Scalar/GuardWidening.cpp
SRCS_MIN+= Transforms/Scalar/IVUsersPrinter.cpp
SRCS_MIN+= Transforms/Scalar/IndVarSimplify.cpp
SRCS_MIN+= Transforms/Scalar/InductiveRangeCheckElimination.cpp
SRCS_EXT+= Transforms/Scalar/InferAddressSpaces.cpp
SRCS_MIN+= Transforms/Scalar/InstSimplifyPass.cpp
SRCS_MIN+= Transforms/Scalar/JumpThreading.cpp
SRCS_MIN+= Transforms/Scalar/LICM.cpp
SRCS_MIN+= Transforms/Scalar/LoopAccessAnalysisPrinter.cpp
SRCS_MIN+= Transforms/Scalar/LoopDataPrefetch.cpp
SRCS_MIN+= Transforms/Scalar/LoopDeletion.cpp
SRCS_MIN+= Transforms/Scalar/LoopDistribute.cpp
SRCS_MIN+= Transforms/Scalar/LoopIdiomRecognize.cpp
SRCS_MIN+= Transforms/Scalar/LoopInstSimplify.cpp
SRCS_MIN+= Transforms/Scalar/LoopInterchange.cpp
SRCS_MIN+= Transforms/Scalar/LoopLoadElimination.cpp
SRCS_MIN+= Transforms/Scalar/LoopPassManager.cpp
SRCS_MIN+= Transforms/Scalar/LoopPredication.cpp
SRCS_MIN+= Transforms/Scalar/LoopRerollPass.cpp
SRCS_MIN+= Transforms/Scalar/LoopRotation.cpp
SRCS_MIN+= Transforms/Scalar/LoopSimplifyCFG.cpp
SRCS_MIN+= Transforms/Scalar/LoopSink.cpp
SRCS_MIN+= Transforms/Scalar/LoopStrengthReduce.cpp
SRCS_MIN+= Transforms/Scalar/LoopUnrollPass.cpp
SRCS_MIN+= Transforms/Scalar/LoopUnrollAndJamPass.cpp
SRCS_MIN+= Transforms/Scalar/LoopUnswitch.cpp
SRCS_MIN+= Transforms/Scalar/LoopVersioningLICM.cpp
SRCS_MIN+= Transforms/Scalar/LowerAtomic.cpp
SRCS_MIN+= Transforms/Scalar/LowerExpectIntrinsic.cpp
SRCS_MIN+= Transforms/Scalar/LowerGuardIntrinsic.cpp
SRCS_MIN+= Transforms/Scalar/MakeGuardsExplicit.cpp
SRCS_MIN+= Transforms/Scalar/MemCpyOptimizer.cpp
SRCS_MIN+= Transforms/Scalar/MergeICmps.cpp
SRCS_MIN+= Transforms/Scalar/MergedLoadStoreMotion.cpp
SRCS_MIN+= Transforms/Scalar/NaryReassociate.cpp
SRCS_MIN+= Transforms/Scalar/NewGVN.cpp
SRCS_MIN+= Transforms/Scalar/PartiallyInlineLibCalls.cpp
SRCS_MIN+= Transforms/Scalar/PlaceSafepoints.cpp
SRCS_MIN+= Transforms/Scalar/Reassociate.cpp
SRCS_MIN+= Transforms/Scalar/Reg2Mem.cpp
SRCS_MIN+= Transforms/Scalar/RewriteStatepointsForGC.cpp
SRCS_MIN+= Transforms/Scalar/SCCP.cpp
SRCS_MIN+= Transforms/Scalar/SROA.cpp
SRCS_EXT+= Transforms/Scalar/Scalar.cpp
SRCS_MIN+= Transforms/Scalar/Scalarizer.cpp
SRCS_MIN+= Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
SRCS_MIN+= Transforms/Scalar/SimpleLoopUnswitch.cpp
SRCS_MIN+= Transforms/Scalar/SimplifyCFGPass.cpp
SRCS_MIN+= Transforms/Scalar/Sink.cpp
SRCS_MIN+= Transforms/Scalar/SpeculateAroundPHIs.cpp
SRCS_MIN+= Transforms/Scalar/SpeculativeExecution.cpp
SRCS_MIN+= Transforms/Scalar/StraightLineStrengthReduce.cpp
SRCS_MIN+= Transforms/Scalar/StructurizeCFG.cpp
SRCS_MIN+= Transforms/Scalar/TailRecursionElimination.cpp
SRCS_MIN+= Transforms/Scalar/WarnMissedTransforms.cpp
SRCS_MIN+= Transforms/Utils/ASanStackFrameLayout.cpp
SRCS_MIN+= Transforms/Utils/AddDiscriminators.cpp
SRCS_MIN+= Transforms/Utils/BasicBlockUtils.cpp
SRCS_MIN+= Transforms/Utils/BreakCriticalEdges.cpp
SRCS_MIN+= Transforms/Utils/BuildLibCalls.cpp
SRCS_MIN+= Transforms/Utils/BypassSlowDivision.cpp
SRCS_MIN+= Transforms/Utils/CallPromotionUtils.cpp
SRCS_MIN+= Transforms/Utils/CanonicalizeAliases.cpp
SRCS_MIN+= Transforms/Utils/CloneFunction.cpp
SRCS_MIN+= Transforms/Utils/CloneModule.cpp
SRCS_MIN+= Transforms/Utils/CodeExtractor.cpp
SRCS_MIN+= Transforms/Utils/CtorUtils.cpp
SRCS_MIN+= Transforms/Utils/DemoteRegToStack.cpp
SRCS_MIN+= Transforms/Utils/EntryExitInstrumenter.cpp
SRCS_MIN+= Transforms/Utils/EscapeEnumerator.cpp
SRCS_MIN+= Transforms/Utils/Evaluator.cpp
SRCS_MIN+= Transforms/Utils/FlattenCFG.cpp
SRCS_MIN+= Transforms/Utils/FunctionComparator.cpp
SRCS_MIN+= Transforms/Utils/FunctionImportUtils.cpp
SRCS_MIN+= Transforms/Utils/GlobalStatus.cpp
SRCS_MIN+= Transforms/Utils/GuardUtils.cpp
SRCS_MIN+= Transforms/Utils/ImportedFunctionsInliningStatistics.cpp
SRCS_MIN+= Transforms/Utils/InlineFunction.cpp
SRCS_MIN+= Transforms/Utils/InstructionNamer.cpp
SRCS_MIN+= Transforms/Utils/IntegerDivision.cpp
SRCS_MIN+= Transforms/Utils/LCSSA.cpp
SRCS_MIN+= Transforms/Utils/LibCallsShrinkWrap.cpp
SRCS_MIN+= Transforms/Utils/Local.cpp
SRCS_MIN+= Transforms/Utils/LoopSimplify.cpp
SRCS_MIN+= Transforms/Utils/LoopRotationUtils.cpp
SRCS_MIN+= Transforms/Utils/LoopUnroll.cpp
SRCS_MIN+= Transforms/Utils/LoopUnrollAndJam.cpp
SRCS_MIN+= Transforms/Utils/LoopUnrollPeel.cpp
SRCS_MIN+= Transforms/Utils/LoopUnrollRuntime.cpp
SRCS_MIN+= Transforms/Utils/LoopUtils.cpp
SRCS_MIN+= Transforms/Utils/LoopVersioning.cpp
SRCS_MIN+= Transforms/Utils/LowerInvoke.cpp
SRCS_MIN+= Transforms/Utils/LowerSwitch.cpp
SRCS_MIN+= Transforms/Utils/Mem2Reg.cpp
SRCS_MIN+= Transforms/Utils/MetaRenamer.cpp
SRCS_MIN+= Transforms/Utils/ModuleUtils.cpp
SRCS_MIN+= Transforms/Utils/NameAnonGlobals.cpp
SRCS_MIN+= Transforms/Utils/PredicateInfo.cpp
SRCS_MIN+= Transforms/Utils/PromoteMemoryToRegister.cpp
SRCS_MIN+= Transforms/Utils/SSAUpdater.cpp
SRCS_MIN+= Transforms/Utils/SanitizerStats.cpp
SRCS_MIN+= Transforms/Utils/SimplifyCFG.cpp
SRCS_MIN+= Transforms/Utils/SimplifyIndVar.cpp
SRCS_MIN+= Transforms/Utils/SimplifyLibCalls.cpp
SRCS_MIN+= Transforms/Utils/SplitModule.cpp
SRCS_MIN+= Transforms/Utils/StripGCRelocates.cpp
SRCS_MIN+= Transforms/Utils/StripNonLineTableDebugInfo.cpp
SRCS_MIN+= Transforms/Utils/SymbolRewriter.cpp
SRCS_MIN+= Transforms/Utils/UnifyFunctionExitNodes.cpp
SRCS_EXT+= Transforms/Utils/Utils.cpp
SRCS_MIN+= Transforms/Utils/VNCoercion.cpp
SRCS_MIN+= Transforms/Utils/ValueMapper.cpp
SRCS_MIN+= Transforms/Vectorize/LoadStoreVectorizer.cpp
SRCS_MIN+= Transforms/Vectorize/LoopVectorizationLegality.cpp
SRCS_MIN+= Transforms/Vectorize/LoopVectorize.cpp
SRCS_MIN+= Transforms/Vectorize/SLPVectorizer.cpp
SRCS_MIN+= Transforms/Vectorize/VPlan.cpp
SRCS_MIN+= Transforms/Vectorize/VPlanHCFGBuilder.cpp
SRCS_MIN+= Transforms/Vectorize/VPlanHCFGTransforms.cpp
SRCS_MIN+= Transforms/Vectorize/VPlanVerifier.cpp
SRCS_EXT+= Transforms/Vectorize/Vectorize.cpp
SRCS_EXT+= XRay/BlockIndexer.cpp
SRCS_EXT+= XRay/BlockVerifier.cpp
SRCS_EXT+= XRay/FDRRecordProducer.cpp
SRCS_EXT+= XRay/FDRRecords.cpp
SRCS_EXT+= XRay/FDRTraceExpander.cpp
SRCS_EXT+= XRay/FileHeaderReader.cpp
SRCS_EXT+= XRay/InstrumentationMap.cpp
SRCS_EXT+= XRay/LogBuilderConsumer.cpp
SRCS_EXT+= XRay/RecordInitializer.cpp
SRCS_EXT+= XRay/Trace.cpp
SRCS_ALL+= ${SRCS_MIN}
.if !defined(TOOLS_PREFIX) || ${MK_LLD_IS_LD} != "no"
SRCS_ALL+= ${SRCS_MIW}
.endif
.if ${MK_CLANG_EXTRAS} != "no"
SRCS_ALL+= ${SRCS_EXT}
.endif
.if ${MK_CLANG_FULL} != "no"
SRCS_ALL+= ${SRCS_FUL}
.endif
.if ${MK_CLANG_EXTRAS} != "no" || ${MK_LLD} != "no"
SRCS_ALL+= ${SRCS_EXL}
.endif
.if ${MK_LLD} != "no"
SRCS_ALL+= ${SRCS_LLD}
.endif
.if ${MK_CLANG_EXTRAS} != "no" || ${MK_LLDB} != "no"
SRCS_ALL+= ${SRCS_XDB}
.endif
.if ${MK_CLANG_EXTRAS} != "no" || ${MK_LLDB} != "no" || ${MK_LLD} != "no"
SRCS_ALL+= ${SRCS_XDL}
.endif
.if ${MK_CLANG_EXTRAS} != "no" || ${MK_LLDB} != "no" || !defined(TOOLS_PREFIX)
SRCS_ALL+= ${SRCS_XDW}
.endif
SRCS+= ${SRCS_ALL:O}
llvm/IR/Attributes.inc: ${LLVM_SRCS}/include/llvm/IR/Attributes.td
${LLVM_TBLGEN} -gen-attrs \
-I ${LLVM_SRCS}/include -d ${.TARGET}.d -o ${.TARGET} \
${LLVM_SRCS}/include/llvm/IR/Attributes.td
TGHDRS+= llvm/IR/Attributes.inc
llvm/IR/IntrinsicEnums.inc: ${LLVM_SRCS}/include/llvm/IR/Intrinsics.td
${LLVM_TBLGEN} -gen-intrinsic-enums \
-I ${LLVM_SRCS}/include -d ${.TARGET}.d -o ${.TARGET} \
${LLVM_SRCS}/include/llvm/IR/Intrinsics.td
TGHDRS+= llvm/IR/IntrinsicEnums.inc
llvm/IR/IntrinsicImpl.inc: ${LLVM_SRCS}/include/llvm/IR/Intrinsics.td
${LLVM_TBLGEN} -gen-intrinsic-impl \
-I ${LLVM_SRCS}/include -d ${.TARGET}.d -o ${.TARGET} \
${LLVM_SRCS}/include/llvm/IR/Intrinsics.td
TGHDRS+= llvm/IR/IntrinsicImpl.inc
AttributesCompatFunc.inc: ${LLVM_SRCS}/lib/IR/AttributesCompatFunc.td
${LLVM_TBLGEN} -gen-attrs \
-I ${LLVM_SRCS}/include -d ${.TARGET}.d -o ${.TARGET} \
${LLVM_SRCS}/lib/IR/AttributesCompatFunc.td
TGHDRS+= AttributesCompatFunc.inc
InstCombineTables.inc: ${LLVM_SRCS}/lib/Transforms/InstCombine/InstCombineTables.td
${LLVM_TBLGEN} -gen-searchable-tables \
-I ${LLVM_SRCS}/include -d ${.TARGET}.d -o ${.TARGET} \
${LLVM_SRCS}/lib/Transforms/InstCombine/InstCombineTables.td
TGHDRS+= InstCombineTables.inc
llvm-lib/Options.inc: ${LLVM_SRCS}/lib/ToolDrivers/llvm-lib/Options.td
${LLVM_TBLGEN} -gen-opt-parser-defs \
-I ${LLVM_SRCS}/include -d ${.TARGET}.d -o ${.TARGET} \
${LLVM_SRCS}/lib/ToolDrivers/llvm-lib/Options.td
TGHDRS+= llvm-lib/Options.inc
CFLAGS.LibDriver.cpp+= -I${.OBJDIR}/llvm-lib
llvm-dlltool/Options.inc: ${LLVM_SRCS}/lib/ToolDrivers/llvm-dlltool/Options.td
${LLVM_TBLGEN} -gen-opt-parser-defs \
-I ${LLVM_SRCS}/include -d ${.TARGET}.d -o ${.TARGET} \
${LLVM_SRCS}/lib/ToolDrivers/llvm-dlltool/Options.td
TGHDRS+= llvm-dlltool/Options.inc
CFLAGS.DlltoolDriver.cpp+= -I${.OBJDIR}/llvm-dlltool
beforebuild:
# 20170724 remove stale Options.inc file, of which there are two different
# versions after upstream r308421, one for llvm-lib, one for llvm-dlltool
.for f in Options.inc
.if exists(${f}) || exists(${f}.d)
@echo Removing stale generated ${f} files
@rm -f ${f} ${f}.d
.endif
.endfor
# Note: some rules are superfluous, not every combination is valid.
.for arch in \
AArch64/AArch64 ARM/ARM BPF/BPF Mips/Mips PowerPC/PPC Sparc/Sparc \
RISCV/RISCV X86/X86
. for hdr in \
AsmMatcher/-gen-asm-matcher \
AsmWriter1/-gen-asm-writer,-asmwriternum=1 \
AsmWriter/-gen-asm-writer \
CallingConv/-gen-callingconv \
CodeEmitter/-gen-emitter \
CompressInstEmitter/-gen-compress-inst-emitter \
DAGISel/-gen-dag-isel \
DisassemblerTables/-gen-disassembler \
EVEX2VEXTables/-gen-x86-EVEX2VEX-tables \
FastISel/-gen-fast-isel \
GlobalISel/-gen-global-isel \
InstrInfo/-gen-instr-info \
MCCodeEmitter/-gen-emitter \
MCPseudoLowering/-gen-pseudo-lowering \
RegisterBank/-gen-register-bank \
RegisterInfo/-gen-register-info \
SubtargetInfo/-gen-subtarget \
SystemOperands/-gen-searchable-tables \
SystemRegister/-gen-searchable-tables
${arch:T}Gen${hdr:H}.inc: ${LLVM_SRCS}/lib/Target/${arch:H}/${arch:T}.td
${LLVM_TBLGEN} ${hdr:T:C/,/ /g} \
-I ${LLVM_SRCS}/include -I ${LLVM_SRCS}/lib/Target/${arch:H} \
-d ${.TARGET}.d -o ${.TARGET} \
${LLVM_SRCS}/lib/Target/${arch:H}/${arch:T}.td
. endfor
.endfor
.if ${MK_LLVM_TARGET_AARCH64} != "no"
TGHDRS+= AArch64GenAsmMatcher.inc
TGHDRS+= AArch64GenAsmWriter.inc
TGHDRS+= AArch64GenAsmWriter1.inc
TGHDRS+= AArch64GenCallingConv.inc
TGHDRS+= AArch64GenDAGISel.inc
TGHDRS+= AArch64GenDisassemblerTables.inc
TGHDRS+= AArch64GenFastISel.inc
TGHDRS+= AArch64GenGlobalISel.inc
TGHDRS+= AArch64GenInstrInfo.inc
TGHDRS+= AArch64GenMCCodeEmitter.inc
TGHDRS+= AArch64GenMCPseudoLowering.inc
TGHDRS+= AArch64GenRegisterBank.inc
TGHDRS+= AArch64GenRegisterInfo.inc
TGHDRS+= AArch64GenSubtargetInfo.inc
TGHDRS+= AArch64GenSystemOperands.inc
.endif # MK_LLVM_TARGET_AARCH64
.if ${MK_LLVM_TARGET_ARM} != "no"
TGHDRS+= ARMGenAsmMatcher.inc
TGHDRS+= ARMGenAsmWriter.inc
TGHDRS+= ARMGenCallingConv.inc
TGHDRS+= ARMGenDAGISel.inc
TGHDRS+= ARMGenDisassemblerTables.inc
TGHDRS+= ARMGenFastISel.inc
TGHDRS+= ARMGenGlobalISel.inc
TGHDRS+= ARMGenInstrInfo.inc
TGHDRS+= ARMGenMCCodeEmitter.inc
TGHDRS+= ARMGenMCPseudoLowering.inc
TGHDRS+= ARMGenRegisterBank.inc
TGHDRS+= ARMGenRegisterInfo.inc
TGHDRS+= ARMGenSubtargetInfo.inc
TGHDRS+= ARMGenSystemRegister.inc
.endif # MK_LLVM_TARGET_ARM
.if ${MK_LLVM_TARGET_BPF} != "no"
TGHDRS+= BPFGenAsmMatcher.inc
TGHDRS+= BPFGenAsmWriter.inc
TGHDRS+= BPFGenCallingConv.inc
TGHDRS+= BPFGenDAGISel.inc
TGHDRS+= BPFGenDisassemblerTables.inc
TGHDRS+= BPFGenInstrInfo.inc
TGHDRS+= BPFGenMCCodeEmitter.inc
TGHDRS+= BPFGenRegisterInfo.inc
TGHDRS+= BPFGenSubtargetInfo.inc
.endif # MK_LLVM_TARGET_BPF
.if ${MK_LLVM_TARGET_MIPS} != "no"
TGHDRS+= MipsGenAsmMatcher.inc
TGHDRS+= MipsGenAsmWriter.inc
TGHDRS+= MipsGenCallingConv.inc
TGHDRS+= MipsGenDAGISel.inc
TGHDRS+= MipsGenDisassemblerTables.inc
TGHDRS+= MipsGenFastISel.inc
TGHDRS+= MipsGenGlobalISel.inc
TGHDRS+= MipsGenInstrInfo.inc
TGHDRS+= MipsGenMCCodeEmitter.inc
TGHDRS+= MipsGenMCPseudoLowering.inc
TGHDRS+= MipsGenRegisterBank.inc
TGHDRS+= MipsGenRegisterInfo.inc
TGHDRS+= MipsGenSubtargetInfo.inc
.endif # MK_LLVM_TARGET_MIPS
.if ${MK_LLVM_TARGET_POWERPC} != "no"
TGHDRS+= PPCGenAsmMatcher.inc
TGHDRS+= PPCGenAsmWriter.inc
TGHDRS+= PPCGenCallingConv.inc
TGHDRS+= PPCGenDAGISel.inc
TGHDRS+= PPCGenDisassemblerTables.inc
TGHDRS+= PPCGenFastISel.inc
TGHDRS+= PPCGenInstrInfo.inc
TGHDRS+= PPCGenMCCodeEmitter.inc
TGHDRS+= PPCGenRegisterInfo.inc
TGHDRS+= PPCGenSubtargetInfo.inc
.endif # MK_LLVM_TARGET_POWERPC
.if ${MK_LLVM_TARGET_RISCV} != "no"
TGHDRS+= RISCVGenAsmMatcher.inc
TGHDRS+= RISCVGenAsmWriter.inc
TGHDRS+= RISCVGenCallingConv.inc
TGHDRS+= RISCVGenCompressInstEmitter.inc
TGHDRS+= RISCVGenDAGISel.inc
TGHDRS+= RISCVGenDisassemblerTables.inc
TGHDRS+= RISCVGenDAGISel.inc
TGHDRS+= RISCVGenInstrInfo.inc
TGHDRS+= RISCVGenMCCodeEmitter.inc
TGHDRS+= RISCVGenMCPseudoLowering.inc
TGHDRS+= RISCVGenRegisterInfo.inc
TGHDRS+= RISCVGenSubtargetInfo.inc
TGHDRS+= RISCVGenSystemOperands.inc
.endif # MK_LLVM_TARGET_RISCV
.if ${MK_LLVM_TARGET_SPARC} != "no"
TGHDRS+= SparcGenAsmMatcher.inc
TGHDRS+= SparcGenAsmWriter.inc
TGHDRS+= SparcGenCallingConv.inc
TGHDRS+= SparcGenDAGISel.inc
TGHDRS+= SparcGenDisassemblerTables.inc
TGHDRS+= SparcGenInstrInfo.inc
TGHDRS+= SparcGenMCCodeEmitter.inc
TGHDRS+= SparcGenRegisterInfo.inc
TGHDRS+= SparcGenSubtargetInfo.inc
.endif # MK_LLVM_TARGET_SPARC
.if ${MK_LLVM_TARGET_X86} != "no"
TGHDRS+= X86GenAsmMatcher.inc
TGHDRS+= X86GenAsmWriter.inc
TGHDRS+= X86GenAsmWriter1.inc
TGHDRS+= X86GenCallingConv.inc
TGHDRS+= X86GenDAGISel.inc
TGHDRS+= X86GenDisassemblerTables.inc
TGHDRS+= X86GenEVEX2VEXTables.inc
TGHDRS+= X86GenFastISel.inc
TGHDRS+= X86GenGlobalISel.inc
TGHDRS+= X86GenInstrInfo.inc
TGHDRS+= X86GenRegisterBank.inc
TGHDRS+= X86GenRegisterInfo.inc
TGHDRS+= X86GenSubtargetInfo.inc
.endif # MK_LLVM_TARGET_X86
.for dep in ${TGHDRS:C/$/.d/}
. if ${MAKE_VERSION} < 20160220
. if !make(depend)
. sinclude "${dep}"
. endif
. else
. dinclude "${dep}"
. endif
.endfor
DPSRCS+= ${TGHDRS}
CLEANFILES+= ${TGHDRS} ${TGHDRS:C/$/.d/}
.include "../llvm.build.mk"
.include <bsd.lib.mk>
Index: stable/11/lib/libclang_rt/Makefile.inc
===================================================================
--- stable/11/lib/libclang_rt/Makefile.inc (revision 350258)
+++ stable/11/lib/libclang_rt/Makefile.inc (revision 350259)
@@ -1,37 +1,37 @@
# $FreeBSD$
.include <src.opts.mk>
CRTARCH= ${MACHINE_CPUARCH:C/amd64/x86_64/}
CRTSRC= ${SRCTOP}/contrib/compiler-rt
.PATH: ${CRTSRC}/lib
-CLANGDIR= /usr/lib/clang/8.0.0
+CLANGDIR= /usr/lib/clang/8.0.1
LIBDIR= ${CLANGDIR}/lib/freebsd
SHLIBDIR= ${LIBDIR}
NO_PIC=
MK_PROFILE= no
WARNS?= 0
SSP_CFLAGS=
CFLAGS+= -DNDEBUG
CFLAGS+= -DHAVE_RPC_XDR_H=0
CFLAGS+= -DHAVE_TIRPC_RPC_XDR_H=0
CFLAGS+= -DSANITIZER_SUPPORTS_WEAK_HOOKS=0
CFLAGS+= -DUBSAN_CAN_USE_CXXABI
CFLAGS+= ${PICFLAG}
CFLAGS+= -fno-builtin
CFLAGS+= -fno-exceptions
CFLAGS+= -fno-rtti
.if ${COMPILER_VERSION} >= 30700
CFLAGS+= -fno-sanitize=safe-stack
.endif
CFLAGS+= -fno-stack-protector
CFLAGS+= -funwind-tables
CFLAGS+= -fvisibility-inlines-hidden
CFLAGS+= -fvisibility=hidden
CFLAGS+= -I${CRTSRC}/lib
CXXFLAGS+= -std=c++11
Index: stable/11/tools/build/mk/OptionalObsoleteFiles.inc
===================================================================
--- stable/11/tools/build/mk/OptionalObsoleteFiles.inc (revision 350258)
+++ stable/11/tools/build/mk/OptionalObsoleteFiles.inc (revision 350259)
@@ -1,9954 +1,9954 @@
#
# $FreeBSD$
#
# This file add 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_AMD} == no
OLD_FILES+=etc/amd.map
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
.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+=etc/rc.d/atm1
OLD_FILES+=etc/rc.d/atm2
OLD_FILES+=etc/rc.d/atm3
OLD_FILES+=rescue/atmconfig
OLD_FILES+=sbin/atmconfig
OLD_FILES+=usr/bin/sscop
OLD_FILES+=usr/include/bsnmp/snmp_atm.h
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/lib/snmp_atm.so
OLD_LIBS+=usr/lib/snmp_atm.so.6
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/lib32/libngatm.a
OLD_FILES+=usr/lib32/libngatm.so
OLD_LIBS+=usr/lib32/libngatm.so.4
OLD_FILES+=usr/lib32/libngatm_p.a
.endif
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/man1/sscop.1.gz
OLD_FILES+=usr/share/man/man3/libngatm.3.gz
OLD_FILES+=usr/share/man/man3/snmp_atm.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
OLD_FILES+=usr/share/man/man8/atmconfig.8.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
.endif
.if ${MK_AUDIT} == no
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
.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 ${MK_BINUTILS} == no
OLD_FILES+=usr/bin/as
.if ${MK_LLD_IS_LD} == no
OLD_FILES+=usr/bin/ld
.endif
OLD_FILES+=usr/bin/ld.bfd
.if ${MK_ELFCOPY_AS_OBJCOPY} == no
OLD_FILES+=usr/bin/objcopy
.endif
OLD_FILES+=usr/bin/objdump
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
OLD_FILES+=usr/share/man/man1/as.1.gz
OLD_FILES+=usr/share/man/man1/ld.1.gz
.if ${MK_ELFCOPY_AS_OBJCOPY} == no
OLD_FILES+=usr/share/man/man1/objcopy.1.gz
.endif
OLD_FILES+=usr/share/man/man1/objdump.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
.if ${MK_BLACKLIST} == no
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_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
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/lib32/libbluetooth.a
OLD_FILES+=usr/lib32/libbluetooth.so
OLD_LIBS+=usr/lib32/libbluetooth.so.4
OLD_FILES+=usr/lib32/libbluetooth_p.a
OLD_FILES+=usr/lib32/libsdp.a
OLD_FILES+=usr/lib32/libsdp.so
OLD_LIBS+=usr/lib32/libsdp.so.4
OLD_FILES+=usr/lib32/libsdp_p.a
.endif
OLD_FILES+=usr/sbin/ath3kfw
OLD_FILES+=usr/sbin/bcmfw
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/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/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/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/boot1.efifat
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+=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_BSD_GREP} == no
OLD_FILES+=usr/bin/lzegrep
OLD_FILES+=usr/bin/lzfgrep
OLD_FILES+=usr/bin/lzgrep
OLD_FILES+=usr/bin/xzegrep
OLD_FILES+=usr/bin/xzfgrep
OLD_FILES+=usr/bin/xzgrep
OLD_FILES+=usr/share/man/man1/lzegrep.1.gz
OLD_FILES+=usr/share/man/man1/lzfgrep.1.gz
OLD_FILES+=usr/share/man/man1/lzgrep.1.gz
OLD_FILES+=usr/share/man/man1/xzegrep.1.gz
OLD_FILES+=usr/share/man/man1/xzfgrep.1.gz
OLD_FILES+=usr/share/man/man1/xzgrep.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/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_atm.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_atm.so
OLD_LIBS+=usr/lib/snmp_atm.so.6
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/lib32/libbsnmp.a
OLD_FILES+=usr/lib32/libbsnmp.so
OLD_LIBS+=usr/lib32/libbsnmp.so.6
OLD_FILES+=usr/lib32/libbsnmp_p.a
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_atm.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/atm_freebsd.def
OLD_FILES+=usr/share/snmp/defs/atm_tree.def
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/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_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_FILES+=etc/rc.d/casperd
OLD_LIBS+=lib/libcapsicum.so.0
OLD_LIBS+=lib/libcasper.so.0
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+=sbin/casper
OLD_FILES+=sbin/casperd
OLD_FILES+=usr/include/libcapsicum.h
OLD_FILES+=usr/include/libcapsicum_dns.h
OLD_FILES+=usr/include/libcapsicum_grp.h
OLD_FILES+=usr/include/libcapsicum_pwd.h
OLD_FILES+=usr/include/libcapsicum_random.h
OLD_FILES+=usr/include/libcapsicum_service.h
OLD_FILES+=usr/include/libcapsicum_sysctl.h
OLD_FILES+=usr/include/libcasper.h
OLD_FILES+=usr/lib/libcapsicum.a
OLD_FILES+=usr/lib/libcapsicum.so
OLD_FILES+=usr/lib/libcapsicum_p.a
OLD_FILES+=usr/lib/libcasper.a
OLD_FILES+=usr/lib/libcasper.so
OLD_FILES+=usr/lib/libcasper_p.a
OLD_FILES+=usr/lib32/libcapsicum.a
OLD_FILES+=usr/lib32/libcapsicum.so
OLD_LIBS+=usr/lib32/libcapsicum.so.0
OLD_FILES+=usr/lib32/libcapsicum_p.a
OLD_FILES+=usr/lib32/libcasper.a
OLD_FILES+=usr/lib32/libcasper.so
OLD_LIBS+=usr/lib32/libcasper.so.0
OLD_FILES+=usr/lib32/libcasper_p.a
OLD_FILES+=usr/share/man/man3/cap_clone.3.gz
OLD_FILES+=usr/share/man/man3/cap_close.3.gz
OLD_FILES+=usr/share/man/man3/cap_init.3.gz
OLD_FILES+=usr/share/man/man3/cap_limit_get.3.gz
OLD_FILES+=usr/share/man/man3/cap_limit_set.3.gz
OLD_FILES+=usr/share/man/man3/cap_recv_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/cap_send_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/cap_service_open.3.gz
OLD_FILES+=usr/share/man/man3/cap_sock.3.gz
OLD_FILES+=usr/share/man/man3/cap_unwrap.3.gz
OLD_FILES+=usr/share/man/man3/cap_wrap.3.gz
OLD_FILES+=usr/share/man/man3/cap_xfer_nvlist.3.gz
OLD_FILES+=usr/share/man/man3/libcapsicum.3.gz
OLD_FILES+=usr/share/man/man8/casperd.8.gz
.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/psinfo.d
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/lib/dtrace/regs_x86.d
.endif
OLD_FILES+=usr/lib/dtrace/signal.d
OLD_FILES+=usr/lib/dtrace/tcp.d
OLD_FILES+=usr/lib/dtrace/udp.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
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/lib32/dtrace/drti.o
OLD_FILES+=usr/lib32/libavl.a
OLD_FILES+=usr/lib32/libavl.so
OLD_LIBS+=usr/lib32/libavl.so.2
OLD_FILES+=usr/lib32/libavl_p.a
OLD_FILES+=usr/lib32/libctf.a
OLD_FILES+=usr/lib32/libctf.so
OLD_LIBS+=usr/lib32/libctf.so.2
OLD_FILES+=usr/lib32/libctf_p.a
OLD_FILES+=usr/lib32/libdtrace.a
OLD_FILES+=usr/lib32/libdtrace.so
OLD_LIBS+=usr/lib32/libdtrace.so.2
OLD_FILES+=usr/lib32/libdtrace_p.a
OLD_FILES+=usr/lib32/libnvpair.a
OLD_FILES+=usr/lib32/libnvpair.so
OLD_LIBS+=usr/lib32/libnvpair.so.2
OLD_FILES+=usr/lib32/libnvpair_p.a
OLD_FILES+=usr/lib32/libumem.a
OLD_FILES+=usr/lib32/libumem.so
OLD_LIBS+=usr/lib32/libumem.so.2
OLD_FILES+=usr/lib32/libumem_p.a
OLD_FILES+=usr/lib32/libuutil.a
OLD_FILES+=usr/lib32/libuutil.so
OLD_LIBS+=usr/lib32/libuutil.so.2
OLD_FILES+=usr/lib32/libuutil_p.a
.endif
OLD_LIBS+=lib/libdtrace.so.2
OLD_FILES+=usr/sbin/dtrace
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/disklatency
OLD_FILES+=usr/share/dtrace/disklatencycmd
OLD_FILES+=usr/share/dtrace/hotopen
OLD_FILES+=usr/share/dtrace/nfsclienttime
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/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/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/zfsd
OLD_FILES+=etc/rc.d/zfsbe
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_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_LIBS+=usr/lib/libzfs.so
OLD_FILES+=usr/lib/libzfs_core.a
OLD_LIBS+=usr/lib/libzfs_core.so
OLD_LIBS+=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
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/lib32/libzfs.a
OLD_FILES+=usr/lib32/libzfs.so
OLD_LIBS+=usr/lib32/libzfs.so.2
OLD_LIBS+=usr/lib32/libzfs.so.3
OLD_FILES+=usr/lib32/libzfs_core.a
OLD_FILES+=usr/lib32/libzfs_core.so
OLD_LIBS+=usr/lib32/libzfs_core.so.2
OLD_FILES+=usr/lib32/libzfs_core_p.a
OLD_FILES+=usr/lib32/libzfs_p.a
OLD_FILES+=usr/lib32/libzpool.a
OLD_FILES+=usr/lib32/libzpool.so
OLD_LIBS+=usr/lib32/libzpool.so.2
.endif
OLD_FILES+=usr/sbin/zfsd
OLD_FILES+=usr/sbin/zhack
OLD_FILES+=usr/sbin/zdb
OLD_FILES+=usr/share/man/man3/libbe.3.gz
OLD_FILES+=usr/share/man/man7/zpool-features.7.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
OLD_FILES+=usr/bin/clang
OLD_FILES+=usr/bin/clang++
OLD_FILES+=usr/bin/clang-cpp
OLD_FILES+=usr/bin/clang-tblgen
OLD_FILES+=usr/bin/llvm-objdump
+OLD_FILES+=usr/bin/llvm-symbolizer
OLD_FILES+=usr/bin/llvm-tblgen
-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-i386.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-i386.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
+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-i386.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-i386.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-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
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
OLD_FILES+=usr/share/man/man1/llvm-tblgen.1.gz
.endif
.if ${MK_CLANG_EXTRAS} == no
OLD_FILES+=usr/bin/bugpoint
OLD_FILES+=usr/bin/clang-format
OLD_FILES+=usr/bin/llc
OLD_FILES+=usr/bin/lli
OLD_FILES+=usr/bin/llvm-ar
OLD_FILES+=usr/bin/llvm-as
OLD_FILES+=usr/bin/llvm-bcanalyzer
OLD_FILES+=usr/bin/llvm-cxxdump
OLD_FILES+=usr/bin/llvm-cxxfilt
OLD_FILES+=usr/bin/llvm-diff
OLD_FILES+=usr/bin/llvm-dis
OLD_FILES+=usr/bin/llvm-dwarfdump
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-nm
OLD_FILES+=usr/bin/llvm-objcopy
OLD_FILES+=usr/bin/llvm-pdbutil
OLD_FILES+=usr/bin/llvm-ranlib
OLD_FILES+=usr/bin/llvm-rtdyld
-OLD_FILES+=usr/bin/llvm-symbolizer
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-ar.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-nm.1.gz
OLD_FILES+=usr/share/man/man1/llvm-pdbutil.1.gz
OLD_FILES+=usr/share/man/man1/llvm-symbolizer.1.gz
OLD_FILES+=usr/share/man/man1/opt.1.gz
.endif
.if ${MK_CPP} == no
OLD_FILES+=usr/bin/cpp
OLD_FILES+=usr/share/man/man1/cpp.1.gz
.endif
.if ${MK_CTM} == no
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
.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
# devd(8) not listed here on purpose
.if ${MK_CXX} == no
OLD_FILES+=usr/bin/CC
OLD_FILES+=usr/bin/c++
OLD_FILES+=usr/bin/g++
OLD_FILES+=usr/libexec/cc1plus
.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
.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/pam.d/ftp
OLD_FILES+=etc/pam.d/ftpd
OLD_FILES+=etc/rc.d/ftpd
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_GNUCXX} == no
OLD_FILES+=usr/bin/g++
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
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
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/lib32/libstdc++.a
OLD_FILES+=usr/lib32/libstdc++.so
OLD_LIBS+=usr/lib32/libstdc++.so.6
OLD_FILES+=usr/lib32/libstdc++_p.a
OLD_FILES+=usr/lib32/libsupc++.a
OLD_FILES+=usr/lib32/libsupc++.so
OLD_LIBS+=usr/lib32/libsupc++.so.1
OLD_FILES+=usr/lib32/libsupc++_p.a
.endif
OLD_FILES+=usr/libexec/cc1plus
.endif
.if ${MK_DICT} == no
OLD_FILES+=usr/share/dict/README
OLD_FILES+=usr/share/dict/eign
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_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
# to be filled in
#.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_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_GCC} == no
OLD_FILES+=usr/bin/g++
OLD_FILES+=usr/bin/gcc
OLD_FILES+=usr/bin/gcpp
OLD_FILES+=usr/bin/gperf
.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
.if ${MK_OPENMP} == no
OLD_FILES+=usr/include/omp.h
.endif
OLD_FILES+=usr/lib/libgcov.a
OLD_FILES+=usr/lib/libgomp.a
.if ${MK_OPENMP} == no
OLD_FILES+=usr/lib/libgomp.so
.endif
OLD_LIBS+=usr/lib/libgomp.so.1
OLD_FILES+=usr/lib/libgomp_p.a
OLD_FILES+=usr/lib32/libgcov.a
OLD_FILES+=usr/lib32/libgomp.a
.if ${MK_OPENMP} == no
OLD_FILES+=usr/lib32/libgomp.so
.endif
OLD_LIBS+=usr/lib32/libgomp.so.1
OLD_FILES+=usr/lib32/libgomp_p.a
OLD_FILES+=usr/libexec/cc1
OLD_FILES+=usr/libexec/cc1plus
OLD_FILES+=usr/share/man/man1/g++.1.gz
OLD_FILES+=usr/share/man/man1/gcc.1.gz
OLD_FILES+=usr/share/man/man1/gcpp.1.gz
OLD_FILES+=usr/share/man/man1/gperf.1.gz
OLD_FILES+=usr/share/man/man1/gperf.7.gz
.endif
.if (${MK_GCOV} == no || ${MK_GCC} == no) && ${MK_LLVM_COV} == no
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
.endif
.if ${MK_GDB} == no
OLD_FILES+=usr/bin/gdb
OLD_FILES+=usr/bin/gdbserver
OLD_FILES+=usr/bin/gdbtui
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
.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/lib32/libgpio.a
OLD_FILES+=usr/lib32/libgpio.so
OLD_LIBS+=usr/lib32/libgpio.so.0
OLD_FILES+=usr/lib32/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/diff
OLD_FILES+=usr/bin/diff3
OLD_FILES+=usr/share/man/man1/diff.1.gz
OLD_FILES+=usr/share/man/man1/diff3.1.gz
OLD_FILES+=usr/share/man/man7/diff.7.gz
.endif
.if ${MK_GNU_GREP} == no
OLD_FILES+=usr/bin/gnugrep
OLD_FILES+=usr/share/man/man1/gnugrep.1.gz
.if ${MK_BSD_GREP} == no
OLD_FILES+=usr/bin/bzgrep
OLD_FILES+=usr/bin/bzegrep
OLD_FILES+=usr/bin/bzfgrep
OLD_FILES+=usr/bin/egrep
OLD_FILES+=usr/bin/fgrep
OLD_FILES+=usr/bin/grep
OLD_FILES+=usr/bin/zegrep
OLD_FILES+=usr/bin/zfgrep
OLD_FILES+=usr/bin/zgrep
OLD_FILES+=usr/share/man/man1/bzegrep.1.gz
OLD_FILES+=usr/share/man/man1/bzfgrep.1.gz
OLD_FILES+=usr/share/man/man1/bzgrep.1.gz
OLD_FILES+=usr/share/man/man1/egrep.1.gz
OLD_FILES+=usr/share/man/man1/fgrep.1.gz
OLD_FILES+=usr/share/man/man1/grep.1.gz
OLD_FILES+=usr/share/man/man1/zegrep.1.gz
OLD_FILES+=usr/share/man/man1/zfgrep.1.gz
OLD_FILES+=usr/share/man/man1/zgrep.1.gz
.endif
.endif
# Also includes vgrind(1)
.if ${MK_GROFF} == no
OLD_FILES+=usr/bin/addftinfo
OLD_FILES+=usr/bin/afmtodit
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/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_FILES+=usr/share/doc/psd/01.cacm/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/02.implement/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/03.iosys/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/04.uprog/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/05.sysman/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/06.Clang/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/12.make/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/13.rcs/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/13.rcs/rcs_func.ascii.gz
OLD_FILES+=usr/share/doc/psd/15.yacc/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/16.lex/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/17.m4/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/18.gprof/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/20.ipctut/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/21.ipc/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/22.rpcgen/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/23.rpc/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/24.xdr/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/25.xdrrfc/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/26.rpcrfc/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/27.nfsrfc/paper.ascii.gz
OLD_FILES+=usr/share/doc/psd/Title.ascii.gz
OLD_FILES+=usr/share/doc/psd/contents.ascii.gz
OLD_FILES+=usr/share/doc/smm/01.setup/paper.ascii.gz
OLD_FILES+=usr/share/doc/smm/02.config/paper.ascii.gz
OLD_FILES+=usr/share/doc/smm/03.fsck/paper.ascii.gz
OLD_FILES+=usr/share/doc/smm/04.quotas/paper.ascii.gz
OLD_FILES+=usr/share/doc/smm/05.fastfs/paper.ascii.gz
OLD_FILES+=usr/share/doc/smm/06.nfs/paper.ascii.gz
OLD_FILES+=usr/share/doc/smm/07.lpd/paper.ascii.gz
OLD_FILES+=usr/share/doc/smm/08.sendmailop/paper.ascii.gz
OLD_FILES+=usr/share/doc/smm/11.timedop/paper.ascii.gz
OLD_FILES+=usr/share/doc/smm/12.timed/paper.ascii.gz
OLD_FILES+=usr/share/doc/smm/18.net/paper.ascii.gz
OLD_FILES+=usr/share/doc/smm/Title.ascii.gz
OLD_FILES+=usr/share/doc/smm/contents.ascii.gz
OLD_FILES+=usr/share/doc/usd/04.csh/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/05.dc/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/06.bc/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/07.mail/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/10.exref/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/10.exref/summary.ascii.gz
OLD_FILES+=usr/share/doc/usd/11.edit/paper.ascii.gz
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_FILES+=usr/share/doc/usd/13.viref/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/18.msdiffs/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/19.memacros/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/20.meref/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/21.troff/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/22.trofftut/paper.ascii.gz
OLD_FILES+=usr/share/doc/usd/Title.ascii.gz
OLD_FILES+=usr/share/doc/usd/contents.ascii.gz
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/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/man/man7/roff.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
.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
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/lib32/libgssapi.a
OLD_FILES+=usr/lib32/libgssapi.so
OLD_LIBS+=usr/lib32/libgssapi.so.10
OLD_FILES+=usr/lib32/libgssapi_p.a
OLD_FILES+=usr/lib32/librpcsec_gss.a
OLD_FILES+=usr/lib32/librpcsec_gss.so
OLD_LIBS+=usr/lib32/librpcsec_gss.so.1
.endif
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+=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_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
.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/ping6.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/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+=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/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/compile_et
OLD_FILES+=usr/bin/hxtool
OLD_FILES+=usr/bin/kadmin
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/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/private/libheimipcc.a
OLD_FILES+=usr/lib/private/libheimipcc.so
OLD_LIBS+=usr/lib/private/libheimipcc.so.11
OLD_FILES+=usr/lib/private/libheimipcc_p.a
OLD_FILES+=usr/lib/private/libheimipcs.a
OLD_FILES+=usr/lib/private/libheimipcs.so
OLD_LIBS+=usr/lib/private/libheimipcs.so.11
OLD_FILES+=usr/lib/private/libheimipcs_p.a
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/lib32/libasn1.a
OLD_FILES+=usr/lib32/libasn1.so
OLD_LIBS+=usr/lib32/libasn1.so.11
OLD_FILES+=usr/lib32/libasn1_p.a
OLD_FILES+=usr/lib32/libgssapi_krb5.a
OLD_FILES+=usr/lib32/libgssapi_krb5.so
OLD_LIBS+=usr/lib32/libgssapi_krb5.so.10
OLD_FILES+=usr/lib32/libgssapi_krb5_p.a
OLD_FILES+=usr/lib32/libgssapi_ntlm.a
OLD_FILES+=usr/lib32/libgssapi_ntlm.so
OLD_LIBS+=usr/lib32/libgssapi_ntlm.so.10
OLD_FILES+=usr/lib32/libgssapi_ntlm_p.a
OLD_FILES+=usr/lib32/libgssapi_spnego.a
OLD_FILES+=usr/lib32/libgssapi_spnego.so
OLD_LIBS+=usr/lib32/libgssapi_spnego.so.10
OLD_FILES+=usr/lib32/libgssapi_spnego_p.a
OLD_FILES+=usr/lib32/libhdb.a
OLD_FILES+=usr/lib32/libhdb.so
OLD_LIBS+=usr/lib32/libhdb.so.11
OLD_FILES+=usr/lib32/libhdb_p.a
OLD_FILES+=usr/lib32/libheimbase.a
OLD_FILES+=usr/lib32/libheimbase.so
OLD_LIBS+=usr/lib32/libheimbase.so.11
OLD_FILES+=usr/lib32/libheimbase_p.a
OLD_FILES+=usr/lib32/libheimntlm.a
OLD_FILES+=usr/lib32/libheimntlm.so
OLD_LIBS+=usr/lib32/libheimntlm.so.11
OLD_FILES+=usr/lib32/libheimntlm_p.a
OLD_FILES+=usr/lib32/libheimsqlite.a
OLD_FILES+=usr/lib32/libheimsqlite.so
OLD_LIBS+=usr/lib32/libheimsqlite.so.11
OLD_FILES+=usr/lib32/libheimsqlite_p.a
OLD_FILES+=usr/lib32/libhx509.a
OLD_FILES+=usr/lib32/libhx509.so
OLD_LIBS+=usr/lib32/libhx509.so.11
OLD_FILES+=usr/lib32/libhx509_p.a
OLD_FILES+=usr/lib32/libkadm5clnt.a
OLD_FILES+=usr/lib32/libkadm5clnt.so
OLD_LIBS+=usr/lib32/libkadm5clnt.so.11
OLD_FILES+=usr/lib32/libkadm5clnt_p.a
OLD_FILES+=usr/lib32/libkadm5srv.a
OLD_FILES+=usr/lib32/libkadm5srv.so
OLD_LIBS+=usr/lib32/libkadm5srv.so.11
OLD_FILES+=usr/lib32/libkadm5srv_p.a
OLD_FILES+=usr/lib32/libkafs5.a
OLD_FILES+=usr/lib32/libkafs5.so
OLD_LIBS+=usr/lib32/libkafs5.so.11
OLD_FILES+=usr/lib32/libkafs5_p.a
OLD_FILES+=usr/lib32/libkdc.a
OLD_FILES+=usr/lib32/libkdc.so
OLD_LIBS+=usr/lib32/libkdc.so.11
OLD_FILES+=usr/lib32/libkdc_p.a
OLD_FILES+=usr/lib32/libkrb5.a
OLD_FILES+=usr/lib32/libkrb5.so
OLD_LIBS+=usr/lib32/libkrb5.so.11
OLD_FILES+=usr/lib32/libkrb5_p.a
OLD_FILES+=usr/lib32/libroken.a
OLD_FILES+=usr/lib32/libroken.so
OLD_LIBS+=usr/lib32/libroken.so.11
OLD_FILES+=usr/lib32/libroken_p.a
OLD_FILES+=usr/lib32/libwind.a
OLD_FILES+=usr/lib32/libwind.so
OLD_LIBS+=usr/lib32/libwind.so.11
OLD_FILES+=usr/lib32/libwind_p.a
OLD_FILES+=usr/lib32/pam_krb5.so
OLD_LIBS+=usr/lib32/pam_krb5.so.6
OLD_FILES+=usr/lib32/pam_ksu.so
OLD_LIBS+=usr/lib32/pam_ksu.so.6
OLD_FILES+=usr/lib32/private/libheimipcc.a
OLD_FILES+=usr/lib32/private/libheimipcc.so
OLD_LIBS+=usr/lib32/private/libheimipcc.so.11
OLD_FILES+=usr/lib32/private/libheimipcc_p.a
OLD_FILES+=usr/lib32/private/libheimipcs.a
OLD_FILES+=usr/lib32/private/libheimipcs.so
OLD_LIBS+=usr/lib32/private/libheimipcs.so.11
OLD_FILES+=usr/lib32/private/libheimipcs_p.a
.endif
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/lib32/libcom_err.a
OLD_FILES+=usr/lib32/libcom_err.so
OLD_LIBS+=usr/lib32/libcom_err.so.5
OLD_FILES+=usr/lib32/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/private/libldns.a
OLD_FILES+=usr/lib/private/libldns.so
OLD_LIBS+=usr/lib/private/libldns.so.5
OLD_FILES+=usr/lib/private/libldns_p.a
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/lib32/private/libldns.a
OLD_FILES+=usr/lib32/private/libldns.so
OLD_LIBS+=usr/lib32/private/libldns.so.5
OLD_FILES+=usr/lib32/private/libldns_p.a
.endif
.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+=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_LIBCPLUSPLUS} == 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++fs.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/__bit_reference
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/__config
OLD_FILES+=usr/include/c++/v1/__debug
OLD_FILES+=usr/include/c++/v1/__errc
OLD_FILES+=usr/include/c++/v1/__functional_03
OLD_FILES+=usr/include/c++/v1/__functional_base
OLD_FILES+=usr/include/c++/v1/__functional_base_03
OLD_FILES+=usr/include/c++/v1/__hash_table
OLD_FILES+=usr/include/c++/v1/__libcpp_version
OLD_FILES+=usr/include/c++/v1/__locale
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/__split_buffer
OLD_FILES+=usr/include/c++/v1/__sso_allocator
OLD_FILES+=usr/include/c++/v1/__std_stream
OLD_FILES+=usr/include/c++/v1/__string
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/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/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/condition_variable
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/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/any
OLD_FILES+=usr/include/c++/v1/experimental/chrono
OLD_FILES+=usr/include/c++/v1/experimental/coroutine
OLD_FILES+=usr/include/c++/v1/experimental/deque
OLD_FILES+=usr/include/c++/v1/experimental/dynarray
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/numeric
OLD_FILES+=usr/include/c++/v1/experimental/optional
OLD_FILES+=usr/include/c++/v1/experimental/propagate_const
OLD_FILES+=usr/include/c++/v1/experimental/ratio
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/string_view
OLD_FILES+=usr/include/c++/v1/experimental/system_error
OLD_FILES+=usr/include/c++/v1/experimental/tuple
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_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_FILES+=usr/include/c++/v1/filesystem
OLD_FILES+=usr/include/c++/v1/float.h
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/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/mutex
OLD_FILES+=usr/include/c++/v1/new
OLD_FILES+=usr/include/c++/v1/numeric
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/ratio
OLD_FILES+=usr/include/c++/v1/regex
OLD_FILES+=usr/include/c++/v1/scoped_allocator
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/version
OLD_FILES+=usr/include/c++/v1/tr1/__bit_reference
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/__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/__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/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/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/complex
OLD_FILES+=usr/include/c++/v1/tr1/complex.h
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/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/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/numeric
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/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/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/wchar.h
OLD_FILES+=usr/include/c++/v1/tr1/wctype.h
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/unwind-arm.h
OLD_FILES+=usr/include/c++/v1/unwind-itanium.h
OLD_FILES+=usr/include/c++/v1/unwind.h
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/wchar.h
OLD_FILES+=usr/include/c++/v1/wctype.h
OLD_FILES+=usr/lib32/libc++.a
OLD_FILES+=usr/lib32/libc++.so
OLD_LIBS+=usr/lib32/libc++.so.1
OLD_FILES+=usr/lib32/libc++_p.a
OLD_FILES+=usr/lib32/libc++experimental.a
OLD_FILES+=usr/lib32/libc++fs.a
OLD_FILES+=usr/lib32/libcxxrt.a
OLD_FILES+=usr/lib32/libcxxrt.so
OLD_LIBS+=usr/lib32/libcxxrt.so.1
OLD_FILES+=usr/lib32/libcxxrt_p.a
OLD_DIRS+=usr/include/c++/v1/tr1
OLD_DIRS+=usr/include/c++/v1/experimental
OLD_DIRS+=usr/include/c++/v1/ext
OLD_DIRS+=usr/include/c++/v1
.endif
.if ${MK_LIBTHR} == no
OLD_LIBS+=lib/libthr.so.3
OLD_FILES+=usr/lib/libthr.a
OLD_FILES+=usr/lib/libthr_p.a
OLD_FILES+=usr/share/man/man3/libthr.3.gz
.endif
.if ${MK_LLD} == no
OLD_FILES+=usr/bin/ld.lld
.endif
.if ${MK_LLDB} == no
OLD_FILES+=usr/bin/lldb
OLD_FILES+=usr/share/man/man1/lldb.1.gz
.endif
.if ${MK_LOCALES} == no
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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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/rc.d/lpd
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+=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}
.endif
.if ${MK_MAN_UTILS} == no
OLD_FILES+=etc/periodic/weekly/320.whatis
OLD_FILES+=etc/periodic/weekly/330.catman
OLD_FILES+=usr/bin/apropos
OLD_FILES+=usr/bin/catman
OLD_FILES+=usr/bin/makewhatis
OLD_FILES+=usr/bin/man
OLD_FILES+=usr/bin/manpath
OLD_FILES+=usr/bin/whatis
OLD_FILES+=usr/libexec/catman.local
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/catman.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/catman.local.8.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/lib32/libnetgraph.a
OLD_FILES+=usr/lib32/libnetgraph.so
OLD_LIBS+=usr/lib32/libnetgraph.so.4
OLD_FILES+=usr/lib32/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_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
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/lib32/libypclnt.a
OLD_FILES+=usr/lib32/libypclnt.so
OLD_LIBS+=usr/lib32/libypclnt.so.4
OLD_FILES+=usr/lib32/libypclnt_p.a
.endif
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_FILES+=usr/share/nls/C/ee.cat
OLD_FILES+=usr/share/nls/be_BY.UTF-8/libc.cat
OLD_FILES+=usr/share/nls/ca_ES.ISO8859-1/libc.cat
OLD_FILES+=usr/share/nls/de_AT.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/de_AT.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/de_AT.ISO8859-15/ee.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/ee.cat
OLD_FILES+=usr/share/nls/de_CH.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/de_CH.ISO8859-15/ee.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/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_FILES+=usr/share/nls/de_DE.ISO8859-15/ee.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/libc.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/en_US.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/en_US.ISO8859-15/ee.cat
OLD_FILES+=usr/share/nls/es_ES.ISO8859-1/grep.cat
OLD_FILES+=usr/share/nls/es_ES.ISO8859-1/libc.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/libc.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/ee.cat
OLD_FILES+=usr/share/nls/fr_BE.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/fr_BE.ISO8859-15/ee.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/ee.cat
OLD_FILES+=usr/share/nls/fr_CA.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/fr_CA.ISO8859-15/ee.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/ee.cat
OLD_FILES+=usr/share/nls/fr_CH.ISO8859-1/tcsh.cat
OLD_FILES+=usr/share/nls/fr_CH.ISO8859-15/ee.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/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_FILES+=usr/share/nls/fr_FR.ISO8859-15/ee.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/gl_ES.ISO8859-1/grep.cat
OLD_FILES+=usr/share/nls/gl_ES.ISO8859-1/libc.cat
OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/ee.cat
OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/grep.cat
OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/libc.cat
OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/sort.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/libc.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/grep.cat
OLD_FILES+=usr/share/nls/ja_JP.SJIS/tcsh.cat
OLD_FILES+=usr/share/nls/ja_JP.UTF-8/grep.cat
OLD_FILES+=usr/share/nls/ja_JP.UTF-8/libc.cat
OLD_FILES+=usr/share/nls/ja_JP.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/ja_JP.eucJP/grep.cat
OLD_FILES+=usr/share/nls/ja_JP.eucJP/libc.cat
OLD_FILES+=usr/share/nls/ja_JP.eucJP/tcsh.cat
OLD_FILES+=usr/share/nls/ko_KR.UTF-8/libc.cat
OLD_FILES+=usr/share/nls/ko_KR.eucKR/libc.cat
OLD_FILES+=usr/share/nls/mn_MN.UTF-8/libc.cat
OLD_FILES+=usr/share/nls/nl_NL.ISO8859-1/libc.cat
OLD_FILES+=usr/share/nls/no_NO.ISO8859-1/libc.cat
OLD_FILES+=usr/share/nls/pl_PL.ISO8859-2/ee.cat
OLD_FILES+=usr/share/nls/pl_PL.ISO8859-2/libc.cat
OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/ee.cat
OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/grep.cat
OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/libc.cat
OLD_FILES+=usr/share/nls/pt_PT.ISO8859-1/ee.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/ee.cat
OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/grep.cat
OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/libc.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/sk_SK.ISO8859-2/libc.cat
OLD_FILES+=usr/share/nls/sv_SE.ISO8859-1/libc.cat
OLD_FILES+=usr/share/nls/uk_UA.ISO8859-5/tcsh.cat
OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/ee.cat
OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/tcsh.cat
OLD_FILES+=usr/share/nls/uk_UA.UTF-8/grep.cat
OLD_FILES+=usr/share/nls/uk_UA.UTF-8/libc.cat
OLD_FILES+=usr/share/nls/uk_UA.UTF-8/tcsh.cat
OLD_FILES+=usr/share/nls/zh_CN.GB18030/libc.cat
OLD_FILES+=usr/share/nls/zh_CN.GB2312/libc.cat
OLD_FILES+=usr/share/nls/zh_CN.UTF-8/grep.cat
OLD_FILES+=usr/share/nls/zh_CN.UTF-8/libc.cat
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.conf
OLD_FILES+=etc/periodic/daily/480.status-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/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
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_OPENMP} == no
.if ${MK_GCC} == no
OLD_FILES+=usr/include/omp.h
OLD_LIBS+=usr/lib/libgomp.so
OLD_LIBS+=usr/lib32/libgomp.so
.endif
OLD_LIBS+=usr/lib/libomp.so
OLD_LIBS+=usr/lib32/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_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/pam_ssh.so
OLD_LIBS+=usr/lib/pam_ssh.so.6
OLD_FILES+=usr/lib/private/libssh.a
OLD_FILES+=usr/lib/private/libssh.so
OLD_LIBS+=usr/lib/private/libssh.so.5
OLD_FILES+=usr/lib/private/libssh_p.a
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/lib32/pam_ssh.so
OLD_LIBS+=usr/lib32/pam_ssh.so.6
OLD_FILES+=usr/lib32/private/libssh.a
OLD_FILES+=usr/lib32/private/libssh.so
OLD_LIBS+=usr/lib32/private/libssh.so.5
OLD_FILES+=usr/lib32/private/libssh_p.a
.endif
OLD_FILES+=usr/libexec/sftp-server
OLD_FILES+=usr/libexec/ssh-keysign
OLD_FILES+=usr/libexec/ssh-pkcs11-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/sshd.8.gz
.endif
.if ${MK_OPENSSL} == no
OLD_FILES+=etc/rc.d/keyserv
.endif
.if ${MK_PC_SYSINSTALL} == no
# backend-partmanager
OLD_FILES+=usr/share/pc-sysinstall/backend-partmanager/create-part.sh
OLD_FILES+=usr/share/pc-sysinstall/backend-partmanager/delete-part.sh
# backend-query
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
# backend
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
# conf
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
# doc
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
# examples
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
# pc-sysinstall
OLD_FILES+=usr/sbin/pc-sysinstall
OLD_FILES+=usr/share/man/man8/pc-sysinstall.8.gz
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
OLD_DIRS+=usr/share/examples/pc-sysinstall
.endif
.if ${MK_PF} == no
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
OLD_FILES+=usr/include/pmc.h
OLD_FILES+=usr/include/pmclog.h
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/lib32/libpmc.a
OLD_FILES+=usr/lib32/libpmc.so
OLD_LIBS+=usr/lib32/libpmc.so.5
OLD_FILES+=usr/lib32/libpmc_p.a
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/libexec/phttpget
OLD_FILES+=usr/sbin/portsnap
OLD_FILES+=usr/share/examples/etc/portsnap.conf
OLD_FILES+=usr/share/man/man8/phttpget.8.gz
OLD_FILES+=usr/share/man/man8/portsnap.8.gz
.endif
.if ${MK_PPP} == no
OLD_FILES+=etc/ppp/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/libalias_cuseeme_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/libbegemot_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/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/libcrypt_p.a
OLD_FILES+=usr/lib/libcrypto_p.a
OLD_FILES+=usr/lib/libcurses_p.a
OLD_FILES+=usr/lib/libcursesw_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/libedit_p.a
OLD_FILES+=usr/lib/libelf_p.a
OLD_FILES+=usr/lib/libfetch_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_p.a
OLD_FILES+=usr/lib/libgeom_p.a
OLD_FILES+=usr/lib/libgnuregex_p.a
OLD_FILES+=usr/lib/libgssapi_krb5_p.a
OLD_FILES+=usr/lib/libgssapi_p.a
OLD_FILES+=usr/lib/libhdb_p.a
OLD_FILES+=usr/lib/libheimbase_p.a
OLD_FILES+=usr/lib/libheimsqlite_p.a
OLD_FILES+=usr/lib/libhistory_p.a
OLD_FILES+=usr/lib/libipsec_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/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/libncurses_p.a
OLD_FILES+=usr/lib/libncursesw_p.a
OLD_FILES+=usr/lib/libnetgraph_p.a
OLD_FILES+=usr/lib/libngatm_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/libpcap_p.a
OLD_FILES+=usr/lib/libpmc_p.a
OLD_FILES+=usr/lib/libpthread_p.a
OLD_FILES+=usr/lib/libradius_p.a
OLD_FILES+=usr/lib/libroken_p.a
OLD_FILES+=usr/lib/librpcsvc_p.a
OLD_FILES+=usr/lib/librt_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/libssl_p.a
OLD_FILES+=usr/lib/libstdc++_p.a
OLD_FILES+=usr/lib/libsupc++_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/libufs_p.a
OLD_FILES+=usr/lib/libugidfw_p.a
OLD_FILES+=usr/lib/libusbhid_p.a
OLD_FILES+=usr/lib/libutil_p.a
OLD_FILES+=usr/lib/libvgl_p.a
OLD_FILES+=usr/lib/libwind_p.a
OLD_FILES+=usr/lib/libwrap_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/private/libldns_p.a
OLD_FILES+=usr/lib/private/libssh_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/lib32/libradius.a
OLD_FILES+=usr/lib32/libradius.so
OLD_LIBS+=usr/lib32/libradius.so.4
OLD_FILES+=usr/lib32/libradius_p.a
OLD_FILES+=usr/lib32/pam_radius.so
OLD_LIBS+=usr/lib32/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_RCMDS} == no
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
.endif
.if ${MK_RCS} == no
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/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
.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+=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/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+=bin/rmail
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
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/lib32/libmilter.a
OLD_FILES+=usr/lib32/libmilter.so
OLD_LIBS+=usr/lib32/libmilter.so.5
OLD_FILES+=usr/lib32/libmilter_p.a
.endif
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
.endif
.if ${MK_SHAREDOCS} == no
OLD_FILES+=usr/share/doc/pjdfstest/README
OLD_DIRS+=usr/share/doc/pjdfstest
.endif
.if ${MK_SSP} == no
OLD_LIBS+=lib/libssp.so.0
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_FILES+=usr/lib/libssp.a
OLD_FILES+=usr/lib/libssp.so
OLD_FILES+=usr/lib/libssp_nonshared.a
OLD_FILES+=usr/lib32/libssp.a
OLD_FILES+=usr/lib32/libssp.so
OLD_LIBS+=usr/lib32/libssp.so.0
OLD_FILES+=usr/lib32/libssp_nonshared.a
OLD_FILES+=usr/tests/lib/libc/ssp/Kyuafile
OLD_FILES+=usr/tests/lib/libc/ssp/h_fgets
OLD_FILES+=usr/tests/lib/libc/ssp/h_getcwd
OLD_FILES+=usr/tests/lib/libc/ssp/h_gets
OLD_FILES+=usr/tests/lib/libc/ssp/h_memcpy
OLD_FILES+=usr/tests/lib/libc/ssp/h_memmove
OLD_FILES+=usr/tests/lib/libc/ssp/h_memset
OLD_FILES+=usr/tests/lib/libc/ssp/h_read
OLD_FILES+=usr/tests/lib/libc/ssp/h_readlink
OLD_FILES+=usr/tests/lib/libc/ssp/h_snprintf
OLD_FILES+=usr/tests/lib/libc/ssp/h_sprintf
OLD_FILES+=usr/tests/lib/libc/ssp/h_stpcpy
OLD_FILES+=usr/tests/lib/libc/ssp/h_stpncpy
OLD_FILES+=usr/tests/lib/libc/ssp/h_strcat
OLD_FILES+=usr/tests/lib/libc/ssp/h_strcpy
OLD_FILES+=usr/tests/lib/libc/ssp/h_strncat
OLD_FILES+=usr/tests/lib/libc/ssp/h_strncpy
OLD_FILES+=usr/tests/lib/libc/ssp/h_vsnprintf
OLD_FILES+=usr/tests/lib/libc/ssp/h_vsprintf
OLD_FILES+=usr/tests/lib/libc/ssp/ssp_test
.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/jp.pc98.iso.kbd
OLD_FILES+=usr/share/syscons/keymaps/jp.pc98.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
.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_LIBS+=usr/lib/libatf-c++.a
OLD_LIBS+=usr/lib/libatf-c++.so
OLD_LIBS+=usr/lib/libatf-c++.so.1
OLD_LIBS+=usr/lib/libatf-c++.so.2
OLD_LIBS+=usr/lib/libatf-c++_p.a
OLD_LIBS+=usr/lib/libatf-c.a
OLD_LIBS+=usr/lib/libatf-c.so
OLD_LIBS+=usr/lib/libatf-c.so.1
OLD_LIBS+=usr/lib/libatf-c_p.a
OLD_LIBS+=usr/lib/private/libatf-c.so.0
OLD_LIBS+=usr/lib/private/libatf-c++.so.1
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_LIBS+=usr/lib32/libatf-c++.a
OLD_LIBS+=usr/lib32/libatf-c++.so
OLD_LIBS+=usr/lib32/libatf-c++.so.1
OLD_LIBS+=usr/lib32/libatf-c++.so.2
OLD_LIBS+=usr/lib32/libatf-c++_p.a
OLD_LIBS+=usr/lib32/libatf-c.a
OLD_LIBS+=usr/lib32/libatf-c.so
OLD_LIBS+=usr/lib32/libatf-c.so.1
OLD_LIBS+=usr/lib32/libatf-c_p.a
OLD_LIBS+=usr/lib32/private/libatf-c.so.0
OLD_LIBS+=usr/lib32/private/libatf-c++.so.1
.endif
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/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/private/libatf-c++.so.2
OLD_LIBS+=usr/lib/private/libatf-c.so.1
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/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_TIMED} == no
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
.endif
.if ${MK_TOOLCHAIN} == no
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/readelf
OLD_FILES+=usr/bin/size
OLD_FILES+=usr/bin/strings
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/strings.1.gz
OLD_FILES+=usr/share/man/man1/strip.1.gz
.if ${MK_ELFCOPY_AS_OBJCOPY} != no
OLD_FILES+=usr/bin/objcopy
OLD_FILES+=usr/share/man/man1/objcopy.1.gz
.endif
# 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
.endif
.if ${MK_TOOLCHAIN} == no || ${MK_ELFCOPY_AS_OBJCOPY} != no
OLD_FILES+=usr/bin/elfcopy
OLD_FILES+=usr/share/man/man1/elfcopy.1.gz
.endif
.if ${MK_UNBOUND} == no
OLD_FILES+=etc/rc.d/local_unbound
OLD_FILES+=etc/unbound
OLD_FILES+=usr/lib/private/libunbound.a
OLD_FILES+=usr/lib/private/libunbound.so
OLD_LIBS+=usr/lib/private/libunbound.so.5
OLD_FILES+=usr/lib/private/libunbound_p.a
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
OLD_FILES+=usr/lib32/private/libunbound.a
OLD_FILES+=usr/lib32/private/libunbound.so
OLD_LIBS+=usr/lib32/private/libunbound.so.5
OLD_FILES+=usr/lib32/private/libunbound_p.a
.endif
OLD_FILES+=usr/sbin/local-unbound-setup
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
.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/lib32/libusb.a
OLD_FILES+=usr/lib32/libusb.so
OLD_LIBS+=usr/lib32/libusb.so.3
OLD_FILES+=usr/lib32/libusb_p.a
OLD_FILES+=usr/lib32/libusbhid.a
OLD_FILES+=usr/lib32/libusbhid.so
OLD_LIBS+=usr/lib32/libusbhid.so.4
OLD_FILES+=usr/lib32/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/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/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/ubsec.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/urtwn.4.gz
OLD_FILES+=usr/share/man/man4/urtwnfw.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/utopia.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/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+=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
.if ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/sbin/wlconfig
.endif
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
.if ${TARGET_ARCH} == "i386"
OLD_FILES+=usr/share/man/man8/i386/wlconfig.8.gz
.endif
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/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
Index: stable/11/usr.bin/clang/Makefile
===================================================================
--- stable/11/usr.bin/clang/Makefile (revision 350258)
+++ stable/11/usr.bin/clang/Makefile (revision 350259)
@@ -1,54 +1,55 @@
# $FreeBSD$
.include <src.opts.mk>
SUBDIR+= clang
SUBDIR+= clang-tblgen
SUBDIR+= llvm-tblgen
.if !defined(TOOLS_PREFIX)
+SUBDIR+= llvm-symbolizer
+
.if ${MK_CLANG_EXTRAS} != "no"
SUBDIR+= bugpoint
SUBDIR+= clang-format
SUBDIR+= llc
SUBDIR+= lli
SUBDIR+= llvm-ar
SUBDIR+= llvm-as
SUBDIR+= llvm-bcanalyzer
SUBDIR+= llvm-cxxdump
SUBDIR+= llvm-cxxfilt
SUBDIR+= llvm-diff
SUBDIR+= llvm-dis
SUBDIR+= llvm-dwarfdump
SUBDIR+= llvm-extract
SUBDIR+= llvm-link
SUBDIR+= llvm-lto
SUBDIR+= llvm-lto2
SUBDIR+= llvm-mc
SUBDIR+= llvm-mca
SUBDIR+= llvm-modextract
SUBDIR+= llvm-nm
SUBDIR+= llvm-objcopy
SUBDIR+= llvm-objdump
SUBDIR+= llvm-pdbutil
SUBDIR+= llvm-rtdyld
-SUBDIR+= llvm-symbolizer
SUBDIR+= llvm-xray
SUBDIR+= opt
.endif
.if ${MK_LLD} != "no"
SUBDIR+= lld
.endif
.if ${MK_LLDB} != "no"
SUBDIR+= lldb
.endif
.if ${MK_LLVM_COV} != "no"
SUBDIR+= llvm-cov
SUBDIR+= llvm-profdata
.endif
.endif # TOOLS_PREFIX
SUBDIR_PARALLEL=
.include <bsd.subdir.mk>
Index: stable/11
===================================================================
--- stable/11 (revision 350258)
+++ stable/11 (revision 350259)
Property changes on: stable/11
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /head:r348504,349004,349351,349793,350177

File Metadata

Mime Type
application/octet-stream
Expires
Sat, Apr 20, 3:32 PM (1 d, 23 h)
Storage Engine
chunks
Storage Format
Chunks
Storage Handle
mVjG8v7FpOFA
Default Alt Text
(4 MB)

Event Timeline